From: Daniel Stenberg Date: Mon, 19 May 2025 08:31:24 +0000 (+0200) Subject: ftplistparser: split up into more functions X-Git-Tag: curl-8_14_0~56 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e83e8c30a88c5e48d07c37eda96bc24d0fd06357;p=thirdparty%2Fcurl.git ftplistparser: split up into more functions And some general cleanups Closes #17384 --- diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c index f15759fb2b..f416308e16 100644 --- a/lib/ftplistparser.c +++ b/lib/ftplistparser.c @@ -363,6 +363,571 @@ static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data, #define MAX_FTPLIST_BUFFER 10000 /* arbitrarily set */ +static CURLcode unix_filetype(const char c, curlfiletype *t) +{ + switch(c) { + case '-': + *t = CURLFILETYPE_FILE; + break; + case 'd': + *t = CURLFILETYPE_DIRECTORY; + break; + case 'l': + *t = CURLFILETYPE_SYMLINK; + break; + case 'p': + *t = CURLFILETYPE_NAMEDPIPE; + break; + case 's': + *t = CURLFILETYPE_SOCKET; + break; + case 'c': + *t = CURLFILETYPE_DEVICE_CHAR; + break; + case 'b': + *t = CURLFILETYPE_DEVICE_BLOCK; + break; + case 'D': + *t = CURLFILETYPE_DOOR; + break; + default: + return CURLE_FTP_BAD_FILE_LIST; + } + return CURLE_OK; +} + +static CURLcode parse_unix(struct Curl_easy *data, + struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + struct curl_fileinfo *finfo = &infop->info; + size_t len = curlx_dyn_len(&infop->buf); + char *mem = curlx_dyn_ptr(&infop->buf); + CURLcode result = CURLE_OK; + + 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; + /* continue to fall through */ + } + break; + case PL_UNIX_TOTALSIZE_READING: + parser->item_length++; + if(c == '\r') { + parser->item_length--; + curlx_dyn_setlen(&infop->buf, --len); + } + else if(c == '\n') { + mem[parser->item_length - 1] = 0; + if(!strncmp("total ", mem, 6)) { + const char *endptr = mem + 6; + /* here we can deal with directory size, pass the leading + whitespace and then the digits */ + curlx_str_passblanks(&endptr); + while(ISDIGIT(*endptr)) + endptr++; + if(*endptr) { + return CURLE_FTP_BAD_FILE_LIST; + } + parser->state.UNIX.main = PL_UNIX_FILETYPE; + curlx_dyn_reset(&infop->buf); + } + else + return CURLE_FTP_BAD_FILE_LIST; + + } + break; + } + if(parser->state.UNIX.main != PL_UNIX_FILETYPE) + break; + FALLTHROUGH(); + case PL_UNIX_FILETYPE: + result = unix_filetype(c, &finfo->filetype); + if(result) + return result; + 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) && !strchr("rwx-tTsS", c)) + return CURLE_FTP_BAD_FILE_LIST; + + else if(parser->item_length == 10) { + unsigned int perm; + if(c != ' ') + return CURLE_FTP_BAD_FILE_LIST; + + mem[10] = 0; /* terminate permissions */ + perm = ftp_pl_get_permission(mem + parser->item_offset); + if(perm & FTP_LP_MALFORMATED_PERM) + return CURLE_FTP_BAD_FILE_LIST; + + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM; + parser->file_data->info.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(ISDIGIT(c)) { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER; + } + else + return CURLE_FTP_BAD_FILE_LIST; + } + break; + case PL_UNIX_HLINKS_NUMBER: + parser->item_length ++; + if(c == ' ') { + const char *p = &mem[parser->item_offset]; + curl_off_t hlinks; + mem[parser->item_offset + parser->item_length - 1] = 0; + + if(!curlx_str_number(&p, &hlinks, LONG_MAX)) { + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT; + parser->file_data->info.hardlinks = (long)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(!ISDIGIT(c)) + return CURLE_FTP_BAD_FILE_LIST; + + break; + } + break; + case PL_UNIX_USER: + switch(parser->state.UNIX.sub.user) { + case PL_UNIX_USER_PRESPACE: + if(c != ' ') { + parser->item_offset = len - 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 == ' ') { + mem[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 = len - 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 == ' ') { + mem[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(ISDIGIT(c)) { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER; + } + else + return CURLE_FTP_BAD_FILE_LIST; + } + break; + case PL_UNIX_SIZE_NUMBER: + parser->item_length++; + if(c == ' ') { + const char *p = mem + parser->item_offset; + curl_off_t fsize; + mem[parser->item_offset + parser->item_length - 1] = 0; + if(!curlx_str_numblanks(&p, &fsize)) { + if(p[0] == '\0' && fsize != CURL_OFF_T_MAX) { + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; + parser->file_data->info.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)) + return CURLE_FTP_BAD_FILE_LIST; + + 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 = len -1; + parser->item_length = 1; + parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1; + } + else + return CURLE_FTP_BAD_FILE_LIST; + } + 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 != '.') + return CURLE_FTP_BAD_FILE_LIST; + + break; + case PL_UNIX_TIME_PREPART2: + parser->item_length++; + if(c != ' ') { + if(ISALNUM(c)) + parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2; + else + return CURLE_FTP_BAD_FILE_LIST; + } + 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 != '.') + return CURLE_FTP_BAD_FILE_LIST; + break; + case PL_UNIX_TIME_PREPART3: + parser->item_length++; + if(c != ' ') { + if(ISALNUM(c)) + parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3; + else + return CURLE_FTP_BAD_FILE_LIST; + } + break; + case PL_UNIX_TIME_PART3: + parser->item_length++; + if(c == ' ') { + mem[parser->item_offset + parser->item_length -1] = 0; + parser->offsets.time = parser->item_offset; + 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 != ':') + return CURLE_FTP_BAD_FILE_LIST; + break; + } + break; + case PL_UNIX_FILENAME: + switch(parser->state.UNIX.sub.filename) { + case PL_UNIX_FILENAME_PRESPACE: + if(c != ' ') { + parser->item_offset = len - 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->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; + + else if(c == '\n') { + mem[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(data, infop); + if(result) + return result; + } + break; + case PL_UNIX_FILENAME_WINDOWSEOL: + if(c == '\n') { + mem[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(data, infop); + if(result) + return result; + } + else + return CURLE_FTP_BAD_FILE_LIST; + + break; + } + break; + case PL_UNIX_SYMLINK: + switch(parser->state.UNIX.sub.symlink) { + case PL_UNIX_SYMLINK_PRESPACE: + if(c != ' ') { + parser->item_offset = len - 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') + return CURLE_FTP_BAD_FILE_LIST; + + 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') + return CURLE_FTP_BAD_FILE_LIST; + 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') + return CURLE_FTP_BAD_FILE_LIST; + 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 */ + mem[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') + return CURLE_FTP_BAD_FILE_LIST; + 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 = len - 1; + parser->item_length = 1; + } + else + return CURLE_FTP_BAD_FILE_LIST; + + break; + case PL_UNIX_SYMLINK_TARGET: + parser->item_length++; + if(c == '\r') + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; + + else if(c == '\n') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.symlink_target = parser->item_offset; + result = ftp_pl_insert_finfo(data, infop); + if(result) + return result; + + parser->state.UNIX.main = PL_UNIX_FILETYPE; + } + break; + case PL_UNIX_SYMLINK_WINDOWSEOL: + if(c == '\n') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.symlink_target = parser->item_offset; + result = ftp_pl_insert_finfo(data, infop); + if(result) + return result; + + parser->state.UNIX.main = PL_UNIX_FILETYPE; + } + else + return CURLE_FTP_BAD_FILE_LIST; + + break; + } + break; + } + return CURLE_OK; +} + +static CURLcode parse_winnt(struct Curl_easy *data, + struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + struct curl_fileinfo *finfo = &infop->info; + size_t len = curlx_dyn_len(&infop->buf); + char *mem = curlx_dyn_ptr(&infop->buf); + CURLcode result = CURLE_OK; + + switch(parser->state.NT.main) { + case PL_WINNT_DATE: + parser->item_length++; + if(parser->item_length < 9) { + if(!strchr("0123456789-", c)) { /* only simple control */ + return CURLE_FTP_BAD_FILE_LIST; + } + } + 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 + return CURLE_FTP_BAD_FILE_LIST; + } + else + return CURLE_FTP_BAD_FILE_LIST; + break; + case PL_WINNT_TIME: + parser->item_length++; + switch(parser->state.NT.sub.time) { + case PL_WINNT_TIME_PRESPACE: + if(!ISBLANK(c)) + parser->state.NT.sub.time = PL_WINNT_TIME_TIME; + break; + case PL_WINNT_TIME_TIME: + if(c == ' ') { + parser->offsets.time = parser->item_offset; + mem[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)) + return CURLE_FTP_BAD_FILE_LIST; + break; + } + break; + case PL_WINNT_DIRORSIZE: + switch(parser->state.NT.sub.dirorsize) { + case PL_WINNT_DIRORSIZE_PRESPACE: + if(c != ' ') { + parser->item_offset = len - 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 == ' ') { + mem[parser->item_offset + parser->item_length - 1] = 0; + if(strcmp("", mem + parser->item_offset) == 0) { + finfo->filetype = CURLFILETYPE_DIRECTORY; + finfo->size = 0; + } + else { + const char *p = mem + parser->item_offset; + if(curlx_str_numblanks(&p, &finfo->size)) { + return CURLE_FTP_BAD_FILE_LIST; + } + /* correct file type */ + parser->file_data->info.filetype = CURLFILETYPE_FILE; + } + + parser->file_data->info.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 = len -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; + mem[len - 1] = 0; + } + else if(c == '\n') { + parser->offsets.filename = parser->item_offset; + mem[len - 1] = 0; + result = ftp_pl_insert_finfo(data, infop); + if(result) + return result; + + 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(data, infop); + if(result) + return result; + + parser->state.NT.main = PL_WINNT_DATE; + parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; + } + else + return CURLE_FTP_BAD_FILE_LIST; + + break; + } + break; + } + + return CURLE_OK; +} + size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr) { @@ -390,11 +955,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } while(i < bufflen) { /* FSM */ - char *mem; - size_t len; /* number of bytes of data in the dynbuf */ char c = buffer[i]; struct fileinfo *infop; - struct curl_fileinfo *finfo; if(!parser->file_data) { /* tmp file data is not allocated yet */ parser->file_data = Curl_fileinfo_alloc(); if(!parser->file_data) { @@ -407,618 +969,27 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } infop = parser->file_data; - finfo = &infop->info; if(curlx_dyn_addn(&infop->buf, &c, 1)) { parser->error = CURLE_OUT_OF_MEMORY; goto fail; } - len = curlx_dyn_len(&infop->buf); - mem = curlx_dyn_ptr(&infop->buf); 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 */ - curlx_dyn_reset(&infop->buf); - continue; - } - break; - case PL_UNIX_TOTALSIZE_READING: - parser->item_length++; - if(c == '\r') { - parser->item_length--; - curlx_dyn_setlen(&infop->buf, --len); - } - else if(c == '\n') { - mem[parser->item_length - 1] = 0; - if(!strncmp("total ", mem, 6)) { - const char *endptr = mem + 6; - /* here we can deal with directory size, pass the leading - whitespace and then the digits */ - curlx_str_passblanks(&endptr); - while(ISDIGIT(*endptr)) - endptr++; - if(*endptr) { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - parser->state.UNIX.main = PL_UNIX_FILETYPE; - curlx_dyn_reset(&infop->buf); - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - } - 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: - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - 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)) { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - } - else if(parser->item_length == 10) { - unsigned int perm; - if(c != ' ') { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - mem[10] = 0; /* terminate permissions */ - perm = ftp_pl_get_permission(mem + parser->item_offset); - if(perm & FTP_LP_MALFORMATED_PERM) { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM; - parser->file_data->info.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(ISDIGIT(c)) { - parser->item_offset = len - 1; - parser->item_length = 1; - parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER; - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - } - break; - case PL_UNIX_HLINKS_NUMBER: - parser->item_length ++; - if(c == ' ') { - const char *p = &mem[parser->item_offset]; - curl_off_t hlinks; - mem[parser->item_offset + parser->item_length - 1] = 0; - - if(!curlx_str_number(&p, &hlinks, LONG_MAX)) { - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT; - parser->file_data->info.hardlinks = (long)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(!ISDIGIT(c)) { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - break; - } - break; - case PL_UNIX_USER: - switch(parser->state.UNIX.sub.user) { - case PL_UNIX_USER_PRESPACE: - if(c != ' ') { - parser->item_offset = len - 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 == ' ') { - mem[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 = len - 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 == ' ') { - mem[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(ISDIGIT(c)) { - parser->item_offset = len - 1; - parser->item_length = 1; - parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER; - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - } - break; - case PL_UNIX_SIZE_NUMBER: - parser->item_length++; - if(c == ' ') { - const char *p = mem + parser->item_offset; - curl_off_t fsize; - mem[parser->item_offset + parser->item_length - 1] = 0; - if(!curlx_str_numblanks(&p, &fsize)) { - if(p[0] == '\0' && fsize != CURL_OFF_T_MAX) { - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; - parser->file_data->info.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)) { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - 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 = len -1; - parser->item_length = 1; - parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1; - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - } - 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 != '.') { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - break; - case PL_UNIX_TIME_PREPART2: - parser->item_length++; - if(c != ' ') { - if(ISALNUM(c)) { - parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2; - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - } - 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 != '.') { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - break; - case PL_UNIX_TIME_PREPART3: - parser->item_length++; - if(c != ' ') { - if(ISALNUM(c)) { - parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3; - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - } - break; - case PL_UNIX_TIME_PART3: - parser->item_length++; - if(c == ' ') { - mem[parser->item_offset + parser->item_length -1] = 0; - parser->offsets.time = parser->item_offset; - /* - if(ftp_pl_gettime(parser, finfo->mem + 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 != ':') { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - break; - } - break; - case PL_UNIX_FILENAME: - switch(parser->state.UNIX.sub.filename) { - case PL_UNIX_FILENAME_PRESPACE: - if(c != ' ') { - parser->item_offset = len - 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->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; - } - else if(c == '\n') { - mem[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(data, infop); - if(result) { - parser->error = result; - goto fail; - } - } - break; - case PL_UNIX_FILENAME_WINDOWSEOL: - if(c == '\n') { - mem[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(data, infop); - if(result) { - parser->error = result; - goto fail; - } - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - break; - } - break; - case PL_UNIX_SYMLINK: - switch(parser->state.UNIX.sub.symlink) { - case PL_UNIX_SYMLINK_PRESPACE: - if(c != ' ') { - parser->item_offset = len - 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') { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - 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') { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - 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') { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - 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 */ - mem[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') { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - 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 = len - 1; - parser->item_length = 1; - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - break; - case PL_UNIX_SYMLINK_TARGET: - parser->item_length++; - if(c == '\r') { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; - } - else if(c == '\n') { - mem[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.symlink_target = parser->item_offset; - result = ftp_pl_insert_finfo(data, infop); - if(result) { - parser->error = result; - goto fail; - } - parser->state.UNIX.main = PL_UNIX_FILETYPE; - } - break; - case PL_UNIX_SYMLINK_WINDOWSEOL: - if(c == '\n') { - mem[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.symlink_target = parser->item_offset; - result = ftp_pl_insert_finfo(data, infop); - if(result) { - parser->error = result; - goto fail; - } - parser->state.UNIX.main = PL_UNIX_FILETYPE; - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - break; - } - break; - } + result = parse_unix(data, parser, infop, c); 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 */ - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - } - 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 { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - break; - case PL_WINNT_TIME: - parser->item_length++; - switch(parser->state.NT.sub.time) { - case PL_WINNT_TIME_PRESPACE: - if(!ISBLANK(c)) { - parser->state.NT.sub.time = PL_WINNT_TIME_TIME; - } - break; - case PL_WINNT_TIME_TIME: - if(c == ' ') { - parser->offsets.time = parser->item_offset; - mem[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)) { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - break; - } - break; - case PL_WINNT_DIRORSIZE: - switch(parser->state.NT.sub.dirorsize) { - case PL_WINNT_DIRORSIZE_PRESPACE: - if(c != ' ') { - parser->item_offset = len - 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 == ' ') { - mem[parser->item_offset + parser->item_length - 1] = 0; - if(strcmp("", mem + parser->item_offset) == 0) { - finfo->filetype = CURLFILETYPE_DIRECTORY; - finfo->size = 0; - } - else { - const char *p = mem + parser->item_offset; - if(curlx_str_numblanks(&p, &finfo->size)) { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - /* correct file type */ - parser->file_data->info.filetype = CURLFILETYPE_FILE; - } - - parser->file_data->info.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 = len -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; - mem[len - 1] = 0; - } - else if(c == '\n') { - parser->offsets.filename = parser->item_offset; - mem[len - 1] = 0; - result = ftp_pl_insert_finfo(data, infop); - if(result) { - parser->error = result; - goto fail; - } - 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(data, infop); - if(result) { - parser->error = result; - goto fail; - } - parser->state.NT.main = PL_WINNT_DATE; - parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; - } - else { - parser->error = CURLE_FTP_BAD_FILE_LIST; - goto fail; - } - break; - } - break; - } + result = parse_winnt(data, parser, infop, c); break; default: retsize = bufflen + 1; goto fail; } + if(result) { + parser->error = result; + goto fail; + } i++; }