1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23/** 24 * Now implemented: 25 * 26 * 1) UNIX version 1 27 * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog 28 * 2) UNIX version 2 29 * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog 30 * 3) UNIX version 3 31 * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog 32 * 4) UNIX symlink 33 * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000 34 * 5) DOS style 35 * 01-29-97 11:32PM <DIR> prog 36 */ 37 38#include "setup.h" 39 40#include "ftplistparser.h" 41#include "curl_fnmatch.h" 42 43#include "urldata.h" 44#include "ftp.h" 45#include "fileinfo.h" 46#include "llist.h" 47#include "strtoofft.h" 48#include "rawstr.h" 49#include "ftp.h" 50 51#define _MPRINTF_REPLACE /* use our functions only */ 52#include <curl/mprintf.h> 53 54#include "curl_memory.h" 55/* The last #include file should be: */ 56#include "memdebug.h" 57 58/* allocs buffer which will contain one line of LIST command response */ 59#define FTP_BUFFER_ALLOCSIZE 160 60 61typedef enum { 62 PL_UNIX_TOTALSIZE = 0, 63 PL_UNIX_FILETYPE, 64 PL_UNIX_PERMISSION, 65 PL_UNIX_HLINKS, 66 PL_UNIX_USER, 67 PL_UNIX_GROUP, 68 PL_UNIX_SIZE, 69 PL_UNIX_TIME, 70 PL_UNIX_FILENAME, 71 PL_UNIX_SYMLINK 72} pl_unix_mainstate; 73 74typedef union { 75 enum { 76 PL_UNIX_TOTALSIZE_INIT = 0, 77 PL_UNIX_TOTALSIZE_READING 78 } total_dirsize; 79 80 enum { 81 PL_UNIX_HLINKS_PRESPACE = 0, 82 PL_UNIX_HLINKS_NUMBER 83 } hlinks; 84 85 enum { 86 PL_UNIX_USER_PRESPACE = 0, 87 PL_UNIX_USER_PARSING 88 } user; 89 90 enum { 91 PL_UNIX_GROUP_PRESPACE = 0, 92 PL_UNIX_GROUP_NAME 93 } group; 94 95 enum { 96 PL_UNIX_SIZE_PRESPACE = 0, 97 PL_UNIX_SIZE_NUMBER 98 } size; 99 100 enum { 101 PL_UNIX_TIME_PREPART1 = 0, 102 PL_UNIX_TIME_PART1, 103 PL_UNIX_TIME_PREPART2, 104 PL_UNIX_TIME_PART2, 105 PL_UNIX_TIME_PREPART3, 106 PL_UNIX_TIME_PART3 107 } time; 108 109 enum { 110 PL_UNIX_FILENAME_PRESPACE = 0, 111 PL_UNIX_FILENAME_NAME, 112 PL_UNIX_FILENAME_WINDOWSEOL 113 } filename; 114 115 enum { 116 PL_UNIX_SYMLINK_PRESPACE = 0, 117 PL_UNIX_SYMLINK_NAME, 118 PL_UNIX_SYMLINK_PRETARGET1, 119 PL_UNIX_SYMLINK_PRETARGET2, 120 PL_UNIX_SYMLINK_PRETARGET3, 121 PL_UNIX_SYMLINK_PRETARGET4, 122 PL_UNIX_SYMLINK_TARGET, 123 PL_UNIX_SYMLINK_WINDOWSEOL 124 } symlink; 125} pl_unix_substate; 126 127typedef enum { 128 PL_WINNT_DATE = 0, 129 PL_WINNT_TIME, 130 PL_WINNT_DIRORSIZE, 131 PL_WINNT_FILENAME 132} pl_winNT_mainstate; 133 134typedef union { 135 enum { 136 PL_WINNT_TIME_PRESPACE = 0, 137 PL_WINNT_TIME_TIME 138 } time; 139 enum { 140 PL_WINNT_DIRORSIZE_PRESPACE = 0, 141 PL_WINNT_DIRORSIZE_CONTENT 142 } dirorsize; 143 enum { 144 PL_WINNT_FILENAME_PRESPACE = 0, 145 PL_WINNT_FILENAME_CONTENT, 146 PL_WINNT_FILENAME_WINEOL 147 } filename; 148} pl_winNT_substate; 149 150/* This struct is used in wildcard downloading - for parsing LIST response */ 151struct ftp_parselist_data { 152 enum { 153 OS_TYPE_UNKNOWN = 0, 154 OS_TYPE_UNIX, 155 OS_TYPE_WIN_NT 156 } os_type; 157 158 union { 159 struct { 160 pl_unix_mainstate main; 161 pl_unix_substate sub; 162 } UNIX; 163 164 struct { 165 pl_winNT_mainstate main; 166 pl_winNT_substate sub; 167 } NT; 168 } state; 169 170 CURLcode error; 171 struct curl_fileinfo *file_data; 172 unsigned int item_length; 173 size_t item_offset; 174 struct { 175 size_t filename; 176 size_t user; 177 size_t group; 178 size_t time; 179 size_t perm; 180 size_t symlink_target; 181 } offsets; 182}; 183 184struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void) 185{ 186 return calloc(1, sizeof(struct ftp_parselist_data)); 187} 188 189 190void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data) 191{ 192 if(*pl_data) 193 free(*pl_data); 194 *pl_data = NULL; 195} 196 197 198CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data) 199{ 200 return pl_data->error; 201} 202 203 204#define FTP_LP_MALFORMATED_PERM 0x01000000 205 206static int ftp_pl_get_permission(const char *str) 207{ 208 int permissions = 0; 209 /* USER */ 210 if(str[0] == 'r') 211 permissions |= 1 << 8; 212 else if(str[0] != '-') 213 permissions |= FTP_LP_MALFORMATED_PERM; 214 if(str[1] == 'w') 215 permissions |= 1 << 7; 216 else if(str[1] != '-') 217 permissions |= FTP_LP_MALFORMATED_PERM; 218 219 if(str[2] == 'x') 220 permissions |= 1 << 6; 221 else if(str[2] == 's') { 222 permissions |= 1 << 6; 223 permissions |= 1 << 11; 224 } 225 else if(str[2] == 'S') 226 permissions |= 1 << 11; 227 else if(str[2] != '-') 228 permissions |= FTP_LP_MALFORMATED_PERM; 229 /* GROUP */ 230 if(str[3] == 'r') 231 permissions |= 1 << 5; 232 else if(str[3] != '-') 233 permissions |= FTP_LP_MALFORMATED_PERM; 234 if(str[4] == 'w') 235 permissions |= 1 << 4; 236 else if(str[4] != '-') 237 permissions |= FTP_LP_MALFORMATED_PERM; 238 if(str[5] == 'x') 239 permissions |= 1 << 3; 240 else if(str[5] == 's') { 241 permissions |= 1 << 3; 242 permissions |= 1 << 10; 243 } 244 else if(str[5] == 'S') 245 permissions |= 1 << 10; 246 else if(str[5] != '-') 247 permissions |= FTP_LP_MALFORMATED_PERM; 248 /* others */ 249 if(str[6] == 'r') 250 permissions |= 1 << 2; 251 else if(str[6] != '-') 252 permissions |= FTP_LP_MALFORMATED_PERM; 253 if(str[7] == 'w') 254 permissions |= 1 << 1; 255 else if(str[7] != '-') 256 permissions |= FTP_LP_MALFORMATED_PERM; 257 if(str[8] == 'x') 258 permissions |= 1; 259 else if(str[8] == 't') { 260 permissions |= 1; 261 permissions |= 1 << 9; 262 } 263 else if(str[8] == 'T') 264 permissions |= 1 << 9; 265 else if(str[8] != '-') 266 permissions |= FTP_LP_MALFORMATED_PERM; 267 268 return permissions; 269} 270 271static void PL_ERROR(struct connectdata *conn, CURLcode err) 272{ 273 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp; 274 struct ftp_parselist_data *parser = tmpdata->parser; 275 if(parser->file_data) 276 Curl_fileinfo_dtor(NULL, parser->file_data); 277 parser->file_data = NULL; 278 parser->error = err; 279} 280 281static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string) 282{ 283 (void)parser; 284 (void)string; 285 /* TODO 286 * There could be possible parse timestamp from server. Leaving unimplemented 287 * for now. 288 * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to 289 * parser->file_data->flags 290 * 291 * Ftp servers are giving usually these formats: 292 * Apr 11 1998 (unknown time.. set it to 00:00:00?) 293 * Apr 11 12:21 (unknown year -> set it to NOW() time?) 294 * 08-05-09 02:49PM (ms-dos format) 295 * 20100421092538 -> for MLST/MLSD response 296 */ 297 298 return FALSE; 299} 300 301static CURLcode ftp_pl_insert_finfo(struct connectdata *conn, 302 struct curl_fileinfo *finfo) 303{ 304 curl_fnmatch_callback compare; 305 struct WildcardData *wc = &conn->data->wildcard; 306 struct ftp_wc_tmpdata *tmpdata = wc->tmp; 307 struct curl_llist *llist = wc->filelist; 308 struct ftp_parselist_data *parser = tmpdata->parser; 309 bool add = TRUE; 310 311 /* move finfo pointers to b_data */ 312 char *str = finfo->b_data; 313 finfo->filename = str + parser->offsets.filename; 314 finfo->strings.group = parser->offsets.group ? 315 str + parser->offsets.group : NULL; 316 finfo->strings.perm = parser->offsets.perm ? 317 str + parser->offsets.perm : NULL; 318 finfo->strings.target = parser->offsets.symlink_target ? 319 str + parser->offsets.symlink_target : NULL; 320 finfo->strings.time = str + parser->offsets.time; 321 finfo->strings.user = parser->offsets.user ? 322 str + parser->offsets.user : NULL; 323 324 /* get correct fnmatch callback */ 325 compare = conn->data->set.fnmatch; 326 if(!compare) 327 compare = Curl_fnmatch; 328 329 /* filter pattern-corresponding filenames */ 330 if(compare(conn->data->set.fnmatch_data, wc->pattern, 331 finfo->filename) == 0) { 332 /* discard symlink which is containing multiple " -> " */ 333 if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target && 334 (strstr(finfo->strings.target, " -> "))) { 335 add = FALSE; 336 } 337 } 338 else { 339 add = FALSE; 340 } 341 342 if(add) { 343 if(!Curl_llist_insert_next(llist, llist->tail, finfo)) { 344 Curl_fileinfo_dtor(NULL, finfo); 345 tmpdata->parser->file_data = NULL; 346 return CURLE_OUT_OF_MEMORY; 347 } 348 } 349 else { 350 Curl_fileinfo_dtor(NULL, finfo); 351 } 352 353 tmpdata->parser->file_data = NULL; 354 return CURLE_OK; 355} 356 357size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, 358 void *connptr) 359{ 360 size_t bufflen = size*nmemb; 361 struct connectdata *conn = (struct connectdata *)connptr; 362 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp; 363 struct ftp_parselist_data *parser = tmpdata->parser; 364 struct curl_fileinfo *finfo; 365 unsigned long i = 0; 366 CURLcode rc; 367 368 if(parser->error) { /* error in previous call */ 369 /* scenario: 370 * 1. call => OK.. 371 * 2. call => OUT_OF_MEMORY (or other error) 372 * 3. (last) call => is skipped RIGHT HERE and the error is hadled later 373 * in wc_statemach() 374 */ 375 return bufflen; 376 } 377 378 if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) { 379 /* considering info about FILE response format */ 380 parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ? 381 OS_TYPE_WIN_NT : OS_TYPE_UNIX; 382 } 383 384 while(i < bufflen) { /* FSM */ 385 386 char c = buffer[i]; 387 if(!parser->file_data) { /* tmp file data is not allocated yet */ 388 parser->file_data = Curl_fileinfo_alloc(); 389 if(!parser->file_data) { 390 parser->error = CURLE_OUT_OF_MEMORY; 391 return bufflen; 392 } 393 parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE); 394 if(!parser->file_data->b_data) { 395 PL_ERROR(conn, CURLE_OUT_OF_MEMORY); 396 return bufflen; 397 } 398 parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE; 399 parser->item_offset = 0; 400 parser->item_length = 0; 401 } 402 403 finfo = parser->file_data; 404 finfo->b_data[finfo->b_used++] = c; 405 406 if(finfo->b_used >= finfo->b_size - 1) { 407 /* if it is important, extend buffer space for file data */ 408 char *tmp = realloc(finfo->b_data, 409 finfo->b_size + FTP_BUFFER_ALLOCSIZE); 410 if(tmp) { 411 finfo->b_size += FTP_BUFFER_ALLOCSIZE; 412 finfo->b_data = tmp; 413 } 414 else { 415 Curl_fileinfo_dtor(NULL, parser->file_data); 416 parser->file_data = NULL; 417 parser->error = CURLE_OUT_OF_MEMORY; 418 PL_ERROR(conn, CURLE_OUT_OF_MEMORY); 419 return bufflen; 420 } 421 } 422 423 switch (parser->os_type) { 424 case OS_TYPE_UNIX: 425 switch (parser->state.UNIX.main) { 426 case PL_UNIX_TOTALSIZE: 427 switch(parser->state.UNIX.sub.total_dirsize) { 428 case PL_UNIX_TOTALSIZE_INIT: 429 if(c == 't') { 430 parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING; 431 parser->item_length++; 432 } 433 else { 434 parser->state.UNIX.main = PL_UNIX_FILETYPE; 435 /* start FSM again not considering size of directory */ 436 finfo->b_used = 0; 437 i--; 438 } 439 break; 440 case PL_UNIX_TOTALSIZE_READING: 441 parser->item_length++; 442 if(c == '\r') { 443 parser->item_length--; 444 finfo->b_used--; 445 } 446 else if(c == '\n') { 447 finfo->b_data[parser->item_length - 1] = 0; 448 if(strncmp("total ", finfo->b_data, 6) == 0) { 449 char *endptr = finfo->b_data+6; 450 /* here we can deal with directory size */ 451 while(ISSPACE(*endptr)) 452 endptr++; 453 if(*endptr != 0) { 454 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 455 return bufflen; 456 } 457 else { 458 parser->state.UNIX.main = PL_UNIX_FILETYPE; 459 finfo->b_used = 0; 460 } 461 } 462 else { 463 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 464 return bufflen; 465 } 466 } 467 break; 468 } 469 break; 470 case PL_UNIX_FILETYPE: 471 switch (c) { 472 case '-': 473 finfo->filetype = CURLFILETYPE_FILE; 474 break; 475 case 'd': 476 finfo->filetype = CURLFILETYPE_DIRECTORY; 477 break; 478 case 'l': 479 finfo->filetype = CURLFILETYPE_SYMLINK; 480 break; 481 case 'p': 482 finfo->filetype = CURLFILETYPE_NAMEDPIPE; 483 break; 484 case 's': 485 finfo->filetype = CURLFILETYPE_SOCKET; 486 break; 487 case 'c': 488 finfo->filetype = CURLFILETYPE_DEVICE_CHAR; 489 break; 490 case 'b': 491 finfo->filetype = CURLFILETYPE_DEVICE_BLOCK; 492 break; 493 case 'D': 494 finfo->filetype = CURLFILETYPE_DOOR; 495 break; 496 default: 497 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 498 return bufflen; 499 } 500 parser->state.UNIX.main = PL_UNIX_PERMISSION; 501 parser->item_length = 0; 502 parser->item_offset = 1; 503 break; 504 case PL_UNIX_PERMISSION: 505 parser->item_length++; 506 if(parser->item_length <= 9) { 507 if(!strchr("rwx-tTsS", c)) { 508 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 509 return bufflen; 510 } 511 } 512 else if(parser->item_length == 10) { 513 unsigned int perm; 514 if(c != ' ') { 515 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 516 return bufflen; 517 } 518 finfo->b_data[10] = 0; /* terminate permissions */ 519 perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset); 520 if(perm & FTP_LP_MALFORMATED_PERM) { 521 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 522 return bufflen; 523 } 524 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM; 525 parser->file_data->perm = perm; 526 parser->offsets.perm = parser->item_offset; 527 528 parser->item_length = 0; 529 parser->state.UNIX.main = PL_UNIX_HLINKS; 530 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE; 531 } 532 break; 533 case PL_UNIX_HLINKS: 534 switch(parser->state.UNIX.sub.hlinks) { 535 case PL_UNIX_HLINKS_PRESPACE: 536 if(c != ' ') { 537 if(c >= '0' && c <= '9') { 538 parser->item_offset = finfo->b_used - 1; 539 parser->item_length = 1; 540 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER; 541 } 542 else { 543 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 544 return bufflen; 545 } 546 } 547 break; 548 case PL_UNIX_HLINKS_NUMBER: 549 parser->item_length ++; 550 if(c == ' ') { 551 char *p; 552 long int hlinks; 553 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; 554 hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10); 555 if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) { 556 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT; 557 parser->file_data->hardlinks = hlinks; 558 } 559 parser->item_length = 0; 560 parser->item_offset = 0; 561 parser->state.UNIX.main = PL_UNIX_USER; 562 parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE; 563 } 564 else if(c < '0' || c > '9') { 565 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 566 return bufflen; 567 } 568 break; 569 } 570 break; 571 case PL_UNIX_USER: 572 switch(parser->state.UNIX.sub.user) { 573 case PL_UNIX_USER_PRESPACE: 574 if(c != ' ') { 575 parser->item_offset = finfo->b_used - 1; 576 parser->item_length = 1; 577 parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING; 578 } 579 break; 580 case PL_UNIX_USER_PARSING: 581 parser->item_length++; 582 if(c == ' ') { 583 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; 584 parser->offsets.user = parser->item_offset; 585 parser->state.UNIX.main = PL_UNIX_GROUP; 586 parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE; 587 parser->item_offset = 0; 588 parser->item_length = 0; 589 } 590 break; 591 } 592 break; 593 case PL_UNIX_GROUP: 594 switch(parser->state.UNIX.sub.group) { 595 case PL_UNIX_GROUP_PRESPACE: 596 if(c != ' ') { 597 parser->item_offset = finfo->b_used - 1; 598 parser->item_length = 1; 599 parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME; 600 } 601 break; 602 case PL_UNIX_GROUP_NAME: 603 parser->item_length++; 604 if(c == ' ') { 605 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; 606 parser->offsets.group = parser->item_offset; 607 parser->state.UNIX.main = PL_UNIX_SIZE; 608 parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE; 609 parser->item_offset = 0; 610 parser->item_length = 0; 611 } 612 break; 613 } 614 break; 615 case PL_UNIX_SIZE: 616 switch(parser->state.UNIX.sub.size) { 617 case PL_UNIX_SIZE_PRESPACE: 618 if(c != ' ') { 619 if(c >= '0' && c <= '9') { 620 parser->item_offset = finfo->b_used - 1; 621 parser->item_length = 1; 622 parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER; 623 } 624 else { 625 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 626 return bufflen; 627 } 628 } 629 break; 630 case PL_UNIX_SIZE_NUMBER: 631 parser->item_length++; 632 if(c == ' ') { 633 char *p; 634 curl_off_t fsize; 635 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; 636 fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10); 637 if(p[0] == '\0' && fsize != CURL_OFF_T_MAX && 638 fsize != CURL_OFF_T_MIN) { 639 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE; 640 parser->file_data->size = fsize; 641 } 642 parser->item_length = 0; 643 parser->item_offset = 0; 644 parser->state.UNIX.main = PL_UNIX_TIME; 645 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1; 646 } 647 else if(!ISDIGIT(c)) { 648 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 649 return bufflen; 650 } 651 break; 652 } 653 break; 654 case PL_UNIX_TIME: 655 switch(parser->state.UNIX.sub.time) { 656 case PL_UNIX_TIME_PREPART1: 657 if(c != ' ') { 658 if(ISALNUM(c)) { 659 parser->item_offset = finfo->b_used -1; 660 parser->item_length = 1; 661 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1; 662 } 663 else { 664 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 665 return bufflen; 666 } 667 } 668 break; 669 case PL_UNIX_TIME_PART1: 670 parser->item_length++; 671 if(c == ' ') { 672 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2; 673 } 674 else if(!ISALNUM(c) && c != '.') { 675 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 676 return bufflen; 677 } 678 break; 679 case PL_UNIX_TIME_PREPART2: 680 parser->item_length++; 681 if(c != ' ') { 682 if(ISALNUM(c)) { 683 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2; 684 } 685 else { 686 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 687 return bufflen; 688 } 689 } 690 break; 691 case PL_UNIX_TIME_PART2: 692 parser->item_length++; 693 if(c == ' ') { 694 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3; 695 } 696 else if(!ISALNUM(c) && c != '.') { 697 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 698 return bufflen; 699 } 700 break; 701 case PL_UNIX_TIME_PREPART3: 702 parser->item_length++; 703 if(c != ' ') { 704 if(ISALNUM(c)) { 705 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3; 706 } 707 else { 708 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 709 return bufflen; 710 } 711 } 712 break; 713 case PL_UNIX_TIME_PART3: 714 parser->item_length++; 715 if(c == ' ') { 716 finfo->b_data[parser->item_offset + parser->item_length -1] = 0; 717 parser->offsets.time = parser->item_offset; 718 if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) { 719 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME; 720 } 721 if(finfo->filetype == CURLFILETYPE_SYMLINK) { 722 parser->state.UNIX.main = PL_UNIX_SYMLINK; 723 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE; 724 } 725 else { 726 parser->state.UNIX.main = PL_UNIX_FILENAME; 727 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE; 728 } 729 } 730 else if(!ISALNUM(c) && c != '.' && c != ':') { 731 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 732 return bufflen; 733 } 734 break; 735 } 736 break; 737 case PL_UNIX_FILENAME: 738 switch(parser->state.UNIX.sub.filename) { 739 case PL_UNIX_FILENAME_PRESPACE: 740 if(c != ' ') { 741 parser->item_offset = finfo->b_used - 1; 742 parser->item_length = 1; 743 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME; 744 } 745 break; 746 case PL_UNIX_FILENAME_NAME: 747 parser->item_length++; 748 if(c == '\r') { 749 parser->item_length--; 750 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; 751 } 752 else if(c == '\n') { 753 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; 754 parser->offsets.filename = parser->item_offset; 755 parser->state.UNIX.main = PL_UNIX_FILETYPE; 756 rc = ftp_pl_insert_finfo(conn, finfo); 757 if(rc) { 758 PL_ERROR(conn, rc); 759 return bufflen; 760 } 761 } 762 break; 763 case PL_UNIX_FILENAME_WINDOWSEOL: 764 if(c == '\n') { 765 finfo->b_data[parser->item_offset + parser->item_length] = 0; 766 parser->offsets.filename = parser->item_offset; 767 parser->state.UNIX.main = PL_UNIX_FILETYPE; 768 rc = ftp_pl_insert_finfo(conn, finfo); 769 if(rc) { 770 PL_ERROR(conn, rc); 771 return bufflen; 772 } 773 } 774 else { 775 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 776 return bufflen; 777 } 778 break; 779 } 780 break; 781 case PL_UNIX_SYMLINK: 782 switch(parser->state.UNIX.sub.symlink) { 783 case PL_UNIX_SYMLINK_PRESPACE: 784 if(c != ' ') { 785 parser->item_offset = finfo->b_used - 1; 786 parser->item_length = 1; 787 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; 788 } 789 break; 790 case PL_UNIX_SYMLINK_NAME: 791 parser->item_length++; 792 if(c == ' ') { 793 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1; 794 } 795 else if(c == '\r' || c == '\n') { 796 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 797 return bufflen; 798 } 799 break; 800 case PL_UNIX_SYMLINK_PRETARGET1: 801 parser->item_length++; 802 if(c == '-') { 803 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2; 804 } 805 else if(c == '\r' || c == '\n') { 806 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 807 return bufflen; 808 } 809 else { 810 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; 811 } 812 break; 813 case PL_UNIX_SYMLINK_PRETARGET2: 814 parser->item_length++; 815 if(c == '>') { 816 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3; 817 } 818 else if(c == '\r' || c == '\n') { 819 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 820 return bufflen; 821 } 822 else { 823 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; 824 } 825 break; 826 case PL_UNIX_SYMLINK_PRETARGET3: 827 parser->item_length++; 828 if(c == ' ') { 829 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4; 830 /* now place where is symlink following */ 831 finfo->b_data[parser->item_offset + parser->item_length - 4] = 0; 832 parser->offsets.filename = parser->item_offset; 833 parser->item_length = 0; 834 parser->item_offset = 0; 835 } 836 else if(c == '\r' || c == '\n') { 837 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 838 return bufflen; 839 } 840 else { 841 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; 842 } 843 break; 844 case PL_UNIX_SYMLINK_PRETARGET4: 845 if(c != '\r' && c != '\n') { 846 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET; 847 parser->item_offset = finfo->b_used - 1; 848 parser->item_length = 1; 849 } 850 else { 851 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 852 return bufflen; 853 } 854 break; 855 case PL_UNIX_SYMLINK_TARGET: 856 parser->item_length ++; 857 if(c == '\r') { 858 parser->item_length --; 859 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; 860 } 861 else if(c == '\n') { 862 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; 863 parser->offsets.symlink_target = parser->item_offset; 864 rc = ftp_pl_insert_finfo(conn, finfo); 865 if(rc) { 866 PL_ERROR(conn, rc); 867 return bufflen; 868 } 869 parser->state.UNIX.main = PL_UNIX_FILETYPE; 870 } 871 break; 872 case PL_UNIX_SYMLINK_WINDOWSEOL: 873 if(c == '\n') { 874 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; 875 parser->offsets.symlink_target = parser->item_offset; 876 rc = ftp_pl_insert_finfo(conn, finfo); 877 if(rc) { 878 PL_ERROR(conn, rc); 879 return bufflen; 880 } 881 parser->state.UNIX.main = PL_UNIX_FILETYPE; 882 } 883 else { 884 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 885 return bufflen; 886 } 887 break; 888 } 889 break; 890 } 891 break; 892 case OS_TYPE_WIN_NT: 893 switch(parser->state.NT.main) { 894 case PL_WINNT_DATE: 895 parser->item_length++; 896 if(parser->item_length < 9) { 897 if(!strchr("0123456789-", c)) { /* only simple control */ 898 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 899 return bufflen; 900 } 901 } 902 else if(parser->item_length == 9) { 903 if(c == ' ') { 904 parser->state.NT.main = PL_WINNT_TIME; 905 parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE; 906 } 907 else { 908 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 909 return bufflen; 910 } 911 } 912 else { 913 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 914 return bufflen; 915 } 916 break; 917 case PL_WINNT_TIME: 918 parser->item_length++; 919 switch(parser->state.NT.sub.time) { 920 case PL_WINNT_TIME_PRESPACE: 921 if(!ISSPACE(c)) { 922 parser->state.NT.sub.time = PL_WINNT_TIME_TIME; 923 } 924 break; 925 case PL_WINNT_TIME_TIME: 926 if(c == ' ') { 927 parser->offsets.time = parser->item_offset; 928 finfo->b_data[parser->item_offset + parser->item_length -1] = 0; 929 parser->state.NT.main = PL_WINNT_DIRORSIZE; 930 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE; 931 parser->item_length = 0; 932 } 933 else if(!strchr("APM0123456789:", c)) { 934 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 935 return bufflen; 936 } 937 break; 938 } 939 break; 940 case PL_WINNT_DIRORSIZE: 941 switch(parser->state.NT.sub.dirorsize) { 942 case PL_WINNT_DIRORSIZE_PRESPACE: 943 if(c == ' ') { 944 945 } 946 else { 947 parser->item_offset = finfo->b_used - 1; 948 parser->item_length = 1; 949 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT; 950 } 951 break; 952 case PL_WINNT_DIRORSIZE_CONTENT: 953 parser->item_length ++; 954 if(c == ' ') { 955 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; 956 if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) { 957 finfo->filetype = CURLFILETYPE_DIRECTORY; 958 finfo->size = 0; 959 } 960 else { 961 char *endptr; 962 finfo->size = curlx_strtoofft(finfo->b_data + 963 parser->item_offset, 964 &endptr, 10); 965 if(!*endptr) { 966 if(finfo->size == CURL_OFF_T_MAX || 967 finfo->size == CURL_OFF_T_MIN) { 968 if(errno == ERANGE) { 969 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 970 return bufflen; 971 } 972 } 973 } 974 else { 975 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 976 return bufflen; 977 } 978 /* correct file type */ 979 parser->file_data->filetype = CURLFILETYPE_FILE; 980 } 981 982 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE; 983 parser->item_length = 0; 984 parser->state.NT.main = PL_WINNT_FILENAME; 985 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; 986 } 987 break; 988 } 989 break; 990 case PL_WINNT_FILENAME: 991 switch (parser->state.NT.sub.filename) { 992 case PL_WINNT_FILENAME_PRESPACE: 993 if(c != ' ') { 994 parser->item_offset = finfo->b_used -1; 995 parser->item_length = 1; 996 parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT; 997 } 998 break; 999 case PL_WINNT_FILENAME_CONTENT: 1000 parser->item_length++; 1001 if(c == '\r') { 1002 parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL; 1003 finfo->b_data[finfo->b_used - 1] = 0; 1004 } 1005 else if(c == '\n') { 1006 parser->offsets.filename = parser->item_offset; 1007 finfo->b_data[finfo->b_used - 1] = 0; 1008 parser->offsets.filename = parser->item_offset; 1009 rc = ftp_pl_insert_finfo(conn, finfo); 1010 if(rc) { 1011 PL_ERROR(conn, rc); 1012 return bufflen; 1013 } 1014 parser->state.NT.main = PL_WINNT_DATE; 1015 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; 1016 } 1017 break; 1018 case PL_WINNT_FILENAME_WINEOL: 1019 if(c == '\n') { 1020 parser->offsets.filename = parser->item_offset; 1021 rc = ftp_pl_insert_finfo(conn, finfo); 1022 if(rc) { 1023 PL_ERROR(conn, rc); 1024 return bufflen; 1025 } 1026 parser->state.NT.main = PL_WINNT_DATE; 1027 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; 1028 } 1029 else { 1030 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); 1031 return bufflen; 1032 } 1033 break; 1034 } 1035 break; 1036 } 1037 break; 1038 default: 1039 return bufflen+1; 1040 } 1041 1042 i++; 1043 } 1044 1045 return bufflen; 1046} 1047