Skip to content

A re-fetch that never gets a response truncates the mirrored file to zero on macOS #748

Description

@xroche

On the macOS CI runner, a re-fetch whose connection dies before the status line arrives overwrites the mirrored file with zero bytes. The same crawl on Linux leaves the previous copy alone.

Seen in run 30220185765 (job "build (macOS arm64, clang)"), on a fixture that serves /changes/reset.bin in full on the first fetch and, on every fetch after that, closes the connection without answering. The change report for pass 2 puts the file under changed with:

{ "url": ".../changes/reset.bin", "file": "127.0.0.1_50718/changes/reset.bin", "size": 0, "previous_size": 2062 }

size is a plain fsize_utf8() of the path after the crawl, so the 2062 bytes pass 1 mirrored are gone and a zero-length file is in their place. Three attempts (--retries=2) all failed, so nothing was ever received to write.

The suspect is the save gate in htscore.c (around the "An empty body must not overwrite the file when the transfer failed" comment): it lets a zero-length body through on r.size == 0 && r.statuscode > 0. If the Darwin socket path leaves a positive status code behind on a connection that produced no response, filesave() runs and truncates. I have not reproduced it locally, so which of the two differs, the status code or the body pointer, is still open.

Related to #746 and to the #562 family: a failed re-fetch must not damage the copy it failed to refresh. This one destroys the bytes directly rather than through the purge.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions