ftplistparser: split parse_unix into sub functions

Closes #17608
This commit is contained in:
Daniel Stenberg 2025-06-12 13:42:28 +02:00
parent 4a686ee6b0
commit 3b4e84c44f
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -396,407 +396,500 @@ static CURLcode unix_filetype(const char c, curlfiletype *t)
return CURLE_OK;
}
static CURLcode parse_unix_totalsize(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
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--;
if(len)
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;
}
return CURLE_OK;
}
static CURLcode parse_unix_permission(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
char *mem = curlx_dyn_ptr(&infop->buf);
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;
}
return CURLE_OK;
}
static CURLcode parse_unix_hlinks(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
switch(parser->state.UNIX.sub.hlinks) {
case PL_UNIX_HLINKS_PRESPACE:
if(c != ' ') {
if(ISDIGIT(c) && len) {
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;
}
return CURLE_OK;
}
static CURLcode parse_unix_user(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
switch(parser->state.UNIX.sub.user) {
case PL_UNIX_USER_PRESPACE:
if(c != ' ' && len) {
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;
}
return CURLE_OK;
}
static CURLcode parse_unix_group(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
switch(parser->state.UNIX.sub.group) {
case PL_UNIX_GROUP_PRESPACE:
if(c != ' ' && len) {
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;
}
return CURLE_OK;
}
static CURLcode parse_unix_size(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
switch(parser->state.UNIX.sub.size) {
case PL_UNIX_SIZE_PRESPACE:
if(c != ' ') {
if(ISDIGIT(c) && len) {
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;
}
return CURLE_OK;
}
static CURLcode parse_unix_time(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
struct curl_fileinfo *finfo = &infop->info;
switch(parser->state.UNIX.sub.time) {
case PL_UNIX_TIME_PREPART1:
if(c != ' ') {
if(ISALNUM(c) && len) {
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;
}
return CURLE_OK;
}
static CURLcode parse_unix_filename(struct Curl_easy *data,
struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
CURLcode result = CURLE_OK;
switch(parser->state.UNIX.sub.filename) {
case PL_UNIX_FILENAME_PRESPACE:
if(c != ' ' && len) {
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);
}
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);
}
else
result = CURLE_FTP_BAD_FILE_LIST;
break;
}
return result;
}
static CURLcode parse_unix_symlink(struct Curl_easy *data,
struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
CURLcode result = CURLE_OK;
switch(parser->state.UNIX.sub.symlink) {
case PL_UNIX_SYMLINK_PRESPACE:
if(c != ' ' && len) {
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' && len) {
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)
break;
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)
break;
parser->state.UNIX.main = PL_UNIX_FILETYPE;
}
else
result = CURLE_FTP_BAD_FILE_LIST;
break;
}
return result;
}
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 */
}
result = parse_unix_totalsize(parser, infop, c);
if(result)
break;
case PL_UNIX_TOTALSIZE_READING:
parser->item_length++;
if(c == '\r') {
parser->item_length--;
if(len)
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;
if(!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;
}
result = parse_unix_permission(parser, infop, c);
break;
case PL_UNIX_HLINKS:
switch(parser->state.UNIX.sub.hlinks) {
case PL_UNIX_HLINKS_PRESPACE:
if(c != ' ') {
if(ISDIGIT(c) && len) {
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;
}
result = parse_unix_hlinks(parser, infop, c);
break;
case PL_UNIX_USER:
switch(parser->state.UNIX.sub.user) {
case PL_UNIX_USER_PRESPACE:
if(c != ' ' && len) {
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;
}
result = parse_unix_user(parser, infop, c);
break;
case PL_UNIX_GROUP:
switch(parser->state.UNIX.sub.group) {
case PL_UNIX_GROUP_PRESPACE:
if(c != ' ' && len) {
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;
}
result = parse_unix_group(parser, infop, c);
break;
case PL_UNIX_SIZE:
switch(parser->state.UNIX.sub.size) {
case PL_UNIX_SIZE_PRESPACE:
if(c != ' ') {
if(ISDIGIT(c) && len) {
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;
}
result = parse_unix_size(parser, infop, c);
break;
case PL_UNIX_TIME:
switch(parser->state.UNIX.sub.time) {
case PL_UNIX_TIME_PREPART1:
if(c != ' ') {
if(ISALNUM(c) && len) {
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;
}
result = parse_unix_time(parser, infop, c);
break;
case PL_UNIX_FILENAME:
switch(parser->state.UNIX.sub.filename) {
case PL_UNIX_FILENAME_PRESPACE:
if(c != ' ' && len) {
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;
}
result = parse_unix_filename(data, parser, infop, c);
break;
case PL_UNIX_SYMLINK:
switch(parser->state.UNIX.sub.symlink) {
case PL_UNIX_SYMLINK_PRESPACE:
if(c != ' ' && len) {
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' && len) {
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;
}
result = parse_unix_symlink(data, parser, infop, c);
break;
}
return CURLE_OK;
return result;
}
static CURLcode parse_winnt(struct Curl_easy *data,