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