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>