Source file
src/os/os_unix_test.go
1
2
3
4
5
6
7 package os_test
8
9 import (
10 "internal/testenv"
11 "io"
12 . "os"
13 "path/filepath"
14 "runtime"
15 "strings"
16 "syscall"
17 "testing"
18 "time"
19 )
20
21 func init() {
22 isReadonlyError = func(err error) bool { return err == syscall.EROFS }
23 }
24
25
26 type syscallDescriptor = int
27
28 func checkUidGid(t *testing.T, path string, uid, gid int) {
29 dir, err := Lstat(path)
30 if err != nil {
31 t.Fatalf("Lstat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
32 }
33 sys := dir.Sys().(*syscall.Stat_t)
34 if int(sys.Uid) != uid {
35 t.Errorf("Lstat %q: uid %d want %d", path, sys.Uid, uid)
36 }
37 if int(sys.Gid) != gid {
38 t.Errorf("Lstat %q: gid %d want %d", path, sys.Gid, gid)
39 }
40 }
41
42 func TestChown(t *testing.T) {
43 if runtime.GOOS == "wasip1" {
44 t.Skip("file ownership not supported on " + runtime.GOOS)
45 }
46 t.Parallel()
47
48
49
50
51
52 f := newFile("TestChown", t)
53 defer Remove(f.Name())
54 defer f.Close()
55 dir, err := f.Stat()
56 if err != nil {
57 t.Fatalf("stat %s: %s", f.Name(), err)
58 }
59
60
61
62 gid := Getgid()
63 t.Log("gid:", gid)
64 if err = Chown(f.Name(), -1, gid); err != nil {
65 t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
66 }
67 sys := dir.Sys().(*syscall.Stat_t)
68 checkUidGid(t, f.Name(), int(sys.Uid), gid)
69
70
71 groups, err := Getgroups()
72 if err != nil {
73 t.Fatalf("getgroups: %s", err)
74 }
75 t.Log("groups: ", groups)
76 for _, g := range groups {
77 if err = Chown(f.Name(), -1, g); err != nil {
78 t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
79 }
80 checkUidGid(t, f.Name(), int(sys.Uid), g)
81
82
83 if err = f.Chown(-1, gid); err != nil {
84 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
85 }
86 checkUidGid(t, f.Name(), int(sys.Uid), gid)
87 }
88 }
89
90 func TestFileChown(t *testing.T) {
91 if runtime.GOOS == "wasip1" {
92 t.Skip("file ownership not supported on " + runtime.GOOS)
93 }
94 t.Parallel()
95
96
97
98
99
100 f := newFile("TestFileChown", t)
101 defer Remove(f.Name())
102 defer f.Close()
103 dir, err := f.Stat()
104 if err != nil {
105 t.Fatalf("stat %s: %s", f.Name(), err)
106 }
107
108
109
110 gid := Getgid()
111 t.Log("gid:", gid)
112 if err = f.Chown(-1, gid); err != nil {
113 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
114 }
115 sys := dir.Sys().(*syscall.Stat_t)
116 checkUidGid(t, f.Name(), int(sys.Uid), gid)
117
118
119 groups, err := Getgroups()
120 if err != nil {
121 t.Fatalf("getgroups: %s", err)
122 }
123 t.Log("groups: ", groups)
124 for _, g := range groups {
125 if err = f.Chown(-1, g); err != nil {
126 t.Fatalf("fchown %s -1 %d: %s", f.Name(), g, err)
127 }
128 checkUidGid(t, f.Name(), int(sys.Uid), g)
129
130
131 if err = f.Chown(-1, gid); err != nil {
132 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
133 }
134 checkUidGid(t, f.Name(), int(sys.Uid), gid)
135 }
136 }
137
138 func TestLchown(t *testing.T) {
139 testenv.MustHaveSymlink(t)
140 t.Parallel()
141
142
143
144
145
146 f := newFile("TestLchown", t)
147 defer Remove(f.Name())
148 defer f.Close()
149 dir, err := f.Stat()
150 if err != nil {
151 t.Fatalf("stat %s: %s", f.Name(), err)
152 }
153
154 linkname := f.Name() + "2"
155 if err := Symlink(f.Name(), linkname); err != nil {
156 if runtime.GOOS == "android" && IsPermission(err) {
157 t.Skip("skipping test on Android; permission error creating symlink")
158 }
159 t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err)
160 }
161 defer Remove(linkname)
162
163
164
165 gid := Getgid()
166 t.Log("gid:", gid)
167 if err = Lchown(linkname, -1, gid); err != nil {
168 if err, ok := err.(*PathError); ok && err.Err == syscall.ENOSYS {
169 t.Skip("lchown is unavailable")
170 }
171 t.Fatalf("lchown %s -1 %d: %s", linkname, gid, err)
172 }
173 sys := dir.Sys().(*syscall.Stat_t)
174 checkUidGid(t, linkname, int(sys.Uid), gid)
175
176
177 groups, err := Getgroups()
178 if err != nil {
179 t.Fatalf("getgroups: %s", err)
180 }
181 t.Log("groups: ", groups)
182 for _, g := range groups {
183 if err = Lchown(linkname, -1, g); err != nil {
184 t.Fatalf("lchown %s -1 %d: %s", linkname, g, err)
185 }
186 checkUidGid(t, linkname, int(sys.Uid), g)
187
188
189 checkUidGid(t, f.Name(), int(sys.Uid), int(sys.Gid))
190 }
191 }
192
193
194 func TestReaddirRemoveRace(t *testing.T) {
195 oldStat := *LstatP
196 defer func() { *LstatP = oldStat }()
197 *LstatP = func(name string) (FileInfo, error) {
198 if strings.HasSuffix(name, "some-file") {
199
200 return nil, ErrNotExist
201 }
202 return oldStat(name)
203 }
204 dir := newDir("TestReaddirRemoveRace", t)
205 defer RemoveAll(dir)
206 if err := WriteFile(filepath.Join(dir, "some-file"), []byte("hello"), 0644); err != nil {
207 t.Fatal(err)
208 }
209 d, err := Open(dir)
210 if err != nil {
211 t.Fatal(err)
212 }
213 defer d.Close()
214 fis, err := d.Readdir(2)
215 if len(fis) == 0 && err == nil {
216
217 t.Fatal("Readdir = empty slice & err == nil")
218 }
219 if len(fis) != 0 || err != io.EOF {
220 t.Errorf("Readdir = %d entries: %v; want 0, io.EOF", len(fis), err)
221 for i, fi := range fis {
222 t.Errorf(" entry[%d]: %q, %v", i, fi.Name(), fi.Mode())
223 }
224 t.FailNow()
225 }
226 }
227
228
229 func TestMkdirStickyUmask(t *testing.T) {
230 if runtime.GOOS == "wasip1" {
231 t.Skip("file permissions not supported on " + runtime.GOOS)
232 }
233 t.Parallel()
234
235 const umask = 0077
236 dir := newDir("TestMkdirStickyUmask", t)
237 defer RemoveAll(dir)
238 oldUmask := syscall.Umask(umask)
239 defer syscall.Umask(oldUmask)
240 p := filepath.Join(dir, "dir1")
241 if err := Mkdir(p, ModeSticky|0755); err != nil {
242 t.Fatal(err)
243 }
244 fi, err := Stat(p)
245 if err != nil {
246 t.Fatal(err)
247 }
248 if mode := fi.Mode(); (mode&umask) != 0 || (mode&^ModePerm) != (ModeDir|ModeSticky) {
249 t.Errorf("unexpected mode %s", mode)
250 }
251 }
252
253
254 func newFileTest(t *testing.T, blocking bool) {
255 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
256 t.Skipf("syscall.Pipe is not available on %s.", runtime.GOOS)
257 }
258
259 p := make([]int, 2)
260 if err := syscall.Pipe(p); err != nil {
261 t.Fatalf("pipe: %v", err)
262 }
263 defer syscall.Close(p[1])
264
265
266 if !blocking {
267 if err := syscall.SetNonblock(p[0], true); err != nil {
268 syscall.Close(p[0])
269 t.Fatalf("SetNonblock: %v", err)
270 }
271 }
272
273 file := NewFile(uintptr(p[0]), "notapipe")
274 if file == nil {
275 syscall.Close(p[0])
276 t.Fatalf("failed to convert fd to file!")
277 }
278 defer file.Close()
279
280 timeToWrite := 100 * time.Millisecond
281 timeToDeadline := 1 * time.Millisecond
282 if !blocking {
283
284
285 timeToWrite = 1 * time.Second
286 }
287
288
289 b := make([]byte, 1)
290 timer := time.AfterFunc(timeToWrite, func() { syscall.Write(p[1], []byte("a")) })
291 defer timer.Stop()
292 file.SetReadDeadline(time.Now().Add(timeToDeadline))
293 _, err := file.Read(b)
294 if !blocking {
295
296 if !isDeadlineExceeded(err) {
297 t.Fatalf("No timeout reading from file: %v", err)
298 }
299 } else {
300
301 if err != nil {
302 t.Fatalf("Error reading from file: %v", err)
303 }
304 }
305 }
306
307 func TestNewFileBlock(t *testing.T) {
308 t.Parallel()
309 newFileTest(t, true)
310 }
311
312 func TestNewFileNonBlock(t *testing.T) {
313 t.Parallel()
314 newFileTest(t, false)
315 }
316
317 func TestNewFileInvalid(t *testing.T) {
318 t.Parallel()
319 const negOne = ^uintptr(0)
320 if f := NewFile(negOne, "invalid"); f != nil {
321 t.Errorf("NewFile(-1) got %v want nil", f)
322 }
323 }
324
325 func TestSplitPath(t *testing.T) {
326 t.Parallel()
327 for _, tt := range []struct{ path, wantDir, wantBase string }{
328 {"a", ".", "a"},
329 {"a/", ".", "a"},
330 {"a//", ".", "a"},
331 {"a/b", "a", "b"},
332 {"a/b/", "a", "b"},
333 {"a/b/c", "a/b", "c"},
334 {"/a", "/", "a"},
335 {"/a/", "/", "a"},
336 {"/a/b", "/a", "b"},
337 {"/a/b/", "/a", "b"},
338 {"/a/b/c", "/a/b", "c"},
339 {"//a", "/", "a"},
340 {"//a/", "/", "a"},
341 {"///a", "/", "a"},
342 {"///a/", "/", "a"},
343 } {
344 if dir, base := SplitPath(tt.path); dir != tt.wantDir || base != tt.wantBase {
345 t.Errorf("splitPath(%q) = %q, %q, want %q, %q", tt.path, dir, base, tt.wantDir, tt.wantBase)
346 }
347 }
348 }
349
View as plain text