From 02679fe33545ad9a6e09f05c76b429f54c152bd9 Mon Sep 17 00:00:00 2001 From: TapTap Date: Sun, 6 Sep 2026 19:35:28 +0200 Subject: [PATCH] docs: clarify --del alias, early keep-set caps, ACK wait, --no-delete conflict Usage help now gives --delete-during a complete description with --del on its own line, and notes that timing flags imply --delete while timing+--no-delete is rejected regardless of argument order. RSYNC_COMPAT.md documents: the receiver's MAX_MANIFEST_ENTRIES/MAX_MANIFEST_BYTES caps now abort an early-mode run before any data (previously only the deletion step failed), the extended early-delete ACK deadline, and the order-independent flag-conflict policy. --- RSYNC_COMPAT.md | 24 ++++++++++++++++++++++++ src/client/usage.c | 11 +++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/RSYNC_COMPAT.md b/RSYNC_COMPAT.md index 0d2544e..5526c39 100644 --- a/RSYNC_COMPAT.md +++ b/RSYNC_COMPAT.md @@ -129,6 +129,30 @@ manifest ack. `--delete-delay` and `--delete-during` are each implemented as the closest safe approximation their engine mode allows; the divergences are noted in the rows above. +Manifest size: the sender's keep-set collection (streaming or early pre-scan) +is unbounded, but the receiver rejects any manifest beyond `MAX_MANIFEST_ENTRIES` +(1 048 576 entries) / `MAX_MANIFEST_BYTES` (16 MB of paths) as a hard protocol +error. In the commit modes this only means the deletion is refused after the +data already arrived; in the NEW early modes (`--delete-before`/`--delete-during`) +the manifest is the first frame, so an oversized keep-set now aborts the whole +transfer BEFORE any data is sent (previously all data transferred and only the +deletion step failed). Keep the source tree small enough for the receiver's +manifest caps when using the early timing. + +Early-delete ACK wait: after committing a large deletion (up to +`MAX_SERVER_DELETE_COUNT` unlinks) the receiver's `STATUS_OK`/`STATUS_ERROR` +reply can legitimately take much longer than a normal round trip, so the sender +waits for that single ACK with an extended explicit deadline (1 hour) instead +of the default 60 s per-message receive window. A receiver that is genuinely +gone still aborts the wait via connection close/error; the extended bound only +protects against aborting after the deletion already committed on the receiver. + +Flag-conflict policy: unlike rsync's last-one-wins behaviour, every deletion +timing flag implies `--delete`, and combining a timing flag with `--no-delete` +(in either argument order) — or more than one timing flag — is rejected as a +configuration error rather than silently resolved. Note the check is +order-independent because it runs over the fully parsed config. + ## 8. Metadata Preservation | Flag | Rsync Description | FastSync Status | Notes | diff --git a/src/client/usage.c b/src/client/usage.c index 5634094..6d18531 100644 --- a/src/client/usage.c +++ b/src/client/usage.c @@ -28,12 +28,15 @@ void print_usage(void) { printf(" transfer has succeeded)\n"); printf(" --delete-before Delete extras before the transfer starts\n"); printf(" (implies --delete)\n"); - printf(" --delete-during Delete extras once the keep-set is known, before\n"); - printf(" --del data is applied (alias --del; implies --delete)\n"); + printf(" --delete-during Delete extras once the keep-set manifest is known,\n"); + printf(" before the data is applied (implies --delete)\n"); + printf(" --del Alias for --delete-during\n"); printf(" --delete-delay Delete extras only after a successful transfer\n"); printf(" (implies --delete)\n"); - printf(" --delete-after Alias of the default --delete timing: delete only\n"); - printf(" after the transfer succeeded (implies --delete)\n"); + printf(" --delete-after Delete only after the whole transfer succeeded\n"); + printf(" (the default --delete timing; implies --delete)\n"); + printf(" Note: each timing flag implies --delete. Combining a timing flag with\n"); + printf(" --no-delete (in either order) is rejected as a config error.\n"); printf(" --ignore-existing Skip files that already exist on receiver\n"); printf(" --delay-updates Put updated files into place only at the end of transfer\n"); printf(" --dirs, -d, --old-dirs, --old-d Transfer the named directory entries without\n");