00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 362358 $")
00031
00032 #include <sys/stat.h>
00033
00034 #include "asterisk/module.h"
00035 #include "asterisk/channel.h"
00036 #include "asterisk/pbx.h"
00037 #include "asterisk/utils.h"
00038 #include "asterisk/app.h"
00039 #include "asterisk/file.h"
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 static int env_read(struct ast_channel *chan, const char *cmd, char *data,
00228 char *buf, size_t len)
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 }
00242
00243 static int env_write(struct ast_channel *chan, const char *cmd, char *data,
00244 const char *value)
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 }
00256
00257 static int stat_read(struct ast_channel *chan, const char *cmd, char *data,
00258 char *buf, size_t len)
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 }
00299
00300 enum file_format {
00301 FF_UNKNOWN = -1,
00302 FF_UNIX,
00303 FF_DOS,
00304 FF_MAC,
00305 };
00306
00307 static int64_t count_lines(const char *filename, enum file_format newline_format)
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
00322
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
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
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
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
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 }
00381
00382 static int file_count_line(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
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 }
00406
00407 #define LINE_COUNTER(cptr, term, counter) \
00408 if (*cptr == '\n' && term == FF_UNIX) { \
00409 counter++; \
00410 } else if (*cptr == '\n' && term == FF_DOS && dos_state == 0) { \
00411 dos_state = 1; \
00412 } else if (*cptr == '\r' && term == FF_DOS && dos_state == 1) { \
00413 dos_state = 0; \
00414 counter++; \
00415 } else if (*cptr == '\r' && term == FF_MAC) { \
00416 counter++; \
00417 } else if (term == FF_DOS) { \
00418 dos_state = 0; \
00419 }
00420
00421 static enum file_format file2format(const char *filename)
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
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 }
00460
00461 static int file_format(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
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 }
00467
00468 static int file_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
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;
00475 int64_t offset_offset = -1, length_offset = -1;
00476 char dos_state = 0;
00477 AST_DECLARE_APP_ARGS(args,
00478 AST_APP_ARG(filename);
00479 AST_APP_ARG(offset);
00480 AST_APP_ARG(length);
00481 AST_APP_ARG(options);
00482 AST_APP_ARG(fileformat);
00483 );
00484
00485 AST_STANDARD_APP_ARGS(args, data);
00486
00487 if (args.argc > 1) {
00488 sscanf(args.offset, "%" SCNd64, &offset);
00489 }
00490 if (args.argc > 2) {
00491 sscanf(args.length, "%" SCNd64, &length);
00492 }
00493
00494 if (args.argc < 4 || !strchr(args.options, 'l')) {
00495
00496 off_t off_i;
00497
00498 if (!(ff = fopen(args.filename, "r"))) {
00499 ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", args.filename, strerror(errno));
00500 return 0;
00501 }
00502
00503 if (fseeko(ff, 0, SEEK_END) < 0) {
00504 ast_log(LOG_ERROR, "Cannot seek to end of '%s': %s\n", args.filename, strerror(errno));
00505 fclose(ff);
00506 return -1;
00507 }
00508 flength = ftello(ff);
00509
00510 if (offset < 0) {
00511 fseeko(ff, offset, SEEK_END);
00512 if ((offset = ftello(ff)) < 0) {
00513 ast_log(AST_LOG_ERROR, "Cannot determine offset position of '%s': %s\n", args.filename, strerror(errno));
00514 fclose(ff);
00515 return -1;
00516 }
00517 }
00518 if (length < 0) {
00519 fseeko(ff, length, SEEK_END);
00520 if ((length = ftello(ff)) - offset < 0) {
00521
00522 fclose(ff);
00523 return -1;
00524 }
00525 } else if (length == LLONG_MAX) {
00526 fseeko(ff, 0, SEEK_END);
00527 length = ftello(ff);
00528 }
00529
00530 ast_str_reset(*buf);
00531
00532 fseeko(ff, offset, SEEK_SET);
00533 for (off_i = ftello(ff); off_i < flength && off_i < offset + length; off_i += sizeof(fbuf)) {
00534
00535 size_t toappend = sizeof(fbuf);
00536
00537 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
00538 ast_log(LOG_ERROR, "Short read?!!\n");
00539 break;
00540 }
00541
00542
00543 if (off_i + toappend > offset + length) {
00544 toappend = length - off_i;
00545 }
00546
00547 ast_str_append_substr(buf, len, fbuf, toappend);
00548 }
00549 fclose(ff);
00550 return 0;
00551 }
00552
00553
00554 if (args.argc == 5) {
00555 if (tolower(args.fileformat[0]) == 'd') {
00556 format = FF_DOS;
00557 } else if (tolower(args.fileformat[0]) == 'm') {
00558 format = FF_MAC;
00559 } else if (tolower(args.fileformat[0]) == 'u') {
00560 format = FF_UNIX;
00561 }
00562 }
00563
00564 if (format == FF_UNKNOWN) {
00565 if ((format = file2format(args.filename)) == FF_UNKNOWN) {
00566 ast_log(LOG_WARNING, "'%s' is not a line-based file\n", args.filename);
00567 return -1;
00568 }
00569 }
00570
00571 if (offset < 0 && length <= offset) {
00572
00573 return -1;
00574 } else if (offset == 0) {
00575 offset_offset = 0;
00576 }
00577
00578 if (!(ff = fopen(args.filename, "r"))) {
00579 ast_log(LOG_ERROR, "Cannot open '%s': %s\n", args.filename, strerror(errno));
00580 return -1;
00581 }
00582
00583 if (fseek(ff, 0, SEEK_END)) {
00584 ast_log(LOG_ERROR, "Cannot seek to end of file '%s': %s\n", args.filename, strerror(errno));
00585 fclose(ff);
00586 return -1;
00587 }
00588
00589 flength = ftello(ff);
00590
00591 if (length == LLONG_MAX) {
00592 length_offset = flength;
00593 }
00594
00595
00596 if (offset < 0 || length < 0) {
00597 int64_t count = 0;
00598
00599
00600 for (i = (flength / sizeof(fbuf)) * sizeof(fbuf); i >= 0; i -= sizeof(fbuf)) {
00601 size_t end;
00602 char *pos;
00603 if (fseeko(ff, i, SEEK_SET)) {
00604 ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno));
00605 }
00606 end = fread(fbuf, 1, sizeof(fbuf), ff);
00607 for (pos = (end < sizeof(fbuf) ? fbuf + end - 1 : fbuf + sizeof(fbuf) - 1); pos > fbuf - 1; pos--) {
00608 LINE_COUNTER(pos, format, count);
00609
00610 if (length < 0 && count * -1 == length) {
00611 length_offset = i + (pos - fbuf);
00612 } else if (offset < 0 && count * -1 == (offset - 1)) {
00613
00614 if (format == FF_DOS) {
00615 offset_offset = i + (pos - fbuf) + 2;
00616 } else {
00617 offset_offset = i + (pos - fbuf) + 1;
00618 }
00619 break;
00620 }
00621 }
00622 if ((offset < 0 && offset_offset >= 0) || (offset >= 0 && length_offset >= 0)) {
00623 break;
00624 }
00625 }
00626
00627 if (offset < 0 && offset_offset < 0 && offset == count * -1) {
00628 offset_offset = 0;
00629 }
00630 }
00631
00632
00633 if (offset > 0) {
00634 int64_t count = 0;
00635 fseek(ff, 0, SEEK_SET);
00636 for (i = 0; i < flength; i += sizeof(fbuf)) {
00637 char *pos;
00638 if (i + sizeof(fbuf) <= flength) {
00639
00640 memset(fbuf, 0, sizeof(fbuf));
00641 }
00642 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
00643 ast_log(LOG_ERROR, "Short read?!!\n");
00644 fclose(ff);
00645 return -1;
00646 }
00647 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
00648 LINE_COUNTER(pos, format, count);
00649
00650 if (count == offset) {
00651 offset_offset = i + (pos - fbuf) + 1;
00652 break;
00653 }
00654 }
00655 if (offset_offset >= 0) {
00656 break;
00657 }
00658 }
00659 }
00660
00661 if (offset_offset < 0) {
00662 ast_log(LOG_ERROR, "Offset '%s' refers to before the beginning of the file!\n", args.offset);
00663 fclose(ff);
00664 return -1;
00665 }
00666
00667 ast_str_reset(*buf);
00668 if (fseeko(ff, offset_offset, SEEK_SET)) {
00669 ast_log(LOG_ERROR, "fseeko failed: %s\n", strerror(errno));
00670 }
00671
00672
00673
00674
00675
00676 if (length_offset >= 0) {
00677 ast_debug(3, "offset=%" PRId64 ", length=%" PRId64 ", offset_offset=%" PRId64 ", length_offset=%" PRId64 "\n", offset, length, offset_offset, length_offset);
00678 for (i = offset_offset; i < length_offset; i += sizeof(fbuf)) {
00679 if (fread(fbuf, 1, i + sizeof(fbuf) > flength ? flength - i : sizeof(fbuf), ff) < (i + sizeof(fbuf) > flength ? flength - i : sizeof(fbuf))) {
00680 ast_log(LOG_ERROR, "Short read?!!\n");
00681 }
00682 ast_debug(3, "Appending first %" PRId64" bytes of fbuf=%s\n", i + sizeof(fbuf) > length_offset ? length_offset - i : sizeof(fbuf), fbuf);
00683 ast_str_append_substr(buf, len, fbuf, i + sizeof(fbuf) > length_offset ? length_offset - i : sizeof(fbuf));
00684 }
00685 } else if (length == 0) {
00686
00687 } else {
00688
00689 int64_t current_length = 0;
00690 char dos_state = 0;
00691 ast_debug(3, "offset=%" PRId64 ", length=%" PRId64 ", offset_offset=%" PRId64 ", length_offset=%" PRId64 "\n", offset, length, offset_offset, length_offset);
00692 for (i = offset_offset; i < flength; i += sizeof(fbuf)) {
00693 char *pos;
00694 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
00695 ast_log(LOG_ERROR, "Short read?!!\n");
00696 fclose(ff);
00697 return -1;
00698 }
00699 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
00700 LINE_COUNTER(pos, format, current_length);
00701
00702 if (current_length == length) {
00703 length_offset = i + (pos - fbuf) + 1;
00704 break;
00705 }
00706 }
00707 ast_debug(3, "length_offset=%" PRId64 ", length_offset - i=%" PRId64 "\n", length_offset, length_offset - i);
00708 ast_str_append_substr(buf, len, fbuf, length_offset >= 0 ? length_offset - i : flength > i + sizeof(fbuf)) ? sizeof(fbuf) : flength - i;
00709
00710 if (length_offset >= 0) {
00711 break;
00712 }
00713 }
00714 }
00715
00716 fclose(ff);
00717 return 0;
00718 }
00719
00720 const char *format2term(enum file_format f) __attribute__((const));
00721 const char *format2term(enum file_format f)
00722 {
00723 const char *term[] = { "", "\n", "\r\n", "\r" };
00724 return term[f + 1];
00725 }
00726
00727 static int file_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00728 {
00729 AST_DECLARE_APP_ARGS(args,
00730 AST_APP_ARG(filename);
00731 AST_APP_ARG(offset);
00732 AST_APP_ARG(length);
00733 AST_APP_ARG(options);
00734 AST_APP_ARG(format);
00735 );
00736 int64_t offset = 0, length = LLONG_MAX;
00737 off_t flength, vlength;
00738 size_t foplen = 0;
00739 FILE *ff;
00740
00741 AST_STANDARD_APP_ARGS(args, data);
00742
00743 if (args.argc > 1) {
00744 sscanf(args.offset, "%" SCNd64, &offset);
00745 }
00746 if (args.argc > 2) {
00747 sscanf(args.length, "%" SCNd64, &length);
00748 }
00749
00750 vlength = strlen(value);
00751
00752 if (args.argc < 4 || !strchr(args.options, 'l')) {
00753
00754
00755 if (args.argc > 3 && strchr(args.options, 'a')) {
00756
00757 if (!(ff = fopen(args.filename, "a"))) {
00758 ast_log(LOG_WARNING, "Cannot open file '%s' for appending: %s\n", args.filename, strerror(errno));
00759 return 0;
00760 }
00761 if (fwrite(value, 1, vlength, ff) < vlength) {
00762 ast_log(LOG_ERROR, "Short write?!!\n");
00763 }
00764 fclose(ff);
00765 return 0;
00766 } else if (offset == 0 && length == LLONG_MAX) {
00767 if (!(ff = fopen(args.filename, "w"))) {
00768 ast_log(LOG_WARNING, "Cannot open file '%s' for writing: %s\n", args.filename, strerror(errno));
00769 return 0;
00770 }
00771 if (fwrite(value, 1, vlength, ff) < vlength) {
00772 ast_log(LOG_ERROR, "Short write?!!\n");
00773 }
00774 fclose(ff);
00775 return 0;
00776 }
00777
00778 if (!(ff = fopen(args.filename, "r+"))) {
00779 ast_log(LOG_WARNING, "Cannot open file '%s' for modification: %s\n", args.filename, strerror(errno));
00780 return 0;
00781 }
00782 fseeko(ff, 0, SEEK_END);
00783 flength = ftello(ff);
00784
00785 if (offset < 0) {
00786 if (fseeko(ff, offset, SEEK_END)) {
00787 ast_log(LOG_ERROR, "Cannot seek to offset of '%s': %s\n", args.filename, strerror(errno));
00788 fclose(ff);
00789 return -1;
00790 }
00791 if ((offset = ftello(ff)) < 0) {
00792 ast_log(AST_LOG_ERROR, "Cannot determine offset position of '%s': %s\n", args.filename, strerror(errno));
00793 fclose(ff);
00794 return -1;
00795 }
00796 }
00797
00798 if (length < 0) {
00799 length = flength - offset + length;
00800 if (length < 0) {
00801 ast_log(LOG_ERROR, "Length '%s' exceeds the file length. No data will be written.\n", args.length);
00802 fclose(ff);
00803 return -1;
00804 }
00805 }
00806
00807 fseeko(ff, offset, SEEK_SET);
00808
00809 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 ", vlength=%" PRId64 ", flength=%" PRId64 "\n",
00810 S_OR(args.offset, "(null)"), offset, S_OR(args.length, "(null)"), length, vlength, flength);
00811
00812 if (length == vlength) {
00813
00814 if (fwrite(value, 1, vlength, ff) < vlength) {
00815 ast_log(LOG_ERROR, "Short write?!!\n");
00816 }
00817 fclose(ff);
00818 } else if (length == LLONG_MAX) {
00819
00820 if (fwrite(value, 1, vlength, ff) < vlength) {
00821 ast_log(LOG_ERROR, "Short write?!!\n");
00822 }
00823 fclose(ff);
00824 if (truncate(args.filename, offset + vlength)) {
00825 ast_log(LOG_ERROR, "Unable to truncate the file: %s\n", strerror(errno));
00826 }
00827 } else if (length > vlength) {
00828
00829 char fbuf[4096];
00830 off_t cur;
00831 if (fwrite(value, 1, vlength, ff) < vlength) {
00832 ast_log(LOG_ERROR, "Short write?!!\n");
00833 }
00834 fseeko(ff, length - vlength, SEEK_CUR);
00835 while ((cur = ftello(ff)) < flength) {
00836 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
00837 ast_log(LOG_ERROR, "Short read?!!\n");
00838 }
00839 fseeko(ff, cur + vlength - length, SEEK_SET);
00840 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
00841 ast_log(LOG_ERROR, "Short write?!!\n");
00842 }
00843
00844 if (fseeko(ff, cur + sizeof(fbuf), SEEK_SET) < 0) {
00845
00846 break;
00847 }
00848 }
00849 fclose(ff);
00850 if (truncate(args.filename, flength - (length - vlength))) {
00851 ast_log(LOG_ERROR, "Unable to truncate the file: %s\n", strerror(errno));
00852 }
00853 } else {
00854
00855 char fbuf[4096];
00856 off_t lastwritten = flength + vlength - length;
00857
00858
00859 fseeko(ff, flength - sizeof(fbuf), SEEK_SET);
00860 while (offset < ftello(ff)) {
00861 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
00862 ast_log(LOG_ERROR, "Short read?!!\n");
00863 fclose(ff);
00864 return -1;
00865 }
00866
00867
00868
00869 fseeko(ff, vlength - length - sizeof(fbuf), SEEK_CUR);
00870
00871
00872 lastwritten = ftello(ff);
00873
00874 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
00875 ast_log(LOG_ERROR, "Short write?!!\n");
00876 fclose(ff);
00877 return -1;
00878 }
00879
00880 if (lastwritten < offset + sizeof(fbuf)) {
00881 break;
00882 }
00883
00884
00885
00886
00887
00888
00889 fseeko(ff, 2 * sizeof(fbuf) + vlength - length, SEEK_CUR);
00890 }
00891
00892
00893 if (fseeko(ff, offset + length, SEEK_SET)) {
00894 ast_log(LOG_WARNING, "Unable to seek to %" PRId64 " + %" PRId64 " != %" PRId64 "?)\n", offset, length, ftello(ff));
00895 }
00896
00897
00898 ast_debug(1, "Reading at %" PRId64 "\n", ftello(ff));
00899 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
00900 ast_log(LOG_ERROR, "Short read?!!\n");
00901 }
00902 fseek(ff, offset, SEEK_SET);
00903
00904 if (fwrite(value, 1, vlength, ff) < vlength) {
00905 ast_log(LOG_ERROR, "Short write?!!\n");
00906 } else {
00907 off_t curpos = ftello(ff);
00908 foplen = lastwritten - curpos;
00909 if (fwrite(fbuf, 1, foplen, ff) < foplen) {
00910 ast_log(LOG_ERROR, "Short write?!!\n");
00911 }
00912 }
00913 fclose(ff);
00914 }
00915 } else {
00916 enum file_format newline_format = FF_UNKNOWN;
00917
00918
00919 if (args.argc == 5) {
00920 if (tolower(args.format[0]) == 'u') {
00921 newline_format = FF_UNIX;
00922 } else if (tolower(args.format[0]) == 'm') {
00923 newline_format = FF_MAC;
00924 } else if (tolower(args.format[0]) == 'd') {
00925 newline_format = FF_DOS;
00926 }
00927 }
00928 if (newline_format == FF_UNKNOWN && (newline_format = file2format(args.filename)) == FF_UNKNOWN) {
00929 ast_log(LOG_ERROR, "File '%s' not in line format\n", args.filename);
00930 return -1;
00931 }
00932
00933 if (strchr(args.options, 'a')) {
00934
00935 if (!(ff = fopen(args.filename, "a"))) {
00936 ast_log(LOG_ERROR, "Unable to open '%s' for appending: %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 fclose(ff);
00945 } else if (offset == 0 && length == LLONG_MAX) {
00946
00947 off_t truncsize;
00948 if (!(ff = fopen(args.filename, "w"))) {
00949 ast_log(LOG_ERROR, "Unable to open '%s' for writing: %s\n", args.filename, strerror(errno));
00950 return -1;
00951 }
00952 if (fwrite(value, 1, vlength, ff) < vlength) {
00953 ast_log(LOG_ERROR, "Short write?!!\n");
00954 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
00955 ast_log(LOG_ERROR, "Short write?!!\n");
00956 }
00957 if ((truncsize = ftello(ff)) < 0) {
00958 ast_log(AST_LOG_ERROR, "Unable to determine truncate position of '%s': %s\n", args.filename, strerror(errno));
00959 }
00960 fclose(ff);
00961 if (truncsize >= 0 && truncate(args.filename, truncsize)) {
00962 ast_log(LOG_ERROR, "Unable to truncate file '%s': %s\n", args.filename, strerror(errno));
00963 return -1;
00964 }
00965 } else {
00966 int64_t offset_offset = (offset == 0 ? 0 : -1), length_offset = -1, flength, i, current_length = 0;
00967 char dos_state = 0, fbuf[4096];
00968
00969 if (offset < 0 && length < offset) {
00970
00971 ast_log(LOG_ERROR, "Length cannot specify a position prior to the offset\n");
00972 return -1;
00973 }
00974
00975 if (!(ff = fopen(args.filename, "r+"))) {
00976 ast_log(LOG_ERROR, "Cannot open '%s' for modification: %s\n", args.filename, strerror(errno));
00977 return -1;
00978 }
00979
00980 if (fseek(ff, 0, SEEK_END)) {
00981 ast_log(LOG_ERROR, "Cannot seek to end of file '%s': %s\n", args.filename, strerror(errno));
00982 fclose(ff);
00983 return -1;
00984 }
00985 if ((flength = ftello(ff)) < 0) {
00986 ast_log(AST_LOG_ERROR, "Cannot determine end position of file '%s': %s\n", args.filename, strerror(errno));
00987 fclose(ff);
00988 return -1;
00989 }
00990
00991
00992 if (offset < 0 || length < 0) {
00993 int64_t count = 0;
00994 for (i = (flength / sizeof(fbuf)) * sizeof(fbuf); i >= 0; i -= sizeof(fbuf)) {
00995 char *pos;
00996 if (fseeko(ff, i, SEEK_SET)) {
00997 ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno));
00998 }
00999 if (i + sizeof(fbuf) >= flength) {
01000 memset(fbuf, 0, sizeof(fbuf));
01001 }
01002 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
01003 ast_log(LOG_ERROR, "Short read: %s\n", strerror(errno));
01004 fclose(ff);
01005 return -1;
01006 }
01007 for (pos = fbuf + sizeof(fbuf) - 1; pos > fbuf - 1; pos--) {
01008 LINE_COUNTER(pos, newline_format, count);
01009
01010 if (length < 0 && count * -1 == length) {
01011 length_offset = i + (pos - fbuf);
01012 } else if (offset < 0 && count * -1 == (offset - 1)) {
01013
01014 if (newline_format == FF_DOS) {
01015 offset_offset = i + (pos - fbuf) + 2;
01016 } else {
01017 offset_offset = i + (pos - fbuf) + 1;
01018 }
01019 break;
01020 }
01021 }
01022 if ((offset < 0 && offset_offset >= 0) || (offset >= 0 && length_offset >= 0)) {
01023 break;
01024 }
01025 }
01026
01027 if (offset < 0 && offset_offset < 0 && offset == count * -1) {
01028 offset_offset = 0;
01029 }
01030 }
01031
01032
01033 if (offset > 0) {
01034 int64_t count = 0;
01035 fseek(ff, 0, SEEK_SET);
01036 for (i = 0; i < flength; i += sizeof(fbuf)) {
01037 char *pos;
01038 if (i + sizeof(fbuf) >= flength) {
01039 memset(fbuf, 0, sizeof(fbuf));
01040 }
01041 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
01042 ast_log(LOG_ERROR, "Short read?!!\n");
01043 fclose(ff);
01044 return -1;
01045 }
01046 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
01047 LINE_COUNTER(pos, newline_format, count);
01048
01049 if (count == offset) {
01050 offset_offset = i + (pos - fbuf) + 1;
01051 break;
01052 }
01053 }
01054 if (offset_offset >= 0) {
01055 break;
01056 }
01057 }
01058 }
01059
01060 if (offset_offset < 0) {
01061 ast_log(LOG_ERROR, "Offset '%s' refers to before the beginning of the file!\n", args.offset);
01062 fclose(ff);
01063 return -1;
01064 }
01065
01066 if (length == 0) {
01067 length_offset = offset_offset;
01068 } else if (length == LLONG_MAX) {
01069 length_offset = flength;
01070 }
01071
01072
01073 if (length_offset < 0) {
01074 fseeko(ff, offset_offset, SEEK_SET);
01075 for (i = offset_offset; i < flength; i += sizeof(fbuf)) {
01076 char *pos;
01077 if (i + sizeof(fbuf) >= flength) {
01078 memset(fbuf, 0, sizeof(fbuf));
01079 }
01080 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
01081 ast_log(LOG_ERROR, "Short read?!!\n");
01082 fclose(ff);
01083 return -1;
01084 }
01085 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
01086 LINE_COUNTER(pos, newline_format, current_length);
01087
01088 if (current_length == length) {
01089 length_offset = i + (pos - fbuf) + 1;
01090 break;
01091 }
01092 }
01093 if (length_offset >= 0) {
01094 break;
01095 }
01096 }
01097 if (length_offset < 0) {
01098
01099 ast_debug(3, "Exceeds length of file? length=%" PRId64 ", count=%" PRId64 ", flength=%" PRId64 "\n", length, current_length, flength);
01100 length_offset = flength;
01101 }
01102 }
01103
01104
01105 if (length_offset - offset_offset == vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)))) {
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 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
01111 ast_log(LOG_ERROR, "Short write?!!\n");
01112 }
01113 fclose(ff);
01114 } else if (length_offset - offset_offset > vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)))) {
01115
01116 off_t cur;
01117 int64_t length_length = length_offset - offset_offset;
01118 size_t vlen = vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)));
01119
01120 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 " (%" PRId64 "), vlength=%" PRId64 ", flength=%" PRId64 "\n",
01121 args.offset, offset_offset, args.length, length_offset, length_length, vlength, flength);
01122
01123 fseeko(ff, offset_offset, SEEK_SET);
01124 if (fwrite(value, 1, vlength, ff) < vlength) {
01125 ast_log(LOG_ERROR, "Short write?!!\n");
01126 fclose(ff);
01127 return -1;
01128 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, vlen - vlength, ff) < vlen - vlength) {
01129 ast_log(LOG_ERROR, "Short write?!!\n");
01130 fclose(ff);
01131 return -1;
01132 }
01133 while ((cur = ftello(ff)) < flength) {
01134 if (cur < 0) {
01135 ast_log(AST_LOG_ERROR, "Unable to determine last write position for '%s': %s\n", args.filename, strerror(errno));
01136 fclose(ff);
01137 return -1;
01138 }
01139 fseeko(ff, length_length - vlen, SEEK_CUR);
01140 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
01141 ast_log(LOG_ERROR, "Short read?!!\n");
01142 fclose(ff);
01143 return -1;
01144 }
01145
01146 fseeko(ff, cur, SEEK_SET);
01147 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
01148 ast_log(LOG_ERROR, "Short write?!!\n");
01149 fclose(ff);
01150 return -1;
01151 }
01152 }
01153 fclose(ff);
01154 if (truncate(args.filename, flength - (length_length - vlen))) {
01155 ast_log(LOG_ERROR, "Truncation of file failed: %s\n", strerror(errno));
01156 }
01157 } else {
01158
01159 size_t vlen = vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)));
01160 int64_t origlen = length_offset - offset_offset;
01161 off_t lastwritten = flength + vlen - origlen;
01162
01163 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 ", vlength=%" PRId64 ", flength=%" PRId64 "\n",
01164 args.offset, offset_offset, args.length, length_offset, vlength, flength);
01165
01166 fseeko(ff, flength - sizeof(fbuf), SEEK_SET);
01167 while (offset_offset + sizeof(fbuf) < ftello(ff)) {
01168 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
01169 ast_log(LOG_ERROR, "Short read?!!\n");
01170 fclose(ff);
01171 return -1;
01172 }
01173 fseeko(ff, sizeof(fbuf) - vlen - origlen, SEEK_CUR);
01174 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
01175 ast_log(LOG_ERROR, "Short write?!!\n");
01176 fclose(ff);
01177 return -1;
01178 }
01179 if ((lastwritten = ftello(ff) - sizeof(fbuf)) < offset_offset + sizeof(fbuf)) {
01180 break;
01181 }
01182 fseeko(ff, 2 * sizeof(fbuf) + vlen - origlen, SEEK_CUR);
01183 }
01184 fseek(ff, length_offset, SEEK_SET);
01185 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
01186 ast_log(LOG_ERROR, "Short read?!!\n");
01187 fclose(ff);
01188 return -1;
01189 }
01190 fseek(ff, offset_offset, SEEK_SET);
01191 if (fwrite(value, 1, vlength, ff) < vlength) {
01192 ast_log(LOG_ERROR, "Short write?!!\n");
01193 fclose(ff);
01194 return -1;
01195 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
01196 ast_log(LOG_ERROR, "Short write?!!\n");
01197 fclose(ff);
01198 return -1;
01199 } else {
01200 off_t curpos = ftello(ff);
01201 foplen = lastwritten - curpos;
01202 if (fwrite(fbuf, 1, foplen, ff) < foplen) {
01203 ast_log(LOG_ERROR, "Short write?!!\n");
01204 }
01205 }
01206 fclose(ff);
01207 }
01208 }
01209 }
01210
01211 return 0;
01212 }
01213
01214 static struct ast_custom_function env_function = {
01215 .name = "ENV",
01216 .read = env_read,
01217 .write = env_write
01218 };
01219
01220 static struct ast_custom_function stat_function = {
01221 .name = "STAT",
01222 .read = stat_read,
01223 .read_max = 12,
01224 };
01225
01226 static struct ast_custom_function file_function = {
01227 .name = "FILE",
01228 .read2 = file_read,
01229 .write = file_write,
01230 };
01231
01232 static struct ast_custom_function file_count_line_function = {
01233 .name = "FILE_COUNT_LINE",
01234 .read2 = file_count_line,
01235 .read_max = 12,
01236 };
01237
01238 static struct ast_custom_function file_format_function = {
01239 .name = "FILE_FORMAT",
01240 .read2 = file_format,
01241 .read_max = 2,
01242 };
01243
01244 static int unload_module(void)
01245 {
01246 int res = 0;
01247
01248 res |= ast_custom_function_unregister(&env_function);
01249 res |= ast_custom_function_unregister(&stat_function);
01250 res |= ast_custom_function_unregister(&file_function);
01251 res |= ast_custom_function_unregister(&file_count_line_function);
01252 res |= ast_custom_function_unregister(&file_format_function);
01253
01254 return res;
01255 }
01256
01257 static int load_module(void)
01258 {
01259 int res = 0;
01260
01261 res |= ast_custom_function_register(&env_function);
01262 res |= ast_custom_function_register(&stat_function);
01263 res |= ast_custom_function_register(&file_function);
01264 res |= ast_custom_function_register(&file_count_line_function);
01265 res |= ast_custom_function_register(&file_format_function);
01266
01267 return res;
01268 }
01269
01270 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Environment/filesystem dialplan functions");