Rename backup archive root so extraction dir mode isn't clobbered #10

Merged
jknapp merged 1 commits from fix/backup-root-dir-mode into main 2026-07-01 13:35:03 +00:00
Owner

Problem

Follow-up to #9. The backup transform s,^\./,workspace/, rewrites the workspace contents (./fooworkspace/foo) but leaves tar's root member as a bare ./. That ./ entry carries the source root's mode/mtime, so extracting the archive stamps them onto the extraction directory itself (e.g. an unexpected chmod/mtime on wherever the user unpacks it).

Fix

Match the leading . instead of ./ (s,^\.,workspace,), so tar's root member is renamed ./workspace. The archive then carries a proper workspace/ directory entry and no bare ./, and the extraction directory is left untouched. Contents, hidden files, excludes, symlink targets, and the flags=rh hardlink handling are all unchanged.

Verification (in-container, exact production script)

  • Archive top level is exactly workspace/ + home-claude/; no ./ member.
  • Extracting into a 0755 directory leaves it 0755 (previously the root entry could reset it).
  • node_modules/target still excluded (0 leaked).
  • home-claude/ still un-nested; workspace/.git history preserved.
  • Symlink targets preserved; intra-workspace hardlink pair shares one inode.
  • cargo check passes.

🤖 Generated with Claude Code

## Problem Follow-up to #9. The backup transform `s,^\./,workspace/,` rewrites the workspace *contents* (`./foo` → `workspace/foo`) but leaves tar's root member as a bare `./`. That `./` entry carries the source root's mode/mtime, so extracting the archive stamps them onto the **extraction directory itself** (e.g. an unexpected chmod/mtime on wherever the user unpacks it). ## Fix Match the leading `.` instead of `./` (`s,^\.,workspace,`), so tar's root member is renamed `./` → `workspace`. The archive then carries a proper `workspace/` directory entry and no bare `./`, and the extraction directory is left untouched. Contents, hidden files, excludes, symlink targets, and the `flags=rh` hardlink handling are all unchanged. ## Verification (in-container, exact production script) - Archive top level is exactly `workspace/` + `home-claude/`; **no `./` member**. - Extracting into a `0755` directory leaves it `0755` (previously the root entry could reset it). - `node_modules`/`target` still excluded (0 leaked). - `home-claude/` still un-nested; `workspace/.git` history preserved. - Symlink targets preserved; intra-workspace hardlink pair shares one inode. - `cargo check` passes. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jknapp added 1 commit 2026-07-01 13:33:14 +00:00
Rename backup archive root so extraction dir mode isn't clobbered
Build App / compute-version (pull_request) Successful in 4s
Build App / build-macos (pull_request) Successful in 2m14s
Build App / build-windows (pull_request) Successful in 4m26s
Build App / build-linux (pull_request) Successful in 5m0s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
26adccce5b
The transform used `s,^\./,workspace/,`, which rewrites the workspace
*contents* (`./foo` -> `workspace/foo`) but leaves tar's root member as a
bare `./`. That `./` entry carries the source root's mode/mtime, and on
extraction tar stamps them onto the extraction directory itself.

Match the leading `.` instead (`s,^\.,workspace,`) so the root member is
renamed `./` -> `workspace`, giving the archive a proper `workspace/`
directory entry and no bare `./`. The extraction directory is left
untouched. Contents, hidden files, excludes, symlink targets and the
`flags=rh` hardlink handling are unchanged.

Verified in-container: archive top level is exactly `workspace/` +
`home-claude/`, no `./` member, node_modules excluded, extraction into a
0755 dir leaves it 0755, workspace/.git preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jknapp merged commit 59d89bcd1b into main 2026-07-01 13:35:03 +00:00
jknapp deleted branch fix/backup-root-dir-mode 2026-07-01 13:35:03 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: CyberCoveLLC/Triple-C#10