1 package sysfs_test
2
3 import (
4 "io"
5 "io/fs"
6 "os"
7 "runtime"
8 "sort"
9 "testing"
10
11 "github.com/tetratelabs/wazero/experimental/sys"
12 "github.com/tetratelabs/wazero/internal/fstest"
13 "github.com/tetratelabs/wazero/internal/sysfs"
14 "github.com/tetratelabs/wazero/internal/testing/require"
15 )
16
17 func TestFSFileReaddir(t *testing.T) {
18 t.Parallel()
19
20 tmpDir := t.TempDir()
21 require.NoError(t, fstest.WriteTestFiles(tmpDir))
22 dirFS := os.DirFS(tmpDir)
23 maskFS := &sysfs.MaskOsFS{Fs: dirFS}
24 maskFSZeroIno := &sysfs.MaskOsFS{Fs: os.DirFS(tmpDir), ZeroIno: true}
25
26 expectIno := runtime.GOOS != "windows"
27
28 tests := []struct {
29 name string
30 fs fs.FS
31 expectIno bool
32 }{
33 {name: "os.DirFS", fs: dirFS, expectIno: expectIno},
34 {name: "mask(os.DirFS)", fs: maskFS, expectIno: expectIno},
35 {name: "mask(os.DirFS) ZeroIno", fs: maskFSZeroIno, expectIno: false},
36 {name: "fstest.MapFS", fs: fstest.FS, expectIno: false},
37 }
38
39 for _, tc := range tests {
40 tc := tc
41
42 t.Run(tc.name, func(t *testing.T) {
43 dotF, errno := sysfs.OpenFSFile(tc.fs, ".", sys.O_RDONLY, 0)
44 require.EqualErrno(t, 0, errno)
45 defer dotF.Close()
46
47 t.Run("dir", func(t *testing.T) {
48 testReaddirAll(t, dotF, tc.expectIno)
49
50
51 dirents, errno := dotF.Readdir(100)
52 require.EqualErrno(t, 0, errno)
53 require.Zero(t, len(dirents))
54
55
56 newOffset, errno := dotF.Seek(0, io.SeekStart)
57 require.EqualErrno(t, 0, errno)
58 require.Zero(t, newOffset)
59
60
61 newOffset, errno = dotF.Seek(0, io.SeekStart)
62 require.EqualErrno(t, 0, errno)
63 require.Zero(t, newOffset)
64
65
66 testReaddirAll(t, dotF, tc.expectIno)
67 })
68
69
70
71 t.Run("closed dir", func(t *testing.T) {
72 require.EqualErrno(t, 0, dotF.Close())
73 _, errno := dotF.Readdir(-1)
74 require.EqualErrno(t, sys.EBADF, errno)
75 })
76
77 fileF, errno := sysfs.OpenFSFile(tc.fs, "empty.txt", sys.O_RDONLY, 0)
78 require.EqualErrno(t, 0, errno)
79 defer fileF.Close()
80
81 t.Run("file", func(t *testing.T) {
82 _, errno := fileF.Readdir(-1)
83 require.EqualErrno(t, sys.EBADF, errno)
84 })
85
86 dirF, errno := sysfs.OpenFSFile(tc.fs, "dir", sys.O_RDONLY, 0)
87 require.EqualErrno(t, 0, errno)
88 defer dirF.Close()
89
90 t.Run("partial", func(t *testing.T) {
91 dirents1, errno := dirF.Readdir(1)
92 require.EqualErrno(t, 0, errno)
93 require.Equal(t, 1, len(dirents1))
94
95 dirents2, errno := dirF.Readdir(1)
96 require.EqualErrno(t, 0, errno)
97 require.Equal(t, 1, len(dirents2))
98
99
100 dirents3, errno := dirF.Readdir(1)
101 require.EqualErrno(t, 0, errno)
102 require.Equal(t, 1, len(dirents3))
103
104 dirents := []sys.Dirent{dirents1[0], dirents2[0], dirents3[0]}
105 sort.Slice(dirents, func(i, j int) bool { return dirents[i].Name < dirents[j].Name })
106
107 requireIno(t, dirents, tc.expectIno)
108
109
110 for i := range dirents {
111 dirents[i].Ino = 0
112 }
113
114 require.Equal(t, []sys.Dirent{
115 {Name: "-", Type: 0},
116 {Name: "a-", Type: fs.ModeDir},
117 {Name: "ab-", Type: 0},
118 }, dirents)
119
120
121 _, errno = dirF.Readdir(1)
122 require.EqualErrno(t, 0, errno)
123 })
124
125 subdirF, errno := sysfs.OpenFSFile(tc.fs, "sub", sys.O_RDONLY, 0)
126 require.EqualErrno(t, 0, errno)
127 defer subdirF.Close()
128
129 t.Run("subdir", func(t *testing.T) {
130 dirents, errno := subdirF.Readdir(-1)
131 require.EqualErrno(t, 0, errno)
132 sort.Slice(dirents, func(i, j int) bool { return dirents[i].Name < dirents[j].Name })
133
134 require.Equal(t, 1, len(dirents))
135 require.Equal(t, "test.txt", dirents[0].Name)
136 require.Zero(t, dirents[0].Type)
137 })
138 })
139 }
140 }
141
142 func testReaddirAll(t *testing.T, dotF sys.File, expectDirIno bool) {
143 dirents, errno := dotF.Readdir(-1)
144 require.EqualErrno(t, 0, errno)
145 sort.Slice(dirents, func(i, j int) bool { return dirents[i].Name < dirents[j].Name })
146
147 requireIno(t, dirents, expectDirIno)
148
149
150 for i := range dirents {
151 dirents[i].Ino = 0
152 }
153
154 require.Equal(t, []sys.Dirent{
155 {Name: "animals.txt", Type: 0},
156 {Name: "dir", Type: fs.ModeDir},
157 {Name: "empty.txt", Type: 0},
158 {Name: "emptydir", Type: fs.ModeDir},
159 {Name: "sub", Type: fs.ModeDir},
160 }, dirents)
161 }
162
163 func requireIno(t *testing.T, dirents []sys.Dirent, expectDirIno bool) {
164 for _, e := range dirents {
165 if expectDirIno {
166 require.NotEqual(t, uint64(0), e.Ino, "%+v", e)
167 e.Ino = 0
168 } else {
169 require.Zero(t, e.Ino, "%+v", e)
170 }
171 }
172 }
173
View as plain text