mirror of
https://github.com/kevinveenbirkenbach/docker-volume-backup.git
synced 2026-10-20 01:43:25 +00:00
fix(backup): carry extended attributes, ACLs and hardlinks into a generation
rsync -a expands to -rlptgoD, so the backup stored neither extended attributes nor ACLs nor hardlinks while the restore side asks for -aHAX. A generation therefore never held what a restore wants back, and rsync faithfully mirrored a snapshot that has none. Reproduced end to end against a source carrying user.oc.* attributes and a hardlink: with the old argv, getfattr -d -R over the generation returns nothing and the hardlink splits into two inodes; with -aHAX both sides come back identical to the source. That is the shape in which an OpenCloud volume survived a disaster-recovery drill with its files intact and its storage metadata gone, so its posix driver skipped every space it could no longer read. restore/files.py had the same gap on this repository's own restore path. Two consequences worth knowing. The first backup after this re-copies every attribute-carrying volume once, because rsync declines to hardlink against a generation whose xattrs do not match. And a backup destination on a filesystem without xattr support now fails the run instead of producing a generation that cannot be restored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -75,7 +75,7 @@ def backup_volume(
|
||||
pathlib.Path(dest).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
last = get_last_backup_dir(versions_dir, volume_name, dest)
|
||||
cmd = ["rsync", "-aP", "--no-D", "--delete", "--delete-excluded"]
|
||||
cmd = ["rsync", "-aHAX", "-P", "--no-D", "--delete", "--delete-excluded"]
|
||||
if authoritative:
|
||||
cmd.append("--checksum")
|
||||
if last:
|
||||
|
||||
@@ -59,6 +59,6 @@ def restore_volume_files(volume_name: str, backup_files_dir: str) -> int:
|
||||
# rsync reads "dir/" as its contents and "dir" as the directory itself.
|
||||
src = f"{Path(backup_files_dir)}{os.sep}"
|
||||
dest = f"{Path(mountpoint)}{os.sep}"
|
||||
run(["rsync", "-avv", "--delete", src, dest])
|
||||
run(["rsync", "-aHAX", "-vv", "--delete", src, dest])
|
||||
print("File restore complete.")
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user