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