Annotation of embedaddon/curl/lib/ftplistparser.c, revision 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>