From 76ccceba5be8163f84575226db2a7374bdaf984d Mon Sep 17 00:00:00 2001 From: Emanuele Torre Date: Sat, 21 Oct 2023 19:54:29 +0200 Subject: [PATCH] tool/-T: perform non-chunked transfer for stdin if it is a regular file curl will now also compute the content-length of the transfer if stdin is the file to upload and stdin is a regular file, using its file size. Since, while being a regular file, stdin could not have its offset at the start of the file, curl will now also get the current offset into the upload file's file descriptor and use (filesize - offset) as content-length for transfer instead of just using the full filesize. This also fixes a bug on BSDs where open("/dev/fd/N") behaves like dup(N), so, if N is a file descriptor to a regular file, the file offset of the file descriptor returned by open() may not have been at the start of the file despite curl's previous assumption. Since I don't know anything about VMS systems, I left the behaviour for VMS unchanged; on VMS, curl will still perform a chunked transfer if the upload file is stdin. Fixes #12171 Fixes #12177 --- src/tool_operate.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/tool_operate.c b/src/tool_operate.c index 2c7d88a71044ce..a443cd0d2e8e15 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -269,6 +269,7 @@ static CURLcode pre_transfer(struct GlobalConfig *global, struct_stat fileinfo; CURLcode result = CURLE_OK; +#ifdef __VMS if(per->uploadfile && !stdin_upload(per->uploadfile)) { /* VMS Note: * @@ -284,7 +285,6 @@ static CURLcode pre_transfer(struct GlobalConfig *global, * header for VARIABLE header files only the bare record data needs * to be considered with one appended if implied CC */ -#ifdef __VMS /* Calculate the real upload size for VMS */ per->infd = -1; if(stat(per->uploadfile, &fileinfo) == 0) { @@ -302,6 +302,8 @@ static CURLcode pre_transfer(struct GlobalConfig *global, } if(per->infd == -1) #else + if(per->uploadfile) { + if(!stdin_upload(per->uploadfile)) per->infd = open(per->uploadfile, O_RDONLY | O_BINARY); if((per->infd == -1) || fstat(per->infd, &fileinfo)) #endif @@ -317,7 +319,22 @@ static CURLcode pre_transfer(struct GlobalConfig *global, /* we ignore file size for char/block devices, sockets, etc. */ if(S_ISREG(fileinfo.st_mode)) +#ifdef __VMS uploadfilesize = fileinfo.st_size; +#else + { + /* When the upload file is stdin, or when the upload file is + /dev/std{in,out,err} or /dev/fd/N on BSDs, the offset may not + be 0 */ + off_t offset = lseek(per->infd, 0, SEEK_CUR); + if(offset >= 0) + uploadfilesize = fileinfo.st_size - offset; + else { + warnf(global, "Can't get file position of file descriptor %d ('%s')", + per->infd, per->uploadfile); + } + } +#endif #ifdef DEBUGBUILD /* allow dedicated test cases to override */