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