1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2017, 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.haxx.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 **pl_data)
195 CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
197 return pl_data->error;
201 #define FTP_LP_MALFORMATED_PERM 0x01000000
203 static int ftp_pl_get_permission(const char *str)
208 permissions |= 1 << 8;
209 else if(str[0] != '-')
210 permissions |= FTP_LP_MALFORMATED_PERM;
212 permissions |= 1 << 7;
213 else if(str[1] != '-')
214 permissions |= FTP_LP_MALFORMATED_PERM;
217 permissions |= 1 << 6;
218 else if(str[2] == 's') {
219 permissions |= 1 << 6;
220 permissions |= 1 << 11;
222 else if(str[2] == 'S')
223 permissions |= 1 << 11;
224 else if(str[2] != '-')
225 permissions |= FTP_LP_MALFORMATED_PERM;
228 permissions |= 1 << 5;
229 else if(str[3] != '-')
230 permissions |= FTP_LP_MALFORMATED_PERM;
232 permissions |= 1 << 4;
233 else if(str[4] != '-')
234 permissions |= FTP_LP_MALFORMATED_PERM;
236 permissions |= 1 << 3;
237 else if(str[5] == 's') {
238 permissions |= 1 << 3;
239 permissions |= 1 << 10;
241 else if(str[5] == 'S')
242 permissions |= 1 << 10;
243 else if(str[5] != '-')
244 permissions |= FTP_LP_MALFORMATED_PERM;
247 permissions |= 1 << 2;
248 else if(str[6] != '-')
249 permissions |= FTP_LP_MALFORMATED_PERM;
251 permissions |= 1 << 1;
252 else if(str[7] != '-')
253 permissions |= FTP_LP_MALFORMATED_PERM;
256 else if(str[8] == 't') {
258 permissions |= 1 << 9;
260 else if(str[8] == 'T')
261 permissions |= 1 << 9;
262 else if(str[8] != '-')
263 permissions |= FTP_LP_MALFORMATED_PERM;
268 static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
269 struct fileinfo *infop)
271 curl_fnmatch_callback compare;
272 struct WildcardData *wc = &conn->data->wildcard;
273 struct ftp_wc_tmpdata *tmpdata = wc->tmp;
274 struct curl_llist *llist = &wc->filelist;
275 struct ftp_parselist_data *parser = tmpdata->parser;
277 struct curl_fileinfo *finfo = &infop->info;
279 /* move finfo pointers to b_data */
280 char *str = finfo->b_data;
281 finfo->filename = str + parser->offsets.filename;
282 finfo->strings.group = parser->offsets.group ?
283 str + parser->offsets.group : NULL;
284 finfo->strings.perm = parser->offsets.perm ?
285 str + parser->offsets.perm : NULL;
286 finfo->strings.target = parser->offsets.symlink_target ?
287 str + parser->offsets.symlink_target : NULL;
288 finfo->strings.time = str + parser->offsets.time;
289 finfo->strings.user = parser->offsets.user ?
290 str + parser->offsets.user : NULL;
292 /* get correct fnmatch callback */
293 compare = conn->data->set.fnmatch;
295 compare = Curl_fnmatch;
297 /* filter pattern-corresponding filenames */
298 Curl_set_in_callback(conn->data, true);
299 if(compare(conn->data->set.fnmatch_data, wc->pattern,
300 finfo->filename) == 0) {
301 /* discard symlink which is containing multiple " -> " */
302 if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
303 (strstr(finfo->strings.target, " -> "))) {
310 Curl_set_in_callback(conn->data, false);
313 Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
316 Curl_fileinfo_dtor(NULL, finfo);
319 tmpdata->parser->file_data = NULL;
323 size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
326 size_t bufflen = size*nmemb;
327 struct connectdata *conn = (struct connectdata *)connptr;
328 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
329 struct ftp_parselist_data *parser = tmpdata->parser;
330 struct fileinfo *infop;
331 struct curl_fileinfo *finfo;
334 size_t retsize = bufflen;
336 if(parser->error) { /* error in previous call */
339 * 2. call => OUT_OF_MEMORY (or other error)
340 * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
346 if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
347 /* considering info about FILE response format */
348 parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
349 OS_TYPE_WIN_NT : OS_TYPE_UNIX;
352 while(i < bufflen) { /* FSM */
355 if(!parser->file_data) { /* tmp file data is not allocated yet */
356 parser->file_data = Curl_fileinfo_alloc();
357 if(!parser->file_data) {
358 parser->error = CURLE_OUT_OF_MEMORY;
361 parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE);
362 if(!parser->file_data->info.b_data) {
363 parser->error = CURLE_OUT_OF_MEMORY;
366 parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE;
367 parser->item_offset = 0;
368 parser->item_length = 0;
371 infop = parser->file_data;
372 finfo = &infop->info;
373 finfo->b_data[finfo->b_used++] = c;
375 if(finfo->b_used >= finfo->b_size - 1) {
376 /* if it is important, extend buffer space for file data */
377 char *tmp = realloc(finfo->b_data,
378 finfo->b_size + FTP_BUFFER_ALLOCSIZE);
380 finfo->b_size += FTP_BUFFER_ALLOCSIZE;
384 Curl_fileinfo_dtor(NULL, parser->file_data);
385 parser->file_data = NULL;
386 parser->error = CURLE_OUT_OF_MEMORY;
391 switch(parser->os_type) {
393 switch(parser->state.UNIX.main) {
394 case PL_UNIX_TOTALSIZE:
395 switch(parser->state.UNIX.sub.total_dirsize) {
396 case PL_UNIX_TOTALSIZE_INIT:
398 parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
399 parser->item_length++;
402 parser->state.UNIX.main = PL_UNIX_FILETYPE;
403 /* start FSM again not considering size of directory */
408 case PL_UNIX_TOTALSIZE_READING:
409 parser->item_length++;
411 parser->item_length--;
415 finfo->b_data[parser->item_length - 1] = 0;
416 if(strncmp("total ", finfo->b_data, 6) == 0) {
417 char *endptr = finfo->b_data + 6;
418 /* here we can deal with directory size, pass the leading white
419 spaces and then the digits */
420 while(ISSPACE(*endptr))
422 while(ISDIGIT(*endptr))
425 parser->error = CURLE_FTP_BAD_FILE_LIST;
428 parser->state.UNIX.main = PL_UNIX_FILETYPE;
432 parser->error = CURLE_FTP_BAD_FILE_LIST;
439 case PL_UNIX_FILETYPE:
442 finfo->filetype = CURLFILETYPE_FILE;
445 finfo->filetype = CURLFILETYPE_DIRECTORY;
448 finfo->filetype = CURLFILETYPE_SYMLINK;
451 finfo->filetype = CURLFILETYPE_NAMEDPIPE;
454 finfo->filetype = CURLFILETYPE_SOCKET;
457 finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
460 finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
463 finfo->filetype = CURLFILETYPE_DOOR;
466 parser->error = CURLE_FTP_BAD_FILE_LIST;
469 parser->state.UNIX.main = PL_UNIX_PERMISSION;
470 parser->item_length = 0;
471 parser->item_offset = 1;
473 case PL_UNIX_PERMISSION:
474 parser->item_length++;
475 if(parser->item_length <= 9) {
476 if(!strchr("rwx-tTsS", c)) {
477 parser->error = CURLE_FTP_BAD_FILE_LIST;
481 else if(parser->item_length == 10) {
484 parser->error = CURLE_FTP_BAD_FILE_LIST;
487 finfo->b_data[10] = 0; /* terminate permissions */
488 perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
489 if(perm & FTP_LP_MALFORMATED_PERM) {
490 parser->error = CURLE_FTP_BAD_FILE_LIST;
493 parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
494 parser->file_data->info.perm = perm;
495 parser->offsets.perm = parser->item_offset;
497 parser->item_length = 0;
498 parser->state.UNIX.main = PL_UNIX_HLINKS;
499 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
503 switch(parser->state.UNIX.sub.hlinks) {
504 case PL_UNIX_HLINKS_PRESPACE:
506 if(c >= '0' && c <= '9') {
507 parser->item_offset = finfo->b_used - 1;
508 parser->item_length = 1;
509 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
512 parser->error = CURLE_FTP_BAD_FILE_LIST;
517 case PL_UNIX_HLINKS_NUMBER:
518 parser->item_length ++;
522 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
523 hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
524 if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
525 parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
526 parser->file_data->info.hardlinks = hlinks;
528 parser->item_length = 0;
529 parser->item_offset = 0;
530 parser->state.UNIX.main = PL_UNIX_USER;
531 parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
533 else if(c < '0' || c > '9') {
534 parser->error = CURLE_FTP_BAD_FILE_LIST;
541 switch(parser->state.UNIX.sub.user) {
542 case PL_UNIX_USER_PRESPACE:
544 parser->item_offset = finfo->b_used - 1;
545 parser->item_length = 1;
546 parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
549 case PL_UNIX_USER_PARSING:
550 parser->item_length++;
552 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
553 parser->offsets.user = parser->item_offset;
554 parser->state.UNIX.main = PL_UNIX_GROUP;
555 parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
556 parser->item_offset = 0;
557 parser->item_length = 0;
563 switch(parser->state.UNIX.sub.group) {
564 case PL_UNIX_GROUP_PRESPACE:
566 parser->item_offset = finfo->b_used - 1;
567 parser->item_length = 1;
568 parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
571 case PL_UNIX_GROUP_NAME:
572 parser->item_length++;
574 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
575 parser->offsets.group = parser->item_offset;
576 parser->state.UNIX.main = PL_UNIX_SIZE;
577 parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
578 parser->item_offset = 0;
579 parser->item_length = 0;
585 switch(parser->state.UNIX.sub.size) {
586 case PL_UNIX_SIZE_PRESPACE:
588 if(c >= '0' && c <= '9') {
589 parser->item_offset = finfo->b_used - 1;
590 parser->item_length = 1;
591 parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
594 parser->error = CURLE_FTP_BAD_FILE_LIST;
599 case PL_UNIX_SIZE_NUMBER:
600 parser->item_length++;
604 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
605 if(!curlx_strtoofft(finfo->b_data + parser->item_offset,
607 if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
608 fsize != CURL_OFF_T_MIN) {
609 parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
610 parser->file_data->info.size = fsize;
612 parser->item_length = 0;
613 parser->item_offset = 0;
614 parser->state.UNIX.main = PL_UNIX_TIME;
615 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
618 else if(!ISDIGIT(c)) {
619 parser->error = CURLE_FTP_BAD_FILE_LIST;
626 switch(parser->state.UNIX.sub.time) {
627 case PL_UNIX_TIME_PREPART1:
630 parser->item_offset = finfo->b_used -1;
631 parser->item_length = 1;
632 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
635 parser->error = CURLE_FTP_BAD_FILE_LIST;
640 case PL_UNIX_TIME_PART1:
641 parser->item_length++;
643 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
645 else if(!ISALNUM(c) && c != '.') {
646 parser->error = CURLE_FTP_BAD_FILE_LIST;
650 case PL_UNIX_TIME_PREPART2:
651 parser->item_length++;
654 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
657 parser->error = CURLE_FTP_BAD_FILE_LIST;
662 case PL_UNIX_TIME_PART2:
663 parser->item_length++;
665 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
667 else if(!ISALNUM(c) && c != '.') {
668 parser->error = CURLE_FTP_BAD_FILE_LIST;
672 case PL_UNIX_TIME_PREPART3:
673 parser->item_length++;
676 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
679 parser->error = CURLE_FTP_BAD_FILE_LIST;
684 case PL_UNIX_TIME_PART3:
685 parser->item_length++;
687 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
688 parser->offsets.time = parser->item_offset;
690 if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
691 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
694 if(finfo->filetype == CURLFILETYPE_SYMLINK) {
695 parser->state.UNIX.main = PL_UNIX_SYMLINK;
696 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
699 parser->state.UNIX.main = PL_UNIX_FILENAME;
700 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
703 else if(!ISALNUM(c) && c != '.' && c != ':') {
704 parser->error = CURLE_FTP_BAD_FILE_LIST;
710 case PL_UNIX_FILENAME:
711 switch(parser->state.UNIX.sub.filename) {
712 case PL_UNIX_FILENAME_PRESPACE:
714 parser->item_offset = finfo->b_used - 1;
715 parser->item_length = 1;
716 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
719 case PL_UNIX_FILENAME_NAME:
720 parser->item_length++;
722 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
725 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
726 parser->offsets.filename = parser->item_offset;
727 parser->state.UNIX.main = PL_UNIX_FILETYPE;
728 result = ftp_pl_insert_finfo(conn, infop);
730 parser->error = result;
735 case PL_UNIX_FILENAME_WINDOWSEOL:
737 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
738 parser->offsets.filename = parser->item_offset;
739 parser->state.UNIX.main = PL_UNIX_FILETYPE;
740 result = ftp_pl_insert_finfo(conn, infop);
742 parser->error = result;
747 parser->error = CURLE_FTP_BAD_FILE_LIST;
753 case PL_UNIX_SYMLINK:
754 switch(parser->state.UNIX.sub.symlink) {
755 case PL_UNIX_SYMLINK_PRESPACE:
757 parser->item_offset = finfo->b_used - 1;
758 parser->item_length = 1;
759 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
762 case PL_UNIX_SYMLINK_NAME:
763 parser->item_length++;
765 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
767 else if(c == '\r' || c == '\n') {
768 parser->error = CURLE_FTP_BAD_FILE_LIST;
772 case PL_UNIX_SYMLINK_PRETARGET1:
773 parser->item_length++;
775 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
777 else if(c == '\r' || c == '\n') {
778 parser->error = CURLE_FTP_BAD_FILE_LIST;
782 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
785 case PL_UNIX_SYMLINK_PRETARGET2:
786 parser->item_length++;
788 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
790 else if(c == '\r' || c == '\n') {
791 parser->error = CURLE_FTP_BAD_FILE_LIST;
795 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
798 case PL_UNIX_SYMLINK_PRETARGET3:
799 parser->item_length++;
801 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
802 /* now place where is symlink following */
803 finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
804 parser->offsets.filename = parser->item_offset;
805 parser->item_length = 0;
806 parser->item_offset = 0;
808 else if(c == '\r' || c == '\n') {
809 parser->error = CURLE_FTP_BAD_FILE_LIST;
813 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
816 case PL_UNIX_SYMLINK_PRETARGET4:
817 if(c != '\r' && c != '\n') {
818 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
819 parser->item_offset = finfo->b_used - 1;
820 parser->item_length = 1;
823 parser->error = CURLE_FTP_BAD_FILE_LIST;
827 case PL_UNIX_SYMLINK_TARGET:
828 parser->item_length++;
830 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
833 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
834 parser->offsets.symlink_target = parser->item_offset;
835 result = ftp_pl_insert_finfo(conn, infop);
837 parser->error = result;
840 parser->state.UNIX.main = PL_UNIX_FILETYPE;
843 case PL_UNIX_SYMLINK_WINDOWSEOL:
845 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
846 parser->offsets.symlink_target = parser->item_offset;
847 result = ftp_pl_insert_finfo(conn, infop);
849 parser->error = result;
852 parser->state.UNIX.main = PL_UNIX_FILETYPE;
855 parser->error = CURLE_FTP_BAD_FILE_LIST;
864 switch(parser->state.NT.main) {
866 parser->item_length++;
867 if(parser->item_length < 9) {
868 if(!strchr("0123456789-", c)) { /* only simple control */
869 parser->error = CURLE_FTP_BAD_FILE_LIST;
873 else if(parser->item_length == 9) {
875 parser->state.NT.main = PL_WINNT_TIME;
876 parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
879 parser->error = CURLE_FTP_BAD_FILE_LIST;
884 parser->error = CURLE_FTP_BAD_FILE_LIST;
889 parser->item_length++;
890 switch(parser->state.NT.sub.time) {
891 case PL_WINNT_TIME_PRESPACE:
893 parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
896 case PL_WINNT_TIME_TIME:
898 parser->offsets.time = parser->item_offset;
899 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
900 parser->state.NT.main = PL_WINNT_DIRORSIZE;
901 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
902 parser->item_length = 0;
904 else if(!strchr("APM0123456789:", c)) {
905 parser->error = CURLE_FTP_BAD_FILE_LIST;
911 case PL_WINNT_DIRORSIZE:
912 switch(parser->state.NT.sub.dirorsize) {
913 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 parser->offsets.filename = parser->item_offset;
970 result = ftp_pl_insert_finfo(conn, infop);
972 parser->error = result;
975 parser->state.NT.main = PL_WINNT_DATE;
976 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
979 case PL_WINNT_FILENAME_WINEOL:
981 parser->offsets.filename = parser->item_offset;
982 result = ftp_pl_insert_finfo(conn, infop);
984 parser->error = result;
987 parser->state.NT.main = PL_WINNT_DATE;
988 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
991 parser->error = CURLE_FTP_BAD_FILE_LIST;
1000 retsize = bufflen + 1;
1009 /* Clean up any allocated memory. */
1010 if(parser->file_data) {
1011 Curl_fileinfo_dtor(NULL, parser->file_data);
1012 parser->file_data = NULL;
1018 #endif /* CURL_DISABLE_FTP */