#include "asterisk.h"
#include <sys/stat.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/file.h"
Go to the source code of this file.
Defines | |
#define | LINE_COUNTER(cptr, term, counter) |
Enumerations | |
enum | file_format { FF_UNKNOWN = -1, FF_UNIX, FF_DOS, FF_MAC } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int64_t | count_lines (const char *filename, enum file_format newline_format) |
static int | env_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | env_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
static enum file_format | file2format (const char *filename) |
static int | file_count_line (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) |
static int | file_format (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) |
static int | file_read (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) |
static int | file_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
const char * | format2term (enum file_format f) |
static int | load_module (void) |
static int | stat_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Environment/filesystem dialplan functions" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_custom_function | env_function |
static struct ast_custom_function | file_count_line_function |
static struct ast_custom_function | file_format_function |
static struct ast_custom_function | file_function |
static struct ast_custom_function | stat_function |
Definition in file func_env.c.
#define LINE_COUNTER | ( | cptr, | |||
term, | |||||
counter | ) |
enum file_format |
Definition at line 296 of file func_env.c.
00296 { 00297 FF_UNKNOWN = -1, 00298 FF_UNIX, 00299 FF_DOS, 00300 FF_MAC, 00301 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 1245 of file func_env.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1245 of file func_env.c.
static int64_t count_lines | ( | const char * | filename, | |
enum file_format | newline_format | |||
) | [static] |
Definition at line 303 of file func_env.c.
References ast_log(), errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, and LOG_ERROR.
Referenced by file_count_line().
00304 { 00305 int count = 0; 00306 char fbuf[4096]; 00307 FILE *ff; 00308 00309 if (!(ff = fopen(filename, "r"))) { 00310 ast_log(LOG_ERROR, "Unable to open '%s': %s\n", filename, strerror(errno)); 00311 return -1; 00312 } 00313 00314 while (fgets(fbuf, sizeof(fbuf), ff)) { 00315 char *next = fbuf, *first_cr = NULL, *first_nl = NULL; 00316 00317 /* Must do it this way, because if the fileformat is FF_MAC, then Unix 00318 * assumptions about line-format will not come into play. */ 00319 while (next) { 00320 if (newline_format == FF_DOS || newline_format == FF_MAC || newline_format == FF_UNKNOWN) { 00321 first_cr = strchr(next, '\r'); 00322 } 00323 if (newline_format == FF_UNIX || newline_format == FF_UNKNOWN) { 00324 first_nl = strchr(next, '\n'); 00325 } 00326 00327 /* No terminators found in buffer */ 00328 if (!first_cr && !first_nl) { 00329 break; 00330 } 00331 00332 if (newline_format == FF_UNKNOWN) { 00333 if ((first_cr && !first_nl) || (first_cr && first_cr < first_nl)) { 00334 if (first_nl && first_nl == first_cr + 1) { 00335 newline_format = FF_DOS; 00336 } else if (first_cr && first_cr == &fbuf[sizeof(fbuf) - 2]) { 00337 /* Get it on the next pass */ 00338 fseek(ff, -1, SEEK_CUR); 00339 break; 00340 } else { 00341 newline_format = FF_MAC; 00342 first_nl = NULL; 00343 } 00344 } else { 00345 newline_format = FF_UNIX; 00346 first_cr = NULL; 00347 } 00348 /* Jump down into next section */ 00349 } 00350 00351 if (newline_format == FF_DOS) { 00352 if (first_nl && first_cr && first_nl == first_cr + 1) { 00353 next = first_nl + 1; 00354 count++; 00355 } else if (first_cr == &fbuf[sizeof(fbuf) - 2]) { 00356 /* Get it on the next pass */ 00357 fseek(ff, -1, SEEK_CUR); 00358 break; 00359 } 00360 } else if (newline_format == FF_MAC) { 00361 if (first_cr) { 00362 next = first_cr + 1; 00363 count++; 00364 } 00365 } else if (newline_format == FF_UNIX) { 00366 if (first_nl) { 00367 next = first_nl + 1; 00368 count++; 00369 } 00370 } 00371 } 00372 } 00373 fclose(ff); 00374 00375 return count; 00376 }
static int env_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 223 of file func_env.c.
References ast_copy_string().
00225 { 00226 char *ret = NULL; 00227 00228 *buf = '\0'; 00229 00230 if (data) 00231 ret = getenv(data); 00232 00233 if (ret) 00234 ast_copy_string(buf, ret, len); 00235 00236 return 0; 00237 }
static int env_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 239 of file func_env.c.
References ast_strlen_zero(), setenv(), and unsetenv().
00241 { 00242 if (!ast_strlen_zero(data) && strncmp(data, "AST_", 4)) { 00243 if (!ast_strlen_zero(value)) { 00244 setenv(data, value, 1); 00245 } else { 00246 unsetenv(data); 00247 } 00248 } 00249 00250 return 0; 00251 }
static enum file_format file2format | ( | const char * | filename | ) | [static] |
Definition at line 417 of file func_env.c.
References ast_log(), errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file_format(), and LOG_ERROR.
Referenced by file_format(), file_read(), and file_write().
00418 { 00419 FILE *ff; 00420 char fbuf[4096]; 00421 char *first_cr, *first_nl; 00422 enum file_format newline_format = FF_UNKNOWN; 00423 00424 if (!(ff = fopen(filename, "r"))) { 00425 ast_log(LOG_ERROR, "Cannot open '%s': %s\n", filename, strerror(errno)); 00426 return -1; 00427 } 00428 00429 while (fgets(fbuf, sizeof(fbuf), ff)) { 00430 first_cr = strchr(fbuf, '\r'); 00431 first_nl = strchr(fbuf, '\n'); 00432 00433 if (!first_cr && !first_nl) { 00434 continue; 00435 } 00436 00437 if ((first_cr && !first_nl) || (first_cr && first_cr < first_nl)) { 00438 00439 if (first_nl && first_nl == first_cr + 1) { 00440 newline_format = FF_DOS; 00441 } else if (first_cr && first_cr == &fbuf[sizeof(fbuf) - 2]) { 00442 /* Edge case: get it on the next pass */ 00443 fseek(ff, -1, SEEK_CUR); 00444 continue; 00445 } else { 00446 newline_format = FF_MAC; 00447 } 00448 } else { 00449 newline_format = FF_UNIX; 00450 } 00451 break; 00452 } 00453 fclose(ff); 00454 return newline_format; 00455 }
static int file_count_line | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
struct ast_str ** | buf, | |||
ssize_t | len | |||
) | [static] |
Definition at line 378 of file func_env.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_STANDARD_APP_ARGS, ast_str_set(), count_lines(), FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file_format(), and format.
00379 { 00380 enum file_format newline_format = FF_UNKNOWN; 00381 int64_t count; 00382 AST_DECLARE_APP_ARGS(args, 00383 AST_APP_ARG(filename); 00384 AST_APP_ARG(format); 00385 ); 00386 00387 AST_STANDARD_APP_ARGS(args, data); 00388 if (args.argc > 1) { 00389 if (tolower(args.format[0]) == 'd') { 00390 newline_format = FF_DOS; 00391 } else if (tolower(args.format[0]) == 'm') { 00392 newline_format = FF_MAC; 00393 } else if (tolower(args.format[0]) == 'u') { 00394 newline_format = FF_UNIX; 00395 } 00396 } 00397 00398 count = count_lines(args.filename, newline_format); 00399 ast_str_set(buf, len, "%" PRId64, count); 00400 return 0; 00401 }
static int file_format | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
struct ast_str ** | buf, | |||
ssize_t | len | |||
) | [static] |
Definition at line 457 of file func_env.c.
References ast_str_set(), FF_DOS, FF_MAC, FF_UNIX, and file2format().
Referenced by file2format(), file_count_line(), file_read(), and file_write().
00458 { 00459 enum file_format newline_format = file2format(data); 00460 ast_str_set(buf, len, "%c", newline_format == FF_UNIX ? 'u' : newline_format == FF_DOS ? 'd' : newline_format == FF_MAC ? 'm' : 'x'); 00461 return 0; 00462 }
static int file_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
struct ast_str ** | buf, | |||
ssize_t | len | |||
) | [static] |
Definition at line 464 of file func_env.c.
References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_str_append_substr(), ast_str_reset(), errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file2format(), file_format(), format, LINE_COUNTER, LLONG_MAX, LOG_ERROR, and LOG_WARNING.
00465 { 00466 FILE *ff; 00467 int64_t offset = 0, length = LLONG_MAX; 00468 enum file_format format = FF_UNKNOWN; 00469 char fbuf[4096]; 00470 int64_t flength, i; /* iterator needs to be signed, so it can go negative and terminate the loop */ 00471 int64_t offset_offset = -1, length_offset = -1; 00472 char dos_state = 0; 00473 size_t readlen; 00474 AST_DECLARE_APP_ARGS(args, 00475 AST_APP_ARG(filename); 00476 AST_APP_ARG(offset); 00477 AST_APP_ARG(length); 00478 AST_APP_ARG(options); 00479 AST_APP_ARG(fileformat); 00480 ); 00481 00482 AST_STANDARD_APP_ARGS(args, data); 00483 00484 if (args.argc > 1) { 00485 sscanf(args.offset, "%" SCNd64, &offset); 00486 } 00487 if (args.argc > 2) { 00488 sscanf(args.length, "%" SCNd64, &length); 00489 } 00490 00491 if (args.argc < 4 || !strchr(args.options, 'l')) { 00492 /* Character-based mode */ 00493 off_t off_i; 00494 00495 if (!(ff = fopen(args.filename, "r"))) { 00496 ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", args.filename, strerror(errno)); 00497 return 0; 00498 } 00499 00500 if (fseeko(ff, 0, SEEK_END) < 0) { 00501 ast_log(LOG_ERROR, "Cannot seek to end of '%s': %s\n", args.filename, strerror(errno)); 00502 fclose(ff); 00503 return -1; 00504 } 00505 flength = ftello(ff); 00506 00507 if (offset < 0) { 00508 fseeko(ff, offset, SEEK_END); 00509 offset = ftello(ff); 00510 } 00511 if (length < 0) { 00512 fseeko(ff, length, SEEK_END); 00513 if ((length = ftello(ff)) - offset < 0) { 00514 /* Eliminates all results */ 00515 fclose(ff); 00516 return -1; 00517 } 00518 } else if (length == LLONG_MAX) { 00519 fseeko(ff, 0, SEEK_END); 00520 length = ftello(ff); 00521 } 00522 00523 ast_str_reset(*buf); 00524 00525 fseeko(ff, offset, SEEK_SET); 00526 for (off_i = ftello(ff); off_i < flength && off_i < offset + length; off_i += sizeof(fbuf)) { 00527 /* Calculate if we need to retrieve just a portion of the file in memory */ 00528 size_t toappend = sizeof(fbuf); 00529 00530 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 00531 ast_log(LOG_ERROR, "Short read?!!\n"); 00532 break; 00533 } 00534 00535 /* Don't go past the length requested */ 00536 if (off_i + toappend > offset + length) { 00537 toappend = length - off_i; 00538 } 00539 00540 ast_str_append_substr(buf, len, fbuf, toappend); 00541 } 00542 fclose(ff); 00543 return 0; 00544 } 00545 00546 /* Line-based read */ 00547 if (args.argc == 5) { 00548 if (tolower(args.fileformat[0]) == 'd') { 00549 format = FF_DOS; 00550 } else if (tolower(args.fileformat[0]) == 'm') { 00551 format = FF_MAC; 00552 } else if (tolower(args.fileformat[0]) == 'u') { 00553 format = FF_UNIX; 00554 } 00555 } 00556 00557 if (format == FF_UNKNOWN) { 00558 if ((format = file2format(args.filename)) == FF_UNKNOWN) { 00559 ast_log(LOG_WARNING, "'%s' is not a line-based file\n", args.filename); 00560 return -1; 00561 } 00562 } 00563 00564 if (offset < 0 && length <= offset) { 00565 /* Length eliminates all content */ 00566 return -1; 00567 } else if (offset == 0) { 00568 offset_offset = 0; 00569 } 00570 00571 if (!(ff = fopen(args.filename, "r"))) { 00572 ast_log(LOG_ERROR, "Cannot open '%s': %s\n", args.filename, strerror(errno)); 00573 return -1; 00574 } 00575 00576 if (fseek(ff, 0, SEEK_END)) { 00577 ast_log(LOG_ERROR, "Cannot seek to end of file '%s': %s\n", args.filename, strerror(errno)); 00578 fclose(ff); 00579 return -1; 00580 } 00581 00582 flength = ftello(ff); 00583 00584 if (length == LLONG_MAX) { 00585 length_offset = flength; 00586 } 00587 00588 /* For negative offset and/or negative length */ 00589 if (offset < 0 || length < 0) { 00590 int64_t count = 0; 00591 /* Start with an even multiple of fbuf, so at the end of reading with a 00592 * 0 offset, we don't try to go past the beginning of the file. */ 00593 for (i = (flength / sizeof(fbuf)) * sizeof(fbuf); i >= 0; i -= sizeof(fbuf)) { 00594 size_t end; 00595 char *pos; 00596 if (fseeko(ff, i, SEEK_SET)) { 00597 ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno)); 00598 } 00599 end = fread(fbuf, 1, sizeof(fbuf), ff); 00600 for (pos = end < sizeof(fbuf) ? fbuf + end - 1 : fbuf + sizeof(fbuf) - 1; pos > fbuf - 1; pos--) { 00601 LINE_COUNTER(pos, format, count); 00602 00603 if (length < 0 && count * -1 == length) { 00604 length_offset = i + (pos - fbuf); 00605 } else if (offset < 0 && count * -1 == (offset - 1)) { 00606 /* Found our initial offset. We're done with reverse motion! */ 00607 if (format == FF_DOS) { 00608 offset_offset = i + (pos - fbuf) + 2; 00609 } else { 00610 offset_offset = i + (pos - fbuf) + 1; 00611 } 00612 break; 00613 } 00614 } 00615 if ((offset < 0 && offset_offset >= 0) || (offset >= 0 && length_offset >= 0)) { 00616 break; 00617 } 00618 } 00619 /* We're at the beginning, and the negative offset indicates the exact number of lines in the file */ 00620 if (offset < 0 && offset_offset < 0 && offset == count * -1) { 00621 offset_offset = 0; 00622 } 00623 } 00624 00625 /* Positve line offset */ 00626 if (offset > 0) { 00627 int64_t count = 0; 00628 fseek(ff, 0, SEEK_SET); 00629 for (i = 0; i < flength; i += sizeof(fbuf)) { 00630 char *pos; 00631 if (i + sizeof(fbuf) <= flength) { 00632 /* Don't let previous values influence current counts, due to short reads */ 00633 memset(fbuf, 0, sizeof(fbuf)); 00634 } 00635 if (fread(fbuf, 1, sizeof(fbuf), ff) && !feof(ff)) { 00636 ast_log(LOG_ERROR, "Short read?!!\n"); 00637 fclose(ff); 00638 return -1; 00639 } 00640 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) { 00641 LINE_COUNTER(pos, format, count); 00642 00643 if (count == offset) { 00644 offset_offset = i + (pos - fbuf) + 1; 00645 break; 00646 } 00647 } 00648 if (offset_offset >= 0) { 00649 break; 00650 } 00651 } 00652 } 00653 00654 if (offset_offset < 0) { 00655 ast_log(LOG_ERROR, "Offset '%s' refers to before the beginning of the file!\n", args.offset); 00656 fclose(ff); 00657 return -1; 00658 } 00659 00660 ast_str_reset(*buf); 00661 if (fseeko(ff, offset_offset, SEEK_SET)) { 00662 ast_log(LOG_ERROR, "fseeko failed: %s\n", strerror(errno)); 00663 } 00664 00665 /* If we have both offset_offset and length_offset, then grabbing the 00666 * buffer is simply a matter of just retrieving the file and adding it 00667 * to buf. Otherwise, we need to run byte-by-byte forward until the 00668 * length is complete. */ 00669 if (length_offset >= 0) { 00670 ast_debug(3, "offset=%" PRId64 ", length=%" PRId64 ", offset_offset=%" PRId64 ", length_offset=%" PRId64 "\n", offset, length, offset_offset, length_offset); 00671 for (i = offset_offset; i < length_offset; i += sizeof(fbuf)) { 00672 if (fread(fbuf, 1, i + sizeof(fbuf) > flength ? flength - i : sizeof(fbuf), ff) < (i + sizeof(fbuf) > flength ? flength - i : sizeof(fbuf))) { 00673 ast_log(LOG_ERROR, "Short read?!!\n"); 00674 } 00675 ast_debug(3, "Appending first %" PRId64" bytes of fbuf=%s\n", i + sizeof(fbuf) > length_offset ? length_offset - i : sizeof(fbuf), fbuf); 00676 ast_str_append_substr(buf, len, fbuf, i + sizeof(fbuf) > length_offset ? length_offset - i : sizeof(fbuf)); 00677 } 00678 } else if (length == 0) { 00679 /* Nothing to do */ 00680 } else { 00681 /* Positive line offset */ 00682 int64_t current_length = 0; 00683 char dos_state = 0; 00684 ast_debug(3, "offset=%" PRId64 ", length=%" PRId64 ", offset_offset=%" PRId64 ", length_offset=%" PRId64 "\n", offset, length, offset_offset, length_offset); 00685 for (i = offset_offset; i < flength; i += sizeof(fbuf)) { 00686 char *pos; 00687 if ((readlen = fread(fbuf, 1, sizeof(fbuf), ff)) < sizeof(fbuf) && !feof(ff)) { 00688 ast_log(LOG_ERROR, "Short read?!!\n"); 00689 } 00690 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) { 00691 LINE_COUNTER(pos, format, current_length); 00692 00693 if (current_length == length) { 00694 length_offset = i + (pos - fbuf) + 1; 00695 break; 00696 } 00697 } 00698 ast_debug(3, "length_offset=%" PRId64 ", length_offset - i=%" PRId64 "\n", length_offset, length_offset - i); 00699 ast_str_append_substr(buf, len, fbuf, length_offset >= 0 ? length_offset - i : flength > i + sizeof(fbuf)) ? sizeof(fbuf) : flength - i; 00700 00701 if (length_offset >= 0) { 00702 break; 00703 } 00704 } 00705 } 00706 00707 fclose(ff); 00708 return 0; 00709 }
static int file_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 718 of file func_env.c.
References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file2format(), file_format(), format, format2term(), fwrite, LINE_COUNTER, LLONG_MAX, LOG_ERROR, LOG_WARNING, and S_OR.
00719 { 00720 AST_DECLARE_APP_ARGS(args, 00721 AST_APP_ARG(filename); 00722 AST_APP_ARG(offset); 00723 AST_APP_ARG(length); 00724 AST_APP_ARG(options); 00725 AST_APP_ARG(format); 00726 ); 00727 int64_t offset = 0, length = LLONG_MAX; 00728 off_t flength, vlength; 00729 size_t foplen = 0; 00730 FILE *ff; 00731 00732 AST_STANDARD_APP_ARGS(args, data); 00733 00734 if (args.argc > 1) { 00735 sscanf(args.offset, "%" SCNd64, &offset); 00736 } 00737 if (args.argc > 2) { 00738 sscanf(args.length, "%" SCNd64, &length); 00739 } 00740 00741 vlength = strlen(value); 00742 00743 if (args.argc < 4 || !strchr(args.options, 'l')) { 00744 /* Character-based mode */ 00745 00746 if (args.argc > 3 && strchr(args.options, 'a')) { 00747 /* Append mode */ 00748 if (!(ff = fopen(args.filename, "a"))) { 00749 ast_log(LOG_WARNING, "Cannot open file '%s' for appending: %s\n", args.filename, strerror(errno)); 00750 return 0; 00751 } 00752 if (fwrite(value, 1, vlength, ff) < vlength) { 00753 ast_log(LOG_ERROR, "Short write?!!\n"); 00754 } 00755 fclose(ff); 00756 return 0; 00757 } else if (offset == 0 && length == LLONG_MAX) { 00758 if (!(ff = fopen(args.filename, "w"))) { 00759 ast_log(LOG_WARNING, "Cannot open file '%s' for writing: %s\n", args.filename, strerror(errno)); 00760 return 0; 00761 } 00762 if (fwrite(value, 1, vlength, ff) < vlength) { 00763 ast_log(LOG_ERROR, "Short write?!!\n"); 00764 } 00765 fclose(ff); 00766 return 0; 00767 } 00768 00769 if (!(ff = fopen(args.filename, "r+"))) { 00770 ast_log(LOG_WARNING, "Cannot open file '%s' for modification: %s\n", args.filename, strerror(errno)); 00771 return 0; 00772 } 00773 fseeko(ff, 0, SEEK_END); 00774 flength = ftello(ff); 00775 00776 if (offset < 0) { 00777 if (fseeko(ff, offset, SEEK_END)) { 00778 ast_log(LOG_ERROR, "Cannot seek to offset: %s\n", strerror(errno)); 00779 fclose(ff); 00780 return -1; 00781 } 00782 offset = ftello(ff); 00783 } 00784 00785 if (length < 0) { 00786 length = flength - offset + length; 00787 if (length < 0) { 00788 ast_log(LOG_ERROR, "Length '%s' exceeds the file length. No data will be written.\n", args.length); 00789 fclose(ff); 00790 return -1; 00791 } 00792 } 00793 00794 fseeko(ff, offset, SEEK_SET); 00795 00796 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 ", vlength=%" PRId64 ", flength=%" PRId64 "\n", 00797 S_OR(args.offset, "(null)"), offset, S_OR(args.length, "(null)"), length, vlength, flength); 00798 00799 if (length == vlength) { 00800 /* Simplest case, a straight replace */ 00801 if (fwrite(value, 1, vlength, ff) < vlength) { 00802 ast_log(LOG_ERROR, "Short write?!!\n"); 00803 } 00804 fclose(ff); 00805 } else if (length == LLONG_MAX) { 00806 /* Simple truncation */ 00807 if (fwrite(value, 1, vlength, ff) < vlength) { 00808 ast_log(LOG_ERROR, "Short write?!!\n"); 00809 } 00810 fclose(ff); 00811 if (truncate(args.filename, offset + vlength)) { 00812 ast_log(LOG_ERROR, "Unable to truncate the file: %s\n", strerror(errno)); 00813 } 00814 } else if (length > vlength) { 00815 /* More complex -- need to close a gap */ 00816 char fbuf[4096]; 00817 off_t cur; 00818 if (fwrite(value, 1, vlength, ff) < vlength) { 00819 ast_log(LOG_ERROR, "Short write?!!\n"); 00820 } 00821 fseeko(ff, length - vlength, SEEK_CUR); 00822 while ((cur = ftello(ff)) < flength) { 00823 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 00824 ast_log(LOG_ERROR, "Short read?!!\n"); 00825 } 00826 fseeko(ff, cur + vlength - length, SEEK_SET); 00827 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 00828 ast_log(LOG_ERROR, "Short write?!!\n"); 00829 } 00830 /* Seek to where we stopped reading */ 00831 if (fseeko(ff, cur + sizeof(fbuf), SEEK_SET) < 0) { 00832 /* Only reason for seek to fail is EOF */ 00833 break; 00834 } 00835 } 00836 fclose(ff); 00837 if (truncate(args.filename, flength - (length - vlength))) { 00838 ast_log(LOG_ERROR, "Unable to truncate the file: %s\n", strerror(errno)); 00839 } 00840 } else { 00841 /* Most complex -- need to open a gap */ 00842 char fbuf[4096]; 00843 off_t lastwritten = flength + vlength - length; 00844 00845 /* Start reading exactly the buffer size back from the end. */ 00846 fseeko(ff, flength - sizeof(fbuf), SEEK_SET); 00847 while (offset < ftello(ff)) { 00848 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 00849 ast_log(LOG_ERROR, "Short read?!!\n"); 00850 fclose(ff); 00851 return -1; 00852 } 00853 /* Since the read moved our file ptr forward, we reverse, but 00854 * seek an offset equal to the amount we want to extend the 00855 * file by */ 00856 fseeko(ff, vlength - length - sizeof(fbuf), SEEK_CUR); 00857 00858 /* Note the location of this buffer -- we must not overwrite this position. */ 00859 lastwritten = ftello(ff); 00860 00861 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 00862 ast_log(LOG_ERROR, "Short write?!!\n"); 00863 fclose(ff); 00864 return -1; 00865 } 00866 00867 if (lastwritten < offset + sizeof(fbuf)) { 00868 break; 00869 } 00870 /* Our file pointer is now either pointing to the end of the 00871 * file (new position) or a multiple of the fbuf size back from 00872 * that point. Move back to where we want to start reading 00873 * again. We never actually try to read beyond the end of the 00874 * file, so we don't have do deal with short reads, as we would 00875 * when we're shortening the file. */ 00876 fseeko(ff, 2 * sizeof(fbuf) + vlength - length, SEEK_CUR); 00877 } 00878 00879 /* Last part of the file that we need to preserve */ 00880 if (fseeko(ff, offset + length, SEEK_SET)) { 00881 ast_log(LOG_WARNING, "Unable to seek to %" PRId64 " + %" PRId64 " != %" PRId64 "?)\n", offset, length, ftello(ff)); 00882 } 00883 00884 /* Doesn't matter how much we read -- just need to restrict the write */ 00885 ast_debug(1, "Reading at %" PRId64 "\n", ftello(ff)); 00886 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 00887 ast_log(LOG_ERROR, "Short read?!!\n"); 00888 } 00889 fseek(ff, offset, SEEK_SET); 00890 /* Write out the value, then write just up until where we last moved some data */ 00891 if (fwrite(value, 1, vlength, ff) < vlength) { 00892 ast_log(LOG_ERROR, "Short write?!!\n"); 00893 } else { 00894 off_t curpos = ftello(ff); 00895 foplen = lastwritten - curpos; 00896 if (fwrite(fbuf, 1, foplen, ff) < foplen) { 00897 ast_log(LOG_ERROR, "Short write?!!\n"); 00898 } 00899 } 00900 fclose(ff); 00901 } 00902 } else { 00903 enum file_format newline_format = FF_UNKNOWN; 00904 00905 /* Line mode */ 00906 if (args.argc == 5) { 00907 if (tolower(args.format[0]) == 'u') { 00908 newline_format = FF_UNIX; 00909 } else if (tolower(args.format[0]) == 'm') { 00910 newline_format = FF_MAC; 00911 } else if (tolower(args.format[0]) == 'd') { 00912 newline_format = FF_DOS; 00913 } 00914 } 00915 if (newline_format == FF_UNKNOWN && (newline_format = file2format(args.filename)) == FF_UNKNOWN) { 00916 ast_log(LOG_ERROR, "File '%s' not in line format\n", args.filename); 00917 return -1; 00918 } 00919 00920 if (strchr(args.options, 'a')) { 00921 /* Append to file */ 00922 if (!(ff = fopen(args.filename, "a"))) { 00923 ast_log(LOG_ERROR, "Unable to open '%s' for appending: %s\n", args.filename, strerror(errno)); 00924 return -1; 00925 } 00926 if (fwrite(value, 1, vlength, ff) < vlength) { 00927 ast_log(LOG_ERROR, "Short write?!!\n"); 00928 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) { 00929 ast_log(LOG_ERROR, "Short write?!!\n"); 00930 } 00931 fclose(ff); 00932 } else if (offset == 0 && length == LLONG_MAX) { 00933 /* Overwrite file */ 00934 off_t truncsize; 00935 if (!(ff = fopen(args.filename, "w"))) { 00936 ast_log(LOG_ERROR, "Unable to open '%s' for writing: %s\n", args.filename, strerror(errno)); 00937 return -1; 00938 } 00939 if (fwrite(value, 1, vlength, ff) < vlength) { 00940 ast_log(LOG_ERROR, "Short write?!!\n"); 00941 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) { 00942 ast_log(LOG_ERROR, "Short write?!!\n"); 00943 } 00944 truncsize = ftello(ff); 00945 fclose(ff); 00946 if (truncate(args.filename, truncsize)) { 00947 ast_log(LOG_ERROR, "Unable to truncate file: %s\n", strerror(errno)); 00948 } 00949 } else { 00950 int64_t offset_offset = (offset == 0 ? 0 : -1), length_offset = -1, flength, i, current_length = 0; 00951 char dos_state = 0, fbuf[4096]; 00952 00953 if (offset < 0 && length < offset) { 00954 /* Nonsense! */ 00955 ast_log(LOG_ERROR, "Length cannot specify a position prior to the offset\n"); 00956 return -1; 00957 } 00958 00959 if (!(ff = fopen(args.filename, "r+"))) { 00960 ast_log(LOG_ERROR, "Cannot open '%s' for modification: %s\n", args.filename, strerror(errno)); 00961 return -1; 00962 } 00963 00964 if (fseek(ff, 0, SEEK_END)) { 00965 ast_log(LOG_ERROR, "Cannot seek to end of file '%s': %s\n", args.filename, strerror(errno)); 00966 fclose(ff); 00967 return -1; 00968 } 00969 flength = ftello(ff); 00970 00971 /* For negative offset and/or negative length */ 00972 if (offset < 0 || length < 0) { 00973 int64_t count = 0; 00974 for (i = (flength / sizeof(fbuf)) * sizeof(fbuf); i >= 0; i -= sizeof(fbuf)) { 00975 char *pos; 00976 if (fseeko(ff, i, SEEK_SET)) { 00977 ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno)); 00978 } 00979 if (i + sizeof(fbuf) >= flength) { 00980 memset(fbuf, 0, sizeof(fbuf)); 00981 } 00982 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 00983 ast_log(LOG_ERROR, "Short read: %s\n", strerror(errno)); 00984 fclose(ff); 00985 return -1; 00986 } 00987 for (pos = fbuf + sizeof(fbuf) - 1; pos > fbuf - 1; pos--) { 00988 LINE_COUNTER(pos, newline_format, count); 00989 00990 if (length < 0 && count * -1 == length) { 00991 length_offset = i + (pos - fbuf); 00992 } else if (offset < 0 && count * -1 == (offset - 1)) { 00993 /* Found our initial offset. We're done with reverse motion! */ 00994 if (newline_format == FF_DOS) { 00995 offset_offset = i + (pos - fbuf) + 2; 00996 } else { 00997 offset_offset = i + (pos - fbuf) + 1; 00998 } 00999 break; 01000 } 01001 } 01002 if ((offset < 0 && offset_offset >= 0) || (offset >= 0 && length_offset >= 0)) { 01003 break; 01004 } 01005 } 01006 /* We're at the beginning, and the negative offset indicates the exact number of lines in the file */ 01007 if (offset < 0 && offset_offset < 0 && offset == count * -1) { 01008 offset_offset = 0; 01009 } 01010 } 01011 01012 /* Positve line offset */ 01013 if (offset > 0) { 01014 int64_t count = 0; 01015 fseek(ff, 0, SEEK_SET); 01016 for (i = 0; i < flength; i += sizeof(fbuf)) { 01017 char *pos; 01018 if (i + sizeof(fbuf) >= flength) { 01019 memset(fbuf, 0, sizeof(fbuf)); 01020 } 01021 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 01022 ast_log(LOG_ERROR, "Short read?!!\n"); 01023 fclose(ff); 01024 return -1; 01025 } 01026 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) { 01027 LINE_COUNTER(pos, newline_format, count); 01028 01029 if (count == offset) { 01030 offset_offset = i + (pos - fbuf) + 1; 01031 break; 01032 } 01033 } 01034 if (offset_offset >= 0) { 01035 break; 01036 } 01037 } 01038 } 01039 01040 if (offset_offset < 0) { 01041 ast_log(LOG_ERROR, "Offset '%s' refers to before the beginning of the file!\n", args.offset); 01042 fclose(ff); 01043 return -1; 01044 } 01045 01046 if (length == 0) { 01047 length_offset = offset_offset; 01048 } else if (length == LLONG_MAX) { 01049 length_offset = flength; 01050 } 01051 01052 /* Positive line length */ 01053 if (length_offset < 0) { 01054 fseeko(ff, offset_offset, SEEK_SET); 01055 for (i = offset_offset; i < flength; i += sizeof(fbuf)) { 01056 char *pos; 01057 if (i + sizeof(fbuf) >= flength) { 01058 memset(fbuf, 0, sizeof(fbuf)); 01059 } 01060 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 01061 ast_log(LOG_ERROR, "Short read?!!\n"); 01062 fclose(ff); 01063 return -1; 01064 } 01065 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) { 01066 LINE_COUNTER(pos, newline_format, current_length); 01067 01068 if (current_length == length) { 01069 length_offset = i + (pos - fbuf) + 1; 01070 break; 01071 } 01072 } 01073 if (length_offset >= 0) { 01074 break; 01075 } 01076 } 01077 if (length_offset < 0) { 01078 /* Exceeds length of file */ 01079 ast_debug(3, "Exceeds length of file? length=%" PRId64 ", count=%" PRId64 ", flength=%" PRId64 "\n", length, current_length, flength); 01080 length_offset = flength; 01081 } 01082 } 01083 01084 /* Have offset_offset and length_offset now */ 01085 if (length_offset - offset_offset == vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)))) { 01086 /* Simple case - replacement of text inline */ 01087 fseeko(ff, offset_offset, SEEK_SET); 01088 if (fwrite(value, 1, vlength, ff) < vlength) { 01089 ast_log(LOG_ERROR, "Short write?!!\n"); 01090 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) { 01091 ast_log(LOG_ERROR, "Short write?!!\n"); 01092 } 01093 fclose(ff); 01094 } else if (length_offset - offset_offset > vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)))) { 01095 /* More complex case - need to shorten file */ 01096 off_t cur; 01097 int64_t length_length = length_offset - offset_offset; 01098 size_t vlen = vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format))); 01099 01100 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 " (%" PRId64 "), vlength=%" PRId64 ", flength=%" PRId64 "\n", 01101 args.offset, offset_offset, args.length, length_offset, length_length, vlength, flength); 01102 01103 fseeko(ff, offset_offset, SEEK_SET); 01104 if (fwrite(value, 1, vlength, ff) < vlength) { 01105 ast_log(LOG_ERROR, "Short write?!!\n"); 01106 fclose(ff); 01107 return -1; 01108 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, vlen - vlength, ff) < vlen - vlength) { 01109 ast_log(LOG_ERROR, "Short write?!!\n"); 01110 fclose(ff); 01111 return -1; 01112 } 01113 while ((cur = ftello(ff)) < flength) { 01114 fseeko(ff, length_length - vlen, SEEK_CUR); 01115 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 01116 ast_log(LOG_ERROR, "Short read?!!\n"); 01117 fclose(ff); 01118 return -1; 01119 } 01120 /* Seek to where we last stopped writing */ 01121 fseeko(ff, cur, SEEK_SET); 01122 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 01123 ast_log(LOG_ERROR, "Short write?!!\n"); 01124 fclose(ff); 01125 return -1; 01126 } 01127 } 01128 fclose(ff); 01129 if (truncate(args.filename, flength - (length_length - vlen))) { 01130 ast_log(LOG_ERROR, "Truncation of file failed: %s\n", strerror(errno)); 01131 } 01132 } else { 01133 /* Most complex case - need to lengthen file */ 01134 size_t vlen = vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format))); 01135 int64_t origlen = length_offset - offset_offset; 01136 off_t lastwritten = flength + vlen - origlen; 01137 01138 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 ", vlength=%" PRId64 ", flength=%" PRId64 "\n", 01139 args.offset, offset_offset, args.length, length_offset, vlength, flength); 01140 01141 fseeko(ff, flength - sizeof(fbuf), SEEK_SET); 01142 while (offset_offset + sizeof(fbuf) < ftello(ff)) { 01143 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 01144 ast_log(LOG_ERROR, "Short read?!!\n"); 01145 fclose(ff); 01146 return -1; 01147 } 01148 fseeko(ff, sizeof(fbuf) - vlen - origlen, SEEK_CUR); 01149 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 01150 ast_log(LOG_ERROR, "Short write?!!\n"); 01151 fclose(ff); 01152 return -1; 01153 } 01154 if ((lastwritten = ftello(ff) - sizeof(fbuf)) < offset_offset + sizeof(fbuf)) { 01155 break; 01156 } 01157 fseeko(ff, 2 * sizeof(fbuf) + vlen - origlen, SEEK_CUR); 01158 } 01159 fseek(ff, length_offset, SEEK_SET); 01160 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 01161 ast_log(LOG_ERROR, "Short read?!!\n"); 01162 fclose(ff); 01163 return -1; 01164 } 01165 fseek(ff, offset_offset, SEEK_SET); 01166 if (fwrite(value, 1, vlength, ff) < vlength) { 01167 ast_log(LOG_ERROR, "Short write?!!\n"); 01168 fclose(ff); 01169 return -1; 01170 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) { 01171 ast_log(LOG_ERROR, "Short write?!!\n"); 01172 fclose(ff); 01173 return -1; 01174 } else { 01175 off_t curpos = ftello(ff); 01176 foplen = lastwritten - curpos; 01177 if (fwrite(fbuf, 1, foplen, ff) < foplen) { 01178 ast_log(LOG_ERROR, "Short write?!!\n"); 01179 } 01180 } 01181 fclose(ff); 01182 } 01183 } 01184 } 01185 01186 return 0; 01187 }
const char * format2term | ( | enum file_format | f | ) |
Definition at line 712 of file func_env.c.
Referenced by file_write().
00713 { 00714 const char *term[] = { "", "\n", "\r\n", "\r" }; 00715 return term[f + 1]; 00716 }
static int load_module | ( | void | ) | [static] |
Definition at line 1232 of file func_env.c.
References ast_custom_function_register, env_function, file_count_line_function, file_format_function, file_function, and stat_function.
01233 { 01234 int res = 0; 01235 01236 res |= ast_custom_function_register(&env_function); 01237 res |= ast_custom_function_register(&stat_function); 01238 res |= ast_custom_function_register(&file_function); 01239 res |= ast_custom_function_register(&file_count_line_function); 01240 res |= ast_custom_function_register(&file_format_function); 01241 01242 return res; 01243 }
static int stat_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 253 of file func_env.c.
References ast_copy_string(), and strsep().
00255 { 00256 char *action; 00257 struct stat s; 00258 00259 ast_copy_string(buf, "0", len); 00260 00261 action = strsep(&data, ","); 00262 if (stat(data, &s)) { 00263 return 0; 00264 } else { 00265 switch (*action) { 00266 case 'e': 00267 strcpy(buf, "1"); 00268 break; 00269 case 's': 00270 snprintf(buf, len, "%d", (unsigned int) s.st_size); 00271 break; 00272 case 'f': 00273 snprintf(buf, len, "%d", S_ISREG(s.st_mode) ? 1 : 0); 00274 break; 00275 case 'd': 00276 snprintf(buf, len, "%d", S_ISDIR(s.st_mode) ? 1 : 0); 00277 break; 00278 case 'M': 00279 snprintf(buf, len, "%d", (int) s.st_mtime); 00280 break; 00281 case 'A': 00282 snprintf(buf, len, "%d", (int) s.st_mtime); 00283 break; 00284 case 'C': 00285 snprintf(buf, len, "%d", (int) s.st_ctime); 00286 break; 00287 case 'm': 00288 snprintf(buf, len, "%o", (int) s.st_mode); 00289 break; 00290 } 00291 } 00292 00293 return 0; 00294 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1219 of file func_env.c.
References ast_custom_function_unregister(), env_function, file_count_line_function, file_format_function, file_function, and stat_function.
01220 { 01221 int res = 0; 01222 01223 res |= ast_custom_function_unregister(&env_function); 01224 res |= ast_custom_function_unregister(&stat_function); 01225 res |= ast_custom_function_unregister(&file_function); 01226 res |= ast_custom_function_unregister(&file_count_line_function); 01227 res |= ast_custom_function_unregister(&file_format_function); 01228 01229 return res; 01230 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Environment/filesystem dialplan functions" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 1245 of file func_env.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1245 of file func_env.c.
struct ast_custom_function env_function [static] |
Initial value:
Definition at line 1189 of file func_env.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function file_count_line_function [static] |
Initial value:
{ .name = "FILE_COUNT_LINE", .read2 = file_count_line, .read_max = 12, }
Definition at line 1207 of file func_env.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function file_format_function [static] |
Initial value:
{ .name = "FILE_FORMAT", .read2 = file_format, .read_max = 2, }
Definition at line 1213 of file func_env.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function file_function [static] |
Initial value:
{ .name = "FILE", .read2 = file_read, .write = file_write, }
Definition at line 1201 of file func_env.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function stat_function [static] |
Initial value:
{ .name = "STAT", .read = stat_read, .read_max = 12, }
Definition at line 1195 of file func_env.c.
Referenced by load_module(), and unload_module().