Base code merged to SPIN 2.4
[platform/upstream/curl.git] / lib / ftplistparser.c
index 4e10c43..9aacad9 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, 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
 /**
  * Now implemented:
  *
- * 1) UNIX version 1
+ * 1) Unix version 1
  * drwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog
- * 2) UNIX version 2
+ * 2) Unix version 2
  * drwxr-xr-x 1 user01 ftp  512 Jan 29 1997  prog
- * 3) UNIX version 3
+ * 3) Unix version 3
  * drwxr-xr-x 1      1   1  512 Jan 29 23:32 prog
- * 4) UNIX symlink
+ * 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 "setup.h"
+#include "curl_setup.h"
 
-#include <time.h>
+#ifndef CURL_DISABLE_FTP
 
-#include "ftplistparser.h"
-#include "curl_fnmatch.h"
+#include <curl/curl.h>
 
 #include "urldata.h"
-#include "ftp.h"
 #include "fileinfo.h"
 #include "llist.h"
 #include "strtoofft.h"
 #include "rawstr.h"
 #include "ftp.h"
+#include "ftplistparser.h"
+#include "curl_fnmatch.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.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_FILETYPE = 0,
+  PL_UNIX_TOTALSIZE = 0,
+  PL_UNIX_FILETYPE,
   PL_UNIX_PERMISSION,
   PL_UNIX_HLINKS,
   PL_UNIX_USER,
@@ -67,6 +75,11 @@ typedef enum {
 
 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;
@@ -156,17 +169,6 @@ struct ftp_parselist_data {
     } NT;
   } state;
 
-  struct {
-    char *buffer;
-    size_t bufferlength; /* how many bytes is allocated at *buffer */
-    size_t bufferin; /* how many bytes is in buffer */
-  } tmpdata;
-
-  struct {
-    curl_write_callback old_fwritefunc;
-    FILE *old_file_descriptor;
-  } backup;
-
   CURLcode error;
   struct curl_fileinfo *file_data;
   unsigned int item_length;
@@ -181,18 +183,13 @@ struct ftp_parselist_data {
   } offsets;
 };
 
-struct ftp_parselist_data *ftp_parselist_data_alloc(void)
+struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
 {
-  struct ftp_parselist_data *parselist_data =
-      malloc(sizeof(struct ftp_parselist_data));
-  if(!parselist_data)
-    return ZERO_NULL;
-  memset(parselist_data, 0, sizeof(struct ftp_parselist_data));
-  return parselist_data;
+  return calloc(1, sizeof(struct ftp_parselist_data));
 }
 
 
-void ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
+void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
 {
   if(*pl_data)
     free(*pl_data);
@@ -200,7 +197,7 @@ void ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
 }
 
 
-CURLcode ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
+CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
 {
   return pl_data->error;
 }
@@ -332,9 +329,10 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
     compare = Curl_fnmatch;
 
   /* filter pattern-corresponding filenames */
-  if(compare(conn->data->set.fnmatch_data, wc->pattern, finfo->filename) == 0) {
+  if(compare(conn->data->set.fnmatch_data, wc->pattern,
+             finfo->filename) == 0) {
     /* discard symlink which is containing multiple " -> " */
-    if((finfo->filetype == CURLFILETYPE_SYMLINK) &&
+    if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
        (strstr(finfo->strings.target, " -> "))) {
       add = FALSE;
     }
@@ -358,7 +356,8 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
   return CURLE_OK;
 }
 
-size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
+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;
@@ -366,7 +365,7 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
   struct ftp_parselist_data *parser = tmpdata->parser;
   struct curl_fileinfo *finfo;
   unsigned long i = 0;
-  CURLcode rc;
+  CURLcode result;
 
   if(parser->error) { /* error in previous call */
     /* scenario:
@@ -404,7 +403,7 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
     }
 
     finfo = parser->file_data;
-    finfo->b_data[finfo->b_used++] = buffer[i];
+    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 */
@@ -417,12 +416,62 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
       else {
         Curl_fileinfo_dtor(NULL, parser->file_data);
         parser->file_data = NULL;
+        parser->error = CURLE_OUT_OF_MEMORY;
+        PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
+        return bufflen;
       }
     }
 
     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) {
+                PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+                return bufflen;
+              }
+              else {
+                parser->state.UNIX.main = PL_UNIX_FILETYPE;
+                finfo->b_used = 0;
+              }
+            }
+            else {
+              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+              return bufflen;
+            }
+          }
+          break;
+        }
+        break;
       case PL_UNIX_FILETYPE:
         switch (c) {
         case '-':
@@ -452,7 +501,6 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
         default:
           PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
           return bufflen;
-          break;
         }
         parser->state.UNIX.main = PL_UNIX_PERMISSION;
         parser->item_length = 0;
@@ -591,8 +639,8 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
             curl_off_t fsize;
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
-            if(p[0] == '\0' && fsize != CURL_LLONG_MAX &&
-                               fsize != CURL_LLONG_MIN) {
+            if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
+                               fsize != CURL_OFF_T_MIN) {
               parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
               parser->file_data->size = fsize;
             }
@@ -601,7 +649,7 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
             parser->state.UNIX.main = PL_UNIX_TIME;
             parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
           }
-          else if (!ISDIGIT(c)) {
+          else if(!ISDIGIT(c)) {
             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
             return bufflen;
           }
@@ -710,9 +758,9 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.filename = parser->item_offset;
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
-            rc = ftp_pl_insert_finfo(conn, finfo);
-            if(rc) {
-              PL_ERROR(conn, rc);
+            result = ftp_pl_insert_finfo(conn, finfo);
+            if(result) {
+              PL_ERROR(conn, result);
               return bufflen;
             }
           }
@@ -722,9 +770,9 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
             finfo->b_data[parser->item_offset + parser->item_length] = 0;
             parser->offsets.filename = parser->item_offset;
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
-            rc = ftp_pl_insert_finfo(conn, finfo);
-            if(rc) {
-              PL_ERROR(conn, rc);
+            result = ftp_pl_insert_finfo(conn, finfo);
+            if(result) {
+              PL_ERROR(conn, result);
               return bufflen;
             }
           }
@@ -818,9 +866,9 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
           else if(c == '\n') {
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.symlink_target = parser->item_offset;
-            rc = ftp_pl_insert_finfo(conn, finfo);
-            if(rc) {
-              PL_ERROR(conn, rc);
+            result = ftp_pl_insert_finfo(conn, finfo);
+            if(result) {
+              PL_ERROR(conn, result);
               return bufflen;
             }
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
@@ -830,9 +878,9 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
           if(c == '\n') {
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.symlink_target = parser->item_offset;
-            rc = ftp_pl_insert_finfo(conn, finfo);
-            if(rc) {
-              PL_ERROR(conn, rc);
+            result = ftp_pl_insert_finfo(conn, finfo);
+            if(result) {
+              PL_ERROR(conn, result);
               return bufflen;
             }
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
@@ -916,11 +964,12 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
             }
             else {
               char *endptr;
-              finfo->size = curlx_strtoofft(finfo->b_data + parser->item_offset,
+              finfo->size = curlx_strtoofft(finfo->b_data +
+                                            parser->item_offset,
                                             &endptr, 10);
               if(!*endptr) {
-                if(finfo->size == CURL_LLONG_MAX ||
-                   finfo->size == CURL_LLONG_MIN) {
+                if(finfo->size == CURL_OFF_T_MAX ||
+                   finfo->size == CURL_OFF_T_MIN) {
                   if(errno == ERANGE) {
                     PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
                     return bufflen;
@@ -931,7 +980,7 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
                 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
                 return bufflen;
               }
-              /* correct file size */
+              /* correct file type */
               parser->file_data->filetype = CURLFILETYPE_FILE;
             }
 
@@ -962,9 +1011,9 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
             parser->offsets.filename = parser->item_offset;
             finfo->b_data[finfo->b_used - 1] = 0;
             parser->offsets.filename = parser->item_offset;
-            rc = ftp_pl_insert_finfo(conn, finfo);
-            if(rc) {
-              PL_ERROR(conn, rc);
+            result = ftp_pl_insert_finfo(conn, finfo);
+            if(result) {
+              PL_ERROR(conn, result);
               return bufflen;
             }
             parser->state.NT.main = PL_WINNT_DATE;
@@ -974,9 +1023,9 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
         case PL_WINNT_FILENAME_WINEOL:
           if(c == '\n') {
             parser->offsets.filename = parser->item_offset;
-            rc = ftp_pl_insert_finfo(conn, finfo);
-            if(rc) {
-              PL_ERROR(conn, rc);
+            result = ftp_pl_insert_finfo(conn, finfo);
+            if(result) {
+              PL_ERROR(conn, result);
               return bufflen;
             }
             parser->state.NT.main = PL_WINNT_DATE;
@@ -992,8 +1041,7 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
       }
       break;
     default:
-      return bufflen+1;
-      break;
+      return bufflen + 1;
     }
 
     i++;
@@ -1001,3 +1049,5 @@ size_t ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr)
 
   return bufflen;
 }
+
+#endif /* CURL_DISABLE_FTP */