| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091 |
- /***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <[email protected]>, 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 https://curl.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.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
- #include "curl_setup.h"
- #ifndef CURL_DISABLE_FTP
- /**
- * 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 "urldata.h"
- #include "fileinfo.h"
- #include "llist.h"
- #include "ftp.h"
- #include "ftplistparser.h"
- #include "curl_fnmatch.h"
- #include "multiif.h"
- #include "curlx/strparse.h"
- 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 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;
- };
- static void fileinfo_dtor(void *user, void *element)
- {
- (void)user;
- Curl_fileinfo_cleanup(element);
- }
- void Curl_wildcard_init(struct WildcardData *wc)
- {
- Curl_llist_init(&wc->filelist, fileinfo_dtor);
- wc->state = CURLWC_INIT;
- }
- void Curl_wildcard_dtor(struct WildcardData **wcp)
- {
- struct WildcardData *wc = *wcp;
- if(!wc)
- return;
- if(wc->dtor) {
- wc->dtor(wc->ftpwc);
- wc->dtor = ZERO_NULL;
- wc->ftpwc = NULL;
- }
- DEBUGASSERT(wc->ftpwc == NULL);
- Curl_llist_destroy(&wc->filelist, NULL);
- curlx_free(wc->path);
- wc->path = NULL;
- curlx_free(wc->pattern);
- wc->pattern = NULL;
- wc->state = CURLWC_INIT;
- curlx_free(wc);
- *wcp = NULL;
- }
- struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
- {
- return curlx_calloc(1, sizeof(struct ftp_parselist_data));
- }
- void Curl_ftp_parselist_data_free(struct ftp_parselist_data **parserp)
- {
- struct ftp_parselist_data *parser = *parserp;
- if(parser)
- Curl_fileinfo_cleanup(parser->file_data);
- curlx_free(parser);
- *parserp = NULL;
- }
- CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
- {
- return pl_data->error;
- }
- #define FTP_LP_MALFORMATED_PERM 0x01000000
- static unsigned int ftp_pl_get_permission(const char *str)
- {
- unsigned 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 CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
- struct fileinfo *infop)
- {
- curl_fnmatch_callback compare;
- struct WildcardData *wc = data->wildcard;
- struct ftp_wc *ftpwc = wc->ftpwc;
- struct Curl_llist *llist = &wc->filelist;
- struct ftp_parselist_data *parser = ftpwc->parser;
- bool add = TRUE;
- struct curl_fileinfo *finfo = &infop->info;
- /* set the finfo pointers */
- char *str = curlx_dyn_ptr(&infop->buf);
- 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 = data->set.fnmatch;
- if(!compare)
- compare = Curl_fnmatch;
- /* filter pattern-corresponding filenames */
- Curl_set_in_callback(data, TRUE);
- if(compare(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;
- }
- Curl_set_in_callback(data, FALSE);
- if(add) {
- Curl_llist_append(llist, finfo, &infop->list);
- }
- else {
- Curl_fileinfo_cleanup(infop);
- }
- ftpwc->parser->file_data = NULL;
- return CURLE_OK;
- }
- #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_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;
- CURLcode result = CURLE_OK;
- switch(parser->state.UNIX.main) {
- case PL_UNIX_TOTALSIZE:
- result = parse_unix_totalsize(parser, infop, c);
- if(result)
- break;
- if(parser->state.UNIX.main != PL_UNIX_FILETYPE)
- break;
- FALLTHROUGH();
- case PL_UNIX_FILETYPE:
- result = unix_filetype(c, &finfo->filetype);
- if(!result) {
- parser->state.UNIX.main = PL_UNIX_PERMISSION;
- parser->item_length = 0;
- parser->item_offset = 1;
- }
- break;
- case PL_UNIX_PERMISSION:
- result = parse_unix_permission(parser, infop, c);
- break;
- case PL_UNIX_HLINKS:
- result = parse_unix_hlinks(parser, infop, c);
- break;
- case PL_UNIX_USER:
- result = parse_unix_user(parser, infop, c);
- break;
- case PL_UNIX_GROUP:
- result = parse_unix_group(parser, infop, c);
- break;
- case PL_UNIX_SIZE:
- result = parse_unix_size(parser, infop, c);
- break;
- case PL_UNIX_TIME:
- result = parse_unix_time(parser, infop, c);
- break;
- case PL_UNIX_FILENAME:
- result = parse_unix_filename(data, parser, infop, c);
- break;
- case PL_UNIX_SYMLINK:
- result = parse_unix_symlink(data, parser, infop, c);
- break;
- }
- return result;
- }
- 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 != ' ' && len) {
- 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("<DIR>", 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 != ' ' && len) {
- 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(!len)
- return CURLE_FTP_BAD_FILE_LIST;
- 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)
- {
- size_t bufflen = size * nmemb;
- struct Curl_easy *data = (struct Curl_easy *)connptr;
- struct ftp_wc *ftpwc = data->wildcard->ftpwc;
- struct ftp_parselist_data *parser = ftpwc->parser;
- size_t i = 0;
- CURLcode result;
- size_t retsize = bufflen;
- 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 handled later
- * in wc_statemach()
- */
- goto fail;
- }
- if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
- /* considering info about FILE response format */
- parser->os_type = ISDIGIT(buffer[0]) ? OS_TYPE_WIN_NT : OS_TYPE_UNIX;
- }
- while(i < bufflen) { /* FSM */
- char c = buffer[i];
- struct fileinfo *infop;
- 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;
- goto fail;
- }
- parser->item_offset = 0;
- parser->item_length = 0;
- curlx_dyn_init(&parser->file_data->buf, MAX_FTPLIST_BUFFER);
- }
- infop = parser->file_data;
- if(curlx_dyn_addn(&infop->buf, &c, 1)) {
- parser->error = CURLE_OUT_OF_MEMORY;
- goto fail;
- }
- switch(parser->os_type) {
- case OS_TYPE_UNIX:
- result = parse_unix(data, parser, infop, c);
- break;
- case OS_TYPE_WIN_NT:
- result = parse_winnt(data, parser, infop, c);
- break;
- default:
- retsize = bufflen + 1;
- goto fail;
- }
- if(result) {
- parser->error = result;
- goto fail;
- }
- i++;
- }
- return retsize;
- fail:
- /* Clean up any allocated memory. */
- if(parser->file_data) {
- Curl_fileinfo_cleanup(parser->file_data);
- parser->file_data = NULL;
- }
- return retsize;
- }
- #endif /* !CURL_DISABLE_FTP */
|