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
40 #include "ftplistparser.h"
41 #include "curl_fnmatch.h"
47 #include "strtoofft.h"
51 /* allocs buffer which will contain one line of LIST command response */
52 #define FTP_BUFFER_ALLOCSIZE 160
68 PL_UNIX_HLINKS_PRESPACE = 0,
73 PL_UNIX_USER_PRESPACE = 0,
78 PL_UNIX_GROUP_PRESPACE = 0,
83 PL_UNIX_SIZE_PRESPACE = 0,
88 PL_UNIX_TIME_PREPART1 = 0,
90 PL_UNIX_TIME_PREPART2,
92 PL_UNIX_TIME_PREPART3,
97 PL_UNIX_FILENAME_PRESPACE = 0,
98 PL_UNIX_FILENAME_NAME,
99 PL_UNIX_FILENAME_WINDOWSEOL
103 PL_UNIX_SYMLINK_PRESPACE = 0,
104 PL_UNIX_SYMLINK_NAME,
105 PL_UNIX_SYMLINK_PRETARGET1,
106 PL_UNIX_SYMLINK_PRETARGET2,
107 PL_UNIX_SYMLINK_PRETARGET3,
108 PL_UNIX_SYMLINK_PRETARGET4,
109 PL_UNIX_SYMLINK_TARGET,
110 PL_UNIX_SYMLINK_WINDOWSEOL
119 } pl_winNT_mainstate;
123 PL_WINNT_TIME_PRESPACE = 0,
127 PL_WINNT_DIRORSIZE_PRESPACE = 0,
128 PL_WINNT_DIRORSIZE_CONTENT
131 PL_WINNT_FILENAME_PRESPACE = 0,
132 PL_WINNT_FILENAME_CONTENT,
133 PL_WINNT_FILENAME_WINEOL
137 /* This struct is used in wildcard downloading - for parsing LIST response */
138 struct ftp_parselist_data {
147 pl_unix_mainstate main;
148 pl_unix_substate sub;
152 pl_winNT_mainstate main;
153 pl_winNT_substate sub;
159 size_t bufferlength; /* how many bytes is allocated at *buffer */
160 size_t bufferin; /* how many bytes is in buffer */
164 curl_write_callback old_fwritefunc;
165 FILE *old_file_descriptor;
169 struct curl_fileinfo *file_data;
170 unsigned int item_length;
178 size_t symlink_target;
182 struct ftp_parselist_data *ftp_parselist_data_alloc(void)
184 struct ftp_parselist_data *parselist_data =
185 malloc(sizeof(struct ftp_parselist_data));
188 memset(parselist_data, 0, sizeof(struct ftp_parselist_data));
189 return parselist_data;
193 void ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
201 CURLcode ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
203 return pl_data->error;
207 #define FTP_LP_MALFORMATED_PERM 0x01000000
209 static int ftp_pl_get_permission(const char *str)
214 permissions |= 1 << 8;
215 else if(str[0] != '-')
216 permissions |= FTP_LP_MALFORMATED_PERM;
218 permissions |= 1 << 7;
219 else if(str[1] != '-')
220 permissions |= FTP_LP_MALFORMATED_PERM;
223 permissions |= 1 << 6;
224 else if(str[2] == 's') {
225 permissions |= 1 << 6;
226 permissions |= 1 << 11;
228 else if(str[2] == 'S')
229 permissions |= 1 << 11;
230 else if(str[2] != '-')
231 permissions |= FTP_LP_MALFORMATED_PERM;
234 permissions |= 1 << 5;
235 else if(str[3] != '-')
236 permissions |= FTP_LP_MALFORMATED_PERM;
238 permissions |= 1 << 4;
239 else if(str[4] != '-')
240 permissions |= FTP_LP_MALFORMATED_PERM;
242 permissions |= 1 << 3;
243 else if(str[5] == 's') {
244 permissions |= 1 << 3;
245 permissions |= 1 << 10;
247 else if(str[5] == 'S')
248 permissions |= 1 << 10;
249 else if(str[5] != '-')
250 permissions |= FTP_LP_MALFORMATED_PERM;
253 permissions |= 1 << 2;
254 else if(str[6] != '-')
255 permissions |= FTP_LP_MALFORMATED_PERM;
257 permissions |= 1 << 1;
258 else if(str[7] != '-')
259 permissions |= FTP_LP_MALFORMATED_PERM;
262 else if(str[8] == 't') {
264 permissions |= 1 << 9;
266 else if(str[8] == 'T')
267 permissions |= 1 << 9;
268 else if(str[8] != '-')
269 permissions |= FTP_LP_MALFORMATED_PERM;
274 static void PL_ERROR(struct connectdata *conn, CURLcode err)
276 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
277 struct ftp_parselist_data *parser = tmpdata->parser;
278 if(parser->file_data)
279 Curl_fileinfo_dtor(NULL, parser->file_data);
280 parser->file_data = NULL;
284 static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string)
289 * There could be possible parse timestamp from server. Leaving unimplemented
291 * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to
292 * parser->file_data->flags
294 * Ftp servers are giving usually these formats:
295 * Apr 11 1998 (unknown time.. set it to 00:00:00?)
296 * Apr 11 12:21 (unknown year -> set it to NOW() time?)
297 * 08-05-09 02:49PM (ms-dos format)
298 * 20100421092538 -> for MLST/MLSD response
304 static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
305 struct curl_fileinfo *finfo)
307 curl_fnmatch_callback compare;
308 struct WildcardData *wc = &conn->data->wildcard;
309 struct ftp_wc_tmpdata *tmpdata = wc->tmp;
310 struct curl_llist *llist = wc->filelist;
311 struct ftp_parselist_data *parser = tmpdata->parser;
314 /* move finfo pointers to b_data */
315 char *str = finfo->b_data;
316 finfo->filename = str + parser->offsets.filename;
317 finfo->strings.group = parser->offsets.group ?
318 str + parser->offsets.group : NULL;
319 finfo->strings.perm = parser->offsets.perm ?
320 str + parser->offsets.perm : NULL;
321 finfo->strings.target = parser->offsets.symlink_target ?
322 str + parser->offsets.symlink_target : NULL;
323 finfo->strings.time = str + parser->offsets.time;
324 finfo->strings.user = parser->offsets.user ?
325 str + parser->offsets.user : NULL;
327 /* get correct fnmatch callback */
328 compare = conn->data->set.fnmatch;
330 compare = Curl_fnmatch;
332 /* filter pattern-corresponding filenames */
333 if(compare(wc->pattern, finfo->filename) == 0) {
334 /* discard symlink which is containing multiple " -> " */
335 if((finfo->filetype == CURLFILETYPE_SYMLINK) &&
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 ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
361 size_t bufflen = size*nmemb;
362 struct connectdata *conn = (struct connectdata *)connptr;
363 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
364 struct ftp_parselist_data *parser = tmpdata->parser;
365 struct curl_fileinfo *finfo;
369 if(parser->error) { /* error in previous call */
372 * 2. call => OUT_OF_MEMORY (or other error)
373 * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
379 if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
380 /* considering info about FILE response format */
381 parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
382 OS_TYPE_WIN_NT : OS_TYPE_UNIX;
385 while(i < bufflen) { /* FSM */
388 if(!parser->file_data) { /* tmp file data is not allocated yet */
389 parser->file_data = Curl_fileinfo_alloc();
390 if(!parser->file_data) {
391 parser->error = CURLE_OUT_OF_MEMORY;
394 parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
395 if(!parser->file_data->b_data) {
396 PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
399 parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
400 parser->item_offset = 0;
401 parser->item_length = 0;
404 finfo = parser->file_data;
405 finfo->b_data[finfo->b_used++] = buffer[i];
407 if(finfo->b_used >= finfo->b_size - 1) {
408 /* if it is important, extend buffer space for file data */
409 char *tmp = realloc(finfo->b_data,
410 finfo->b_size + FTP_BUFFER_ALLOCSIZE);
412 finfo->b_size += FTP_BUFFER_ALLOCSIZE;
416 Curl_fileinfo_dtor(NULL, parser->file_data);
417 parser->file_data = NULL;
421 switch (parser->os_type) {
423 switch (parser->state.UNIX.main) {
424 case PL_UNIX_FILETYPE:
427 finfo->filetype = CURLFILETYPE_FILE;
430 finfo->filetype = CURLFILETYPE_DIRECTORY;
433 finfo->filetype = CURLFILETYPE_SYMLINK;
436 finfo->filetype = CURLFILETYPE_NAMEDPIPE;
439 finfo->filetype = CURLFILETYPE_SOCKET;
442 finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
445 finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
448 finfo->filetype = CURLFILETYPE_DOOR;
451 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
455 parser->state.UNIX.main = PL_UNIX_PERMISSION;
456 parser->item_length = 0;
457 parser->item_offset = 1;
459 case PL_UNIX_PERMISSION:
460 parser->item_length++;
461 if(parser->item_length <= 9) {
462 if(!strchr("rwx-tTsS", c)) {
463 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
467 else if(parser->item_length == 10) {
470 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
473 finfo->b_data[10] = 0; /* terminate permissions */
474 perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
475 if(perm & FTP_LP_MALFORMATED_PERM) {
476 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
479 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM;
480 parser->file_data->perm = perm;
481 parser->offsets.perm = parser->item_offset;
483 parser->item_length = 0;
484 parser->state.UNIX.main = PL_UNIX_HLINKS;
485 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
489 switch(parser->state.UNIX.sub.hlinks) {
490 case PL_UNIX_HLINKS_PRESPACE:
492 if(c >= '0' && c <= '9') {
493 parser->item_offset = finfo->b_used - 1;
494 parser->item_length = 1;
495 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
498 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
503 case PL_UNIX_HLINKS_NUMBER:
504 parser->item_length ++;
508 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
509 hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
510 if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
511 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
512 parser->file_data->hardlinks = hlinks;
514 parser->item_length = 0;
515 parser->item_offset = 0;
516 parser->state.UNIX.main = PL_UNIX_USER;
517 parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
519 else if(c < '0' || c > '9') {
520 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
527 switch(parser->state.UNIX.sub.user) {
528 case PL_UNIX_USER_PRESPACE:
530 parser->item_offset = finfo->b_used - 1;
531 parser->item_length = 1;
532 parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
535 case PL_UNIX_USER_PARSING:
536 parser->item_length++;
538 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
539 parser->offsets.user = parser->item_offset;
540 parser->state.UNIX.main = PL_UNIX_GROUP;
541 parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
542 parser->item_offset = 0;
543 parser->item_length = 0;
549 switch(parser->state.UNIX.sub.group) {
550 case PL_UNIX_GROUP_PRESPACE:
552 parser->item_offset = finfo->b_used - 1;
553 parser->item_length = 1;
554 parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
557 case PL_UNIX_GROUP_NAME:
558 parser->item_length++;
560 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
561 parser->offsets.group = parser->item_offset;
562 parser->state.UNIX.main = PL_UNIX_SIZE;
563 parser->state.UNIX.sub.group = PL_UNIX_SIZE_PRESPACE;
564 parser->item_offset = 0;
565 parser->item_length = 0;
571 switch(parser->state.UNIX.sub.size) {
572 case PL_UNIX_SIZE_PRESPACE:
574 if(c >= '0' && c <= '9') {
575 parser->item_offset = finfo->b_used - 1;
576 parser->item_length = 1;
577 parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
580 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
585 case PL_UNIX_SIZE_NUMBER:
586 parser->item_length++;
590 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
591 fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
592 if(p[0] == '\0' && fsize != CURL_LLONG_MAX &&
593 fsize != CURL_LLONG_MIN) {
594 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
595 parser->file_data->size = fsize;
597 parser->item_length = 0;
598 parser->item_offset = 0;
599 parser->state.UNIX.main = PL_UNIX_TIME;
600 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
602 else if (!ISDIGIT(c)) {
603 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
610 switch(parser->state.UNIX.sub.time) {
611 case PL_UNIX_TIME_PREPART1:
614 parser->item_offset = finfo->b_used -1;
615 parser->item_length = 1;
616 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
619 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
624 case PL_UNIX_TIME_PART1:
625 parser->item_length++;
627 parser->state.UNIX.sub.size = PL_UNIX_TIME_PREPART2;
629 else if(!ISALNUM(c) && c != '.') {
630 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
634 case PL_UNIX_TIME_PREPART2:
635 parser->item_length++;
638 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
641 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
646 case PL_UNIX_TIME_PART2:
647 parser->item_length++;
649 parser->state.UNIX.sub.size = PL_UNIX_TIME_PREPART3;
651 else if(!ISALNUM(c) && c != '.') {
652 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
656 case PL_UNIX_TIME_PREPART3:
657 parser->item_length++;
660 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
663 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
668 case PL_UNIX_TIME_PART3:
669 parser->item_length++;
671 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
672 parser->offsets.time = parser->item_offset;
673 if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
674 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
676 if(finfo->filetype == CURLFILETYPE_SYMLINK) {
677 parser->state.UNIX.main = PL_UNIX_SYMLINK;
678 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
681 parser->state.UNIX.main = PL_UNIX_FILENAME;
682 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
685 else if(!ISALNUM(c) && c != '.' && c != ':') {
686 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
692 case PL_UNIX_FILENAME:
693 switch(parser->state.UNIX.sub.filename) {
694 case PL_UNIX_FILENAME_PRESPACE:
696 parser->item_offset = finfo->b_used - 1;
697 parser->item_length = 1;
698 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
701 case PL_UNIX_FILENAME_NAME:
702 parser->item_length++;
704 parser->item_length--;
705 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
708 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
709 parser->offsets.filename = parser->item_offset;
710 parser->state.UNIX.main = PL_UNIX_FILETYPE;
711 rc = ftp_pl_insert_finfo(conn, finfo);
718 case PL_UNIX_FILENAME_WINDOWSEOL:
720 finfo->b_data[parser->item_offset + parser->item_length] = 0;
721 parser->offsets.filename = parser->item_offset;
722 parser->state.UNIX.main = PL_UNIX_FILETYPE;
723 rc = ftp_pl_insert_finfo(conn, finfo);
730 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
736 case PL_UNIX_SYMLINK:
737 switch(parser->state.UNIX.sub.symlink) {
738 case PL_UNIX_SYMLINK_PRESPACE:
740 parser->item_offset = finfo->b_used - 1;
741 parser->item_length = 1;
742 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
745 case PL_UNIX_SYMLINK_NAME:
746 parser->item_length++;
748 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
750 else if(c == '\r' || c == '\n') {
751 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
755 case PL_UNIX_SYMLINK_PRETARGET1:
756 parser->item_length++;
758 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
760 else if(c == '\r' || c == '\n') {
761 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
765 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
768 case PL_UNIX_SYMLINK_PRETARGET2:
769 parser->item_length++;
771 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
773 else if(c == '\r' || c == '\n') {
774 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
778 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
781 case PL_UNIX_SYMLINK_PRETARGET3:
782 parser->item_length++;
784 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
785 /* now place where is symlink following */
786 finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
787 parser->offsets.filename = parser->item_offset;
788 parser->item_length = 0;
789 parser->item_offset = 0;
791 else if(c == '\r' || c == '\n') {
792 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
796 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
799 case PL_UNIX_SYMLINK_PRETARGET4:
800 if(c != '\r' && c != '\n') {
801 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
802 parser->item_offset = finfo->b_used - 1;
803 parser->item_length = 1;
806 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
810 case PL_UNIX_SYMLINK_TARGET:
811 parser->item_length ++;
813 parser->item_length --;
814 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
817 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
818 parser->offsets.symlink_target = parser->item_offset;
819 rc = ftp_pl_insert_finfo(conn, finfo);
824 parser->state.UNIX.main = PL_UNIX_FILETYPE;
827 case PL_UNIX_SYMLINK_WINDOWSEOL:
829 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
830 parser->offsets.symlink_target = parser->item_offset;
831 rc = ftp_pl_insert_finfo(conn, finfo);
836 parser->state.UNIX.main = PL_UNIX_FILETYPE;
839 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
848 switch(parser->state.NT.main) {
850 parser->item_length++;
851 if(parser->item_length < 9) {
852 if(!strchr("0123456789-", c)) { /* only simple control */
853 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
857 else if(parser->item_length == 9) {
859 parser->state.NT.main = PL_WINNT_TIME;
860 parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
863 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
868 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
873 parser->item_length++;
874 switch(parser->state.NT.sub.time) {
875 case PL_WINNT_TIME_PRESPACE:
877 parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
880 case PL_WINNT_TIME_TIME:
882 parser->offsets.time = parser->item_offset;
883 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
884 parser->state.NT.main = PL_WINNT_DIRORSIZE;
885 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
886 parser->item_length = 0;
888 else if(!strchr("APM0123456789:", c)) {
889 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
895 case PL_WINNT_DIRORSIZE:
896 switch(parser->state.NT.sub.dirorsize) {
897 case PL_WINNT_DIRORSIZE_PRESPACE:
902 parser->item_offset = finfo->b_used - 1;
903 parser->item_length = 1;
904 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
907 case PL_WINNT_DIRORSIZE_CONTENT:
908 parser->item_length ++;
910 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
911 if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
912 finfo->filetype = CURLFILETYPE_DIRECTORY;
917 finfo->size = curlx_strtoofft(finfo->b_data + parser->item_offset,
920 if(finfo->size < CURL_LLONG_MAX &&
921 finfo->size > CURL_LLONG_MIN) {
924 else if(finfo->size == CURL_LLONG_MAX ||
925 finfo->size == CURL_LLONG_MIN) {
926 if(errno == ERANGE) {
927 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
932 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
937 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
940 /* correct file size */
941 parser->file_data->filetype = CURLFILETYPE_FILE;
944 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
945 parser->item_length = 0;
946 parser->state.NT.main = PL_WINNT_FILENAME;
947 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
952 case PL_WINNT_FILENAME:
953 switch (parser->state.NT.sub.filename) {
954 case PL_WINNT_FILENAME_PRESPACE:
956 parser->item_offset = finfo->b_used -1;
957 parser->item_length = 1;
958 parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
961 case PL_WINNT_FILENAME_CONTENT:
962 parser->item_length++;
964 parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
965 finfo->b_data[finfo->b_used - 1] = 0;
968 parser->offsets.filename = parser->item_offset;
969 finfo->b_data[finfo->b_used - 1] = 0;
970 parser->offsets.filename = parser->item_offset;
971 rc = ftp_pl_insert_finfo(conn, finfo);
976 parser->state.NT.main = PL_WINNT_DATE;
977 parser->state.NT.sub.filename = 0;
980 case PL_WINNT_FILENAME_WINEOL:
982 parser->offsets.filename = parser->item_offset;
983 rc = ftp_pl_insert_finfo(conn, finfo);
988 parser->state.NT.main = PL_WINNT_DATE;
989 parser->state.NT.sub.filename = 0;
992 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);