github.com/xingly-cn/shorturl-go@v0.0.0-20220110130535-e21de4659f74/pkg/mod/golang.org/x/sys@v0.0.0-20200323222414-85ca7c5b95cd/unix/syscall_unix_test.go (about) 1 // Copyright 2013 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 unix_test 8 9 import ( 10 "flag" 11 "fmt" 12 "io/ioutil" 13 "net" 14 "os" 15 "os/exec" 16 "path/filepath" 17 "runtime" 18 "strconv" 19 "syscall" 20 "testing" 21 "time" 22 23 "golang.org/x/sys/unix" 24 ) 25 26 // Tests that below functions, structures and constants are consistent 27 // on all Unix-like systems. 28 func _() { 29 // program scheduling priority functions and constants 30 var ( 31 _ func(int, int, int) error = unix.Setpriority 32 _ func(int, int) (int, error) = unix.Getpriority 33 ) 34 const ( 35 _ int = unix.PRIO_USER 36 _ int = unix.PRIO_PROCESS 37 _ int = unix.PRIO_PGRP 38 ) 39 40 // termios constants 41 const ( 42 _ int = unix.TCIFLUSH 43 _ int = unix.TCIOFLUSH 44 _ int = unix.TCOFLUSH 45 ) 46 47 // fcntl file locking structure and constants 48 var ( 49 _ = unix.Flock_t{ 50 Type: int16(0), 51 Whence: int16(0), 52 Start: int64(0), 53 Len: int64(0), 54 Pid: int32(0), 55 } 56 ) 57 const ( 58 _ = unix.F_GETLK 59 _ = unix.F_SETLK 60 _ = unix.F_SETLKW 61 ) 62 } 63 64 func TestErrnoSignalName(t *testing.T) { 65 testErrors := []struct { 66 num syscall.Errno 67 name string 68 }{ 69 {syscall.EPERM, "EPERM"}, 70 {syscall.EINVAL, "EINVAL"}, 71 {syscall.ENOENT, "ENOENT"}, 72 } 73 74 for _, te := range testErrors { 75 t.Run(fmt.Sprintf("%d/%s", te.num, te.name), func(t *testing.T) { 76 e := unix.ErrnoName(te.num) 77 if e != te.name { 78 t.Errorf("ErrnoName(%d) returned %s, want %s", te.num, e, te.name) 79 } 80 }) 81 } 82 83 testSignals := []struct { 84 num syscall.Signal 85 name string 86 }{ 87 {syscall.SIGHUP, "SIGHUP"}, 88 {syscall.SIGPIPE, "SIGPIPE"}, 89 {syscall.SIGSEGV, "SIGSEGV"}, 90 } 91 92 for _, ts := range testSignals { 93 t.Run(fmt.Sprintf("%d/%s", ts.num, ts.name), func(t *testing.T) { 94 s := unix.SignalName(ts.num) 95 if s != ts.name { 96 t.Errorf("SignalName(%d) returned %s, want %s", ts.num, s, ts.name) 97 } 98 }) 99 } 100 } 101 102 func TestSignalNum(t *testing.T) { 103 testSignals := []struct { 104 name string 105 want syscall.Signal 106 }{ 107 {"SIGHUP", syscall.SIGHUP}, 108 {"SIGPIPE", syscall.SIGPIPE}, 109 {"SIGSEGV", syscall.SIGSEGV}, 110 {"NONEXISTS", 0}, 111 } 112 for _, ts := range testSignals { 113 t.Run(fmt.Sprintf("%s/%d", ts.name, ts.want), func(t *testing.T) { 114 got := unix.SignalNum(ts.name) 115 if got != ts.want { 116 t.Errorf("SignalNum(%s) returned %d, want %d", ts.name, got, ts.want) 117 } 118 }) 119 120 } 121 } 122 123 func TestFcntlInt(t *testing.T) { 124 t.Parallel() 125 file, err := ioutil.TempFile("", "TestFnctlInt") 126 if err != nil { 127 t.Fatal(err) 128 } 129 defer os.Remove(file.Name()) 130 defer file.Close() 131 f := file.Fd() 132 flags, err := unix.FcntlInt(f, unix.F_GETFD, 0) 133 if err != nil { 134 t.Fatal(err) 135 } 136 if flags&unix.FD_CLOEXEC == 0 { 137 t.Errorf("flags %#x do not include FD_CLOEXEC", flags) 138 } 139 } 140 141 // TestFcntlFlock tests whether the file locking structure matches 142 // the calling convention of each kernel. 143 func TestFcntlFlock(t *testing.T) { 144 name := filepath.Join(os.TempDir(), "TestFcntlFlock") 145 fd, err := unix.Open(name, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0) 146 if err != nil { 147 t.Fatalf("Open failed: %v", err) 148 } 149 defer unix.Unlink(name) 150 defer unix.Close(fd) 151 flock := unix.Flock_t{ 152 Type: unix.F_RDLCK, 153 Start: 0, Len: 0, Whence: 1, 154 } 155 if err := unix.FcntlFlock(uintptr(fd), unix.F_GETLK, &flock); err != nil { 156 t.Fatalf("FcntlFlock failed: %v", err) 157 } 158 } 159 160 // TestPassFD tests passing a file descriptor over a Unix socket. 161 // 162 // This test involved both a parent and child process. The parent 163 // process is invoked as a normal test, with "go test", which then 164 // runs the child process by running the current test binary with args 165 // "-test.run=^TestPassFD$" and an environment variable used to signal 166 // that the test should become the child process instead. 167 func TestPassFD(t *testing.T) { 168 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { 169 t.Skip("cannot exec subprocess on iOS, skipping test") 170 } 171 172 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { 173 passFDChild() 174 return 175 } 176 177 if runtime.GOOS == "aix" { 178 // Unix network isn't properly working on AIX 179 // 7.2 with Technical Level < 2 180 out, err := exec.Command("oslevel", "-s").Output() 181 if err != nil { 182 t.Skipf("skipping on AIX because oslevel -s failed: %v", err) 183 } 184 185 if len(out) < len("7200-XX-ZZ-YYMM") { // AIX 7.2, Tech Level XX, Service Pack ZZ, date YYMM 186 t.Skip("skipping on AIX because oslevel -s hasn't the right length") 187 } 188 aixVer := string(out[:4]) 189 tl, err := strconv.Atoi(string(out[5:7])) 190 if err != nil { 191 t.Skipf("skipping on AIX because oslevel -s output cannot be parsed: %v", err) 192 } 193 if aixVer < "7200" || (aixVer == "7200" && tl < 2) { 194 t.Skip("skipped on AIX versions previous to 7.2 TL 2") 195 } 196 } 197 198 tempDir, err := ioutil.TempDir("", "TestPassFD") 199 if err != nil { 200 t.Fatal(err) 201 } 202 defer os.RemoveAll(tempDir) 203 204 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) 205 if err != nil { 206 t.Fatalf("Socketpair: %v", err) 207 } 208 defer unix.Close(fds[0]) 209 defer unix.Close(fds[1]) 210 writeFile := os.NewFile(uintptr(fds[0]), "child-writes") 211 readFile := os.NewFile(uintptr(fds[1]), "parent-reads") 212 defer writeFile.Close() 213 defer readFile.Close() 214 215 cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) 216 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} 217 if lp := os.Getenv("LD_LIBRARY_PATH"); lp != "" { 218 cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+lp) 219 } 220 cmd.ExtraFiles = []*os.File{writeFile} 221 222 out, err := cmd.CombinedOutput() 223 if len(out) > 0 || err != nil { 224 t.Fatalf("child process: %q, %v", out, err) 225 } 226 227 c, err := net.FileConn(readFile) 228 if err != nil { 229 t.Fatalf("FileConn: %v", err) 230 } 231 defer c.Close() 232 233 uc, ok := c.(*net.UnixConn) 234 if !ok { 235 t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c) 236 } 237 238 buf := make([]byte, 32) // expect 1 byte 239 oob := make([]byte, 32) // expect 24 bytes 240 closeUnix := time.AfterFunc(5*time.Second, func() { 241 t.Logf("timeout reading from unix socket") 242 uc.Close() 243 }) 244 _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) 245 if err != nil { 246 t.Fatalf("ReadMsgUnix: %v", err) 247 } 248 closeUnix.Stop() 249 250 scms, err := unix.ParseSocketControlMessage(oob[:oobn]) 251 if err != nil { 252 t.Fatalf("ParseSocketControlMessage: %v", err) 253 } 254 if len(scms) != 1 { 255 t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms) 256 } 257 scm := scms[0] 258 gotFds, err := unix.ParseUnixRights(&scm) 259 if err != nil { 260 t.Fatalf("unix.ParseUnixRights: %v", err) 261 } 262 if len(gotFds) != 1 { 263 t.Fatalf("wanted 1 fd; got %#v", gotFds) 264 } 265 266 f := os.NewFile(uintptr(gotFds[0]), "fd-from-child") 267 defer f.Close() 268 269 got, err := ioutil.ReadAll(f) 270 want := "Hello from child process!\n" 271 if string(got) != want { 272 t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want) 273 } 274 } 275 276 // passFDChild is the child process used by TestPassFD. 277 func passFDChild() { 278 defer os.Exit(0) 279 280 // Look for our fd. It should be fd 3, but we work around an fd leak 281 // bug here (http://golang.org/issue/2603) to let it be elsewhere. 282 var uc *net.UnixConn 283 for fd := uintptr(3); fd <= 10; fd++ { 284 f := os.NewFile(fd, "unix-conn") 285 var ok bool 286 netc, _ := net.FileConn(f) 287 uc, ok = netc.(*net.UnixConn) 288 if ok { 289 break 290 } 291 } 292 if uc == nil { 293 fmt.Println("failed to find unix fd") 294 return 295 } 296 297 // Make a file f to send to our parent process on uc. 298 // We make it in tempDir, which our parent will clean up. 299 flag.Parse() 300 tempDir := flag.Arg(0) 301 f, err := ioutil.TempFile(tempDir, "") 302 if err != nil { 303 fmt.Printf("TempFile: %v", err) 304 return 305 } 306 307 f.Write([]byte("Hello from child process!\n")) 308 f.Seek(0, 0) 309 310 rights := unix.UnixRights(int(f.Fd())) 311 dummyByte := []byte("x") 312 n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil) 313 if err != nil { 314 fmt.Printf("WriteMsgUnix: %v", err) 315 return 316 } 317 if n != 1 || oobn != len(rights) { 318 fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights)) 319 return 320 } 321 } 322 323 // TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, 324 // and ParseUnixRights are able to successfully round-trip lists of file descriptors. 325 func TestUnixRightsRoundtrip(t *testing.T) { 326 testCases := [...][][]int{ 327 {{42}}, 328 {{1, 2}}, 329 {{3, 4, 5}}, 330 {{}}, 331 {{1, 2}, {3, 4, 5}, {}, {7}}, 332 } 333 for _, testCase := range testCases { 334 b := []byte{} 335 var n int 336 for _, fds := range testCase { 337 // Last assignment to n wins 338 n = len(b) + unix.CmsgLen(4*len(fds)) 339 b = append(b, unix.UnixRights(fds...)...) 340 } 341 // Truncate b 342 b = b[:n] 343 344 scms, err := unix.ParseSocketControlMessage(b) 345 if err != nil { 346 t.Fatalf("ParseSocketControlMessage: %v", err) 347 } 348 if len(scms) != len(testCase) { 349 t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms) 350 } 351 for i, scm := range scms { 352 gotFds, err := unix.ParseUnixRights(&scm) 353 if err != nil { 354 t.Fatalf("ParseUnixRights: %v", err) 355 } 356 wantFds := testCase[i] 357 if len(gotFds) != len(wantFds) { 358 t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds) 359 } 360 for j, fd := range gotFds { 361 if fd != wantFds[j] { 362 t.Fatalf("expected fd %v, got %v", wantFds[j], fd) 363 } 364 } 365 } 366 } 367 } 368 369 func TestRlimit(t *testing.T) { 370 var rlimit, zero unix.Rlimit 371 err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit) 372 if err != nil { 373 t.Fatalf("Getrlimit: save failed: %v", err) 374 } 375 if zero == rlimit { 376 t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit) 377 } 378 set := rlimit 379 set.Cur = set.Max - 1 380 if runtime.GOOS == "darwin" && set.Cur > 10240 { 381 // The max file limit is 10240, even though 382 // the max returned by Getrlimit is 1<<63-1. 383 // This is OPEN_MAX in sys/syslimits.h. 384 set.Cur = 10240 385 } 386 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &set) 387 if err != nil { 388 t.Fatalf("Setrlimit: set failed: %#v %v", set, err) 389 } 390 var get unix.Rlimit 391 err = unix.Getrlimit(unix.RLIMIT_NOFILE, &get) 392 if err != nil { 393 t.Fatalf("Getrlimit: get failed: %v", err) 394 } 395 set = rlimit 396 set.Cur = set.Max - 1 397 if set != get { 398 // Seems like Darwin requires some privilege to 399 // increase the soft limit of rlimit sandbox, though 400 // Setrlimit never reports an error. 401 switch runtime.GOOS { 402 case "darwin": 403 default: 404 t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get) 405 } 406 } 407 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit) 408 if err != nil { 409 t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err) 410 } 411 } 412 413 func TestSeekFailure(t *testing.T) { 414 _, err := unix.Seek(-1, 0, 0) 415 if err == nil { 416 t.Fatalf("Seek(-1, 0, 0) did not fail") 417 } 418 str := err.Error() // used to crash on Linux 419 t.Logf("Seek: %v", str) 420 if str == "" { 421 t.Fatalf("Seek(-1, 0, 0) return error with empty message") 422 } 423 } 424 425 func TestSetsockoptString(t *testing.T) { 426 // should not panic on empty string, see issue #31277 427 err := unix.SetsockoptString(-1, 0, 0, "") 428 if err == nil { 429 t.Fatalf("SetsockoptString: did not fail") 430 } 431 } 432 433 func TestDup(t *testing.T) { 434 file, err := ioutil.TempFile("", "TestDup") 435 if err != nil { 436 t.Fatalf("Tempfile failed: %v", err) 437 } 438 defer os.Remove(file.Name()) 439 defer file.Close() 440 f := int(file.Fd()) 441 442 newFd, err := unix.Dup(f) 443 if err != nil { 444 t.Fatalf("Dup: %v", err) 445 } 446 447 // Create and reserve a file descriptor. 448 // Dup2 automatically closes it before reusing it. 449 nullFile, err := os.Open("/dev/null") 450 if err != nil { 451 t.Fatal(err) 452 } 453 dupFd := int(file.Fd()) 454 err = unix.Dup2(newFd, dupFd) 455 if err != nil { 456 t.Fatalf("Dup2: %v", err) 457 } 458 // Keep the dummy file open long enough to not be closed in 459 // its finalizer. 460 runtime.KeepAlive(nullFile) 461 462 b1 := []byte("Test123") 463 b2 := make([]byte, 7) 464 _, err = unix.Write(dupFd, b1) 465 if err != nil { 466 t.Fatalf("Write to dup2 fd failed: %v", err) 467 } 468 _, err = unix.Seek(f, 0, 0) 469 if err != nil { 470 t.Fatalf("Seek failed: %v", err) 471 } 472 _, err = unix.Read(f, b2) 473 if err != nil { 474 t.Fatalf("Read back failed: %v", err) 475 } 476 if string(b1) != string(b2) { 477 t.Errorf("Dup: stdout write not in file, expected %v, got %v", string(b1), string(b2)) 478 } 479 } 480 481 func TestPoll(t *testing.T) { 482 if runtime.GOOS == "android" || 483 (runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")) { 484 t.Skip("mkfifo syscall is not available on android and iOS, skipping test") 485 } 486 487 defer chtmpdir(t)() 488 f, cleanup := mktmpfifo(t) 489 defer cleanup() 490 491 const timeout = 100 492 493 ok := make(chan bool, 1) 494 go func() { 495 select { 496 case <-time.After(10 * timeout * time.Millisecond): 497 t.Errorf("Poll: failed to timeout after %d milliseconds", 10*timeout) 498 case <-ok: 499 } 500 }() 501 502 fds := []unix.PollFd{{Fd: int32(f.Fd()), Events: unix.POLLIN}} 503 n, err := unix.Poll(fds, timeout) 504 ok <- true 505 if err != nil { 506 t.Errorf("Poll: unexpected error: %v", err) 507 return 508 } 509 if n != 0 { 510 t.Errorf("Poll: wrong number of events: got %v, expected %v", n, 0) 511 return 512 } 513 } 514 515 func TestSelect(t *testing.T) { 516 for { 517 n, err := unix.Select(0, nil, nil, nil, &unix.Timeval{Sec: 0, Usec: 0}) 518 if err == unix.EINTR { 519 t.Logf("Select interrupted") 520 continue 521 } else if err != nil { 522 t.Fatalf("Select: %v", err) 523 } 524 if n != 0 { 525 t.Fatalf("Select: got %v ready file descriptors, expected 0", n) 526 } 527 break 528 } 529 530 dur := 250 * time.Millisecond 531 tv := unix.NsecToTimeval(int64(dur)) 532 var took time.Duration 533 for { 534 start := time.Now() 535 n, err := unix.Select(0, nil, nil, nil, &tv) 536 took = time.Since(start) 537 if err == unix.EINTR { 538 t.Logf("Select interrupted after %v", took) 539 continue 540 } else if err != nil { 541 t.Fatalf("Select: %v", err) 542 } 543 if n != 0 { 544 t.Fatalf("Select: got %v ready file descriptors, expected 0", n) 545 } 546 break 547 } 548 549 // On some BSDs the actual timeout might also be slightly less than the requested. 550 // Add an acceptable margin to avoid flaky tests. 551 if took < dur*2/3 { 552 t.Errorf("Select: got %v timeout, expected at least %v", took, dur) 553 } 554 555 rr, ww, err := os.Pipe() 556 if err != nil { 557 t.Fatal(err) 558 } 559 defer rr.Close() 560 defer ww.Close() 561 562 if _, err := ww.Write([]byte("HELLO GOPHER")); err != nil { 563 t.Fatal(err) 564 } 565 566 rFdSet := &unix.FdSet{} 567 fd := int(rr.Fd()) 568 rFdSet.Set(fd) 569 570 for { 571 n, err := unix.Select(fd+1, rFdSet, nil, nil, nil) 572 if err == unix.EINTR { 573 t.Log("Select interrupted") 574 continue 575 } else if err != nil { 576 t.Fatalf("Select: %v", err) 577 } 578 if n != 1 { 579 t.Fatalf("Select: got %v ready file descriptors, expected 1", n) 580 } 581 break 582 } 583 } 584 585 func TestGetwd(t *testing.T) { 586 fd, err := os.Open(".") 587 if err != nil { 588 t.Fatalf("Open .: %s", err) 589 } 590 defer fd.Close() 591 // Directory list for test. Do not worry if any are symlinks or do not 592 // exist on some common unix desktop environments. That will be checked. 593 dirs := []string{"/", "/usr/bin", "/etc", "/var", "/opt"} 594 switch runtime.GOOS { 595 case "android": 596 dirs = []string{"/", "/system/bin"} 597 case "darwin": 598 switch runtime.GOARCH { 599 case "arm", "arm64": 600 d1, err := ioutil.TempDir("", "d1") 601 if err != nil { 602 t.Fatalf("TempDir: %v", err) 603 } 604 d2, err := ioutil.TempDir("", "d2") 605 if err != nil { 606 t.Fatalf("TempDir: %v", err) 607 } 608 dirs = []string{d1, d2} 609 } 610 } 611 oldwd := os.Getenv("PWD") 612 for _, d := range dirs { 613 // Check whether d exists, is a dir and that d's path does not contain a symlink 614 fi, err := os.Stat(d) 615 if err != nil || !fi.IsDir() { 616 t.Logf("Test dir %s stat error (%v) or not a directory, skipping", d, err) 617 continue 618 } 619 check, err := filepath.EvalSymlinks(d) 620 if err != nil || check != d { 621 t.Logf("Test dir %s (%s) is symlink or other error (%v), skipping", d, check, err) 622 continue 623 } 624 err = os.Chdir(d) 625 if err != nil { 626 t.Fatalf("Chdir: %v", err) 627 } 628 pwd, err := unix.Getwd() 629 if err != nil { 630 t.Fatalf("Getwd in %s: %s", d, err) 631 } 632 os.Setenv("PWD", oldwd) 633 err = fd.Chdir() 634 if err != nil { 635 // We changed the current directory and cannot go back. 636 // Don't let the tests continue; they'll scribble 637 // all over some other directory. 638 fmt.Fprintf(os.Stderr, "fchdir back to dot failed: %s\n", err) 639 os.Exit(1) 640 } 641 if pwd != d { 642 t.Fatalf("Getwd returned %q want %q", pwd, d) 643 } 644 } 645 } 646 647 func TestFstatat(t *testing.T) { 648 defer chtmpdir(t)() 649 650 touch(t, "file1") 651 652 var st1 unix.Stat_t 653 err := unix.Stat("file1", &st1) 654 if err != nil { 655 t.Fatalf("Stat: %v", err) 656 } 657 658 var st2 unix.Stat_t 659 err = unix.Fstatat(unix.AT_FDCWD, "file1", &st2, 0) 660 if err != nil { 661 t.Fatalf("Fstatat: %v", err) 662 } 663 664 if st1 != st2 { 665 t.Errorf("Fstatat: returned stat does not match Stat") 666 } 667 668 err = os.Symlink("file1", "symlink1") 669 if err != nil { 670 t.Fatal(err) 671 } 672 673 err = unix.Lstat("symlink1", &st1) 674 if err != nil { 675 t.Fatalf("Lstat: %v", err) 676 } 677 678 err = unix.Fstatat(unix.AT_FDCWD, "symlink1", &st2, unix.AT_SYMLINK_NOFOLLOW) 679 if err != nil { 680 t.Fatalf("Fstatat: %v", err) 681 } 682 683 if st2.Dev != st1.Dev { 684 t.Errorf("Fstatat: got dev %v, expected %v", st2.Dev, st1.Dev) 685 } 686 if st2.Ino != st1.Ino { 687 t.Errorf("Fstatat: got ino %v, expected %v", st2.Ino, st1.Ino) 688 } 689 if st2.Mode != st1.Mode { 690 t.Errorf("Fstatat: got mode %v, expected %v", st2.Mode, st1.Mode) 691 } 692 if st2.Uid != st1.Uid { 693 t.Errorf("Fstatat: got uid %v, expected %v", st2.Uid, st1.Uid) 694 } 695 if st2.Gid != st1.Gid { 696 t.Errorf("Fstatat: got gid %v, expected %v", st2.Gid, st1.Gid) 697 } 698 if st2.Size != st1.Size { 699 t.Errorf("Fstatat: got size %v, expected %v", st2.Size, st1.Size) 700 } 701 } 702 703 func TestFchmodat(t *testing.T) { 704 defer chtmpdir(t)() 705 706 touch(t, "file1") 707 err := os.Symlink("file1", "symlink1") 708 if err != nil { 709 t.Fatal(err) 710 } 711 712 mode := os.FileMode(0444) 713 err = unix.Fchmodat(unix.AT_FDCWD, "symlink1", uint32(mode), 0) 714 if err != nil { 715 t.Fatalf("Fchmodat: unexpected error: %v", err) 716 } 717 718 fi, err := os.Stat("file1") 719 if err != nil { 720 t.Fatal(err) 721 } 722 723 if fi.Mode() != mode { 724 t.Errorf("Fchmodat: failed to change file mode: expected %v, got %v", mode, fi.Mode()) 725 } 726 727 mode = os.FileMode(0644) 728 didChmodSymlink := true 729 err = unix.Fchmodat(unix.AT_FDCWD, "symlink1", uint32(mode), unix.AT_SYMLINK_NOFOLLOW) 730 if err != nil { 731 if (runtime.GOOS == "android" || runtime.GOOS == "linux" || 732 runtime.GOOS == "solaris" || runtime.GOOS == "illumos") && err == unix.EOPNOTSUPP { 733 // Linux and Illumos don't support flags != 0 734 didChmodSymlink = false 735 } else { 736 t.Fatalf("Fchmodat: unexpected error: %v", err) 737 } 738 } 739 740 if !didChmodSymlink { 741 // Didn't change mode of the symlink. On Linux, the permissions 742 // of a symbolic link are always 0777 according to symlink(7) 743 mode = os.FileMode(0777) 744 } 745 746 var st unix.Stat_t 747 err = unix.Lstat("symlink1", &st) 748 if err != nil { 749 t.Fatal(err) 750 } 751 752 got := os.FileMode(st.Mode & 0777) 753 if got != mode { 754 t.Errorf("Fchmodat: failed to change symlink mode: expected %v, got %v", mode, got) 755 } 756 } 757 758 func TestMkdev(t *testing.T) { 759 major := uint32(42) 760 minor := uint32(7) 761 dev := unix.Mkdev(major, minor) 762 763 if unix.Major(dev) != major { 764 t.Errorf("Major(%#x) == %d, want %d", dev, unix.Major(dev), major) 765 } 766 if unix.Minor(dev) != minor { 767 t.Errorf("Minor(%#x) == %d, want %d", dev, unix.Minor(dev), minor) 768 } 769 } 770 771 func TestRenameat(t *testing.T) { 772 defer chtmpdir(t)() 773 774 from, to := "renamefrom", "renameto" 775 776 touch(t, from) 777 778 err := unix.Renameat(unix.AT_FDCWD, from, unix.AT_FDCWD, to) 779 if err != nil { 780 t.Fatalf("Renameat: unexpected error: %v", err) 781 } 782 783 _, err = os.Stat(to) 784 if err != nil { 785 t.Error(err) 786 } 787 788 _, err = os.Stat(from) 789 if err == nil { 790 t.Errorf("Renameat: stat of renamed file %q unexpectedly succeeded", from) 791 } 792 } 793 794 func TestUtimesNanoAt(t *testing.T) { 795 defer chtmpdir(t)() 796 797 symlink := "symlink1" 798 os.Remove(symlink) 799 err := os.Symlink("nonexisting", symlink) 800 if err != nil { 801 t.Fatal(err) 802 } 803 804 // Some filesystems only support microsecond resolution. Account for 805 // that in Nsec. 806 ts := []unix.Timespec{ 807 {Sec: 1111, Nsec: 2000}, 808 {Sec: 3333, Nsec: 4000}, 809 } 810 err = unix.UtimesNanoAt(unix.AT_FDCWD, symlink, ts, unix.AT_SYMLINK_NOFOLLOW) 811 if err != nil { 812 t.Fatalf("UtimesNanoAt: %v", err) 813 } 814 815 var st unix.Stat_t 816 err = unix.Lstat(symlink, &st) 817 if err != nil { 818 t.Fatalf("Lstat: %v", err) 819 } 820 821 // Only check Mtim, Atim might not be supported by the underlying filesystem 822 expected := ts[1] 823 if st.Mtim.Nsec == 0 { 824 // Some filesystems only support 1-second time stamp resolution 825 // and will always set Nsec to 0. 826 expected.Nsec = 0 827 } 828 if st.Mtim != expected { 829 t.Errorf("UtimesNanoAt: wrong mtime: got %v, expected %v", st.Mtim, expected) 830 } 831 } 832 833 // mktmpfifo creates a temporary FIFO and provides a cleanup function. 834 func mktmpfifo(t *testing.T) (*os.File, func()) { 835 err := unix.Mkfifo("fifo", 0666) 836 if err != nil { 837 t.Fatalf("mktmpfifo: failed to create FIFO: %v", err) 838 } 839 840 f, err := os.OpenFile("fifo", os.O_RDWR, 0666) 841 if err != nil { 842 os.Remove("fifo") 843 t.Fatalf("mktmpfifo: failed to open FIFO: %v", err) 844 } 845 846 return f, func() { 847 f.Close() 848 os.Remove("fifo") 849 } 850 } 851 852 // utilities taken from os/os_test.go 853 854 func touch(t *testing.T, name string) { 855 f, err := os.Create(name) 856 if err != nil { 857 t.Fatal(err) 858 } 859 if err := f.Close(); err != nil { 860 t.Fatal(err) 861 } 862 } 863 864 // chtmpdir changes the working directory to a new temporary directory and 865 // provides a cleanup function. Used when PWD is read-only. 866 func chtmpdir(t *testing.T) func() { 867 oldwd, err := os.Getwd() 868 if err != nil { 869 t.Fatalf("chtmpdir: %v", err) 870 } 871 d, err := ioutil.TempDir("", "test") 872 if err != nil { 873 t.Fatalf("chtmpdir: %v", err) 874 } 875 if err := os.Chdir(d); err != nil { 876 t.Fatalf("chtmpdir: %v", err) 877 } 878 return func() { 879 if err := os.Chdir(oldwd); err != nil { 880 t.Fatalf("chtmpdir: %v", err) 881 } 882 os.RemoveAll(d) 883 } 884 }