github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/os/os_unix_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris 6 7 package os_test 8 9 import ( 10 "io" 11 "io/ioutil" 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 // For TestRawConnReadWrite. 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 // Use TempDir() to make sure we're on a local file system, 44 // so that the group ids returned by Getgroups will be allowed 45 // on the file. On NFS, the Getgroups groups are 46 // basically useless. 47 f := newFile("TestChown", t) 48 defer Remove(f.Name()) 49 defer f.Close() 50 dir, err := f.Stat() 51 if err != nil { 52 t.Fatalf("stat %s: %s", f.Name(), err) 53 } 54 55 // Can't change uid unless root, but can try 56 // changing the group id. First try our current group. 57 gid := Getgid() 58 t.Log("gid:", gid) 59 if err = Chown(f.Name(), -1, gid); err != nil { 60 t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err) 61 } 62 sys := dir.Sys().(*syscall.Stat_t) 63 checkUidGid(t, f.Name(), int(sys.Uid), gid) 64 65 // Then try all the auxiliary groups. 66 groups, err := Getgroups() 67 if err != nil { 68 t.Fatalf("getgroups: %s", err) 69 } 70 t.Log("groups: ", groups) 71 for _, g := range groups { 72 if err = Chown(f.Name(), -1, g); err != nil { 73 t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err) 74 } 75 checkUidGid(t, f.Name(), int(sys.Uid), g) 76 77 // change back to gid to test fd.Chown 78 if err = f.Chown(-1, gid); err != nil { 79 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err) 80 } 81 checkUidGid(t, f.Name(), int(sys.Uid), gid) 82 } 83 } 84 85 func TestFileChown(t *testing.T) { 86 // Use TempDir() to make sure we're on a local file system, 87 // so that the group ids returned by Getgroups will be allowed 88 // on the file. On NFS, the Getgroups groups are 89 // basically useless. 90 f := newFile("TestFileChown", t) 91 defer Remove(f.Name()) 92 defer f.Close() 93 dir, err := f.Stat() 94 if err != nil { 95 t.Fatalf("stat %s: %s", f.Name(), err) 96 } 97 98 // Can't change uid unless root, but can try 99 // changing the group id. First try our current group. 100 gid := Getgid() 101 t.Log("gid:", gid) 102 if err = f.Chown(-1, gid); err != nil { 103 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err) 104 } 105 sys := dir.Sys().(*syscall.Stat_t) 106 checkUidGid(t, f.Name(), int(sys.Uid), gid) 107 108 // Then try all the auxiliary groups. 109 groups, err := Getgroups() 110 if err != nil { 111 t.Fatalf("getgroups: %s", err) 112 } 113 t.Log("groups: ", groups) 114 for _, g := range groups { 115 if err = f.Chown(-1, g); err != nil { 116 t.Fatalf("fchown %s -1 %d: %s", f.Name(), g, err) 117 } 118 checkUidGid(t, f.Name(), int(sys.Uid), g) 119 120 // change back to gid to test fd.Chown 121 if err = f.Chown(-1, gid); err != nil { 122 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err) 123 } 124 checkUidGid(t, f.Name(), int(sys.Uid), gid) 125 } 126 } 127 128 func TestLchown(t *testing.T) { 129 // Use TempDir() to make sure we're on a local file system, 130 // so that the group ids returned by Getgroups will be allowed 131 // on the file. On NFS, the Getgroups groups are 132 // basically useless. 133 f := newFile("TestLchown", t) 134 defer Remove(f.Name()) 135 defer f.Close() 136 dir, err := f.Stat() 137 if err != nil { 138 t.Fatalf("stat %s: %s", f.Name(), err) 139 } 140 141 linkname := f.Name() + "2" 142 if err := Symlink(f.Name(), linkname); err != nil { 143 if runtime.GOOS == "android" && IsPermission(err) { 144 t.Skip("skipping test on Android; permission error creating symlink") 145 } 146 t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err) 147 } 148 defer Remove(linkname) 149 150 // Can't change uid unless root, but can try 151 // changing the group id. First try our current group. 152 gid := Getgid() 153 t.Log("gid:", gid) 154 if err = Lchown(linkname, -1, gid); err != nil { 155 t.Fatalf("lchown %s -1 %d: %s", linkname, gid, err) 156 } 157 sys := dir.Sys().(*syscall.Stat_t) 158 checkUidGid(t, linkname, int(sys.Uid), gid) 159 160 // Then try all the auxiliary groups. 161 groups, err := Getgroups() 162 if err != nil { 163 t.Fatalf("getgroups: %s", err) 164 } 165 t.Log("groups: ", groups) 166 for _, g := range groups { 167 if err = Lchown(linkname, -1, g); err != nil { 168 t.Fatalf("lchown %s -1 %d: %s", linkname, g, err) 169 } 170 checkUidGid(t, linkname, int(sys.Uid), g) 171 172 // Check that link target's gid is unchanged. 173 checkUidGid(t, f.Name(), int(sys.Uid), int(sys.Gid)) 174 } 175 } 176 177 // Issue 16919: Readdir must return a non-empty slice or an error. 178 func TestReaddirRemoveRace(t *testing.T) { 179 oldStat := *LstatP 180 defer func() { *LstatP = oldStat }() 181 *LstatP = func(name string) (FileInfo, error) { 182 if strings.HasSuffix(name, "some-file") { 183 // Act like it's been deleted. 184 return nil, ErrNotExist 185 } 186 return oldStat(name) 187 } 188 dir := newDir("TestReaddirRemoveRace", t) 189 defer RemoveAll(dir) 190 if err := ioutil.WriteFile(filepath.Join(dir, "some-file"), []byte("hello"), 0644); err != nil { 191 t.Fatal(err) 192 } 193 d, err := Open(dir) 194 if err != nil { 195 t.Fatal(err) 196 } 197 defer d.Close() 198 fis, err := d.Readdir(2) // notably, greater than zero 199 if len(fis) == 0 && err == nil { 200 // This is what used to happen (Issue 16919) 201 t.Fatal("Readdir = empty slice & err == nil") 202 } 203 if len(fis) != 0 || err != io.EOF { 204 t.Errorf("Readdir = %d entries: %v; want 0, io.EOF", len(fis), err) 205 for i, fi := range fis { 206 t.Errorf(" entry[%d]: %q, %v", i, fi.Name(), fi.Mode()) 207 } 208 t.FailNow() 209 } 210 } 211 212 // Issue 23120: respect umask when doing Mkdir with the sticky bit 213 func TestMkdirStickyUmask(t *testing.T) { 214 const umask = 0077 215 dir := newDir("TestMkdirStickyUmask", t) 216 defer RemoveAll(dir) 217 oldUmask := syscall.Umask(umask) 218 defer syscall.Umask(oldUmask) 219 p := filepath.Join(dir, "dir1") 220 if err := Mkdir(p, ModeSticky|0755); err != nil { 221 t.Fatal(err) 222 } 223 fi, err := Stat(p) 224 if err != nil { 225 t.Fatal(err) 226 } 227 if mode := fi.Mode(); (mode&umask) != 0 || (mode&^ModePerm) != (ModeDir|ModeSticky) { 228 t.Errorf("unexpected mode %s", mode) 229 } 230 } 231 232 // See also issues: 22939, 24331 233 func newFileTest(t *testing.T, blocking bool) { 234 p := make([]int, 2) 235 if err := syscall.Pipe(p); err != nil { 236 t.Fatalf("pipe: %v", err) 237 } 238 defer syscall.Close(p[1]) 239 240 // Set the read-side to non-blocking. 241 if !blocking { 242 if err := syscall.SetNonblock(p[0], true); err != nil { 243 syscall.Close(p[0]) 244 t.Fatalf("SetNonblock: %v", err) 245 } 246 } 247 // Convert it to a file. 248 file := NewFile(uintptr(p[0]), "notapipe") 249 if file == nil { 250 syscall.Close(p[0]) 251 t.Fatalf("failed to convert fd to file!") 252 } 253 defer file.Close() 254 255 // Try to read with deadline (but don't block forever). 256 b := make([]byte, 1) 257 // Send something after 100ms. 258 timer := time.AfterFunc(100*time.Millisecond, func() { syscall.Write(p[1], []byte("a")) }) 259 defer timer.Stop() 260 file.SetReadDeadline(time.Now().Add(10 * time.Millisecond)) 261 _, err := file.Read(b) 262 if !blocking { 263 // We want it to fail with a timeout. 264 if !IsTimeout(err) { 265 t.Fatalf("No timeout reading from file: %v", err) 266 } 267 } else { 268 // We want it to succeed after 100ms 269 if err != nil { 270 t.Fatalf("Error reading from file: %v", err) 271 } 272 } 273 } 274 275 func TestNewFileBlock(t *testing.T) { 276 t.Parallel() 277 newFileTest(t, true) 278 } 279 280 func TestNewFileNonBlock(t *testing.T) { 281 t.Parallel() 282 newFileTest(t, false) 283 } 284 285 func TestSplitPath(t *testing.T) { 286 t.Parallel() 287 for _, tt := range []struct{ path, wantDir, wantBase string }{ 288 {"a", ".", "a"}, 289 {"a/", ".", "a"}, 290 {"a//", ".", "a"}, 291 {"a/b", "a", "b"}, 292 {"a/b/", "a", "b"}, 293 {"a/b/c", "a/b", "c"}, 294 {"/a", "/", "a"}, 295 {"/a/", "/", "a"}, 296 {"/a/b", "/a", "b"}, 297 {"/a/b/", "/a", "b"}, 298 {"/a/b/c", "/a/b", "c"}, 299 {"//a", "/", "a"}, 300 {"//a/", "/", "a"}, 301 {"///a", "/", "a"}, 302 {"///a/", "/", "a"}, 303 } { 304 if dir, base := SplitPath(tt.path); dir != tt.wantDir || base != tt.wantBase { 305 t.Errorf("splitPath(%q) = %q, %q, want %q, %q", tt.path, dir, base, tt.wantDir, tt.wantBase) 306 } 307 } 308 }