A write error outside the fatal class still read as the end of the body - #1417
Open
xroche wants to merge 5 commits into
Open
A write error outside the fatal class still read as the end of the body#1417xroche wants to merge 5 commits into
xroche wants to merge 5 commits into
Conversation
http_xfread1() advances r->size before the fwrite, so a body the failing write happened to complete still satisfied the size test at the bottom and came back as a clean EOF. #1391 stopped that for the fatal class alone; every other write errno was laundered the same way, in back_wait()'s chunk-end test, its classification of a short read and its length check too. The non-fatal class gets a code of its own, STATUSCODE_IO_ERROR, and the four size-based sites test for either class. A close that fails outside the fatal class is reported as well, and no longer leaves a slot claiming a success it never wrote to disk. Closes #1398 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
The decode step writes ~hts-tmp/<name>.u before renaming it into place, and a full disk there was reported as "Error when decompressing": the same fatal error wearing the stream's clothes, with the mirror carrying on. hts_codec_unpack() and hts_zunpack() now leave the local failure's errno behind and clear it for a body the decoder itself refused, so back_finalize() can tell the two apart the way every other write site does. Both closes are checked as well, stdio holding the tail of a small decode until then. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
http_xfread1() discarded fflush()'s return, and glibc's later fclose() returns 0 once that flush has taken the error. A body with no Content-Length and no chunking has no completion test to fall back on, so a failed write went unreported and the file was recorded as mirrored with nothing on disk -- the fatal class included, where not even "Mirror aborted" was printed. back_finalize() gated the decode's write failure on check_fatal_io_errno() where hts_codec_unpack()'s contract is errno != 0, so a non-fatal failure on ~hts-tmp/<name>.u still read as "Error when decompressing". Also pins the statuscode > 0 guard in back_report_write_failure(), which is what keeps a failed decode's copy out of the update purge, and drops a dead ternary in hts_codec_unpack(). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
xroche
enabled auto-merge (squash)
August 24, 2026 22:12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
http_xfread1()advancesr->sizebefore thefwrite, so a body the failing write happened to complete still satisfied the size test at the bottom and came back as a clean EOF. #1391 stopped that for the fatal class alone; the non-fatal class now has a code of its own,STATUSCODE_IO_ERROR, and the four size-based sites inback_wait()test for either. The same function also discardedfflush()'s return, and glibc's laterfclose()reports nothing once that flush has taken the error, so a body with no Content-Length and no chunking (the one shape with no completion test to fall back on) was recorded as mirrored with nothing on disk, the fatal class included. The decode step is the third door onto the same bug:hts_codec_unpack()andhts_zunpack()now leave a local failure's errno behind and clear it for a body the decoder refused, which is whatback_finalize()needs to stop blaming our own disk on the server.Report rather than abort is the call for the non-fatal class, since a full disk means the next file fails too while a broken pipe is about one destination. 350 and 355 cover both classes with controls, and every guard was reverted in turn and reds.
Closes #1398