ftplistparser.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00038 #include "curl_setup.h"
00039 
00040 #ifndef CURL_DISABLE_FTP
00041 
00042 #include <curl/curl.h>
00043 
00044 #include "urldata.h"
00045 #include "fileinfo.h"
00046 #include "llist.h"
00047 #include "strtoofft.h"
00048 #include "ftp.h"
00049 #include "ftplistparser.h"
00050 #include "curl_fnmatch.h"
00051 #include "curl_memory.h"
00052 /* The last #include file should be: */
00053 #include "memdebug.h"
00054 
00055 /* allocs buffer which will contain one line of LIST command response */
00056 #define FTP_BUFFER_ALLOCSIZE 160
00057 
00058 typedef enum {
00059   PL_UNIX_TOTALSIZE = 0,
00060   PL_UNIX_FILETYPE,
00061   PL_UNIX_PERMISSION,
00062   PL_UNIX_HLINKS,
00063   PL_UNIX_USER,
00064   PL_UNIX_GROUP,
00065   PL_UNIX_SIZE,
00066   PL_UNIX_TIME,
00067   PL_UNIX_FILENAME,
00068   PL_UNIX_SYMLINK
00069 } pl_unix_mainstate;
00070 
00071 typedef union {
00072   enum {
00073     PL_UNIX_TOTALSIZE_INIT = 0,
00074     PL_UNIX_TOTALSIZE_READING
00075   } total_dirsize;
00076 
00077   enum {
00078     PL_UNIX_HLINKS_PRESPACE = 0,
00079     PL_UNIX_HLINKS_NUMBER
00080   } hlinks;
00081 
00082   enum {
00083     PL_UNIX_USER_PRESPACE = 0,
00084     PL_UNIX_USER_PARSING
00085   } user;
00086 
00087   enum {
00088     PL_UNIX_GROUP_PRESPACE = 0,
00089     PL_UNIX_GROUP_NAME
00090   } group;
00091 
00092   enum {
00093     PL_UNIX_SIZE_PRESPACE = 0,
00094     PL_UNIX_SIZE_NUMBER
00095   } size;
00096 
00097   enum {
00098     PL_UNIX_TIME_PREPART1 = 0,
00099     PL_UNIX_TIME_PART1,
00100     PL_UNIX_TIME_PREPART2,
00101     PL_UNIX_TIME_PART2,
00102     PL_UNIX_TIME_PREPART3,
00103     PL_UNIX_TIME_PART3
00104   } time;
00105 
00106   enum {
00107     PL_UNIX_FILENAME_PRESPACE = 0,
00108     PL_UNIX_FILENAME_NAME,
00109     PL_UNIX_FILENAME_WINDOWSEOL
00110   } filename;
00111 
00112   enum {
00113     PL_UNIX_SYMLINK_PRESPACE = 0,
00114     PL_UNIX_SYMLINK_NAME,
00115     PL_UNIX_SYMLINK_PRETARGET1,
00116     PL_UNIX_SYMLINK_PRETARGET2,
00117     PL_UNIX_SYMLINK_PRETARGET3,
00118     PL_UNIX_SYMLINK_PRETARGET4,
00119     PL_UNIX_SYMLINK_TARGET,
00120     PL_UNIX_SYMLINK_WINDOWSEOL
00121   } symlink;
00122 } pl_unix_substate;
00123 
00124 typedef enum {
00125   PL_WINNT_DATE = 0,
00126   PL_WINNT_TIME,
00127   PL_WINNT_DIRORSIZE,
00128   PL_WINNT_FILENAME
00129 } pl_winNT_mainstate;
00130 
00131 typedef union {
00132   enum {
00133     PL_WINNT_TIME_PRESPACE = 0,
00134     PL_WINNT_TIME_TIME
00135   } time;
00136   enum {
00137     PL_WINNT_DIRORSIZE_PRESPACE = 0,
00138     PL_WINNT_DIRORSIZE_CONTENT
00139   } dirorsize;
00140   enum {
00141     PL_WINNT_FILENAME_PRESPACE = 0,
00142     PL_WINNT_FILENAME_CONTENT,
00143     PL_WINNT_FILENAME_WINEOL
00144   } filename;
00145 } pl_winNT_substate;
00146 
00147 /* This struct is used in wildcard downloading - for parsing LIST response */
00148 struct ftp_parselist_data {
00149   enum {
00150     OS_TYPE_UNKNOWN = 0,
00151     OS_TYPE_UNIX,
00152     OS_TYPE_WIN_NT
00153   } os_type;
00154 
00155   union {
00156     struct {
00157       pl_unix_mainstate main;
00158       pl_unix_substate sub;
00159     } UNIX;
00160 
00161     struct {
00162       pl_winNT_mainstate main;
00163       pl_winNT_substate sub;
00164     } NT;
00165   } state;
00166 
00167   CURLcode error;
00168   struct curl_fileinfo *file_data;
00169   unsigned int item_length;
00170   size_t item_offset;
00171   struct {
00172     size_t filename;
00173     size_t user;
00174     size_t group;
00175     size_t time;
00176     size_t perm;
00177     size_t symlink_target;
00178   } offsets;
00179 };
00180 
00181 struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
00182 {
00183   return calloc(1, sizeof(struct ftp_parselist_data));
00184 }
00185 
00186 
00187 void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
00188 {
00189   free(*pl_data);
00190   *pl_data = NULL;
00191 }
00192 
00193 
00194 CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
00195 {
00196   return pl_data->error;
00197 }
00198 
00199 
00200 #define FTP_LP_MALFORMATED_PERM 0x01000000
00201 
00202 static int ftp_pl_get_permission(const char *str)
00203 {
00204   int permissions = 0;
00205   /* USER */
00206   if(str[0] == 'r')
00207     permissions |= 1 << 8;
00208   else if(str[0] != '-')
00209     permissions |= FTP_LP_MALFORMATED_PERM;
00210   if(str[1] == 'w')
00211     permissions |= 1 << 7;
00212   else if(str[1] != '-')
00213     permissions |= FTP_LP_MALFORMATED_PERM;
00214 
00215   if(str[2] == 'x')
00216     permissions |= 1 << 6;
00217   else if(str[2] == 's') {
00218     permissions |= 1 << 6;
00219     permissions |= 1 << 11;
00220   }
00221   else if(str[2] == 'S')
00222     permissions |= 1 << 11;
00223   else if(str[2] != '-')
00224     permissions |= FTP_LP_MALFORMATED_PERM;
00225   /* GROUP */
00226   if(str[3] == 'r')
00227     permissions |= 1 << 5;
00228   else if(str[3] != '-')
00229     permissions |= FTP_LP_MALFORMATED_PERM;
00230   if(str[4] == 'w')
00231     permissions |= 1 << 4;
00232   else if(str[4] != '-')
00233     permissions |= FTP_LP_MALFORMATED_PERM;
00234   if(str[5] == 'x')
00235     permissions |= 1 << 3;
00236   else if(str[5] == 's') {
00237     permissions |= 1 << 3;
00238     permissions |= 1 << 10;
00239   }
00240   else if(str[5] == 'S')
00241     permissions |= 1 << 10;
00242   else if(str[5] != '-')
00243     permissions |= FTP_LP_MALFORMATED_PERM;
00244   /* others */
00245   if(str[6] == 'r')
00246     permissions |= 1 << 2;
00247   else if(str[6] != '-')
00248     permissions |= FTP_LP_MALFORMATED_PERM;
00249   if(str[7] == 'w')
00250     permissions |= 1 << 1;
00251   else if(str[7] != '-')
00252       permissions |= FTP_LP_MALFORMATED_PERM;
00253   if(str[8] == 'x')
00254     permissions |= 1;
00255   else if(str[8] == 't') {
00256     permissions |= 1;
00257     permissions |= 1 << 9;
00258   }
00259   else if(str[8] == 'T')
00260     permissions |= 1 << 9;
00261   else if(str[8] != '-')
00262     permissions |= FTP_LP_MALFORMATED_PERM;
00263 
00264   return permissions;
00265 }
00266 
00267 static void PL_ERROR(struct connectdata *conn, CURLcode err)
00268 {
00269   struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
00270   struct ftp_parselist_data *parser = tmpdata->parser;
00271   if(parser->file_data)
00272     Curl_fileinfo_dtor(NULL, parser->file_data);
00273   parser->file_data = NULL;
00274   parser->error = err;
00275 }
00276 
00277 static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
00278                                     struct curl_fileinfo *finfo)
00279 {
00280   curl_fnmatch_callback compare;
00281   struct WildcardData *wc = &conn->data->wildcard;
00282   struct ftp_wc_tmpdata *tmpdata = wc->tmp;
00283   struct curl_llist *llist = wc->filelist;
00284   struct ftp_parselist_data *parser = tmpdata->parser;
00285   bool add = TRUE;
00286 
00287   /* move finfo pointers to b_data */
00288   char *str = finfo->b_data;
00289   finfo->filename       = str + parser->offsets.filename;
00290   finfo->strings.group  = parser->offsets.group ?
00291                           str + parser->offsets.group : NULL;
00292   finfo->strings.perm   = parser->offsets.perm ?
00293                           str + parser->offsets.perm : NULL;
00294   finfo->strings.target = parser->offsets.symlink_target ?
00295                           str + parser->offsets.symlink_target : NULL;
00296   finfo->strings.time   = str + parser->offsets.time;
00297   finfo->strings.user   = parser->offsets.user ?
00298                           str + parser->offsets.user : NULL;
00299 
00300   /* get correct fnmatch callback */
00301   compare = conn->data->set.fnmatch;
00302   if(!compare)
00303     compare = Curl_fnmatch;
00304 
00305   /* filter pattern-corresponding filenames */
00306   if(compare(conn->data->set.fnmatch_data, wc->pattern,
00307              finfo->filename) == 0) {
00308     /* discard symlink which is containing multiple " -> " */
00309     if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
00310        (strstr(finfo->strings.target, " -> "))) {
00311       add = FALSE;
00312     }
00313   }
00314   else {
00315     add = FALSE;
00316   }
00317 
00318   if(add) {
00319     if(!Curl_llist_insert_next(llist, llist->tail, finfo)) {
00320       Curl_fileinfo_dtor(NULL, finfo);
00321       tmpdata->parser->file_data = NULL;
00322       return CURLE_OUT_OF_MEMORY;
00323     }
00324   }
00325   else {
00326     Curl_fileinfo_dtor(NULL, finfo);
00327   }
00328 
00329   tmpdata->parser->file_data = NULL;
00330   return CURLE_OK;
00331 }
00332 
00333 size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
00334                           void *connptr)
00335 {
00336   size_t bufflen = size*nmemb;
00337   struct connectdata *conn = (struct connectdata *)connptr;
00338   struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
00339   struct ftp_parselist_data *parser = tmpdata->parser;
00340   struct curl_fileinfo *finfo;
00341   unsigned long i = 0;
00342   CURLcode result;
00343 
00344   if(parser->error) { /* error in previous call */
00345     /* scenario:
00346      * 1. call => OK..
00347      * 2. call => OUT_OF_MEMORY (or other error)
00348      * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
00349      *    in wc_statemach()
00350      */
00351     return bufflen;
00352   }
00353 
00354   if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
00355     /* considering info about FILE response format */
00356     parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
00357                        OS_TYPE_WIN_NT : OS_TYPE_UNIX;
00358   }
00359 
00360   while(i < bufflen) { /* FSM */
00361 
00362     char c = buffer[i];
00363     if(!parser->file_data) { /* tmp file data is not allocated yet */
00364       parser->file_data = Curl_fileinfo_alloc();
00365       if(!parser->file_data) {
00366         parser->error = CURLE_OUT_OF_MEMORY;
00367         return bufflen;
00368       }
00369       parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
00370       if(!parser->file_data->b_data) {
00371         PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
00372         return bufflen;
00373       }
00374       parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
00375       parser->item_offset = 0;
00376       parser->item_length = 0;
00377     }
00378 
00379     finfo = parser->file_data;
00380     finfo->b_data[finfo->b_used++] = c;
00381 
00382     if(finfo->b_used >= finfo->b_size - 1) {
00383       /* if it is important, extend buffer space for file data */
00384       char *tmp = realloc(finfo->b_data,
00385                           finfo->b_size + FTP_BUFFER_ALLOCSIZE);
00386       if(tmp) {
00387         finfo->b_size += FTP_BUFFER_ALLOCSIZE;
00388         finfo->b_data = tmp;
00389       }
00390       else {
00391         Curl_fileinfo_dtor(NULL, parser->file_data);
00392         parser->file_data = NULL;
00393         parser->error = CURLE_OUT_OF_MEMORY;
00394         PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
00395         return bufflen;
00396       }
00397     }
00398 
00399     switch(parser->os_type) {
00400     case OS_TYPE_UNIX:
00401       switch(parser->state.UNIX.main) {
00402       case PL_UNIX_TOTALSIZE:
00403         switch(parser->state.UNIX.sub.total_dirsize) {
00404         case PL_UNIX_TOTALSIZE_INIT:
00405           if(c == 't') {
00406             parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
00407             parser->item_length++;
00408           }
00409           else {
00410             parser->state.UNIX.main = PL_UNIX_FILETYPE;
00411             /* start FSM again not considering size of directory */
00412             finfo->b_used = 0;
00413             i--;
00414           }
00415           break;
00416         case PL_UNIX_TOTALSIZE_READING:
00417           parser->item_length++;
00418           if(c == '\r') {
00419             parser->item_length--;
00420             finfo->b_used--;
00421           }
00422           else if(c == '\n') {
00423             finfo->b_data[parser->item_length - 1] = 0;
00424             if(strncmp("total ", finfo->b_data, 6) == 0) {
00425               char *endptr = finfo->b_data+6;
00426               /* here we can deal with directory size, pass the leading white
00427                  spaces and then the digits */
00428               while(ISSPACE(*endptr))
00429                 endptr++;
00430               while(ISDIGIT(*endptr))
00431                 endptr++;
00432               if(*endptr != 0) {
00433                 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00434                 return bufflen;
00435               }
00436               else {
00437                 parser->state.UNIX.main = PL_UNIX_FILETYPE;
00438                 finfo->b_used = 0;
00439               }
00440             }
00441             else {
00442               PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00443               return bufflen;
00444             }
00445           }
00446           break;
00447         }
00448         break;
00449       case PL_UNIX_FILETYPE:
00450         switch(c) {
00451         case '-':
00452           finfo->filetype = CURLFILETYPE_FILE;
00453           break;
00454         case 'd':
00455           finfo->filetype = CURLFILETYPE_DIRECTORY;
00456           break;
00457         case 'l':
00458           finfo->filetype = CURLFILETYPE_SYMLINK;
00459           break;
00460         case 'p':
00461           finfo->filetype = CURLFILETYPE_NAMEDPIPE;
00462           break;
00463         case 's':
00464           finfo->filetype = CURLFILETYPE_SOCKET;
00465           break;
00466         case 'c':
00467           finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
00468           break;
00469         case 'b':
00470           finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
00471           break;
00472         case 'D':
00473           finfo->filetype = CURLFILETYPE_DOOR;
00474           break;
00475         default:
00476           PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00477           return bufflen;
00478         }
00479         parser->state.UNIX.main = PL_UNIX_PERMISSION;
00480         parser->item_length = 0;
00481         parser->item_offset = 1;
00482         break;
00483       case PL_UNIX_PERMISSION:
00484         parser->item_length++;
00485         if(parser->item_length <= 9) {
00486           if(!strchr("rwx-tTsS", c)) {
00487             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00488             return bufflen;
00489           }
00490         }
00491         else if(parser->item_length == 10) {
00492           unsigned int perm;
00493           if(c != ' ') {
00494             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00495             return bufflen;
00496           }
00497           finfo->b_data[10] = 0; /* terminate permissions */
00498           perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
00499           if(perm & FTP_LP_MALFORMATED_PERM) {
00500             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00501             return bufflen;
00502           }
00503           parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM;
00504           parser->file_data->perm = perm;
00505           parser->offsets.perm = parser->item_offset;
00506 
00507           parser->item_length = 0;
00508           parser->state.UNIX.main = PL_UNIX_HLINKS;
00509           parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
00510         }
00511         break;
00512       case PL_UNIX_HLINKS:
00513         switch(parser->state.UNIX.sub.hlinks) {
00514         case PL_UNIX_HLINKS_PRESPACE:
00515           if(c != ' ') {
00516             if(c >= '0' && c <= '9') {
00517               parser->item_offset = finfo->b_used - 1;
00518               parser->item_length = 1;
00519               parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
00520             }
00521             else {
00522               PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00523               return bufflen;
00524             }
00525           }
00526           break;
00527         case PL_UNIX_HLINKS_NUMBER:
00528           parser->item_length ++;
00529           if(c == ' ') {
00530             char *p;
00531             long int hlinks;
00532             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00533             hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
00534             if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
00535               parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
00536               parser->file_data->hardlinks = hlinks;
00537             }
00538             parser->item_length = 0;
00539             parser->item_offset = 0;
00540             parser->state.UNIX.main = PL_UNIX_USER;
00541             parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
00542           }
00543           else if(c < '0' || c > '9') {
00544             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00545             return bufflen;
00546           }
00547           break;
00548         }
00549         break;
00550       case PL_UNIX_USER:
00551         switch(parser->state.UNIX.sub.user) {
00552         case PL_UNIX_USER_PRESPACE:
00553           if(c != ' ') {
00554             parser->item_offset = finfo->b_used - 1;
00555             parser->item_length = 1;
00556             parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
00557           }
00558           break;
00559         case PL_UNIX_USER_PARSING:
00560           parser->item_length++;
00561           if(c == ' ') {
00562             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00563             parser->offsets.user = parser->item_offset;
00564             parser->state.UNIX.main = PL_UNIX_GROUP;
00565             parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
00566             parser->item_offset = 0;
00567             parser->item_length = 0;
00568           }
00569           break;
00570         }
00571         break;
00572       case PL_UNIX_GROUP:
00573         switch(parser->state.UNIX.sub.group) {
00574         case PL_UNIX_GROUP_PRESPACE:
00575           if(c != ' ') {
00576             parser->item_offset = finfo->b_used - 1;
00577             parser->item_length = 1;
00578             parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
00579           }
00580           break;
00581         case PL_UNIX_GROUP_NAME:
00582           parser->item_length++;
00583           if(c == ' ') {
00584             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00585             parser->offsets.group = parser->item_offset;
00586             parser->state.UNIX.main = PL_UNIX_SIZE;
00587             parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
00588             parser->item_offset = 0;
00589             parser->item_length = 0;
00590           }
00591           break;
00592         }
00593         break;
00594       case PL_UNIX_SIZE:
00595         switch(parser->state.UNIX.sub.size) {
00596         case PL_UNIX_SIZE_PRESPACE:
00597           if(c != ' ') {
00598             if(c >= '0' && c <= '9') {
00599               parser->item_offset = finfo->b_used - 1;
00600               parser->item_length = 1;
00601               parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
00602             }
00603             else {
00604               PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00605               return bufflen;
00606             }
00607           }
00608           break;
00609         case PL_UNIX_SIZE_NUMBER:
00610           parser->item_length++;
00611           if(c == ' ') {
00612             char *p;
00613             curl_off_t fsize;
00614             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00615             fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
00616             if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
00617                                fsize != CURL_OFF_T_MIN) {
00618               parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
00619               parser->file_data->size = fsize;
00620             }
00621             parser->item_length = 0;
00622             parser->item_offset = 0;
00623             parser->state.UNIX.main = PL_UNIX_TIME;
00624             parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
00625           }
00626           else if(!ISDIGIT(c)) {
00627             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00628             return bufflen;
00629           }
00630           break;
00631         }
00632         break;
00633       case PL_UNIX_TIME:
00634         switch(parser->state.UNIX.sub.time) {
00635         case PL_UNIX_TIME_PREPART1:
00636           if(c != ' ') {
00637             if(ISALNUM(c)) {
00638               parser->item_offset = finfo->b_used -1;
00639               parser->item_length = 1;
00640               parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
00641             }
00642             else {
00643               PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00644               return bufflen;
00645             }
00646           }
00647           break;
00648         case PL_UNIX_TIME_PART1:
00649           parser->item_length++;
00650           if(c == ' ') {
00651             parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
00652           }
00653           else if(!ISALNUM(c) && c != '.') {
00654             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00655             return bufflen;
00656           }
00657           break;
00658         case PL_UNIX_TIME_PREPART2:
00659           parser->item_length++;
00660           if(c != ' ') {
00661             if(ISALNUM(c)) {
00662               parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
00663             }
00664             else {
00665               PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00666               return bufflen;
00667             }
00668           }
00669           break;
00670         case PL_UNIX_TIME_PART2:
00671           parser->item_length++;
00672           if(c == ' ') {
00673             parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
00674           }
00675           else if(!ISALNUM(c) && c != '.') {
00676             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00677             return bufflen;
00678           }
00679           break;
00680         case PL_UNIX_TIME_PREPART3:
00681           parser->item_length++;
00682           if(c != ' ') {
00683             if(ISALNUM(c)) {
00684               parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
00685             }
00686             else {
00687               PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00688               return bufflen;
00689             }
00690           }
00691           break;
00692         case PL_UNIX_TIME_PART3:
00693           parser->item_length++;
00694           if(c == ' ') {
00695             finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
00696             parser->offsets.time = parser->item_offset;
00697             /*
00698               if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
00699                 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
00700               }
00701             */
00702             if(finfo->filetype == CURLFILETYPE_SYMLINK) {
00703               parser->state.UNIX.main = PL_UNIX_SYMLINK;
00704               parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
00705             }
00706             else {
00707               parser->state.UNIX.main = PL_UNIX_FILENAME;
00708               parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
00709             }
00710           }
00711           else if(!ISALNUM(c) && c != '.' && c != ':') {
00712             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00713             return bufflen;
00714           }
00715           break;
00716         }
00717         break;
00718       case PL_UNIX_FILENAME:
00719         switch(parser->state.UNIX.sub.filename) {
00720         case PL_UNIX_FILENAME_PRESPACE:
00721           if(c != ' ') {
00722             parser->item_offset = finfo->b_used - 1;
00723             parser->item_length = 1;
00724             parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
00725           }
00726           break;
00727         case PL_UNIX_FILENAME_NAME:
00728           parser->item_length++;
00729           if(c == '\r') {
00730             parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
00731           }
00732           else if(c == '\n') {
00733             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00734             parser->offsets.filename = parser->item_offset;
00735             parser->state.UNIX.main = PL_UNIX_FILETYPE;
00736             result = ftp_pl_insert_finfo(conn, finfo);
00737             if(result) {
00738               PL_ERROR(conn, result);
00739               return bufflen;
00740             }
00741           }
00742           break;
00743         case PL_UNIX_FILENAME_WINDOWSEOL:
00744           if(c == '\n') {
00745             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00746             parser->offsets.filename = parser->item_offset;
00747             parser->state.UNIX.main = PL_UNIX_FILETYPE;
00748             result = ftp_pl_insert_finfo(conn, finfo);
00749             if(result) {
00750               PL_ERROR(conn, result);
00751               return bufflen;
00752             }
00753           }
00754           else {
00755             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00756             return bufflen;
00757           }
00758           break;
00759         }
00760         break;
00761       case PL_UNIX_SYMLINK:
00762         switch(parser->state.UNIX.sub.symlink) {
00763         case PL_UNIX_SYMLINK_PRESPACE:
00764           if(c != ' ') {
00765             parser->item_offset = finfo->b_used - 1;
00766             parser->item_length = 1;
00767             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
00768           }
00769           break;
00770         case PL_UNIX_SYMLINK_NAME:
00771           parser->item_length++;
00772           if(c == ' ') {
00773             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
00774           }
00775           else if(c == '\r' || c == '\n') {
00776             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00777             return bufflen;
00778           }
00779           break;
00780         case PL_UNIX_SYMLINK_PRETARGET1:
00781           parser->item_length++;
00782           if(c == '-') {
00783             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
00784           }
00785           else if(c == '\r' || c == '\n') {
00786             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00787             return bufflen;
00788           }
00789           else {
00790             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
00791           }
00792           break;
00793         case PL_UNIX_SYMLINK_PRETARGET2:
00794           parser->item_length++;
00795           if(c == '>') {
00796             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
00797           }
00798           else if(c == '\r' || c == '\n') {
00799             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00800             return bufflen;
00801           }
00802           else {
00803             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
00804           }
00805           break;
00806         case PL_UNIX_SYMLINK_PRETARGET3:
00807           parser->item_length++;
00808           if(c == ' ') {
00809             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
00810             /* now place where is symlink following */
00811             finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
00812             parser->offsets.filename = parser->item_offset;
00813             parser->item_length = 0;
00814             parser->item_offset = 0;
00815           }
00816           else if(c == '\r' || c == '\n') {
00817             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00818             return bufflen;
00819           }
00820           else {
00821             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
00822           }
00823           break;
00824         case PL_UNIX_SYMLINK_PRETARGET4:
00825           if(c != '\r' && c != '\n') {
00826             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
00827             parser->item_offset = finfo->b_used - 1;
00828             parser->item_length = 1;
00829           }
00830           else {
00831             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00832             return bufflen;
00833           }
00834           break;
00835         case PL_UNIX_SYMLINK_TARGET:
00836           parser->item_length++;
00837           if(c == '\r') {
00838             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
00839           }
00840           else if(c == '\n') {
00841             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00842             parser->offsets.symlink_target = parser->item_offset;
00843             result = ftp_pl_insert_finfo(conn, finfo);
00844             if(result) {
00845               PL_ERROR(conn, result);
00846               return bufflen;
00847             }
00848             parser->state.UNIX.main = PL_UNIX_FILETYPE;
00849           }
00850           break;
00851         case PL_UNIX_SYMLINK_WINDOWSEOL:
00852           if(c == '\n') {
00853             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00854             parser->offsets.symlink_target = parser->item_offset;
00855             result = ftp_pl_insert_finfo(conn, finfo);
00856             if(result) {
00857               PL_ERROR(conn, result);
00858               return bufflen;
00859             }
00860             parser->state.UNIX.main = PL_UNIX_FILETYPE;
00861           }
00862           else {
00863             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00864             return bufflen;
00865           }
00866           break;
00867         }
00868         break;
00869       }
00870       break;
00871     case OS_TYPE_WIN_NT:
00872       switch(parser->state.NT.main) {
00873       case PL_WINNT_DATE:
00874         parser->item_length++;
00875         if(parser->item_length < 9) {
00876           if(!strchr("0123456789-", c)) { /* only simple control */
00877             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00878             return bufflen;
00879           }
00880         }
00881         else if(parser->item_length == 9) {
00882           if(c == ' ') {
00883             parser->state.NT.main = PL_WINNT_TIME;
00884             parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
00885           }
00886           else {
00887             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00888             return bufflen;
00889           }
00890         }
00891         else {
00892           PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00893           return bufflen;
00894         }
00895         break;
00896       case PL_WINNT_TIME:
00897         parser->item_length++;
00898         switch(parser->state.NT.sub.time) {
00899         case PL_WINNT_TIME_PRESPACE:
00900           if(!ISSPACE(c)) {
00901             parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
00902           }
00903           break;
00904         case PL_WINNT_TIME_TIME:
00905           if(c == ' ') {
00906             parser->offsets.time = parser->item_offset;
00907             finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
00908             parser->state.NT.main = PL_WINNT_DIRORSIZE;
00909             parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
00910             parser->item_length = 0;
00911           }
00912           else if(!strchr("APM0123456789:", c)) {
00913             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00914             return bufflen;
00915           }
00916           break;
00917         }
00918         break;
00919       case PL_WINNT_DIRORSIZE:
00920         switch(parser->state.NT.sub.dirorsize) {
00921         case PL_WINNT_DIRORSIZE_PRESPACE:
00922           if(c == ' ') {
00923 
00924           }
00925           else {
00926             parser->item_offset = finfo->b_used - 1;
00927             parser->item_length = 1;
00928             parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
00929           }
00930           break;
00931         case PL_WINNT_DIRORSIZE_CONTENT:
00932           parser->item_length ++;
00933           if(c == ' ') {
00934             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
00935             if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
00936               finfo->filetype = CURLFILETYPE_DIRECTORY;
00937               finfo->size = 0;
00938             }
00939             else {
00940               char *endptr;
00941               finfo->size = curlx_strtoofft(finfo->b_data +
00942                                             parser->item_offset,
00943                                             &endptr, 10);
00944               if(!*endptr) {
00945                 if(finfo->size == CURL_OFF_T_MAX ||
00946                    finfo->size == CURL_OFF_T_MIN) {
00947                   if(errno == ERANGE) {
00948                     PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00949                     return bufflen;
00950                   }
00951                 }
00952               }
00953               else {
00954                 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
00955                 return bufflen;
00956               }
00957               /* correct file type */
00958               parser->file_data->filetype = CURLFILETYPE_FILE;
00959             }
00960 
00961             parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
00962             parser->item_length = 0;
00963             parser->state.NT.main = PL_WINNT_FILENAME;
00964             parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
00965           }
00966           break;
00967         }
00968         break;
00969       case PL_WINNT_FILENAME:
00970         switch(parser->state.NT.sub.filename) {
00971         case PL_WINNT_FILENAME_PRESPACE:
00972           if(c != ' ') {
00973             parser->item_offset = finfo->b_used -1;
00974             parser->item_length = 1;
00975             parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
00976           }
00977           break;
00978         case PL_WINNT_FILENAME_CONTENT:
00979           parser->item_length++;
00980           if(c == '\r') {
00981             parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
00982             finfo->b_data[finfo->b_used - 1] = 0;
00983           }
00984           else if(c == '\n') {
00985             parser->offsets.filename = parser->item_offset;
00986             finfo->b_data[finfo->b_used - 1] = 0;
00987             parser->offsets.filename = parser->item_offset;
00988             result = ftp_pl_insert_finfo(conn, finfo);
00989             if(result) {
00990               PL_ERROR(conn, result);
00991               return bufflen;
00992             }
00993             parser->state.NT.main = PL_WINNT_DATE;
00994             parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
00995           }
00996           break;
00997         case PL_WINNT_FILENAME_WINEOL:
00998           if(c == '\n') {
00999             parser->offsets.filename = parser->item_offset;
01000             result = ftp_pl_insert_finfo(conn, finfo);
01001             if(result) {
01002               PL_ERROR(conn, result);
01003               return bufflen;
01004             }
01005             parser->state.NT.main = PL_WINNT_DATE;
01006             parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
01007           }
01008           else {
01009             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
01010             return bufflen;
01011           }
01012           break;
01013         }
01014         break;
01015       }
01016       break;
01017     default:
01018       return bufflen + 1;
01019     }
01020 
01021     i++;
01022   }
01023 
01024   return bufflen;
01025 }
01026 
01027 #endif /* CURL_DISABLE_FTP */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:02