fix(fs): recreate empty dirs, replace blocking file; -R --no-implied-dirs implied parents
- Recursive scans emit a directory entry for every traversed directory that produced no transferred child, so empty source dirs (and dirs emptied by filtering) are recreated like rsync; -m prunes them, --files-from/--list-only never emit implicit dirs. - A directory entry now replaces a destination regular file (rsync removes the non-directory) instead of aborting; confined to the secure parent fd. - -R --no-implied-dirs --files-from: stop refusing a listed file whose parent is not listed; create the implied parent with default attributes (no source metadata is captured for it), matching rsync 3.4.1. - Differential gate: drop min_size/empty_dirs_recursive/dirs_plain allowlist entries (dirs_plain now hands FastSync the same trailing-slash source as rsync); add differential test for the files-from implied parent. - Docs: -d row -> Parity, tally 108/24/24. No wire change (PROTOCOL_VERSION stays 2.26.0).
This commit is contained in:
@@ -25,40 +25,6 @@ re-triaged when the row moves.
|
||||
|
||||
# case id -> {aspect: "reason (ref: RSYNC_COMPAT.md ...)"}
|
||||
CAVEATS = {
|
||||
# A source subtree whose only files are all filtered out (here, by
|
||||
# --min-size) is left behind as an empty directory by rsync but not by
|
||||
# FastSync: the recursive scanner keeps directory entries record-only, so
|
||||
# `sub/deep` is only implicit through the (skipped) file. This is the
|
||||
# documented recursive-empty-directory residual, not a payload/selection
|
||||
# bug.
|
||||
"min_size": {
|
||||
"tree": "recursive transfer does not create a source directory that "
|
||||
"becomes empty after --min-size filtering (FastSync directory "
|
||||
"entries are record-only). ref: RSYNC_COMPAT.md `-d/--dirs` "
|
||||
"row and completion-wave residual ('recursive transfers still "
|
||||
"do not create empty directories').",
|
||||
},
|
||||
# FastSync's recursive scanner keeps directory entries record-only, so a
|
||||
# plain `-d`/recursive source whose only role for a directory is that entry
|
||||
# (empty dir, or a dir emptied by filtering) is not created on the
|
||||
# destination. rsync creates it. `--dirs`/`--files-from`-listed
|
||||
# directories DO cross as explicit entries (covered by the passing
|
||||
# `empty_dirs_files_from` / `files_from` cases).
|
||||
"empty_dirs_recursive": {
|
||||
"tree": "recursive transfer does not create empty source directories. "
|
||||
"ref: RSYNC_COMPAT.md `-d/--dirs` row and completion-wave "
|
||||
"residual ('recursive transfers still do not create empty "
|
||||
"directories').",
|
||||
},
|
||||
# A plain `-d` invocation: FastSync's `--source-dir` treats the argument as
|
||||
# the directory entry itself (creates the empty source-root mirror), while
|
||||
# rsync's `src/` trailing-slash form lists the immediate contents.
|
||||
"dirs_plain": {
|
||||
"tree": "plain -d semantics: FastSync creates the source-root directory "
|
||||
"entry (its documented --dirs files-from behavior) instead of "
|
||||
"rsync's one-level contents listing for a `src/` argument. "
|
||||
"ref: RSYNC_COMPAT.md `-d/--dirs` row (⚠️).",
|
||||
},
|
||||
# --max-delete stops the extras walk part-way and exits 25 in both
|
||||
# implementations; which of the remaining extras survives depends on
|
||||
# deletion order, which neither tool specifies. The exit code and the
|
||||
|
||||
Reference in New Issue
Block a user