runtime: abort stack scan in cases that we cannot unwind the stack
[gcc.git] / libgo / go / os / os_test.go
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.go",
31 "env.go",
32 "error.go",
33 "file.go",
34 "os_test.go",
35 "types.go",
36 }
37
38 type sysDir struct {
39 name string
40 files []string
41 }
42
43 var 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
96 func 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
117 func 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.
128 func 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
141 func 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
149 func 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
157 var sfdir = sysdir.name
158 var sfname = sysdir.files[0]
159
160 func 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
175 func 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
211 func 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
231 func 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.
247 func 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
268 func 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
289 func 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
318 func 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
344 func TestReaddirnames(t *testing.T) {
345 testReaddirnames(".", dot, t)
346 testReaddirnames(sysdir.name, sysdir.files, t)
347 }
348
349 func TestReaddir(t *testing.T) {
350 testReaddir(".", dot, t)
351 testReaddir(sysdir.name, sysdir.files, t)
352 }
353
354 func 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
371 func 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
388 func BenchmarkReaddirname(b *testing.B) {
389 benchmarkReaddirname(".", b)
390 }
391
392 func BenchmarkReaddir(b *testing.B) {
393 benchmarkReaddir(".", b)
394 }
395
396 func 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
406 func 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
416 func BenchmarkStatDot(b *testing.B) {
417 benchmarkStat(b, ".")
418 }
419
420 func BenchmarkStatFile(b *testing.B) {
421 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
422 }
423
424 func BenchmarkStatDir(b *testing.B) {
425 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os"))
426 }
427
428 func BenchmarkLstatDot(b *testing.B) {
429 benchmarkLstat(b, ".")
430 }
431
432 func BenchmarkLstatFile(b *testing.B) {
433 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
434 }
435
436 func BenchmarkLstatDir(b *testing.B) {
437 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os"))
438 }
439
440 // Read the directory one entry at a time.
441 func 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.
463 func 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
508 func 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
579 func 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
589 func 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.
658 func 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
681 func 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.
741 func 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
761 func 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
822 func 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
843 func 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
864 func 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
901 func 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
924 func 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
935 func 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
961 func 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
987 func 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
1017 func 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
1027 func 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
1047 func 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
1057 func 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
1077 func 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).
1101 func 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).
1115 func TestChtimesDir(t *testing.T) {
1116 name := newDir("TestChtimes", t)
1117 defer RemoveAll(name)
1118
1119 testChtimes(t, name)
1120 }
1121
1122 func 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
1171 func 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.
1248 func 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
1305 func 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
1357 func 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
1383 type openErrorTest struct {
1384 path string
1385 mode int
1386 error error
1387 }
1388
1389 var 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
1407 func 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
1446 func TestOpenNoName(t *testing.T) {
1447 f, err := Open("")
1448 if err == nil {
1449 t.Fatal(`Open("") succeeded`)
1450 f.Close()
1451 }
1452 }
1453
1454 func 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
1496 func 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
1508 func 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
1545 func 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.
1567 func 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.
1596 func 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
1615 func 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.
1638 func 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
1651 func 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
1668 func 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
1701 func 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
1723 func 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
1731 func 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
1765 func 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
1791 func 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
1811 func TestDevNullFile(t *testing.T) {
1812 testDevNullFile(t, DevNull, false)
1813 }
1814
1815 var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output")
1816
1817 func 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
1842 func 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
1864 func 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
1911 func 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
1965 func 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
1981 func 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
2051 func 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.
2072 func TestSleep(t *testing.T) {
2073 if testing.Short() {
2074 t.Skip("Skipping in short mode")
2075 }
2076 time.Sleep(time.Second)
2077 }
2078
2079 func 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
2088 func 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
2117 func 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
2130 var 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.
2152 func 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
2162 func 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.
2178 func 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.
2212 func 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
2284 func 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
2304 func 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 }