123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053 |
- /***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
- /**
- * Now implemented:
- *
- * 1) UNIX version 1
- * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog
- * 2) UNIX version 2
- * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog
- * 3) UNIX version 3
- * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog
- * 4) UNIX symlink
- * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000
- * 5) DOS style
- * 01-29-97 11:32PM <DIR> prog
- */
- #include "curl_setup.h"
- #ifndef CURL_DISABLE_FTP
- #include <curl/curl.h>
- #include "urldata.h"
- #include "fileinfo.h"
- #include "llist.h"
- #include "strtoofft.h"
- #include "rawstr.h"
- #include "ftp.h"
- #include "ftplistparser.h"
- #include "curl_fnmatch.h"
- #define _MPRINTF_REPLACE /* use our functions only */
- #include <curl/mprintf.h>
- #include "curl_memory.h"
- /* The last #include file should be: */
- #include "memdebug.h"
- /* allocs buffer which will contain one line of LIST command response */
- #define FTP_BUFFER_ALLOCSIZE 160
- typedef enum {
- PL_UNIX_TOTALSIZE = 0,
- PL_UNIX_FILETYPE,
- PL_UNIX_PERMISSION,
- PL_UNIX_HLINKS,
- PL_UNIX_USER,
- PL_UNIX_GROUP,
- PL_UNIX_SIZE,
- PL_UNIX_TIME,
- PL_UNIX_FILENAME,
- PL_UNIX_SYMLINK
- } pl_unix_mainstate;
- typedef union {
- enum {
- PL_UNIX_TOTALSIZE_INIT = 0,
- PL_UNIX_TOTALSIZE_READING
- } total_dirsize;
- enum {
- PL_UNIX_HLINKS_PRESPACE = 0,
- PL_UNIX_HLINKS_NUMBER
- } hlinks;
- enum {
- PL_UNIX_USER_PRESPACE = 0,
- PL_UNIX_USER_PARSING
- } user;
- enum {
- PL_UNIX_GROUP_PRESPACE = 0,
- PL_UNIX_GROUP_NAME
- } group;
- enum {
- PL_UNIX_SIZE_PRESPACE = 0,
- PL_UNIX_SIZE_NUMBER
- } size;
- enum {
- PL_UNIX_TIME_PREPART1 = 0,
- PL_UNIX_TIME_PART1,
- PL_UNIX_TIME_PREPART2,
- PL_UNIX_TIME_PART2,
- PL_UNIX_TIME_PREPART3,
- PL_UNIX_TIME_PART3
- } time;
- enum {
- PL_UNIX_FILENAME_PRESPACE = 0,
- PL_UNIX_FILENAME_NAME,
- PL_UNIX_FILENAME_WINDOWSEOL
- } filename;
- enum {
- PL_UNIX_SYMLINK_PRESPACE = 0,
- PL_UNIX_SYMLINK_NAME,
- PL_UNIX_SYMLINK_PRETARGET1,
- PL_UNIX_SYMLINK_PRETARGET2,
- PL_UNIX_SYMLINK_PRETARGET3,
- PL_UNIX_SYMLINK_PRETARGET4,
- PL_UNIX_SYMLINK_TARGET,
- PL_UNIX_SYMLINK_WINDOWSEOL
- } symlink;
- } pl_unix_substate;
- typedef enum {
- PL_WINNT_DATE = 0,
- PL_WINNT_TIME,
- PL_WINNT_DIRORSIZE,
- PL_WINNT_FILENAME
- } pl_winNT_mainstate;
- typedef union {
- enum {
- PL_WINNT_TIME_PRESPACE = 0,
- PL_WINNT_TIME_TIME
- } time;
- enum {
- PL_WINNT_DIRORSIZE_PRESPACE = 0,
- PL_WINNT_DIRORSIZE_CONTENT
- } dirorsize;
- enum {
- PL_WINNT_FILENAME_PRESPACE = 0,
- PL_WINNT_FILENAME_CONTENT,
- PL_WINNT_FILENAME_WINEOL
- } filename;
- } pl_winNT_substate;
- /* This struct is used in wildcard downloading - for parsing LIST response */
- struct ftp_parselist_data {
- enum {
- OS_TYPE_UNKNOWN = 0,
- OS_TYPE_UNIX,
- OS_TYPE_WIN_NT
- } os_type;
- union {
- struct {
- pl_unix_mainstate main;
- pl_unix_substate sub;
- } UNIX;
- struct {
- pl_winNT_mainstate main;
- pl_winNT_substate sub;
- } NT;
- } state;
- CURLcode error;
- struct curl_fileinfo *file_data;
- unsigned int item_length;
- size_t item_offset;
- struct {
- size_t filename;
- size_t user;
- size_t group;
- size_t time;
- size_t perm;
- size_t symlink_target;
- } offsets;
- };
- struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
- {
- return calloc(1, sizeof(struct ftp_parselist_data));
- }
- void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
- {
- if(*pl_data)
- free(*pl_data);
- *pl_data = NULL;
- }
- CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
- {
- return pl_data->error;
- }
- #define FTP_LP_MALFORMATED_PERM 0x01000000
- static int ftp_pl_get_permission(const char *str)
- {
- int permissions = 0;
- /* USER */
- if(str[0] == 'r')
- permissions |= 1 << 8;
- else if(str[0] != '-')
- permissions |= FTP_LP_MALFORMATED_PERM;
- if(str[1] == 'w')
- permissions |= 1 << 7;
- else if(str[1] != '-')
- permissions |= FTP_LP_MALFORMATED_PERM;
- if(str[2] == 'x')
- permissions |= 1 << 6;
- else if(str[2] == 's') {
- permissions |= 1 << 6;
- permissions |= 1 << 11;
- }
- else if(str[2] == 'S')
- permissions |= 1 << 11;
- else if(str[2] != '-')
- permissions |= FTP_LP_MALFORMATED_PERM;
- /* GROUP */
- if(str[3] == 'r')
- permissions |= 1 << 5;
- else if(str[3] != '-')
- permissions |= FTP_LP_MALFORMATED_PERM;
- if(str[4] == 'w')
- permissions |= 1 << 4;
- else if(str[4] != '-')
- permissions |= FTP_LP_MALFORMATED_PERM;
- if(str[5] == 'x')
- permissions |= 1 << 3;
- else if(str[5] == 's') {
- permissions |= 1 << 3;
- permissions |= 1 << 10;
- }
- else if(str[5] == 'S')
- permissions |= 1 << 10;
- else if(str[5] != '-')
- permissions |= FTP_LP_MALFORMATED_PERM;
- /* others */
- if(str[6] == 'r')
- permissions |= 1 << 2;
- else if(str[6] != '-')
- permissions |= FTP_LP_MALFORMATED_PERM;
- if(str[7] == 'w')
- permissions |= 1 << 1;
- else if(str[7] != '-')
- permissions |= FTP_LP_MALFORMATED_PERM;
- if(str[8] == 'x')
- permissions |= 1;
- else if(str[8] == 't') {
- permissions |= 1;
- permissions |= 1 << 9;
- }
- else if(str[8] == 'T')
- permissions |= 1 << 9;
- else if(str[8] != '-')
- permissions |= FTP_LP_MALFORMATED_PERM;
- return permissions;
- }
- static void PL_ERROR(struct connectdata *conn, CURLcode err)
- {
- struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
- struct ftp_parselist_data *parser = tmpdata->parser;
- if(parser->file_data)
- Curl_fileinfo_dtor(NULL, parser->file_data);
- parser->file_data = NULL;
- parser->error = err;
- }
- static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string)
- {
- (void)parser;
- (void)string;
- /* TODO
- * There could be possible parse timestamp from server. Leaving unimplemented
- * for now.
- * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to
- * parser->file_data->flags
- *
- * Ftp servers are giving usually these formats:
- * Apr 11 1998 (unknown time.. set it to 00:00:00?)
- * Apr 11 12:21 (unknown year -> set it to NOW() time?)
- * 08-05-09 02:49PM (ms-dos format)
- * 20100421092538 -> for MLST/MLSD response
- */
- return FALSE;
- }
- static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
- struct curl_fileinfo *finfo)
- {
- curl_fnmatch_callback compare;
- struct WildcardData *wc = &conn->data->wildcard;
- struct ftp_wc_tmpdata *tmpdata = wc->tmp;
- struct curl_llist *llist = wc->filelist;
- struct ftp_parselist_data *parser = tmpdata->parser;
- bool add = TRUE;
- /* move finfo pointers to b_data */
- char *str = finfo->b_data;
- finfo->filename = str + parser->offsets.filename;
- finfo->strings.group = parser->offsets.group ?
- str + parser->offsets.group : NULL;
- finfo->strings.perm = parser->offsets.perm ?
- str + parser->offsets.perm : NULL;
- finfo->strings.target = parser->offsets.symlink_target ?
- str + parser->offsets.symlink_target : NULL;
- finfo->strings.time = str + parser->offsets.time;
- finfo->strings.user = parser->offsets.user ?
- str + parser->offsets.user : NULL;
- /* get correct fnmatch callback */
- compare = conn->data->set.fnmatch;
- if(!compare)
- compare = Curl_fnmatch;
- /* filter pattern-corresponding filenames */
- if(compare(conn->data->set.fnmatch_data, wc->pattern,
- finfo->filename) == 0) {
- /* discard symlink which is containing multiple " -> " */
- if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
- (strstr(finfo->strings.target, " -> "))) {
- add = FALSE;
- }
- }
- else {
- add = FALSE;
- }
- if(add) {
- if(!Curl_llist_insert_next(llist, llist->tail, finfo)) {
- Curl_fileinfo_dtor(NULL, finfo);
- tmpdata->parser->file_data = NULL;
- return CURLE_OUT_OF_MEMORY;
- }
- }
- else {
- Curl_fileinfo_dtor(NULL, finfo);
- }
- tmpdata->parser->file_data = NULL;
- return CURLE_OK;
- }
- size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
- void *connptr)
- {
- size_t bufflen = size*nmemb;
- struct connectdata *conn = (struct connectdata *)connptr;
- struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
- struct ftp_parselist_data *parser = tmpdata->parser;
- struct curl_fileinfo *finfo;
- unsigned long i = 0;
- CURLcode result;
- if(parser->error) { /* error in previous call */
- /* scenario:
- * 1. call => OK..
- * 2. call => OUT_OF_MEMORY (or other error)
- * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
- * in wc_statemach()
- */
- return bufflen;
- }
- if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
- /* considering info about FILE response format */
- parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
- OS_TYPE_WIN_NT : OS_TYPE_UNIX;
- }
- while(i < bufflen) { /* FSM */
- char c = buffer[i];
- if(!parser->file_data) { /* tmp file data is not allocated yet */
- parser->file_data = Curl_fileinfo_alloc();
- if(!parser->file_data) {
- parser->error = CURLE_OUT_OF_MEMORY;
- return bufflen;
- }
- parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
- if(!parser->file_data->b_data) {
- PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
- return bufflen;
- }
- parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
- parser->item_offset = 0;
- parser->item_length = 0;
- }
- finfo = parser->file_data;
- finfo->b_data[finfo->b_used++] = c;
- if(finfo->b_used >= finfo->b_size - 1) {
- /* if it is important, extend buffer space for file data */
- char *tmp = realloc(finfo->b_data,
- finfo->b_size + FTP_BUFFER_ALLOCSIZE);
- if(tmp) {
- finfo->b_size += FTP_BUFFER_ALLOCSIZE;
- finfo->b_data = tmp;
- }
- else {
- Curl_fileinfo_dtor(NULL, parser->file_data);
- parser->file_data = NULL;
- parser->error = CURLE_OUT_OF_MEMORY;
- PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
- return bufflen;
- }
- }
- switch (parser->os_type) {
- case OS_TYPE_UNIX:
- switch (parser->state.UNIX.main) {
- case PL_UNIX_TOTALSIZE:
- switch(parser->state.UNIX.sub.total_dirsize) {
- case PL_UNIX_TOTALSIZE_INIT:
- if(c == 't') {
- parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
- parser->item_length++;
- }
- else {
- parser->state.UNIX.main = PL_UNIX_FILETYPE;
- /* start FSM again not considering size of directory */
- finfo->b_used = 0;
- i--;
- }
- break;
- case PL_UNIX_TOTALSIZE_READING:
- parser->item_length++;
- if(c == '\r') {
- parser->item_length--;
- finfo->b_used--;
- }
- else if(c == '\n') {
- finfo->b_data[parser->item_length - 1] = 0;
- if(strncmp("total ", finfo->b_data, 6) == 0) {
- char *endptr = finfo->b_data+6;
- /* here we can deal with directory size, pass the leading white
- spaces and then the digits */
- while(ISSPACE(*endptr))
- endptr++;
- while(ISDIGIT(*endptr))
- endptr++;
- if(*endptr != 0) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- else {
- parser->state.UNIX.main = PL_UNIX_FILETYPE;
- finfo->b_used = 0;
- }
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- break;
- }
- break;
- case PL_UNIX_FILETYPE:
- switch (c) {
- case '-':
- finfo->filetype = CURLFILETYPE_FILE;
- break;
- case 'd':
- finfo->filetype = CURLFILETYPE_DIRECTORY;
- break;
- case 'l':
- finfo->filetype = CURLFILETYPE_SYMLINK;
- break;
- case 'p':
- finfo->filetype = CURLFILETYPE_NAMEDPIPE;
- break;
- case 's':
- finfo->filetype = CURLFILETYPE_SOCKET;
- break;
- case 'c':
- finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
- break;
- case 'b':
- finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
- break;
- case 'D':
- finfo->filetype = CURLFILETYPE_DOOR;
- break;
- default:
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- parser->state.UNIX.main = PL_UNIX_PERMISSION;
- parser->item_length = 0;
- parser->item_offset = 1;
- break;
- case PL_UNIX_PERMISSION:
- parser->item_length++;
- if(parser->item_length <= 9) {
- if(!strchr("rwx-tTsS", c)) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- else if(parser->item_length == 10) {
- unsigned int perm;
- if(c != ' ') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- finfo->b_data[10] = 0; /* terminate permissions */
- perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
- if(perm & FTP_LP_MALFORMATED_PERM) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM;
- parser->file_data->perm = perm;
- parser->offsets.perm = parser->item_offset;
- parser->item_length = 0;
- parser->state.UNIX.main = PL_UNIX_HLINKS;
- parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
- }
- break;
- case PL_UNIX_HLINKS:
- switch(parser->state.UNIX.sub.hlinks) {
- case PL_UNIX_HLINKS_PRESPACE:
- if(c != ' ') {
- if(c >= '0' && c <= '9') {
- parser->item_offset = finfo->b_used - 1;
- parser->item_length = 1;
- parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- break;
- case PL_UNIX_HLINKS_NUMBER:
- parser->item_length ++;
- if(c == ' ') {
- char *p;
- long int hlinks;
- finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
- hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
- if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
- parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
- parser->file_data->hardlinks = hlinks;
- }
- parser->item_length = 0;
- parser->item_offset = 0;
- parser->state.UNIX.main = PL_UNIX_USER;
- parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
- }
- else if(c < '0' || c > '9') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- }
- break;
- case PL_UNIX_USER:
- switch(parser->state.UNIX.sub.user) {
- case PL_UNIX_USER_PRESPACE:
- if(c != ' ') {
- parser->item_offset = finfo->b_used - 1;
- parser->item_length = 1;
- parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
- }
- break;
- case PL_UNIX_USER_PARSING:
- parser->item_length++;
- if(c == ' ') {
- finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
- parser->offsets.user = parser->item_offset;
- parser->state.UNIX.main = PL_UNIX_GROUP;
- parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
- parser->item_offset = 0;
- parser->item_length = 0;
- }
- break;
- }
- break;
- case PL_UNIX_GROUP:
- switch(parser->state.UNIX.sub.group) {
- case PL_UNIX_GROUP_PRESPACE:
- if(c != ' ') {
- parser->item_offset = finfo->b_used - 1;
- parser->item_length = 1;
- parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
- }
- break;
- case PL_UNIX_GROUP_NAME:
- parser->item_length++;
- if(c == ' ') {
- finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
- parser->offsets.group = parser->item_offset;
- parser->state.UNIX.main = PL_UNIX_SIZE;
- parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
- parser->item_offset = 0;
- parser->item_length = 0;
- }
- break;
- }
- break;
- case PL_UNIX_SIZE:
- switch(parser->state.UNIX.sub.size) {
- case PL_UNIX_SIZE_PRESPACE:
- if(c != ' ') {
- if(c >= '0' && c <= '9') {
- parser->item_offset = finfo->b_used - 1;
- parser->item_length = 1;
- parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- break;
- case PL_UNIX_SIZE_NUMBER:
- parser->item_length++;
- if(c == ' ') {
- char *p;
- curl_off_t fsize;
- finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
- fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
- if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
- fsize != CURL_OFF_T_MIN) {
- parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
- parser->file_data->size = fsize;
- }
- parser->item_length = 0;
- parser->item_offset = 0;
- parser->state.UNIX.main = PL_UNIX_TIME;
- parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
- }
- else if(!ISDIGIT(c)) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- }
- break;
- case PL_UNIX_TIME:
- switch(parser->state.UNIX.sub.time) {
- case PL_UNIX_TIME_PREPART1:
- if(c != ' ') {
- if(ISALNUM(c)) {
- parser->item_offset = finfo->b_used -1;
- parser->item_length = 1;
- parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- break;
- case PL_UNIX_TIME_PART1:
- parser->item_length++;
- if(c == ' ') {
- parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
- }
- else if(!ISALNUM(c) && c != '.') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- case PL_UNIX_TIME_PREPART2:
- parser->item_length++;
- if(c != ' ') {
- if(ISALNUM(c)) {
- parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- break;
- case PL_UNIX_TIME_PART2:
- parser->item_length++;
- if(c == ' ') {
- parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
- }
- else if(!ISALNUM(c) && c != '.') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- case PL_UNIX_TIME_PREPART3:
- parser->item_length++;
- if(c != ' ') {
- if(ISALNUM(c)) {
- parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- break;
- case PL_UNIX_TIME_PART3:
- parser->item_length++;
- if(c == ' ') {
- finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
- parser->offsets.time = parser->item_offset;
- if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
- parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
- }
- if(finfo->filetype == CURLFILETYPE_SYMLINK) {
- parser->state.UNIX.main = PL_UNIX_SYMLINK;
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
- }
- else {
- parser->state.UNIX.main = PL_UNIX_FILENAME;
- parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
- }
- }
- else if(!ISALNUM(c) && c != '.' && c != ':') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- }
- break;
- case PL_UNIX_FILENAME:
- switch(parser->state.UNIX.sub.filename) {
- case PL_UNIX_FILENAME_PRESPACE:
- if(c != ' ') {
- parser->item_offset = finfo->b_used - 1;
- parser->item_length = 1;
- parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
- }
- break;
- case PL_UNIX_FILENAME_NAME:
- parser->item_length++;
- if(c == '\r') {
- parser->item_length--;
- parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
- }
- else if(c == '\n') {
- finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
- parser->offsets.filename = parser->item_offset;
- parser->state.UNIX.main = PL_UNIX_FILETYPE;
- result = ftp_pl_insert_finfo(conn, finfo);
- if(result) {
- PL_ERROR(conn, result);
- return bufflen;
- }
- }
- break;
- case PL_UNIX_FILENAME_WINDOWSEOL:
- if(c == '\n') {
- finfo->b_data[parser->item_offset + parser->item_length] = 0;
- parser->offsets.filename = parser->item_offset;
- parser->state.UNIX.main = PL_UNIX_FILETYPE;
- result = ftp_pl_insert_finfo(conn, finfo);
- if(result) {
- PL_ERROR(conn, result);
- return bufflen;
- }
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- }
- break;
- case PL_UNIX_SYMLINK:
- switch(parser->state.UNIX.sub.symlink) {
- case PL_UNIX_SYMLINK_PRESPACE:
- if(c != ' ') {
- parser->item_offset = finfo->b_used - 1;
- parser->item_length = 1;
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
- }
- break;
- case PL_UNIX_SYMLINK_NAME:
- parser->item_length++;
- if(c == ' ') {
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
- }
- else if(c == '\r' || c == '\n') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- case PL_UNIX_SYMLINK_PRETARGET1:
- parser->item_length++;
- if(c == '-') {
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
- }
- else if(c == '\r' || c == '\n') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- else {
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
- }
- break;
- case PL_UNIX_SYMLINK_PRETARGET2:
- parser->item_length++;
- if(c == '>') {
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
- }
- else if(c == '\r' || c == '\n') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- else {
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
- }
- break;
- case PL_UNIX_SYMLINK_PRETARGET3:
- parser->item_length++;
- if(c == ' ') {
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
- /* now place where is symlink following */
- finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
- parser->offsets.filename = parser->item_offset;
- parser->item_length = 0;
- parser->item_offset = 0;
- }
- else if(c == '\r' || c == '\n') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- else {
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
- }
- break;
- case PL_UNIX_SYMLINK_PRETARGET4:
- if(c != '\r' && c != '\n') {
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
- parser->item_offset = finfo->b_used - 1;
- parser->item_length = 1;
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- case PL_UNIX_SYMLINK_TARGET:
- parser->item_length ++;
- if(c == '\r') {
- parser->item_length --;
- parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
- }
- else if(c == '\n') {
- finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
- parser->offsets.symlink_target = parser->item_offset;
- result = ftp_pl_insert_finfo(conn, finfo);
- if(result) {
- PL_ERROR(conn, result);
- return bufflen;
- }
- parser->state.UNIX.main = PL_UNIX_FILETYPE;
- }
- break;
- case PL_UNIX_SYMLINK_WINDOWSEOL:
- if(c == '\n') {
- finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
- parser->offsets.symlink_target = parser->item_offset;
- result = ftp_pl_insert_finfo(conn, finfo);
- if(result) {
- PL_ERROR(conn, result);
- return bufflen;
- }
- parser->state.UNIX.main = PL_UNIX_FILETYPE;
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- }
- break;
- }
- break;
- case OS_TYPE_WIN_NT:
- switch(parser->state.NT.main) {
- case PL_WINNT_DATE:
- parser->item_length++;
- if(parser->item_length < 9) {
- if(!strchr("0123456789-", c)) { /* only simple control */
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- else if(parser->item_length == 9) {
- if(c == ' ') {
- parser->state.NT.main = PL_WINNT_TIME;
- parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- case PL_WINNT_TIME:
- parser->item_length++;
- switch(parser->state.NT.sub.time) {
- case PL_WINNT_TIME_PRESPACE:
- if(!ISSPACE(c)) {
- parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
- }
- break;
- case PL_WINNT_TIME_TIME:
- if(c == ' ') {
- parser->offsets.time = parser->item_offset;
- finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
- parser->state.NT.main = PL_WINNT_DIRORSIZE;
- parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
- parser->item_length = 0;
- }
- else if(!strchr("APM0123456789:", c)) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- }
- break;
- case PL_WINNT_DIRORSIZE:
- switch(parser->state.NT.sub.dirorsize) {
- case PL_WINNT_DIRORSIZE_PRESPACE:
- if(c == ' ') {
- }
- else {
- parser->item_offset = finfo->b_used - 1;
- parser->item_length = 1;
- parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
- }
- break;
- case PL_WINNT_DIRORSIZE_CONTENT:
- parser->item_length ++;
- if(c == ' ') {
- finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
- if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
- finfo->filetype = CURLFILETYPE_DIRECTORY;
- finfo->size = 0;
- }
- else {
- char *endptr;
- finfo->size = curlx_strtoofft(finfo->b_data +
- parser->item_offset,
- &endptr, 10);
- if(!*endptr) {
- if(finfo->size == CURL_OFF_T_MAX ||
- finfo->size == CURL_OFF_T_MIN) {
- if(errno == ERANGE) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- /* correct file type */
- parser->file_data->filetype = CURLFILETYPE_FILE;
- }
- parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
- parser->item_length = 0;
- parser->state.NT.main = PL_WINNT_FILENAME;
- parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
- }
- break;
- }
- break;
- case PL_WINNT_FILENAME:
- switch (parser->state.NT.sub.filename) {
- case PL_WINNT_FILENAME_PRESPACE:
- if(c != ' ') {
- parser->item_offset = finfo->b_used -1;
- parser->item_length = 1;
- parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
- }
- break;
- case PL_WINNT_FILENAME_CONTENT:
- parser->item_length++;
- if(c == '\r') {
- parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
- finfo->b_data[finfo->b_used - 1] = 0;
- }
- else if(c == '\n') {
- parser->offsets.filename = parser->item_offset;
- finfo->b_data[finfo->b_used - 1] = 0;
- parser->offsets.filename = parser->item_offset;
- result = ftp_pl_insert_finfo(conn, finfo);
- if(result) {
- PL_ERROR(conn, result);
- return bufflen;
- }
- parser->state.NT.main = PL_WINNT_DATE;
- parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
- }
- break;
- case PL_WINNT_FILENAME_WINEOL:
- if(c == '\n') {
- parser->offsets.filename = parser->item_offset;
- result = ftp_pl_insert_finfo(conn, finfo);
- if(result) {
- PL_ERROR(conn, result);
- return bufflen;
- }
- parser->state.NT.main = PL_WINNT_DATE;
- parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- break;
- }
- break;
- }
- break;
- default:
- return bufflen + 1;
- }
- i++;
- }
- return bufflen;
- }
- #endif /* CURL_DISABLE_FTP */
|