From: Daniel Stenberg Date: Fri, 16 May 2025 22:17:11 +0000 (+0200) Subject: tool_operate: when retrying, only truncate regular files X-Git-Tag: curl-8_14_0~62 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=99f5c5c79485f65ea68bcb6df72582fae67e0a20;p=thirdparty%2Fcurl.git tool_operate: when retrying, only truncate regular files If /dev/null or another character device etc is used for output, trying to truncate that only causes errors. Add test 1497 to verify Fixes #17371 Reported-by: Brendan Dolan-Gavitt Closes #17374 --- diff --git a/src/tool_operate.c b/src/tool_operate.c index b533e62574..91b3e97ac9 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -587,37 +587,49 @@ static CURLcode post_per_transfer(struct GlobalConfig *global, if(per->retry_sleep > RETRY_SLEEP_MAX) per->retry_sleep = RETRY_SLEEP_MAX; } + if(outs->bytes && outs->filename && outs->stream) { - /* We have written data to an output file, we truncate file - */ - notef(config->global, - "Throwing away %" CURL_FORMAT_CURL_OFF_T " bytes", - outs->bytes); - fflush(outs->stream); - /* truncate file at the position where we started appending */ +#ifndef __MINGW32CE__ + struct_stat fileinfo; + + /* The output can be a named pipe or a character device etc that + cannot be truncated. Only truncate regular files. */ + if(!fstat(fileno(outs->stream), &fileinfo) && + S_ISREG(fileinfo.st_mode)) +#else + /* Windows CE's fileno() is bad so just skip the check */ +#endif + { + /* We have written data to an output file, we truncate file */ + fflush(outs->stream); + notef(config->global, + "Throwing away %" CURL_FORMAT_CURL_OFF_T " bytes", + outs->bytes); + /* truncate file at the position where we started appending */ #if defined(HAVE_FTRUNCATE) && !defined(__DJGPP__) && !defined(__AMIGA__) && \ !defined(__MINGW32CE__) - if(ftruncate(fileno(outs->stream), outs->init)) { - /* when truncate fails, we cannot just append as then we will - create something strange, bail out */ - errorf(config->global, "Failed to truncate file"); - return CURLE_WRITE_ERROR; - } - /* now seek to the end of the file, the position where we - just truncated the file in a large file-safe way */ - rc = fseek(outs->stream, 0, SEEK_END); + if(ftruncate(fileno(outs->stream), outs->init)) { + /* when truncate fails, we cannot just append as then we will + create something strange, bail out */ + errorf(config->global, "Failed to truncate file"); + return CURLE_WRITE_ERROR; + } + /* now seek to the end of the file, the position where we + just truncated the file in a large file-safe way */ + rc = fseek(outs->stream, 0, SEEK_END); #else - /* ftruncate is not available, so just reposition the file - to the location we would have truncated it. This will not - work properly with large files on 32-bit systems, but - most of those will have ftruncate. */ - rc = fseek(outs->stream, (long)outs->init, SEEK_SET); + /* ftruncate is not available, so just reposition the file + to the location we would have truncated it. This will not + work properly with large files on 32-bit systems, but + most of those will have ftruncate. */ + rc = fseek(outs->stream, (long)outs->init, SEEK_SET); #endif - if(rc) { - errorf(config->global, "Failed seeking to end of file"); - return CURLE_WRITE_ERROR; + if(rc) { + errorf(config->global, "Failed seeking to end of file"); + return CURLE_WRITE_ERROR; + } + outs->bytes = 0; /* clear for next round */ } - outs->bytes = 0; /* clear for next round */ } *retryp = TRUE; per->num_retries++; diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 33ba9b5b17..c718b44615 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -196,7 +196,7 @@ test1460 test1461 test1462 test1463 test1464 test1465 test1466 test1467 \ test1468 test1469 test1470 test1471 test1472 test1473 test1474 test1475 \ test1476 test1477 test1478 test1479 test1480 test1481 test1482 test1483 \ test1484 test1485 test1486 test1487 test1488 test1489 test1490 test1491 \ -test1492 test1493 test1494 test1495 test1496 \ +test1492 test1493 test1494 test1495 test1496 test1497 \ \ test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \ test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \ diff --git a/tests/data/test1497 b/tests/data/test1497 new file mode 100644 index 0000000000..94b19a2514 --- /dev/null +++ b/tests/data/test1497 @@ -0,0 +1,61 @@ + + + +HTTP +HTTP GET +retry + + +# +# Server-side + + +HTTP/1.1 503 BAD swsbounce +Date: Tue, 09 Nov 2010 14:49:00 GMT +Content-Length: 21 + +server not available + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Content-Length: 3 +Connection: close + +ok + + + + +# +# Client-side + + +http + + +HTTP GET --retry on 503 error with output to /dev/null + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --retry 3 -o /dev/null + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + + +