Use flags=rh so intra-workspace hardlinks survive the transform
Build App / compute-version (pull_request) Successful in 3s
Build App / build-macos (pull_request) Successful in 2m15s
Build App / build-windows (pull_request) Successful in 4m24s
Build App / build-linux (pull_request) Successful in 5m3s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
Build App / compute-version (pull_request) Successful in 3s
Build App / build-macos (pull_request) Successful in 2m15s
Build App / build-windows (pull_request) Successful in 4m24s
Build App / build-linux (pull_request) Successful in 5m3s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
Review caught that `flags=r` disables rewriting of both symlink AND
hardlink target names. Leaving symlink targets alone is intended, but a
hardlink's stored target is an archive-internal reference to another
member's name — when member names become `workspace/...` but the
hardlink target stays `./hard_link`, extraction fails hard:
tar: workspace/file.txt: Cannot hard link to './hard_link':
No such file or directory
`flags=rh` rewrites regular member names and hardlink target names
together (keeping the pair consistent) while still leaving symlink
targets untouched. Verified in-container: extract exit 0, symlink target
preserved, hardlink pair shares one inode, nesting under workspace/ intact.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -206,8 +206,10 @@ pub async fn download_container_backup(
|
|||||||
// so secrets can't leak through the sanitization fallback.
|
// so secrets can't leak through the sanitization fallback.
|
||||||
// The `--transform` nests the workspace under `workspace/` (parallel to
|
// The `--transform` nests the workspace under `workspace/` (parallel to
|
||||||
// `home-claude/`) so an extracted archive has both clearly labeled instead
|
// `home-claude/`) so an extracted archive has both clearly labeled instead
|
||||||
// of scattering the workspace files into the extraction dir. `flags=r`
|
// of scattering the workspace files into the extraction dir. `flags=rh`
|
||||||
// scopes the rewrite to member names only, leaving symlink targets intact.
|
// rewrites regular member names AND hardlink target names (so an intra-
|
||||||
|
// workspace hardlink pair still resolves on extract) while leaving symlink
|
||||||
|
// targets untouched (rewriting those would corrupt relative/absolute links).
|
||||||
let script = r#"set -e
|
let script = r#"set -e
|
||||||
STAGE=$(mktemp -d)
|
STAGE=$(mktemp -d)
|
||||||
trap 'rm -rf "$STAGE"' EXIT
|
trap 'rm -rf "$STAGE"' EXIT
|
||||||
@@ -225,7 +227,7 @@ if [ -d "$HOME/.claude" ]; then
|
|||||||
fi
|
fi
|
||||||
tar czf - --ignore-failed-read \
|
tar czf - --ignore-failed-read \
|
||||||
--exclude='*/node_modules' --exclude='*/target' \
|
--exclude='*/node_modules' --exclude='*/target' \
|
||||||
--transform='flags=r;s,^\./,workspace/,' \
|
--transform='flags=rh;s,^\./,workspace/,' \
|
||||||
-C "$TC_BACKUP_SRC" . \
|
-C "$TC_BACKUP_SRC" . \
|
||||||
-C "$STAGE" home-claude"#;
|
-C "$STAGE" home-claude"#;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user