github.com/tristanisham/sys@v0.0.0-20240326010300-a16cbabb7555/unix/syscall_darwin_test.go (about) 1 // Copyright 2018 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 package unix_test 6 7 import ( 8 "bytes" 9 "net" 10 "os" 11 "path/filepath" 12 "testing" 13 14 "golang.org/x/sys/unix" 15 ) 16 17 var testData = []byte("This is a test\n") 18 19 // stringsFromByteSlice converts a sequence of attributes to a []string. 20 // On Darwin, each entry is a NULL-terminated string. 21 func stringsFromByteSlice(buf []byte) []string { 22 var result []string 23 off := 0 24 for i, b := range buf { 25 if b == 0 { 26 result = append(result, string(buf[off:i])) 27 off = i + 1 28 } 29 } 30 return result 31 } 32 33 func createTestFile(t *testing.T) string { 34 filename := filepath.Join(t.TempDir(), t.Name()) 35 err := os.WriteFile(filename, testData, 0600) 36 if err != nil { 37 t.Fatal(err) 38 } 39 return filename 40 } 41 42 func TestClonefile(t *testing.T) { 43 fileName := createTestFile(t) 44 45 clonedName := fileName + "-cloned" 46 err := unix.Clonefile(fileName, clonedName, 0) 47 if err == unix.ENOSYS || err == unix.ENOTSUP { 48 t.Skip("clonefile is not available or supported, skipping test") 49 } else if err != nil { 50 t.Fatal(err) 51 } 52 53 clonedData, err := os.ReadFile(clonedName) 54 if err != nil { 55 t.Fatal(err) 56 } 57 58 if !bytes.Equal(testData, clonedData) { 59 t.Errorf("Clonefile: got %q, expected %q", clonedData, testData) 60 } 61 } 62 63 func TestClonefileatWithCwd(t *testing.T) { 64 fileName := createTestFile(t) 65 66 clonedName := fileName + "-cloned" 67 err := unix.Clonefileat(unix.AT_FDCWD, fileName, unix.AT_FDCWD, clonedName, 0) 68 if err == unix.ENOSYS || err == unix.ENOTSUP { 69 t.Skip("clonefileat is not available or supported, skipping test") 70 } else if err != nil { 71 t.Fatal(err) 72 } 73 74 clonedData, err := os.ReadFile(clonedName) 75 if err != nil { 76 t.Fatal(err) 77 } 78 79 if !bytes.Equal(testData, clonedData) { 80 t.Errorf("Clonefileat: got %q, expected %q", clonedData, testData) 81 } 82 } 83 84 func TestClonefileatWithRelativePaths(t *testing.T) { 85 srcFileName := createTestFile(t) 86 srcDir := filepath.Dir(srcFileName) 87 srcFd, err := unix.Open(srcDir, unix.O_RDONLY|unix.O_DIRECTORY, 0) 88 if err != nil { 89 t.Fatal(err) 90 } 91 defer unix.Close(srcFd) 92 93 dstDir := t.TempDir() 94 dstFd, err := unix.Open(dstDir, unix.O_RDONLY|unix.O_DIRECTORY, 0) 95 if err != nil { 96 t.Fatal(err) 97 } 98 defer unix.Close(dstFd) 99 100 dstFile, err := os.Create(filepath.Join(dstDir, "TestClonefileat")) 101 if err != nil { 102 t.Fatal(err) 103 } 104 err = os.Remove(dstFile.Name()) 105 if err != nil { 106 t.Fatal(err) 107 } 108 109 src := filepath.Base(srcFileName) 110 dst := filepath.Base(dstFile.Name()) 111 err = unix.Clonefileat(srcFd, src, dstFd, dst, 0) 112 if err == unix.ENOSYS || err == unix.ENOTSUP { 113 t.Skip("clonefileat is not available or supported, skipping test") 114 } else if err != nil { 115 t.Fatal(err) 116 } 117 118 clonedData, err := os.ReadFile(dstFile.Name()) 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 if !bytes.Equal(testData, clonedData) { 124 t.Errorf("Clonefileat: got %q, expected %q", clonedData, testData) 125 } 126 } 127 128 func TestFclonefileat(t *testing.T) { 129 fileName := createTestFile(t) 130 dir := filepath.Dir(fileName) 131 132 fd, err := unix.Open(fileName, unix.O_RDONLY, 0) 133 if err != nil { 134 t.Fatal(err) 135 } 136 defer unix.Close(fd) 137 138 dstFile, err := os.Create(filepath.Join(dir, "dst")) 139 if err != nil { 140 t.Fatal(err) 141 } 142 os.Remove(dstFile.Name()) 143 144 err = unix.Fclonefileat(fd, unix.AT_FDCWD, dstFile.Name(), 0) 145 if err == unix.ENOSYS || err == unix.ENOTSUP { 146 t.Skip("clonefileat is not available or supported, skipping test") 147 } else if err != nil { 148 t.Fatal(err) 149 } 150 151 clonedData, err := os.ReadFile(dstFile.Name()) 152 if err != nil { 153 t.Fatal(err) 154 } 155 156 if !bytes.Equal(testData, clonedData) { 157 t.Errorf("Fclonefileat: got %q, expected %q", clonedData, testData) 158 } 159 } 160 161 func TestFcntlFstore(t *testing.T) { 162 f, err := os.CreateTemp(t.TempDir(), t.Name()) 163 if err != nil { 164 t.Fatal(err) 165 } 166 defer f.Close() 167 168 fstore := &unix.Fstore_t{ 169 Flags: unix.F_ALLOCATEALL, 170 Posmode: unix.F_PEOFPOSMODE, 171 Offset: 0, 172 Length: 1 << 10, 173 } 174 err = unix.FcntlFstore(f.Fd(), unix.F_PREALLOCATE, fstore) 175 if err == unix.EOPNOTSUPP { 176 t.Skipf("fcntl with F_PREALLOCATE not supported, skipping test") 177 } else if err != nil { 178 t.Fatalf("FcntlFstore: %v", err) 179 } 180 181 st, err := f.Stat() 182 if err != nil { 183 t.Fatal(err) 184 } 185 186 if st.Size() != 0 { 187 t.Errorf("FcntlFstore: got size = %d, want %d", st.Size(), 0) 188 } 189 190 } 191 192 func TestGetsockoptXucred(t *testing.T) { 193 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) 194 if err != nil { 195 t.Fatalf("Socketpair: %v", err) 196 } 197 198 srvFile := os.NewFile(uintptr(fds[0]), "server") 199 cliFile := os.NewFile(uintptr(fds[1]), "client") 200 defer srvFile.Close() 201 defer cliFile.Close() 202 203 srv, err := net.FileConn(srvFile) 204 if err != nil { 205 t.Fatalf("FileConn: %v", err) 206 } 207 defer srv.Close() 208 209 cli, err := net.FileConn(cliFile) 210 if err != nil { 211 t.Fatalf("FileConn: %v", err) 212 } 213 defer cli.Close() 214 215 cred, err := unix.GetsockoptXucred(fds[1], unix.SOL_LOCAL, unix.LOCAL_PEERCRED) 216 if err != nil { 217 t.Fatal(err) 218 } 219 t.Logf("got: %+v", cred) 220 if got, want := cred.Uid, os.Getuid(); int(got) != int(want) { 221 t.Errorf("uid = %v; want %v", got, want) 222 } 223 if cred.Ngroups > 0 { 224 if got, want := cred.Groups[0], os.Getgid(); int(got) != int(want) { 225 t.Errorf("gid = %v; want %v", got, want) 226 } 227 } 228 } 229 230 func TestSysctlKinfoProc(t *testing.T) { 231 pid := unix.Getpid() 232 kp, err := unix.SysctlKinfoProc("kern.proc.pid", pid) 233 if err != nil { 234 t.Fatalf("SysctlKinfoProc: %v", err) 235 } 236 if got, want := int(kp.Proc.P_pid), pid; got != want { 237 t.Errorf("got pid %d, want %d", got, want) 238 } 239 } 240 241 func TestSysctlKinfoProcSlice(t *testing.T) { 242 kps, err := unix.SysctlKinfoProcSlice("kern.proc.all") 243 if err != nil { 244 t.Fatalf("SysctlKinfoProc: %v", err) 245 } 246 if len(kps) == 0 { 247 t.Errorf("SysctlKinfoProcSlice: expected at least one process") 248 } 249 250 uid := unix.Getuid() 251 kps, err = unix.SysctlKinfoProcSlice("kern.proc.uid", uid) 252 if err != nil { 253 t.Fatalf("SysctlKinfoProc: %v", err) 254 } 255 if len(kps) == 0 { 256 t.Errorf("SysctlKinfoProcSlice: expected at least one process") 257 } 258 259 for _, kp := range kps { 260 if got, want := int(kp.Eproc.Ucred.Uid), uid; got != want { 261 t.Errorf("process %d: got uid %d, want %d", kp.Proc.P_pid, got, want) 262 } 263 } 264 }