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 f := newFile(t)
49 dir, err := f.Stat()
50 if err != nil {
51 t.Fatalf("stat %s: %s", f.Name(), err)
52 }
53
54
55
56 gid := Getgid()
57 t.Log("gid:", gid)
58 if err = Chown(f.Name(), -1, gid); err != nil {
59 t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
60 }
61 sys := dir.Sys().(*syscall.Stat_t)
62 checkUidGid(t, f.Name(), int(sys.Uid), gid)
63
64
65 groups, err := Getgroups()
66 if err != nil {
67 t.Fatalf("getgroups: %s", err)
68 }
69 t.Log("groups: ", groups)
70 for _, g := range groups {
71 if err = Chown(f.Name(), -1, g); err != nil {
72 if testenv.SyscallIsNotSupported(err) {
73 t.Logf("chown %s -1 %d: %s (error ignored)", f.Name(), g, err)
74
75 checkUidGid(t, f.Name(), int(sys.Uid), gid)
76 continue
77 }
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 f := newFile(t)
97 dir, err := f.Stat()
98 if err != nil {
99 t.Fatalf("stat %s: %s", f.Name(), err)
100 }
101
102
103
104 gid := Getgid()
105 t.Log("gid:", gid)
106 if err = f.Chown(-1, gid); err != nil {
107 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
108 }
109 sys := dir.Sys().(*syscall.Stat_t)
110 checkUidGid(t, f.Name(), int(sys.Uid), gid)
111
112
113 groups, err := Getgroups()
114 if err != nil {
115 t.Fatalf("getgroups: %s", err)
116 }
117 t.Log("groups: ", groups)
118 for _, g := range groups {
119 if err = f.Chown(-1, g); err != nil {
120 if testenv.SyscallIsNotSupported(err) {
121 t.Logf("chown %s -1 %d: %s (error ignored)", f.Name(), g, err)
122
123 checkUidGid(t, f.Name(), int(sys.Uid), gid)
124 continue
125 }
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 f := newFile(t)
143 dir, err := f.Stat()
144 if err != nil {
145 t.Fatalf("stat %s: %s", f.Name(), err)
146 }
147
148 linkname := f.Name() + "2"
149 if err := Symlink(f.Name(), linkname); err != nil {
150 if runtime.GOOS == "android" && IsPermission(err) {
151 t.Skip("skipping test on Android; permission error creating symlink")
152 }
153 t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err)
154 }
155 defer Remove(linkname)
156
157
158
159 gid := Getgid()
160 t.Log("gid:", gid)
161 if err = Lchown(linkname, -1, gid); err != nil {
162 if err, ok := err.(*PathError); ok && err.Err == syscall.ENOSYS {
163 t.Skip("lchown is unavailable")
164 }
165 t.Fatalf("lchown %s -1 %d: %s", linkname, gid, err)
166 }
167 sys := dir.Sys().(*syscall.Stat_t)
168 checkUidGid(t, linkname, int(sys.Uid), gid)
169
170
171 groups, err := Getgroups()
172 if err != nil {
173 t.Fatalf("getgroups: %s", err)
174 }
175 t.Log("groups: ", groups)
176 for _, g := range groups {
177 if err = Lchown(linkname, -1, g); err != nil {
178 if testenv.SyscallIsNotSupported(err) {
179 t.Logf("lchown %s -1 %d: %s (error ignored)", f.Name(), g, err)
180
181 checkUidGid(t, f.Name(), int(sys.Uid), gid)
182 continue
183 }
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 if err = Lchown(linkname, -1, gid); err != nil {
192 t.Fatalf("lchown %s -1 %d: %s", f.Name(), gid, err)
193 }
194 }
195 }
196
197
198 func TestReaddirRemoveRace(t *testing.T) {
199 oldStat := *LstatP
200 defer func() { *LstatP = oldStat }()
201 *LstatP = func(name string) (FileInfo, error) {
202 if strings.HasSuffix(name, "some-file") {
203
204 return nil, ErrNotExist
205 }
206 return oldStat(name)
207 }
208 dir := t.TempDir()
209 if err := WriteFile(filepath.Join(dir, "some-file"), []byte("hello"), 0644); err != nil {
210 t.Fatal(err)
211 }
212 d, err := Open(dir)
213 if err != nil {
214 t.Fatal(err)
215 }
216 defer d.Close()
217 fis, err := d.Readdir(2)
218 if len(fis) == 0 && err == nil {
219
220 t.Fatal("Readdir = empty slice & err == nil")
221 }
222 if len(fis) != 0 || err != io.EOF {
223 t.Errorf("Readdir = %d entries: %v; want 0, io.EOF", len(fis), err)
224 for i, fi := range fis {
225 t.Errorf(" entry[%d]: %q, %v", i, fi.Name(), fi.Mode())
226 }
227 t.FailNow()
228 }
229 }
230
231
232 func TestMkdirStickyUmask(t *testing.T) {
233 if runtime.GOOS == "wasip1" {
234 t.Skip("file permissions not supported on " + runtime.GOOS)
235 }
236
237
238
239
240 const umask = 0077
241 dir := t.TempDir()
242
243 oldUmask := syscall.Umask(umask)
244 defer syscall.Umask(oldUmask)
245
246
247
248
249
250 control := filepath.Join(dir, "control")
251 if err := Mkdir(control, 0755); err != nil {
252 t.Fatal(err)
253 }
254 cfi, err := Stat(control)
255 if err != nil {
256 t.Fatal(err)
257 }
258
259 p := filepath.Join(dir, "dir1")
260 if err := Mkdir(p, ModeSticky|0755); err != nil {
261 t.Fatal(err)
262 }
263 fi, err := Stat(p)
264 if err != nil {
265 t.Fatal(err)
266 }
267
268 got := fi.Mode()
269 want := cfi.Mode() | ModeSticky
270 if got != want {
271 t.Errorf("Mkdir(_, ModeSticky|0755) created dir with mode %v; want %v", got, want)
272 }
273 }
274
275
276 func newFileTest(t *testing.T, blocking bool) {
277 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
278 t.Skipf("syscall.Pipe is not available on %s.", runtime.GOOS)
279 }
280
281 p := make([]int, 2)
282 if err := syscall.Pipe(p); err != nil {
283 t.Fatalf("pipe: %v", err)
284 }
285 defer syscall.Close(p[1])
286
287
288 if !blocking {
289 if err := syscall.SetNonblock(p[0], true); err != nil {
290 syscall.Close(p[0])
291 t.Fatalf("SetNonblock: %v", err)
292 }
293 }
294
295 file := NewFile(uintptr(p[0]), "notapipe")
296 if file == nil {
297 syscall.Close(p[0])
298 t.Fatalf("failed to convert fd to file!")
299 }
300 defer file.Close()
301
302 timeToWrite := 100 * time.Millisecond
303 timeToDeadline := 1 * time.Millisecond
304 if !blocking {
305
306
307 timeToWrite = 1 * time.Second
308 }
309
310
311 b := make([]byte, 1)
312 timer := time.AfterFunc(timeToWrite, func() { syscall.Write(p[1], []byte("a")) })
313 defer timer.Stop()
314 file.SetReadDeadline(time.Now().Add(timeToDeadline))
315 _, err := file.Read(b)
316 if !blocking {
317
318 if !isDeadlineExceeded(err) {
319 t.Fatalf("No timeout reading from file: %v", err)
320 }
321 } else {
322
323 if err != nil {
324 t.Fatalf("Error reading from file: %v", err)
325 }
326 }
327 }
328
329 func TestNewFileBlock(t *testing.T) {
330 t.Parallel()
331 newFileTest(t, true)
332 }
333
334 func TestNewFileNonBlock(t *testing.T) {
335 t.Parallel()
336 newFileTest(t, false)
337 }
338
339 func TestNewFileInvalid(t *testing.T) {
340 t.Parallel()
341 const negOne = ^uintptr(0)
342 if f := NewFile(negOne, "invalid"); f != nil {
343 t.Errorf("NewFile(-1) got %v want nil", f)
344 }
345 }
346
347 func TestSplitPath(t *testing.T) {
348 t.Parallel()
349 for _, tt := range []struct{ path, wantDir, wantBase string }{
350 {"a", ".", "a"},
351 {"a/", ".", "a"},
352 {"a//", ".", "a"},
353 {"a/b", "a", "b"},
354 {"a/b/", "a", "b"},
355 {"a/b/c", "a/b", "c"},
356 {"/a", "/", "a"},
357 {"/a/", "/", "a"},
358 {"/a/b", "/a", "b"},
359 {"/a/b/", "/a", "b"},
360 {"/a/b/c", "/a/b", "c"},
361 {"//a", "/", "a"},
362 {"//a/", "/", "a"},
363 {"///a", "/", "a"},
364 {"///a/", "/", "a"},
365 } {
366 if dir, base := SplitPath(tt.path); dir != tt.wantDir || base != tt.wantBase {
367 t.Errorf("splitPath(%q) = %q, %q, want %q, %q", tt.path, dir, base, tt.wantDir, tt.wantBase)
368 }
369 }
370 }
371
372
373
374
375
376 func TestIssue60181(t *testing.T) {
377 t.Chdir(t.TempDir())
378
379 want := "hello gopher"
380
381 a, err := CreateTemp(".", "a")
382 if err != nil {
383 t.Fatal(err)
384 }
385 a.WriteString(want[:5])
386 a.Close()
387
388 b, err := CreateTemp(".", "b")
389 if err != nil {
390 t.Fatal(err)
391 }
392 b.WriteString(want[5:])
393 b.Close()
394
395 afd, err := syscall.Open(a.Name(), syscall.O_RDWR|syscall.O_APPEND, 0)
396 if err != nil {
397 t.Fatal(err)
398 }
399
400 bfd, err := syscall.Open(b.Name(), syscall.O_RDONLY, 0)
401 if err != nil {
402 t.Fatal(err)
403 }
404
405 aa := NewFile(uintptr(afd), a.Name())
406 defer aa.Close()
407 bb := NewFile(uintptr(bfd), b.Name())
408 defer bb.Close()
409
410
411
412
413 _, err = io.Copy(aa, bb)
414 if err != nil {
415 t.Fatal(err)
416 }
417
418 buf, err := ReadFile(aa.Name())
419 if err != nil {
420 t.Fatal(err)
421 }
422
423 if got := string(buf); got != want {
424 t.Errorf("files not concatenated: got %q, want %q", got, want)
425 }
426 }
427
View as plain text