tool_cb_hdr: check the etag file write results in save_etag

save_etag() returns CURL_WRITEFUNC_ERROR when the ftruncate/fseek of the
etag file fails, but the subsequent fwrite() and fputc() results were
ignored and the fflush() return was (void)-cast. A write failure after a
successful truncate (a full disk, a quota, or an I/O error) left the
--etag-save file empty or partially written while curl still exited
successfully. A later --etag-compare run then reads the empty validator
and silently loses the conditional request.

Check fwrite/fputc/fflush and return CURL_WRITEFUNC_ERROR on failure, the
same way the truncate failure in the same function is already handled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Rui He 2026-07-18 21:20:41 -04:00
parent 1128177a6f
commit 5241ab5673

View file

@ -273,10 +273,13 @@ static size_t save_etag(const char *etag_h, const char *endp,
toolx_ftruncate(fd, 0)))
return CURL_WRITEFUNC_ERROR;
fwrite(etag_h, 1, etag_length, etag_save->stream);
/* terminate with newline */
fputc('\n', etag_save->stream);
(void)fflush(etag_save->stream);
/* a failed etag write must surface, not be silently discarded */
if(fwrite(etag_h, 1, etag_length, etag_save->stream) != etag_length ||
/* terminate with newline */
fputc('\n', etag_save->stream) == EOF ||
fflush(etag_save->stream)) {
return CURL_WRITEFUNC_ERROR; /* etag write failed */
}
}
}
return 0; /* ok */