github.com/remobjects/goldbaselibrary@v0.0.0-20230924164425-d458680a936b/Source/Gold/os/os_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 package os_test 6 7 import ( 8 "bytes" 9 "errors" 10 "flag" 11 "fmt" 12 "internal/testenv" 13 "io" 14 "io/ioutil" 15 . "os" 16 osexec "os/exec" 17 "path/filepath" 18 "reflect" 19 "runtime" 20 "runtime/debug" 21 "sort" 22 "strings" 23 "sync" 24 "syscall" 25 "testing" 26 "time" 27 ) 28 29 var dot = []string{ 30 "dir_unix.go", 31 "env.go", 32 "error.go", 33 "file.go", 34 "os_test.go", 35 "types.go", 36 "stat_darwin.go", 37 "stat_linux.go", 38 } 39 40 type sysDir struct { 41 name string 42 files []string 43 } 44 45 var sysdir = func() *sysDir { 46 switch runtime.GOOS { 47 case "android": 48 return &sysDir{ 49 "/system/lib", 50 []string{ 51 "libmedia.so", 52 "libpowermanager.so", 53 }, 54 } 55 case "darwin": 56 switch runtime.GOARCH { 57 case "arm", "arm64": 58 wd, err := syscall.Getwd() 59 if err != nil { 60 wd = err.Error() 61 } 62 sd := &sysDir{ 63 filepath.Join(wd, "..", ".."), 64 []string{ 65 "ResourceRules.plist", 66 "Info.plist", 67 }, 68 } 69 found := true 70 for _, f := range sd.files { 71 path := filepath.Join(sd.name, f) 72 if _, err := Stat(path); err != nil { 73 found = false 74 break 75 } 76 } 77 if found { 78 return sd 79 } 80 // In a self-hosted iOS build the above files might 81 // not exist. Look for system files instead below. 82 } 83 case "windows": 84 return &sysDir{ 85 Getenv("SystemRoot") + "\\system32\\drivers\\etc", 86 []string{ 87 "networks", 88 "protocol", 89 "services", 90 }, 91 } 92 case "plan9": 93 return &sysDir{ 94 "/lib/ndb", 95 []string{ 96 "common", 97 "local", 98 }, 99 } 100 } 101 return &sysDir{ 102 "/etc", 103 []string{ 104 "group", 105 "hosts", 106 "passwd", 107 }, 108 } 109 }() 110 111 func size(name string, t *testing.T) int64 { 112 file, err := Open(name) 113 if err != nil { 114 t.Fatal("open failed:", err) 115 } 116 defer file.Close() 117 var buf [100]byte 118 len := 0 119 for { 120 n, e := file.Read(buf[0:]) 121 len += n 122 if e == io.EOF { 123 break 124 } 125 if e != nil { 126 t.Fatal("read failed:", e) 127 } 128 } 129 return int64(len) 130 } 131 132 func equal(name1, name2 string) (r bool) { 133 switch runtime.GOOS { 134 case "windows": 135 r = strings.ToLower(name1) == strings.ToLower(name2) 136 default: 137 r = name1 == name2 138 } 139 return 140 } 141 142 // localTmp returns a local temporary directory not on NFS. 143 func localTmp() string { 144 switch runtime.GOOS { 145 case "android", "windows": 146 return TempDir() 147 case "darwin": 148 switch runtime.GOARCH { 149 case "arm", "arm64": 150 return TempDir() 151 } 152 } 153 return "/tmp" 154 } 155 156 func newFile(testName string, t *testing.T) (f *File) { 157 f, err := ioutil.TempFile(localTmp(), "_Go_"+testName) 158 if err != nil { 159 t.Fatalf("TempFile %s: %s", testName, err) 160 } 161 return 162 } 163 164 func newDir(testName string, t *testing.T) (name string) { 165 name, err := ioutil.TempDir(localTmp(), "_Go_"+testName) 166 if err != nil { 167 t.Fatalf("TempDir %s: %s", testName, err) 168 } 169 return 170 } 171 172 var sfdir = sysdir.name 173 var sfname = sysdir.files[0] 174 175 func TestStat(t *testing.T) { 176 path := sfdir + "/" + sfname 177 dir, err := Stat(path) 178 if err != nil { 179 t.Fatal("stat failed:", err) 180 } 181 if !equal(sfname, dir.Name()) { 182 t.Error("name should be ", sfname, "; is", dir.Name()) 183 } 184 filesize := size(path, t) 185 if dir.Size() != filesize { 186 t.Error("size should be", filesize, "; is", dir.Size()) 187 } 188 } 189 190 func TestStatError(t *testing.T) { 191 defer chtmpdir(t)() 192 193 path := "no-such-file" 194 195 fi, err := Stat(path) 196 if err == nil { 197 t.Fatal("got nil, want error") 198 } 199 if fi != nil { 200 t.Errorf("got %v, want nil", fi) 201 } 202 if perr, ok := err.(*PathError); !ok { 203 t.Errorf("got %T, want %T", err, perr) 204 } 205 206 testenv.MustHaveSymlink(t) 207 208 link := "symlink" 209 err = Symlink(path, link) 210 if err != nil { 211 t.Fatal(err) 212 } 213 214 fi, err = Stat(link) 215 if err == nil { 216 t.Fatal("got nil, want error") 217 } 218 if fi != nil { 219 t.Errorf("got %v, want nil", fi) 220 } 221 if perr, ok := err.(*PathError); !ok { 222 t.Errorf("got %T, want %T", err, perr) 223 } 224 } 225 226 func TestFstat(t *testing.T) { 227 path := sfdir + "/" + sfname 228 file, err1 := Open(path) 229 if err1 != nil { 230 t.Fatal("open failed:", err1) 231 } 232 defer file.Close() 233 dir, err2 := file.Stat() 234 if err2 != nil { 235 t.Fatal("fstat failed:", err2) 236 } 237 if !equal(sfname, dir.Name()) { 238 t.Error("name should be ", sfname, "; is", dir.Name()) 239 } 240 filesize := size(path, t) 241 if dir.Size() != filesize { 242 t.Error("size should be", filesize, "; is", dir.Size()) 243 } 244 } 245 246 func TestLstat(t *testing.T) { 247 path := sfdir + "/" + sfname 248 dir, err := Lstat(path) 249 if err != nil { 250 t.Fatal("lstat failed:", err) 251 } 252 if !equal(sfname, dir.Name()) { 253 t.Error("name should be ", sfname, "; is", dir.Name()) 254 } 255 filesize := size(path, t) 256 if dir.Size() != filesize { 257 t.Error("size should be", filesize, "; is", dir.Size()) 258 } 259 } 260 261 // Read with length 0 should not return EOF. 262 func TestRead0(t *testing.T) { 263 path := sfdir + "/" + sfname 264 f, err := Open(path) 265 if err != nil { 266 t.Fatal("open failed:", err) 267 } 268 defer f.Close() 269 270 b := make([]byte, 0) 271 n, err := f.Read(b) 272 if n != 0 || err != nil { 273 t.Errorf("Read(0) = %d, %v, want 0, nil", n, err) 274 } 275 b = make([]byte, 100) 276 n, err = f.Read(b) 277 if n <= 0 || err != nil { 278 t.Errorf("Read(100) = %d, %v, want >0, nil", n, err) 279 } 280 } 281 282 // Reading a closed file should return ErrClosed error 283 func TestReadClosed(t *testing.T) { 284 path := sfdir + "/" + sfname 285 file, err := Open(path) 286 if err != nil { 287 t.Fatal("open failed:", err) 288 } 289 file.Close() // close immediately 290 291 b := make([]byte, 100) 292 _, err = file.Read(b) 293 294 e, ok := err.(*PathError) 295 if !ok { 296 t.Fatalf("Read: %T(%v), want PathError", e, e) 297 } 298 299 if e.Err != ErrClosed { 300 t.Errorf("Read: %v, want PathError(ErrClosed)", e) 301 } 302 } 303 304 func testReaddirnames(dir string, contents []string, t *testing.T) { 305 file, err := Open(dir) 306 if err != nil { 307 t.Fatalf("open %q failed: %v", dir, err) 308 } 309 defer file.Close() 310 s, err2 := file.Readdirnames(-1) 311 if err2 != nil { 312 t.Fatalf("readdirnames %q failed: %v", dir, err2) 313 } 314 for _, m := range contents { 315 found := false 316 for _, n := range s { 317 if n == "." || n == ".." { 318 t.Errorf("got %s in directory", n) 319 } 320 if equal(m, n) { 321 if found { 322 t.Error("present twice:", m) 323 } 324 found = true 325 } 326 } 327 if !found { 328 t.Error("could not find", m) 329 } 330 } 331 } 332 333 func testReaddir(dir string, contents []string, t *testing.T) { 334 file, err := Open(dir) 335 if err != nil { 336 t.Fatalf("open %q failed: %v", dir, err) 337 } 338 defer file.Close() 339 s, err2 := file.Readdir(-1) 340 if err2 != nil { 341 t.Fatalf("readdir %q failed: %v", dir, err2) 342 } 343 for _, m := range contents { 344 found := false 345 for _, n := range s { 346 if equal(m, n.Name()) { 347 if found { 348 t.Error("present twice:", m) 349 } 350 found = true 351 } 352 } 353 if !found { 354 t.Error("could not find", m) 355 } 356 } 357 } 358 359 func TestReaddirnames(t *testing.T) { 360 testReaddirnames(".", dot, t) 361 testReaddirnames(sysdir.name, sysdir.files, t) 362 } 363 364 func TestReaddir(t *testing.T) { 365 testReaddir(".", dot, t) 366 testReaddir(sysdir.name, sysdir.files, t) 367 } 368 369 func benchmarkReaddirname(path string, b *testing.B) { 370 var nentries int 371 for i := 0; i < b.N; i++ { 372 f, err := Open(path) 373 if err != nil { 374 b.Fatalf("open %q failed: %v", path, err) 375 } 376 ns, err := f.Readdirnames(-1) 377 f.Close() 378 if err != nil { 379 b.Fatalf("readdirnames %q failed: %v", path, err) 380 } 381 nentries = len(ns) 382 } 383 b.Logf("benchmarkReaddirname %q: %d entries", path, nentries) 384 } 385 386 func benchmarkReaddir(path string, b *testing.B) { 387 var nentries int 388 for i := 0; i < b.N; i++ { 389 f, err := Open(path) 390 if err != nil { 391 b.Fatalf("open %q failed: %v", path, err) 392 } 393 fs, err := f.Readdir(-1) 394 f.Close() 395 if err != nil { 396 b.Fatalf("readdir %q failed: %v", path, err) 397 } 398 nentries = len(fs) 399 } 400 b.Logf("benchmarkReaddir %q: %d entries", path, nentries) 401 } 402 403 func BenchmarkReaddirname(b *testing.B) { 404 benchmarkReaddirname(".", b) 405 } 406 407 func BenchmarkReaddir(b *testing.B) { 408 benchmarkReaddir(".", b) 409 } 410 411 func benchmarkStat(b *testing.B, path string) { 412 b.ResetTimer() 413 for i := 0; i < b.N; i++ { 414 _, err := Stat(path) 415 if err != nil { 416 b.Fatalf("Stat(%q) failed: %v", path, err) 417 } 418 } 419 } 420 421 func benchmarkLstat(b *testing.B, path string) { 422 b.ResetTimer() 423 for i := 0; i < b.N; i++ { 424 _, err := Lstat(path) 425 if err != nil { 426 b.Fatalf("Lstat(%q) failed: %v", path, err) 427 } 428 } 429 } 430 431 func BenchmarkStatDot(b *testing.B) { 432 benchmarkStat(b, ".") 433 } 434 435 func BenchmarkStatFile(b *testing.B) { 436 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go")) 437 } 438 439 func BenchmarkStatDir(b *testing.B) { 440 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os")) 441 } 442 443 func BenchmarkLstatDot(b *testing.B) { 444 benchmarkLstat(b, ".") 445 } 446 447 func BenchmarkLstatFile(b *testing.B) { 448 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go")) 449 } 450 451 func BenchmarkLstatDir(b *testing.B) { 452 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os")) 453 } 454 455 // Read the directory one entry at a time. 456 func smallReaddirnames(file *File, length int, t *testing.T) []string { 457 names := make([]string, length) 458 count := 0 459 for { 460 d, err := file.Readdirnames(1) 461 if err == io.EOF { 462 break 463 } 464 if err != nil { 465 t.Fatalf("readdirnames %q failed: %v", file.Name(), err) 466 } 467 if len(d) == 0 { 468 t.Fatalf("readdirnames %q returned empty slice and no error", file.Name()) 469 } 470 names[count] = d[0] 471 count++ 472 } 473 return names[0:count] 474 } 475 476 // Check that reading a directory one entry at a time gives the same result 477 // as reading it all at once. 478 func TestReaddirnamesOneAtATime(t *testing.T) { 479 // big directory that doesn't change often. 480 dir := "/usr/bin" 481 switch runtime.GOOS { 482 case "android": 483 dir = "/system/bin" 484 case "darwin": 485 switch runtime.GOARCH { 486 case "arm", "arm64": 487 wd, err := Getwd() 488 if err != nil { 489 t.Fatal(err) 490 } 491 dir = wd 492 } 493 case "plan9": 494 dir = "/bin" 495 case "windows": 496 dir = Getenv("SystemRoot") + "\\system32" 497 } 498 file, err := Open(dir) 499 if err != nil { 500 t.Fatalf("open %q failed: %v", dir, err) 501 } 502 defer file.Close() 503 all, err1 := file.Readdirnames(-1) 504 if err1 != nil { 505 t.Fatalf("readdirnames %q failed: %v", dir, err1) 506 } 507 file1, err2 := Open(dir) 508 if err2 != nil { 509 t.Fatalf("open %q failed: %v", dir, err2) 510 } 511 defer file1.Close() 512 small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up 513 if len(small) < len(all) { 514 t.Fatalf("len(small) is %d, less than %d", len(small), len(all)) 515 } 516 for i, n := range all { 517 if small[i] != n { 518 t.Errorf("small read %q mismatch: %v", small[i], n) 519 } 520 } 521 } 522 523 func TestReaddirNValues(t *testing.T) { 524 if testing.Short() { 525 t.Skip("test.short; skipping") 526 } 527 dir, err := ioutil.TempDir("", "") 528 if err != nil { 529 t.Fatalf("TempDir: %v", err) 530 } 531 defer RemoveAll(dir) 532 for i := 1; i <= 105; i++ { 533 f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i))) 534 if err != nil { 535 t.Fatalf("Create: %v", err) 536 } 537 f.Write([]byte(strings.Repeat("X", i))) 538 f.Close() 539 } 540 541 var d *File 542 openDir := func() { 543 var err error 544 d, err = Open(dir) 545 if err != nil { 546 t.Fatalf("Open directory: %v", err) 547 } 548 } 549 550 readDirExpect := func(n, want int, wantErr error) { 551 fi, err := d.Readdir(n) 552 if err != wantErr { 553 t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr) 554 } 555 if g, e := len(fi), want; g != e { 556 t.Errorf("Readdir of %d got %d files, want %d", n, g, e) 557 } 558 } 559 560 readDirNamesExpect := func(n, want int, wantErr error) { 561 fi, err := d.Readdirnames(n) 562 if err != wantErr { 563 t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr) 564 } 565 if g, e := len(fi), want; g != e { 566 t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e) 567 } 568 } 569 570 for _, fn := range []func(int, int, error){readDirExpect, readDirNamesExpect} { 571 // Test the slurp case 572 openDir() 573 fn(0, 105, nil) 574 fn(0, 0, nil) 575 d.Close() 576 577 // Slurp with -1 instead 578 openDir() 579 fn(-1, 105, nil) 580 fn(-2, 0, nil) 581 fn(0, 0, nil) 582 d.Close() 583 584 // Test the bounded case 585 openDir() 586 fn(1, 1, nil) 587 fn(2, 2, nil) 588 fn(105, 102, nil) // and tests buffer >100 case 589 fn(3, 0, io.EOF) 590 d.Close() 591 } 592 } 593 594 func touch(t *testing.T, name string) { 595 f, err := Create(name) 596 if err != nil { 597 t.Fatal(err) 598 } 599 if err := f.Close(); err != nil { 600 t.Fatal(err) 601 } 602 } 603 604 func TestReaddirStatFailures(t *testing.T) { 605 switch runtime.GOOS { 606 case "windows", "plan9": 607 // Windows and Plan 9 already do this correctly, 608 // but are structured with different syscalls such 609 // that they don't use Lstat, so the hook below for 610 // testing it wouldn't work. 611 t.Skipf("skipping test on %v", runtime.GOOS) 612 } 613 dir, err := ioutil.TempDir("", "") 614 if err != nil { 615 t.Fatalf("TempDir: %v", err) 616 } 617 defer RemoveAll(dir) 618 touch(t, filepath.Join(dir, "good1")) 619 touch(t, filepath.Join(dir, "x")) // will disappear or have an error 620 touch(t, filepath.Join(dir, "good2")) 621 defer func() { 622 *LstatP = Lstat 623 }() 624 var xerr error // error to return for x 625 *LstatP = func(path string) (FileInfo, error) { 626 if xerr != nil && strings.HasSuffix(path, "x") { 627 return nil, xerr 628 } 629 return Lstat(path) 630 } 631 readDir := func() ([]FileInfo, error) { 632 d, err := Open(dir) 633 if err != nil { 634 t.Fatal(err) 635 } 636 defer d.Close() 637 return d.Readdir(-1) 638 } 639 mustReadDir := func(testName string) []FileInfo { 640 fis, err := readDir() 641 if err != nil { 642 t.Fatalf("%s: Readdir: %v", testName, err) 643 } 644 return fis 645 } 646 names := func(fis []FileInfo) []string { 647 s := make([]string, len(fis)) 648 for i, fi := range fis { 649 s[i] = fi.Name() 650 } 651 sort.Strings(s) 652 return s 653 } 654 655 if got, want := names(mustReadDir("initial readdir")), 656 []string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) { 657 t.Errorf("initial readdir got %q; want %q", got, want) 658 } 659 660 xerr = ErrNotExist 661 if got, want := names(mustReadDir("with x disappearing")), 662 []string{"good1", "good2"}; !reflect.DeepEqual(got, want) { 663 t.Errorf("with x disappearing, got %q; want %q", got, want) 664 } 665 666 xerr = errors.New("some real error") 667 if _, err := readDir(); err != xerr { 668 t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr) 669 } 670 } 671 672 // Readdir on a regular file should fail. 673 func TestReaddirOfFile(t *testing.T) { 674 f, err := ioutil.TempFile("", "_Go_ReaddirOfFile") 675 if err != nil { 676 t.Fatal(err) 677 } 678 defer Remove(f.Name()) 679 f.Write([]byte("foo")) 680 f.Close() 681 reg, err := Open(f.Name()) 682 if err != nil { 683 t.Fatal(err) 684 } 685 defer reg.Close() 686 687 names, err := reg.Readdirnames(-1) 688 if err == nil { 689 t.Error("Readdirnames succeeded; want non-nil error") 690 } 691 if len(names) > 0 { 692 t.Errorf("unexpected dir names in regular file: %q", names) 693 } 694 } 695 696 func TestHardLink(t *testing.T) { 697 testenv.MustHaveLink(t) 698 699 defer chtmpdir(t)() 700 from, to := "hardlinktestfrom", "hardlinktestto" 701 file, err := Create(to) 702 if err != nil { 703 t.Fatalf("open %q failed: %v", to, err) 704 } 705 if err = file.Close(); err != nil { 706 t.Errorf("close %q failed: %v", to, err) 707 } 708 err = Link(to, from) 709 if err != nil { 710 t.Fatalf("link %q, %q failed: %v", to, from, err) 711 } 712 713 none := "hardlinktestnone" 714 err = Link(none, none) 715 // Check the returned error is well-formed. 716 if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" { 717 t.Errorf("link %q, %q failed to return a valid error", none, none) 718 } 719 720 tostat, err := Stat(to) 721 if err != nil { 722 t.Fatalf("stat %q failed: %v", to, err) 723 } 724 fromstat, err := Stat(from) 725 if err != nil { 726 t.Fatalf("stat %q failed: %v", from, err) 727 } 728 if !SameFile(tostat, fromstat) { 729 t.Errorf("link %q, %q did not create hard link", to, from) 730 } 731 // We should not be able to perform the same Link() a second time 732 err = Link(to, from) 733 switch err := err.(type) { 734 case *LinkError: 735 if err.Op != "link" { 736 t.Errorf("Link(%q, %q) err.Op = %q; want %q", to, from, err.Op, "link") 737 } 738 if err.Old != to { 739 t.Errorf("Link(%q, %q) err.Old = %q; want %q", to, from, err.Old, to) 740 } 741 if err.New != from { 742 t.Errorf("Link(%q, %q) err.New = %q; want %q", to, from, err.New, from) 743 } 744 if !IsExist(err.Err) { 745 t.Errorf("Link(%q, %q) err.Err = %q; want %q", to, from, err.Err, "file exists error") 746 } 747 case nil: 748 t.Errorf("link %q, %q: expected error, got nil", from, to) 749 default: 750 t.Errorf("link %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 751 } 752 } 753 754 // chtmpdir changes the working directory to a new temporary directory and 755 // provides a cleanup function. 756 func chtmpdir(t *testing.T) func() { 757 oldwd, err := Getwd() 758 if err != nil { 759 t.Fatalf("chtmpdir: %v", err) 760 } 761 d, err := ioutil.TempDir("", "test") 762 if err != nil { 763 t.Fatalf("chtmpdir: %v", err) 764 } 765 if err := Chdir(d); err != nil { 766 t.Fatalf("chtmpdir: %v", err) 767 } 768 return func() { 769 if err := Chdir(oldwd); err != nil { 770 t.Fatalf("chtmpdir: %v", err) 771 } 772 RemoveAll(d) 773 } 774 } 775 776 func TestSymlink(t *testing.T) { 777 testenv.MustHaveSymlink(t) 778 779 defer chtmpdir(t)() 780 from, to := "symlinktestfrom", "symlinktestto" 781 file, err := Create(to) 782 if err != nil { 783 t.Fatalf("Create(%q) failed: %v", to, err) 784 } 785 if err = file.Close(); err != nil { 786 t.Errorf("Close(%q) failed: %v", to, err) 787 } 788 err = Symlink(to, from) 789 if err != nil { 790 t.Fatalf("Symlink(%q, %q) failed: %v", to, from, err) 791 } 792 tostat, err := Lstat(to) 793 if err != nil { 794 t.Fatalf("Lstat(%q) failed: %v", to, err) 795 } 796 if tostat.Mode()&ModeSymlink != 0 { 797 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = %v, want 0", to, tostat.Mode()&ModeSymlink) 798 } 799 fromstat, err := Stat(from) 800 if err != nil { 801 t.Fatalf("Stat(%q) failed: %v", from, err) 802 } 803 if !SameFile(tostat, fromstat) { 804 t.Errorf("Symlink(%q, %q) did not create symlink", to, from) 805 } 806 fromstat, err = Lstat(from) 807 if err != nil { 808 t.Fatalf("Lstat(%q) failed: %v", from, err) 809 } 810 if fromstat.Mode()&ModeSymlink == 0 { 811 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = 0, want %v", from, ModeSymlink) 812 } 813 fromstat, err = Stat(from) 814 if err != nil { 815 t.Fatalf("Stat(%q) failed: %v", from, err) 816 } 817 if fromstat.Name() != from { 818 t.Errorf("Stat(%q).Name() = %q, want %q", from, fromstat.Name(), from) 819 } 820 if fromstat.Mode()&ModeSymlink != 0 { 821 t.Fatalf("Stat(%q).Mode()&ModeSymlink = %v, want 0", from, fromstat.Mode()&ModeSymlink) 822 } 823 s, err := Readlink(from) 824 if err != nil { 825 t.Fatalf("Readlink(%q) failed: %v", from, err) 826 } 827 if s != to { 828 t.Fatalf("Readlink(%q) = %q, want %q", from, s, to) 829 } 830 file, err = Open(from) 831 if err != nil { 832 t.Fatalf("Open(%q) failed: %v", from, err) 833 } 834 file.Close() 835 } 836 837 func TestLongSymlink(t *testing.T) { 838 testenv.MustHaveSymlink(t) 839 840 defer chtmpdir(t)() 841 s := "0123456789abcdef" 842 // Long, but not too long: a common limit is 255. 843 s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s 844 from := "longsymlinktestfrom" 845 err := Symlink(s, from) 846 if err != nil { 847 t.Fatalf("symlink %q, %q failed: %v", s, from, err) 848 } 849 r, err := Readlink(from) 850 if err != nil { 851 t.Fatalf("readlink %q failed: %v", from, err) 852 } 853 if r != s { 854 t.Fatalf("after symlink %q != %q", r, s) 855 } 856 } 857 858 func TestRename(t *testing.T) { 859 defer chtmpdir(t)() 860 from, to := "renamefrom", "renameto" 861 862 file, err := Create(from) 863 if err != nil { 864 t.Fatalf("open %q failed: %v", from, err) 865 } 866 if err = file.Close(); err != nil { 867 t.Errorf("close %q failed: %v", from, err) 868 } 869 err = Rename(from, to) 870 if err != nil { 871 t.Fatalf("rename %q, %q failed: %v", to, from, err) 872 } 873 _, err = Stat(to) 874 if err != nil { 875 t.Errorf("stat %q failed: %v", to, err) 876 } 877 } 878 879 func TestRenameOverwriteDest(t *testing.T) { 880 defer chtmpdir(t)() 881 from, to := "renamefrom", "renameto" 882 883 toData := []byte("to") 884 fromData := []byte("from") 885 886 err := ioutil.WriteFile(to, toData, 0777) 887 if err != nil { 888 t.Fatalf("write file %q failed: %v", to, err) 889 } 890 891 err = ioutil.WriteFile(from, fromData, 0777) 892 if err != nil { 893 t.Fatalf("write file %q failed: %v", from, err) 894 } 895 err = Rename(from, to) 896 if err != nil { 897 t.Fatalf("rename %q, %q failed: %v", to, from, err) 898 } 899 900 _, err = Stat(from) 901 if err == nil { 902 t.Errorf("from file %q still exists", from) 903 } 904 if err != nil && !IsNotExist(err) { 905 t.Fatalf("stat from: %v", err) 906 } 907 toFi, err := Stat(to) 908 if err != nil { 909 t.Fatalf("stat %q failed: %v", to, err) 910 } 911 if toFi.Size() != int64(len(fromData)) { 912 t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData)) 913 } 914 } 915 916 func TestRenameFailed(t *testing.T) { 917 defer chtmpdir(t)() 918 from, to := "renamefrom", "renameto" 919 920 err := Rename(from, to) 921 switch err := err.(type) { 922 case *LinkError: 923 if err.Op != "rename" { 924 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) 925 } 926 if err.Old != from { 927 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) 928 } 929 if err.New != to { 930 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) 931 } 932 case nil: 933 t.Errorf("rename %q, %q: expected error, got nil", from, to) 934 default: 935 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 936 } 937 } 938 939 func TestRenameNotExisting(t *testing.T) { 940 defer chtmpdir(t)() 941 from, to := "doesnt-exist", "dest" 942 943 Mkdir(to, 0777) 944 945 if err := Rename(from, to); !IsNotExist(err) { 946 t.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from, to, err) 947 } 948 } 949 950 func TestRenameToDirFailed(t *testing.T) { 951 defer chtmpdir(t)() 952 from, to := "renamefrom", "renameto" 953 954 Mkdir(from, 0777) 955 Mkdir(to, 0777) 956 957 err := Rename(from, to) 958 switch err := err.(type) { 959 case *LinkError: 960 if err.Op != "rename" { 961 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) 962 } 963 if err.Old != from { 964 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) 965 } 966 if err.New != to { 967 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) 968 } 969 case nil: 970 t.Errorf("rename %q, %q: expected error, got nil", from, to) 971 default: 972 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 973 } 974 } 975 976 func exec(t *testing.T, dir, cmd string, args []string, expect string) { 977 r, w, err := Pipe() 978 if err != nil { 979 t.Fatalf("Pipe: %v", err) 980 } 981 defer r.Close() 982 attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}} 983 p, err := StartProcess(cmd, args, attr) 984 if err != nil { 985 t.Fatalf("StartProcess: %v", err) 986 } 987 w.Close() 988 989 var b bytes.Buffer 990 io.Copy(&b, r) 991 output := b.String() 992 993 fi1, _ := Stat(strings.TrimSpace(output)) 994 fi2, _ := Stat(expect) 995 if !SameFile(fi1, fi2) { 996 t.Errorf("exec %q returned %q wanted %q", 997 strings.Join(append([]string{cmd}, args...), " "), output, expect) 998 } 999 p.Wait() 1000 } 1001 1002 func TestStartProcess(t *testing.T) { 1003 testenv.MustHaveExec(t) 1004 1005 var dir, cmd string 1006 var args []string 1007 switch runtime.GOOS { 1008 case "android": 1009 t.Skip("android doesn't have /bin/pwd") 1010 case "windows": 1011 cmd = Getenv("COMSPEC") 1012 dir = Getenv("SystemRoot") 1013 args = []string{"/c", "cd"} 1014 default: 1015 var err error 1016 cmd, err = osexec.LookPath("pwd") 1017 if err != nil { 1018 t.Fatalf("Can't find pwd: %v", err) 1019 } 1020 dir = "/" 1021 args = []string{} 1022 t.Logf("Testing with %v", cmd) 1023 } 1024 cmddir, cmdbase := filepath.Split(cmd) 1025 args = append([]string{cmdbase}, args...) 1026 // Test absolute executable path. 1027 exec(t, dir, cmd, args, dir) 1028 // Test relative executable path. 1029 exec(t, cmddir, cmdbase, args, cmddir) 1030 } 1031 1032 func checkMode(t *testing.T, path string, mode FileMode) { 1033 dir, err := Stat(path) 1034 if err != nil { 1035 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 1036 } 1037 if dir.Mode()&0777 != mode { 1038 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode) 1039 } 1040 } 1041 1042 func TestChmod(t *testing.T) { 1043 // Chmod is not supported under windows. 1044 if runtime.GOOS == "windows" { 1045 return 1046 } 1047 f := newFile("TestChmod", t) 1048 defer Remove(f.Name()) 1049 defer f.Close() 1050 1051 if err := Chmod(f.Name(), 0456); err != nil { 1052 t.Fatalf("chmod %s 0456: %s", f.Name(), err) 1053 } 1054 checkMode(t, f.Name(), 0456) 1055 1056 if err := f.Chmod(0123); err != nil { 1057 t.Fatalf("chmod %s 0123: %s", f.Name(), err) 1058 } 1059 checkMode(t, f.Name(), 0123) 1060 } 1061 1062 func checkSize(t *testing.T, f *File, size int64) { 1063 dir, err := f.Stat() 1064 if err != nil { 1065 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err) 1066 } 1067 if dir.Size() != size { 1068 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size) 1069 } 1070 } 1071 1072 func TestFTruncate(t *testing.T) { 1073 f := newFile("TestFTruncate", t) 1074 defer Remove(f.Name()) 1075 defer f.Close() 1076 1077 checkSize(t, f, 0) 1078 f.Write([]byte("hello, world\n")) 1079 checkSize(t, f, 13) 1080 f.Truncate(10) 1081 checkSize(t, f, 10) 1082 f.Truncate(1024) 1083 checkSize(t, f, 1024) 1084 f.Truncate(0) 1085 checkSize(t, f, 0) 1086 _, err := f.Write([]byte("surprise!")) 1087 if err == nil { 1088 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 1089 } 1090 } 1091 1092 func TestTruncate(t *testing.T) { 1093 f := newFile("TestTruncate", t) 1094 defer Remove(f.Name()) 1095 defer f.Close() 1096 1097 checkSize(t, f, 0) 1098 f.Write([]byte("hello, world\n")) 1099 checkSize(t, f, 13) 1100 Truncate(f.Name(), 10) 1101 checkSize(t, f, 10) 1102 Truncate(f.Name(), 1024) 1103 checkSize(t, f, 1024) 1104 Truncate(f.Name(), 0) 1105 checkSize(t, f, 0) 1106 _, err := f.Write([]byte("surprise!")) 1107 if err == nil { 1108 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 1109 } 1110 } 1111 1112 // Use TempDir (via newFile) to make sure we're on a local file system, 1113 // so that timings are not distorted by latency and caching. 1114 // On NFS, timings can be off due to caching of meta-data on 1115 // NFS servers (Issue 848). 1116 func TestChtimes(t *testing.T) { 1117 f := newFile("TestChtimes", t) 1118 defer Remove(f.Name()) 1119 1120 f.Write([]byte("hello, world\n")) 1121 f.Close() 1122 1123 testChtimes(t, f.Name()) 1124 } 1125 1126 // Use TempDir (via newDir) to make sure we're on a local file system, 1127 // so that timings are not distorted by latency and caching. 1128 // On NFS, timings can be off due to caching of meta-data on 1129 // NFS servers (Issue 848). 1130 func TestChtimesDir(t *testing.T) { 1131 name := newDir("TestChtimes", t) 1132 defer RemoveAll(name) 1133 1134 testChtimes(t, name) 1135 } 1136 1137 func testChtimes(t *testing.T, name string) { 1138 st, err := Stat(name) 1139 if err != nil { 1140 t.Fatalf("Stat %s: %s", name, err) 1141 } 1142 preStat := st 1143 1144 // Move access and modification time back a second 1145 at := Atime(preStat) 1146 mt := preStat.ModTime() 1147 err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second)) 1148 if err != nil { 1149 t.Fatalf("Chtimes %s: %s", name, err) 1150 } 1151 1152 st, err = Stat(name) 1153 if err != nil { 1154 t.Fatalf("second Stat %s: %s", name, err) 1155 } 1156 postStat := st 1157 1158 pat := Atime(postStat) 1159 pmt := postStat.ModTime() 1160 if !pat.Before(at) { 1161 switch runtime.GOOS { 1162 case "plan9", "nacl": 1163 // Ignore. 1164 // Plan 9, NaCl: 1165 // Mtime is the time of the last change of 1166 // content. Similarly, atime is set whenever 1167 // the contents are accessed; also, it is set 1168 // whenever mtime is set. 1169 case "netbsd": 1170 mounts, _ := ioutil.ReadFile("/proc/mounts") 1171 if strings.Contains(string(mounts), "noatime") { 1172 t.Logf("AccessTime didn't go backwards, but see a filesystem mounted noatime; ignoring. Issue 19293.") 1173 } else { 1174 t.Logf("AccessTime didn't go backwards; was=%v, after=%v (Ignoring on NetBSD, assuming noatime, Issue 19293)", at, pat) 1175 } 1176 default: 1177 t.Errorf("AccessTime didn't go backwards; was=%v, after=%v", at, pat) 1178 } 1179 } 1180 1181 if !pmt.Before(mt) { 1182 t.Errorf("ModTime didn't go backwards; was=%v, after=%v", mt, pmt) 1183 } 1184 } 1185 1186 func TestChdirAndGetwd(t *testing.T) { 1187 // TODO(brainman): file.Chdir() is not implemented on windows. 1188 if runtime.GOOS == "windows" { 1189 return 1190 } 1191 fd, err := Open(".") 1192 if err != nil { 1193 t.Fatalf("Open .: %s", err) 1194 } 1195 // These are chosen carefully not to be symlinks on a Mac 1196 // (unlike, say, /var, /etc), except /tmp, which we handle below. 1197 dirs := []string{"/", "/usr/bin", "/tmp"} 1198 // /usr/bin does not usually exist on Plan 9 or Android. 1199 switch runtime.GOOS { 1200 case "android": 1201 dirs = []string{"/system/bin"} 1202 case "plan9": 1203 dirs = []string{"/", "/usr"} 1204 case "darwin": 1205 switch runtime.GOARCH { 1206 case "arm", "arm64": 1207 dirs = nil 1208 for _, d := range []string{"d1", "d2"} { 1209 dir, err := ioutil.TempDir("", d) 1210 if err != nil { 1211 t.Fatalf("TempDir: %v", err) 1212 } 1213 // Expand symlinks so path equality tests work. 1214 dir, err = filepath.EvalSymlinks(dir) 1215 if err != nil { 1216 t.Fatalf("EvalSymlinks: %v", err) 1217 } 1218 dirs = append(dirs, dir) 1219 } 1220 } 1221 } 1222 oldwd := Getenv("PWD") 1223 for mode := 0; mode < 2; mode++ { 1224 for _, d := range dirs { 1225 if mode == 0 { 1226 err = Chdir(d) 1227 } else { 1228 fd1, err1 := Open(d) 1229 if err1 != nil { 1230 t.Errorf("Open %s: %s", d, err1) 1231 continue 1232 } 1233 err = fd1.Chdir() 1234 fd1.Close() 1235 } 1236 if d == "/tmp" { 1237 Setenv("PWD", "/tmp") 1238 } 1239 pwd, err1 := Getwd() 1240 Setenv("PWD", oldwd) 1241 err2 := fd.Chdir() 1242 if err2 != nil { 1243 // We changed the current directory and cannot go back. 1244 // Don't let the tests continue; they'll scribble 1245 // all over some other directory. 1246 fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2) 1247 Exit(1) 1248 } 1249 if err != nil { 1250 fd.Close() 1251 t.Fatalf("Chdir %s: %s", d, err) 1252 } 1253 if err1 != nil { 1254 fd.Close() 1255 t.Fatalf("Getwd in %s: %s", d, err1) 1256 } 1257 if pwd != d { 1258 fd.Close() 1259 t.Fatalf("Getwd returned %q want %q", pwd, d) 1260 } 1261 } 1262 } 1263 fd.Close() 1264 } 1265 1266 // Test that Chdir+Getwd is program-wide. 1267 func TestProgWideChdir(t *testing.T) { 1268 const N = 10 1269 c := make(chan bool) 1270 cpwd := make(chan string) 1271 for i := 0; i < N; i++ { 1272 go func(i int) { 1273 // Lock half the goroutines in their own operating system 1274 // thread to exercise more scheduler possibilities. 1275 if i%2 == 1 { 1276 // On Plan 9, after calling LockOSThread, the goroutines 1277 // run on different processes which don't share the working 1278 // directory. This used to be an issue because Go expects 1279 // the working directory to be program-wide. 1280 // See issue 9428. 1281 runtime.LockOSThread() 1282 } 1283 <-c 1284 pwd, err := Getwd() 1285 if err != nil { 1286 t.Errorf("Getwd on goroutine %d: %v", i, err) 1287 return 1288 } 1289 cpwd <- pwd 1290 }(i) 1291 } 1292 oldwd, err := Getwd() 1293 if err != nil { 1294 t.Fatalf("Getwd: %v", err) 1295 } 1296 d, err := ioutil.TempDir("", "test") 1297 if err != nil { 1298 t.Fatalf("TempDir: %v", err) 1299 } 1300 defer func() { 1301 if err := Chdir(oldwd); err != nil { 1302 t.Fatalf("Chdir: %v", err) 1303 } 1304 RemoveAll(d) 1305 }() 1306 if err := Chdir(d); err != nil { 1307 t.Fatalf("Chdir: %v", err) 1308 } 1309 // OS X sets TMPDIR to a symbolic link. 1310 // So we resolve our working directory again before the test. 1311 d, err = Getwd() 1312 if err != nil { 1313 t.Fatalf("Getwd: %v", err) 1314 } 1315 close(c) 1316 for i := 0; i < N; i++ { 1317 pwd := <-cpwd 1318 if pwd != d { 1319 t.Errorf("Getwd returned %q; want %q", pwd, d) 1320 } 1321 } 1322 } 1323 1324 func TestSeek(t *testing.T) { 1325 f := newFile("TestSeek", t) 1326 defer Remove(f.Name()) 1327 defer f.Close() 1328 1329 const data = "hello, world\n" 1330 io.WriteString(f, data) 1331 1332 type test struct { 1333 in int64 1334 whence int 1335 out int64 1336 } 1337 var tests = []test{ 1338 {0, io.SeekCurrent, int64(len(data))}, 1339 {0, io.SeekStart, 0}, 1340 {5, io.SeekStart, 5}, 1341 {0, io.SeekEnd, int64(len(data))}, 1342 {0, io.SeekStart, 0}, 1343 {-1, io.SeekEnd, int64(len(data)) - 1}, 1344 {1 << 33, io.SeekStart, 1 << 33}, 1345 {1 << 33, io.SeekEnd, 1<<33 + int64(len(data))}, 1346 1347 // Issue 21681, Windows 4G-1, etc: 1348 {1<<32 - 1, io.SeekStart, 1<<32 - 1}, 1349 {0, io.SeekCurrent, 1<<32 - 1}, 1350 {2<<32 - 1, io.SeekStart, 2<<32 - 1}, 1351 {0, io.SeekCurrent, 2<<32 - 1}, 1352 } 1353 for i, tt := range tests { 1354 if runtime.GOOS == "nacl" && tt.out > 1<<30 { 1355 t.Logf("skipping test case #%d on nacl; https://golang.org/issue/21728", i) 1356 continue 1357 } 1358 off, err := f.Seek(tt.in, tt.whence) 1359 if off != tt.out || err != nil { 1360 if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 && runtime.GOOS == "linux" { 1361 mounts, _ := ioutil.ReadFile("/proc/mounts") 1362 if strings.Contains(string(mounts), "reiserfs") { 1363 // Reiserfs rejects the big seeks. 1364 t.Skipf("skipping test known to fail on reiserfs; https://golang.org/issue/91") 1365 } 1366 } 1367 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out) 1368 } 1369 } 1370 } 1371 1372 func TestSeekError(t *testing.T) { 1373 switch runtime.GOOS { 1374 case "js", "nacl", "plan9": 1375 t.Skipf("skipping test on %v", runtime.GOOS) 1376 } 1377 1378 r, w, err := Pipe() 1379 if err != nil { 1380 t.Fatal(err) 1381 } 1382 _, err = r.Seek(0, 0) 1383 if err == nil { 1384 t.Fatal("Seek on pipe should fail") 1385 } 1386 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE { 1387 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err) 1388 } 1389 _, err = w.Seek(0, 0) 1390 if err == nil { 1391 t.Fatal("Seek on pipe should fail") 1392 } 1393 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE { 1394 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err) 1395 } 1396 } 1397 1398 type openErrorTest struct { 1399 path string 1400 mode int 1401 error error 1402 } 1403 1404 var openErrorTests = []openErrorTest{ 1405 { 1406 sfdir + "/no-such-file", 1407 O_RDONLY, 1408 syscall.ENOENT, 1409 }, 1410 { 1411 sfdir, 1412 O_WRONLY, 1413 syscall.EISDIR, 1414 }, 1415 { 1416 sfdir + "/" + sfname + "/no-such-file", 1417 O_WRONLY, 1418 syscall.ENOTDIR, 1419 }, 1420 } 1421 1422 func TestOpenError(t *testing.T) { 1423 for _, tt := range openErrorTests { 1424 f, err := OpenFile(tt.path, tt.mode, 0) 1425 if err == nil { 1426 t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode) 1427 f.Close() 1428 continue 1429 } 1430 perr, ok := err.(*PathError) 1431 if !ok { 1432 t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err) 1433 } 1434 if perr.Err != tt.error { 1435 if runtime.GOOS == "plan9" { 1436 syscallErrStr := perr.Err.Error() 1437 expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1) 1438 if !strings.HasSuffix(syscallErrStr, expectedErrStr) { 1439 // Some Plan 9 file servers incorrectly return 1440 // EACCES rather than EISDIR when a directory is 1441 // opened for write. 1442 if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) { 1443 continue 1444 } 1445 t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr) 1446 } 1447 continue 1448 } 1449 if runtime.GOOS == "dragonfly" { 1450 // DragonFly incorrectly returns EACCES rather 1451 // EISDIR when a directory is opened for write. 1452 if tt.error == syscall.EISDIR && perr.Err == syscall.EACCES { 1453 continue 1454 } 1455 } 1456 t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error()) 1457 } 1458 } 1459 } 1460 1461 func TestOpenNoName(t *testing.T) { 1462 f, err := Open("") 1463 if err == nil { 1464 t.Fatal(`Open("") succeeded`) 1465 f.Close() 1466 } 1467 } 1468 1469 func runBinHostname(t *testing.T) string { 1470 // Run /bin/hostname and collect output. 1471 r, w, err := Pipe() 1472 if err != nil { 1473 t.Fatal(err) 1474 } 1475 defer r.Close() 1476 const path = "/bin/hostname" 1477 argv := []string{"hostname"} 1478 if runtime.GOOS == "aix" { 1479 argv = []string{"hostname", "-s"} 1480 } 1481 p, err := StartProcess(path, argv, &ProcAttr{Files: []*File{nil, w, Stderr}}) 1482 if err != nil { 1483 if _, err := Stat(path); IsNotExist(err) { 1484 t.Skipf("skipping test; test requires %s but it does not exist", path) 1485 } 1486 t.Fatal(err) 1487 } 1488 w.Close() 1489 1490 var b bytes.Buffer 1491 io.Copy(&b, r) 1492 _, err = p.Wait() 1493 if err != nil { 1494 t.Fatalf("run hostname Wait: %v", err) 1495 } 1496 err = p.Kill() 1497 if err == nil { 1498 t.Errorf("expected an error from Kill running 'hostname'") 1499 } 1500 output := b.String() 1501 if n := len(output); n > 0 && output[n-1] == '\n' { 1502 output = output[0 : n-1] 1503 } 1504 if output == "" { 1505 t.Fatalf("/bin/hostname produced no output") 1506 } 1507 1508 return output 1509 } 1510 1511 func testWindowsHostname(t *testing.T, hostname string) { 1512 cmd := osexec.Command("hostname") 1513 out, err := cmd.CombinedOutput() 1514 if err != nil { 1515 t.Fatalf("Failed to execute hostname command: %v %s", err, out) 1516 } 1517 want := strings.Trim(string(out), "\r\n") 1518 if hostname != want { 1519 t.Fatalf("Hostname() = %q != system hostname of %q", hostname, want) 1520 } 1521 } 1522 1523 func TestHostname(t *testing.T) { 1524 hostname, err := Hostname() 1525 if err != nil { 1526 t.Fatal(err) 1527 } 1528 if hostname == "" { 1529 t.Fatal("Hostname returned empty string and no error") 1530 } 1531 if strings.Contains(hostname, "\x00") { 1532 t.Fatalf("unexpected zero byte in hostname: %q", hostname) 1533 } 1534 1535 // There is no other way to fetch hostname on windows, but via winapi. 1536 // On Plan 9 it can be taken from #c/sysname as Hostname() does. 1537 switch runtime.GOOS { 1538 case "android", "plan9": 1539 // No /bin/hostname to verify against. 1540 return 1541 case "windows": 1542 testWindowsHostname(t, hostname) 1543 return 1544 } 1545 1546 testenv.MustHaveExec(t) 1547 1548 // Check internal Hostname() against the output of /bin/hostname. 1549 // Allow that the internal Hostname returns a Fully Qualified Domain Name 1550 // and the /bin/hostname only returns the first component 1551 want := runBinHostname(t) 1552 if hostname != want { 1553 i := strings.Index(hostname, ".") 1554 if i < 0 || hostname[0:i] != want { 1555 t.Errorf("Hostname() = %q, want %q", hostname, want) 1556 } 1557 } 1558 } 1559 1560 func TestReadAt(t *testing.T) { 1561 f := newFile("TestReadAt", t) 1562 defer Remove(f.Name()) 1563 defer f.Close() 1564 1565 const data = "hello, world\n" 1566 io.WriteString(f, data) 1567 1568 b := make([]byte, 5) 1569 n, err := f.ReadAt(b, 7) 1570 if err != nil || n != len(b) { 1571 t.Fatalf("ReadAt 7: %d, %v", n, err) 1572 } 1573 if string(b) != "world" { 1574 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 1575 } 1576 } 1577 1578 // Verify that ReadAt doesn't affect seek offset. 1579 // In the Plan 9 kernel, there used to be a bug in the implementation of 1580 // the pread syscall, where the channel offset was erroneously updated after 1581 // calling pread on a file. 1582 func TestReadAtOffset(t *testing.T) { 1583 f := newFile("TestReadAtOffset", t) 1584 defer Remove(f.Name()) 1585 defer f.Close() 1586 1587 const data = "hello, world\n" 1588 io.WriteString(f, data) 1589 1590 f.Seek(0, 0) 1591 b := make([]byte, 5) 1592 1593 n, err := f.ReadAt(b, 7) 1594 if err != nil || n != len(b) { 1595 t.Fatalf("ReadAt 7: %d, %v", n, err) 1596 } 1597 if string(b) != "world" { 1598 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 1599 } 1600 1601 n, err = f.Read(b) 1602 if err != nil || n != len(b) { 1603 t.Fatalf("Read: %d, %v", n, err) 1604 } 1605 if string(b) != "hello" { 1606 t.Fatalf("Read: have %q want %q", string(b), "hello") 1607 } 1608 } 1609 1610 // Verify that ReadAt doesn't allow negative offset. 1611 func TestReadAtNegativeOffset(t *testing.T) { 1612 f := newFile("TestReadAtNegativeOffset", t) 1613 defer Remove(f.Name()) 1614 defer f.Close() 1615 1616 const data = "hello, world\n" 1617 io.WriteString(f, data) 1618 1619 f.Seek(0, 0) 1620 b := make([]byte, 5) 1621 1622 n, err := f.ReadAt(b, -10) 1623 1624 const wantsub = "negative offset" 1625 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 { 1626 t.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub) 1627 } 1628 } 1629 1630 func TestWriteAt(t *testing.T) { 1631 f := newFile("TestWriteAt", t) 1632 defer Remove(f.Name()) 1633 defer f.Close() 1634 1635 const data = "hello, world\n" 1636 io.WriteString(f, data) 1637 1638 n, err := f.WriteAt([]byte("WORLD"), 7) 1639 if err != nil || n != 5 { 1640 t.Fatalf("WriteAt 7: %d, %v", n, err) 1641 } 1642 1643 b, err := ioutil.ReadFile(f.Name()) 1644 if err != nil { 1645 t.Fatalf("ReadFile %s: %v", f.Name(), err) 1646 } 1647 if string(b) != "hello, WORLD\n" { 1648 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n") 1649 } 1650 } 1651 1652 // Verify that WriteAt doesn't allow negative offset. 1653 func TestWriteAtNegativeOffset(t *testing.T) { 1654 f := newFile("TestWriteAtNegativeOffset", t) 1655 defer Remove(f.Name()) 1656 defer f.Close() 1657 1658 n, err := f.WriteAt([]byte("WORLD"), -10) 1659 1660 const wantsub = "negative offset" 1661 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 { 1662 t.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub) 1663 } 1664 } 1665 1666 // Verify that WriteAt doesn't work in append mode. 1667 func TestWriteAtInAppendMode(t *testing.T) { 1668 defer chtmpdir(t)() 1669 f, err := OpenFile("write_at_in_append_mode.txt", O_APPEND|O_CREATE, 0666) 1670 if err != nil { 1671 t.Fatalf("OpenFile: %v", err) 1672 } 1673 defer f.Close() 1674 1675 _, err = f.WriteAt([]byte(""), 1) 1676 if err != ErrWriteAtInAppendMode { 1677 t.Fatalf("f.WriteAt returned %v, expected %v", err, ErrWriteAtInAppendMode) 1678 } 1679 } 1680 1681 func writeFile(t *testing.T, fname string, flag int, text string) string { 1682 f, err := OpenFile(fname, flag, 0666) 1683 if err != nil { 1684 t.Fatalf("Open: %v", err) 1685 } 1686 n, err := io.WriteString(f, text) 1687 if err != nil { 1688 t.Fatalf("WriteString: %d, %v", n, err) 1689 } 1690 f.Close() 1691 data, err := ioutil.ReadFile(fname) 1692 if err != nil { 1693 t.Fatalf("ReadFile: %v", err) 1694 } 1695 return string(data) 1696 } 1697 1698 func TestAppend(t *testing.T) { 1699 defer chtmpdir(t)() 1700 const f = "append.txt" 1701 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 1702 if s != "new" { 1703 t.Fatalf("writeFile: have %q want %q", s, "new") 1704 } 1705 s = writeFile(t, f, O_APPEND|O_RDWR, "|append") 1706 if s != "new|append" { 1707 t.Fatalf("writeFile: have %q want %q", s, "new|append") 1708 } 1709 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append") 1710 if s != "new|append|append" { 1711 t.Fatalf("writeFile: have %q want %q", s, "new|append|append") 1712 } 1713 err := Remove(f) 1714 if err != nil { 1715 t.Fatalf("Remove: %v", err) 1716 } 1717 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append") 1718 if s != "new&append" { 1719 t.Fatalf("writeFile: after append have %q want %q", s, "new&append") 1720 } 1721 s = writeFile(t, f, O_CREATE|O_RDWR, "old") 1722 if s != "old&append" { 1723 t.Fatalf("writeFile: after create have %q want %q", s, "old&append") 1724 } 1725 s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 1726 if s != "new" { 1727 t.Fatalf("writeFile: after truncate have %q want %q", s, "new") 1728 } 1729 } 1730 1731 func TestStatDirWithTrailingSlash(t *testing.T) { 1732 // Create new temporary directory and arrange to clean it up. 1733 path, err := ioutil.TempDir("", "/_TestStatDirWithSlash_") 1734 if err != nil { 1735 t.Fatalf("TempDir: %s", err) 1736 } 1737 defer RemoveAll(path) 1738 1739 // Stat of path should succeed. 1740 _, err = Stat(path) 1741 if err != nil { 1742 t.Fatalf("stat %s failed: %s", path, err) 1743 } 1744 1745 // Stat of path+"/" should succeed too. 1746 path += "/" 1747 _, err = Stat(path) 1748 if err != nil { 1749 t.Fatalf("stat %s failed: %s", path, err) 1750 } 1751 } 1752 1753 func TestNilProcessStateString(t *testing.T) { 1754 var ps *ProcessState 1755 s := ps.String() 1756 if s != "<nil>" { 1757 t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>") 1758 } 1759 } 1760 1761 func TestSameFile(t *testing.T) { 1762 defer chtmpdir(t)() 1763 fa, err := Create("a") 1764 if err != nil { 1765 t.Fatalf("Create(a): %v", err) 1766 } 1767 fa.Close() 1768 fb, err := Create("b") 1769 if err != nil { 1770 t.Fatalf("Create(b): %v", err) 1771 } 1772 fb.Close() 1773 1774 ia1, err := Stat("a") 1775 if err != nil { 1776 t.Fatalf("Stat(a): %v", err) 1777 } 1778 ia2, err := Stat("a") 1779 if err != nil { 1780 t.Fatalf("Stat(a): %v", err) 1781 } 1782 if !SameFile(ia1, ia2) { 1783 t.Errorf("files should be same") 1784 } 1785 1786 ib, err := Stat("b") 1787 if err != nil { 1788 t.Fatalf("Stat(b): %v", err) 1789 } 1790 if SameFile(ia1, ib) { 1791 t.Errorf("files should be different") 1792 } 1793 } 1794 1795 func testDevNullFileInfo(t *testing.T, statname, devNullName string, fi FileInfo, ignoreCase bool) { 1796 pre := fmt.Sprintf("%s(%q): ", statname, devNullName) 1797 name := filepath.Base(devNullName) 1798 if ignoreCase { 1799 if strings.ToUpper(fi.Name()) != strings.ToUpper(name) { 1800 t.Errorf(pre+"wrong file name have %v want %v", fi.Name(), name) 1801 } 1802 } else { 1803 if fi.Name() != name { 1804 t.Errorf(pre+"wrong file name have %v want %v", fi.Name(), name) 1805 } 1806 } 1807 if fi.Size() != 0 { 1808 t.Errorf(pre+"wrong file size have %d want 0", fi.Size()) 1809 } 1810 if fi.Mode()&ModeDevice == 0 { 1811 t.Errorf(pre+"wrong file mode %q: ModeDevice is not set", fi.Mode()) 1812 } 1813 if fi.Mode()&ModeCharDevice == 0 { 1814 t.Errorf(pre+"wrong file mode %q: ModeCharDevice is not set", fi.Mode()) 1815 } 1816 if fi.Mode().IsRegular() { 1817 t.Errorf(pre+"wrong file mode %q: IsRegular returns true", fi.Mode()) 1818 } 1819 } 1820 1821 func testDevNullFile(t *testing.T, devNullName string, ignoreCase bool) { 1822 f, err := Open(devNullName) 1823 if err != nil { 1824 t.Fatalf("Open(%s): %v", devNullName, err) 1825 } 1826 defer f.Close() 1827 1828 fi, err := f.Stat() 1829 if err != nil { 1830 t.Fatalf("Stat(%s): %v", devNullName, err) 1831 } 1832 testDevNullFileInfo(t, "f.Stat", devNullName, fi, ignoreCase) 1833 1834 fi, err = Stat(devNullName) 1835 if err != nil { 1836 t.Fatalf("Stat(%s): %v", devNullName, err) 1837 } 1838 testDevNullFileInfo(t, "Stat", devNullName, fi, ignoreCase) 1839 } 1840 1841 func TestDevNullFile(t *testing.T) { 1842 testDevNullFile(t, DevNull, false) 1843 } 1844 1845 var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output") 1846 1847 func TestLargeWriteToConsole(t *testing.T) { 1848 if !*testLargeWrite { 1849 t.Skip("skipping console-flooding test; enable with -large_write") 1850 } 1851 b := make([]byte, 32000) 1852 for i := range b { 1853 b[i] = '.' 1854 } 1855 b[len(b)-1] = '\n' 1856 n, err := Stdout.Write(b) 1857 if err != nil { 1858 t.Fatalf("Write to os.Stdout failed: %v", err) 1859 } 1860 if n != len(b) { 1861 t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n) 1862 } 1863 n, err = Stderr.Write(b) 1864 if err != nil { 1865 t.Fatalf("Write to os.Stderr failed: %v", err) 1866 } 1867 if n != len(b) { 1868 t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n) 1869 } 1870 } 1871 1872 func TestStatDirModeExec(t *testing.T) { 1873 const mode = 0111 1874 1875 path, err := ioutil.TempDir("", "go-build") 1876 if err != nil { 1877 t.Fatalf("Failed to create temp directory: %v", err) 1878 } 1879 defer RemoveAll(path) 1880 1881 if err := Chmod(path, 0777); err != nil { 1882 t.Fatalf("Chmod %q 0777: %v", path, err) 1883 } 1884 1885 dir, err := Stat(path) 1886 if err != nil { 1887 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 1888 } 1889 if dir.Mode()&mode != mode { 1890 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode) 1891 } 1892 } 1893 1894 func TestStatStdin(t *testing.T) { 1895 switch runtime.GOOS { 1896 case "android", "plan9": 1897 t.Skipf("%s doesn't have /bin/sh", runtime.GOOS) 1898 } 1899 1900 testenv.MustHaveExec(t) 1901 1902 if Getenv("GO_WANT_HELPER_PROCESS") == "1" { 1903 st, err := Stdin.Stat() 1904 if err != nil { 1905 t.Fatalf("Stat failed: %v", err) 1906 } 1907 fmt.Println(st.Mode() & ModeNamedPipe) 1908 Exit(0) 1909 } 1910 1911 fi, err := Stdin.Stat() 1912 if err != nil { 1913 t.Fatal(err) 1914 } 1915 switch mode := fi.Mode(); { 1916 case mode&ModeCharDevice != 0 && mode&ModeDevice != 0: 1917 case mode&ModeNamedPipe != 0: 1918 default: 1919 t.Fatalf("unexpected Stdin mode (%v), want ModeCharDevice or ModeNamedPipe", mode) 1920 } 1921 1922 var cmd *osexec.Cmd 1923 if runtime.GOOS == "windows" { 1924 cmd = osexec.Command("cmd", "/c", "echo output | "+Args[0]+" -test.run=TestStatStdin") 1925 } else { 1926 cmd = osexec.Command("/bin/sh", "-c", "echo output | "+Args[0]+" -test.run=TestStatStdin") 1927 } 1928 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") 1929 1930 output, err := cmd.CombinedOutput() 1931 if err != nil { 1932 t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) 1933 } 1934 1935 // result will be like "prw-rw-rw" 1936 if len(output) < 1 || output[0] != 'p' { 1937 t.Fatalf("Child process reports stdin is not pipe '%v'", string(output)) 1938 } 1939 } 1940 1941 func TestStatRelativeSymlink(t *testing.T) { 1942 testenv.MustHaveSymlink(t) 1943 1944 tmpdir, err := ioutil.TempDir("", "TestStatRelativeSymlink") 1945 if err != nil { 1946 t.Fatal(err) 1947 } 1948 defer RemoveAll(tmpdir) 1949 1950 target := filepath.Join(tmpdir, "target") 1951 f, err := Create(target) 1952 if err != nil { 1953 t.Fatal(err) 1954 } 1955 defer f.Close() 1956 1957 st, err := f.Stat() 1958 if err != nil { 1959 t.Fatal(err) 1960 } 1961 1962 link := filepath.Join(tmpdir, "link") 1963 err = Symlink(filepath.Base(target), link) 1964 if err != nil { 1965 t.Fatal(err) 1966 } 1967 1968 st1, err := Stat(link) 1969 if err != nil { 1970 t.Fatal(err) 1971 } 1972 1973 if !SameFile(st, st1) { 1974 t.Error("Stat doesn't follow relative symlink") 1975 } 1976 1977 if runtime.GOOS == "windows" { 1978 Remove(link) 1979 err = Symlink(target[len(filepath.VolumeName(target)):], link) 1980 if err != nil { 1981 t.Fatal(err) 1982 } 1983 1984 st1, err := Stat(link) 1985 if err != nil { 1986 t.Fatal(err) 1987 } 1988 1989 if !SameFile(st, st1) { 1990 t.Error("Stat doesn't follow relative symlink") 1991 } 1992 } 1993 } 1994 1995 func TestReadAtEOF(t *testing.T) { 1996 f := newFile("TestReadAtEOF", t) 1997 defer Remove(f.Name()) 1998 defer f.Close() 1999 2000 _, err := f.ReadAt(make([]byte, 10), 0) 2001 switch err { 2002 case io.EOF: 2003 // all good 2004 case nil: 2005 t.Fatalf("ReadAt succeeded") 2006 default: 2007 t.Fatalf("ReadAt failed: %s", err) 2008 } 2009 } 2010 2011 func TestLongPath(t *testing.T) { 2012 tmpdir := newDir("TestLongPath", t) 2013 defer func(d string) { 2014 if err := RemoveAll(d); err != nil { 2015 t.Fatalf("RemoveAll failed: %v", err) 2016 } 2017 }(tmpdir) 2018 2019 // Test the boundary of 247 and fewer bytes (normal) and 248 and more bytes (adjusted). 2020 sizes := []int{247, 248, 249, 400} 2021 for len(tmpdir) < 400 { 2022 tmpdir += "/dir3456789" 2023 } 2024 for _, sz := range sizes { 2025 t.Run(fmt.Sprintf("length=%d", sz), func(t *testing.T) { 2026 sizedTempDir := tmpdir[:sz-1] + "x" // Ensure it does not end with a slash. 2027 2028 // The various sized runs are for this call to trigger the boundary 2029 // condition. 2030 if err := MkdirAll(sizedTempDir, 0755); err != nil { 2031 t.Fatalf("MkdirAll failed: %v", err) 2032 } 2033 data := []byte("hello world\n") 2034 if err := ioutil.WriteFile(sizedTempDir+"/foo.txt", data, 0644); err != nil { 2035 t.Fatalf("ioutil.WriteFile() failed: %v", err) 2036 } 2037 if err := Rename(sizedTempDir+"/foo.txt", sizedTempDir+"/bar.txt"); err != nil { 2038 t.Fatalf("Rename failed: %v", err) 2039 } 2040 mtime := time.Now().Truncate(time.Minute) 2041 if err := Chtimes(sizedTempDir+"/bar.txt", mtime, mtime); err != nil { 2042 t.Fatalf("Chtimes failed: %v", err) 2043 } 2044 names := []string{"bar.txt"} 2045 if testenv.HasSymlink() { 2046 if err := Symlink(sizedTempDir+"/bar.txt", sizedTempDir+"/symlink.txt"); err != nil { 2047 t.Fatalf("Symlink failed: %v", err) 2048 } 2049 names = append(names, "symlink.txt") 2050 } 2051 if testenv.HasLink() { 2052 if err := Link(sizedTempDir+"/bar.txt", sizedTempDir+"/link.txt"); err != nil { 2053 t.Fatalf("Link failed: %v", err) 2054 } 2055 names = append(names, "link.txt") 2056 } 2057 for _, wantSize := range []int64{int64(len(data)), 0} { 2058 for _, name := range names { 2059 path := sizedTempDir + "/" + name 2060 dir, err := Stat(path) 2061 if err != nil { 2062 t.Fatalf("Stat(%q) failed: %v", path, err) 2063 } 2064 filesize := size(path, t) 2065 if dir.Size() != filesize || filesize != wantSize { 2066 t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize) 2067 } 2068 err = Chmod(path, dir.Mode()) 2069 if err != nil { 2070 t.Fatalf("Chmod(%q) failed: %v", path, err) 2071 } 2072 } 2073 if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil { 2074 t.Fatalf("Truncate failed: %v", err) 2075 } 2076 } 2077 }) 2078 } 2079 } 2080 2081 func testKillProcess(t *testing.T, processKiller func(p *Process)) { 2082 testenv.MustHaveExec(t) 2083 2084 // Re-exec the test binary itself to emulate "sleep 1". 2085 cmd := osexec.Command(Args[0], "-test.run", "TestSleep") 2086 err := cmd.Start() 2087 if err != nil { 2088 t.Fatalf("Failed to start test process: %v", err) 2089 } 2090 go func() { 2091 time.Sleep(100 * time.Millisecond) 2092 processKiller(cmd.Process) 2093 }() 2094 err = cmd.Wait() 2095 if err == nil { 2096 t.Errorf("Test process succeeded, but expected to fail") 2097 } 2098 } 2099 2100 // TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we 2101 // don't have to rely on an external "sleep" command being available. 2102 func TestSleep(t *testing.T) { 2103 if testing.Short() { 2104 t.Skip("Skipping in short mode") 2105 } 2106 time.Sleep(time.Second) 2107 } 2108 2109 func TestKillStartProcess(t *testing.T) { 2110 testKillProcess(t, func(p *Process) { 2111 err := p.Kill() 2112 if err != nil { 2113 t.Fatalf("Failed to kill test process: %v", err) 2114 } 2115 }) 2116 } 2117 2118 func TestGetppid(t *testing.T) { 2119 if runtime.GOOS == "plan9" { 2120 // TODO: golang.org/issue/8206 2121 t.Skipf("skipping test on plan9; see issue 8206") 2122 } 2123 2124 testenv.MustHaveExec(t) 2125 2126 if Getenv("GO_WANT_HELPER_PROCESS") == "1" { 2127 fmt.Print(Getppid()) 2128 Exit(0) 2129 } 2130 2131 cmd := osexec.Command(Args[0], "-test.run=TestGetppid") 2132 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") 2133 2134 // verify that Getppid() from the forked process reports our process id 2135 output, err := cmd.CombinedOutput() 2136 if err != nil { 2137 t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) 2138 } 2139 2140 childPpid := string(output) 2141 ourPid := fmt.Sprintf("%d", Getpid()) 2142 if childPpid != ourPid { 2143 t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid) 2144 } 2145 } 2146 2147 func TestKillFindProcess(t *testing.T) { 2148 testKillProcess(t, func(p *Process) { 2149 p2, err := FindProcess(p.Pid) 2150 if err != nil { 2151 t.Fatalf("Failed to find test process: %v", err) 2152 } 2153 err = p2.Kill() 2154 if err != nil { 2155 t.Fatalf("Failed to kill test process: %v", err) 2156 } 2157 }) 2158 } 2159 2160 var nilFileMethodTests = []struct { 2161 name string 2162 f func(*File) error 2163 }{ 2164 {"Chdir", func(f *File) error { return f.Chdir() }}, 2165 {"Close", func(f *File) error { return f.Close() }}, 2166 {"Chmod", func(f *File) error { return f.Chmod(0) }}, 2167 {"Chown", func(f *File) error { return f.Chown(0, 0) }}, 2168 {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }}, 2169 {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }}, 2170 {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }}, 2171 {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }}, 2172 {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }}, 2173 {"Stat", func(f *File) error { _, err := f.Stat(); return err }}, 2174 {"Sync", func(f *File) error { return f.Sync() }}, 2175 {"Truncate", func(f *File) error { return f.Truncate(0) }}, 2176 {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }}, 2177 {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }}, 2178 {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }}, 2179 } 2180 2181 // Test that all File methods give ErrInvalid if the receiver is nil. 2182 func TestNilFileMethods(t *testing.T) { 2183 for _, tt := range nilFileMethodTests { 2184 var file *File 2185 got := tt.f(file) 2186 if got != ErrInvalid { 2187 t.Errorf("%v should fail when f is nil; got %v", tt.name, got) 2188 } 2189 } 2190 } 2191 2192 func mkdirTree(t *testing.T, root string, level, max int) { 2193 if level >= max { 2194 return 2195 } 2196 level++ 2197 for i := 'a'; i < 'c'; i++ { 2198 dir := filepath.Join(root, string(i)) 2199 if err := Mkdir(dir, 0700); err != nil { 2200 t.Fatal(err) 2201 } 2202 mkdirTree(t, dir, level, max) 2203 } 2204 } 2205 2206 // Test that simultaneous RemoveAll do not report an error. 2207 // As long as it gets removed, we should be happy. 2208 func TestRemoveAllRace(t *testing.T) { 2209 if runtime.GOOS == "windows" { 2210 // Windows has very strict rules about things like 2211 // removing directories while someone else has 2212 // them open. The racing doesn't work out nicely 2213 // like it does on Unix. 2214 t.Skip("skipping on windows") 2215 } 2216 2217 n := runtime.GOMAXPROCS(16) 2218 defer runtime.GOMAXPROCS(n) 2219 root, err := ioutil.TempDir("", "issue") 2220 if err != nil { 2221 t.Fatal(err) 2222 } 2223 mkdirTree(t, root, 1, 6) 2224 hold := make(chan struct{}) 2225 var wg sync.WaitGroup 2226 for i := 0; i < 4; i++ { 2227 wg.Add(1) 2228 go func() { 2229 defer wg.Done() 2230 <-hold 2231 err := RemoveAll(root) 2232 if err != nil { 2233 t.Errorf("unexpected error: %T, %q", err, err) 2234 } 2235 }() 2236 } 2237 close(hold) // let workers race to remove root 2238 wg.Wait() 2239 } 2240 2241 // Test that reading from a pipe doesn't use up a thread. 2242 func TestPipeThreads(t *testing.T) { 2243 switch runtime.GOOS { 2244 case "freebsd": 2245 t.Skip("skipping on FreeBSD; issue 19093") 2246 case "illumos", "solaris": 2247 t.Skip("skipping on Solaris and illumos; issue 19111") 2248 case "windows": 2249 t.Skip("skipping on Windows; issue 19098") 2250 case "plan9": 2251 t.Skip("skipping on Plan 9; does not support runtime poller") 2252 case "js": 2253 t.Skip("skipping on js; no support for os.Pipe") 2254 } 2255 2256 threads := 100 2257 2258 // OpenBSD has a low default for max number of files. 2259 if runtime.GOOS == "openbsd" { 2260 threads = 50 2261 } 2262 2263 r := make([]*File, threads) 2264 w := make([]*File, threads) 2265 for i := 0; i < threads; i++ { 2266 rp, wp, err := Pipe() 2267 if err != nil { 2268 for j := 0; j < i; j++ { 2269 r[j].Close() 2270 w[j].Close() 2271 } 2272 t.Fatal(err) 2273 } 2274 r[i] = rp 2275 w[i] = wp 2276 } 2277 2278 defer debug.SetMaxThreads(debug.SetMaxThreads(threads / 2)) 2279 2280 creading := make(chan bool, threads) 2281 cdone := make(chan bool, threads) 2282 for i := 0; i < threads; i++ { 2283 go func(i int) { 2284 var b [1]byte 2285 creading <- true 2286 if _, err := r[i].Read(b[:]); err != nil { 2287 t.Error(err) 2288 } 2289 if err := r[i].Close(); err != nil { 2290 t.Error(err) 2291 } 2292 cdone <- true 2293 }(i) 2294 } 2295 2296 for i := 0; i < threads; i++ { 2297 <-creading 2298 } 2299 2300 // If we are still alive, it means that the 100 goroutines did 2301 // not require 100 threads. 2302 2303 for i := 0; i < threads; i++ { 2304 if _, err := w[i].Write([]byte{0}); err != nil { 2305 t.Error(err) 2306 } 2307 if err := w[i].Close(); err != nil { 2308 t.Error(err) 2309 } 2310 <-cdone 2311 } 2312 } 2313 2314 func testDoubleCloseError(t *testing.T, path string) { 2315 file, err := Open(path) 2316 if err != nil { 2317 t.Fatal(err) 2318 } 2319 if err := file.Close(); err != nil { 2320 t.Fatalf("unexpected error from Close: %v", err) 2321 } 2322 if err := file.Close(); err == nil { 2323 t.Error("second Close did not fail") 2324 } else if pe, ok := err.(*PathError); !ok { 2325 t.Errorf("second Close returned unexpected error type %T; expected os.PathError", pe) 2326 } else if pe.Err != ErrClosed { 2327 t.Errorf("second Close returned %q, wanted %q", err, ErrClosed) 2328 } else { 2329 t.Logf("second close returned expected error %q", err) 2330 } 2331 } 2332 2333 func TestDoubleCloseError(t *testing.T) { 2334 testDoubleCloseError(t, filepath.Join(sfdir, sfname)) 2335 testDoubleCloseError(t, sfdir) 2336 } 2337 2338 func TestUserHomeDir(t *testing.T) { 2339 dir, err := UserHomeDir() 2340 if dir == "" && err == nil { 2341 t.Fatal("UserHomeDir returned an empty string but no error") 2342 } 2343 if err != nil { 2344 t.Skipf("UserHomeDir failed: %v", err) 2345 } 2346 fi, err := Stat(dir) 2347 if err != nil { 2348 t.Fatal(err) 2349 } 2350 if !fi.IsDir() { 2351 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode()) 2352 } 2353 }