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	"sort"
21	"strings"
22	"sync"
23	"syscall"
24	"testing"
25	"time"
26)
27
28var supportsSymlinks = true
29
30var dot = []string{
31	"dir_unix.go",
32	"env.go",
33	"error.go",
34	"file.go",
35	"os_test.go",
36	"types.go",
37}
38
39type sysDir struct {
40	name  string
41	files []string
42}
43
44var sysdir = func() *sysDir {
45	switch runtime.GOOS {
46	case "android":
47		return &sysDir{
48			"/system/framework",
49			[]string{
50				"ext.jar",
51				"framework.jar",
52			},
53		}
54	case "darwin":
55		switch runtime.GOARCH {
56		case "arm", "arm64":
57			wd, err := syscall.Getwd()
58			if err != nil {
59				wd = err.Error()
60			}
61			return &sysDir{
62				filepath.Join(wd, "..", ".."),
63				[]string{
64					"ResourceRules.plist",
65					"Info.plist",
66				},
67			}
68		}
69	case "windows":
70		return &sysDir{
71			Getenv("SystemRoot") + "\\system32\\drivers\\etc",
72			[]string{
73				"networks",
74				"protocol",
75				"services",
76			},
77		}
78	case "plan9":
79		return &sysDir{
80			"/lib/ndb",
81			[]string{
82				"common",
83				"local",
84			},
85		}
86	}
87	return &sysDir{
88		"/etc",
89		[]string{
90			"group",
91			"hosts",
92			"passwd",
93		},
94	}
95}()
96
97func size(name string, t *testing.T) int64 {
98	file, err := Open(name)
99	if err != nil {
100		t.Fatal("open failed:", err)
101	}
102	defer file.Close()
103	var buf [100]byte
104	len := 0
105	for {
106		n, e := file.Read(buf[0:])
107		len += n
108		if e == io.EOF {
109			break
110		}
111		if e != nil {
112			t.Fatal("read failed:", err)
113		}
114	}
115	return int64(len)
116}
117
118func equal(name1, name2 string) (r bool) {
119	switch runtime.GOOS {
120	case "windows":
121		r = strings.ToLower(name1) == strings.ToLower(name2)
122	default:
123		r = name1 == name2
124	}
125	return
126}
127
128// localTmp returns a local temporary directory not on NFS.
129func localTmp() string {
130	switch runtime.GOOS {
131	case "android", "windows":
132		return TempDir()
133	case "darwin":
134		switch runtime.GOARCH {
135		case "arm", "arm64":
136			return TempDir()
137		}
138	}
139	return "/tmp"
140}
141
142func newFile(testName string, t *testing.T) (f *File) {
143	f, err := ioutil.TempFile(localTmp(), "_Go_"+testName)
144	if err != nil {
145		t.Fatalf("TempFile %s: %s", testName, err)
146	}
147	return
148}
149
150func newDir(testName string, t *testing.T) (name string) {
151	name, err := ioutil.TempDir(localTmp(), "_Go_"+testName)
152	if err != nil {
153		t.Fatalf("TempDir %s: %s", testName, err)
154	}
155	return
156}
157
158var sfdir = sysdir.name
159var sfname = sysdir.files[0]
160
161func TestStat(t *testing.T) {
162	path := sfdir + "/" + sfname
163	dir, err := Stat(path)
164	if err != nil {
165		t.Fatal("stat failed:", err)
166	}
167	if !equal(sfname, dir.Name()) {
168		t.Error("name should be ", sfname, "; is", dir.Name())
169	}
170	filesize := size(path, t)
171	if dir.Size() != filesize {
172		t.Error("size should be", filesize, "; is", dir.Size())
173	}
174}
175
176func TestFstat(t *testing.T) {
177	path := sfdir + "/" + sfname
178	file, err1 := Open(path)
179	if err1 != nil {
180		t.Fatal("open failed:", err1)
181	}
182	defer file.Close()
183	dir, err2 := file.Stat()
184	if err2 != nil {
185		t.Fatal("fstat failed:", err2)
186	}
187	if !equal(sfname, dir.Name()) {
188		t.Error("name should be ", sfname, "; is", dir.Name())
189	}
190	filesize := size(path, t)
191	if dir.Size() != filesize {
192		t.Error("size should be", filesize, "; is", dir.Size())
193	}
194}
195
196func TestLstat(t *testing.T) {
197	path := sfdir + "/" + sfname
198	dir, err := Lstat(path)
199	if err != nil {
200		t.Fatal("lstat failed:", err)
201	}
202	if !equal(sfname, dir.Name()) {
203		t.Error("name should be ", sfname, "; is", dir.Name())
204	}
205	filesize := size(path, t)
206	if dir.Size() != filesize {
207		t.Error("size should be", filesize, "; is", dir.Size())
208	}
209}
210
211// Read with length 0 should not return EOF.
212func TestRead0(t *testing.T) {
213	path := sfdir + "/" + sfname
214	f, err := Open(path)
215	if err != nil {
216		t.Fatal("open failed:", err)
217	}
218	defer f.Close()
219
220	b := make([]byte, 0)
221	n, err := f.Read(b)
222	if n != 0 || err != nil {
223		t.Errorf("Read(0) = %d, %v, want 0, nil", n, err)
224	}
225	b = make([]byte, 100)
226	n, err = f.Read(b)
227	if n <= 0 || err != nil {
228		t.Errorf("Read(100) = %d, %v, want >0, nil", n, err)
229	}
230}
231
232func testReaddirnames(dir string, contents []string, t *testing.T) {
233	file, err := Open(dir)
234	if err != nil {
235		t.Fatalf("open %q failed: %v", dir, err)
236	}
237	defer file.Close()
238	s, err2 := file.Readdirnames(-1)
239	if err2 != nil {
240		t.Fatalf("readdirnames %q failed: %v", dir, err2)
241	}
242	for _, m := range contents {
243		found := false
244		for _, n := range s {
245			if n == "." || n == ".." {
246				t.Errorf("got %s in directory", n)
247			}
248			if equal(m, n) {
249				if found {
250					t.Error("present twice:", m)
251				}
252				found = true
253			}
254		}
255		if !found {
256			t.Error("could not find", m)
257		}
258	}
259}
260
261func testReaddir(dir string, contents []string, t *testing.T) {
262	file, err := Open(dir)
263	if err != nil {
264		t.Fatalf("open %q failed: %v", dir, err)
265	}
266	defer file.Close()
267	s, err2 := file.Readdir(-1)
268	if err2 != nil {
269		t.Fatalf("readdir %q failed: %v", dir, err2)
270	}
271	for _, m := range contents {
272		found := false
273		for _, n := range s {
274			if equal(m, n.Name()) {
275				if found {
276					t.Error("present twice:", m)
277				}
278				found = true
279			}
280		}
281		if !found {
282			t.Error("could not find", m)
283		}
284	}
285}
286
287func TestReaddirnames(t *testing.T) {
288	testReaddirnames(".", dot, t)
289	testReaddirnames(sysdir.name, sysdir.files, t)
290}
291
292func TestReaddir(t *testing.T) {
293	testReaddir(".", dot, t)
294	testReaddir(sysdir.name, sysdir.files, t)
295}
296
297func benchmarkReaddirname(path string, b *testing.B) {
298	var nentries int
299	for i := 0; i < b.N; i++ {
300		f, err := Open(path)
301		if err != nil {
302			b.Fatalf("open %q failed: %v", path, err)
303		}
304		ns, err := f.Readdirnames(-1)
305		f.Close()
306		if err != nil {
307			b.Fatalf("readdirnames %q failed: %v", path, err)
308		}
309		nentries = len(ns)
310	}
311	b.Logf("benchmarkReaddirname %q: %d entries", path, nentries)
312}
313
314func benchmarkReaddir(path string, b *testing.B) {
315	var nentries int
316	for i := 0; i < b.N; i++ {
317		f, err := Open(path)
318		if err != nil {
319			b.Fatalf("open %q failed: %v", path, err)
320		}
321		fs, err := f.Readdir(-1)
322		f.Close()
323		if err != nil {
324			b.Fatalf("readdir %q failed: %v", path, err)
325		}
326		nentries = len(fs)
327	}
328	b.Logf("benchmarkReaddir %q: %d entries", path, nentries)
329}
330
331func BenchmarkReaddirname(b *testing.B) {
332	benchmarkReaddirname(".", b)
333}
334
335func BenchmarkReaddir(b *testing.B) {
336	benchmarkReaddir(".", b)
337}
338
339// Read the directory one entry at a time.
340func smallReaddirnames(file *File, length int, t *testing.T) []string {
341	names := make([]string, length)
342	count := 0
343	for {
344		d, err := file.Readdirnames(1)
345		if err == io.EOF {
346			break
347		}
348		if err != nil {
349			t.Fatalf("readdirnames %q failed: %v", file.Name(), err)
350		}
351		if len(d) == 0 {
352			t.Fatalf("readdirnames %q returned empty slice and no error", file.Name())
353		}
354		names[count] = d[0]
355		count++
356	}
357	return names[0:count]
358}
359
360// Check that reading a directory one entry at a time gives the same result
361// as reading it all at once.
362func TestReaddirnamesOneAtATime(t *testing.T) {
363	// big directory that doesn't change often.
364	dir := "/usr/bin"
365	switch runtime.GOOS {
366	case "android":
367		dir = "/system/bin"
368	case "darwin":
369		switch runtime.GOARCH {
370		case "arm", "arm64":
371			wd, err := Getwd()
372			if err != nil {
373				t.Fatal(err)
374			}
375			dir = wd
376		}
377	case "plan9":
378		dir = "/bin"
379	case "windows":
380		dir = Getenv("SystemRoot") + "\\system32"
381	}
382	file, err := Open(dir)
383	if err != nil {
384		t.Fatalf("open %q failed: %v", dir, err)
385	}
386	defer file.Close()
387	all, err1 := file.Readdirnames(-1)
388	if err1 != nil {
389		t.Fatalf("readdirnames %q failed: %v", dir, err1)
390	}
391	file1, err2 := Open(dir)
392	if err2 != nil {
393		t.Fatalf("open %q failed: %v", dir, err2)
394	}
395	defer file1.Close()
396	small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
397	if len(small) < len(all) {
398		t.Fatalf("len(small) is %d, less than %d", len(small), len(all))
399	}
400	for i, n := range all {
401		if small[i] != n {
402			t.Errorf("small read %q mismatch: %v", small[i], n)
403		}
404	}
405}
406
407func TestReaddirNValues(t *testing.T) {
408	if testing.Short() {
409		t.Skip("test.short; skipping")
410	}
411	dir, err := ioutil.TempDir("", "")
412	if err != nil {
413		t.Fatalf("TempDir: %v", err)
414	}
415	defer RemoveAll(dir)
416	for i := 1; i <= 105; i++ {
417		f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i)))
418		if err != nil {
419			t.Fatalf("Create: %v", err)
420		}
421		f.Write([]byte(strings.Repeat("X", i)))
422		f.Close()
423	}
424
425	var d *File
426	openDir := func() {
427		var err error
428		d, err = Open(dir)
429		if err != nil {
430			t.Fatalf("Open directory: %v", err)
431		}
432	}
433
434	readDirExpect := func(n, want int, wantErr error) {
435		fi, err := d.Readdir(n)
436		if err != wantErr {
437			t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr)
438		}
439		if g, e := len(fi), want; g != e {
440			t.Errorf("Readdir of %d got %d files, want %d", n, g, e)
441		}
442	}
443
444	readDirNamesExpect := func(n, want int, wantErr error) {
445		fi, err := d.Readdirnames(n)
446		if err != wantErr {
447			t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr)
448		}
449		if g, e := len(fi), want; g != e {
450			t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e)
451		}
452	}
453
454	for _, fn := range []func(int, int, error){readDirExpect, readDirNamesExpect} {
455		// Test the slurp case
456		openDir()
457		fn(0, 105, nil)
458		fn(0, 0, nil)
459		d.Close()
460
461		// Slurp with -1 instead
462		openDir()
463		fn(-1, 105, nil)
464		fn(-2, 0, nil)
465		fn(0, 0, nil)
466		d.Close()
467
468		// Test the bounded case
469		openDir()
470		fn(1, 1, nil)
471		fn(2, 2, nil)
472		fn(105, 102, nil) // and tests buffer >100 case
473		fn(3, 0, io.EOF)
474		d.Close()
475	}
476}
477
478func touch(t *testing.T, name string) {
479	f, err := Create(name)
480	if err != nil {
481		t.Fatal(err)
482	}
483	if err := f.Close(); err != nil {
484		t.Fatal(err)
485	}
486}
487
488func TestReaddirStatFailures(t *testing.T) {
489	switch runtime.GOOS {
490	case "windows", "plan9":
491		// Windows and Plan 9 already do this correctly,
492		// but are structured with different syscalls such
493		// that they don't use Lstat, so the hook below for
494		// testing it wouldn't work.
495		t.Skipf("skipping test on %v", runtime.GOOS)
496	}
497	dir, err := ioutil.TempDir("", "")
498	if err != nil {
499		t.Fatalf("TempDir: %v", err)
500	}
501	defer RemoveAll(dir)
502	touch(t, filepath.Join(dir, "good1"))
503	touch(t, filepath.Join(dir, "x")) // will disappear or have an error
504	touch(t, filepath.Join(dir, "good2"))
505	defer func() {
506		*LstatP = Lstat
507	}()
508	var xerr error // error to return for x
509	*LstatP = func(path string) (FileInfo, error) {
510		if xerr != nil && strings.HasSuffix(path, "x") {
511			return nil, xerr
512		}
513		return Lstat(path)
514	}
515	readDir := func() ([]FileInfo, error) {
516		d, err := Open(dir)
517		if err != nil {
518			t.Fatal(err)
519		}
520		defer d.Close()
521		return d.Readdir(-1)
522	}
523	mustReadDir := func(testName string) []FileInfo {
524		fis, err := readDir()
525		if err != nil {
526			t.Fatalf("%s: Readdir: %v", testName, err)
527		}
528		return fis
529	}
530	names := func(fis []FileInfo) []string {
531		s := make([]string, len(fis))
532		for i, fi := range fis {
533			s[i] = fi.Name()
534		}
535		sort.Strings(s)
536		return s
537	}
538
539	if got, want := names(mustReadDir("inital readdir")),
540		[]string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) {
541		t.Errorf("initial readdir got %q; want %q", got, want)
542	}
543
544	xerr = ErrNotExist
545	if got, want := names(mustReadDir("with x disappearing")),
546		[]string{"good1", "good2"}; !reflect.DeepEqual(got, want) {
547		t.Errorf("with x disappearing, got %q; want %q", got, want)
548	}
549
550	xerr = errors.New("some real error")
551	if _, err := readDir(); err != xerr {
552		t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr)
553	}
554}
555
556// Readdir on a regular file should fail.
557func TestReaddirOfFile(t *testing.T) {
558	f, err := ioutil.TempFile("", "_Go_ReaddirOfFile")
559	if err != nil {
560		t.Fatal(err)
561	}
562	defer Remove(f.Name())
563	f.Write([]byte("foo"))
564	f.Close()
565	reg, err := Open(f.Name())
566	if err != nil {
567		t.Fatal(err)
568	}
569	defer reg.Close()
570
571	names, err := reg.Readdirnames(-1)
572	if err == nil {
573		t.Error("Readdirnames succeeded; want non-nil error")
574	}
575	if len(names) > 0 {
576		t.Errorf("unexpected dir names in regular file: %q", names)
577	}
578}
579
580func TestHardLink(t *testing.T) {
581	if runtime.GOOS == "plan9" {
582		t.Skip("skipping on plan9, hardlinks not supported")
583	}
584	// From Android release M (Marshmallow), hard linking files is blocked
585	// and an attempt to call link() on a file will return EACCES.
586	// - https://code.google.com/p/android-developer-preview/issues/detail?id=3150
587	if runtime.GOOS == "android" {
588		t.Skip("skipping on android, hardlinks not supported")
589	}
590	defer chtmpdir(t)()
591	from, to := "hardlinktestfrom", "hardlinktestto"
592	Remove(from) // Just in case.
593	file, err := Create(to)
594	if err != nil {
595		t.Fatalf("open %q failed: %v", to, err)
596	}
597	defer Remove(to)
598	if err = file.Close(); err != nil {
599		t.Errorf("close %q failed: %v", to, err)
600	}
601	err = Link(to, from)
602	if err != nil {
603		t.Fatalf("link %q, %q failed: %v", to, from, err)
604	}
605
606	none := "hardlinktestnone"
607	err = Link(none, none)
608	// Check the returned error is well-formed.
609	if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" {
610		t.Errorf("link %q, %q failed to return a valid error", none, none)
611	}
612
613	defer Remove(from)
614	tostat, err := Stat(to)
615	if err != nil {
616		t.Fatalf("stat %q failed: %v", to, err)
617	}
618	fromstat, err := Stat(from)
619	if err != nil {
620		t.Fatalf("stat %q failed: %v", from, err)
621	}
622	if !SameFile(tostat, fromstat) {
623		t.Errorf("link %q, %q did not create hard link", to, from)
624	}
625}
626
627// chtmpdir changes the working directory to a new temporary directory and
628// provides a cleanup function. Used when PWD is read-only.
629func chtmpdir(t *testing.T) func() {
630	if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") {
631		return func() {} // only needed on darwin/arm{,64}
632	}
633	oldwd, err := Getwd()
634	if err != nil {
635		t.Fatalf("chtmpdir: %v", err)
636	}
637	d, err := ioutil.TempDir("", "test")
638	if err != nil {
639		t.Fatalf("chtmpdir: %v", err)
640	}
641	if err := Chdir(d); err != nil {
642		t.Fatalf("chtmpdir: %v", err)
643	}
644	return func() {
645		if err := Chdir(oldwd); err != nil {
646			t.Fatalf("chtmpdir: %v", err)
647		}
648		RemoveAll(d)
649	}
650}
651
652func TestSymlink(t *testing.T) {
653	switch runtime.GOOS {
654	case "android", "nacl", "plan9":
655		t.Skipf("skipping on %s", runtime.GOOS)
656	case "windows":
657		if !supportsSymlinks {
658			t.Skipf("skipping on %s", runtime.GOOS)
659		}
660	}
661	defer chtmpdir(t)()
662	from, to := "symlinktestfrom", "symlinktestto"
663	Remove(from) // Just in case.
664	file, err := Create(to)
665	if err != nil {
666		t.Fatalf("open %q failed: %v", to, err)
667	}
668	defer Remove(to)
669	if err = file.Close(); err != nil {
670		t.Errorf("close %q failed: %v", to, err)
671	}
672	err = Symlink(to, from)
673	if err != nil {
674		t.Fatalf("symlink %q, %q failed: %v", to, from, err)
675	}
676	defer Remove(from)
677	tostat, err := Lstat(to)
678	if err != nil {
679		t.Fatalf("stat %q failed: %v", to, err)
680	}
681	if tostat.Mode()&ModeSymlink != 0 {
682		t.Fatalf("stat %q claims to have found a symlink", to)
683	}
684	fromstat, err := Stat(from)
685	if err != nil {
686		t.Fatalf("stat %q failed: %v", from, err)
687	}
688	if !SameFile(tostat, fromstat) {
689		t.Errorf("symlink %q, %q did not create symlink", to, from)
690	}
691	fromstat, err = Lstat(from)
692	if err != nil {
693		t.Fatalf("lstat %q failed: %v", from, err)
694	}
695	if fromstat.Mode()&ModeSymlink == 0 {
696		t.Fatalf("symlink %q, %q did not create symlink", to, from)
697	}
698	fromstat, err = Stat(from)
699	if err != nil {
700		t.Fatalf("stat %q failed: %v", from, err)
701	}
702	if fromstat.Mode()&ModeSymlink != 0 {
703		t.Fatalf("stat %q did not follow symlink", from)
704	}
705	s, err := Readlink(from)
706	if err != nil {
707		t.Fatalf("readlink %q failed: %v", from, err)
708	}
709	if s != to {
710		t.Fatalf("after symlink %q != %q", s, to)
711	}
712	file, err = Open(from)
713	if err != nil {
714		t.Fatalf("open %q failed: %v", from, err)
715	}
716	file.Close()
717}
718
719func TestLongSymlink(t *testing.T) {
720	switch runtime.GOOS {
721	case "android", "plan9", "nacl":
722		t.Skipf("skipping on %s", runtime.GOOS)
723	case "windows":
724		if !supportsSymlinks {
725			t.Skipf("skipping on %s", runtime.GOOS)
726		}
727	}
728	defer chtmpdir(t)()
729	s := "0123456789abcdef"
730	// Long, but not too long: a common limit is 255.
731	s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
732	from := "longsymlinktestfrom"
733	Remove(from) // Just in case.
734	err := Symlink(s, from)
735	if err != nil {
736		t.Fatalf("symlink %q, %q failed: %v", s, from, err)
737	}
738	defer Remove(from)
739	r, err := Readlink(from)
740	if err != nil {
741		t.Fatalf("readlink %q failed: %v", from, err)
742	}
743	if r != s {
744		t.Fatalf("after symlink %q != %q", r, s)
745	}
746}
747
748func TestRename(t *testing.T) {
749	defer chtmpdir(t)()
750	from, to := "renamefrom", "renameto"
751	// Ensure we are not testing the overwrite case here.
752	Remove(from)
753	Remove(to)
754
755	file, err := Create(from)
756	if err != nil {
757		t.Fatalf("open %q failed: %v", from, err)
758	}
759	if err = file.Close(); err != nil {
760		t.Errorf("close %q failed: %v", from, err)
761	}
762	err = Rename(from, to)
763	if err != nil {
764		t.Fatalf("rename %q, %q failed: %v", to, from, err)
765	}
766	defer Remove(to)
767	_, err = Stat(to)
768	if err != nil {
769		t.Errorf("stat %q failed: %v", to, err)
770	}
771}
772
773func TestRenameOverwriteDest(t *testing.T) {
774	defer chtmpdir(t)()
775	from, to := "renamefrom", "renameto"
776	// Just in case.
777	Remove(from)
778	Remove(to)
779
780	toData := []byte("to")
781	fromData := []byte("from")
782
783	err := ioutil.WriteFile(to, toData, 0777)
784	if err != nil {
785		t.Fatalf("write file %q failed: %v", to, err)
786	}
787
788	err = ioutil.WriteFile(from, fromData, 0777)
789	if err != nil {
790		t.Fatalf("write file %q failed: %v", from, err)
791	}
792	err = Rename(from, to)
793	if err != nil {
794		t.Fatalf("rename %q, %q failed: %v", to, from, err)
795	}
796	defer Remove(to)
797
798	_, err = Stat(from)
799	if err == nil {
800		t.Errorf("from file %q still exists", from)
801	}
802	if err != nil && !IsNotExist(err) {
803		t.Fatalf("stat from: %v", err)
804	}
805	toFi, err := Stat(to)
806	if err != nil {
807		t.Fatalf("stat %q failed: %v", to, err)
808	}
809	if toFi.Size() != int64(len(fromData)) {
810		t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData))
811	}
812}
813
814func TestRenameFailed(t *testing.T) {
815	defer chtmpdir(t)()
816	from, to := "renamefrom", "renameto"
817	// Ensure we are not testing the overwrite case here.
818	Remove(from)
819	Remove(to)
820
821	err := Rename(from, to)
822	switch err := err.(type) {
823	case *LinkError:
824		if err.Op != "rename" {
825			t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
826		}
827		if err.Old != from {
828			t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
829		}
830		if err.New != to {
831			t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
832		}
833	case nil:
834		t.Errorf("rename %q, %q: expected error, got nil", from, to)
835
836		// cleanup whatever was placed in "renameto"
837		Remove(to)
838	default:
839		t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
840	}
841}
842
843func exec(t *testing.T, dir, cmd string, args []string, expect string) {
844	r, w, err := Pipe()
845	if err != nil {
846		t.Fatalf("Pipe: %v", err)
847	}
848	defer r.Close()
849	attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}}
850	p, err := StartProcess(cmd, args, attr)
851	if err != nil {
852		t.Fatalf("StartProcess: %v", err)
853	}
854	w.Close()
855
856	var b bytes.Buffer
857	io.Copy(&b, r)
858	output := b.String()
859
860	fi1, _ := Stat(strings.TrimSpace(output))
861	fi2, _ := Stat(expect)
862	if !SameFile(fi1, fi2) {
863		t.Errorf("exec %q returned %q wanted %q",
864			strings.Join(append([]string{cmd}, args...), " "), output, expect)
865	}
866	p.Wait()
867}
868
869func TestStartProcess(t *testing.T) {
870	testenv.MustHaveExec(t)
871
872	var dir, cmd string
873	var args []string
874	switch runtime.GOOS {
875	case "android":
876		t.Skip("android doesn't have /bin/pwd")
877	case "windows":
878		cmd = Getenv("COMSPEC")
879		dir = Getenv("SystemRoot")
880		args = []string{"/c", "cd"}
881	default:
882		cmd = "/bin/pwd"
883		dir = "/"
884		args = []string{}
885	}
886	cmddir, cmdbase := filepath.Split(cmd)
887	args = append([]string{cmdbase}, args...)
888	// Test absolute executable path.
889	exec(t, dir, cmd, args, dir)
890	// Test relative executable path.
891	exec(t, cmddir, cmdbase, args, cmddir)
892}
893
894func checkMode(t *testing.T, path string, mode FileMode) {
895	dir, err := Stat(path)
896	if err != nil {
897		t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
898	}
899	if dir.Mode()&0777 != mode {
900		t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
901	}
902}
903
904func TestChmod(t *testing.T) {
905	// Chmod is not supported under windows.
906	if runtime.GOOS == "windows" {
907		return
908	}
909	f := newFile("TestChmod", t)
910	defer Remove(f.Name())
911	defer f.Close()
912
913	if err := Chmod(f.Name(), 0456); err != nil {
914		t.Fatalf("chmod %s 0456: %s", f.Name(), err)
915	}
916	checkMode(t, f.Name(), 0456)
917
918	if err := f.Chmod(0123); err != nil {
919		t.Fatalf("chmod %s 0123: %s", f.Name(), err)
920	}
921	checkMode(t, f.Name(), 0123)
922}
923
924func checkSize(t *testing.T, f *File, size int64) {
925	dir, err := f.Stat()
926	if err != nil {
927		t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
928	}
929	if dir.Size() != size {
930		t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size)
931	}
932}
933
934func TestFTruncate(t *testing.T) {
935	f := newFile("TestFTruncate", t)
936	defer Remove(f.Name())
937	defer f.Close()
938
939	checkSize(t, f, 0)
940	f.Write([]byte("hello, world\n"))
941	checkSize(t, f, 13)
942	f.Truncate(10)
943	checkSize(t, f, 10)
944	f.Truncate(1024)
945	checkSize(t, f, 1024)
946	f.Truncate(0)
947	checkSize(t, f, 0)
948	_, err := f.Write([]byte("surprise!"))
949	if err == nil {
950		checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
951	}
952}
953
954func TestTruncate(t *testing.T) {
955	f := newFile("TestTruncate", t)
956	defer Remove(f.Name())
957	defer f.Close()
958
959	checkSize(t, f, 0)
960	f.Write([]byte("hello, world\n"))
961	checkSize(t, f, 13)
962	Truncate(f.Name(), 10)
963	checkSize(t, f, 10)
964	Truncate(f.Name(), 1024)
965	checkSize(t, f, 1024)
966	Truncate(f.Name(), 0)
967	checkSize(t, f, 0)
968	_, err := f.Write([]byte("surprise!"))
969	if err == nil {
970		checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
971	}
972}
973
974// Use TempDir (via newFile) to make sure we're on a local file system,
975// so that timings are not distorted by latency and caching.
976// On NFS, timings can be off due to caching of meta-data on
977// NFS servers (Issue 848).
978func TestChtimes(t *testing.T) {
979	f := newFile("TestChtimes", t)
980	defer Remove(f.Name())
981
982	f.Write([]byte("hello, world\n"))
983	f.Close()
984
985	testChtimes(t, f.Name())
986}
987
988// Use TempDir (via newDir) to make sure we're on a local file system,
989// so that timings are not distorted by latency and caching.
990// On NFS, timings can be off due to caching of meta-data on
991// NFS servers (Issue 848).
992func TestChtimesDir(t *testing.T) {
993	name := newDir("TestChtimes", t)
994	defer RemoveAll(name)
995
996	testChtimes(t, name)
997}
998
999func testChtimes(t *testing.T, name string) {
1000	st, err := Stat(name)
1001	if err != nil {
1002		t.Fatalf("Stat %s: %s", name, err)
1003	}
1004	preStat := st
1005
1006	// Move access and modification time back a second
1007	at := Atime(preStat)
1008	mt := preStat.ModTime()
1009	err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second))
1010	if err != nil {
1011		t.Fatalf("Chtimes %s: %s", name, err)
1012	}
1013
1014	st, err = Stat(name)
1015	if err != nil {
1016		t.Fatalf("second Stat %s: %s", name, err)
1017	}
1018	postStat := st
1019
1020	/* Plan 9, NaCl:
1021		Mtime is the time of the last change of content.  Similarly, atime is set whenever the
1022	    contents are accessed; also, it is set whenever mtime is set.
1023	*/
1024	pat := Atime(postStat)
1025	pmt := postStat.ModTime()
1026	if !pat.Before(at) && runtime.GOOS != "plan9" && runtime.GOOS != "nacl" {
1027		t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
1028	}
1029
1030	if !pmt.Before(mt) {
1031		t.Errorf("ModTime didn't go backwards; was=%d, after=%d", mt, pmt)
1032	}
1033}
1034
1035func TestChdirAndGetwd(t *testing.T) {
1036	// TODO(brainman): file.Chdir() is not implemented on windows.
1037	if runtime.GOOS == "windows" {
1038		return
1039	}
1040	fd, err := Open(".")
1041	if err != nil {
1042		t.Fatalf("Open .: %s", err)
1043	}
1044	// These are chosen carefully not to be symlinks on a Mac
1045	// (unlike, say, /var, /etc), except /tmp, which we handle below.
1046	dirs := []string{"/", "/usr/bin", "/tmp"}
1047	// /usr/bin does not usually exist on Plan 9 or Android.
1048	switch runtime.GOOS {
1049	case "android":
1050		dirs = []string{"/", "/system/bin"}
1051	case "plan9":
1052		dirs = []string{"/", "/usr"}
1053	case "darwin":
1054		switch runtime.GOARCH {
1055		case "arm", "arm64":
1056			d1, err := ioutil.TempDir("", "d1")
1057			if err != nil {
1058				t.Fatalf("TempDir: %v", err)
1059			}
1060			d2, err := ioutil.TempDir("", "d2")
1061			if err != nil {
1062				t.Fatalf("TempDir: %v", err)
1063			}
1064			dirs = []string{d1, d2}
1065		}
1066	}
1067	oldwd := Getenv("PWD")
1068	for mode := 0; mode < 2; mode++ {
1069		for _, d := range dirs {
1070			if mode == 0 {
1071				err = Chdir(d)
1072			} else {
1073				fd1, err := Open(d)
1074				if err != nil {
1075					t.Errorf("Open %s: %s", d, err)
1076					continue
1077				}
1078				err = fd1.Chdir()
1079				fd1.Close()
1080			}
1081			if d == "/tmp" {
1082				Setenv("PWD", "/tmp")
1083			}
1084			pwd, err1 := Getwd()
1085			Setenv("PWD", oldwd)
1086			err2 := fd.Chdir()
1087			if err2 != nil {
1088				// We changed the current directory and cannot go back.
1089				// Don't let the tests continue; they'll scribble
1090				// all over some other directory.
1091				fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2)
1092				Exit(1)
1093			}
1094			if err != nil {
1095				fd.Close()
1096				t.Fatalf("Chdir %s: %s", d, err)
1097			}
1098			if err1 != nil {
1099				fd.Close()
1100				t.Fatalf("Getwd in %s: %s", d, err1)
1101			}
1102			if pwd != d {
1103				fd.Close()
1104				t.Fatalf("Getwd returned %q want %q", pwd, d)
1105			}
1106		}
1107	}
1108	fd.Close()
1109}
1110
1111// Test that Chdir+Getwd is program-wide.
1112func TestProgWideChdir(t *testing.T) {
1113	const N = 10
1114	c := make(chan bool)
1115	cpwd := make(chan string)
1116	for i := 0; i < N; i++ {
1117		go func(i int) {
1118			// Lock half the goroutines in their own operating system
1119			// thread to exercise more scheduler possibilities.
1120			if i%2 == 1 {
1121				// On Plan 9, after calling LockOSThread, the goroutines
1122				// run on different processes which don't share the working
1123				// directory. This used to be an issue because Go expects
1124				// the working directory to be program-wide.
1125				// See issue 9428.
1126				runtime.LockOSThread()
1127			}
1128			<-c
1129			pwd, err := Getwd()
1130			if err != nil {
1131				t.Errorf("Getwd on goroutine %d: %v", i, err)
1132				return
1133			}
1134			cpwd <- pwd
1135		}(i)
1136	}
1137	oldwd, err := Getwd()
1138	if err != nil {
1139		t.Fatalf("Getwd: %v", err)
1140	}
1141	d, err := ioutil.TempDir("", "test")
1142	if err != nil {
1143		t.Fatalf("TempDir: %v", err)
1144	}
1145	defer func() {
1146		if err := Chdir(oldwd); err != nil {
1147			t.Fatalf("Chdir: %v", err)
1148		}
1149		RemoveAll(d)
1150	}()
1151	if err := Chdir(d); err != nil {
1152		t.Fatalf("Chdir: %v", err)
1153	}
1154	// OS X sets TMPDIR to a symbolic link.
1155	// So we resolve our working directory again before the test.
1156	d, err = Getwd()
1157	if err != nil {
1158		t.Fatalf("Getwd: %v", err)
1159	}
1160	close(c)
1161	for i := 0; i < N; i++ {
1162		pwd := <-cpwd
1163		if pwd != d {
1164			t.Errorf("Getwd returned %q; want %q", pwd, d)
1165		}
1166	}
1167}
1168
1169func TestSeek(t *testing.T) {
1170	f := newFile("TestSeek", t)
1171	defer Remove(f.Name())
1172	defer f.Close()
1173
1174	const data = "hello, world\n"
1175	io.WriteString(f, data)
1176
1177	type test struct {
1178		in     int64
1179		whence int
1180		out    int64
1181	}
1182	var tests = []test{
1183		{0, 1, int64(len(data))},
1184		{0, 0, 0},
1185		{5, 0, 5},
1186		{0, 2, int64(len(data))},
1187		{0, 0, 0},
1188		{-1, 2, int64(len(data)) - 1},
1189		{1 << 33, 0, 1 << 33},
1190		{1 << 33, 2, 1<<33 + int64(len(data))},
1191	}
1192	for i, tt := range tests {
1193		off, err := f.Seek(tt.in, tt.whence)
1194		if off != tt.out || err != nil {
1195			if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 {
1196				// Reiserfs rejects the big seeks.
1197				// https://golang.org/issue/91
1198				break
1199			}
1200			t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
1201		}
1202	}
1203}
1204
1205type openErrorTest struct {
1206	path  string
1207	mode  int
1208	error error
1209}
1210
1211var openErrorTests = []openErrorTest{
1212	{
1213		sfdir + "/no-such-file",
1214		O_RDONLY,
1215		syscall.ENOENT,
1216	},
1217	{
1218		sfdir,
1219		O_WRONLY,
1220		syscall.EISDIR,
1221	},
1222	{
1223		sfdir + "/" + sfname + "/no-such-file",
1224		O_WRONLY,
1225		syscall.ENOTDIR,
1226	},
1227}
1228
1229func TestOpenError(t *testing.T) {
1230	for _, tt := range openErrorTests {
1231		f, err := OpenFile(tt.path, tt.mode, 0)
1232		if err == nil {
1233			t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
1234			f.Close()
1235			continue
1236		}
1237		perr, ok := err.(*PathError)
1238		if !ok {
1239			t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err)
1240		}
1241		if perr.Err != tt.error {
1242			if runtime.GOOS == "plan9" {
1243				syscallErrStr := perr.Err.Error()
1244				expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1)
1245				if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
1246					// Some Plan 9 file servers incorrectly return
1247					// EACCES rather than EISDIR when a directory is
1248					// opened for write.
1249					if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) {
1250						continue
1251					}
1252					t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
1253				}
1254				continue
1255			}
1256			if runtime.GOOS == "dragonfly" {
1257				// DragonFly incorrectly returns EACCES rather
1258				// EISDIR when a directory is opened for write.
1259				if tt.error == syscall.EISDIR && perr.Err == syscall.EACCES {
1260					continue
1261				}
1262			}
1263			t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error())
1264		}
1265	}
1266}
1267
1268func TestOpenNoName(t *testing.T) {
1269	f, err := Open("")
1270	if err == nil {
1271		t.Fatal(`Open("") succeeded`)
1272		f.Close()
1273	}
1274}
1275
1276func run(t *testing.T, cmd []string) string {
1277	// Run /bin/hostname and collect output.
1278	r, w, err := Pipe()
1279	if err != nil {
1280		t.Fatal(err)
1281	}
1282	defer r.Close()
1283	p, err := StartProcess("/bin/hostname", []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
1284	if err != nil {
1285		t.Fatal(err)
1286	}
1287	w.Close()
1288
1289	var b bytes.Buffer
1290	io.Copy(&b, r)
1291	_, err = p.Wait()
1292	if err != nil {
1293		t.Fatalf("run hostname Wait: %v", err)
1294	}
1295	err = p.Kill()
1296	if err == nil {
1297		t.Errorf("expected an error from Kill running 'hostname'")
1298	}
1299	output := b.String()
1300	if n := len(output); n > 0 && output[n-1] == '\n' {
1301		output = output[0 : n-1]
1302	}
1303	if output == "" {
1304		t.Fatalf("%v produced no output", cmd)
1305	}
1306
1307	return output
1308}
1309
1310func testWindowsHostname(t *testing.T) {
1311	hostname, err := Hostname()
1312	if err != nil {
1313		t.Fatal(err)
1314	}
1315	cmd := osexec.Command("hostname")
1316	out, err := cmd.CombinedOutput()
1317	if err != nil {
1318		t.Fatalf("Failed to execute hostname command: %v %s", err, out)
1319	}
1320	want := strings.Trim(string(out), "\r\n")
1321	if hostname != want {
1322		t.Fatalf("Hostname() = %q, want %q", hostname, want)
1323	}
1324}
1325
1326func TestHostname(t *testing.T) {
1327	// There is no other way to fetch hostname on windows, but via winapi.
1328	// On Plan 9 it can be taken from #c/sysname as Hostname() does.
1329	switch runtime.GOOS {
1330	case "android", "plan9":
1331		t.Skipf("%s doesn't have /bin/hostname", runtime.GOOS)
1332	case "windows":
1333		testWindowsHostname(t)
1334		return
1335	}
1336
1337	testenv.MustHaveExec(t)
1338
1339	// Check internal Hostname() against the output of /bin/hostname.
1340	// Allow that the internal Hostname returns a Fully Qualified Domain Name
1341	// and the /bin/hostname only returns the first component
1342	hostname, err := Hostname()
1343	if err != nil {
1344		t.Fatalf("%v", err)
1345	}
1346	want := run(t, []string{"/bin/hostname"})
1347	if hostname != want {
1348		i := strings.Index(hostname, ".")
1349		if i < 0 || hostname[0:i] != want {
1350			t.Errorf("Hostname() = %q, want %q", hostname, want)
1351		}
1352	}
1353}
1354
1355func TestReadAt(t *testing.T) {
1356	f := newFile("TestReadAt", t)
1357	defer Remove(f.Name())
1358	defer f.Close()
1359
1360	const data = "hello, world\n"
1361	io.WriteString(f, data)
1362
1363	b := make([]byte, 5)
1364	n, err := f.ReadAt(b, 7)
1365	if err != nil || n != len(b) {
1366		t.Fatalf("ReadAt 7: %d, %v", n, err)
1367	}
1368	if string(b) != "world" {
1369		t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
1370	}
1371}
1372
1373func TestWriteAt(t *testing.T) {
1374	f := newFile("TestWriteAt", t)
1375	defer Remove(f.Name())
1376	defer f.Close()
1377
1378	const data = "hello, world\n"
1379	io.WriteString(f, data)
1380
1381	n, err := f.WriteAt([]byte("WORLD"), 7)
1382	if err != nil || n != 5 {
1383		t.Fatalf("WriteAt 7: %d, %v", n, err)
1384	}
1385
1386	b, err := ioutil.ReadFile(f.Name())
1387	if err != nil {
1388		t.Fatalf("ReadFile %s: %v", f.Name(), err)
1389	}
1390	if string(b) != "hello, WORLD\n" {
1391		t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
1392	}
1393}
1394
1395func writeFile(t *testing.T, fname string, flag int, text string) string {
1396	f, err := OpenFile(fname, flag, 0666)
1397	if err != nil {
1398		t.Fatalf("Open: %v", err)
1399	}
1400	n, err := io.WriteString(f, text)
1401	if err != nil {
1402		t.Fatalf("WriteString: %d, %v", n, err)
1403	}
1404	f.Close()
1405	data, err := ioutil.ReadFile(fname)
1406	if err != nil {
1407		t.Fatalf("ReadFile: %v", err)
1408	}
1409	return string(data)
1410}
1411
1412func TestAppend(t *testing.T) {
1413	defer chtmpdir(t)()
1414	const f = "append.txt"
1415	defer Remove(f)
1416	s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
1417	if s != "new" {
1418		t.Fatalf("writeFile: have %q want %q", s, "new")
1419	}
1420	s = writeFile(t, f, O_APPEND|O_RDWR, "|append")
1421	if s != "new|append" {
1422		t.Fatalf("writeFile: have %q want %q", s, "new|append")
1423	}
1424	s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append")
1425	if s != "new|append|append" {
1426		t.Fatalf("writeFile: have %q want %q", s, "new|append|append")
1427	}
1428	err := Remove(f)
1429	if err != nil {
1430		t.Fatalf("Remove: %v", err)
1431	}
1432	s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append")
1433	if s != "new&append" {
1434		t.Fatalf("writeFile: after append have %q want %q", s, "new&append")
1435	}
1436	s = writeFile(t, f, O_CREATE|O_RDWR, "old")
1437	if s != "old&append" {
1438		t.Fatalf("writeFile: after create have %q want %q", s, "old&append")
1439	}
1440	s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
1441	if s != "new" {
1442		t.Fatalf("writeFile: after truncate have %q want %q", s, "new")
1443	}
1444}
1445
1446func TestStatDirWithTrailingSlash(t *testing.T) {
1447	// Create new temporary directory and arrange to clean it up.
1448	path, err := ioutil.TempDir("", "/_TestStatDirWithSlash_")
1449	if err != nil {
1450		t.Fatalf("TempDir: %s", err)
1451	}
1452	defer RemoveAll(path)
1453
1454	// Stat of path should succeed.
1455	_, err = Stat(path)
1456	if err != nil {
1457		t.Fatalf("stat %s failed: %s", path, err)
1458	}
1459
1460	// Stat of path+"/" should succeed too.
1461	path += "/"
1462	_, err = Stat(path)
1463	if err != nil {
1464		t.Fatalf("stat %s failed: %s", path, err)
1465	}
1466}
1467
1468func TestNilProcessStateString(t *testing.T) {
1469	var ps *ProcessState
1470	s := ps.String()
1471	if s != "<nil>" {
1472		t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>")
1473	}
1474}
1475
1476func TestSameFile(t *testing.T) {
1477	defer chtmpdir(t)()
1478	fa, err := Create("a")
1479	if err != nil {
1480		t.Fatalf("Create(a): %v", err)
1481	}
1482	defer Remove(fa.Name())
1483	fa.Close()
1484	fb, err := Create("b")
1485	if err != nil {
1486		t.Fatalf("Create(b): %v", err)
1487	}
1488	defer Remove(fb.Name())
1489	fb.Close()
1490
1491	ia1, err := Stat("a")
1492	if err != nil {
1493		t.Fatalf("Stat(a): %v", err)
1494	}
1495	ia2, err := Stat("a")
1496	if err != nil {
1497		t.Fatalf("Stat(a): %v", err)
1498	}
1499	if !SameFile(ia1, ia2) {
1500		t.Errorf("files should be same")
1501	}
1502
1503	ib, err := Stat("b")
1504	if err != nil {
1505		t.Fatalf("Stat(b): %v", err)
1506	}
1507	if SameFile(ia1, ib) {
1508		t.Errorf("files should be different")
1509	}
1510}
1511
1512func TestDevNullFile(t *testing.T) {
1513	f, err := Open(DevNull)
1514	if err != nil {
1515		t.Fatalf("Open(%s): %v", DevNull, err)
1516	}
1517	defer f.Close()
1518	fi, err := f.Stat()
1519	if err != nil {
1520		t.Fatalf("Stat(%s): %v", DevNull, err)
1521	}
1522	name := filepath.Base(DevNull)
1523	if fi.Name() != name {
1524		t.Fatalf("wrong file name have %v want %v", fi.Name(), name)
1525	}
1526	if fi.Size() != 0 {
1527		t.Fatalf("wrong file size have %d want 0", fi.Size())
1528	}
1529}
1530
1531var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output")
1532
1533func TestLargeWriteToConsole(t *testing.T) {
1534	if !*testLargeWrite {
1535		t.Skip("skipping console-flooding test; enable with -large_write")
1536	}
1537	b := make([]byte, 32000)
1538	for i := range b {
1539		b[i] = '.'
1540	}
1541	b[len(b)-1] = '\n'
1542	n, err := Stdout.Write(b)
1543	if err != nil {
1544		t.Fatalf("Write to os.Stdout failed: %v", err)
1545	}
1546	if n != len(b) {
1547		t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n)
1548	}
1549	n, err = Stderr.Write(b)
1550	if err != nil {
1551		t.Fatalf("Write to os.Stderr failed: %v", err)
1552	}
1553	if n != len(b) {
1554		t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n)
1555	}
1556}
1557
1558func TestStatDirModeExec(t *testing.T) {
1559	const mode = 0111
1560
1561	path, err := ioutil.TempDir("", "go-build")
1562	if err != nil {
1563		t.Fatalf("Failed to create temp directory: %v", err)
1564	}
1565	defer RemoveAll(path)
1566
1567	if err := Chmod(path, 0777); err != nil {
1568		t.Fatalf("Chmod %q 0777: %v", path, err)
1569	}
1570
1571	dir, err := Stat(path)
1572	if err != nil {
1573		t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
1574	}
1575	if dir.Mode()&mode != mode {
1576		t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode)
1577	}
1578}
1579
1580func TestReadAtEOF(t *testing.T) {
1581	f := newFile("TestReadAtEOF", t)
1582	defer Remove(f.Name())
1583	defer f.Close()
1584
1585	_, err := f.ReadAt(make([]byte, 10), 0)
1586	switch err {
1587	case io.EOF:
1588		// all good
1589	case nil:
1590		t.Fatalf("ReadAt succeeded")
1591	default:
1592		t.Fatalf("ReadAt failed: %s", err)
1593	}
1594}
1595
1596func testKillProcess(t *testing.T, processKiller func(p *Process)) {
1597	testenv.MustHaveExec(t)
1598
1599	// Re-exec the test binary itself to emulate "sleep 1".
1600	cmd := osexec.Command(Args[0], "-test.run", "TestSleep")
1601	err := cmd.Start()
1602	if err != nil {
1603		t.Fatalf("Failed to start test process: %v", err)
1604	}
1605	go func() {
1606		time.Sleep(100 * time.Millisecond)
1607		processKiller(cmd.Process)
1608	}()
1609	err = cmd.Wait()
1610	if err == nil {
1611		t.Errorf("Test process succeeded, but expected to fail")
1612	}
1613}
1614
1615// TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we
1616// don't have to rely on an external "sleep" command being available.
1617func TestSleep(t *testing.T) {
1618	if testing.Short() {
1619		t.Skip("Skipping in short mode")
1620	}
1621	time.Sleep(time.Second)
1622}
1623
1624func TestKillStartProcess(t *testing.T) {
1625	testKillProcess(t, func(p *Process) {
1626		err := p.Kill()
1627		if err != nil {
1628			t.Fatalf("Failed to kill test process: %v", err)
1629		}
1630	})
1631}
1632
1633func TestGetppid(t *testing.T) {
1634	if runtime.GOOS == "plan9" {
1635		// TODO: golang.org/issue/8206
1636		t.Skipf("skipping test on plan9; see issue 8206")
1637	}
1638
1639	testenv.MustHaveExec(t)
1640
1641	if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
1642		fmt.Print(Getppid())
1643		Exit(0)
1644	}
1645
1646	cmd := osexec.Command(Args[0], "-test.run=TestGetppid")
1647	cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
1648
1649	// verify that Getppid() from the forked process reports our process id
1650	output, err := cmd.CombinedOutput()
1651	if err != nil {
1652		t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
1653	}
1654
1655	childPpid := string(output)
1656	ourPid := fmt.Sprintf("%d", Getpid())
1657	if childPpid != ourPid {
1658		t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid)
1659	}
1660}
1661
1662func TestKillFindProcess(t *testing.T) {
1663	testKillProcess(t, func(p *Process) {
1664		p2, err := FindProcess(p.Pid)
1665		if err != nil {
1666			t.Fatalf("Failed to find test process: %v", err)
1667		}
1668		err = p2.Kill()
1669		if err != nil {
1670			t.Fatalf("Failed to kill test process: %v", err)
1671		}
1672	})
1673}
1674
1675var nilFileMethodTests = []struct {
1676	name string
1677	f    func(*File) error
1678}{
1679	{"Chdir", func(f *File) error { return f.Chdir() }},
1680	{"Close", func(f *File) error { return f.Close() }},
1681	{"Chmod", func(f *File) error { return f.Chmod(0) }},
1682	{"Chown", func(f *File) error { return f.Chown(0, 0) }},
1683	{"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }},
1684	{"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
1685	{"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
1686	{"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
1687	{"Seek", func(f *File) error { _, err := f.Seek(0, 0); return err }},
1688	{"Stat", func(f *File) error { _, err := f.Stat(); return err }},
1689	{"Sync", func(f *File) error { return f.Sync() }},
1690	{"Truncate", func(f *File) error { return f.Truncate(0) }},
1691	{"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }},
1692	{"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }},
1693	{"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }},
1694}
1695
1696// Test that all File methods give ErrInvalid if the receiver is nil.
1697func TestNilFileMethods(t *testing.T) {
1698	for _, tt := range nilFileMethodTests {
1699		var file *File
1700		got := tt.f(file)
1701		if got != ErrInvalid {
1702			t.Errorf("%v should fail when f is nil; got %v", tt.name, got)
1703		}
1704	}
1705}
1706
1707func mkdirTree(t *testing.T, root string, level, max int) {
1708	if level >= max {
1709		return
1710	}
1711	level++
1712	for i := 'a'; i < 'c'; i++ {
1713		dir := filepath.Join(root, string(i))
1714		if err := Mkdir(dir, 0700); err != nil {
1715			t.Fatal(err)
1716		}
1717		mkdirTree(t, dir, level, max)
1718	}
1719}
1720
1721// Test that simultaneous RemoveAll do not report an error.
1722// As long as it gets removed, we should be happy.
1723func TestRemoveAllRace(t *testing.T) {
1724	if runtime.GOOS == "windows" {
1725		// Windows has very strict rules about things like
1726		// removing directories while someone else has
1727		// them open. The racing doesn't work out nicely
1728		// like it does on Unix.
1729		t.Skip("skipping on windows")
1730	}
1731
1732	n := runtime.GOMAXPROCS(16)
1733	defer runtime.GOMAXPROCS(n)
1734	root, err := ioutil.TempDir("", "issue")
1735	if err != nil {
1736		t.Fatal(err)
1737	}
1738	mkdirTree(t, root, 1, 6)
1739	hold := make(chan struct{})
1740	var wg sync.WaitGroup
1741	for i := 0; i < 4; i++ {
1742		wg.Add(1)
1743		go func() {
1744			defer wg.Done()
1745			<-hold
1746			err := RemoveAll(root)
1747			if err != nil {
1748				t.Errorf("unexpected error: %T, %q", err, err)
1749			}
1750		}()
1751	}
1752	close(hold) // let workers race to remove root
1753	wg.Wait()
1754}
1755