feat: parity burn-down — inc-recursive, temp-dir, delete-before, fake-super, devices, daemon config #309

Merged
TapTap merged 15 commits from feat/parity-next into dev 2026-09-22 23:33:21 +02:00
Owner

Parity cycle — no-wire residual burn-down

Closes four achievable rsync-parity gaps from the 157-row matrix, all without a protocol change (PROTOCOL_VERSION stays 2.28.0). Matrix: 119 ✅ / 14 ⚠️ / 24 ❌ = 157.

Changes

  • --inc-recursive/--no-inc-recursive accepted as inert no-ops (❌ → ✅): FastSync's full scan is rsync's --no-inc-recursive; the destination is identical.
  • --temp-dir/-T: an absolute path that canonicalizes inside the receive root is now accepted (❌ narrowed, out-of-root stays rejected — the confinement invariant holds via realpath + boundary-checked prefix).
  • --delete-before phase-0 (⚠️ → ✅): both the single-threaded and --threads data passes now replay the pre-scan file list instead of re-scanning, so a source file created after the pre-scan is neither transferred nor kept — matching rsync's single file list (parametrized differential test, single-threaded vs --threads=4).
  • --fake-super (❌ → ⚠️): writes/reads rsync 3.4.1's exact user.rsync.%stat key and <octal-mode> <rdev_major>,<rdev_minor> <uid>:<gid> grammar; regular files and char/block devices (faked as regular files carrying the real rdev) interoperate with real rsync both ways. Still never real-chowns.
  • --devices (❌ → ⚠️): a failed device mknod is now a per-entry failure that logs, continues the remaining files, and ends non-OK — like rsync's partial (23) behavior.
  • --config/--dparam: accept a practical subset of rsync's rsyncd.conf grammar; modules are now read-only by default (matching rsync) with read only = no/write only = yes opting in, and every accepted-but-unenforced access-control key emits a startup WARN.

Review follow-ups (fixed before merge)

Two independent reviews found and we fixed: the fake-super device-node regression, the --threads delete-before gap, sscanf integer-overflow UB in the stat parser (now strict strtoul with range checks), and the rsync read-only default. Test hygiene (non-setpriv coverage for the device error path, stronger temp-dir assertions) was also tightened.

Verification

Strict -Werror, clang-format 18, cppcheck clean; unit 45/45 (ASan/UBSan/valgrind); integration 898 passed; differential parity 62 passed; README-consistency 3 passed. Tally arithmetic verified by parsing the rows: 119/14/24 = 157.

## Parity cycle — no-wire residual burn-down Closes four achievable rsync-parity gaps from the 157-row matrix, all without a protocol change (`PROTOCOL_VERSION` stays 2.28.0). Matrix: **119 ✅ / 14 ⚠️ / 24 ❌ = 157**. ### Changes - **`--inc-recursive`/`--no-inc-recursive`** accepted as inert no-ops (❌ → ✅): FastSync's full scan is rsync's `--no-inc-recursive`; the destination is identical. - **`--temp-dir`/`-T`**: an absolute path that canonicalizes **inside** the receive root is now accepted (❌ narrowed, out-of-root stays rejected — the confinement invariant holds via `realpath` + boundary-checked prefix). - **`--delete-before` phase-0 (⚠️ → ✅)**: both the single-threaded and `--threads` data passes now replay the pre-scan file list instead of re-scanning, so a source file created after the pre-scan is neither transferred nor kept — matching rsync's single file list (parametrized differential test, single-threaded vs `--threads=4`). - **`--fake-super` (❌ → ⚠️)**: writes/reads rsync 3.4.1's exact `user.rsync.%stat` key and `<octal-mode> <rdev_major>,<rdev_minor> <uid>:<gid>` grammar; regular files and char/block devices (faked as regular files carrying the real rdev) interoperate with real rsync both ways. Still never real-chowns. - **`--devices` (❌ → ⚠️)**: a failed device `mknod` is now a per-entry failure that logs, continues the remaining files, and ends non-OK — like rsync's partial (23) behavior. - **`--config`/`--dparam`**: accept a practical subset of rsync's `rsyncd.conf` grammar; modules are now **read-only by default** (matching rsync) with `read only = no`/`write only = yes` opting in, and every accepted-but-unenforced access-control key emits a startup WARN. ### Review follow-ups (fixed before merge) Two independent reviews found and we fixed: the fake-super device-node regression, the `--threads` delete-before gap, `sscanf` integer-overflow UB in the stat parser (now strict `strtoul` with range checks), and the rsync read-only default. Test hygiene (non-setpriv coverage for the device error path, stronger temp-dir assertions) was also tightened. ### Verification Strict `-Werror`, clang-format 18, cppcheck clean; unit 45/45 (ASan/UBSan/valgrind); integration **898 passed**; differential parity **62 passed**; README-consistency **3 passed**. Tally arithmetic verified by parsing the rows: 119/14/24 = 157.
TapTap added 15 commits 2026-09-22 23:28:06 +02:00
# Conflicts:
#	RSYNC_COMPAT.md
# Conflicts:
#	RSYNC_COMPAT.md
docs: reconcile RSYNC_COMPAT for parity-next review follow-ups
CI / lint (pull_request) Successful in 1m46s
CI / parity-full (pull_request) Skipped
CI / sanitizers (address) (pull_request) Skipped
CI / sanitizers (undefined) (pull_request) Skipped
CI / fuzz-build (pull_request) Skipped
CI / coverage (pull_request) Skipped
CI / valgrind (pull_request) Skipped
CI / parity-fast (pull_request) Successful in 17s
CI / build-and-test (pull_request) Successful in 54s
4f945a8e39
TapTap merged commit 3ae7685655 into dev 2026-09-22 23:33:21 +02:00
TapTap deleted branch feat/parity-next 2026-09-22 23:33:21 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: TapTap/FastSync#309