WebDAV: MOVE with Overwrite: T deletes the destination before renaming (not atomic) #496
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Cordy/Cairn#496
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Status: from source (read at
bd006ef, not reproduced). Unchanged onmain(e1c855d).What happens
In the MOVE/COPY handler (
internal/dav/dav.go:292–336), when the destination exists andOverwriteis notF, the server DELETEs the destination and then renames the source onto it. If the rename then fails — no space, permissions, a crash or restart between the two steps — the destination is already gone and the source has not arrived.Impact
A rename that overwrites an existing file (which sync clients issue when a local rename lands on an already-synced name) can lose the overwritten file on failure, with no copy anywhere.
Suggested fix
For files, rename over the destination directly —
os.Renamereplaces the target atomically on POSIX (andMoveFileExwithMOVEFILE_REPLACE_EXISTINGon Windows). For collections, stage: rename the destination aside, rename the source in, then remove the staged copy, restoring it if the second step fails. Add a fault-injection test.Found while building the cairn-desktop WebDAV client (phase 2, Cordy/cairn-desktop#23). Filed by Claude on behalf of @Cordy.
Shipped in v0.6.169, live on both dogfoods.
What landed in
moveCopy:Overwrite: F→ 412 check.<dst>.cairn-replace-<token>before the operation: on success the staged copy is deleted; on failure it is restored, so a failed MOVE can no longer leave the destination half-deleted or gone.TDD:
move_test.goinjects rename/copy failures via afailOpdriver wrapper and asserts the destination survives — witnessed red first.