diff options
Diffstat (limited to 'src/os/root_test.go')
| -rw-r--r-- | src/os/root_test.go | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/os/root_test.go b/src/os/root_test.go index f9fbd11575..71ce5e559a 100644 --- a/src/os/root_test.go +++ b/src/os/root_test.go @@ -1952,3 +1952,108 @@ func TestRootName(t *testing.T) { t.Errorf(`root.OpenRoot("dir").Name() = %q, want %q`, got, want) } } + +// TestRootNoLstat verifies that we do not use lstat (possibly escaping the root) +// when reading directories in a Root. +func TestRootNoLstat(t *testing.T) { + if runtime.GOARCH == "wasm" { + t.Skip("wasm lacks fstatat") + } + + dir := makefs(t, []string{ + "subdir/", + }) + const size = 42 + contents := strings.Repeat("x", size) + if err := os.WriteFile(dir+"/subdir/file", []byte(contents), 0666); err != nil { + t.Fatal(err) + } + root, err := os.OpenRoot(dir) + if err != nil { + t.Fatal(err) + } + defer root.Close() + + test := func(name string, fn func(t *testing.T, f *os.File)) { + t.Run(name, func(t *testing.T) { + os.SetStatHook(t, func(f *os.File, name string) (os.FileInfo, error) { + if f == nil { + t.Errorf("unexpected Lstat(%q)", name) + } + return nil, nil + }) + f, err := root.Open("subdir") + if err != nil { + t.Fatal(err) + } + defer f.Close() + fn(t, f) + }) + } + + checkFileInfo := func(t *testing.T, fi fs.FileInfo) { + t.Helper() + if got, want := fi.Name(), "file"; got != want { + t.Errorf("FileInfo.Name() = %q, want %q", got, want) + } + if got, want := fi.Size(), int64(size); got != want { + t.Errorf("FileInfo.Size() = %v, want %v", got, want) + } + } + checkDirEntry := func(t *testing.T, d fs.DirEntry) { + t.Helper() + if got, want := d.Name(), "file"; got != want { + t.Errorf("DirEntry.Name() = %q, want %q", got, want) + } + if got, want := d.IsDir(), false; got != want { + t.Errorf("DirEntry.IsDir() = %v, want %v", got, want) + } + fi, err := d.Info() + if err != nil { + t.Fatalf("DirEntry.Info() = _, %v", err) + } + checkFileInfo(t, fi) + } + + test("Stat", func(t *testing.T, subdir *os.File) { + fi, err := subdir.Stat() + if err != nil { + t.Fatal(err) + } + if !fi.IsDir() { + t.Fatalf(`Open("subdir").Stat().IsDir() = false, want true`) + } + }) + // File.ReadDir, returning []DirEntry + test("ReadDirEntry", func(t *testing.T, subdir *os.File) { + dirents, err := subdir.ReadDir(-1) + if err != nil { + t.Fatal(err) + } + if len(dirents) != 1 { + t.Fatalf(`Open("subdir").ReadDir(-1) = {%v}, want {file}`, dirents) + } + checkDirEntry(t, dirents[0]) + }) + // File.Readdir, returning []FileInfo + test("ReadFileInfo", func(t *testing.T, subdir *os.File) { + fileinfos, err := subdir.Readdir(-1) + if err != nil { + t.Fatal(err) + } + if len(fileinfos) != 1 { + t.Fatalf(`Open("subdir").Readdir(-1) = {%v}, want {file}`, fileinfos) + } + checkFileInfo(t, fileinfos[0]) + }) + // File.Readdirnames, returning []string + test("Readdirnames", func(t *testing.T, subdir *os.File) { + names, err := subdir.Readdirnames(-1) + if err != nil { + t.Fatal(err) + } + if got, want := names, []string{"file"}; !slices.Equal(got, want) { + t.Fatalf(`Open("subdir").Readdirnames(-1) = %q, want %q`, got, want) + } + }) +} |
