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