From 934482086fec5aef9106df6717b1416c09b03767 Mon Sep 17 00:00:00 2001 From: Maksim Shulga Date: Thu, 6 Aug 2026 16:00:09 +0000 Subject: [PATCH] Document ACL, xattr, sparse-file, and hardlink backup behavior (#19) * Document ACL, xattr, sparse-file, and hardlink backup behavior Extend the README Limitations section with the filesystem-feature behaviors that weren't documented: ACLs/xattrs/flags are never preserved by either backend, sparse files are materialized as full allocated copies, source-side hardlinks are not preserved as hardlinks in the backup, and ownership is only preserved when running as root. Co-Authored-By: Claude Sonnet 5 * Soften README timestamp/ownership claims for external-rsync backend Nanosecond mtime precision and 'silently logged chown failures' are Python-backend specifics that don't hold for --external-rsync: rsync's own timestamp precision depends on the build/filesystem, and it skips disallowed ownership changes itself rather than going through our logging path. Co-Authored-By: Claude Sonnet 5 --------- Co-authored-by: Maxim Shulga Co-authored-by: Claude Sonnet 5 --- IMPROVEMENTS.md | 2 +- README.md | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/IMPROVEMENTS.md b/IMPROVEMENTS.md index 131e3b0..a30e651 100644 --- a/IMPROVEMENTS.md +++ b/IMPROVEMENTS.md @@ -138,7 +138,7 @@ Acceptance criteria: ### Define filesystem compatibility -- [ ] Document behavior for ACLs, xattrs, flags, sparse files, source hardlinks, +- [x] Document behavior for ACLs, xattrs, flags, sparse files, source hardlinks, ownership, permissions, and timestamps. - [x] Add an explicit one-filesystem policy. - [ ] Make Python and external implementations provide equivalent guarantees or diff --git a/README.md b/README.md index 2a09eb7..29f6f1a 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,24 @@ backups/ - **Symlinks are preserved as symlinks**, including ones pointing outside the source tree - their targets are never followed or copied. +- **ACLs, extended attributes, and filesystem-specific flags (e.g. + BSD/macOS `chflags`) are never preserved**, by either implementation. + The Python backend never reads or sets them; `--external-rsync` uses + `--archive` without `-A`/`-X`/`--fileflags`, so they're dropped too. +- **Sparse files are not preserved as sparse.** Both implementations + do a whole-file copy (`--whole-file` for external rsync), so holes + are read and rewritten as allocated zero blocks in the backup. +- **Hardlinks between source files are not preserved as hardlinks.** + Each hardlinked source file is backed up as an independent file; + neither backend passes rsync's `-H`. Only hardlinks *within* the + backup repository (across snapshots) are meaningful. +- **Mode and timestamps are always preserved.** The Python backend + restores mtime with nanosecond precision; `--external-rsync`'s + precision depends on the installed rsync build and destination + filesystem. **Ownership (uid/gid) is preserved only when running as + root.** In the Python backend a failed `chown` is caught and logged, + not fatal; with `--external-rsync`, rsync itself just skips + ownership it isn't permitted to set. ## Development