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