]> granicus.if.org Git - curl/commitdiff
- CURLOPT_FTP_CREATE_MISSING_DIRS can now be set to 2 in addition to 1 for
authorDaniel Stenberg <daniel@haxx.se>
Tue, 17 Feb 2009 09:07:25 +0000 (09:07 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 17 Feb 2009 09:07:25 +0000 (09:07 +0000)
  plain FTP connections, and it will then allow MKD to fail once and retry the
  CWD afterwards. This is especially useful if you're doing many simultanoes
  connections against the same server and they all have this option enabled,
  as then CWD may first fail but then another connection does MKD before this
  connection and thus MKD fails but trying CWD works! The numbers can
  (should?) now be set with the convenience enums now called
  CURLFTP_CREATE_DIR and CURLFTP_CREATE_DIR_RETRY.

  Tests has proven that if you're making an application that uploads a set of
  files to an ftp server, you will get a noticable gain in speed if you're
  using multiple connections and this option will be then be very useful.

CHANGES
RELEASE-NOTES
docs/libcurl/curl_easy_setopt.3
include/curl/curl.h
lib/ftp.c
lib/url.c
lib/urldata.h
src/main.c

diff --git a/CHANGES b/CHANGES
index 2ad7ca185864f0e49d2fea28281743731b3d64b8..43756b60f34106114e27a87ab28d34c01186b770 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,20 @@
 
                                   Changelog
 
+Daniel Stenberg (17 Feb 2009)
+- CURLOPT_FTP_CREATE_MISSING_DIRS can now be set to 2 in addition to 1 for
+  plain FTP connections, and it will then allow MKD to fail once and retry the
+  CWD afterwards. This is especially useful if you're doing many simultanoes
+  connections against the same server and they all have this option enabled,
+  as then CWD may first fail but then another connection does MKD before this
+  connection and thus MKD fails but trying CWD works! The numbers can
+  (should?) now be set with the convenience enums now called
+  CURLFTP_CREATE_DIR and CURLFTP_CREATE_DIR_RETRY.
+
+  Tests has proven that if you're making an application that uploads a set of
+  files to an ftp server, you will get a noticable gain in speed if you're
+  using multiple connections and this option will be then be very useful.
+
 Daniel Stenberg (14 Feb 2009)
 - Andre Guibert de Bruet found and fixed a memory leak in the content encoding
   code, which could happen on libz errors.
index 59e44263506a80a71a386d62dd5e0bb2327abc09..ebd3c3a420bb94ccb83d825a1627dee795e419ea 100644 (file)
@@ -21,6 +21,8 @@ This release includes the following changes:
  o Added docs/libcurl/symbols-in-versions
  o Added CURLINFO_CONDITION_UNMET
  o Added support for Digest and NTLM authentication using GnuTLS
+ o CURLOPT_FTP_CREATE_MISSING_DIRS can now be set to 2 to retry the CWD even
+   when MKD fails
 
 This release includes the following bugfixes:
 
index e5e35d3d01c86a4efeb9a33cf62f9532e4172c40..59a277d0d6cdc412892f45dcac20ece42881a3ed 100644 (file)
@@ -1103,6 +1103,17 @@ This setting also applies to SFTP-connections. curl will attempt to create
 the remote directory if it can't obtain a handle to the target-location. The
 creation will fail if a file of the same name as the directory to create
 already exists or lack of permissions prevents creation. (Added in 7.16.3)
+
+Starting with 7.19.4, you can also set this value to 2, which will make
+libcurl retry the CWD command again if the subsequent MKD command fails. This
+is especially useful if you're doing many simultanoes connections against the
+same server and they all have this option enabled, as then CWD may first fail
+but then another connection does MKD before this connection and thus MKD fails
+but trying CWD works! 7.19.4 also introduced the \fICURLFTP_CREATE_DIR\fP and
+\fICURLFTP_CREATE_DIR_RETRY\fP enum names for these arguments.
+
+Before version 7.19.4, libcurl will simply ignore arguments set to 2 and act
+as if 1 was selected.
 .IP CURLOPT_FTP_RESPONSE_TIMEOUT
 Pass a long.  Causes curl to set a timeout period (in seconds) on the amount
 of time that the server is allowed to take in order to generate a response
index 3cbf69f7c56eb14b7cb91f23eda917837b23d8aa..69fe45757d82a80e6041b0070021d2b141fbaf7b 100644 (file)
@@ -530,6 +530,17 @@ typedef enum {
   CURLFTPAUTH_LAST /* not an option, never use */
 } curl_ftpauth;
 
+/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */
+typedef enum {
+  CURLFTP_CREATE_DIR_NONE,  /* do NOT create missing dirs! */
+  CURLFTP_CREATE_DIR,       /* (FTP/SFTP) if CWD fails, try MKD and then CWD
+                               again if MKD succeeded, for SFTP this does
+                               similar magic */
+  CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD
+                               again even if MKD failed! */
+  CURLFTP_CREATE_DIR_LAST   /* not an option, never use */
+} curl_ftpcreatedir;
+
 /* parameter for the CURLOPT_FTP_FILEMETHOD option */
 typedef enum {
   CURLFTPMETHOD_DEFAULT,   /* let libcurl pick */
@@ -936,7 +947,10 @@ typedef enum {
      argument */
   CINIT(SSL_CTX_DATA, OBJECTPOINT, 109),
 
-  /* FTP Option that causes missing dirs to be created on the remote server */
+  /* FTP Option that causes missing dirs to be created on the remote server.
+     In 7.19.4 we introduced the convenience enums for this option using the
+     CURLFTP_CREATE_DIR prefix.
+  */
   CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110),
 
   /* Set this to a bitmask value to enable the particular authentications
index f76868f0d69277816118964f43542476a51d5292..08a55a0a4958d56377364508c2b800400430d3de 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -828,7 +828,13 @@ static CURLcode ftp_state_cwd(struct connectdata *conn)
     /* already done and fine */
     result = ftp_state_post_cwd(conn);
   else {
-    ftpc->count2 = 0;
+    ftpc->count2 = 0; /* count2 counts failed CWDs */
+
+    /* count3 is set to allow a MKD to fail once. In the case when first CWD
+       fails and then MKD fails (due to another session raced it to create the
+       dir) this then allows for a second try to CWD to it */
+    ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
+
     if(conn->bits.reuse && ftpc->entrypath) {
       /* This is a re-used connection. Since we change directory to where the
          transfer is taking place, we must first get back to the original dir
@@ -2834,7 +2840,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
       break;
 
     case FTP_MKD:
-      if(ftpcode/100 != 2) {
+      if((ftpcode/100 != 2) && !ftpc->count3--) {
         /* failure to MKD the dir */
         failf(data, "Failed to MKD dir: %03d", ftpcode);
         return CURLE_REMOTE_ACCESS_DENIED;
index 6d5bf42072299362841b9233eb5157c515211891..c16ad97f30cd9cbcfd468b0728e5c9e1d8cc7568 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -922,7 +922,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * An FTP option that modifies an upload to create missing directories on
      * the server.
      */
-    data->set.ftp_create_missing_dirs = (bool)(0 != va_arg(param, long));
+    data->set.ftp_create_missing_dirs = (int)va_arg(param, long);
     break;
   case CURLOPT_FTP_RESPONSE_TIMEOUT:
     /*
index be3f06191c17de6bf5b9f87f33fd10cacb2b5909..d1851066e1d258c1dba1b977075471708b616620 100644 (file)
@@ -1474,6 +1474,10 @@ struct UserDefined {
 
   curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used  */
 
+  int ftp_create_missing_dirs; /* 1 - create directories that don't exist
+                                  2 - the same but also allow MKD to fail once
+                               */
+
 /* Here follows boolean settings that define how to behave during
    this session. They are STATIC, set by libcurl users or at least initially
    and they don't change during operations. */
@@ -1484,7 +1488,6 @@ struct UserDefined {
   bool prefer_ascii;     /* ASCII rather than binary */
   bool ftp_append;       /* append, not overwrite, on upload */
   bool ftp_list_only;    /* switch FTP command for listing directories */
-  bool ftp_create_missing_dirs; /* create directories that don't exist */
   bool ftp_use_port;     /* use the FTP PORT command */
   bool hide_progress;    /* don't use the progress meter */
   bool http_fail_on_error;  /* fail on HTTP error codes >= 300 */
index 16abdfb7b861d9866a9c0eaa762891f00cf2fc05..958c8b514b45a97de2ed73fdca6222ea99f768f5 100644 (file)
@@ -4753,11 +4753,11 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
 
         /* new in curl 7.10 */
         my_setopt(curl, CURLOPT_ENCODING,
-                         (config->encoding) ? "" : NULL);
+                  (config->encoding) ? "" : NULL);
 
-        /* new in curl 7.10.7 */
+        /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */
         my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
-                         config->ftp_create_dirs);
+                  config->ftp_create_dirs);
         if(config->proxyanyauth)
           my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
         else if(config->proxynegotiate)
@@ -4925,17 +4925,13 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
             }
 
             if(retry) {
-              static const char * const m[]={NULL,
-                                             "timeout",
-                                             "HTTP error",
-                                             "FTP error"
+              static const char * const m[]={
+                NULL, "timeout", "HTTP error", "FTP error"
               };
               warnf(config, "Transient problem: %s "
                     "Will retry in %ld seconds. "
                     "%ld retries left.\n",
-                    m[retry],
-                    retry_sleep/1000,
-                    retry_numretries);
+                    m[retry], retry_sleep/1000, retry_numretries);
 
               go_sleep(retry_sleep);
               retry_numretries--;
@@ -4977,15 +4973,13 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
         } while(1);
 
         if((config->progressmode == CURL_PROGRESS_BAR) &&
-           progressbar.calls) {
+           progressbar.calls)
           /* if the custom progress bar has been displayed, we output a
              newline here */
           fputs("\n", progressbar.out);
-        }
 
-        if(config->writeout) {
+        if(config->writeout)
           ourWriteOut(curl, config->writeout);
-        }
 #ifdef USE_ENVIRONMENT
         if (config->writeenv)
           ourWriteEnv(curl);