1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2014, 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 http://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"
50 #include "ftplistparser.h"
51 #include "curl_fnmatch.h"
53 #define _MPRINTF_REPLACE /* use our functions only */
54 #include <curl/mprintf.h>
56 #include "curl_memory.h"
57 /* The last #include file should be: */
60 /* allocs buffer which will contain one line of LIST command response */
61 #define FTP_BUFFER_ALLOCSIZE 160
64 PL_UNIX_TOTALSIZE = 0,
78 PL_UNIX_TOTALSIZE_INIT = 0,
79 PL_UNIX_TOTALSIZE_READING
83 PL_UNIX_HLINKS_PRESPACE = 0,
88 PL_UNIX_USER_PRESPACE = 0,
93 PL_UNIX_GROUP_PRESPACE = 0,
98 PL_UNIX_SIZE_PRESPACE = 0,
103 PL_UNIX_TIME_PREPART1 = 0,
105 PL_UNIX_TIME_PREPART2,
107 PL_UNIX_TIME_PREPART3,
112 PL_UNIX_FILENAME_PRESPACE = 0,
113 PL_UNIX_FILENAME_NAME,
114 PL_UNIX_FILENAME_WINDOWSEOL
118 PL_UNIX_SYMLINK_PRESPACE = 0,
119 PL_UNIX_SYMLINK_NAME,
120 PL_UNIX_SYMLINK_PRETARGET1,
121 PL_UNIX_SYMLINK_PRETARGET2,
122 PL_UNIX_SYMLINK_PRETARGET3,
123 PL_UNIX_SYMLINK_PRETARGET4,
124 PL_UNIX_SYMLINK_TARGET,
125 PL_UNIX_SYMLINK_WINDOWSEOL
134 } pl_winNT_mainstate;
138 PL_WINNT_TIME_PRESPACE = 0,
142 PL_WINNT_DIRORSIZE_PRESPACE = 0,
143 PL_WINNT_DIRORSIZE_CONTENT
146 PL_WINNT_FILENAME_PRESPACE = 0,
147 PL_WINNT_FILENAME_CONTENT,
148 PL_WINNT_FILENAME_WINEOL
152 /* This struct is used in wildcard downloading - for parsing LIST response */
153 struct ftp_parselist_data {
162 pl_unix_mainstate main;
163 pl_unix_substate sub;
167 pl_winNT_mainstate main;
168 pl_winNT_substate sub;
173 struct curl_fileinfo *file_data;
174 unsigned int item_length;
182 size_t symlink_target;
186 struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
188 return calloc(1, sizeof(struct ftp_parselist_data));
192 void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
200 CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
202 return pl_data->error;
206 #define FTP_LP_MALFORMATED_PERM 0x01000000
208 static int ftp_pl_get_permission(const char *str)
213 permissions |= 1 << 8;
214 else if(str[0] != '-')
215 permissions |= FTP_LP_MALFORMATED_PERM;
217 permissions |= 1 << 7;
218 else if(str[1] != '-')
219 permissions |= FTP_LP_MALFORMATED_PERM;
222 permissions |= 1 << 6;
223 else if(str[2] == 's') {
224 permissions |= 1 << 6;
225 permissions |= 1 << 11;
227 else if(str[2] == 'S')
228 permissions |= 1 << 11;
229 else if(str[2] != '-')
230 permissions |= FTP_LP_MALFORMATED_PERM;
233 permissions |= 1 << 5;
234 else if(str[3] != '-')
235 permissions |= FTP_LP_MALFORMATED_PERM;
237 permissions |= 1 << 4;
238 else if(str[4] != '-')
239 permissions |= FTP_LP_MALFORMATED_PERM;
241 permissions |= 1 << 3;
242 else if(str[5] == 's') {
243 permissions |= 1 << 3;
244 permissions |= 1 << 10;
246 else if(str[5] == 'S')
247 permissions |= 1 << 10;
248 else if(str[5] != '-')
249 permissions |= FTP_LP_MALFORMATED_PERM;
252 permissions |= 1 << 2;
253 else if(str[6] != '-')
254 permissions |= FTP_LP_MALFORMATED_PERM;
256 permissions |= 1 << 1;
257 else if(str[7] != '-')
258 permissions |= FTP_LP_MALFORMATED_PERM;
261 else if(str[8] == 't') {
263 permissions |= 1 << 9;
265 else if(str[8] == 'T')
266 permissions |= 1 << 9;
267 else if(str[8] != '-')
268 permissions |= FTP_LP_MALFORMATED_PERM;
273 static void PL_ERROR(struct connectdata *conn, CURLcode err)
275 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
276 struct ftp_parselist_data *parser = tmpdata->parser;
277 if(parser->file_data)
278 Curl_fileinfo_dtor(NULL, parser->file_data);
279 parser->file_data = NULL;
283 static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string)
288 * There could be possible parse timestamp from server. Leaving unimplemented
290 * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to
291 * parser->file_data->flags
293 * Ftp servers are giving usually these formats:
294 * Apr 11 1998 (unknown time.. set it to 00:00:00?)
295 * Apr 11 12:21 (unknown year -> set it to NOW() time?)
296 * 08-05-09 02:49PM (ms-dos format)
297 * 20100421092538 -> for MLST/MLSD response
303 static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
304 struct curl_fileinfo *finfo)
306 curl_fnmatch_callback compare;
307 struct WildcardData *wc = &conn->data->wildcard;
308 struct ftp_wc_tmpdata *tmpdata = wc->tmp;
309 struct curl_llist *llist = wc->filelist;
310 struct ftp_parselist_data *parser = tmpdata->parser;
313 /* move finfo pointers to b_data */
314 char *str = finfo->b_data;
315 finfo->filename = str + parser->offsets.filename;
316 finfo->strings.group = parser->offsets.group ?
317 str + parser->offsets.group : NULL;
318 finfo->strings.perm = parser->offsets.perm ?
319 str + parser->offsets.perm : NULL;
320 finfo->strings.target = parser->offsets.symlink_target ?
321 str + parser->offsets.symlink_target : NULL;
322 finfo->strings.time = str + parser->offsets.time;
323 finfo->strings.user = parser->offsets.user ?
324 str + parser->offsets.user : NULL;
326 /* get correct fnmatch callback */
327 compare = conn->data->set.fnmatch;
329 compare = Curl_fnmatch;
331 /* filter pattern-corresponding filenames */
332 if(compare(conn->data->set.fnmatch_data, wc->pattern,
333 finfo->filename) == 0) {
334 /* discard symlink which is containing multiple " -> " */
335 if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
336 (strstr(finfo->strings.target, " -> "))) {
345 if(!Curl_llist_insert_next(llist, llist->tail, finfo)) {
346 Curl_fileinfo_dtor(NULL, finfo);
347 tmpdata->parser->file_data = NULL;
348 return CURLE_OUT_OF_MEMORY;
352 Curl_fileinfo_dtor(NULL, finfo);
355 tmpdata->parser->file_data = NULL;
359 size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
362 size_t bufflen = size*nmemb;
363 struct connectdata *conn = (struct connectdata *)connptr;
364 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
365 struct ftp_parselist_data *parser = tmpdata->parser;
366 struct curl_fileinfo *finfo;
370 if(parser->error) { /* error in previous call */
373 * 2. call => OUT_OF_MEMORY (or other error)
374 * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
380 if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
381 /* considering info about FILE response format */
382 parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
383 OS_TYPE_WIN_NT : OS_TYPE_UNIX;
386 while(i < bufflen) { /* FSM */
389 if(!parser->file_data) { /* tmp file data is not allocated yet */
390 parser->file_data = Curl_fileinfo_alloc();
391 if(!parser->file_data) {
392 parser->error = CURLE_OUT_OF_MEMORY;
395 parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
396 if(!parser->file_data->b_data) {
397 PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
400 parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
401 parser->item_offset = 0;
402 parser->item_length = 0;
405 finfo = parser->file_data;
406 finfo->b_data[finfo->b_used++] = c;
408 if(finfo->b_used >= finfo->b_size - 1) {
409 /* if it is important, extend buffer space for file data */
410 char *tmp = realloc(finfo->b_data,
411 finfo->b_size + FTP_BUFFER_ALLOCSIZE);
413 finfo->b_size += FTP_BUFFER_ALLOCSIZE;
417 Curl_fileinfo_dtor(NULL, parser->file_data);
418 parser->file_data = NULL;
419 parser->error = CURLE_OUT_OF_MEMORY;
420 PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
425 switch (parser->os_type) {
427 switch (parser->state.UNIX.main) {
428 case PL_UNIX_TOTALSIZE:
429 switch(parser->state.UNIX.sub.total_dirsize) {
430 case PL_UNIX_TOTALSIZE_INIT:
432 parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
433 parser->item_length++;
436 parser->state.UNIX.main = PL_UNIX_FILETYPE;
437 /* start FSM again not considering size of directory */
442 case PL_UNIX_TOTALSIZE_READING:
443 parser->item_length++;
445 parser->item_length--;
449 finfo->b_data[parser->item_length - 1] = 0;
450 if(strncmp("total ", finfo->b_data, 6) == 0) {
451 char *endptr = finfo->b_data+6;
452 /* here we can deal with directory size, pass the leading white
453 spaces and then the digits */
454 while(ISSPACE(*endptr))
456 while(ISDIGIT(*endptr))
459 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
463 parser->state.UNIX.main = PL_UNIX_FILETYPE;
468 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
475 case PL_UNIX_FILETYPE:
478 finfo->filetype = CURLFILETYPE_FILE;
481 finfo->filetype = CURLFILETYPE_DIRECTORY;
484 finfo->filetype = CURLFILETYPE_SYMLINK;
487 finfo->filetype = CURLFILETYPE_NAMEDPIPE;
490 finfo->filetype = CURLFILETYPE_SOCKET;
493 finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
496 finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
499 finfo->filetype = CURLFILETYPE_DOOR;
502 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
505 parser->state.UNIX.main = PL_UNIX_PERMISSION;
506 parser->item_length = 0;
507 parser->item_offset = 1;
509 case PL_UNIX_PERMISSION:
510 parser->item_length++;
511 if(parser->item_length <= 9) {
512 if(!strchr("rwx-tTsS", c)) {
513 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
517 else if(parser->item_length == 10) {
520 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
523 finfo->b_data[10] = 0; /* terminate permissions */
524 perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
525 if(perm & FTP_LP_MALFORMATED_PERM) {
526 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
529 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM;
530 parser->file_data->perm = perm;
531 parser->offsets.perm = parser->item_offset;
533 parser->item_length = 0;
534 parser->state.UNIX.main = PL_UNIX_HLINKS;
535 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
539 switch(parser->state.UNIX.sub.hlinks) {
540 case PL_UNIX_HLINKS_PRESPACE:
542 if(c >= '0' && c <= '9') {
543 parser->item_offset = finfo->b_used - 1;
544 parser->item_length = 1;
545 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
548 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
553 case PL_UNIX_HLINKS_NUMBER:
554 parser->item_length ++;
558 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
559 hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
560 if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
561 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
562 parser->file_data->hardlinks = hlinks;
564 parser->item_length = 0;
565 parser->item_offset = 0;
566 parser->state.UNIX.main = PL_UNIX_USER;
567 parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
569 else if(c < '0' || c > '9') {
570 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
577 switch(parser->state.UNIX.sub.user) {
578 case PL_UNIX_USER_PRESPACE:
580 parser->item_offset = finfo->b_used - 1;
581 parser->item_length = 1;
582 parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
585 case PL_UNIX_USER_PARSING:
586 parser->item_length++;
588 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
589 parser->offsets.user = parser->item_offset;
590 parser->state.UNIX.main = PL_UNIX_GROUP;
591 parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
592 parser->item_offset = 0;
593 parser->item_length = 0;
599 switch(parser->state.UNIX.sub.group) {
600 case PL_UNIX_GROUP_PRESPACE:
602 parser->item_offset = finfo->b_used - 1;
603 parser->item_length = 1;
604 parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
607 case PL_UNIX_GROUP_NAME:
608 parser->item_length++;
610 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
611 parser->offsets.group = parser->item_offset;
612 parser->state.UNIX.main = PL_UNIX_SIZE;
613 parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
614 parser->item_offset = 0;
615 parser->item_length = 0;
621 switch(parser->state.UNIX.sub.size) {
622 case PL_UNIX_SIZE_PRESPACE:
624 if(c >= '0' && c <= '9') {
625 parser->item_offset = finfo->b_used - 1;
626 parser->item_length = 1;
627 parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
630 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
635 case PL_UNIX_SIZE_NUMBER:
636 parser->item_length++;
640 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
641 fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
642 if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
643 fsize != CURL_OFF_T_MIN) {
644 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
645 parser->file_data->size = fsize;
647 parser->item_length = 0;
648 parser->item_offset = 0;
649 parser->state.UNIX.main = PL_UNIX_TIME;
650 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
652 else if(!ISDIGIT(c)) {
653 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
660 switch(parser->state.UNIX.sub.time) {
661 case PL_UNIX_TIME_PREPART1:
664 parser->item_offset = finfo->b_used -1;
665 parser->item_length = 1;
666 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
669 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
674 case PL_UNIX_TIME_PART1:
675 parser->item_length++;
677 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
679 else if(!ISALNUM(c) && c != '.') {
680 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
684 case PL_UNIX_TIME_PREPART2:
685 parser->item_length++;
688 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
691 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
696 case PL_UNIX_TIME_PART2:
697 parser->item_length++;
699 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
701 else if(!ISALNUM(c) && c != '.') {
702 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
706 case PL_UNIX_TIME_PREPART3:
707 parser->item_length++;
710 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
713 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
718 case PL_UNIX_TIME_PART3:
719 parser->item_length++;
721 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
722 parser->offsets.time = parser->item_offset;
723 if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
724 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
726 if(finfo->filetype == CURLFILETYPE_SYMLINK) {
727 parser->state.UNIX.main = PL_UNIX_SYMLINK;
728 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
731 parser->state.UNIX.main = PL_UNIX_FILENAME;
732 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
735 else if(!ISALNUM(c) && c != '.' && c != ':') {
736 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
742 case PL_UNIX_FILENAME:
743 switch(parser->state.UNIX.sub.filename) {
744 case PL_UNIX_FILENAME_PRESPACE:
746 parser->item_offset = finfo->b_used - 1;
747 parser->item_length = 1;
748 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
751 case PL_UNIX_FILENAME_NAME:
752 parser->item_length++;
754 parser->item_length--;
755 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
758 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
759 parser->offsets.filename = parser->item_offset;
760 parser->state.UNIX.main = PL_UNIX_FILETYPE;
761 rc = ftp_pl_insert_finfo(conn, finfo);
768 case PL_UNIX_FILENAME_WINDOWSEOL:
770 finfo->b_data[parser->item_offset + parser->item_length] = 0;
771 parser->offsets.filename = parser->item_offset;
772 parser->state.UNIX.main = PL_UNIX_FILETYPE;
773 rc = ftp_pl_insert_finfo(conn, finfo);
780 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
786 case PL_UNIX_SYMLINK:
787 switch(parser->state.UNIX.sub.symlink) {
788 case PL_UNIX_SYMLINK_PRESPACE:
790 parser->item_offset = finfo->b_used - 1;
791 parser->item_length = 1;
792 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
795 case PL_UNIX_SYMLINK_NAME:
796 parser->item_length++;
798 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
800 else if(c == '\r' || c == '\n') {
801 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
805 case PL_UNIX_SYMLINK_PRETARGET1:
806 parser->item_length++;
808 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
810 else if(c == '\r' || c == '\n') {
811 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
815 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
818 case PL_UNIX_SYMLINK_PRETARGET2:
819 parser->item_length++;
821 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
823 else if(c == '\r' || c == '\n') {
824 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
828 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
831 case PL_UNIX_SYMLINK_PRETARGET3:
832 parser->item_length++;
834 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
835 /* now place where is symlink following */
836 finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
837 parser->offsets.filename = parser->item_offset;
838 parser->item_length = 0;
839 parser->item_offset = 0;
841 else if(c == '\r' || c == '\n') {
842 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
846 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
849 case PL_UNIX_SYMLINK_PRETARGET4:
850 if(c != '\r' && c != '\n') {
851 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
852 parser->item_offset = finfo->b_used - 1;
853 parser->item_length = 1;
856 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
860 case PL_UNIX_SYMLINK_TARGET:
861 parser->item_length ++;
863 parser->item_length --;
864 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
867 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
868 parser->offsets.symlink_target = parser->item_offset;
869 rc = ftp_pl_insert_finfo(conn, finfo);
874 parser->state.UNIX.main = PL_UNIX_FILETYPE;
877 case PL_UNIX_SYMLINK_WINDOWSEOL:
879 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
880 parser->offsets.symlink_target = parser->item_offset;
881 rc = ftp_pl_insert_finfo(conn, finfo);
886 parser->state.UNIX.main = PL_UNIX_FILETYPE;
889 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
898 switch(parser->state.NT.main) {
900 parser->item_length++;
901 if(parser->item_length < 9) {
902 if(!strchr("0123456789-", c)) { /* only simple control */
903 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
907 else if(parser->item_length == 9) {
909 parser->state.NT.main = PL_WINNT_TIME;
910 parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
913 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
918 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
923 parser->item_length++;
924 switch(parser->state.NT.sub.time) {
925 case PL_WINNT_TIME_PRESPACE:
927 parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
930 case PL_WINNT_TIME_TIME:
932 parser->offsets.time = parser->item_offset;
933 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
934 parser->state.NT.main = PL_WINNT_DIRORSIZE;
935 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
936 parser->item_length = 0;
938 else if(!strchr("APM0123456789:", c)) {
939 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
945 case PL_WINNT_DIRORSIZE:
946 switch(parser->state.NT.sub.dirorsize) {
947 case PL_WINNT_DIRORSIZE_PRESPACE:
952 parser->item_offset = finfo->b_used - 1;
953 parser->item_length = 1;
954 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
957 case PL_WINNT_DIRORSIZE_CONTENT:
958 parser->item_length ++;
960 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
961 if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
962 finfo->filetype = CURLFILETYPE_DIRECTORY;
967 finfo->size = curlx_strtoofft(finfo->b_data +
971 if(finfo->size == CURL_OFF_T_MAX ||
972 finfo->size == CURL_OFF_T_MIN) {
973 if(errno == ERANGE) {
974 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
980 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
983 /* correct file type */
984 parser->file_data->filetype = CURLFILETYPE_FILE;
987 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
988 parser->item_length = 0;
989 parser->state.NT.main = PL_WINNT_FILENAME;
990 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
995 case PL_WINNT_FILENAME:
996 switch (parser->state.NT.sub.filename) {
997 case PL_WINNT_FILENAME_PRESPACE:
999 parser->item_offset = finfo->b_used -1;
1000 parser->item_length = 1;
1001 parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
1004 case PL_WINNT_FILENAME_CONTENT:
1005 parser->item_length++;
1007 parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
1008 finfo->b_data[finfo->b_used - 1] = 0;
1010 else if(c == '\n') {
1011 parser->offsets.filename = parser->item_offset;
1012 finfo->b_data[finfo->b_used - 1] = 0;
1013 parser->offsets.filename = parser->item_offset;
1014 rc = ftp_pl_insert_finfo(conn, finfo);
1019 parser->state.NT.main = PL_WINNT_DATE;
1020 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
1023 case PL_WINNT_FILENAME_WINEOL:
1025 parser->offsets.filename = parser->item_offset;
1026 rc = ftp_pl_insert_finfo(conn, finfo);
1031 parser->state.NT.main = PL_WINNT_DATE;
1032 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
1035 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
1053 #endif /* CURL_DISABLE_FTP */