feat(p7-output-fs): sparse hole preservation (-S), partial retention (-P), fake-super replay; block-size verified; crtimes/stderr -> Impossible/Divergence (Wave B)

- write_all_sparse: skips all-zero runs >= 4096 bytes via lseek(SEEK_CUR) and
  ftruncates the final size, wired into the atomic temp+rename and --inplace
  paths with no wire change (full image already in memory).
- --partial retention: on a save failure after the temp held data, rename the
  already-written temp to the destination path (best-effort; falls through to
  unlink; never retains when --partial is off) so --append/--append-verify can
  resume; tested by forcing futimens EINVAL with an out-of-range nsec.
- --block-size aliases --delta-block; verified config->delta_block_size is
  honored by the delta engine end-to-end (unit + integration tests).
- fake_super_restore_fd: parses and re-applies user.fastsync.stat fd-relative
  (fchown best-effort/non-root skipped, fchmod, futimens); a save under
  --fake-super now both records and re-applies.
- -N/--crtimes and --stderr=client promoted to a new 'Impossible/Divergence'
  status bucket (Summary: 136/2/4/3/2 = 147).
- cppcheck/clang-format clean; unit 37/37; integration 407 passed.
This commit is contained in:
2026-09-11 15:58:20 +02:00
parent f34eb34f87
commit 47de05d215
14 changed files with 549 additions and 56 deletions
+44
View File
@@ -222,6 +222,49 @@ static void test_link_copy_fallback_preserves_xattrs() {
rmdir(basis_dir);
}
/* --fake-super replay: fake_super_store_fd records the source stat into the
* reserved xattr, and fake_super_restore_fd re-applies mode/mtime (and owner,
* when the process may) fd-relative. Restore must also be a safe no-op with no
* xattr present. Guarded on filesystem xattr support. */
static void test_fake_super_restore() {
const char* path = "test_fake_super_restore.txt";
unlink(path);
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0)
return;
bool has_xattr = setxattr(path, "user.fastsync.xprobe", "p", 1, 0) == 0;
if (has_xattr)
removexattr(path, "user.fastsync.xprobe");
if (!has_xattr) {
close(fd);
unlink(path);
return; /* skip silently when the filesystem has no xattr support */
}
/* No xattr present yet: restore is a silent no-op (returns false, no crash). */
EXPECT_FALSE(fake_super_restore_fd(fd));
fake_super_store_fd(fd, 1001, 1002, 0751, 1700000000, 123456789);
EXPECT_TRUE(fake_super_restore_fd(fd));
struct stat st;
EXPECT_EQ_INT(fstat(fd, &st), 0);
EXPECT_EQ_INT((int)(st.st_mode & 07777), 0751);
/* Restore with a malformed record must skip without failing. */
time_t before = st.st_mtime;
int wfd = open(path, O_RDONLY);
if (wfd >= 0) {
EXPECT_EQ_INT((int)fsetxattr(wfd, FAKESUPER_XATTR, "not-a-valid-record", 19, 0), 0);
close(wfd);
}
EXPECT_FALSE(fake_super_restore_fd(fd));
fstat(fd, &st);
EXPECT_EQ_INT((int)st.st_mtime, (int)before);
close(fd);
unlink(path);
}
void test_xattr() {
test_xattr_wire_roundtrip();
test_xattr_reject_privileged_namespace();
@@ -229,4 +272,5 @@ void test_xattr() {
test_xattr_count_bound();
test_xattr_capture_and_appliable();
test_link_copy_fallback_preserves_xattrs();
test_fake_super_restore();
}