mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-06-08 06:05:57 -04:00
Fill the highest-restructure-risk gap: options that do two-directory / rename /
outside-tree work, asserted at >=3 levels deep with the aux tree kept outside
the main tree, and asserting the option's specific property rather than just
tree equality (which the ported tests already cover).
alt-dest-deep --link-dest hardlinks unchanged files (same inode), --copy-dest
copies (never links), --compare-dest omits unchanged files;
ref tree outside both src and dest.
temp-dir cross-dir temp->final rename at depth; temp dir left clean; a
missing --temp-dir fails (so the option is proven consulted).
partial --partial keeps the partial in the dest file; relative
--partial-dir stages per-directory at depth (pre-seed +
interrupt/resume); absolute --partial-dir writes the partial
outside the tree.
inplace --inplace keeps the destination inode across a delta update;
the default temp+rename path replaces it.
append --append completes truncated files tail-only; --append-verify
repairs a corrupted prefix (protocol >= 30).
backup-deep --suffix saves <name>S beside the new file; --backup-dir
relocates old files to a parallel deep tree outside the dest
and captures deletions under --delete.
All green on master and under --protocol=29/30.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
74 lines
2.8 KiB
Python
74 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Coverage of --append and --append-verify at depth.
|
|
|
|
--append assumes each destination file is a prefix of the (longer) source and
|
|
transfers only the bytes past the existing size; it does NOT re-check the data
|
|
already present, and it never touches a file that is already the same size or
|
|
larger. --append-verify works the same way but folds the existing data into the
|
|
whole-file checksum, so a transfer whose result fails verification is re-sent
|
|
with a normal --inplace pass. Exercise both on files >=3 levels deep.
|
|
"""
|
|
|
|
import os
|
|
|
|
from rsyncfns import (
|
|
FROMDIR, TODIR,
|
|
assert_same, forced_protocol, make_tree, rmtree, run_rsync, test_fail,
|
|
walk_files,
|
|
)
|
|
|
|
src = FROMDIR
|
|
deep = os.path.join('d1', 'd2', 'd3', 'f3')
|
|
|
|
|
|
def seed_source():
|
|
rmtree(src)
|
|
make_tree(src, depth=3, data=True, data_size=8192)
|
|
return [p.relative_to(src) for p in walk_files(src)]
|
|
|
|
|
|
def dest_prefix(rels, *, corrupt=False, frac=0.5):
|
|
"""Build a destination holding the first `frac` of each source file (a
|
|
valid prefix), optionally corrupting the deep file's leading bytes."""
|
|
rmtree(TODIR)
|
|
for rel in rels:
|
|
dst = TODIR / rel
|
|
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
full = (src / rel).read_bytes()
|
|
dst.write_bytes(full[: int(len(full) * frac)])
|
|
if corrupt:
|
|
p = TODIR / deep
|
|
bad = bytearray(p.read_bytes())
|
|
bad[0:64] = b'\x00' * 64
|
|
p.write_bytes(bytes(bad))
|
|
|
|
|
|
# --- --append completes truncated destinations at every level ---------------
|
|
rels = seed_source()
|
|
dest_prefix(rels)
|
|
run_rsync('-a', '--append', f'{src}/', f'{TODIR}/')
|
|
for rel in rels:
|
|
assert_same(TODIR / rel, src / rel, label=f'append {rel}')
|
|
|
|
# The split between non-verifying --append and verifying --append-verify only
|
|
# exists at protocol >= 30; at protocol 29 plain --append still verifies, so
|
|
# skip the distinguishing sub-cases there.
|
|
proto = forced_protocol()
|
|
if proto is not None and proto < 30:
|
|
print(f"append: protocol {proto} -- skipping the --append/--append-verify "
|
|
"split (verifying-append behaviour predates the protocol-30 split)")
|
|
else:
|
|
# plain --append trusts a corrupted prefix (leaves it wrong)
|
|
dest_prefix(rels, corrupt=True)
|
|
run_rsync('-a', '--append', f'{src}/', f'{TODIR}/')
|
|
if (TODIR / deep).read_bytes() == (src / deep).read_bytes():
|
|
test_fail("plain --append unexpectedly repaired a corrupted prefix "
|
|
"(it should append only and trust the existing data)")
|
|
|
|
# --append-verify detects the bad prefix and re-sends the whole file
|
|
dest_prefix(rels, corrupt=True)
|
|
run_rsync('-a', '--append-verify', f'{src}/', f'{TODIR}/')
|
|
assert_same(TODIR / deep, src / deep, label='append-verify deep')
|
|
|
|
print("append: tail-only completion at depth; append-verify repairs prefix")
|