rootfsimage: a directory source's root is always 0:0 0755 (rootfs Plan 1 Task 5, fix)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 files changed,
+27
−2
internal/rootfsimage/dir.go+7 −2internal/rootfsimage/dir_test.go+20 −0
diff --git a/internal/rootfsimage/dir.go b/internal/rootfsimage/dir.go| index 31cc89322..9b9eda4ef 100644 |
| --- a/internal/rootfsimage/dir.go |
| +++ b/internal/rootfsimage/dir.go |
| @@ -12,7 +12,9 @@ import ( |
| // root, and what it holds is the image's files. |
| // |
| // Every entry is owned by 0:0, since a developer's own uid means nothing on |
| -// a box. Modes and times come from Lstat. A regular file is not copied: its |
| +// a box: Entry's UID and GID are never set from the source, and the tests |
| +// check every entry. Modes and times come from Lstat, except the root, which |
| +// is always mode 0755. A regular file is not copied: its |
| // src is its path in the directory, so the spool stays empty and the bytes |
| // are read when something opens the entry. Hardlinks (one device and inode) |
| // share one src. A symlink is kept as the link it is, with its target as it |
| @@ -49,7 +51,10 @@ func readDir(t *Tree, dir string) error { |
| if !fi.IsDir() { |
| return fmt.Errorf("rootfsimage: %s is not a directory", shown(dir)) |
| } |
| - t.Root = Entry{Path: ".", Type: TypeDir, Mode: modeOf(fi), ModTime: timeOf(fi)} |
| + // The root is 0:0 0755 whatever the source directory is: boxes run |
| + // processes as an unprivileged user, and a 0700 root (a mktemp -d |
| + // source) would make the image unenterable. Only its time is the source's. |
| + t.Root = Entry{Path: ".", Type: TypeDir, Mode: 0o755, ModTime: timeOf(fi)} |
| type fileKey struct{ dev, ino uint64 } |
| linked := map[fileKey]string{} // the src of the first name of a multiply linked file |
diff --git a/internal/rootfsimage/dir_test.go b/internal/rootfsimage/dir_test.go| index 643c8d49c..866d132ac 100644 |
| --- a/internal/rootfsimage/dir_test.go |
| +++ b/internal/rootfsimage/dir_test.go |
| @@ -69,11 +69,31 @@ func TestOpenDirOwnsEverythingByRoot(t *testing.T) { |
| if tr.Root.UID != 0 || tr.Root.GID != 0 { |
| t.Errorf("root owner = %d:%d, want 0:0", tr.Root.UID, tr.Root.GID) |
| } |
| + for _, e := range tr.Entries() { |
| + if e.UID != 0 || e.GID != 0 { |
| + t.Errorf("%s owner = %d:%d, want 0:0", e.Path, e.UID, e.GID) |
| + } |
| + } |
| if tr.Files() != 3 { |
| t.Errorf("Files = %d, want 3", tr.Files()) |
| } |
| } |
| +func TestOpenDirRootIs0755RootWhateverTheSource(t *testing.T) { |
| + dir := t.TempDir() |
| + writeSrc(t, filepath.Join(dir, "f"), "x", 0o644) |
| + if err := os.Chmod(dir, 0o700); err != nil { |
| + t.Fatal(err) |
| + } |
| + tr, err := OpenDir(dir, t.TempDir()) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if tr.Root.Mode != 0o755 || tr.Root.UID != 0 || tr.Root.GID != 0 { |
| + t.Errorf("root = mode %v owner %d:%d, want 0755 0:0", tr.Root.Mode, tr.Root.UID, tr.Root.GID) |
| + } |
| +} |
| + |
| func TestOpenDirReadsInPlaceAndKeepsHardlinks(t *testing.T) { |
| dir := t.TempDir() |
| writeSrc(t, filepath.Join(dir, "a"), "same", 0o644) |