David Balazic's patch to make the FTP operations "do right" according to
authorDaniel Stenberg <daniel@haxx.se>
Wed, 30 Apr 2003 16:59:42 +0000 (16:59 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 30 Apr 2003 16:59:42 +0000 (16:59 +0000)
RFC1738, which means it'll use one CWD for each pathpart.

lib/ftp.c

index 25806a45f62312fee99cfc80518659dc237f5a1d..aa96871cbf2944a2a9fff926b3e6c46199c5ba07 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1967,10 +1967,13 @@ CURLcode ftp_perform(struct connectdata *conn,
       return result;
   }
 
-  /* change directory first! */
-  if(ftp->dir && ftp->dir[0]) {
-    if ((result = ftp_cwd(conn, ftp->dir)) != CURLE_OK)
+  {
+    int i; /* counter for loop */
+    for (i=0; ftp->dirs[i]; i++) {
+      /* RFC 1738 says empty components should be respected too */
+      if ((result = ftp_cwd(conn, ftp->dirs[i])) != CURLE_OK)
         return result;
+    }
   }
 
   /* Requested time of file or time-depended transfer? */
@@ -2091,34 +2094,64 @@ CURLcode ftp_perform(struct connectdata *conn,
  */
 CURLcode Curl_ftp(struct connectdata *conn)
 {
-  CURLcode retcode;
+  CURLcode retcode=CURLE_OK;
   bool connected=0;
 
   struct SessionHandle *data = conn->data;
   struct FTP *ftp;
-  int dirlength=0; /* 0 forces strlen() */
+
+  char *slash_pos;  /* position of the first '/' char in curpos */
+  char *cur_pos=conn->ppath; /* current position in ppath. point at the begin
+                                of next path component */
+  int path_part=0;/* current path component */
 
   /* the ftp struct is already inited in ftp_connect() */
   ftp = conn->proto.ftp;
   conn->size = -1; /* make sure this is unknown at this point */
 
-  /* We split the path into dir and file parts *before* we URLdecode
-     it */
-  ftp->file = strrchr(conn->ppath, '/');
-  if(ftp->file) {
-    if(ftp->file != conn->ppath)
-      dirlength=ftp->file-conn->ppath; /* don't count the traling slash */
+  /*  fixed : initialize ftp->dirs[xxx] to NULL !
+      is done in Curl_ftp_connect() */
 
-    ftp->file++; /* point to the first letter in the file name part or
-                    remain NULL */
-  }
-  else {
-    ftp->file = conn->ppath; /* there's only a file part */
+  /* parse the URL path into separate path components */
+  while((slash_pos=strchr(cur_pos, '/'))) {
+    /* seek out the next path component */
+    if (0 == slash_pos-cur_pos)  /* empty path component, like "x//y" */
+      ftp->dirs[path_part] = strdup(""); /* empty string */
+    else
+      ftp->dirs[path_part] = curl_unescape(cur_pos,slash_pos-cur_pos);
+    
+    if (!ftp->dirs[path_part]) { /* run out of memory ... */
+      failf(data, "no memory");
+      retcode = CURLE_OUT_OF_MEMORY;
+    }
+    else {
+      cur_pos = slash_pos + 1; /* jump to the rest of the string */
+      if(++path_part >= CURL_MAX_FTP_DIRDEPTH) {
+        /* too deep */
+        failf(data, "too deep dir hierarchy");
+        retcode = CURLE_URL_MALFORMAT;
+      }
+    }
+    if (retcode) {
+      int i;
+      for (i=0;i<path_part;i++) { /* free previous parts */
+        free(ftp->dirs[i]);
+        ftp->dirs[i]=NULL;
+      }
+      return retcode; /* failure */
+    }
   }
 
+  ftp->file = cur_pos;  /* the rest is the file name */
+
   if(*ftp->file) {
     ftp->file = curl_unescape(ftp->file, 0);
     if(NULL == ftp->file) {
+      int i;
+      for (i=0;i<path_part;i++){
+        free(ftp->dirs[i]);
+        ftp->dirs[i]=NULL;
+      }
       failf(data, "no memory");
       return CURLE_OUT_OF_MEMORY;
     }
@@ -2126,20 +2159,7 @@ CURLcode Curl_ftp(struct connectdata *conn)
   else
     ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
                        pointer */
-
-  ftp->urlpath = conn->ppath;
-  if(dirlength) {
-    ftp->dir = curl_unescape(ftp->urlpath, dirlength);
-    if(NULL == ftp->dir) {
-      if(ftp->file)
-        free(ftp->file);
-      failf(data, "no memory");
-      return CURLE_OUT_OF_MEMORY; /* failure */
-    }
-  }
-  else
-    ftp->dir = NULL;
-
+  
   retcode = ftp_perform(conn, &connected);
 
   if(CURLE_OK == retcode) {
@@ -2219,6 +2239,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
 CURLcode Curl_ftp_disconnect(struct connectdata *conn)
 {
   struct FTP *ftp= conn->proto.ftp;
+  int i;
 
   /* The FTP session may or may not have been allocated/setup at this point! */
   if(ftp) {
@@ -2228,10 +2249,12 @@ CURLcode Curl_ftp_disconnect(struct connectdata *conn)
       free(ftp->cache);
     if(ftp->file)
       free(ftp->file);
-    if(ftp->dir)
-      free(ftp->dir);
+    for (i=0;ftp->dirs[i];i++){
+      free(ftp->dirs[i]);
+      ftp->dirs[i]=NULL;
+    }
 
-    ftp->file = ftp->dir = NULL; /* zero */
+    ftp->file = NULL; /* zero */
   }
   return CURLE_OK;
 }