1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2010, 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
42 #include "ftplistparser.h"
43 #include "curl_fnmatch.h"
49 #include "strtoofft.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
77 PL_UNIX_HLINKS_PRESPACE = 0,
82 PL_UNIX_USER_PRESPACE = 0,
87 PL_UNIX_GROUP_PRESPACE = 0,
92 PL_UNIX_SIZE_PRESPACE = 0,
97 PL_UNIX_TIME_PREPART1 = 0,
99 PL_UNIX_TIME_PREPART2,
101 PL_UNIX_TIME_PREPART3,
106 PL_UNIX_FILENAME_PRESPACE = 0,
107 PL_UNIX_FILENAME_NAME,
108 PL_UNIX_FILENAME_WINDOWSEOL
112 PL_UNIX_SYMLINK_PRESPACE = 0,
113 PL_UNIX_SYMLINK_NAME,
114 PL_UNIX_SYMLINK_PRETARGET1,
115 PL_UNIX_SYMLINK_PRETARGET2,
116 PL_UNIX_SYMLINK_PRETARGET3,
117 PL_UNIX_SYMLINK_PRETARGET4,
118 PL_UNIX_SYMLINK_TARGET,
119 PL_UNIX_SYMLINK_WINDOWSEOL
128 } pl_winNT_mainstate;
132 PL_WINNT_TIME_PRESPACE = 0,
136 PL_WINNT_DIRORSIZE_PRESPACE = 0,
137 PL_WINNT_DIRORSIZE_CONTENT
140 PL_WINNT_FILENAME_PRESPACE = 0,
141 PL_WINNT_FILENAME_CONTENT,
142 PL_WINNT_FILENAME_WINEOL
146 /* This struct is used in wildcard downloading - for parsing LIST response */
147 struct ftp_parselist_data {
156 pl_unix_mainstate main;
157 pl_unix_substate sub;
161 pl_winNT_mainstate main;
162 pl_winNT_substate sub;
168 size_t bufferlength; /* how many bytes is allocated at *buffer */
169 size_t bufferin; /* how many bytes is in buffer */
173 curl_write_callback old_fwritefunc;
174 FILE *old_file_descriptor;
178 struct curl_fileinfo *file_data;
179 unsigned int item_length;
187 size_t symlink_target;
191 struct ftp_parselist_data *ftp_parselist_data_alloc(void)
193 struct ftp_parselist_data *parselist_data =
194 malloc(sizeof(struct ftp_parselist_data));
197 memset(parselist_data, 0, sizeof(struct ftp_parselist_data));
198 return parselist_data;
202 void ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
210 CURLcode ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
212 return pl_data->error;
216 #define FTP_LP_MALFORMATED_PERM 0x01000000
218 static int ftp_pl_get_permission(const char *str)
223 permissions |= 1 << 8;
224 else if(str[0] != '-')
225 permissions |= FTP_LP_MALFORMATED_PERM;
227 permissions |= 1 << 7;
228 else if(str[1] != '-')
229 permissions |= FTP_LP_MALFORMATED_PERM;
232 permissions |= 1 << 6;
233 else if(str[2] == 's') {
234 permissions |= 1 << 6;
235 permissions |= 1 << 11;
237 else if(str[2] == 'S')
238 permissions |= 1 << 11;
239 else if(str[2] != '-')
240 permissions |= FTP_LP_MALFORMATED_PERM;
243 permissions |= 1 << 5;
244 else if(str[3] != '-')
245 permissions |= FTP_LP_MALFORMATED_PERM;
247 permissions |= 1 << 4;
248 else if(str[4] != '-')
249 permissions |= FTP_LP_MALFORMATED_PERM;
251 permissions |= 1 << 3;
252 else if(str[5] == 's') {
253 permissions |= 1 << 3;
254 permissions |= 1 << 10;
256 else if(str[5] == 'S')
257 permissions |= 1 << 10;
258 else if(str[5] != '-')
259 permissions |= FTP_LP_MALFORMATED_PERM;
262 permissions |= 1 << 2;
263 else if(str[6] != '-')
264 permissions |= FTP_LP_MALFORMATED_PERM;
266 permissions |= 1 << 1;
267 else if(str[7] != '-')
268 permissions |= FTP_LP_MALFORMATED_PERM;
271 else if(str[8] == 't') {
273 permissions |= 1 << 9;
275 else if(str[8] == 'T')
276 permissions |= 1 << 9;
277 else if(str[8] != '-')
278 permissions |= FTP_LP_MALFORMATED_PERM;
283 static void PL_ERROR(struct connectdata *conn, CURLcode err)
285 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
286 struct ftp_parselist_data *parser = tmpdata->parser;
287 if(parser->file_data)
288 Curl_fileinfo_dtor(NULL, parser->file_data);
289 parser->file_data = NULL;
293 static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string)
298 * There could be possible parse timestamp from server. Leaving unimplemented
300 * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to
301 * parser->file_data->flags
303 * Ftp servers are giving usually these formats:
304 * Apr 11 1998 (unknown time.. set it to 00:00:00?)
305 * Apr 11 12:21 (unknown year -> set it to NOW() time?)
306 * 08-05-09 02:49PM (ms-dos format)
307 * 20100421092538 -> for MLST/MLSD response
313 static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
314 struct curl_fileinfo *finfo)
316 curl_fnmatch_callback compare;
317 struct WildcardData *wc = &conn->data->wildcard;
318 struct ftp_wc_tmpdata *tmpdata = wc->tmp;
319 struct curl_llist *llist = wc->filelist;
320 struct ftp_parselist_data *parser = tmpdata->parser;
323 /* move finfo pointers to b_data */
324 char *str = finfo->b_data;
325 finfo->filename = str + parser->offsets.filename;
326 finfo->strings.group = parser->offsets.group ?
327 str + parser->offsets.group : NULL;
328 finfo->strings.perm = parser->offsets.perm ?
329 str + parser->offsets.perm : NULL;
330 finfo->strings.target = parser->offsets.symlink_target ?
331 str + parser->offsets.symlink_target : NULL;
332 finfo->strings.time = str + parser->offsets.time;
333 finfo->strings.user = parser->offsets.user ?
334 str + parser->offsets.user : NULL;
336 /* get correct fnmatch callback */
337 compare = conn->data->set.fnmatch;
339 compare = Curl_fnmatch;
341 /* filter pattern-corresponding filenames */
342 if(compare(conn->data->set.fnmatch_data, wc->pattern, finfo->filename) == 0) {
343 /* discard symlink which is containing multiple " -> " */
344 if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
345 (strstr(finfo->strings.target, " -> "))) {
354 if(!Curl_llist_insert_next(llist, llist->tail, finfo)) {
355 Curl_fileinfo_dtor(NULL, finfo);
356 tmpdata->parser->file_data = NULL;
357 return CURLE_OUT_OF_MEMORY;
361 Curl_fileinfo_dtor(NULL, finfo);
364 tmpdata->parser->file_data = NULL;
368 size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
370 size_t bufflen = size*nmemb;
371 struct connectdata *conn = (struct connectdata *)connptr;
372 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
373 struct ftp_parselist_data *parser = tmpdata->parser;
374 struct curl_fileinfo *finfo;
378 if(parser->error) { /* error in previous call */
381 * 2. call => OUT_OF_MEMORY (or other error)
382 * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
388 if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
389 /* considering info about FILE response format */
390 parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
391 OS_TYPE_WIN_NT : OS_TYPE_UNIX;
394 while(i < bufflen) { /* FSM */
397 if(!parser->file_data) { /* tmp file data is not allocated yet */
398 parser->file_data = Curl_fileinfo_alloc();
399 if(!parser->file_data) {
400 parser->error = CURLE_OUT_OF_MEMORY;
403 parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
404 if(!parser->file_data->b_data) {
405 PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
408 parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
409 parser->item_offset = 0;
410 parser->item_length = 0;
413 finfo = parser->file_data;
414 finfo->b_data[finfo->b_used++] = buffer[i];
416 if(finfo->b_used >= finfo->b_size - 1) {
417 /* if it is important, extend buffer space for file data */
418 char *tmp = realloc(finfo->b_data,
419 finfo->b_size + FTP_BUFFER_ALLOCSIZE);
421 finfo->b_size += FTP_BUFFER_ALLOCSIZE;
425 Curl_fileinfo_dtor(NULL, parser->file_data);
426 parser->file_data = NULL;
427 parser->error = CURLE_OUT_OF_MEMORY;
428 PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
433 switch (parser->os_type) {
435 switch (parser->state.UNIX.main) {
436 case PL_UNIX_FILETYPE:
439 finfo->filetype = CURLFILETYPE_FILE;
442 finfo->filetype = CURLFILETYPE_DIRECTORY;
445 finfo->filetype = CURLFILETYPE_SYMLINK;
448 finfo->filetype = CURLFILETYPE_NAMEDPIPE;
451 finfo->filetype = CURLFILETYPE_SOCKET;
454 finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
457 finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
460 finfo->filetype = CURLFILETYPE_DOOR;
463 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
466 parser->state.UNIX.main = PL_UNIX_PERMISSION;
467 parser->item_length = 0;
468 parser->item_offset = 1;
470 case PL_UNIX_PERMISSION:
471 parser->item_length++;
472 if(parser->item_length <= 9) {
473 if(!strchr("rwx-tTsS", c)) {
474 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
478 else if(parser->item_length == 10) {
481 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
484 finfo->b_data[10] = 0; /* terminate permissions */
485 perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
486 if(perm & FTP_LP_MALFORMATED_PERM) {
487 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
490 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM;
491 parser->file_data->perm = perm;
492 parser->offsets.perm = parser->item_offset;
494 parser->item_length = 0;
495 parser->state.UNIX.main = PL_UNIX_HLINKS;
496 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
500 switch(parser->state.UNIX.sub.hlinks) {
501 case PL_UNIX_HLINKS_PRESPACE:
503 if(c >= '0' && c <= '9') {
504 parser->item_offset = finfo->b_used - 1;
505 parser->item_length = 1;
506 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
509 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
514 case PL_UNIX_HLINKS_NUMBER:
515 parser->item_length ++;
519 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
520 hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
521 if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
522 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
523 parser->file_data->hardlinks = hlinks;
525 parser->item_length = 0;
526 parser->item_offset = 0;
527 parser->state.UNIX.main = PL_UNIX_USER;
528 parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
530 else if(c < '0' || c > '9') {
531 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
538 switch(parser->state.UNIX.sub.user) {
539 case PL_UNIX_USER_PRESPACE:
541 parser->item_offset = finfo->b_used - 1;
542 parser->item_length = 1;
543 parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
546 case PL_UNIX_USER_PARSING:
547 parser->item_length++;
549 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
550 parser->offsets.user = parser->item_offset;
551 parser->state.UNIX.main = PL_UNIX_GROUP;
552 parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
553 parser->item_offset = 0;
554 parser->item_length = 0;
560 switch(parser->state.UNIX.sub.group) {
561 case PL_UNIX_GROUP_PRESPACE:
563 parser->item_offset = finfo->b_used - 1;
564 parser->item_length = 1;
565 parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
568 case PL_UNIX_GROUP_NAME:
569 parser->item_length++;
571 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
572 parser->offsets.group = parser->item_offset;
573 parser->state.UNIX.main = PL_UNIX_SIZE;
574 parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
575 parser->item_offset = 0;
576 parser->item_length = 0;
582 switch(parser->state.UNIX.sub.size) {
583 case PL_UNIX_SIZE_PRESPACE:
585 if(c >= '0' && c <= '9') {
586 parser->item_offset = finfo->b_used - 1;
587 parser->item_length = 1;
588 parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
591 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
596 case PL_UNIX_SIZE_NUMBER:
597 parser->item_length++;
601 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
602 fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
603 if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
604 fsize != CURL_OFF_T_MIN) {
605 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
606 parser->file_data->size = fsize;
608 parser->item_length = 0;
609 parser->item_offset = 0;
610 parser->state.UNIX.main = PL_UNIX_TIME;
611 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
613 else if (!ISDIGIT(c)) {
614 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
621 switch(parser->state.UNIX.sub.time) {
622 case PL_UNIX_TIME_PREPART1:
625 parser->item_offset = finfo->b_used -1;
626 parser->item_length = 1;
627 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
630 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
635 case PL_UNIX_TIME_PART1:
636 parser->item_length++;
638 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
640 else if(!ISALNUM(c) && c != '.') {
641 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
645 case PL_UNIX_TIME_PREPART2:
646 parser->item_length++;
649 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
652 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
657 case PL_UNIX_TIME_PART2:
658 parser->item_length++;
660 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
662 else if(!ISALNUM(c) && c != '.') {
663 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
667 case PL_UNIX_TIME_PREPART3:
668 parser->item_length++;
671 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
674 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
679 case PL_UNIX_TIME_PART3:
680 parser->item_length++;
682 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
683 parser->offsets.time = parser->item_offset;
684 if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
685 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
687 if(finfo->filetype == CURLFILETYPE_SYMLINK) {
688 parser->state.UNIX.main = PL_UNIX_SYMLINK;
689 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
692 parser->state.UNIX.main = PL_UNIX_FILENAME;
693 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
696 else if(!ISALNUM(c) && c != '.' && c != ':') {
697 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
703 case PL_UNIX_FILENAME:
704 switch(parser->state.UNIX.sub.filename) {
705 case PL_UNIX_FILENAME_PRESPACE:
707 parser->item_offset = finfo->b_used - 1;
708 parser->item_length = 1;
709 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
712 case PL_UNIX_FILENAME_NAME:
713 parser->item_length++;
715 parser->item_length--;
716 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
719 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
720 parser->offsets.filename = parser->item_offset;
721 parser->state.UNIX.main = PL_UNIX_FILETYPE;
722 rc = ftp_pl_insert_finfo(conn, finfo);
729 case PL_UNIX_FILENAME_WINDOWSEOL:
731 finfo->b_data[parser->item_offset + parser->item_length] = 0;
732 parser->offsets.filename = parser->item_offset;
733 parser->state.UNIX.main = PL_UNIX_FILETYPE;
734 rc = ftp_pl_insert_finfo(conn, finfo);
741 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
747 case PL_UNIX_SYMLINK:
748 switch(parser->state.UNIX.sub.symlink) {
749 case PL_UNIX_SYMLINK_PRESPACE:
751 parser->item_offset = finfo->b_used - 1;
752 parser->item_length = 1;
753 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
756 case PL_UNIX_SYMLINK_NAME:
757 parser->item_length++;
759 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
761 else if(c == '\r' || c == '\n') {
762 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
766 case PL_UNIX_SYMLINK_PRETARGET1:
767 parser->item_length++;
769 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
771 else if(c == '\r' || c == '\n') {
772 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
776 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
779 case PL_UNIX_SYMLINK_PRETARGET2:
780 parser->item_length++;
782 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
784 else if(c == '\r' || c == '\n') {
785 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
789 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
792 case PL_UNIX_SYMLINK_PRETARGET3:
793 parser->item_length++;
795 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
796 /* now place where is symlink following */
797 finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
798 parser->offsets.filename = parser->item_offset;
799 parser->item_length = 0;
800 parser->item_offset = 0;
802 else if(c == '\r' || c == '\n') {
803 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
807 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
810 case PL_UNIX_SYMLINK_PRETARGET4:
811 if(c != '\r' && c != '\n') {
812 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
813 parser->item_offset = finfo->b_used - 1;
814 parser->item_length = 1;
817 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
821 case PL_UNIX_SYMLINK_TARGET:
822 parser->item_length ++;
824 parser->item_length --;
825 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
828 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
829 parser->offsets.symlink_target = parser->item_offset;
830 rc = ftp_pl_insert_finfo(conn, finfo);
835 parser->state.UNIX.main = PL_UNIX_FILETYPE;
838 case PL_UNIX_SYMLINK_WINDOWSEOL:
840 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
841 parser->offsets.symlink_target = parser->item_offset;
842 rc = ftp_pl_insert_finfo(conn, finfo);
847 parser->state.UNIX.main = PL_UNIX_FILETYPE;
850 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
859 switch(parser->state.NT.main) {
861 parser->item_length++;
862 if(parser->item_length < 9) {
863 if(!strchr("0123456789-", c)) { /* only simple control */
864 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
868 else if(parser->item_length == 9) {
870 parser->state.NT.main = PL_WINNT_TIME;
871 parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
874 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
879 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
884 parser->item_length++;
885 switch(parser->state.NT.sub.time) {
886 case PL_WINNT_TIME_PRESPACE:
888 parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
891 case PL_WINNT_TIME_TIME:
893 parser->offsets.time = parser->item_offset;
894 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
895 parser->state.NT.main = PL_WINNT_DIRORSIZE;
896 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
897 parser->item_length = 0;
899 else if(!strchr("APM0123456789:", c)) {
900 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
906 case PL_WINNT_DIRORSIZE:
907 switch(parser->state.NT.sub.dirorsize) {
908 case PL_WINNT_DIRORSIZE_PRESPACE:
913 parser->item_offset = finfo->b_used - 1;
914 parser->item_length = 1;
915 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
918 case PL_WINNT_DIRORSIZE_CONTENT:
919 parser->item_length ++;
921 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
922 if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
923 finfo->filetype = CURLFILETYPE_DIRECTORY;
928 finfo->size = curlx_strtoofft(finfo->b_data + parser->item_offset,
931 if(finfo->size == CURL_OFF_T_MAX ||
932 finfo->size == CURL_OFF_T_MIN) {
933 if(errno == ERANGE) {
934 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
940 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
943 /* correct file type */
944 parser->file_data->filetype = CURLFILETYPE_FILE;
947 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
948 parser->item_length = 0;
949 parser->state.NT.main = PL_WINNT_FILENAME;
950 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
955 case PL_WINNT_FILENAME:
956 switch (parser->state.NT.sub.filename) {
957 case PL_WINNT_FILENAME_PRESPACE:
959 parser->item_offset = finfo->b_used -1;
960 parser->item_length = 1;
961 parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
964 case PL_WINNT_FILENAME_CONTENT:
965 parser->item_length++;
967 parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
968 finfo->b_data[finfo->b_used - 1] = 0;
971 parser->offsets.filename = parser->item_offset;
972 finfo->b_data[finfo->b_used - 1] = 0;
973 parser->offsets.filename = parser->item_offset;
974 rc = ftp_pl_insert_finfo(conn, finfo);
979 parser->state.NT.main = PL_WINNT_DATE;
980 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
983 case PL_WINNT_FILENAME_WINEOL:
985 parser->offsets.filename = parser->item_offset;
986 rc = ftp_pl_insert_finfo(conn, finfo);
991 parser->state.NT.main = PL_WINNT_DATE;
992 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
995 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);