aboutsummaryrefslogtreecommitdiff
path: root/src/os/root_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/os/root_test.go')
-rw-r--r--src/os/root_test.go105
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)
+ }
+ })
+}