00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00038 #include "curl_setup.h"
00039
00040 #ifndef CURL_DISABLE_FTP
00041
00042 #include <curl/curl.h>
00043
00044 #include "urldata.h"
00045 #include "fileinfo.h"
00046 #include "llist.h"
00047 #include "strtoofft.h"
00048 #include "ftp.h"
00049 #include "ftplistparser.h"
00050 #include "curl_fnmatch.h"
00051 #include "curl_memory.h"
00052
00053 #include "memdebug.h"
00054
00055
00056 #define FTP_BUFFER_ALLOCSIZE 160
00057
00058 typedef enum {
00059 PL_UNIX_TOTALSIZE = 0,
00060 PL_UNIX_FILETYPE,
00061 PL_UNIX_PERMISSION,
00062 PL_UNIX_HLINKS,
00063 PL_UNIX_USER,
00064 PL_UNIX_GROUP,
00065 PL_UNIX_SIZE,
00066 PL_UNIX_TIME,
00067 PL_UNIX_FILENAME,
00068 PL_UNIX_SYMLINK
00069 } pl_unix_mainstate;
00070
00071 typedef union {
00072 enum {
00073 PL_UNIX_TOTALSIZE_INIT = 0,
00074 PL_UNIX_TOTALSIZE_READING
00075 } total_dirsize;
00076
00077 enum {
00078 PL_UNIX_HLINKS_PRESPACE = 0,
00079 PL_UNIX_HLINKS_NUMBER
00080 } hlinks;
00081
00082 enum {
00083 PL_UNIX_USER_PRESPACE = 0,
00084 PL_UNIX_USER_PARSING
00085 } user;
00086
00087 enum {
00088 PL_UNIX_GROUP_PRESPACE = 0,
00089 PL_UNIX_GROUP_NAME
00090 } group;
00091
00092 enum {
00093 PL_UNIX_SIZE_PRESPACE = 0,
00094 PL_UNIX_SIZE_NUMBER
00095 } size;
00096
00097 enum {
00098 PL_UNIX_TIME_PREPART1 = 0,
00099 PL_UNIX_TIME_PART1,
00100 PL_UNIX_TIME_PREPART2,
00101 PL_UNIX_TIME_PART2,
00102 PL_UNIX_TIME_PREPART3,
00103 PL_UNIX_TIME_PART3
00104 } time;
00105
00106 enum {
00107 PL_UNIX_FILENAME_PRESPACE = 0,
00108 PL_UNIX_FILENAME_NAME,
00109 PL_UNIX_FILENAME_WINDOWSEOL
00110 } filename;
00111
00112 enum {
00113 PL_UNIX_SYMLINK_PRESPACE = 0,
00114 PL_UNIX_SYMLINK_NAME,
00115 PL_UNIX_SYMLINK_PRETARGET1,
00116 PL_UNIX_SYMLINK_PRETARGET2,
00117 PL_UNIX_SYMLINK_PRETARGET3,
00118 PL_UNIX_SYMLINK_PRETARGET4,
00119 PL_UNIX_SYMLINK_TARGET,
00120 PL_UNIX_SYMLINK_WINDOWSEOL
00121 } symlink;
00122 } pl_unix_substate;
00123
00124 typedef enum {
00125 PL_WINNT_DATE = 0,
00126 PL_WINNT_TIME,
00127 PL_WINNT_DIRORSIZE,
00128 PL_WINNT_FILENAME
00129 } pl_winNT_mainstate;
00130
00131 typedef union {
00132 enum {
00133 PL_WINNT_TIME_PRESPACE = 0,
00134 PL_WINNT_TIME_TIME
00135 } time;
00136 enum {
00137 PL_WINNT_DIRORSIZE_PRESPACE = 0,
00138 PL_WINNT_DIRORSIZE_CONTENT
00139 } dirorsize;
00140 enum {
00141 PL_WINNT_FILENAME_PRESPACE = 0,
00142 PL_WINNT_FILENAME_CONTENT,
00143 PL_WINNT_FILENAME_WINEOL
00144 } filename;
00145 } pl_winNT_substate;
00146
00147
00148 struct ftp_parselist_data {
00149 enum {
00150 OS_TYPE_UNKNOWN = 0,
00151 OS_TYPE_UNIX,
00152 OS_TYPE_WIN_NT
00153 } os_type;
00154
00155 union {
00156 struct {
00157 pl_unix_mainstate main;
00158 pl_unix_substate sub;
00159 } UNIX;
00160
00161 struct {
00162 pl_winNT_mainstate main;
00163 pl_winNT_substate sub;
00164 } NT;
00165 } state;
00166
00167 CURLcode error;
00168 struct curl_fileinfo *file_data;
00169 unsigned int item_length;
00170 size_t item_offset;
00171 struct {
00172 size_t filename;
00173 size_t user;
00174 size_t group;
00175 size_t time;
00176 size_t perm;
00177 size_t symlink_target;
00178 } offsets;
00179 };
00180
00181 struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
00182 {
00183 return calloc(1, sizeof(struct ftp_parselist_data));
00184 }
00185
00186
00187 void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
00188 {
00189 free(*pl_data);
00190 *pl_data = NULL;
00191 }
00192
00193
00194 CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
00195 {
00196 return pl_data->error;
00197 }
00198
00199
00200 #define FTP_LP_MALFORMATED_PERM 0x01000000
00201
00202 static int ftp_pl_get_permission(const char *str)
00203 {
00204 int permissions = 0;
00205
00206 if(str[0] == 'r')
00207 permissions |= 1 << 8;
00208 else if(str[0] != '-')
00209 permissions |= FTP_LP_MALFORMATED_PERM;
00210 if(str[1] == 'w')
00211 permissions |= 1 << 7;
00212 else if(str[1] != '-')
00213 permissions |= FTP_LP_MALFORMATED_PERM;
00214
00215 if(str[2] == 'x')
00216 permissions |= 1 << 6;
00217 else if(str[2] == 's') {
00218 permissions |= 1 << 6;
00219 permissions |= 1 << 11;
00220 }
00221 else if(str[2] == 'S')
00222 permissions |= 1 << 11;
00223 else if(str[2] != '-')
00224 permissions |= FTP_LP_MALFORMATED_PERM;
00225
00226 if(str[3] == 'r')
00227 permissions |= 1 << 5;
00228 else if(str[3] != '-')
00229 permissions |= FTP_LP_MALFORMATED_PERM;
00230 if(str[4] == 'w')
00231 permissions |= 1 << 4;
00232 else if(str[4] != '-')
00233 permissions |= FTP_LP_MALFORMATED_PERM;
00234 if(str[5] == 'x')
00235 permissions |= 1 << 3;
00236 else if(str[5] == 's') {
00237 permissions |= 1 << 3;
00238 permissions |= 1 << 10;
00239 }
00240 else if(str[5] == 'S')
00241 permissions |= 1 << 10;
00242 else if(str[5] != '-')
00243 permissions |= FTP_LP_MALFORMATED_PERM;
00244
00245 if(str[6] == 'r')
00246 permissions |= 1 << 2;
00247 else if(str[6] != '-')
00248 permissions |= FTP_LP_MALFORMATED_PERM;
00249 if(str[7] == 'w')
00250 permissions |= 1 << 1;
00251 else if(str[7] != '-')
00252 permissions |= FTP_LP_MALFORMATED_PERM;
00253 if(str[8] == 'x')
00254 permissions |= 1;
00255 else if(str[8] == 't') {
00256 permissions |= 1;
00257 permissions |= 1 << 9;
00258 }
00259 else if(str[8] == 'T')
00260 permissions |= 1 << 9;
00261 else if(str[8] != '-')
00262 permissions |= FTP_LP_MALFORMATED_PERM;
00263
00264 return permissions;
00265 }
00266
00267 static void PL_ERROR(struct connectdata *conn, CURLcode err)
00268 {
00269 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
00270 struct ftp_parselist_data *parser = tmpdata->parser;
00271 if(parser->file_data)
00272 Curl_fileinfo_dtor(NULL, parser->file_data);
00273 parser->file_data = NULL;
00274 parser->error = err;
00275 }
00276
00277 static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
00278 struct curl_fileinfo *finfo)
00279 {
00280 curl_fnmatch_callback compare;
00281 struct WildcardData *wc = &conn->data->wildcard;
00282 struct ftp_wc_tmpdata *tmpdata = wc->tmp;
00283 struct curl_llist *llist = wc->filelist;
00284 struct ftp_parselist_data *parser = tmpdata->parser;
00285 bool add = TRUE;
00286
00287
00288 char *str = finfo->b_data;
00289 finfo->filename = str + parser->offsets.filename;
00290 finfo->strings.group = parser->offsets.group ?
00291 str + parser->offsets.group : NULL;
00292 finfo->strings.perm = parser->offsets.perm ?
00293 str + parser->offsets.perm : NULL;
00294 finfo->strings.target = parser->offsets.symlink_target ?
00295 str + parser->offsets.symlink_target : NULL;
00296 finfo->strings.time = str + parser->offsets.time;
00297 finfo->strings.user = parser->offsets.user ?
00298 str + parser->offsets.user : NULL;
00299
00300
00301 compare = conn->data->set.fnmatch;
00302 if(!compare)
00303 compare = Curl_fnmatch;
00304
00305
00306 if(compare(conn->data->set.fnmatch_data, wc->pattern,
00307 finfo->filename) == 0) {
00308
00309 if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
00310 (strstr(finfo->strings.target, " -> "))) {
00311 add = FALSE;
00312 }
00313 }
00314 else {
00315 add = FALSE;
00316 }
00317
00318 if(add) {
00319 if(!Curl_llist_insert_next(llist, llist->tail, finfo)) {
00320 Curl_fileinfo_dtor(NULL, finfo);
00321 tmpdata->parser->file_data = NULL;
00322 return CURLE_OUT_OF_MEMORY;
00323 }
00324 }
00325 else {
00326 Curl_fileinfo_dtor(NULL, finfo);
00327 }
00328
00329 tmpdata->parser->file_data = NULL;
00330 return CURLE_OK;
00331 }
00332
00333 size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
00334 void *connptr)
00335 {
00336 size_t bufflen = size*nmemb;
00337 struct connectdata *conn = (struct connectdata *)connptr;
00338 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
00339 struct ftp_parselist_data *parser = tmpdata->parser;
00340 struct curl_fileinfo *finfo;
00341 unsigned long i = 0;
00342 CURLcode result;
00343
00344 if(parser->error) {
00345
00346
00347
00348
00349
00350
00351 return bufflen;
00352 }
00353
00354 if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
00355
00356 parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
00357 OS_TYPE_WIN_NT : OS_TYPE_UNIX;
00358 }
00359
00360 while(i < bufflen) {
00361
00362 char c = buffer[i];
00363 if(!parser->file_data) {
00364 parser->file_data = Curl_fileinfo_alloc();
00365 if(!parser->file_data) {
00366 parser->error = CURLE_OUT_OF_MEMORY;
00367 return bufflen;
00368 }
00369 parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
00370 if(!parser->file_data->b_data) {
00371 PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
00372 return bufflen;
00373 }
00374 parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
00375 parser->item_offset = 0;
00376 parser->item_length = 0;
00377 }
00378
00379 finfo = parser->file_data;
00380 finfo->b_data[finfo->b_used++] = c;
00381
00382 if(finfo->b_used >= finfo->b_size - 1) {
00383
00384 char *tmp = realloc(finfo->b_data,
00385 finfo->b_size + FTP_BUFFER_ALLOCSIZE);
00386 if(tmp) {
00387 finfo->b_size += FTP_BUFFER_ALLOCSIZE;
00388 finfo->b_data = tmp;
00389 }
00390 else {
00391 Curl_fileinfo_dtor(NULL, parser->file_data);
00392 parser->file_data = NULL;
00393 parser->error = CURLE_OUT_OF_MEMORY;
00394 PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
00395 return bufflen;
00396 }
00397 }
00398
00399 switch(parser->os_type) {
00400 case OS_TYPE_UNIX:
00401 switch(parser->state.UNIX.main) {
00402 case PL_UNIX_TOTALSIZE:
00403 switch(parser->state.UNIX.sub.total_dirsize) {
00404 case PL_UNIX_TOTALSIZE_INIT:
00405 if(c == 't') {
00406 parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
00407 parser->item_length++;
00408 }
00409 else {
00410 parser->state.UNIX.main = PL_UNIX_FILETYPE;
00411
00412 finfo->b_used = 0;
00413 i--;
00414 }
00415 break;
00416 case PL_UNIX_TOTALSIZE_READING:
00417 parser->item_length++;
00418 if(c == '\r') {
00419 parser->item_length--;
00420 finfo->b_used--;
00421 }
00422 else if(c == '\n') {
00423 finfo->b_data[parser->item_length - 1] = 0;
00424 if(strncmp("total ", finfo->b_data, 6) == 0) {
00425 char *endptr = finfo->b_data+6;
00426
00427
00428 while(ISSPACE(*endptr))
00429 endptr++;
00430 while(ISDIGIT(*endptr))
00431 endptr++;
00432 if(*endptr != 0) {
00433 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00434 return bufflen;
00435 }
00436 else {
00437 parser->state.UNIX.main = PL_UNIX_FILETYPE;
00438 finfo->b_used = 0;
00439 }
00440 }
00441 else {
00442 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00443 return bufflen;
00444 }
00445 }
00446 break;
00447 }
00448 break;
00449 case PL_UNIX_FILETYPE:
00450 switch(c) {
00451 case '-':
00452 finfo->filetype = CURLFILETYPE_FILE;
00453 break;
00454 case 'd':
00455 finfo->filetype = CURLFILETYPE_DIRECTORY;
00456 break;
00457 case 'l':
00458 finfo->filetype = CURLFILETYPE_SYMLINK;
00459 break;
00460 case 'p':
00461 finfo->filetype = CURLFILETYPE_NAMEDPIPE;
00462 break;
00463 case 's':
00464 finfo->filetype = CURLFILETYPE_SOCKET;
00465 break;
00466 case 'c':
00467 finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
00468 break;
00469 case 'b':
00470 finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
00471 break;
00472 case 'D':
00473 finfo->filetype = CURLFILETYPE_DOOR;
00474 break;
00475 default:
00476 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00477 return bufflen;
00478 }
00479 parser->state.UNIX.main = PL_UNIX_PERMISSION;
00480 parser->item_length = 0;
00481 parser->item_offset = 1;
00482 break;
00483 case PL_UNIX_PERMISSION:
00484 parser->item_length++;
00485 if(parser->item_length <= 9) {
00486 if(!strchr("rwx-tTsS", c)) {
00487 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00488 return bufflen;
00489 }
00490 }
00491 else if(parser->item_length == 10) {
00492 unsigned int perm;
00493 if(c != ' ') {
00494 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00495 return bufflen;
00496 }
00497 finfo->b_data[10] = 0;
00498 perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
00499 if(perm & FTP_LP_MALFORMATED_PERM) {
00500 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00501 return bufflen;
00502 }
00503 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM;
00504 parser->file_data->perm = perm;
00505 parser->offsets.perm = parser->item_offset;
00506
00507 parser->item_length = 0;
00508 parser->state.UNIX.main = PL_UNIX_HLINKS;
00509 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
00510 }
00511 break;
00512 case PL_UNIX_HLINKS:
00513 switch(parser->state.UNIX.sub.hlinks) {
00514 case PL_UNIX_HLINKS_PRESPACE:
00515 if(c != ' ') {
00516 if(c >= '0' && c <= '9') {
00517 parser->item_offset = finfo->b_used - 1;
00518 parser->item_length = 1;
00519 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
00520 }
00521 else {
00522 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00523 return bufflen;
00524 }
00525 }
00526 break;
00527 case PL_UNIX_HLINKS_NUMBER:
00528 parser->item_length ++;
00529 if(c == ' ') {
00530 char *p;
00531 long int hlinks;
00532 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00533 hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
00534 if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
00535 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
00536 parser->file_data->hardlinks = hlinks;
00537 }
00538 parser->item_length = 0;
00539 parser->item_offset = 0;
00540 parser->state.UNIX.main = PL_UNIX_USER;
00541 parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
00542 }
00543 else if(c < '0' || c > '9') {
00544 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00545 return bufflen;
00546 }
00547 break;
00548 }
00549 break;
00550 case PL_UNIX_USER:
00551 switch(parser->state.UNIX.sub.user) {
00552 case PL_UNIX_USER_PRESPACE:
00553 if(c != ' ') {
00554 parser->item_offset = finfo->b_used - 1;
00555 parser->item_length = 1;
00556 parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
00557 }
00558 break;
00559 case PL_UNIX_USER_PARSING:
00560 parser->item_length++;
00561 if(c == ' ') {
00562 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00563 parser->offsets.user = parser->item_offset;
00564 parser->state.UNIX.main = PL_UNIX_GROUP;
00565 parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
00566 parser->item_offset = 0;
00567 parser->item_length = 0;
00568 }
00569 break;
00570 }
00571 break;
00572 case PL_UNIX_GROUP:
00573 switch(parser->state.UNIX.sub.group) {
00574 case PL_UNIX_GROUP_PRESPACE:
00575 if(c != ' ') {
00576 parser->item_offset = finfo->b_used - 1;
00577 parser->item_length = 1;
00578 parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
00579 }
00580 break;
00581 case PL_UNIX_GROUP_NAME:
00582 parser->item_length++;
00583 if(c == ' ') {
00584 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00585 parser->offsets.group = parser->item_offset;
00586 parser->state.UNIX.main = PL_UNIX_SIZE;
00587 parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
00588 parser->item_offset = 0;
00589 parser->item_length = 0;
00590 }
00591 break;
00592 }
00593 break;
00594 case PL_UNIX_SIZE:
00595 switch(parser->state.UNIX.sub.size) {
00596 case PL_UNIX_SIZE_PRESPACE:
00597 if(c != ' ') {
00598 if(c >= '0' && c <= '9') {
00599 parser->item_offset = finfo->b_used - 1;
00600 parser->item_length = 1;
00601 parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
00602 }
00603 else {
00604 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00605 return bufflen;
00606 }
00607 }
00608 break;
00609 case PL_UNIX_SIZE_NUMBER:
00610 parser->item_length++;
00611 if(c == ' ') {
00612 char *p;
00613 curl_off_t fsize;
00614 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00615 fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
00616 if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
00617 fsize != CURL_OFF_T_MIN) {
00618 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
00619 parser->file_data->size = fsize;
00620 }
00621 parser->item_length = 0;
00622 parser->item_offset = 0;
00623 parser->state.UNIX.main = PL_UNIX_TIME;
00624 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
00625 }
00626 else if(!ISDIGIT(c)) {
00627 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00628 return bufflen;
00629 }
00630 break;
00631 }
00632 break;
00633 case PL_UNIX_TIME:
00634 switch(parser->state.UNIX.sub.time) {
00635 case PL_UNIX_TIME_PREPART1:
00636 if(c != ' ') {
00637 if(ISALNUM(c)) {
00638 parser->item_offset = finfo->b_used -1;
00639 parser->item_length = 1;
00640 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
00641 }
00642 else {
00643 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00644 return bufflen;
00645 }
00646 }
00647 break;
00648 case PL_UNIX_TIME_PART1:
00649 parser->item_length++;
00650 if(c == ' ') {
00651 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
00652 }
00653 else if(!ISALNUM(c) && c != '.') {
00654 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00655 return bufflen;
00656 }
00657 break;
00658 case PL_UNIX_TIME_PREPART2:
00659 parser->item_length++;
00660 if(c != ' ') {
00661 if(ISALNUM(c)) {
00662 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
00663 }
00664 else {
00665 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00666 return bufflen;
00667 }
00668 }
00669 break;
00670 case PL_UNIX_TIME_PART2:
00671 parser->item_length++;
00672 if(c == ' ') {
00673 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
00674 }
00675 else if(!ISALNUM(c) && c != '.') {
00676 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00677 return bufflen;
00678 }
00679 break;
00680 case PL_UNIX_TIME_PREPART3:
00681 parser->item_length++;
00682 if(c != ' ') {
00683 if(ISALNUM(c)) {
00684 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
00685 }
00686 else {
00687 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00688 return bufflen;
00689 }
00690 }
00691 break;
00692 case PL_UNIX_TIME_PART3:
00693 parser->item_length++;
00694 if(c == ' ') {
00695 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
00696 parser->offsets.time = parser->item_offset;
00697
00698
00699
00700
00701
00702 if(finfo->filetype == CURLFILETYPE_SYMLINK) {
00703 parser->state.UNIX.main = PL_UNIX_SYMLINK;
00704 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
00705 }
00706 else {
00707 parser->state.UNIX.main = PL_UNIX_FILENAME;
00708 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
00709 }
00710 }
00711 else if(!ISALNUM(c) && c != '.' && c != ':') {
00712 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00713 return bufflen;
00714 }
00715 break;
00716 }
00717 break;
00718 case PL_UNIX_FILENAME:
00719 switch(parser->state.UNIX.sub.filename) {
00720 case PL_UNIX_FILENAME_PRESPACE:
00721 if(c != ' ') {
00722 parser->item_offset = finfo->b_used - 1;
00723 parser->item_length = 1;
00724 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
00725 }
00726 break;
00727 case PL_UNIX_FILENAME_NAME:
00728 parser->item_length++;
00729 if(c == '\r') {
00730 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
00731 }
00732 else if(c == '\n') {
00733 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00734 parser->offsets.filename = parser->item_offset;
00735 parser->state.UNIX.main = PL_UNIX_FILETYPE;
00736 result = ftp_pl_insert_finfo(conn, finfo);
00737 if(result) {
00738 PL_ERROR(conn, result);
00739 return bufflen;
00740 }
00741 }
00742 break;
00743 case PL_UNIX_FILENAME_WINDOWSEOL:
00744 if(c == '\n') {
00745 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00746 parser->offsets.filename = parser->item_offset;
00747 parser->state.UNIX.main = PL_UNIX_FILETYPE;
00748 result = ftp_pl_insert_finfo(conn, finfo);
00749 if(result) {
00750 PL_ERROR(conn, result);
00751 return bufflen;
00752 }
00753 }
00754 else {
00755 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00756 return bufflen;
00757 }
00758 break;
00759 }
00760 break;
00761 case PL_UNIX_SYMLINK:
00762 switch(parser->state.UNIX.sub.symlink) {
00763 case PL_UNIX_SYMLINK_PRESPACE:
00764 if(c != ' ') {
00765 parser->item_offset = finfo->b_used - 1;
00766 parser->item_length = 1;
00767 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
00768 }
00769 break;
00770 case PL_UNIX_SYMLINK_NAME:
00771 parser->item_length++;
00772 if(c == ' ') {
00773 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
00774 }
00775 else if(c == '\r' || c == '\n') {
00776 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00777 return bufflen;
00778 }
00779 break;
00780 case PL_UNIX_SYMLINK_PRETARGET1:
00781 parser->item_length++;
00782 if(c == '-') {
00783 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
00784 }
00785 else if(c == '\r' || c == '\n') {
00786 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00787 return bufflen;
00788 }
00789 else {
00790 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
00791 }
00792 break;
00793 case PL_UNIX_SYMLINK_PRETARGET2:
00794 parser->item_length++;
00795 if(c == '>') {
00796 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
00797 }
00798 else if(c == '\r' || c == '\n') {
00799 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00800 return bufflen;
00801 }
00802 else {
00803 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
00804 }
00805 break;
00806 case PL_UNIX_SYMLINK_PRETARGET3:
00807 parser->item_length++;
00808 if(c == ' ') {
00809 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
00810
00811 finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
00812 parser->offsets.filename = parser->item_offset;
00813 parser->item_length = 0;
00814 parser->item_offset = 0;
00815 }
00816 else if(c == '\r' || c == '\n') {
00817 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00818 return bufflen;
00819 }
00820 else {
00821 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
00822 }
00823 break;
00824 case PL_UNIX_SYMLINK_PRETARGET4:
00825 if(c != '\r' && c != '\n') {
00826 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
00827 parser->item_offset = finfo->b_used - 1;
00828 parser->item_length = 1;
00829 }
00830 else {
00831 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00832 return bufflen;
00833 }
00834 break;
00835 case PL_UNIX_SYMLINK_TARGET:
00836 parser->item_length++;
00837 if(c == '\r') {
00838 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
00839 }
00840 else if(c == '\n') {
00841 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00842 parser->offsets.symlink_target = parser->item_offset;
00843 result = ftp_pl_insert_finfo(conn, finfo);
00844 if(result) {
00845 PL_ERROR(conn, result);
00846 return bufflen;
00847 }
00848 parser->state.UNIX.main = PL_UNIX_FILETYPE;
00849 }
00850 break;
00851 case PL_UNIX_SYMLINK_WINDOWSEOL:
00852 if(c == '\n') {
00853 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00854 parser->offsets.symlink_target = parser->item_offset;
00855 result = ftp_pl_insert_finfo(conn, finfo);
00856 if(result) {
00857 PL_ERROR(conn, result);
00858 return bufflen;
00859 }
00860 parser->state.UNIX.main = PL_UNIX_FILETYPE;
00861 }
00862 else {
00863 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00864 return bufflen;
00865 }
00866 break;
00867 }
00868 break;
00869 }
00870 break;
00871 case OS_TYPE_WIN_NT:
00872 switch(parser->state.NT.main) {
00873 case PL_WINNT_DATE:
00874 parser->item_length++;
00875 if(parser->item_length < 9) {
00876 if(!strchr("0123456789-", c)) {
00877 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00878 return bufflen;
00879 }
00880 }
00881 else if(parser->item_length == 9) {
00882 if(c == ' ') {
00883 parser->state.NT.main = PL_WINNT_TIME;
00884 parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
00885 }
00886 else {
00887 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00888 return bufflen;
00889 }
00890 }
00891 else {
00892 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00893 return bufflen;
00894 }
00895 break;
00896 case PL_WINNT_TIME:
00897 parser->item_length++;
00898 switch(parser->state.NT.sub.time) {
00899 case PL_WINNT_TIME_PRESPACE:
00900 if(!ISSPACE(c)) {
00901 parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
00902 }
00903 break;
00904 case PL_WINNT_TIME_TIME:
00905 if(c == ' ') {
00906 parser->offsets.time = parser->item_offset;
00907 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
00908 parser->state.NT.main = PL_WINNT_DIRORSIZE;
00909 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
00910 parser->item_length = 0;
00911 }
00912 else if(!strchr("APM0123456789:", c)) {
00913 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00914 return bufflen;
00915 }
00916 break;
00917 }
00918 break;
00919 case PL_WINNT_DIRORSIZE:
00920 switch(parser->state.NT.sub.dirorsize) {
00921 case PL_WINNT_DIRORSIZE_PRESPACE:
00922 if(c == ' ') {
00923
00924 }
00925 else {
00926 parser->item_offset = finfo->b_used - 1;
00927 parser->item_length = 1;
00928 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
00929 }
00930 break;
00931 case PL_WINNT_DIRORSIZE_CONTENT:
00932 parser->item_length ++;
00933 if(c == ' ') {
00934 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00935 if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
00936 finfo->filetype = CURLFILETYPE_DIRECTORY;
00937 finfo->size = 0;
00938 }
00939 else {
00940 char *endptr;
00941 finfo->size = curlx_strtoofft(finfo->b_data +
00942 parser->item_offset,
00943 &endptr, 10);
00944 if(!*endptr) {
00945 if(finfo->size == CURL_OFF_T_MAX ||
00946 finfo->size == CURL_OFF_T_MIN) {
00947 if(errno == ERANGE) {
00948 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00949 return bufflen;
00950 }
00951 }
00952 }
00953 else {
00954 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00955 return bufflen;
00956 }
00957
00958 parser->file_data->filetype = CURLFILETYPE_FILE;
00959 }
00960
00961 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
00962 parser->item_length = 0;
00963 parser->state.NT.main = PL_WINNT_FILENAME;
00964 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
00965 }
00966 break;
00967 }
00968 break;
00969 case PL_WINNT_FILENAME:
00970 switch(parser->state.NT.sub.filename) {
00971 case PL_WINNT_FILENAME_PRESPACE:
00972 if(c != ' ') {
00973 parser->item_offset = finfo->b_used -1;
00974 parser->item_length = 1;
00975 parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
00976 }
00977 break;
00978 case PL_WINNT_FILENAME_CONTENT:
00979 parser->item_length++;
00980 if(c == '\r') {
00981 parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
00982 finfo->b_data[finfo->b_used - 1] = 0;
00983 }
00984 else if(c == '\n') {
00985 parser->offsets.filename = parser->item_offset;
00986 finfo->b_data[finfo->b_used - 1] = 0;
00987 parser->offsets.filename = parser->item_offset;
00988 result = ftp_pl_insert_finfo(conn, finfo);
00989 if(result) {
00990 PL_ERROR(conn, result);
00991 return bufflen;
00992 }
00993 parser->state.NT.main = PL_WINNT_DATE;
00994 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
00995 }
00996 break;
00997 case PL_WINNT_FILENAME_WINEOL:
00998 if(c == '\n') {
00999 parser->offsets.filename = parser->item_offset;
01000 result = ftp_pl_insert_finfo(conn, finfo);
01001 if(result) {
01002 PL_ERROR(conn, result);
01003 return bufflen;
01004 }
01005 parser->state.NT.main = PL_WINNT_DATE;
01006 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
01007 }
01008 else {
01009 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
01010 return bufflen;
01011 }
01012 break;
01013 }
01014 break;
01015 }
01016 break;
01017 default:
01018 return bufflen + 1;
01019 }
01020
01021 i++;
01022 }
01023
01024 return bufflen;
01025 }
01026
01027 #endif