From: Daniel Stenberg Date: Tue, 30 May 2023 11:59:17 +0000 (+0200) Subject: curl: count uploaded data to stop at the originally given size X-Git-Tag: curl-8_2_0~169 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1f85420a2877ea75b6bafc8aa58aa5b146fc118b;p=thirdparty%2Fcurl.git curl: count uploaded data to stop at the originally given size Closes #11223 Fixes #11222 Reported-by: JustAnotherArchivist on github --- diff --git a/src/tool_cb_rea.c b/src/tool_cb_rea.c index 401e32077a..d70a9b9091 100644 --- a/src/tool_cb_rea.c +++ b/src/tool_cb_rea.c @@ -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 */ @@ -45,12 +46,18 @@ 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; diff --git a/src/tool_cb_see.c b/src/tool_cb_see.c index 93a84e9e4c..fd34456828 100644 --- a/src/tool_cb_see.c +++ b/src/tool_cb_see.c @@ -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. */ diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index ec5698ba27..2031bd9268 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -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 */ diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index f54622c74a..9609dcdb73 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -26,7 +26,6 @@ #include "tool_setup.h" #include "tool_sdecls.h" #include "tool_urlglob.h" -#include "tool_formparse.h" struct GlobalConfig; diff --git a/src/tool_operate.c b/src/tool_operate.c index cf85fe3a27..1c49c1e4ef 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -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); { diff --git a/src/tool_operate.h b/src/tool_operate.h index 1d333e2499..21a7f929d0 100644 --- a/src/tool_operate.h +++ b/src/tool_operate.h @@ -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; diff --git a/src/tool_sdecls.h b/src/tool_sdecls.h index 8223d6831a..7c03a04a57 100644 --- a/src/tool_sdecls.h +++ b/src/tool_sdecls.h @@ -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