fix: flush and unmount even when the sync is interrupted
Build and publish container / build (pull_request) Canceled after 2m10s

rsync itself is safe under interruption. It writes to a hidden temporary file
and renames it into place only once complete, and by default deletes any
partial file when interrupted -- verified both in the manual and by killing a
transfer and inspecting what was left, which was nothing. --partial is
deliberately absent and there is now a test asserting it stays that way. An
unclean kill can leave a hidden .track.mp3.XXXXXX behind; it is unplayable, it
is not in the source, and the next run's --delete removes it.

The script was not safe. Ctrl-C killed it before the sync and the unmount,
leaving a journal-less FAT filesystem holding dirty buffers -- which is the
exact corruption the script exists to prevent, arrived at by the most likely
route a person would take.

INT and TERM are now trapped. Both the normal path and the interrupt path call
the same finish function, so the flush and the unmount cannot drift apart, and
an interrupted run exits 130 rather than pretending to have succeeded.

The test is structural rather than timed. Reproducing a mid-transfer signal
needs a payload large enough to be slow, and a test that depends on winning a
race is a test that fails in CI for reasons that have nothing to do with the
code. The behaviour was verified by hand: SIGTERM mid-transfer gave exit 130,
the flush ran, and the destination held no short files and no leftover
temporaries.
This commit is contained in:
Emma Thorpe
2026-08-25 12:51:42 +01:00
parent d6ef70922c
commit 8228c81b5c
3 changed files with 78 additions and 13 deletions
+21
View File
@@ -185,6 +185,27 @@ is what a percentage and an estimate that mean something cost — and renders th
rest itself. Piped to a log it prints a plain line every thirty seconds
instead, with no carriage returns, and a summary at the end either way.
### If the sync is interrupted
No partially copied track is ever left under a name Rockbox would play. rsync
writes to a hidden temporary file and only renames it into place once the file
is complete, and *"by default, rsync will delete any partially transferred file
if the transfer is interrupted"*. `--partial` is deliberately not used, and
there is a test asserting it never will be.
After an unclean kill or a power cut a hidden `.track.mp3.XXXXXX` can survive.
It is not playable, it is not in the source, and the next run's `--delete`
removes it.
The real risk is not rsync's, it is the filesystem's: FAT32 has no journal, so
buffers that never reach the card are corruption. The script therefore traps
`INT` and `TERM` and still flushes and unmounts on the way out, exiting 130.
Both the normal path and the interrupt path call the same function, so they
cannot drift apart.
The one case nothing can help with is pulling the cable or the card mid-write.
Wait for the unmount.
### Making it faster over a network mount
The transfer is metadata-bound, not throughput-bound: 49,600 files means 49,600