]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
curl: count uploaded data to stop at the originally given size
authorDaniel Stenberg <daniel@haxx.se>
Tue, 30 May 2023 11:59:17 +0000 (13:59 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 1 Jun 2023 11:43:28 +0000 (13:43 +0200)
Closes #11223
Fixes #11222
Reported-by: JustAnotherArchivist on github
src/tool_cb_rea.c
src/tool_cb_see.c
src/tool_cfgable.c
src/tool_cfgable.h
src/tool_operate.c
src/tool_operate.h
src/tool_sdecls.h

index 401e32077a29a0608112fd7244fedcef20a78b5a..d70a9b90914d0c7d4941c863226856917c906a10 100644 (file)
@@ -35,6 +35,7 @@
 #include "tool_cb_rea.h"
 #include "tool_operate.h"
 #include "tool_util.h"
+#include "tool_msgs.h"
 
 #include "memdebug.h" /* keep this as LAST include */
 
 size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
 {
   ssize_t rc = 0;
-  struct InStruct *in = userdata;
-  struct OperationConfig *config = in->config;
+  struct per_transfer *per = userdata;
+  struct OperationConfig *config = per->config;
+
+  if((per->uploadfilesize != -1) &&
+     (per->uploadedsofar == per->uploadfilesize)) {
+    /* done */
+    return 0;
+  }
 
   if(config->timeout_ms) {
     struct timeval now = tvnow();
-    long msdelta = tvdiff(now, in->per->start);
+    long msdelta = tvdiff(now, per->start);
 
     if(msdelta > config->timeout_ms)
       /* timeout */
@@ -68,24 +75,33 @@ size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
       timeout.tv_usec = (int)((wait%1000)*1000);
 
       FD_ZERO(&bits);
-      FD_SET(in->fd, &bits);
-      if(!select(in->fd + 1, &bits, NULL, NULL, &timeout))
+      FD_SET(per->infd, &bits);
+      if(!select(per->infd + 1, &bits, NULL, NULL, &timeout))
         return 0; /* timeout */
     }
 #endif
   }
 
-  rc = read(in->fd, buffer, sz*nmemb);
+  rc = read(per->infd, buffer, sz*nmemb);
   if(rc < 0) {
     if(errno == EAGAIN) {
       errno = 0;
-      in->config->readbusy = TRUE;
+      config->readbusy = TRUE;
       return CURL_READFUNC_PAUSE;
     }
     /* since size_t is unsigned we can't return negative values fine */
     rc = 0;
   }
-  in->config->readbusy = FALSE;
+  if((per->uploadfilesize != -1) &&
+     (per->uploadedsofar + rc > per->uploadfilesize)) {
+    /* do not allow uploading more than originally set out to do */
+    curl_off_t delta = per->uploadedsofar + rc - per->uploadfilesize;
+    warnf(per->config->global, "File size larger in the end than when "
+          "started. Dropping at least %" CURL_FORMAT_CURL_OFF_T " bytes",
+          delta);
+    rc = (ssize_t)(per->uploadfilesize - per->uploadedsofar);
+  }
+  config->readbusy = FALSE;
 
   /* when select() returned zero here, it timed out */
   return (size_t)rc;
index 93a84e9e4c4f84b94168d49774ee25a81b095bd1..fd3445682800bea8d02467748b96d7f4b0fca3c9 100644 (file)
@@ -28,6 +28,7 @@
 #include "curlx.h"
 
 #include "tool_cfgable.h"
+#include "tool_operate.h"
 #include "tool_cb_see.h"
 
 #include "memdebug.h" /* keep this as LAST include */
@@ -48,7 +49,7 @@
 
 int tool_seek_cb(void *userdata, curl_off_t offset, int whence)
 {
-  struct InStruct *in = userdata;
+  struct per_transfer *per = userdata;
 
 #if(SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
 
@@ -81,7 +82,7 @@ int tool_seek_cb(void *userdata, curl_off_t offset, int whence)
   }
 #endif
 
-  if(LSEEK_ERROR == lseek(in->fd, offset, whence))
+  if(LSEEK_ERROR == lseek(per->infd, offset, whence))
     /* couldn't rewind, the reason is in errno but errno is just not portable
        enough and we don't actually care that much why we failed. We'll let
        libcurl know that it may try other means if it wants to. */
index ec5698ba27cd31e929e48125392959b0ac858a62..2031bd926862b33cc9224773b29197adee1de631 100644 (file)
@@ -24,6 +24,7 @@
 #include "tool_setup.h"
 
 #include "tool_cfgable.h"
+#include "tool_formparse.h"
 #include "tool_main.h"
 
 #include "memdebug.h" /* keep this as LAST include */
index f54622c74ab4ca64eee5b97b028cfe66cb81b0fc..9609dcdb7373f66beab87c7d20edc08f52fa7767 100644 (file)
@@ -26,7 +26,6 @@
 #include "tool_setup.h"
 #include "tool_sdecls.h"
 #include "tool_urlglob.h"
-#include "tool_formparse.h"
 
 struct GlobalConfig;
 
index cf85fe3a271dd01b3f03f86968812b9017ea8ecb..1c49c1e4efee9dffdb655324a56e4d060d97feea 100644 (file)
@@ -327,8 +327,8 @@ static CURLcode pre_transfer(struct GlobalConfig *global,
 #endif
       my_setopt(per->curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
     }
-    per->input.fd = per->infd;
   }
+  per->uploadfilesize = uploadfilesize;
   per->start = tvnow();
   return result;
 }
@@ -845,7 +845,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
       if(state->up < state->infilenum) {
         struct per_transfer *per = NULL;
         struct OutStruct *outs;
-        struct InStruct *input;
         struct OutStruct *heads;
         struct OutStruct *etag_save;
         struct HdrCbData *hdrcbdata = NULL;
@@ -1004,7 +1003,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
         hdrcbdata = &per->hdrcbdata;
 
         outs = &per->outs;
-        input = &per->input;
 
         per->outfile = NULL;
         per->infdopen = FALSE;
@@ -1274,9 +1272,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
         /* what call to write */
         my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
 
-        /* for uploads */
-        input->config = config;
-        input->per = per;
         /* Note that if CURLOPT_READFUNCTION is fread (the default), then
          * lib/telnet.c will Curl_poll() on the input file descriptor
          * rather than calling the READFUNCTION at regular intervals.
@@ -1284,13 +1279,13 @@ static CURLcode single_transfer(struct GlobalConfig *global,
          * behavior, by omitting to set the READFUNCTION & READDATA options,
          * have not been determined.
          */
-        my_setopt(curl, CURLOPT_READDATA, input);
+        my_setopt(curl, CURLOPT_READDATA, per);
         /* what call to read */
         my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
 
         /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
            CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
-        my_setopt(curl, CURLOPT_SEEKDATA, input);
+        my_setopt(curl, CURLOPT_SEEKDATA, per);
         my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
 
         {
index 1d333e2499289acef0d29cbfc3c03af7280cbe65..21a7f929d02b42317b81a2548bf91755fc693db4 100644 (file)
@@ -50,7 +50,6 @@ struct per_transfer {
   struct OutStruct outs;
   struct OutStruct heads;
   struct OutStruct etag_save;
-  struct InStruct input;
   struct HdrCbData hdrcbdata;
   long num_headers;
   bool was_last_header_empty;
@@ -68,6 +67,8 @@ struct per_transfer {
   curl_off_t dlnow;
   curl_off_t ultotal;
   curl_off_t ulnow;
+  curl_off_t uploadfilesize; /* expected total amount */
+  curl_off_t uploadedsofar; /* amount delivered from the callback */
   bool dltotal_added; /* if the total has been added from this */
   bool ultotal_added;
 
index 8223d6831a2221096e644ce5706711d8d930a38d..7c03a04a5766a4c87f455b49a9c2db93c7034973 100644 (file)
@@ -70,24 +70,6 @@ struct OutStruct {
   curl_off_t init;
 };
 
-
-/*
- * InStruct variables keep track of information relative to curl's
- * input reading, which may take place from stdin or from some file.
- *
- * 'fd' member is either 'stdin' file descriptor number STDIN_FILENO
- * or a file descriptor as returned from an 'open' call for some file.
- *
- * 'config' member is a pointer to associated 'OperationConfig' struct.
- */
-
-struct InStruct {
-  int fd;
-  struct OperationConfig *config;
-  struct per_transfer *per;
-};
-
-
 /*
  * A linked list of these 'getout' nodes contain URL's to fetch,
  * as well as information relative to where URL contents should