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.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Parity cycle — no-wire residual burn-down
Closes four achievable rsync-parity gaps from the 157-row matrix, all without a protocol change (
PROTOCOL_VERSIONstays 2.28.0). Matrix: 119 ✅ / 14 ⚠️ / 24 ❌ = 157.Changes
--inc-recursive/--no-inc-recursiveaccepted 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 viarealpath+ boundary-checked prefix).--delete-beforephase-0 (⚠️ → ✅): both the single-threaded and--threadsdata 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 exactuser.rsync.%statkey 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 devicemknodis 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'srsyncd.confgrammar; modules are now read-only by default (matching rsync) withread only = no/write only = yesopting 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
--threadsdelete-before gap,sscanfinteger-overflow UB in the stat parser (now strictstrtoulwith 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.