feat: --append / --append-verify tail-only resume

Implement rsync's append modes: when an existing destination file is SHORTER
than the source, the receiver negotiates a resume offset and only the tail is
transferred; the full file (retained prefix + tail) is rebuilt and installed
through the normal atomic store path, so the result is byte-identical to the
source whenever the prefix matches.

- --append: sends the tail without content-verifying the retained prefix
  (rsync parity; the documented prefix-trust risk).
- --append-verify: verifies the retained prefix against the source's prefix
  xxHash64 before appending and, on a mismatch, falls back to a clean full
  transfer (never a corrupt prefix+tail blend).

New wire frames STATUS_APPEND / STATUS_APPEND_SIG / STATUS_APPEND_OK /
STATUS_APPEND_DATA; PROTOCOL_VERSION bumped 2.9.0 -> 2.10.0 (peers must match).
Both flags imply --incremental and are incompatible with -s (chunk
serialization) and --whole-file (rejected up front). Respects --inplace,
--partial/--partial-dir and --delay-updates via the shared store engine.
This commit is contained in:
2026-09-07 15:43:29 +02:00
parent 6701c103cb
commit 6ad3887aa1
11 changed files with 470 additions and 51 deletions
+12
View File
@@ -531,3 +531,15 @@ char* path_cat(const char* path1, const char* path2) {
new_path[path1_len + path2_len + 1] = '\0';
return new_path;
}
bool append_resume_eligible(unsigned long long old_size, unsigned long long check_size) {
return old_size < check_size;
}
bool append_tail_length(unsigned long long old_size, unsigned long long check_size,
unsigned long long* tail_out) {
if (!tail_out || !append_resume_eligible(old_size, check_size))
return false;
*tail_out = check_size - old_size;
return true;
}