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