1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2011, 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 #define _MPRINTF_REPLACE /* use our functions only */
52 #include <curl/mprintf.h>
54 #include "curl_memory.h"
55 /* The last #include file should be: */
58 /* allocs buffer which will contain one line of LIST command response */
59 #define FTP_BUFFER_ALLOCSIZE 160
62 PL_UNIX_TOTALSIZE = 0,
76 PL_UNIX_TOTALSIZE_INIT = 0,
77 PL_UNIX_TOTALSIZE_READING
81 PL_UNIX_HLINKS_PRESPACE = 0,
86 PL_UNIX_USER_PRESPACE = 0,
91 PL_UNIX_GROUP_PRESPACE = 0,
96 PL_UNIX_SIZE_PRESPACE = 0,
101 PL_UNIX_TIME_PREPART1 = 0,
103 PL_UNIX_TIME_PREPART2,
105 PL_UNIX_TIME_PREPART3,
110 PL_UNIX_FILENAME_PRESPACE = 0,
111 PL_UNIX_FILENAME_NAME,
112 PL_UNIX_FILENAME_WINDOWSEOL
116 PL_UNIX_SYMLINK_PRESPACE = 0,
117 PL_UNIX_SYMLINK_NAME,
118 PL_UNIX_SYMLINK_PRETARGET1,
119 PL_UNIX_SYMLINK_PRETARGET2,
120 PL_UNIX_SYMLINK_PRETARGET3,
121 PL_UNIX_SYMLINK_PRETARGET4,
122 PL_UNIX_SYMLINK_TARGET,
123 PL_UNIX_SYMLINK_WINDOWSEOL
132 } pl_winNT_mainstate;
136 PL_WINNT_TIME_PRESPACE = 0,
140 PL_WINNT_DIRORSIZE_PRESPACE = 0,
141 PL_WINNT_DIRORSIZE_CONTENT
144 PL_WINNT_FILENAME_PRESPACE = 0,
145 PL_WINNT_FILENAME_CONTENT,
146 PL_WINNT_FILENAME_WINEOL
150 /* This struct is used in wildcard downloading - for parsing LIST response */
151 struct ftp_parselist_data {
160 pl_unix_mainstate main;
161 pl_unix_substate sub;
165 pl_winNT_mainstate main;
166 pl_winNT_substate sub;
171 struct curl_fileinfo *file_data;
172 unsigned int item_length;
180 size_t symlink_target;
184 struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
186 return calloc(1, sizeof(struct ftp_parselist_data));
190 void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_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 void PL_ERROR(struct connectdata *conn, CURLcode err)
273 struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
274 struct ftp_parselist_data *parser = tmpdata->parser;
275 if(parser->file_data)
276 Curl_fileinfo_dtor(NULL, parser->file_data);
277 parser->file_data = NULL;
281 static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string)
286 * There could be possible parse timestamp from server. Leaving unimplemented
288 * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to
289 * parser->file_data->flags
291 * Ftp servers are giving usually these formats:
292 * Apr 11 1998 (unknown time.. set it to 00:00:00?)
293 * Apr 11 12:21 (unknown year -> set it to NOW() time?)
294 * 08-05-09 02:49PM (ms-dos format)
295 * 20100421092538 -> for MLST/MLSD response
301 static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
302 struct curl_fileinfo *finfo)
304 curl_fnmatch_callback compare;
305 struct WildcardData *wc = &conn->data->wildcard;
306 struct ftp_wc_tmpdata *tmpdata = wc->tmp;
307 struct curl_llist *llist = wc->filelist;
308 struct ftp_parselist_data *parser = tmpdata->parser;
311 /* move finfo pointers to b_data */
312 char *str = finfo->b_data;
313 finfo->filename = str + parser->offsets.filename;
314 finfo->strings.group = parser->offsets.group ?
315 str + parser->offsets.group : NULL;
316 finfo->strings.perm = parser->offsets.perm ?
317 str + parser->offsets.perm : NULL;
318 finfo->strings.target = parser->offsets.symlink_target ?
319 str + parser->offsets.symlink_target : NULL;
320 finfo->strings.time = str + parser->offsets.time;
321 finfo->strings.user = parser->offsets.user ?
322 str + parser->offsets.user : NULL;
324 /* get correct fnmatch callback */
325 compare = conn->data->set.fnmatch;
327 compare = Curl_fnmatch;
329 /* filter pattern-corresponding filenames */
330 if(compare(conn->data->set.fnmatch_data, wc->pattern,
331 finfo->filename) == 0) {
332 /* discard symlink which is containing multiple " -> " */
333 if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
334 (strstr(finfo->strings.target, " -> "))) {
343 if(!Curl_llist_insert_next(llist, llist->tail, finfo)) {
344 Curl_fileinfo_dtor(NULL, finfo);
345 tmpdata->parser->file_data = NULL;
346 return CURLE_OUT_OF_MEMORY;
350 Curl_fileinfo_dtor(NULL, finfo);
353 tmpdata->parser->file_data = NULL;
357 /* Curl_ftp_parselist is a write callback function */
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(bufflen >= CURL_WRITEFUNC_PAUSE)
371 /* CURL_WRITEFUNC_PAUSE limits input size */
372 return CURL_WRITEFUNC_OUT_OF_MEMORY;
374 if(parser->error) { /* error in previous call */
377 * 2. call => OUT_OF_MEMORY (or other error)
378 * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
381 if(parser->error == CURLE_OUT_OF_MEMORY)
382 return CURL_WRITEFUNC_OUT_OF_MEMORY;
387 if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
388 /* considering info about FILE response format */
389 parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
390 OS_TYPE_WIN_NT : OS_TYPE_UNIX;
393 while(i < bufflen) { /* FSM */
396 if(!parser->file_data) { /* tmp file data is not allocated yet */
397 parser->file_data = Curl_fileinfo_alloc();
398 if(!parser->file_data) {
399 parser->error = CURLE_OUT_OF_MEMORY;
400 return CURL_WRITEFUNC_OUT_OF_MEMORY;
402 parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
403 if(!parser->file_data->b_data) {
404 PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
405 return CURL_WRITEFUNC_OUT_OF_MEMORY;
407 parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
408 parser->item_offset = 0;
409 parser->item_length = 0;
412 finfo = parser->file_data;
413 finfo->b_data[finfo->b_used++] = c;
415 if(finfo->b_used >= finfo->b_size - 1) {
416 /* if it is important, extend buffer space for file data */
417 char *tmp = realloc(finfo->b_data,
418 finfo->b_size + FTP_BUFFER_ALLOCSIZE);
420 finfo->b_size += FTP_BUFFER_ALLOCSIZE;
424 Curl_fileinfo_dtor(NULL, parser->file_data);
425 parser->file_data = NULL;
426 parser->error = CURLE_OUT_OF_MEMORY;
427 PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
428 return CURL_WRITEFUNC_OUT_OF_MEMORY;
432 switch (parser->os_type) {
434 switch (parser->state.UNIX.main) {
435 case PL_UNIX_TOTALSIZE:
436 switch(parser->state.UNIX.sub.total_dirsize) {
437 case PL_UNIX_TOTALSIZE_INIT:
439 parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
440 parser->item_length++;
443 parser->state.UNIX.main = PL_UNIX_FILETYPE;
444 /* start FSM again not considering size of directory */
449 case PL_UNIX_TOTALSIZE_READING:
450 parser->item_length++;
452 parser->item_length--;
456 finfo->b_data[parser->item_length - 1] = 0;
457 if(strncmp("total ", finfo->b_data, 6) == 0) {
458 char *endptr = finfo->b_data+6;
459 /* here we can deal with directory size */
460 while(ISSPACE(*endptr))
463 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
467 parser->state.UNIX.main = PL_UNIX_FILETYPE;
472 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
479 case PL_UNIX_FILETYPE:
482 finfo->filetype = CURLFILETYPE_FILE;
485 finfo->filetype = CURLFILETYPE_DIRECTORY;
488 finfo->filetype = CURLFILETYPE_SYMLINK;
491 finfo->filetype = CURLFILETYPE_NAMEDPIPE;
494 finfo->filetype = CURLFILETYPE_SOCKET;
497 finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
500 finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
503 finfo->filetype = CURLFILETYPE_DOOR;
506 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
509 parser->state.UNIX.main = PL_UNIX_PERMISSION;
510 parser->item_length = 0;
511 parser->item_offset = 1;
513 case PL_UNIX_PERMISSION:
514 parser->item_length++;
515 if(parser->item_length <= 9) {
516 if(!strchr("rwx-tTsS", c)) {
517 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
521 else if(parser->item_length == 10) {
524 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
527 finfo->b_data[10] = 0; /* terminate permissions */
528 perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
529 if(perm & FTP_LP_MALFORMATED_PERM) {
530 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
533 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM;
534 parser->file_data->perm = perm;
535 parser->offsets.perm = parser->item_offset;
537 parser->item_length = 0;
538 parser->state.UNIX.main = PL_UNIX_HLINKS;
539 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
543 switch(parser->state.UNIX.sub.hlinks) {
544 case PL_UNIX_HLINKS_PRESPACE:
546 if(c >= '0' && c <= '9') {
547 parser->item_offset = finfo->b_used - 1;
548 parser->item_length = 1;
549 parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
552 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
557 case PL_UNIX_HLINKS_NUMBER:
558 parser->item_length ++;
562 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
563 hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
564 if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
565 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
566 parser->file_data->hardlinks = hlinks;
568 parser->item_length = 0;
569 parser->item_offset = 0;
570 parser->state.UNIX.main = PL_UNIX_USER;
571 parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
573 else if(c < '0' || c > '9') {
574 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
581 switch(parser->state.UNIX.sub.user) {
582 case PL_UNIX_USER_PRESPACE:
584 parser->item_offset = finfo->b_used - 1;
585 parser->item_length = 1;
586 parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
589 case PL_UNIX_USER_PARSING:
590 parser->item_length++;
592 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
593 parser->offsets.user = parser->item_offset;
594 parser->state.UNIX.main = PL_UNIX_GROUP;
595 parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
596 parser->item_offset = 0;
597 parser->item_length = 0;
603 switch(parser->state.UNIX.sub.group) {
604 case PL_UNIX_GROUP_PRESPACE:
606 parser->item_offset = finfo->b_used - 1;
607 parser->item_length = 1;
608 parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
611 case PL_UNIX_GROUP_NAME:
612 parser->item_length++;
614 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
615 parser->offsets.group = parser->item_offset;
616 parser->state.UNIX.main = PL_UNIX_SIZE;
617 parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
618 parser->item_offset = 0;
619 parser->item_length = 0;
625 switch(parser->state.UNIX.sub.size) {
626 case PL_UNIX_SIZE_PRESPACE:
628 if(c >= '0' && c <= '9') {
629 parser->item_offset = finfo->b_used - 1;
630 parser->item_length = 1;
631 parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
634 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
639 case PL_UNIX_SIZE_NUMBER:
640 parser->item_length++;
644 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
645 fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
646 if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
647 fsize != CURL_OFF_T_MIN) {
648 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
649 parser->file_data->size = fsize;
651 parser->item_length = 0;
652 parser->item_offset = 0;
653 parser->state.UNIX.main = PL_UNIX_TIME;
654 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
656 else if(!ISDIGIT(c)) {
657 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
664 switch(parser->state.UNIX.sub.time) {
665 case PL_UNIX_TIME_PREPART1:
668 parser->item_offset = finfo->b_used -1;
669 parser->item_length = 1;
670 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
673 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
678 case PL_UNIX_TIME_PART1:
679 parser->item_length++;
681 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
683 else if(!ISALNUM(c) && c != '.') {
684 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
688 case PL_UNIX_TIME_PREPART2:
689 parser->item_length++;
692 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
695 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
700 case PL_UNIX_TIME_PART2:
701 parser->item_length++;
703 parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
705 else if(!ISALNUM(c) && c != '.') {
706 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
710 case PL_UNIX_TIME_PREPART3:
711 parser->item_length++;
714 parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
717 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
722 case PL_UNIX_TIME_PART3:
723 parser->item_length++;
725 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
726 parser->offsets.time = parser->item_offset;
727 if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
728 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
730 if(finfo->filetype == CURLFILETYPE_SYMLINK) {
731 parser->state.UNIX.main = PL_UNIX_SYMLINK;
732 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
735 parser->state.UNIX.main = PL_UNIX_FILENAME;
736 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
739 else if(!ISALNUM(c) && c != '.' && c != ':') {
740 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
746 case PL_UNIX_FILENAME:
747 switch(parser->state.UNIX.sub.filename) {
748 case PL_UNIX_FILENAME_PRESPACE:
750 parser->item_offset = finfo->b_used - 1;
751 parser->item_length = 1;
752 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
755 case PL_UNIX_FILENAME_NAME:
756 parser->item_length++;
758 parser->item_length--;
759 parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
762 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
763 parser->offsets.filename = parser->item_offset;
764 parser->state.UNIX.main = PL_UNIX_FILETYPE;
765 rc = ftp_pl_insert_finfo(conn, finfo);
772 case PL_UNIX_FILENAME_WINDOWSEOL:
774 finfo->b_data[parser->item_offset + parser->item_length] = 0;
775 parser->offsets.filename = parser->item_offset;
776 parser->state.UNIX.main = PL_UNIX_FILETYPE;
777 rc = ftp_pl_insert_finfo(conn, finfo);
784 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
790 case PL_UNIX_SYMLINK:
791 switch(parser->state.UNIX.sub.symlink) {
792 case PL_UNIX_SYMLINK_PRESPACE:
794 parser->item_offset = finfo->b_used - 1;
795 parser->item_length = 1;
796 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
799 case PL_UNIX_SYMLINK_NAME:
800 parser->item_length++;
802 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
804 else if(c == '\r' || c == '\n') {
805 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
809 case PL_UNIX_SYMLINK_PRETARGET1:
810 parser->item_length++;
812 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
814 else if(c == '\r' || c == '\n') {
815 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
819 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
822 case PL_UNIX_SYMLINK_PRETARGET2:
823 parser->item_length++;
825 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
827 else if(c == '\r' || c == '\n') {
828 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
832 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
835 case PL_UNIX_SYMLINK_PRETARGET3:
836 parser->item_length++;
838 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
839 /* now place where is symlink following */
840 finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
841 parser->offsets.filename = parser->item_offset;
842 parser->item_length = 0;
843 parser->item_offset = 0;
845 else if(c == '\r' || c == '\n') {
846 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
850 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
853 case PL_UNIX_SYMLINK_PRETARGET4:
854 if(c != '\r' && c != '\n') {
855 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
856 parser->item_offset = finfo->b_used - 1;
857 parser->item_length = 1;
860 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
864 case PL_UNIX_SYMLINK_TARGET:
865 parser->item_length ++;
867 parser->item_length --;
868 parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
871 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
872 parser->offsets.symlink_target = parser->item_offset;
873 rc = ftp_pl_insert_finfo(conn, finfo);
878 parser->state.UNIX.main = PL_UNIX_FILETYPE;
881 case PL_UNIX_SYMLINK_WINDOWSEOL:
883 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
884 parser->offsets.symlink_target = parser->item_offset;
885 rc = ftp_pl_insert_finfo(conn, finfo);
890 parser->state.UNIX.main = PL_UNIX_FILETYPE;
893 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
902 switch(parser->state.NT.main) {
904 parser->item_length++;
905 if(parser->item_length < 9) {
906 if(!strchr("0123456789-", c)) { /* only simple control */
907 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
911 else if(parser->item_length == 9) {
913 parser->state.NT.main = PL_WINNT_TIME;
914 parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
917 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
922 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
927 parser->item_length++;
928 switch(parser->state.NT.sub.time) {
929 case PL_WINNT_TIME_PRESPACE:
931 parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
934 case PL_WINNT_TIME_TIME:
936 parser->offsets.time = parser->item_offset;
937 finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
938 parser->state.NT.main = PL_WINNT_DIRORSIZE;
939 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
940 parser->item_length = 0;
942 else if(!strchr("APM0123456789:", c)) {
943 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
949 case PL_WINNT_DIRORSIZE:
950 switch(parser->state.NT.sub.dirorsize) {
951 case PL_WINNT_DIRORSIZE_PRESPACE:
956 parser->item_offset = finfo->b_used - 1;
957 parser->item_length = 1;
958 parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
961 case PL_WINNT_DIRORSIZE_CONTENT:
962 parser->item_length ++;
964 finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
965 if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
966 finfo->filetype = CURLFILETYPE_DIRECTORY;
971 finfo->size = curlx_strtoofft(finfo->b_data +
975 if(finfo->size == CURL_OFF_T_MAX ||
976 finfo->size == CURL_OFF_T_MIN) {
977 if(errno == ERANGE) {
978 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
984 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
987 /* correct file type */
988 parser->file_data->filetype = CURLFILETYPE_FILE;
991 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
992 parser->item_length = 0;
993 parser->state.NT.main = PL_WINNT_FILENAME;
994 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
999 case PL_WINNT_FILENAME:
1000 switch (parser->state.NT.sub.filename) {
1001 case PL_WINNT_FILENAME_PRESPACE:
1003 parser->item_offset = finfo->b_used -1;
1004 parser->item_length = 1;
1005 parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
1008 case PL_WINNT_FILENAME_CONTENT:
1009 parser->item_length++;
1011 parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
1012 finfo->b_data[finfo->b_used - 1] = 0;
1014 else if(c == '\n') {
1015 parser->offsets.filename = parser->item_offset;
1016 finfo->b_data[finfo->b_used - 1] = 0;
1017 parser->offsets.filename = parser->item_offset;
1018 rc = ftp_pl_insert_finfo(conn, finfo);
1023 parser->state.NT.main = PL_WINNT_DATE;
1024 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
1027 case PL_WINNT_FILENAME_WINEOL:
1029 parser->offsets.filename = parser->item_offset;
1030 rc = ftp_pl_insert_finfo(conn, finfo);
1035 parser->state.NT.main = PL_WINNT_DATE;
1036 parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
1039 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);