source: UsbWattMeter/trunk/curl-7.47.1/lib/ftplistparser.c

Last change on this file was 167, checked in by coas-nagasima, 8 years ago

MIMEにSJISを設定

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