github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/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 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 ) 19 20 func init() { 21 isReadonlyError = func(err error) bool { return err == syscall.EROFS } 22 } 23 24 func checkUidGid(t *testing.T, path string, uid, gid int) { 25 dir, err := Lstat(path) 26 if err != nil { 27 t.Fatalf("Lstat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err) 28 } 29 sys := dir.Sys().(*syscall.Stat_t) 30 if int(sys.Uid) != uid { 31 t.Errorf("Lstat %q: uid %d want %d", path, sys.Uid, uid) 32 } 33 if int(sys.Gid) != gid { 34 t.Errorf("Lstat %q: gid %d want %d", path, sys.Gid, gid) 35 } 36 } 37 38 func TestChown(t *testing.T) { 39 // Use TempDir() to make sure we're on a local file system, 40 // so that the group ids returned by Getgroups will be allowed 41 // on the file. On NFS, the Getgroups groups are 42 // basically useless. 43 f := newFile("TestChown", t) 44 defer Remove(f.Name()) 45 defer f.Close() 46 dir, err := f.Stat() 47 if err != nil { 48 t.Fatalf("stat %s: %s", f.Name(), err) 49 } 50 51 // Can't change uid unless root, but can try 52 // changing the group id. First try our current group. 53 gid := Getgid() 54 t.Log("gid:", gid) 55 if err = Chown(f.Name(), -1, gid); err != nil { 56 t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err) 57 } 58 sys := dir.Sys().(*syscall.Stat_t) 59 checkUidGid(t, f.Name(), int(sys.Uid), gid) 60 61 // Then try all the auxiliary groups. 62 groups, err := Getgroups() 63 if err != nil { 64 t.Fatalf("getgroups: %s", err) 65 } 66 t.Log("groups: ", groups) 67 for _, g := range groups { 68 if err = Chown(f.Name(), -1, g); err != nil { 69 t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err) 70 } 71 checkUidGid(t, f.Name(), int(sys.Uid), g) 72 73 // change back to gid to test fd.Chown 74 if err = f.Chown(-1, gid); err != nil { 75 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err) 76 } 77 checkUidGid(t, f.Name(), int(sys.Uid), gid) 78 } 79 } 80 81 func TestFileChown(t *testing.T) { 82 // Use TempDir() to make sure we're on a local file system, 83 // so that the group ids returned by Getgroups will be allowed 84 // on the file. On NFS, the Getgroups groups are 85 // basically useless. 86 f := newFile("TestFileChown", t) 87 defer Remove(f.Name()) 88 defer f.Close() 89 dir, err := f.Stat() 90 if err != nil { 91 t.Fatalf("stat %s: %s", f.Name(), err) 92 } 93 94 // Can't change uid unless root, but can try 95 // changing the group id. First try our current group. 96 gid := Getgid() 97 t.Log("gid:", gid) 98 if err = f.Chown(-1, gid); err != nil { 99 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err) 100 } 101 sys := dir.Sys().(*syscall.Stat_t) 102 checkUidGid(t, f.Name(), int(sys.Uid), gid) 103 104 // Then try all the auxiliary groups. 105 groups, err := Getgroups() 106 if err != nil { 107 t.Fatalf("getgroups: %s", err) 108 } 109 t.Log("groups: ", groups) 110 for _, g := range groups { 111 if err = f.Chown(-1, g); err != nil { 112 t.Fatalf("fchown %s -1 %d: %s", f.Name(), g, err) 113 } 114 checkUidGid(t, f.Name(), int(sys.Uid), g) 115 116 // change back to gid to test fd.Chown 117 if err = f.Chown(-1, gid); err != nil { 118 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err) 119 } 120 checkUidGid(t, f.Name(), int(sys.Uid), gid) 121 } 122 } 123 124 func TestLchown(t *testing.T) { 125 // Use TempDir() to make sure we're on a local file system, 126 // so that the group ids returned by Getgroups will be allowed 127 // on the file. On NFS, the Getgroups groups are 128 // basically useless. 129 f := newFile("TestLchown", t) 130 defer Remove(f.Name()) 131 defer f.Close() 132 dir, err := f.Stat() 133 if err != nil { 134 t.Fatalf("stat %s: %s", f.Name(), err) 135 } 136 137 linkname := f.Name() + "2" 138 if err := Symlink(f.Name(), linkname); err != nil { 139 if runtime.GOOS == "android" && IsPermission(err) { 140 t.Skip("skipping test on Android; permission error creating symlink") 141 } 142 t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err) 143 } 144 defer Remove(linkname) 145 146 // Can't change uid unless root, but can try 147 // changing the group id. First try our current group. 148 gid := Getgid() 149 t.Log("gid:", gid) 150 if err = Lchown(linkname, -1, gid); err != nil { 151 t.Fatalf("lchown %s -1 %d: %s", linkname, gid, err) 152 } 153 sys := dir.Sys().(*syscall.Stat_t) 154 checkUidGid(t, linkname, int(sys.Uid), gid) 155 156 // Then try all the auxiliary groups. 157 groups, err := Getgroups() 158 if err != nil { 159 t.Fatalf("getgroups: %s", err) 160 } 161 t.Log("groups: ", groups) 162 for _, g := range groups { 163 if err = Lchown(linkname, -1, g); err != nil { 164 t.Fatalf("lchown %s -1 %d: %s", linkname, g, err) 165 } 166 checkUidGid(t, linkname, int(sys.Uid), g) 167 168 // Check that link target's gid is unchanged. 169 checkUidGid(t, f.Name(), int(sys.Uid), int(sys.Gid)) 170 } 171 } 172 173 // Issue 16919: Readdir must return a non-empty slice or an error. 174 func TestReaddirRemoveRace(t *testing.T) { 175 oldStat := *LstatP 176 defer func() { *LstatP = oldStat }() 177 *LstatP = func(name string) (FileInfo, error) { 178 if strings.HasSuffix(name, "some-file") { 179 // Act like it's been deleted. 180 return nil, ErrNotExist 181 } 182 return oldStat(name) 183 } 184 dir := newDir("TestReaddirRemoveRace", t) 185 defer RemoveAll(dir) 186 if err := ioutil.WriteFile(filepath.Join(dir, "some-file"), []byte("hello"), 0644); err != nil { 187 t.Fatal(err) 188 } 189 d, err := Open(dir) 190 if err != nil { 191 t.Fatal(err) 192 } 193 defer d.Close() 194 fis, err := d.Readdir(2) // notably, greater than zero 195 if len(fis) == 0 && err == nil { 196 // This is what used to happen (Issue 16919) 197 t.Fatal("Readdir = empty slice & err == nil") 198 } 199 if len(fis) != 0 || err != io.EOF { 200 t.Errorf("Readdir = %d entries: %v; want 0, io.EOF", len(fis), err) 201 for i, fi := range fis { 202 t.Errorf(" entry[%d]: %q, %v", i, fi.Name(), fi.Mode()) 203 } 204 t.FailNow() 205 } 206 }