File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / ftplistparser.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (4 years, 1 month ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>