Files correlati : omento : Aggiornata cUrl alla ultima versione su Github: 7.56.1 git-svn-id: svn://10.65.10.50/branches/R_10_00@24202 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1016 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1016 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /***************************************************************************
 | |
|  *                                  _   _ ____  _
 | |
|  *  Project                     ___| | | |  _ \| |
 | |
|  *                             / __| | | | |_) | |
 | |
|  *                            | (__| |_| |  _ <| |___
 | |
|  *                             \___|\___/|_| \_\_____|
 | |
|  *
 | |
|  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
 | |
|  *
 | |
|  * This software is licensed as described in the file COPYING, which
 | |
|  * you should have received as part of this distribution. The terms
 | |
|  * are also available at https://curl.haxx.se/docs/copyright.html.
 | |
|  *
 | |
|  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 | |
|  * copies of the Software, and permit persons to whom the Software is
 | |
|  * furnished to do so, under the terms of the COPYING file.
 | |
|  *
 | |
|  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 | |
|  * KIND, either express or implied.
 | |
|  *
 | |
|  ***************************************************************************/
 | |
| 
 | |
| /**
 | |
|  * Now implemented:
 | |
|  *
 | |
|  * 1) Unix version 1
 | |
|  * drwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog
 | |
|  * 2) Unix version 2
 | |
|  * drwxr-xr-x 1 user01 ftp  512 Jan 29 1997  prog
 | |
|  * 3) Unix version 3
 | |
|  * drwxr-xr-x 1      1   1  512 Jan 29 23:32 prog
 | |
|  * 4) Unix symlink
 | |
|  * lrwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog -> prog2000
 | |
|  * 5) DOS style
 | |
|  * 01-29-97 11:32PM <DIR> prog
 | |
|  */
 | |
| 
 | |
| #include "curl_setup.h"
 | |
| 
 | |
| #ifndef CURL_DISABLE_FTP
 | |
| 
 | |
| #include <curl/curl.h>
 | |
| 
 | |
| #include "urldata.h"
 | |
| #include "fileinfo.h"
 | |
| #include "llist.h"
 | |
| #include "strtoofft.h"
 | |
| #include "ftp.h"
 | |
| #include "ftplistparser.h"
 | |
| #include "curl_fnmatch.h"
 | |
| #include "curl_memory.h"
 | |
| /* The last #include file should be: */
 | |
| #include "memdebug.h"
 | |
| 
 | |
| /* allocs buffer which will contain one line of LIST command response */
 | |
| #define FTP_BUFFER_ALLOCSIZE 160
 | |
| 
 | |
| typedef enum {
 | |
|   PL_UNIX_TOTALSIZE = 0,
 | |
|   PL_UNIX_FILETYPE,
 | |
|   PL_UNIX_PERMISSION,
 | |
|   PL_UNIX_HLINKS,
 | |
|   PL_UNIX_USER,
 | |
|   PL_UNIX_GROUP,
 | |
|   PL_UNIX_SIZE,
 | |
|   PL_UNIX_TIME,
 | |
|   PL_UNIX_FILENAME,
 | |
|   PL_UNIX_SYMLINK
 | |
| } pl_unix_mainstate;
 | |
| 
 | |
| typedef union {
 | |
|   enum {
 | |
|     PL_UNIX_TOTALSIZE_INIT = 0,
 | |
|     PL_UNIX_TOTALSIZE_READING
 | |
|   } total_dirsize;
 | |
| 
 | |
|   enum {
 | |
|     PL_UNIX_HLINKS_PRESPACE = 0,
 | |
|     PL_UNIX_HLINKS_NUMBER
 | |
|   } hlinks;
 | |
| 
 | |
|   enum {
 | |
|     PL_UNIX_USER_PRESPACE = 0,
 | |
|     PL_UNIX_USER_PARSING
 | |
|   } user;
 | |
| 
 | |
|   enum {
 | |
|     PL_UNIX_GROUP_PRESPACE = 0,
 | |
|     PL_UNIX_GROUP_NAME
 | |
|   } group;
 | |
| 
 | |
|   enum {
 | |
|     PL_UNIX_SIZE_PRESPACE = 0,
 | |
|     PL_UNIX_SIZE_NUMBER
 | |
|   } size;
 | |
| 
 | |
|   enum {
 | |
|     PL_UNIX_TIME_PREPART1 = 0,
 | |
|     PL_UNIX_TIME_PART1,
 | |
|     PL_UNIX_TIME_PREPART2,
 | |
|     PL_UNIX_TIME_PART2,
 | |
|     PL_UNIX_TIME_PREPART3,
 | |
|     PL_UNIX_TIME_PART3
 | |
|   } time;
 | |
| 
 | |
|   enum {
 | |
|     PL_UNIX_FILENAME_PRESPACE = 0,
 | |
|     PL_UNIX_FILENAME_NAME,
 | |
|     PL_UNIX_FILENAME_WINDOWSEOL
 | |
|   } filename;
 | |
| 
 | |
|   enum {
 | |
|     PL_UNIX_SYMLINK_PRESPACE = 0,
 | |
|     PL_UNIX_SYMLINK_NAME,
 | |
|     PL_UNIX_SYMLINK_PRETARGET1,
 | |
|     PL_UNIX_SYMLINK_PRETARGET2,
 | |
|     PL_UNIX_SYMLINK_PRETARGET3,
 | |
|     PL_UNIX_SYMLINK_PRETARGET4,
 | |
|     PL_UNIX_SYMLINK_TARGET,
 | |
|     PL_UNIX_SYMLINK_WINDOWSEOL
 | |
|   } symlink;
 | |
| } pl_unix_substate;
 | |
| 
 | |
| typedef enum {
 | |
|   PL_WINNT_DATE = 0,
 | |
|   PL_WINNT_TIME,
 | |
|   PL_WINNT_DIRORSIZE,
 | |
|   PL_WINNT_FILENAME
 | |
| } pl_winNT_mainstate;
 | |
| 
 | |
| typedef union {
 | |
|   enum {
 | |
|     PL_WINNT_TIME_PRESPACE = 0,
 | |
|     PL_WINNT_TIME_TIME
 | |
|   } time;
 | |
|   enum {
 | |
|     PL_WINNT_DIRORSIZE_PRESPACE = 0,
 | |
|     PL_WINNT_DIRORSIZE_CONTENT
 | |
|   } dirorsize;
 | |
|   enum {
 | |
|     PL_WINNT_FILENAME_PRESPACE = 0,
 | |
|     PL_WINNT_FILENAME_CONTENT,
 | |
|     PL_WINNT_FILENAME_WINEOL
 | |
|   } filename;
 | |
| } pl_winNT_substate;
 | |
| 
 | |
| /* This struct is used in wildcard downloading - for parsing LIST response */
 | |
| struct ftp_parselist_data {
 | |
|   enum {
 | |
|     OS_TYPE_UNKNOWN = 0,
 | |
|     OS_TYPE_UNIX,
 | |
|     OS_TYPE_WIN_NT
 | |
|   } os_type;
 | |
| 
 | |
|   union {
 | |
|     struct {
 | |
|       pl_unix_mainstate main;
 | |
|       pl_unix_substate sub;
 | |
|     } UNIX;
 | |
| 
 | |
|     struct {
 | |
|       pl_winNT_mainstate main;
 | |
|       pl_winNT_substate sub;
 | |
|     } NT;
 | |
|   } state;
 | |
| 
 | |
|   CURLcode error;
 | |
|   struct fileinfo *file_data;
 | |
|   unsigned int item_length;
 | |
|   size_t item_offset;
 | |
|   struct {
 | |
|     size_t filename;
 | |
|     size_t user;
 | |
|     size_t group;
 | |
|     size_t time;
 | |
|     size_t perm;
 | |
|     size_t symlink_target;
 | |
|   } offsets;
 | |
| };
 | |
| 
 | |
| struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
 | |
| {
 | |
|   return calloc(1, sizeof(struct ftp_parselist_data));
 | |
| }
 | |
| 
 | |
| 
 | |
| void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
 | |
| {
 | |
|   free(*pl_data);
 | |
|   *pl_data = NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
 | |
| {
 | |
|   return pl_data->error;
 | |
| }
 | |
| 
 | |
| 
 | |
| #define FTP_LP_MALFORMATED_PERM 0x01000000
 | |
| 
 | |
| static int ftp_pl_get_permission(const char *str)
 | |
| {
 | |
|   int permissions = 0;
 | |
|   /* USER */
 | |
|   if(str[0] == 'r')
 | |
|     permissions |= 1 << 8;
 | |
|   else if(str[0] != '-')
 | |
|     permissions |= FTP_LP_MALFORMATED_PERM;
 | |
|   if(str[1] == 'w')
 | |
|     permissions |= 1 << 7;
 | |
|   else if(str[1] != '-')
 | |
|     permissions |= FTP_LP_MALFORMATED_PERM;
 | |
| 
 | |
|   if(str[2] == 'x')
 | |
|     permissions |= 1 << 6;
 | |
|   else if(str[2] == 's') {
 | |
|     permissions |= 1 << 6;
 | |
|     permissions |= 1 << 11;
 | |
|   }
 | |
|   else if(str[2] == 'S')
 | |
|     permissions |= 1 << 11;
 | |
|   else if(str[2] != '-')
 | |
|     permissions |= FTP_LP_MALFORMATED_PERM;
 | |
|   /* GROUP */
 | |
|   if(str[3] == 'r')
 | |
|     permissions |= 1 << 5;
 | |
|   else if(str[3] != '-')
 | |
|     permissions |= FTP_LP_MALFORMATED_PERM;
 | |
|   if(str[4] == 'w')
 | |
|     permissions |= 1 << 4;
 | |
|   else if(str[4] != '-')
 | |
|     permissions |= FTP_LP_MALFORMATED_PERM;
 | |
|   if(str[5] == 'x')
 | |
|     permissions |= 1 << 3;
 | |
|   else if(str[5] == 's') {
 | |
|     permissions |= 1 << 3;
 | |
|     permissions |= 1 << 10;
 | |
|   }
 | |
|   else if(str[5] == 'S')
 | |
|     permissions |= 1 << 10;
 | |
|   else if(str[5] != '-')
 | |
|     permissions |= FTP_LP_MALFORMATED_PERM;
 | |
|   /* others */
 | |
|   if(str[6] == 'r')
 | |
|     permissions |= 1 << 2;
 | |
|   else if(str[6] != '-')
 | |
|     permissions |= FTP_LP_MALFORMATED_PERM;
 | |
|   if(str[7] == 'w')
 | |
|     permissions |= 1 << 1;
 | |
|   else if(str[7] != '-')
 | |
|       permissions |= FTP_LP_MALFORMATED_PERM;
 | |
|   if(str[8] == 'x')
 | |
|     permissions |= 1;
 | |
|   else if(str[8] == 't') {
 | |
|     permissions |= 1;
 | |
|     permissions |= 1 << 9;
 | |
|   }
 | |
|   else if(str[8] == 'T')
 | |
|     permissions |= 1 << 9;
 | |
|   else if(str[8] != '-')
 | |
|     permissions |= FTP_LP_MALFORMATED_PERM;
 | |
| 
 | |
|   return permissions;
 | |
| }
 | |
| 
 | |
| static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
 | |
|                                     struct fileinfo *infop)
 | |
| {
 | |
|   curl_fnmatch_callback compare;
 | |
|   struct WildcardData *wc = &conn->data->wildcard;
 | |
|   struct ftp_wc_tmpdata *tmpdata = wc->tmp;
 | |
|   struct curl_llist *llist = &wc->filelist;
 | |
|   struct ftp_parselist_data *parser = tmpdata->parser;
 | |
|   bool add = TRUE;
 | |
|   struct curl_fileinfo *finfo = &infop->info;
 | |
| 
 | |
|   /* move finfo pointers to b_data */
 | |
|   char *str = finfo->b_data;
 | |
|   finfo->filename       = str + parser->offsets.filename;
 | |
|   finfo->strings.group  = parser->offsets.group ?
 | |
|                           str + parser->offsets.group : NULL;
 | |
|   finfo->strings.perm   = parser->offsets.perm ?
 | |
|                           str + parser->offsets.perm : NULL;
 | |
|   finfo->strings.target = parser->offsets.symlink_target ?
 | |
|                           str + parser->offsets.symlink_target : NULL;
 | |
|   finfo->strings.time   = str + parser->offsets.time;
 | |
|   finfo->strings.user   = parser->offsets.user ?
 | |
|                           str + parser->offsets.user : NULL;
 | |
| 
 | |
|   /* get correct fnmatch callback */
 | |
|   compare = conn->data->set.fnmatch;
 | |
|   if(!compare)
 | |
|     compare = Curl_fnmatch;
 | |
| 
 | |
|   /* filter pattern-corresponding filenames */
 | |
|   if(compare(conn->data->set.fnmatch_data, wc->pattern,
 | |
|              finfo->filename) == 0) {
 | |
|     /* discard symlink which is containing multiple " -> " */
 | |
|     if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
 | |
|        (strstr(finfo->strings.target, " -> "))) {
 | |
|       add = FALSE;
 | |
|     }
 | |
|   }
 | |
|   else {
 | |
|     add = FALSE;
 | |
|   }
 | |
| 
 | |
|   if(add) {
 | |
|     Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
 | |
|   }
 | |
|   else {
 | |
|     Curl_fileinfo_dtor(NULL, finfo);
 | |
|   }
 | |
| 
 | |
|   tmpdata->parser->file_data = NULL;
 | |
|   return CURLE_OK;
 | |
| }
 | |
| 
 | |
| size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
 | |
|                           void *connptr)
 | |
| {
 | |
|   size_t bufflen = size*nmemb;
 | |
|   struct connectdata *conn = (struct connectdata *)connptr;
 | |
|   struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
 | |
|   struct ftp_parselist_data *parser = tmpdata->parser;
 | |
|   struct fileinfo *infop;
 | |
|   struct curl_fileinfo *finfo;
 | |
|   unsigned long 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 hadled later
 | |
|      *    in wc_statemach()
 | |
|      */
 | |
|     goto fail;
 | |
|   }
 | |
| 
 | |
|   if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
 | |
|     /* considering info about FILE response format */
 | |
|     parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
 | |
|                        OS_TYPE_WIN_NT : OS_TYPE_UNIX;
 | |
|   }
 | |
| 
 | |
|   while(i < bufflen) { /* FSM */
 | |
| 
 | |
|     char c = buffer[i];
 | |
|     if(!parser->file_data) { /* tmp file data is not allocated yet */
 | |
|       parser->file_data = Curl_fileinfo_alloc();
 | |
|       if(!parser->file_data) {
 | |
|         parser->error = CURLE_OUT_OF_MEMORY;
 | |
|         goto fail;
 | |
|       }
 | |
|       parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE);
 | |
|       if(!parser->file_data->info.b_data) {
 | |
|         parser->error = CURLE_OUT_OF_MEMORY;
 | |
|         goto fail;
 | |
|       }
 | |
|       parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE;
 | |
|       parser->item_offset = 0;
 | |
|       parser->item_length = 0;
 | |
|     }
 | |
| 
 | |
|     infop = parser->file_data;
 | |
|     finfo = &infop->info;
 | |
|     finfo->b_data[finfo->b_used++] = c;
 | |
| 
 | |
|     if(finfo->b_used >= finfo->b_size - 1) {
 | |
|       /* if it is important, extend buffer space for file data */
 | |
|       char *tmp = realloc(finfo->b_data,
 | |
|                           finfo->b_size + FTP_BUFFER_ALLOCSIZE);
 | |
|       if(tmp) {
 | |
|         finfo->b_size += FTP_BUFFER_ALLOCSIZE;
 | |
|         finfo->b_data = tmp;
 | |
|       }
 | |
|       else {
 | |
|         Curl_fileinfo_dtor(NULL, parser->file_data);
 | |
|         parser->file_data = NULL;
 | |
|         parser->error = CURLE_OUT_OF_MEMORY;
 | |
|         goto fail;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     switch(parser->os_type) {
 | |
|     case OS_TYPE_UNIX:
 | |
|       switch(parser->state.UNIX.main) {
 | |
|       case PL_UNIX_TOTALSIZE:
 | |
|         switch(parser->state.UNIX.sub.total_dirsize) {
 | |
|         case PL_UNIX_TOTALSIZE_INIT:
 | |
|           if(c == 't') {
 | |
|             parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
 | |
|             parser->item_length++;
 | |
|           }
 | |
|           else {
 | |
|             parser->state.UNIX.main = PL_UNIX_FILETYPE;
 | |
|             /* start FSM again not considering size of directory */
 | |
|             finfo->b_used = 0;
 | |
|             i--;
 | |
|           }
 | |
|           break;
 | |
|         case PL_UNIX_TOTALSIZE_READING:
 | |
|           parser->item_length++;
 | |
|           if(c == '\r') {
 | |
|             parser->item_length--;
 | |
|             finfo->b_used--;
 | |
|           }
 | |
|           else if(c == '\n') {
 | |
|             finfo->b_data[parser->item_length - 1] = 0;
 | |
|             if(strncmp("total ", finfo->b_data, 6) == 0) {
 | |
|               char *endptr = finfo->b_data + 6;
 | |
|               /* here we can deal with directory size, pass the leading white
 | |
|                  spaces and then the digits */
 | |
|               while(ISSPACE(*endptr))
 | |
|                 endptr++;
 | |
|               while(ISDIGIT(*endptr))
 | |
|                 endptr++;
 | |
|               if(*endptr != 0) {
 | |
|                 parser->error = CURLE_FTP_BAD_FILE_LIST;
 | |
|                 goto fail;
 | |
|               }
 | |
|               parser->state.UNIX.main = PL_UNIX_FILETYPE;
 | |
|               finfo->b_used = 0;
 | |
|             }
 | |
|             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;
 | |
|           }
 | |
|           finfo->b_data[10] = 0; /* terminate permissions */
 | |
|           perm = ftp_pl_get_permission(finfo->b_data + 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(c >= '0' && c <= '9') {
 | |
|               parser->item_offset = finfo->b_used - 1;
 | |
|               parser->item_length = 1;
 | |
|               parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
 | |
|             }
 | |
|             else {
 | |
|               parser->error = CURLE_FTP_BAD_FILE_LIST;
 | |
|               goto fail;
 | |
|             }
 | |
|           }
 | |
|           break;
 | |
|         case PL_UNIX_HLINKS_NUMBER:
 | |
|           parser->item_length ++;
 | |
|           if(c == ' ') {
 | |
|             char *p;
 | |
|             long int hlinks;
 | |
|             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
 | |
|             hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
 | |
|             if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
 | |
|               parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
 | |
|               parser->file_data->info.hardlinks = hlinks;
 | |
|             }
 | |
|             parser->item_length = 0;
 | |
|             parser->item_offset = 0;
 | |
|             parser->state.UNIX.main = PL_UNIX_USER;
 | |
|             parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
 | |
|           }
 | |
|           else if(c < '0' || c > '9') {
 | |
|             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 = finfo->b_used - 1;
 | |
|             parser->item_length = 1;
 | |
|             parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
 | |
|           }
 | |
|           break;
 | |
|         case PL_UNIX_USER_PARSING:
 | |
|           parser->item_length++;
 | |
|           if(c == ' ') {
 | |
|             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
 | |
|             parser->offsets.user = parser->item_offset;
 | |
|             parser->state.UNIX.main = PL_UNIX_GROUP;
 | |
|             parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
 | |
|             parser->item_offset = 0;
 | |
|             parser->item_length = 0;
 | |
|           }
 | |
|           break;
 | |
|         }
 | |
|         break;
 | |
|       case PL_UNIX_GROUP:
 | |
|         switch(parser->state.UNIX.sub.group) {
 | |
|         case PL_UNIX_GROUP_PRESPACE:
 | |
|           if(c != ' ') {
 | |
|             parser->item_offset = finfo->b_used - 1;
 | |
|             parser->item_length = 1;
 | |
|             parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
 | |
|           }
 | |
|           break;
 | |
|         case PL_UNIX_GROUP_NAME:
 | |
|           parser->item_length++;
 | |
|           if(c == ' ') {
 | |
|             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
 | |
|             parser->offsets.group = parser->item_offset;
 | |
|             parser->state.UNIX.main = PL_UNIX_SIZE;
 | |
|             parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
 | |
|             parser->item_offset = 0;
 | |
|             parser->item_length = 0;
 | |
|           }
 | |
|           break;
 | |
|         }
 | |
|         break;
 | |
|       case PL_UNIX_SIZE:
 | |
|         switch(parser->state.UNIX.sub.size) {
 | |
|         case PL_UNIX_SIZE_PRESPACE:
 | |
|           if(c != ' ') {
 | |
|             if(c >= '0' && c <= '9') {
 | |
|               parser->item_offset = finfo->b_used - 1;
 | |
|               parser->item_length = 1;
 | |
|               parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
 | |
|             }
 | |
|             else {
 | |
|               parser->error = CURLE_FTP_BAD_FILE_LIST;
 | |
|               goto fail;
 | |
|             }
 | |
|           }
 | |
|           break;
 | |
|         case PL_UNIX_SIZE_NUMBER:
 | |
|           parser->item_length++;
 | |
|           if(c == ' ') {
 | |
|             char *p;
 | |
|             curl_off_t fsize;
 | |
|             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
 | |
|             if(!curlx_strtoofft(finfo->b_data + parser->item_offset,
 | |
|                                 &p, 10, &fsize)) {
 | |
|               if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
 | |
|                  fsize != CURL_OFF_T_MIN) {
 | |
|                 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 = finfo->b_used -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 == ' ') {
 | |
|             finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
 | |
|             parser->offsets.time = parser->item_offset;
 | |
|             /*
 | |
|               if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
 | |
|                 parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
 | |
|               }
 | |
|             */
 | |
|             if(finfo->filetype == CURLFILETYPE_SYMLINK) {
 | |
|               parser->state.UNIX.main = PL_UNIX_SYMLINK;
 | |
|               parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
 | |
|             }
 | |
|             else {
 | |
|               parser->state.UNIX.main = PL_UNIX_FILENAME;
 | |
|               parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
 | |
|             }
 | |
|           }
 | |
|           else if(!ISALNUM(c) && c != '.' && c != ':') {
 | |
|             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 = finfo->b_used - 1;
 | |
|             parser->item_length = 1;
 | |
|             parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
 | |
|           }
 | |
|           break;
 | |
|         case PL_UNIX_FILENAME_NAME:
 | |
|           parser->item_length++;
 | |
|           if(c == '\r') {
 | |
|             parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
 | |
|           }
 | |
|           else if(c == '\n') {
 | |
|             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
 | |
|             parser->offsets.filename = parser->item_offset;
 | |
|             parser->state.UNIX.main = PL_UNIX_FILETYPE;
 | |
|             result = ftp_pl_insert_finfo(conn, infop);
 | |
|             if(result) {
 | |
|               parser->error = result;
 | |
|               goto fail;
 | |
|             }
 | |
|           }
 | |
|           break;
 | |
|         case PL_UNIX_FILENAME_WINDOWSEOL:
 | |
|           if(c == '\n') {
 | |
|             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
 | |
|             parser->offsets.filename = parser->item_offset;
 | |
|             parser->state.UNIX.main = PL_UNIX_FILETYPE;
 | |
|             result = ftp_pl_insert_finfo(conn, 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 = finfo->b_used - 1;
 | |
|             parser->item_length = 1;
 | |
|             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
 | |
|           }
 | |
|           break;
 | |
|         case PL_UNIX_SYMLINK_NAME:
 | |
|           parser->item_length++;
 | |
|           if(c == ' ') {
 | |
|             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
 | |
|           }
 | |
|           else if(c == '\r' || c == '\n') {
 | |
|             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 */
 | |
|             finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
 | |
|             parser->offsets.filename = parser->item_offset;
 | |
|             parser->item_length = 0;
 | |
|             parser->item_offset = 0;
 | |
|           }
 | |
|           else if(c == '\r' || c == '\n') {
 | |
|             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 = finfo->b_used - 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') {
 | |
|             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
 | |
|             parser->offsets.symlink_target = parser->item_offset;
 | |
|             result = ftp_pl_insert_finfo(conn, infop);
 | |
|             if(result) {
 | |
|               parser->error = result;
 | |
|               goto fail;
 | |
|             }
 | |
|             parser->state.UNIX.main = PL_UNIX_FILETYPE;
 | |
|           }
 | |
|           break;
 | |
|         case PL_UNIX_SYMLINK_WINDOWSEOL:
 | |
|           if(c == '\n') {
 | |
|             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
 | |
|             parser->offsets.symlink_target = parser->item_offset;
 | |
|             result = ftp_pl_insert_finfo(conn, 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;
 | |
|       }
 | |
|       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(!ISSPACE(c)) {
 | |
|             parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
 | |
|           }
 | |
|           break;
 | |
|         case PL_WINNT_TIME_TIME:
 | |
|           if(c == ' ') {
 | |
|             parser->offsets.time = parser->item_offset;
 | |
|             finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
 | |
|             parser->state.NT.main = PL_WINNT_DIRORSIZE;
 | |
|             parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
 | |
|             parser->item_length = 0;
 | |
|           }
 | |
|           else if(!strchr("APM0123456789:", c)) {
 | |
|             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 == ' ') {
 | |
| 
 | |
|           }
 | |
|           else {
 | |
|             parser->item_offset = finfo->b_used - 1;
 | |
|             parser->item_length = 1;
 | |
|             parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
 | |
|           }
 | |
|           break;
 | |
|         case PL_WINNT_DIRORSIZE_CONTENT:
 | |
|           parser->item_length ++;
 | |
|           if(c == ' ') {
 | |
|             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
 | |
|             if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
 | |
|               finfo->filetype = CURLFILETYPE_DIRECTORY;
 | |
|               finfo->size = 0;
 | |
|             }
 | |
|             else {
 | |
|               char *endptr;
 | |
|               if(curlx_strtoofft(finfo->b_data +
 | |
|                                  parser->item_offset,
 | |
|                                  &endptr, 10, &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 = finfo->b_used -1;
 | |
|             parser->item_length = 1;
 | |
|             parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
 | |
|           }
 | |
|           break;
 | |
|         case PL_WINNT_FILENAME_CONTENT:
 | |
|           parser->item_length++;
 | |
|           if(c == '\r') {
 | |
|             parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
 | |
|             finfo->b_data[finfo->b_used - 1] = 0;
 | |
|           }
 | |
|           else if(c == '\n') {
 | |
|             parser->offsets.filename = parser->item_offset;
 | |
|             finfo->b_data[finfo->b_used - 1] = 0;
 | |
|             parser->offsets.filename = parser->item_offset;
 | |
|             result = ftp_pl_insert_finfo(conn, 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(conn, 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;
 | |
|       }
 | |
|       break;
 | |
|     default:
 | |
|       retsize = bufflen + 1;
 | |
|       goto fail;
 | |
|     }
 | |
| 
 | |
|     i++;
 | |
|   }
 | |
| 
 | |
| fail:
 | |
| 
 | |
|   /* Clean up any allocated memory. */
 | |
|   if(parser->file_data) {
 | |
|     Curl_fileinfo_dtor(NULL, parser->file_data);
 | |
|     parser->file_data = NULL;
 | |
|   }
 | |
| 
 | |
|   return retsize;
 | |
| }
 | |
| 
 | |
| #endif /* CURL_DISABLE_FTP */
 |