1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
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 https://curl.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
27 * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog
29 * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog
31 * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog
33 * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000
35 * 01-29-97 11:32PM <DIR> prog
38 #include "curl_setup.h"
40 #ifndef CURL_DISABLE_FTP
42 #include <curl/curl.h>
47 #include "strtoofft.h"
49 #include "ftplistparser.h"
50 #include "curl_fnmatch.h"
51 #include "curl_memory.h"
53 /* The last #include file should be: */
56 /* allocs buffer which will contain one line of LIST command response */
57 #define FTP_BUFFER_ALLOCSIZE 160
60 PL_UNIX_TOTALSIZE = 0,
74 PL_UNIX_TOTALSIZE_INIT = 0,
75 PL_UNIX_TOTALSIZE_READING
79 PL_UNIX_HLINKS_PRESPACE = 0,
84 PL_UNIX_USER_PRESPACE = 0,
89 PL_UNIX_GROUP_PRESPACE = 0,
94 PL_UNIX_SIZE_PRESPACE = 0,
99 PL_UNIX_TIME_PREPART1 = 0,
101 PL_UNIX_TIME_PREPART2,
103 PL_UNIX_TIME_PREPART3,
108 PL_UNIX_FILENAME_PRESPACE = 0,
109 PL_UNIX_FILENAME_NAME,
110 PL_UNIX_FILENAME_WINDOWSEOL
114 PL_UNIX_SYMLINK_PRESPACE = 0,
115 PL_UNIX_SYMLINK_NAME,
116 PL_UNIX_SYMLINK_PRETARGET1,
117 PL_UNIX_SYMLINK_PRETARGET2,
118 PL_UNIX_SYMLINK_PRETARGET3,
119 PL_UNIX_SYMLINK_PRETARGET4,
120 PL_UNIX_SYMLINK_TARGET,
121 PL_UNIX_SYMLINK_WINDOWSEOL
130 } pl_winNT_mainstate;
134 PL_WINNT_TIME_PRESPACE = 0,
138 PL_WINNT_DIRORSIZE_PRESPACE = 0,
139 PL_WINNT_DIRORSIZE_CONTENT
142 PL_WINNT_FILENAME_PRESPACE = 0,
143 PL_WINNT_FILENAME_CONTENT,
144 PL_WINNT_FILENAME_WINEOL
148 /* This struct is used in wildcard downloading - for parsing LIST response */
149 struct ftp_parselist_data {
158 pl_unix_mainstate main;
159 pl_unix_substate sub;
163 pl_winNT_mainstate main;
164 pl_winNT_substate sub;
169 struct fileinfo *file_data;
170 unsigned int item_length;
178 size_t symlink_target;
182 struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
184 return calloc(1, sizeof(struct ftp_parselist_data));
188 void Curl_ftp_parselist_data_free(struct ftp_parselist_data **parserp)
190 struct ftp_parselist_data *parser = *parserp;
192 Curl_fileinfo_cleanup(parser->file_data);
198 CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
200 return pl_data->error;
204 #define FTP_LP_MALFORMATED_PERM 0x01000000
206 static int ftp_pl_get_permission(const char *str)
211 permissions |= 1 << 8;
212 else if(str[0] != '-')
213 permissions |= FTP_LP_MALFORMATED_PERM;
215 permissions |= 1 << 7;
216 else if(str[1] != '-')
217 permissions |= FTP_LP_MALFORMATED_PERM;
220 permissions |= 1 << 6;
221 else if(str[2] == 's') {
222 permissions |= 1 << 6;
223 permissions |= 1 << 11;
225 else if(str[2] == 'S')
226 permissions |= 1 << 11;
227 else if(str[2] != '-')
228 permissions |= FTP_LP_MALFORMATED_PERM;
231 permissions |= 1 << 5;
232 else if(str[3] != '-')
233 permissions |= FTP_LP_MALFORMATED_PERM;
235 permissions |= 1 << 4;
236 else if(str[4] != '-')
237 permissions |= FTP_LP_MALFORMATED_PERM;
239 permissions |= 1 << 3;
240 else if(str[5] == 's') {
241 permissions |= 1 << 3;
242 permissions |= 1 << 10;
244 else if(str[5] == 'S')
245 permissions |= 1 << 10;
246 else if(str[5] != '-')
247 permissions |= FTP_LP_MALFORMATED_PERM;
250 permissions |= 1 << 2;
251 else if(str[6] != '-')
252 permissions |= FTP_LP_MALFORMATED_PERM;
254 permissions |= 1 << 1;
255 else if(str[7] != '-')
256 permissions |= FTP_LP_MALFORMATED_PERM;
259 else if(str[8] == 't') {
261 permissions |= 1 << 9;
263 else if(str[8] == 'T')
264 permissions |= 1 << 9;
265 else if(str[8] != '-')
266 permissions |= FTP_LP_MALFORMATED_PERM;
271 static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
272 struct fileinfo *infop)
274 curl_fnmatch_callback compare;
275 struct WildcardData *wc = &data->wildcard;
276 struct ftp_wc *ftpwc = wc->protdata;
277 struct Curl_llist *llist = &wc->filelist;
278 struct ftp_parselist_data *parser = ftpwc->parser;
280 struct curl_fileinfo *finfo = &infop->info;
282 /* move finfo pointers to b_data */
283 char *str = finfo->b_data;
284 finfo->filename = str + parser->offsets.filename;
285 finfo->strings.group = parser->offsets.group ?
286 str + parser->offsets.group : NULL;
287 finfo->strings.perm = parser->offsets.perm ?
288 str + parser->offsets.perm : NULL;
289 finfo->strings.target = parser->offsets.symlink_target ?
290 str + parser->offsets.symlink_target : NULL;
291 finfo->strings.time = str + parser->offsets.time;
292 finfo->strings.user = parser->offsets.user ?
293 str + parser->offsets.user : NULL;
295 /* get correct fnmatch callback */
296 compare = data->set.fnmatch;
298 compare = Curl_fnmatch;
300 /* filter pattern-corresponding filenames */
301 Curl_set_in_callback(data, true);
302 if(compare(data->set.fnmatch_data, wc->pattern,
303 finfo->filename) == 0) {
304 /* discard symlink which is containing multiple " -> " */
305 if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
306 (strstr(finfo->strings.target, " -> "))) {
313 Curl_set_in_callback(data, false);
316 Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
319 Curl_fileinfo_cleanup(infop);
322 ftpwc->parser->file_data = NULL;
326 size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
329 size_t bufflen = size*nmemb;
330 struct Curl_easy *data = (struct Curl_easy *)connptr;
331 struct ftp_wc *ftpwc = data->wildcard.protdata;
332 struct ftp_parselist_data *parser = ftpwc->parser;
333 struct fileinfo *infop;
334 struct curl_fileinfo *finfo;
337 size_t retsize = bufflen;
339 if(parser->error) { /* error in previous call */
342 * 2. call => OUT_OF_MEMORY (or other error)
343 * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
349 if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
350 /* considering info about FILE response format */
351 parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
352 OS_TYPE_WIN_NT : OS_TYPE_UNIX;
355 while(i < bufflen) { /* FSM */
358 if(!parser->file_data) { /* tmp file data is not allocated yet */
359 parser->file_data = Curl_fileinfo_alloc();
360 if(!parser->file_data) {
361 parser->error = CURLE_OUT_OF_MEMORY;
364 parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE);
365 if(!parser->file_data->info.b_data) {
366 parser->error = CURLE_OUT_OF_MEMORY;
369 parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE;
370 parser->item_offset = 0;
371 parser->item_length = 0;
374 infop = parser->file_data;
375 finfo = &infop->info;
376 finfo->b_data[finfo->b_used++] = c;
378 if(finfo->b_used >= finfo->b_size - 1) {
379 /* if it is important, extend buffer space for file data */
380 char *tmp = realloc(finfo->b_data,
381 finfo->b_size + FTP_BUFFER_ALLOCSIZE);
383 finfo->b_size += FTP_BUFFER_ALLOCSIZE;
387 Curl_fileinfo_cleanup(parser->file_data);
388 parser->file_data = NULL;
389 parser->error = CURLE_OUT_OF_MEMORY;
394 switch(parser->os_type) {
396 switch(parser->state.UNIX.main) {
397 case PL_UNIX_TOTALSIZE:
398 switch(parser->state.UNIX.sub.total_dirsize) {
399 case PL_UNIX_TOTALSIZE_INIT:
401 parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
402 parser->item_length++;
405 parser->state.UNIX.main = PL_UNIX_FILETYPE;
406 /* start FSM again not considering size of directory */
411 case PL_UNIX_TOTALSIZE_READING:
412 parser->item_length++;
414 parser->item_length--;
418 finfo->b_data[parser->item_length - 1] = 0;
419 if(strncmp("total ", finfo->b_data, 6) == 0) {
420 char *endptr = finfo->b_data + 6;
421 /* here we can deal with directory size, pass the leading
422 whitespace and then the digits */
423 while(ISSPACE(*endptr))
425 while(ISDIGIT(*endptr))
428 parser->error = CURLE_FTP_BAD_FILE_LIST;
431 parser->state.UNIX.main = PL_UNIX_FILETYPE;
435 parser->error = CURLE_FTP_BAD_FILE_LIST;
442 case PL_UNIX_FILETYPE:
445 finfo->filetype = CURLFILETYPE_FILE;
448 finfo->filetype = CURLFILETYPE_DIRECTORY;
451 finfo->filetype = CURLFILETYPE_SYMLINK;
454 finfo->filetype = CURLFILETYPE_NAMEDPIPE;
457 finfo->filetype = CURLFILETYPE_SOCKET;
460 finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
463 finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
466 finfo->filetype = CURLFILETYPE_DOOR;
469 parser->error = CURLE_FTP_BAD_FILE_LIST;
472 parser->state.UNIX.main = PL_UNIX_PERMISSION;
473 parser->item_length = 0;
474 parser->item_offset = 1;
476 case PL_UNIX_PERMISSION:
477 parser->item_length++;
478 if(parser->item_length <= 9) {
479 if(!strchr("rwx-tTsS", c)) {
480 parser->error = CURLE_FTP_BAD_FILE_LIST;
484 else if(parser->item_length == 10) {
487 parser->error = CURLE_FTP_BAD_FILE_LIST;
490 finfo->b_data[10] = 0; /* terminate permissions */
491 perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
492 if(perm & FTP_LP_MALFORMATED_PERM) {
493 parser->error = CURLE_FTP_BAD_FILE_LIST;
496 parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
497 parser->file_data->info.perm = perm;
498 parser->offsets.perm = parser->item_offset;
500 parser->item_length = 0;
501 parser->state.UNIX.main = PL_UNIX_HLINKS;
502 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
506 switch(parser->state.UNIX.sub.hlinks) {
507 case PL_UNIX_HLINKS_PRESPACE:
509 if(c >= '0' && c <= '9') {
510 parser->item_offset = finfo->b_used - 1;
511 parser->item_length = 1;
512 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
515 parser->error = CURLE_FTP_BAD_FILE_LIST;
520 case PL_UNIX_HLINKS_NUMBER:
521 parser->item_length ++;
525 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
526 hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
527 if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
528 parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
529 parser->file_data->info.hardlinks = hlinks;
531 parser->item_length = 0;
532 parser->item_offset = 0;
533 parser->state.UNIX.main = PL_UNIX_USER;
534 parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
536 else if(c < '0' || c > '9') {
537 parser->error = CURLE_FTP_BAD_FILE_LIST;
544 switch(parser->state.UNIX.sub.user) {
545 case PL_UNIX_USER_PRESPACE:
547 parser->item_offset = finfo->b_used - 1;
548 parser->item_length = 1;
549 parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
552 case PL_UNIX_USER_PARSING:
553 parser->item_length++;
555 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
556 parser->offsets.user = parser->item_offset;
557 parser->state.UNIX.main = PL_UNIX_GROUP;
558 parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
559 parser->item_offset = 0;
560 parser->item_length = 0;
566 switch(parser->state.UNIX.sub.group) {
567 case PL_UNIX_GROUP_PRESPACE:
569 parser->item_offset = finfo->b_used - 1;
570 parser->item_length = 1;
571 parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
574 case PL_UNIX_GROUP_NAME:
575 parser->item_length++;
577 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
578 parser->offsets.group = parser->item_offset;
579 parser->state.UNIX.main = PL_UNIX_SIZE;
580 parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
581 parser->item_offset = 0;
582 parser->item_length = 0;
588 switch(parser->state.UNIX.sub.size) {
589 case PL_UNIX_SIZE_PRESPACE:
591 if(c >= '0' && c <= '9') {
592 parser->item_offset = finfo->b_used - 1;
593 parser->item_length = 1;
594 parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
597 parser->error = CURLE_FTP_BAD_FILE_LIST;
602 case PL_UNIX_SIZE_NUMBER:
603 parser->item_length++;
607 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
608 if(!curlx_strtoofft(finfo->b_data + parser->item_offset,
610 if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
611 fsize != CURL_OFF_T_MIN) {
612 parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
613 parser->file_data->info.size = fsize;
615 parser->item_length = 0;
616 parser->item_offset = 0;
617 parser->state.UNIX.main = PL_UNIX_TIME;
618 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
621 else if(!ISDIGIT(c)) {
622 parser->error = CURLE_FTP_BAD_FILE_LIST;
629 switch(parser->state.UNIX.sub.time) {
630 case PL_UNIX_TIME_PREPART1:
633 parser->item_offset = finfo->b_used -1;
634 parser->item_length = 1;
635 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
638 parser->error = CURLE_FTP_BAD_FILE_LIST;
643 case PL_UNIX_TIME_PART1:
644 parser->item_length++;
646 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
648 else if(!ISALNUM(c) && c != '.') {
649 parser->error = CURLE_FTP_BAD_FILE_LIST;
653 case PL_UNIX_TIME_PREPART2:
654 parser->item_length++;
657 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
660 parser->error = CURLE_FTP_BAD_FILE_LIST;
665 case PL_UNIX_TIME_PART2:
666 parser->item_length++;
668 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
670 else if(!ISALNUM(c) && c != '.') {
671 parser->error = CURLE_FTP_BAD_FILE_LIST;
675 case PL_UNIX_TIME_PREPART3:
676 parser->item_length++;
679 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
682 parser->error = CURLE_FTP_BAD_FILE_LIST;
687 case PL_UNIX_TIME_PART3:
688 parser->item_length++;
690 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
691 parser->offsets.time = parser->item_offset;
693 if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
694 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
697 if(finfo->filetype == CURLFILETYPE_SYMLINK) {
698 parser->state.UNIX.main = PL_UNIX_SYMLINK;
699 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
702 parser->state.UNIX.main = PL_UNIX_FILENAME;
703 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
706 else if(!ISALNUM(c) && c != '.' && c != ':') {
707 parser->error = CURLE_FTP_BAD_FILE_LIST;
713 case PL_UNIX_FILENAME:
714 switch(parser->state.UNIX.sub.filename) {
715 case PL_UNIX_FILENAME_PRESPACE:
717 parser->item_offset = finfo->b_used - 1;
718 parser->item_length = 1;
719 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
722 case PL_UNIX_FILENAME_NAME:
723 parser->item_length++;
725 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
728 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
729 parser->offsets.filename = parser->item_offset;
730 parser->state.UNIX.main = PL_UNIX_FILETYPE;
731 result = ftp_pl_insert_finfo(data, infop);
733 parser->error = result;
738 case PL_UNIX_FILENAME_WINDOWSEOL:
740 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
741 parser->offsets.filename = parser->item_offset;
742 parser->state.UNIX.main = PL_UNIX_FILETYPE;
743 result = ftp_pl_insert_finfo(data, infop);
745 parser->error = result;
750 parser->error = CURLE_FTP_BAD_FILE_LIST;
756 case PL_UNIX_SYMLINK:
757 switch(parser->state.UNIX.sub.symlink) {
758 case PL_UNIX_SYMLINK_PRESPACE:
760 parser->item_offset = finfo->b_used - 1;
761 parser->item_length = 1;
762 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
765 case PL_UNIX_SYMLINK_NAME:
766 parser->item_length++;
768 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
770 else if(c == '\r' || c == '\n') {
771 parser->error = CURLE_FTP_BAD_FILE_LIST;
775 case PL_UNIX_SYMLINK_PRETARGET1:
776 parser->item_length++;
778 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
780 else if(c == '\r' || c == '\n') {
781 parser->error = CURLE_FTP_BAD_FILE_LIST;
785 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
788 case PL_UNIX_SYMLINK_PRETARGET2:
789 parser->item_length++;
791 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
793 else if(c == '\r' || c == '\n') {
794 parser->error = CURLE_FTP_BAD_FILE_LIST;
798 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
801 case PL_UNIX_SYMLINK_PRETARGET3:
802 parser->item_length++;
804 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
805 /* now place where is symlink following */
806 finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
807 parser->offsets.filename = parser->item_offset;
808 parser->item_length = 0;
809 parser->item_offset = 0;
811 else if(c == '\r' || c == '\n') {
812 parser->error = CURLE_FTP_BAD_FILE_LIST;
816 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
819 case PL_UNIX_SYMLINK_PRETARGET4:
820 if(c != '\r' && c != '\n') {
821 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
822 parser->item_offset = finfo->b_used - 1;
823 parser->item_length = 1;
826 parser->error = CURLE_FTP_BAD_FILE_LIST;
830 case PL_UNIX_SYMLINK_TARGET:
831 parser->item_length++;
833 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
836 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
837 parser->offsets.symlink_target = parser->item_offset;
838 result = ftp_pl_insert_finfo(data, infop);
840 parser->error = result;
843 parser->state.UNIX.main = PL_UNIX_FILETYPE;
846 case PL_UNIX_SYMLINK_WINDOWSEOL:
848 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
849 parser->offsets.symlink_target = parser->item_offset;
850 result = ftp_pl_insert_finfo(data, infop);
852 parser->error = result;
855 parser->state.UNIX.main = PL_UNIX_FILETYPE;
858 parser->error = CURLE_FTP_BAD_FILE_LIST;
867 switch(parser->state.NT.main) {
869 parser->item_length++;
870 if(parser->item_length < 9) {
871 if(!strchr("0123456789-", c)) { /* only simple control */
872 parser->error = CURLE_FTP_BAD_FILE_LIST;
876 else if(parser->item_length == 9) {
878 parser->state.NT.main = PL_WINNT_TIME;
879 parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
882 parser->error = CURLE_FTP_BAD_FILE_LIST;
887 parser->error = CURLE_FTP_BAD_FILE_LIST;
892 parser->item_length++;
893 switch(parser->state.NT.sub.time) {
894 case PL_WINNT_TIME_PRESPACE:
896 parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
899 case PL_WINNT_TIME_TIME:
901 parser->offsets.time = parser->item_offset;
902 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
903 parser->state.NT.main = PL_WINNT_DIRORSIZE;
904 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
905 parser->item_length = 0;
907 else if(!strchr("APM0123456789:", c)) {
908 parser->error = CURLE_FTP_BAD_FILE_LIST;
914 case PL_WINNT_DIRORSIZE:
915 switch(parser->state.NT.sub.dirorsize) {
916 case PL_WINNT_DIRORSIZE_PRESPACE:
918 parser->item_offset = finfo->b_used - 1;
919 parser->item_length = 1;
920 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
923 case PL_WINNT_DIRORSIZE_CONTENT:
924 parser->item_length ++;
926 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
927 if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
928 finfo->filetype = CURLFILETYPE_DIRECTORY;
933 if(curlx_strtoofft(finfo->b_data +
935 &endptr, 10, &finfo->size)) {
936 parser->error = CURLE_FTP_BAD_FILE_LIST;
939 /* correct file type */
940 parser->file_data->info.filetype = CURLFILETYPE_FILE;
943 parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
944 parser->item_length = 0;
945 parser->state.NT.main = PL_WINNT_FILENAME;
946 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
951 case PL_WINNT_FILENAME:
952 switch(parser->state.NT.sub.filename) {
953 case PL_WINNT_FILENAME_PRESPACE:
955 parser->item_offset = finfo->b_used -1;
956 parser->item_length = 1;
957 parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
960 case PL_WINNT_FILENAME_CONTENT:
961 parser->item_length++;
963 parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
964 finfo->b_data[finfo->b_used - 1] = 0;
967 parser->offsets.filename = parser->item_offset;
968 finfo->b_data[finfo->b_used - 1] = 0;
969 result = ftp_pl_insert_finfo(data, infop);
971 parser->error = result;
974 parser->state.NT.main = PL_WINNT_DATE;
975 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
978 case PL_WINNT_FILENAME_WINEOL:
980 parser->offsets.filename = parser->item_offset;
981 result = ftp_pl_insert_finfo(data, infop);
983 parser->error = result;
986 parser->state.NT.main = PL_WINNT_DATE;
987 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
990 parser->error = CURLE_FTP_BAD_FILE_LIST;
999 retsize = bufflen + 1;
1009 /* Clean up any allocated memory. */
1010 if(parser->file_data) {
1011 Curl_fileinfo_cleanup(parser->file_data);
1012 parser->file_data = NULL;
1018 #endif /* CURL_DISABLE_FTP */