Annotation of embedaddon/curl/lib/ftplistparser.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
9: *
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.
13: *
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.
17: *
18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19: * KIND, either express or implied.
20: *
21: ***************************************************************************/
22:
23: /**
24: * Now implemented:
25: *
26: * 1) Unix version 1
27: * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog
28: * 2) Unix version 2
29: * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog
30: * 3) Unix version 3
31: * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog
32: * 4) Unix symlink
33: * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000
34: * 5) DOS style
35: * 01-29-97 11:32PM <DIR> prog
36: */
37:
38: #include "curl_setup.h"
39:
40: #ifndef CURL_DISABLE_FTP
41:
42: #include <curl/curl.h>
43:
44: #include "urldata.h"
45: #include "fileinfo.h"
46: #include "llist.h"
47: #include "strtoofft.h"
48: #include "ftp.h"
49: #include "ftplistparser.h"
50: #include "curl_fnmatch.h"
51: #include "curl_memory.h"
52: #include "multiif.h"
53: /* The last #include file should be: */
54: #include "memdebug.h"
55:
56: /* allocs buffer which will contain one line of LIST command response */
57: #define FTP_BUFFER_ALLOCSIZE 160
58:
59: typedef enum {
60: PL_UNIX_TOTALSIZE = 0,
61: PL_UNIX_FILETYPE,
62: PL_UNIX_PERMISSION,
63: PL_UNIX_HLINKS,
64: PL_UNIX_USER,
65: PL_UNIX_GROUP,
66: PL_UNIX_SIZE,
67: PL_UNIX_TIME,
68: PL_UNIX_FILENAME,
69: PL_UNIX_SYMLINK
70: } pl_unix_mainstate;
71:
72: typedef union {
73: enum {
74: PL_UNIX_TOTALSIZE_INIT = 0,
75: PL_UNIX_TOTALSIZE_READING
76: } total_dirsize;
77:
78: enum {
79: PL_UNIX_HLINKS_PRESPACE = 0,
80: PL_UNIX_HLINKS_NUMBER
81: } hlinks;
82:
83: enum {
84: PL_UNIX_USER_PRESPACE = 0,
85: PL_UNIX_USER_PARSING
86: } user;
87:
88: enum {
89: PL_UNIX_GROUP_PRESPACE = 0,
90: PL_UNIX_GROUP_NAME
91: } group;
92:
93: enum {
94: PL_UNIX_SIZE_PRESPACE = 0,
95: PL_UNIX_SIZE_NUMBER
96: } size;
97:
98: enum {
99: PL_UNIX_TIME_PREPART1 = 0,
100: PL_UNIX_TIME_PART1,
101: PL_UNIX_TIME_PREPART2,
102: PL_UNIX_TIME_PART2,
103: PL_UNIX_TIME_PREPART3,
104: PL_UNIX_TIME_PART3
105: } time;
106:
107: enum {
108: PL_UNIX_FILENAME_PRESPACE = 0,
109: PL_UNIX_FILENAME_NAME,
110: PL_UNIX_FILENAME_WINDOWSEOL
111: } filename;
112:
113: enum {
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
122: } symlink;
123: } pl_unix_substate;
124:
125: typedef enum {
126: PL_WINNT_DATE = 0,
127: PL_WINNT_TIME,
128: PL_WINNT_DIRORSIZE,
129: PL_WINNT_FILENAME
130: } pl_winNT_mainstate;
131:
132: typedef union {
133: enum {
134: PL_WINNT_TIME_PRESPACE = 0,
135: PL_WINNT_TIME_TIME
136: } time;
137: enum {
138: PL_WINNT_DIRORSIZE_PRESPACE = 0,
139: PL_WINNT_DIRORSIZE_CONTENT
140: } dirorsize;
141: enum {
142: PL_WINNT_FILENAME_PRESPACE = 0,
143: PL_WINNT_FILENAME_CONTENT,
144: PL_WINNT_FILENAME_WINEOL
145: } filename;
146: } pl_winNT_substate;
147:
148: /* This struct is used in wildcard downloading - for parsing LIST response */
149: struct ftp_parselist_data {
150: enum {
151: OS_TYPE_UNKNOWN = 0,
152: OS_TYPE_UNIX,
153: OS_TYPE_WIN_NT
154: } os_type;
155:
156: union {
157: struct {
158: pl_unix_mainstate main;
159: pl_unix_substate sub;
160: } UNIX;
161:
162: struct {
163: pl_winNT_mainstate main;
164: pl_winNT_substate sub;
165: } NT;
166: } state;
167:
168: CURLcode error;
169: struct fileinfo *file_data;
170: unsigned int item_length;
171: size_t item_offset;
172: struct {
173: size_t filename;
174: size_t user;
175: size_t group;
176: size_t time;
177: size_t perm;
178: size_t symlink_target;
179: } offsets;
180: };
181:
182: struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
183: {
184: return calloc(1, sizeof(struct ftp_parselist_data));
185: }
186:
187:
188: void Curl_ftp_parselist_data_free(struct ftp_parselist_data **parserp)
189: {
190: struct ftp_parselist_data *parser = *parserp;
191: if(parser)
192: Curl_fileinfo_cleanup(parser->file_data);
193: free(parser);
194: *parserp = NULL;
195: }
196:
197:
198: CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
199: {
200: return pl_data->error;
201: }
202:
203:
204: #define FTP_LP_MALFORMATED_PERM 0x01000000
205:
206: static int ftp_pl_get_permission(const char *str)
207: {
208: int permissions = 0;
209: /* USER */
210: if(str[0] == 'r')
211: permissions |= 1 << 8;
212: else if(str[0] != '-')
213: permissions |= FTP_LP_MALFORMATED_PERM;
214: if(str[1] == 'w')
215: permissions |= 1 << 7;
216: else if(str[1] != '-')
217: permissions |= FTP_LP_MALFORMATED_PERM;
218:
219: if(str[2] == 'x')
220: permissions |= 1 << 6;
221: else if(str[2] == 's') {
222: permissions |= 1 << 6;
223: permissions |= 1 << 11;
224: }
225: else if(str[2] == 'S')
226: permissions |= 1 << 11;
227: else if(str[2] != '-')
228: permissions |= FTP_LP_MALFORMATED_PERM;
229: /* GROUP */
230: if(str[3] == 'r')
231: permissions |= 1 << 5;
232: else if(str[3] != '-')
233: permissions |= FTP_LP_MALFORMATED_PERM;
234: if(str[4] == 'w')
235: permissions |= 1 << 4;
236: else if(str[4] != '-')
237: permissions |= FTP_LP_MALFORMATED_PERM;
238: if(str[5] == 'x')
239: permissions |= 1 << 3;
240: else if(str[5] == 's') {
241: permissions |= 1 << 3;
242: permissions |= 1 << 10;
243: }
244: else if(str[5] == 'S')
245: permissions |= 1 << 10;
246: else if(str[5] != '-')
247: permissions |= FTP_LP_MALFORMATED_PERM;
248: /* others */
249: if(str[6] == 'r')
250: permissions |= 1 << 2;
251: else if(str[6] != '-')
252: permissions |= FTP_LP_MALFORMATED_PERM;
253: if(str[7] == 'w')
254: permissions |= 1 << 1;
255: else if(str[7] != '-')
256: permissions |= FTP_LP_MALFORMATED_PERM;
257: if(str[8] == 'x')
258: permissions |= 1;
259: else if(str[8] == 't') {
260: permissions |= 1;
261: permissions |= 1 << 9;
262: }
263: else if(str[8] == 'T')
264: permissions |= 1 << 9;
265: else if(str[8] != '-')
266: permissions |= FTP_LP_MALFORMATED_PERM;
267:
268: return permissions;
269: }
270:
271: static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
272: struct fileinfo *infop)
273: {
274: curl_fnmatch_callback compare;
275: struct WildcardData *wc = &conn->data->wildcard;
276: struct ftp_wc *ftpwc = wc->protdata;
277: struct curl_llist *llist = &wc->filelist;
278: struct ftp_parselist_data *parser = ftpwc->parser;
279: bool add = TRUE;
280: struct curl_fileinfo *finfo = &infop->info;
281:
282: /* move finfo pointers to b_data */
283: char *str = finfo->b_data;
284: finfo->filename = str + parser->offsets.filename;
285: finfo->strings.group = parser->offsets.group ?
286: str + parser->offsets.group : NULL;
287: finfo->strings.perm = parser->offsets.perm ?
288: str + parser->offsets.perm : NULL;
289: finfo->strings.target = parser->offsets.symlink_target ?
290: str + parser->offsets.symlink_target : NULL;
291: finfo->strings.time = str + parser->offsets.time;
292: finfo->strings.user = parser->offsets.user ?
293: str + parser->offsets.user : NULL;
294:
295: /* get correct fnmatch callback */
296: compare = conn->data->set.fnmatch;
297: if(!compare)
298: compare = Curl_fnmatch;
299:
300: /* filter pattern-corresponding filenames */
301: Curl_set_in_callback(conn->data, true);
302: if(compare(conn->data->set.fnmatch_data, wc->pattern,
303: finfo->filename) == 0) {
304: /* discard symlink which is containing multiple " -> " */
305: if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
306: (strstr(finfo->strings.target, " -> "))) {
307: add = FALSE;
308: }
309: }
310: else {
311: add = FALSE;
312: }
313: Curl_set_in_callback(conn->data, false);
314:
315: if(add) {
316: Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
317: }
318: else {
319: Curl_fileinfo_cleanup(infop);
320: }
321:
322: ftpwc->parser->file_data = NULL;
323: return CURLE_OK;
324: }
325:
326: size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
327: void *connptr)
328: {
329: size_t bufflen = size*nmemb;
330: struct connectdata *conn = (struct connectdata *)connptr;
331: struct ftp_wc *ftpwc = conn->data->wildcard.protdata;
332: struct ftp_parselist_data *parser = ftpwc->parser;
333: struct fileinfo *infop;
334: struct curl_fileinfo *finfo;
335: unsigned long i = 0;
336: CURLcode result;
337: size_t retsize = bufflen;
338:
339: if(parser->error) { /* error in previous call */
340: /* scenario:
341: * 1. call => OK..
342: * 2. call => OUT_OF_MEMORY (or other error)
343: * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
344: * in wc_statemach()
345: */
346: goto fail;
347: }
348:
349: if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
350: /* considering info about FILE response format */
351: parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
352: OS_TYPE_WIN_NT : OS_TYPE_UNIX;
353: }
354:
355: while(i < bufflen) { /* FSM */
356:
357: char c = buffer[i];
358: if(!parser->file_data) { /* tmp file data is not allocated yet */
359: parser->file_data = Curl_fileinfo_alloc();
360: if(!parser->file_data) {
361: parser->error = CURLE_OUT_OF_MEMORY;
362: goto fail;
363: }
364: parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE);
365: if(!parser->file_data->info.b_data) {
366: parser->error = CURLE_OUT_OF_MEMORY;
367: goto fail;
368: }
369: parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE;
370: parser->item_offset = 0;
371: parser->item_length = 0;
372: }
373:
374: infop = parser->file_data;
375: finfo = &infop->info;
376: finfo->b_data[finfo->b_used++] = c;
377:
378: if(finfo->b_used >= finfo->b_size - 1) {
379: /* if it is important, extend buffer space for file data */
380: char *tmp = realloc(finfo->b_data,
381: finfo->b_size + FTP_BUFFER_ALLOCSIZE);
382: if(tmp) {
383: finfo->b_size += FTP_BUFFER_ALLOCSIZE;
384: finfo->b_data = tmp;
385: }
386: else {
387: Curl_fileinfo_cleanup(parser->file_data);
388: parser->file_data = NULL;
389: parser->error = CURLE_OUT_OF_MEMORY;
390: goto fail;
391: }
392: }
393:
394: switch(parser->os_type) {
395: case OS_TYPE_UNIX:
396: switch(parser->state.UNIX.main) {
397: case PL_UNIX_TOTALSIZE:
398: switch(parser->state.UNIX.sub.total_dirsize) {
399: case PL_UNIX_TOTALSIZE_INIT:
400: if(c == 't') {
401: parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
402: parser->item_length++;
403: }
404: else {
405: parser->state.UNIX.main = PL_UNIX_FILETYPE;
406: /* start FSM again not considering size of directory */
407: finfo->b_used = 0;
408: continue;
409: }
410: break;
411: case PL_UNIX_TOTALSIZE_READING:
412: parser->item_length++;
413: if(c == '\r') {
414: parser->item_length--;
415: finfo->b_used--;
416: }
417: else if(c == '\n') {
418: finfo->b_data[parser->item_length - 1] = 0;
419: if(strncmp("total ", finfo->b_data, 6) == 0) {
420: char *endptr = finfo->b_data + 6;
421: /* here we can deal with directory size, pass the leading white
422: spaces and then the digits */
423: while(ISSPACE(*endptr))
424: endptr++;
425: while(ISDIGIT(*endptr))
426: endptr++;
427: if(*endptr != 0) {
428: parser->error = CURLE_FTP_BAD_FILE_LIST;
429: goto fail;
430: }
431: parser->state.UNIX.main = PL_UNIX_FILETYPE;
432: finfo->b_used = 0;
433: }
434: else {
435: parser->error = CURLE_FTP_BAD_FILE_LIST;
436: goto fail;
437: }
438: }
439: break;
440: }
441: break;
442: case PL_UNIX_FILETYPE:
443: switch(c) {
444: case '-':
445: finfo->filetype = CURLFILETYPE_FILE;
446: break;
447: case 'd':
448: finfo->filetype = CURLFILETYPE_DIRECTORY;
449: break;
450: case 'l':
451: finfo->filetype = CURLFILETYPE_SYMLINK;
452: break;
453: case 'p':
454: finfo->filetype = CURLFILETYPE_NAMEDPIPE;
455: break;
456: case 's':
457: finfo->filetype = CURLFILETYPE_SOCKET;
458: break;
459: case 'c':
460: finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
461: break;
462: case 'b':
463: finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
464: break;
465: case 'D':
466: finfo->filetype = CURLFILETYPE_DOOR;
467: break;
468: default:
469: parser->error = CURLE_FTP_BAD_FILE_LIST;
470: goto fail;
471: }
472: parser->state.UNIX.main = PL_UNIX_PERMISSION;
473: parser->item_length = 0;
474: parser->item_offset = 1;
475: break;
476: case PL_UNIX_PERMISSION:
477: parser->item_length++;
478: if(parser->item_length <= 9) {
479: if(!strchr("rwx-tTsS", c)) {
480: parser->error = CURLE_FTP_BAD_FILE_LIST;
481: goto fail;
482: }
483: }
484: else if(parser->item_length == 10) {
485: unsigned int perm;
486: if(c != ' ') {
487: parser->error = CURLE_FTP_BAD_FILE_LIST;
488: goto fail;
489: }
490: finfo->b_data[10] = 0; /* terminate permissions */
491: perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
492: if(perm & FTP_LP_MALFORMATED_PERM) {
493: parser->error = CURLE_FTP_BAD_FILE_LIST;
494: goto fail;
495: }
496: parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
497: parser->file_data->info.perm = perm;
498: parser->offsets.perm = parser->item_offset;
499:
500: parser->item_length = 0;
501: parser->state.UNIX.main = PL_UNIX_HLINKS;
502: parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
503: }
504: break;
505: case PL_UNIX_HLINKS:
506: switch(parser->state.UNIX.sub.hlinks) {
507: case PL_UNIX_HLINKS_PRESPACE:
508: if(c != ' ') {
509: if(c >= '0' && c <= '9') {
510: parser->item_offset = finfo->b_used - 1;
511: parser->item_length = 1;
512: parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
513: }
514: else {
515: parser->error = CURLE_FTP_BAD_FILE_LIST;
516: goto fail;
517: }
518: }
519: break;
520: case PL_UNIX_HLINKS_NUMBER:
521: parser->item_length ++;
522: if(c == ' ') {
523: char *p;
524: long int hlinks;
525: finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
526: hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
527: if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
528: parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
529: parser->file_data->info.hardlinks = hlinks;
530: }
531: parser->item_length = 0;
532: parser->item_offset = 0;
533: parser->state.UNIX.main = PL_UNIX_USER;
534: parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
535: }
536: else if(c < '0' || c > '9') {
537: parser->error = CURLE_FTP_BAD_FILE_LIST;
538: goto fail;
539: }
540: break;
541: }
542: break;
543: case PL_UNIX_USER:
544: switch(parser->state.UNIX.sub.user) {
545: case PL_UNIX_USER_PRESPACE:
546: if(c != ' ') {
547: parser->item_offset = finfo->b_used - 1;
548: parser->item_length = 1;
549: parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
550: }
551: break;
552: case PL_UNIX_USER_PARSING:
553: parser->item_length++;
554: if(c == ' ') {
555: finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
556: parser->offsets.user = parser->item_offset;
557: parser->state.UNIX.main = PL_UNIX_GROUP;
558: parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
559: parser->item_offset = 0;
560: parser->item_length = 0;
561: }
562: break;
563: }
564: break;
565: case PL_UNIX_GROUP:
566: switch(parser->state.UNIX.sub.group) {
567: case PL_UNIX_GROUP_PRESPACE:
568: if(c != ' ') {
569: parser->item_offset = finfo->b_used - 1;
570: parser->item_length = 1;
571: parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
572: }
573: break;
574: case PL_UNIX_GROUP_NAME:
575: parser->item_length++;
576: if(c == ' ') {
577: finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
578: parser->offsets.group = parser->item_offset;
579: parser->state.UNIX.main = PL_UNIX_SIZE;
580: parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
581: parser->item_offset = 0;
582: parser->item_length = 0;
583: }
584: break;
585: }
586: break;
587: case PL_UNIX_SIZE:
588: switch(parser->state.UNIX.sub.size) {
589: case PL_UNIX_SIZE_PRESPACE:
590: if(c != ' ') {
591: if(c >= '0' && c <= '9') {
592: parser->item_offset = finfo->b_used - 1;
593: parser->item_length = 1;
594: parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
595: }
596: else {
597: parser->error = CURLE_FTP_BAD_FILE_LIST;
598: goto fail;
599: }
600: }
601: break;
602: case PL_UNIX_SIZE_NUMBER:
603: parser->item_length++;
604: if(c == ' ') {
605: char *p;
606: curl_off_t fsize;
607: finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
608: if(!curlx_strtoofft(finfo->b_data + parser->item_offset,
609: &p, 10, &fsize)) {
610: if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
611: fsize != CURL_OFF_T_MIN) {
612: parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
613: parser->file_data->info.size = fsize;
614: }
615: parser->item_length = 0;
616: parser->item_offset = 0;
617: parser->state.UNIX.main = PL_UNIX_TIME;
618: parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
619: }
620: }
621: else if(!ISDIGIT(c)) {
622: parser->error = CURLE_FTP_BAD_FILE_LIST;
623: goto fail;
624: }
625: break;
626: }
627: break;
628: case PL_UNIX_TIME:
629: switch(parser->state.UNIX.sub.time) {
630: case PL_UNIX_TIME_PREPART1:
631: if(c != ' ') {
632: if(ISALNUM(c)) {
633: parser->item_offset = finfo->b_used -1;
634: parser->item_length = 1;
635: parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
636: }
637: else {
638: parser->error = CURLE_FTP_BAD_FILE_LIST;
639: goto fail;
640: }
641: }
642: break;
643: case PL_UNIX_TIME_PART1:
644: parser->item_length++;
645: if(c == ' ') {
646: parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
647: }
648: else if(!ISALNUM(c) && c != '.') {
649: parser->error = CURLE_FTP_BAD_FILE_LIST;
650: goto fail;
651: }
652: break;
653: case PL_UNIX_TIME_PREPART2:
654: parser->item_length++;
655: if(c != ' ') {
656: if(ISALNUM(c)) {
657: parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
658: }
659: else {
660: parser->error = CURLE_FTP_BAD_FILE_LIST;
661: goto fail;
662: }
663: }
664: break;
665: case PL_UNIX_TIME_PART2:
666: parser->item_length++;
667: if(c == ' ') {
668: parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
669: }
670: else if(!ISALNUM(c) && c != '.') {
671: parser->error = CURLE_FTP_BAD_FILE_LIST;
672: goto fail;
673: }
674: break;
675: case PL_UNIX_TIME_PREPART3:
676: parser->item_length++;
677: if(c != ' ') {
678: if(ISALNUM(c)) {
679: parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
680: }
681: else {
682: parser->error = CURLE_FTP_BAD_FILE_LIST;
683: goto fail;
684: }
685: }
686: break;
687: case PL_UNIX_TIME_PART3:
688: parser->item_length++;
689: if(c == ' ') {
690: finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
691: parser->offsets.time = parser->item_offset;
692: /*
693: if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
694: parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
695: }
696: */
697: if(finfo->filetype == CURLFILETYPE_SYMLINK) {
698: parser->state.UNIX.main = PL_UNIX_SYMLINK;
699: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
700: }
701: else {
702: parser->state.UNIX.main = PL_UNIX_FILENAME;
703: parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
704: }
705: }
706: else if(!ISALNUM(c) && c != '.' && c != ':') {
707: parser->error = CURLE_FTP_BAD_FILE_LIST;
708: goto fail;
709: }
710: break;
711: }
712: break;
713: case PL_UNIX_FILENAME:
714: switch(parser->state.UNIX.sub.filename) {
715: case PL_UNIX_FILENAME_PRESPACE:
716: if(c != ' ') {
717: parser->item_offset = finfo->b_used - 1;
718: parser->item_length = 1;
719: parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
720: }
721: break;
722: case PL_UNIX_FILENAME_NAME:
723: parser->item_length++;
724: if(c == '\r') {
725: parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
726: }
727: else if(c == '\n') {
728: finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
729: parser->offsets.filename = parser->item_offset;
730: parser->state.UNIX.main = PL_UNIX_FILETYPE;
731: result = ftp_pl_insert_finfo(conn, infop);
732: if(result) {
733: parser->error = result;
734: goto fail;
735: }
736: }
737: break;
738: case PL_UNIX_FILENAME_WINDOWSEOL:
739: if(c == '\n') {
740: finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
741: parser->offsets.filename = parser->item_offset;
742: parser->state.UNIX.main = PL_UNIX_FILETYPE;
743: result = ftp_pl_insert_finfo(conn, infop);
744: if(result) {
745: parser->error = result;
746: goto fail;
747: }
748: }
749: else {
750: parser->error = CURLE_FTP_BAD_FILE_LIST;
751: goto fail;
752: }
753: break;
754: }
755: break;
756: case PL_UNIX_SYMLINK:
757: switch(parser->state.UNIX.sub.symlink) {
758: case PL_UNIX_SYMLINK_PRESPACE:
759: if(c != ' ') {
760: parser->item_offset = finfo->b_used - 1;
761: parser->item_length = 1;
762: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
763: }
764: break;
765: case PL_UNIX_SYMLINK_NAME:
766: parser->item_length++;
767: if(c == ' ') {
768: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
769: }
770: else if(c == '\r' || c == '\n') {
771: parser->error = CURLE_FTP_BAD_FILE_LIST;
772: goto fail;
773: }
774: break;
775: case PL_UNIX_SYMLINK_PRETARGET1:
776: parser->item_length++;
777: if(c == '-') {
778: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
779: }
780: else if(c == '\r' || c == '\n') {
781: parser->error = CURLE_FTP_BAD_FILE_LIST;
782: goto fail;
783: }
784: else {
785: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
786: }
787: break;
788: case PL_UNIX_SYMLINK_PRETARGET2:
789: parser->item_length++;
790: if(c == '>') {
791: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
792: }
793: else if(c == '\r' || c == '\n') {
794: parser->error = CURLE_FTP_BAD_FILE_LIST;
795: goto fail;
796: }
797: else {
798: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
799: }
800: break;
801: case PL_UNIX_SYMLINK_PRETARGET3:
802: parser->item_length++;
803: if(c == ' ') {
804: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
805: /* now place where is symlink following */
806: finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
807: parser->offsets.filename = parser->item_offset;
808: parser->item_length = 0;
809: parser->item_offset = 0;
810: }
811: else if(c == '\r' || c == '\n') {
812: parser->error = CURLE_FTP_BAD_FILE_LIST;
813: goto fail;
814: }
815: else {
816: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
817: }
818: break;
819: case PL_UNIX_SYMLINK_PRETARGET4:
820: if(c != '\r' && c != '\n') {
821: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
822: parser->item_offset = finfo->b_used - 1;
823: parser->item_length = 1;
824: }
825: else {
826: parser->error = CURLE_FTP_BAD_FILE_LIST;
827: goto fail;
828: }
829: break;
830: case PL_UNIX_SYMLINK_TARGET:
831: parser->item_length++;
832: if(c == '\r') {
833: parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
834: }
835: else if(c == '\n') {
836: finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
837: parser->offsets.symlink_target = parser->item_offset;
838: result = ftp_pl_insert_finfo(conn, infop);
839: if(result) {
840: parser->error = result;
841: goto fail;
842: }
843: parser->state.UNIX.main = PL_UNIX_FILETYPE;
844: }
845: break;
846: case PL_UNIX_SYMLINK_WINDOWSEOL:
847: if(c == '\n') {
848: finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
849: parser->offsets.symlink_target = parser->item_offset;
850: result = ftp_pl_insert_finfo(conn, infop);
851: if(result) {
852: parser->error = result;
853: goto fail;
854: }
855: parser->state.UNIX.main = PL_UNIX_FILETYPE;
856: }
857: else {
858: parser->error = CURLE_FTP_BAD_FILE_LIST;
859: goto fail;
860: }
861: break;
862: }
863: break;
864: }
865: break;
866: case OS_TYPE_WIN_NT:
867: switch(parser->state.NT.main) {
868: case PL_WINNT_DATE:
869: parser->item_length++;
870: if(parser->item_length < 9) {
871: if(!strchr("0123456789-", c)) { /* only simple control */
872: parser->error = CURLE_FTP_BAD_FILE_LIST;
873: goto fail;
874: }
875: }
876: else if(parser->item_length == 9) {
877: if(c == ' ') {
878: parser->state.NT.main = PL_WINNT_TIME;
879: parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
880: }
881: else {
882: parser->error = CURLE_FTP_BAD_FILE_LIST;
883: goto fail;
884: }
885: }
886: else {
887: parser->error = CURLE_FTP_BAD_FILE_LIST;
888: goto fail;
889: }
890: break;
891: case PL_WINNT_TIME:
892: parser->item_length++;
893: switch(parser->state.NT.sub.time) {
894: case PL_WINNT_TIME_PRESPACE:
895: if(!ISSPACE(c)) {
896: parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
897: }
898: break;
899: case PL_WINNT_TIME_TIME:
900: if(c == ' ') {
901: parser->offsets.time = parser->item_offset;
902: finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
903: parser->state.NT.main = PL_WINNT_DIRORSIZE;
904: parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
905: parser->item_length = 0;
906: }
907: else if(!strchr("APM0123456789:", c)) {
908: parser->error = CURLE_FTP_BAD_FILE_LIST;
909: goto fail;
910: }
911: break;
912: }
913: break;
914: case PL_WINNT_DIRORSIZE:
915: switch(parser->state.NT.sub.dirorsize) {
916: case PL_WINNT_DIRORSIZE_PRESPACE:
917: if(c != ' ') {
918: parser->item_offset = finfo->b_used - 1;
919: parser->item_length = 1;
920: parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
921: }
922: break;
923: case PL_WINNT_DIRORSIZE_CONTENT:
924: parser->item_length ++;
925: if(c == ' ') {
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;
929: finfo->size = 0;
930: }
931: else {
932: char *endptr;
933: if(curlx_strtoofft(finfo->b_data +
934: parser->item_offset,
935: &endptr, 10, &finfo->size)) {
936: parser->error = CURLE_FTP_BAD_FILE_LIST;
937: goto fail;
938: }
939: /* correct file type */
940: parser->file_data->info.filetype = CURLFILETYPE_FILE;
941: }
942:
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;
947: }
948: break;
949: }
950: break;
951: case PL_WINNT_FILENAME:
952: switch(parser->state.NT.sub.filename) {
953: case PL_WINNT_FILENAME_PRESPACE:
954: if(c != ' ') {
955: parser->item_offset = finfo->b_used -1;
956: parser->item_length = 1;
957: parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
958: }
959: break;
960: case PL_WINNT_FILENAME_CONTENT:
961: parser->item_length++;
962: if(c == '\r') {
963: parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
964: finfo->b_data[finfo->b_used - 1] = 0;
965: }
966: else if(c == '\n') {
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);
971: if(result) {
972: parser->error = result;
973: goto fail;
974: }
975: parser->state.NT.main = PL_WINNT_DATE;
976: parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
977: }
978: break;
979: case PL_WINNT_FILENAME_WINEOL:
980: if(c == '\n') {
981: parser->offsets.filename = parser->item_offset;
982: result = ftp_pl_insert_finfo(conn, infop);
983: if(result) {
984: parser->error = result;
985: goto fail;
986: }
987: parser->state.NT.main = PL_WINNT_DATE;
988: parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
989: }
990: else {
991: parser->error = CURLE_FTP_BAD_FILE_LIST;
992: goto fail;
993: }
994: break;
995: }
996: break;
997: }
998: break;
999: default:
1000: retsize = bufflen + 1;
1001: goto fail;
1002: }
1003:
1004: i++;
1005: }
1006: return retsize;
1007:
1008: fail:
1009:
1010: /* Clean up any allocated memory. */
1011: if(parser->file_data) {
1012: Curl_fileinfo_cleanup(parser->file_data);
1013: parser->file_data = NULL;
1014: }
1015:
1016: return retsize;
1017: }
1018:
1019: #endif /* CURL_DISABLE_FTP */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>