Source file
src/os/os_test.go
1
2
3
4
5 package os_test
6
7 import (
8 "bytes"
9 "errors"
10 "flag"
11 "fmt"
12 "internal/testenv"
13 "io"
14 "io/fs"
15 "log"
16 . "os"
17 "os/exec"
18 "path/filepath"
19 "reflect"
20 "runtime"
21 "runtime/debug"
22 "slices"
23 "strings"
24 "sync"
25 "syscall"
26 "testing"
27 "testing/fstest"
28 "time"
29 )
30
31 func TestMain(m *testing.M) {
32 if Getenv("GO_OS_TEST_DRAIN_STDIN") == "1" {
33 Stdout.Close()
34 io.Copy(io.Discard, Stdin)
35 Exit(0)
36 }
37
38 log.SetFlags(log.LstdFlags | log.Lshortfile)
39
40 Exit(m.Run())
41 }
42
43 var dot = []string{
44 "dir_unix.go",
45 "env.go",
46 "error.go",
47 "file.go",
48 "os_test.go",
49 "types.go",
50 "stat_darwin.go",
51 "stat_linux.go",
52 }
53
54 type sysDir struct {
55 name string
56 files []string
57 }
58
59 var sysdir = func() *sysDir {
60 switch runtime.GOOS {
61 case "android":
62 return &sysDir{
63 "/system/lib",
64 []string{
65 "libmedia.so",
66 "libpowermanager.so",
67 },
68 }
69 case "ios":
70 wd, err := syscall.Getwd()
71 if err != nil {
72 wd = err.Error()
73 }
74 sd := &sysDir{
75 filepath.Join(wd, "..", ".."),
76 []string{
77 "ResourceRules.plist",
78 "Info.plist",
79 },
80 }
81 found := true
82 for _, f := range sd.files {
83 path := filepath.Join(sd.name, f)
84 if _, err := Stat(path); err != nil {
85 found = false
86 break
87 }
88 }
89 if found {
90 return sd
91 }
92
93
94 case "windows":
95 return &sysDir{
96 Getenv("SystemRoot") + "\\system32\\drivers\\etc",
97 []string{
98 "networks",
99 "protocol",
100 "services",
101 },
102 }
103 case "plan9":
104 return &sysDir{
105 "/lib/ndb",
106 []string{
107 "common",
108 "local",
109 },
110 }
111 case "wasip1":
112
113
114
115 return &sysDir{
116 runtime.GOROOT(),
117 []string{
118 "go.env",
119 "LICENSE",
120 "CONTRIBUTING.md",
121 },
122 }
123 }
124 return &sysDir{
125 "/etc",
126 []string{
127 "group",
128 "hosts",
129 "passwd",
130 },
131 }
132 }()
133
134 func size(name string, t *testing.T) int64 {
135 file, err := Open(name)
136 if err != nil {
137 t.Fatal("open failed:", err)
138 }
139 defer func() {
140 if err := file.Close(); err != nil {
141 t.Error(err)
142 }
143 }()
144 n, err := io.Copy(io.Discard, file)
145 if err != nil {
146 t.Fatal(err)
147 }
148 return n
149 }
150
151 func equal(name1, name2 string) (r bool) {
152 switch runtime.GOOS {
153 case "windows":
154 r = strings.EqualFold(name1, name2)
155 default:
156 r = name1 == name2
157 }
158 return
159 }
160
161 func newFile(t *testing.T) (f *File) {
162 t.Helper()
163 f, err := CreateTemp("", "_Go_"+t.Name())
164 if err != nil {
165 t.Fatal(err)
166 }
167 t.Cleanup(func() {
168 if err := f.Close(); err != nil && !errors.Is(err, ErrClosed) {
169 t.Fatal(err)
170 }
171 if err := Remove(f.Name()); err != nil {
172 t.Fatal(err)
173 }
174 })
175 return
176 }
177
178 var sfdir = sysdir.name
179 var sfname = sysdir.files[0]
180
181 func TestStat(t *testing.T) {
182 t.Parallel()
183
184 path := sfdir + "/" + sfname
185 dir, err := Stat(path)
186 if err != nil {
187 t.Fatal("stat failed:", err)
188 }
189 if !equal(sfname, dir.Name()) {
190 t.Error("name should be ", sfname, "; is", dir.Name())
191 }
192 filesize := size(path, t)
193 if dir.Size() != filesize {
194 t.Error("size should be", filesize, "; is", dir.Size())
195 }
196 }
197
198 func TestStatError(t *testing.T) {
199 defer chtmpdir(t)()
200
201 path := "no-such-file"
202
203 fi, err := Stat(path)
204 if err == nil {
205 t.Fatal("got nil, want error")
206 }
207 if fi != nil {
208 t.Errorf("got %v, want nil", fi)
209 }
210 if perr, ok := err.(*PathError); !ok {
211 t.Errorf("got %T, want %T", err, perr)
212 }
213
214 testenv.MustHaveSymlink(t)
215
216 link := "symlink"
217 err = Symlink(path, link)
218 if err != nil {
219 t.Fatal(err)
220 }
221
222 fi, err = Stat(link)
223 if err == nil {
224 t.Fatal("got nil, want error")
225 }
226 if fi != nil {
227 t.Errorf("got %v, want nil", fi)
228 }
229 if perr, ok := err.(*PathError); !ok {
230 t.Errorf("got %T, want %T", err, perr)
231 }
232 }
233
234 func TestStatSymlinkLoop(t *testing.T) {
235 testenv.MustHaveSymlink(t)
236
237 defer chtmpdir(t)()
238
239 err := Symlink("x", "y")
240 if err != nil {
241 t.Fatal(err)
242 }
243 defer Remove("y")
244
245 err = Symlink("y", "x")
246 if err != nil {
247 t.Fatal(err)
248 }
249 defer Remove("x")
250
251 _, err = Stat("x")
252 if _, ok := err.(*fs.PathError); !ok {
253 t.Errorf("expected *PathError, got %T: %v\n", err, err)
254 }
255 }
256
257 func TestFstat(t *testing.T) {
258 t.Parallel()
259
260 path := sfdir + "/" + sfname
261 file, err1 := Open(path)
262 if err1 != nil {
263 t.Fatal("open failed:", err1)
264 }
265 defer file.Close()
266 dir, err2 := file.Stat()
267 if err2 != nil {
268 t.Fatal("fstat failed:", err2)
269 }
270 if !equal(sfname, dir.Name()) {
271 t.Error("name should be ", sfname, "; is", dir.Name())
272 }
273 filesize := size(path, t)
274 if dir.Size() != filesize {
275 t.Error("size should be", filesize, "; is", dir.Size())
276 }
277 }
278
279 func TestLstat(t *testing.T) {
280 t.Parallel()
281
282 path := sfdir + "/" + sfname
283 dir, err := Lstat(path)
284 if err != nil {
285 t.Fatal("lstat failed:", err)
286 }
287 if !equal(sfname, dir.Name()) {
288 t.Error("name should be ", sfname, "; is", dir.Name())
289 }
290 if dir.Mode()&ModeSymlink == 0 {
291 filesize := size(path, t)
292 if dir.Size() != filesize {
293 t.Error("size should be", filesize, "; is", dir.Size())
294 }
295 }
296 }
297
298
299 func TestRead0(t *testing.T) {
300 t.Parallel()
301
302 path := sfdir + "/" + sfname
303 f, err := Open(path)
304 if err != nil {
305 t.Fatal("open failed:", err)
306 }
307 defer f.Close()
308
309 b := make([]byte, 0)
310 n, err := f.Read(b)
311 if n != 0 || err != nil {
312 t.Errorf("Read(0) = %d, %v, want 0, nil", n, err)
313 }
314 b = make([]byte, 100)
315 n, err = f.Read(b)
316 if n <= 0 || err != nil {
317 t.Errorf("Read(100) = %d, %v, want >0, nil", n, err)
318 }
319 }
320
321
322 func TestReadClosed(t *testing.T) {
323 t.Parallel()
324
325 path := sfdir + "/" + sfname
326 file, err := Open(path)
327 if err != nil {
328 t.Fatal("open failed:", err)
329 }
330 file.Close()
331
332 b := make([]byte, 100)
333 _, err = file.Read(b)
334
335 e, ok := err.(*PathError)
336 if !ok || e.Err != ErrClosed {
337 t.Fatalf("Read: got %T(%v), want %T(%v)", err, err, e, ErrClosed)
338 }
339 }
340
341 func testReaddirnames(dir string, contents []string) func(*testing.T) {
342 return func(t *testing.T) {
343 t.Parallel()
344
345 file, err := Open(dir)
346 if err != nil {
347 t.Fatalf("open %q failed: %v", dir, err)
348 }
349 defer file.Close()
350 s, err2 := file.Readdirnames(-1)
351 if err2 != nil {
352 t.Fatalf("Readdirnames %q failed: %v", dir, err2)
353 }
354 for _, m := range contents {
355 found := false
356 for _, n := range s {
357 if n == "." || n == ".." {
358 t.Errorf("got %q in directory", n)
359 }
360 if !equal(m, n) {
361 continue
362 }
363 if found {
364 t.Error("present twice:", m)
365 }
366 found = true
367 }
368 if !found {
369 t.Error("could not find", m)
370 }
371 }
372 if s == nil {
373 t.Error("Readdirnames returned nil instead of empty slice")
374 }
375 }
376 }
377
378 func testReaddir(dir string, contents []string) func(*testing.T) {
379 return func(t *testing.T) {
380 t.Parallel()
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 s, err2 := file.Readdir(-1)
388 if err2 != nil {
389 t.Fatalf("Readdir %q failed: %v", dir, err2)
390 }
391 for _, m := range contents {
392 found := false
393 for _, n := range s {
394 if n.Name() == "." || n.Name() == ".." {
395 t.Errorf("got %q in directory", n.Name())
396 }
397 if !equal(m, n.Name()) {
398 continue
399 }
400 if found {
401 t.Error("present twice:", m)
402 }
403 found = true
404 }
405 if !found {
406 t.Error("could not find", m)
407 }
408 }
409 if s == nil {
410 t.Error("Readdir returned nil instead of empty slice")
411 }
412 }
413 }
414
415 func testReadDir(dir string, contents []string) func(*testing.T) {
416 return func(t *testing.T) {
417 t.Parallel()
418
419 file, err := Open(dir)
420 if err != nil {
421 t.Fatalf("open %q failed: %v", dir, err)
422 }
423 defer file.Close()
424 s, err2 := file.ReadDir(-1)
425 if err2 != nil {
426 t.Fatalf("ReadDir %q failed: %v", dir, err2)
427 }
428 for _, m := range contents {
429 found := false
430 for _, n := range s {
431 if n.Name() == "." || n.Name() == ".." {
432 t.Errorf("got %q in directory", n)
433 }
434 if !equal(m, n.Name()) {
435 continue
436 }
437 if found {
438 t.Error("present twice:", m)
439 }
440 found = true
441 lstat, err := Lstat(dir + "/" + m)
442 if err != nil {
443 t.Fatal(err)
444 }
445 if n.IsDir() != lstat.IsDir() {
446 t.Errorf("%s: IsDir=%v, want %v", m, n.IsDir(), lstat.IsDir())
447 }
448 if n.Type() != lstat.Mode().Type() {
449 t.Errorf("%s: IsDir=%v, want %v", m, n.Type(), lstat.Mode().Type())
450 }
451 info, err := n.Info()
452 if err != nil {
453 t.Errorf("%s: Info: %v", m, err)
454 continue
455 }
456 if !SameFile(info, lstat) {
457 t.Errorf("%s: Info: SameFile(info, lstat) = false", m)
458 }
459 }
460 if !found {
461 t.Error("could not find", m)
462 }
463 }
464 if s == nil {
465 t.Error("ReadDir returned nil instead of empty slice")
466 }
467 }
468 }
469
470 func TestFileReaddirnames(t *testing.T) {
471 t.Parallel()
472
473 t.Run(".", testReaddirnames(".", dot))
474 t.Run("sysdir", testReaddirnames(sysdir.name, sysdir.files))
475 t.Run("TempDir", testReaddirnames(t.TempDir(), nil))
476 }
477
478 func TestFileReaddir(t *testing.T) {
479 t.Parallel()
480
481 t.Run(".", testReaddir(".", dot))
482 t.Run("sysdir", testReaddir(sysdir.name, sysdir.files))
483 t.Run("TempDir", testReaddir(t.TempDir(), nil))
484 }
485
486 func TestFileReadDir(t *testing.T) {
487 t.Parallel()
488
489 t.Run(".", testReadDir(".", dot))
490 t.Run("sysdir", testReadDir(sysdir.name, sysdir.files))
491 t.Run("TempDir", testReadDir(t.TempDir(), nil))
492 }
493
494 func benchmarkReaddirname(path string, b *testing.B) {
495 var nentries int
496 for i := 0; i < b.N; i++ {
497 f, err := Open(path)
498 if err != nil {
499 b.Fatalf("open %q failed: %v", path, err)
500 }
501 ns, err := f.Readdirnames(-1)
502 f.Close()
503 if err != nil {
504 b.Fatalf("readdirnames %q failed: %v", path, err)
505 }
506 nentries = len(ns)
507 }
508 b.Logf("benchmarkReaddirname %q: %d entries", path, nentries)
509 }
510
511 func benchmarkReaddir(path string, b *testing.B) {
512 var nentries int
513 for i := 0; i < b.N; i++ {
514 f, err := Open(path)
515 if err != nil {
516 b.Fatalf("open %q failed: %v", path, err)
517 }
518 fs, err := f.Readdir(-1)
519 f.Close()
520 if err != nil {
521 b.Fatalf("readdir %q failed: %v", path, err)
522 }
523 nentries = len(fs)
524 }
525 b.Logf("benchmarkReaddir %q: %d entries", path, nentries)
526 }
527
528 func benchmarkReadDir(path string, b *testing.B) {
529 var nentries int
530 for i := 0; i < b.N; i++ {
531 f, err := Open(path)
532 if err != nil {
533 b.Fatalf("open %q failed: %v", path, err)
534 }
535 fs, err := f.ReadDir(-1)
536 f.Close()
537 if err != nil {
538 b.Fatalf("readdir %q failed: %v", path, err)
539 }
540 nentries = len(fs)
541 }
542 b.Logf("benchmarkReadDir %q: %d entries", path, nentries)
543 }
544
545 func BenchmarkReaddirname(b *testing.B) {
546 benchmarkReaddirname(".", b)
547 }
548
549 func BenchmarkReaddir(b *testing.B) {
550 benchmarkReaddir(".", b)
551 }
552
553 func BenchmarkReadDir(b *testing.B) {
554 benchmarkReadDir(".", b)
555 }
556
557 func benchmarkStat(b *testing.B, path string) {
558 b.ResetTimer()
559 for i := 0; i < b.N; i++ {
560 _, err := Stat(path)
561 if err != nil {
562 b.Fatalf("Stat(%q) failed: %v", path, err)
563 }
564 }
565 }
566
567 func benchmarkLstat(b *testing.B, path string) {
568 b.ResetTimer()
569 for i := 0; i < b.N; i++ {
570 _, err := Lstat(path)
571 if err != nil {
572 b.Fatalf("Lstat(%q) failed: %v", path, err)
573 }
574 }
575 }
576
577 func BenchmarkStatDot(b *testing.B) {
578 benchmarkStat(b, ".")
579 }
580
581 func BenchmarkStatFile(b *testing.B) {
582 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
583 }
584
585 func BenchmarkStatDir(b *testing.B) {
586 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os"))
587 }
588
589 func BenchmarkLstatDot(b *testing.B) {
590 benchmarkLstat(b, ".")
591 }
592
593 func BenchmarkLstatFile(b *testing.B) {
594 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
595 }
596
597 func BenchmarkLstatDir(b *testing.B) {
598 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os"))
599 }
600
601
602 func smallReaddirnames(file *File, length int, t *testing.T) []string {
603 names := make([]string, length)
604 count := 0
605 for {
606 d, err := file.Readdirnames(1)
607 if err == io.EOF {
608 break
609 }
610 if err != nil {
611 t.Fatalf("readdirnames %q failed: %v", file.Name(), err)
612 }
613 if len(d) == 0 {
614 t.Fatalf("readdirnames %q returned empty slice and no error", file.Name())
615 }
616 names[count] = d[0]
617 count++
618 }
619 return names[0:count]
620 }
621
622
623
624 func TestReaddirnamesOneAtATime(t *testing.T) {
625 t.Parallel()
626
627
628 dir := "/usr/bin"
629 switch runtime.GOOS {
630 case "android":
631 dir = "/system/bin"
632 case "ios", "wasip1":
633 wd, err := Getwd()
634 if err != nil {
635 t.Fatal(err)
636 }
637 dir = wd
638 case "plan9":
639 dir = "/bin"
640 case "windows":
641 dir = Getenv("SystemRoot") + "\\system32"
642 }
643 file, err := Open(dir)
644 if err != nil {
645 t.Fatalf("open %q failed: %v", dir, err)
646 }
647 defer file.Close()
648 all, err1 := file.Readdirnames(-1)
649 if err1 != nil {
650 t.Fatalf("readdirnames %q failed: %v", dir, err1)
651 }
652 file1, err2 := Open(dir)
653 if err2 != nil {
654 t.Fatalf("open %q failed: %v", dir, err2)
655 }
656 defer file1.Close()
657 small := smallReaddirnames(file1, len(all)+100, t)
658 if len(small) < len(all) {
659 t.Fatalf("len(small) is %d, less than %d", len(small), len(all))
660 }
661 for i, n := range all {
662 if small[i] != n {
663 t.Errorf("small read %q mismatch: %v", small[i], n)
664 }
665 }
666 }
667
668 func TestReaddirNValues(t *testing.T) {
669 if testing.Short() {
670 t.Skip("test.short; skipping")
671 }
672 t.Parallel()
673
674 dir := t.TempDir()
675 for i := 1; i <= 105; i++ {
676 f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i)))
677 if err != nil {
678 t.Fatalf("Create: %v", err)
679 }
680 f.Write([]byte(strings.Repeat("X", i)))
681 f.Close()
682 }
683
684 var d *File
685 openDir := func() {
686 var err error
687 d, err = Open(dir)
688 if err != nil {
689 t.Fatalf("Open directory: %v", err)
690 }
691 }
692
693 readdirExpect := func(n, want int, wantErr error) {
694 t.Helper()
695 fi, err := d.Readdir(n)
696 if err != wantErr {
697 t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr)
698 }
699 if g, e := len(fi), want; g != e {
700 t.Errorf("Readdir of %d got %d files, want %d", n, g, e)
701 }
702 }
703
704 readDirExpect := func(n, want int, wantErr error) {
705 t.Helper()
706 de, err := d.ReadDir(n)
707 if err != wantErr {
708 t.Fatalf("ReadDir of %d got error %v, want %v", n, err, wantErr)
709 }
710 if g, e := len(de), want; g != e {
711 t.Errorf("ReadDir of %d got %d files, want %d", n, g, e)
712 }
713 }
714
715 readdirnamesExpect := func(n, want int, wantErr error) {
716 t.Helper()
717 fi, err := d.Readdirnames(n)
718 if err != wantErr {
719 t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr)
720 }
721 if g, e := len(fi), want; g != e {
722 t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e)
723 }
724 }
725
726 for _, fn := range []func(int, int, error){readdirExpect, readdirnamesExpect, readDirExpect} {
727
728 openDir()
729 fn(0, 105, nil)
730 fn(0, 0, nil)
731 d.Close()
732
733
734 openDir()
735 fn(-1, 105, nil)
736 fn(-2, 0, nil)
737 fn(0, 0, nil)
738 d.Close()
739
740
741 openDir()
742 fn(1, 1, nil)
743 fn(2, 2, nil)
744 fn(105, 102, nil)
745 fn(3, 0, io.EOF)
746 d.Close()
747 }
748 }
749
750 func touch(t *testing.T, name string) {
751 f, err := Create(name)
752 if err != nil {
753 t.Fatal(err)
754 }
755 if err := f.Close(); err != nil {
756 t.Fatal(err)
757 }
758 }
759
760 func TestReaddirStatFailures(t *testing.T) {
761 switch runtime.GOOS {
762 case "windows", "plan9":
763
764
765
766
767 t.Skipf("skipping test on %v", runtime.GOOS)
768 }
769
770 var xerr error
771 *LstatP = func(path string) (FileInfo, error) {
772 if xerr != nil && strings.HasSuffix(path, "x") {
773 return nil, xerr
774 }
775 return Lstat(path)
776 }
777 defer func() { *LstatP = Lstat }()
778
779 dir := t.TempDir()
780 touch(t, filepath.Join(dir, "good1"))
781 touch(t, filepath.Join(dir, "x"))
782 touch(t, filepath.Join(dir, "good2"))
783 readDir := func() ([]FileInfo, error) {
784 d, err := Open(dir)
785 if err != nil {
786 t.Fatal(err)
787 }
788 defer d.Close()
789 return d.Readdir(-1)
790 }
791 mustReadDir := func(testName string) []FileInfo {
792 fis, err := readDir()
793 if err != nil {
794 t.Fatalf("%s: Readdir: %v", testName, err)
795 }
796 return fis
797 }
798 names := func(fis []FileInfo) []string {
799 s := make([]string, len(fis))
800 for i, fi := range fis {
801 s[i] = fi.Name()
802 }
803 slices.Sort(s)
804 return s
805 }
806
807 if got, want := names(mustReadDir("initial readdir")),
808 []string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) {
809 t.Errorf("initial readdir got %q; want %q", got, want)
810 }
811
812 xerr = ErrNotExist
813 if got, want := names(mustReadDir("with x disappearing")),
814 []string{"good1", "good2"}; !reflect.DeepEqual(got, want) {
815 t.Errorf("with x disappearing, got %q; want %q", got, want)
816 }
817
818 xerr = errors.New("some real error")
819 if _, err := readDir(); err != xerr {
820 t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr)
821 }
822 }
823
824
825 func TestReaddirOfFile(t *testing.T) {
826 t.Parallel()
827
828 f, err := CreateTemp(t.TempDir(), "_Go_ReaddirOfFile")
829 if err != nil {
830 t.Fatal(err)
831 }
832 f.Write([]byte("foo"))
833 f.Close()
834 reg, err := Open(f.Name())
835 if err != nil {
836 t.Fatal(err)
837 }
838 defer reg.Close()
839
840 names, err := reg.Readdirnames(-1)
841 if err == nil {
842 t.Error("Readdirnames succeeded; want non-nil error")
843 }
844 var pe *PathError
845 if !errors.As(err, &pe) || pe.Path != f.Name() {
846 t.Errorf("Readdirnames returned %q; want a PathError with path %q", err, f.Name())
847 }
848 if len(names) > 0 {
849 t.Errorf("unexpected dir names in regular file: %q", names)
850 }
851 }
852
853 func TestHardLink(t *testing.T) {
854 testenv.MustHaveLink(t)
855
856 defer chtmpdir(t)()
857 from, to := "hardlinktestfrom", "hardlinktestto"
858 file, err := Create(to)
859 if err != nil {
860 t.Fatalf("open %q failed: %v", to, err)
861 }
862 if err = file.Close(); err != nil {
863 t.Errorf("close %q failed: %v", to, err)
864 }
865 err = Link(to, from)
866 if err != nil {
867 t.Fatalf("link %q, %q failed: %v", to, from, err)
868 }
869
870 none := "hardlinktestnone"
871 err = Link(none, none)
872
873 if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" {
874 t.Errorf("link %q, %q failed to return a valid error", none, none)
875 }
876
877 tostat, err := Stat(to)
878 if err != nil {
879 t.Fatalf("stat %q failed: %v", to, err)
880 }
881 fromstat, err := Stat(from)
882 if err != nil {
883 t.Fatalf("stat %q failed: %v", from, err)
884 }
885 if !SameFile(tostat, fromstat) {
886 t.Errorf("link %q, %q did not create hard link", to, from)
887 }
888
889 err = Link(to, from)
890 switch err := err.(type) {
891 case *LinkError:
892 if err.Op != "link" {
893 t.Errorf("Link(%q, %q) err.Op = %q; want %q", to, from, err.Op, "link")
894 }
895 if err.Old != to {
896 t.Errorf("Link(%q, %q) err.Old = %q; want %q", to, from, err.Old, to)
897 }
898 if err.New != from {
899 t.Errorf("Link(%q, %q) err.New = %q; want %q", to, from, err.New, from)
900 }
901 if !IsExist(err.Err) {
902 t.Errorf("Link(%q, %q) err.Err = %q; want %q", to, from, err.Err, "file exists error")
903 }
904 case nil:
905 t.Errorf("link %q, %q: expected error, got nil", from, to)
906 default:
907 t.Errorf("link %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
908 }
909 }
910
911
912
913 func chtmpdir(t *testing.T) func() {
914 oldwd, err := Getwd()
915 if err != nil {
916 t.Fatalf("chtmpdir: %v", err)
917 }
918 d, err := MkdirTemp("", "test")
919 if err != nil {
920 t.Fatalf("chtmpdir: %v", err)
921 }
922 if err := Chdir(d); err != nil {
923 t.Fatalf("chtmpdir: %v", err)
924 }
925 return func() {
926 if err := Chdir(oldwd); err != nil {
927 t.Fatalf("chtmpdir: %v", err)
928 }
929 RemoveAll(d)
930 }
931 }
932
933 func TestSymlink(t *testing.T) {
934 testenv.MustHaveSymlink(t)
935
936 defer chtmpdir(t)()
937 from, to := "symlinktestfrom", "symlinktestto"
938 file, err := Create(to)
939 if err != nil {
940 t.Fatalf("Create(%q) failed: %v", to, err)
941 }
942 if err = file.Close(); err != nil {
943 t.Errorf("Close(%q) failed: %v", to, err)
944 }
945 err = Symlink(to, from)
946 if err != nil {
947 t.Fatalf("Symlink(%q, %q) failed: %v", to, from, err)
948 }
949 tostat, err := Lstat(to)
950 if err != nil {
951 t.Fatalf("Lstat(%q) failed: %v", to, err)
952 }
953 if tostat.Mode()&ModeSymlink != 0 {
954 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = %v, want 0", to, tostat.Mode()&ModeSymlink)
955 }
956 fromstat, err := Stat(from)
957 if err != nil {
958 t.Fatalf("Stat(%q) failed: %v", from, err)
959 }
960 if !SameFile(tostat, fromstat) {
961 t.Errorf("Symlink(%q, %q) did not create symlink", to, from)
962 }
963 fromstat, err = Lstat(from)
964 if err != nil {
965 t.Fatalf("Lstat(%q) failed: %v", from, err)
966 }
967 if fromstat.Mode()&ModeSymlink == 0 {
968 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = 0, want %v", from, ModeSymlink)
969 }
970 fromstat, err = Stat(from)
971 if err != nil {
972 t.Fatalf("Stat(%q) failed: %v", from, err)
973 }
974 if fromstat.Name() != from {
975 t.Errorf("Stat(%q).Name() = %q, want %q", from, fromstat.Name(), from)
976 }
977 if fromstat.Mode()&ModeSymlink != 0 {
978 t.Fatalf("Stat(%q).Mode()&ModeSymlink = %v, want 0", from, fromstat.Mode()&ModeSymlink)
979 }
980 s, err := Readlink(from)
981 if err != nil {
982 t.Fatalf("Readlink(%q) failed: %v", from, err)
983 }
984 if s != to {
985 t.Fatalf("Readlink(%q) = %q, want %q", from, s, to)
986 }
987 file, err = Open(from)
988 if err != nil {
989 t.Fatalf("Open(%q) failed: %v", from, err)
990 }
991 file.Close()
992 }
993
994 func TestLongSymlink(t *testing.T) {
995 testenv.MustHaveSymlink(t)
996
997 defer chtmpdir(t)()
998 s := "0123456789abcdef"
999
1000 s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
1001 from := "longsymlinktestfrom"
1002 err := Symlink(s, from)
1003 if err != nil {
1004 t.Fatalf("symlink %q, %q failed: %v", s, from, err)
1005 }
1006 r, err := Readlink(from)
1007 if err != nil {
1008 t.Fatalf("readlink %q failed: %v", from, err)
1009 }
1010 if r != s {
1011 t.Fatalf("after symlink %q != %q", r, s)
1012 }
1013 }
1014
1015 func TestRename(t *testing.T) {
1016 defer chtmpdir(t)()
1017 from, to := "renamefrom", "renameto"
1018
1019 file, err := Create(from)
1020 if err != nil {
1021 t.Fatalf("open %q failed: %v", from, err)
1022 }
1023 if err = file.Close(); err != nil {
1024 t.Errorf("close %q failed: %v", from, err)
1025 }
1026 err = Rename(from, to)
1027 if err != nil {
1028 t.Fatalf("rename %q, %q failed: %v", to, from, err)
1029 }
1030 _, err = Stat(to)
1031 if err != nil {
1032 t.Errorf("stat %q failed: %v", to, err)
1033 }
1034 }
1035
1036 func TestRenameOverwriteDest(t *testing.T) {
1037 defer chtmpdir(t)()
1038 from, to := "renamefrom", "renameto"
1039
1040 toData := []byte("to")
1041 fromData := []byte("from")
1042
1043 err := WriteFile(to, toData, 0777)
1044 if err != nil {
1045 t.Fatalf("write file %q failed: %v", to, err)
1046 }
1047
1048 err = WriteFile(from, fromData, 0777)
1049 if err != nil {
1050 t.Fatalf("write file %q failed: %v", from, err)
1051 }
1052 err = Rename(from, to)
1053 if err != nil {
1054 t.Fatalf("rename %q, %q failed: %v", to, from, err)
1055 }
1056
1057 _, err = Stat(from)
1058 if err == nil {
1059 t.Errorf("from file %q still exists", from)
1060 }
1061 if err != nil && !IsNotExist(err) {
1062 t.Fatalf("stat from: %v", err)
1063 }
1064 toFi, err := Stat(to)
1065 if err != nil {
1066 t.Fatalf("stat %q failed: %v", to, err)
1067 }
1068 if toFi.Size() != int64(len(fromData)) {
1069 t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData))
1070 }
1071 }
1072
1073 func TestRenameFailed(t *testing.T) {
1074 defer chtmpdir(t)()
1075 from, to := "renamefrom", "renameto"
1076
1077 err := Rename(from, to)
1078 switch err := err.(type) {
1079 case *LinkError:
1080 if err.Op != "rename" {
1081 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
1082 }
1083 if err.Old != from {
1084 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
1085 }
1086 if err.New != to {
1087 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
1088 }
1089 case nil:
1090 t.Errorf("rename %q, %q: expected error, got nil", from, to)
1091 default:
1092 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
1093 }
1094 }
1095
1096 func TestRenameNotExisting(t *testing.T) {
1097 defer chtmpdir(t)()
1098 from, to := "doesnt-exist", "dest"
1099
1100 Mkdir(to, 0777)
1101
1102 if err := Rename(from, to); !IsNotExist(err) {
1103 t.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from, to, err)
1104 }
1105 }
1106
1107 func TestRenameToDirFailed(t *testing.T) {
1108 defer chtmpdir(t)()
1109 from, to := "renamefrom", "renameto"
1110
1111 Mkdir(from, 0777)
1112 Mkdir(to, 0777)
1113
1114 err := Rename(from, to)
1115 switch err := err.(type) {
1116 case *LinkError:
1117 if err.Op != "rename" {
1118 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
1119 }
1120 if err.Old != from {
1121 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
1122 }
1123 if err.New != to {
1124 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
1125 }
1126 case nil:
1127 t.Errorf("rename %q, %q: expected error, got nil", from, to)
1128 default:
1129 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
1130 }
1131 }
1132
1133 func TestRenameCaseDifference(pt *testing.T) {
1134 from, to := "renameFROM", "RENAMEfrom"
1135 tests := []struct {
1136 name string
1137 create func() error
1138 }{
1139 {"dir", func() error {
1140 return Mkdir(from, 0777)
1141 }},
1142 {"file", func() error {
1143 fd, err := Create(from)
1144 if err != nil {
1145 return err
1146 }
1147 return fd.Close()
1148 }},
1149 }
1150
1151 for _, test := range tests {
1152 pt.Run(test.name, func(t *testing.T) {
1153 defer chtmpdir(t)()
1154
1155 if err := test.create(); err != nil {
1156 t.Fatalf("failed to create test file: %s", err)
1157 }
1158
1159 if _, err := Stat(to); err != nil {
1160
1161 if IsNotExist(err) {
1162 t.Skipf("case sensitive filesystem")
1163 }
1164 t.Fatalf("stat %q, got: %q", to, err)
1165 }
1166
1167 if err := Rename(from, to); err != nil {
1168 t.Fatalf("unexpected error when renaming from %q to %q: %s", from, to, err)
1169 }
1170
1171 fd, err := Open(".")
1172 if err != nil {
1173 t.Fatalf("Open .: %s", err)
1174 }
1175
1176
1177
1178 dirNames, err := fd.Readdirnames(-1)
1179 fd.Close()
1180 if err != nil {
1181 t.Fatalf("readdirnames: %s", err)
1182 }
1183
1184 if dirNamesLen := len(dirNames); dirNamesLen != 1 {
1185 t.Fatalf("unexpected dirNames len, got %q, want %q", dirNamesLen, 1)
1186 }
1187
1188 if dirNames[0] != to {
1189 t.Errorf("unexpected name, got %q, want %q", dirNames[0], to)
1190 }
1191 })
1192 }
1193 }
1194
1195 func testStartProcess(dir, cmd string, args []string, expect string) func(t *testing.T) {
1196 return func(t *testing.T) {
1197 t.Parallel()
1198
1199 r, w, err := Pipe()
1200 if err != nil {
1201 t.Fatalf("Pipe: %v", err)
1202 }
1203 defer r.Close()
1204 attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}}
1205 p, err := StartProcess(cmd, args, attr)
1206 if err != nil {
1207 t.Fatalf("StartProcess: %v", err)
1208 }
1209 w.Close()
1210
1211 var b strings.Builder
1212 io.Copy(&b, r)
1213 output := b.String()
1214
1215 fi1, _ := Stat(strings.TrimSpace(output))
1216 fi2, _ := Stat(expect)
1217 if !SameFile(fi1, fi2) {
1218 t.Errorf("exec %q returned %q wanted %q",
1219 strings.Join(append([]string{cmd}, args...), " "), output, expect)
1220 }
1221 p.Wait()
1222 }
1223 }
1224
1225 func TestStartProcess(t *testing.T) {
1226 testenv.MustHaveExec(t)
1227 t.Parallel()
1228
1229 var dir, cmd string
1230 var args []string
1231 switch runtime.GOOS {
1232 case "android":
1233 t.Skip("android doesn't have /bin/pwd")
1234 case "windows":
1235 cmd = Getenv("COMSPEC")
1236 dir = Getenv("SystemRoot")
1237 args = []string{"/c", "cd"}
1238 default:
1239 var err error
1240 cmd, err = exec.LookPath("pwd")
1241 if err != nil {
1242 t.Fatalf("Can't find pwd: %v", err)
1243 }
1244 dir = "/"
1245 args = []string{}
1246 t.Logf("Testing with %v", cmd)
1247 }
1248 cmddir, cmdbase := filepath.Split(cmd)
1249 args = append([]string{cmdbase}, args...)
1250 t.Run("absolute", testStartProcess(dir, cmd, args, dir))
1251 t.Run("relative", testStartProcess(cmddir, cmdbase, args, cmddir))
1252 }
1253
1254 func checkMode(t *testing.T, path string, mode FileMode) {
1255 dir, err := Stat(path)
1256 if err != nil {
1257 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
1258 }
1259 if dir.Mode()&ModePerm != mode {
1260 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
1261 }
1262 }
1263
1264 func TestChmod(t *testing.T) {
1265
1266 if runtime.GOOS == "wasip1" {
1267 t.Skip("Chmod is not supported on " + runtime.GOOS)
1268 }
1269 t.Parallel()
1270
1271 f := newFile(t)
1272
1273
1274 fm := FileMode(0456)
1275 if runtime.GOOS == "windows" {
1276 fm = FileMode(0444)
1277 }
1278 if err := Chmod(f.Name(), fm); err != nil {
1279 t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
1280 }
1281 checkMode(t, f.Name(), fm)
1282
1283 fm = FileMode(0123)
1284 if runtime.GOOS == "windows" {
1285 fm = FileMode(0666)
1286 }
1287 if err := f.Chmod(fm); err != nil {
1288 t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
1289 }
1290 checkMode(t, f.Name(), fm)
1291 }
1292
1293 func checkSize(t *testing.T, f *File, size int64) {
1294 t.Helper()
1295 dir, err := f.Stat()
1296 if err != nil {
1297 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
1298 }
1299 if dir.Size() != size {
1300 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size)
1301 }
1302 }
1303
1304 func TestFTruncate(t *testing.T) {
1305 t.Parallel()
1306
1307 f := newFile(t)
1308
1309 checkSize(t, f, 0)
1310 f.Write([]byte("hello, world\n"))
1311 checkSize(t, f, 13)
1312 f.Truncate(10)
1313 checkSize(t, f, 10)
1314 f.Truncate(1024)
1315 checkSize(t, f, 1024)
1316 f.Truncate(0)
1317 checkSize(t, f, 0)
1318 _, err := f.Write([]byte("surprise!"))
1319 if err == nil {
1320 checkSize(t, f, 13+9)
1321 }
1322 }
1323
1324 func TestTruncate(t *testing.T) {
1325 t.Parallel()
1326
1327 f := newFile(t)
1328
1329 checkSize(t, f, 0)
1330 f.Write([]byte("hello, world\n"))
1331 checkSize(t, f, 13)
1332 Truncate(f.Name(), 10)
1333 checkSize(t, f, 10)
1334 Truncate(f.Name(), 1024)
1335 checkSize(t, f, 1024)
1336 Truncate(f.Name(), 0)
1337 checkSize(t, f, 0)
1338 _, err := f.Write([]byte("surprise!"))
1339 if err == nil {
1340 checkSize(t, f, 13+9)
1341 }
1342 }
1343
1344 func TestTruncateNonexistentFile(t *testing.T) {
1345 t.Parallel()
1346
1347 assertPathError := func(t testing.TB, path string, err error) {
1348 t.Helper()
1349 if pe, ok := err.(*PathError); !ok || !IsNotExist(err) || pe.Path != path {
1350 t.Errorf("got error: %v\nwant an ErrNotExist PathError with path %q", err, path)
1351 }
1352 }
1353
1354 path := filepath.Join(t.TempDir(), "nonexistent")
1355
1356 err := Truncate(path, 1)
1357 assertPathError(t, path, err)
1358
1359
1360 _, err = Stat(path)
1361 assertPathError(t, path, err)
1362 }
1363
1364 var hasNoatime = sync.OnceValue(func() bool {
1365
1366
1367
1368
1369
1370
1371 mounts, _ := ReadFile("/proc/mounts")
1372 return bytes.Contains(mounts, []byte("noatime"))
1373 })
1374
1375 func TestChtimes(t *testing.T) {
1376 t.Parallel()
1377
1378 f := newFile(t)
1379
1380 f.Close()
1381
1382 testChtimes(t, f.Name())
1383 }
1384
1385 func TestChtimesOmit(t *testing.T) {
1386 t.Parallel()
1387
1388 testChtimesOmit(t, true, false)
1389 testChtimesOmit(t, false, true)
1390 testChtimesOmit(t, true, true)
1391 testChtimesOmit(t, false, false)
1392 }
1393
1394 func testChtimesOmit(t *testing.T, omitAt, omitMt bool) {
1395 t.Logf("omit atime: %v, mtime: %v", omitAt, omitMt)
1396 file := newFile(t)
1397
1398 name := file.Name()
1399 err := file.Close()
1400 if err != nil {
1401 t.Error(err)
1402 }
1403 fs, err := Stat(name)
1404 if err != nil {
1405 t.Fatal(err)
1406 }
1407
1408 wantAtime := Atime(fs)
1409 wantMtime := fs.ModTime()
1410 switch runtime.GOOS {
1411 case "js":
1412 wantAtime = wantAtime.Truncate(time.Second)
1413 wantMtime = wantMtime.Truncate(time.Second)
1414 }
1415
1416 var setAtime, setMtime time.Time
1417 if !omitAt {
1418 wantAtime = wantAtime.Add(-1 * time.Second)
1419 setAtime = wantAtime
1420 }
1421 if !omitMt {
1422 wantMtime = wantMtime.Add(-1 * time.Second)
1423 setMtime = wantMtime
1424 }
1425
1426
1427 if err := Chtimes(name, setAtime, setMtime); err != nil {
1428 t.Error(err)
1429 }
1430
1431
1432 fs, err = Stat(name)
1433 if err != nil {
1434 t.Error(err)
1435 }
1436 gotAtime := Atime(fs)
1437 gotMtime := fs.ModTime()
1438
1439
1440
1441
1442 if !gotAtime.Equal(wantAtime) {
1443 errormsg := fmt.Sprintf("atime mismatch, got: %q, want: %q", gotAtime, wantAtime)
1444 switch runtime.GOOS {
1445 case "plan9":
1446
1447
1448
1449 case "dragonfly":
1450 if omitAt && omitMt {
1451 t.Log(errormsg)
1452 t.Log("Known DragonFly BSD issue (won't work when both times are omitted); ignoring.")
1453 } else {
1454
1455
1456
1457
1458
1459
1460
1461 t.Log(errormsg)
1462 t.Log("Known DragonFly BSD issue (atime not supported on hammer2); ignoring.")
1463 }
1464 case "netbsd":
1465 if !omitAt && hasNoatime() {
1466 t.Log(errormsg)
1467 t.Log("Known NetBSD issue (atime not changed on fs mounted with noatime); ignoring.")
1468 } else {
1469 t.Error(errormsg)
1470 }
1471 default:
1472 t.Error(errormsg)
1473 }
1474 }
1475 if !gotMtime.Equal(wantMtime) {
1476 errormsg := fmt.Sprintf("mtime mismatch, got: %q, want: %q", gotMtime, wantMtime)
1477 switch runtime.GOOS {
1478 case "dragonfly":
1479 if omitAt && omitMt {
1480 t.Log(errormsg)
1481 t.Log("Known DragonFly BSD issue (won't work when both times are omitted); ignoring.")
1482 } else {
1483 t.Error(errormsg)
1484 }
1485 default:
1486 t.Error(errormsg)
1487 }
1488 }
1489 }
1490
1491 func TestChtimesDir(t *testing.T) {
1492 t.Parallel()
1493
1494 testChtimes(t, t.TempDir())
1495 }
1496
1497 func testChtimes(t *testing.T, name string) {
1498 st, err := Stat(name)
1499 if err != nil {
1500 t.Fatalf("Stat %s: %s", name, err)
1501 }
1502 preStat := st
1503
1504
1505 at := Atime(preStat)
1506 mt := preStat.ModTime()
1507 err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second))
1508 if err != nil {
1509 t.Fatalf("Chtimes %s: %s", name, err)
1510 }
1511
1512 st, err = Stat(name)
1513 if err != nil {
1514 t.Fatalf("second Stat %s: %s", name, err)
1515 }
1516 postStat := st
1517
1518 pat := Atime(postStat)
1519 pmt := postStat.ModTime()
1520 if !pat.Before(at) {
1521 errormsg := fmt.Sprintf("AccessTime didn't go backwards; was=%v, after=%v", at, pat)
1522 switch runtime.GOOS {
1523 case "plan9":
1524
1525
1526
1527
1528 case "netbsd":
1529 if hasNoatime() {
1530 t.Log(errormsg)
1531 t.Log("Known NetBSD issue (atime not changed on fs mounted with noatime); ignoring.")
1532 } else {
1533 t.Errorf(errormsg)
1534 }
1535 default:
1536 t.Errorf(errormsg)
1537 }
1538 }
1539
1540 if !pmt.Before(mt) {
1541 t.Errorf("ModTime didn't go backwards; was=%v, after=%v", mt, pmt)
1542 }
1543 }
1544
1545 func TestChtimesToUnixZero(t *testing.T) {
1546 file := newFile(t)
1547 fn := file.Name()
1548 if _, err := file.Write([]byte("hi")); err != nil {
1549 t.Fatal(err)
1550 }
1551 if err := file.Close(); err != nil {
1552 t.Fatal(err)
1553 }
1554
1555 unixZero := time.Unix(0, 0)
1556 if err := Chtimes(fn, unixZero, unixZero); err != nil {
1557 t.Fatalf("Chtimes failed: %v", err)
1558 }
1559
1560 st, err := Stat(fn)
1561 if err != nil {
1562 t.Fatal(err)
1563 }
1564
1565 if mt := st.ModTime(); mt != unixZero {
1566 t.Errorf("mtime is %v, want %v", mt, unixZero)
1567 }
1568 }
1569
1570 func TestFileChdir(t *testing.T) {
1571 wd, err := Getwd()
1572 if err != nil {
1573 t.Fatalf("Getwd: %s", err)
1574 }
1575 defer Chdir(wd)
1576
1577 fd, err := Open(".")
1578 if err != nil {
1579 t.Fatalf("Open .: %s", err)
1580 }
1581 defer fd.Close()
1582
1583 if err := Chdir("/"); err != nil {
1584 t.Fatalf("Chdir /: %s", err)
1585 }
1586
1587 if err := fd.Chdir(); err != nil {
1588 t.Fatalf("fd.Chdir: %s", err)
1589 }
1590
1591 wdNew, err := Getwd()
1592 if err != nil {
1593 t.Fatalf("Getwd: %s", err)
1594 }
1595
1596 wdInfo, err := fd.Stat()
1597 if err != nil {
1598 t.Fatal(err)
1599 }
1600 newInfo, err := Stat(wdNew)
1601 if err != nil {
1602 t.Fatal(err)
1603 }
1604 if !SameFile(wdInfo, newInfo) {
1605 t.Fatalf("fd.Chdir failed: got %s, want %s", wdNew, wd)
1606 }
1607 }
1608
1609 func TestChdirAndGetwd(t *testing.T) {
1610 fd, err := Open(".")
1611 if err != nil {
1612 t.Fatalf("Open .: %s", err)
1613 }
1614
1615
1616 dirs := []string{"/", "/usr/bin", "/tmp"}
1617
1618 switch runtime.GOOS {
1619 case "android":
1620 dirs = []string{"/system/bin"}
1621 case "plan9":
1622 dirs = []string{"/", "/usr"}
1623 case "ios", "windows", "wasip1":
1624 dirs = nil
1625 for _, dir := range []string{t.TempDir(), t.TempDir()} {
1626
1627 dir, err = filepath.EvalSymlinks(dir)
1628 if err != nil {
1629 t.Fatalf("EvalSymlinks: %v", err)
1630 }
1631 dirs = append(dirs, dir)
1632 }
1633 }
1634 oldwd := Getenv("PWD")
1635 for mode := 0; mode < 2; mode++ {
1636 for _, d := range dirs {
1637 if mode == 0 {
1638 err = Chdir(d)
1639 } else {
1640 fd1, err1 := Open(d)
1641 if err1 != nil {
1642 t.Errorf("Open %s: %s", d, err1)
1643 continue
1644 }
1645 err = fd1.Chdir()
1646 fd1.Close()
1647 }
1648 if d == "/tmp" {
1649 Setenv("PWD", "/tmp")
1650 }
1651 pwd, err1 := Getwd()
1652 Setenv("PWD", oldwd)
1653 err2 := fd.Chdir()
1654 if err2 != nil {
1655
1656
1657
1658 fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2)
1659 Exit(1)
1660 }
1661 if err != nil {
1662 fd.Close()
1663 t.Fatalf("Chdir %s: %s", d, err)
1664 }
1665 if err1 != nil {
1666 fd.Close()
1667 t.Fatalf("Getwd in %s: %s", d, err1)
1668 }
1669 if !equal(pwd, d) {
1670 fd.Close()
1671 t.Fatalf("Getwd returned %q want %q", pwd, d)
1672 }
1673 }
1674 }
1675 fd.Close()
1676 }
1677
1678
1679 func TestProgWideChdir(t *testing.T) {
1680 const N = 10
1681 var wg sync.WaitGroup
1682 hold := make(chan struct{})
1683 done := make(chan struct{})
1684
1685 d := t.TempDir()
1686 oldwd, err := Getwd()
1687 if err != nil {
1688 t.Fatalf("Getwd: %v", err)
1689 }
1690 defer func() {
1691 if err := Chdir(oldwd); err != nil {
1692
1693
1694 panic(err)
1695 }
1696 }()
1697
1698
1699
1700
1701
1702
1703 defer wg.Wait()
1704 defer close(done)
1705
1706 for i := 0; i < N; i++ {
1707 wg.Add(1)
1708 go func(i int) {
1709 defer wg.Done()
1710
1711
1712 if i%2 == 1 {
1713
1714
1715
1716
1717
1718 runtime.LockOSThread()
1719 }
1720 select {
1721 case <-done:
1722 return
1723 case <-hold:
1724 }
1725
1726 f0, err := Stat(".")
1727 if err != nil {
1728 t.Error(err)
1729 return
1730 }
1731 pwd, err := Getwd()
1732 if err != nil {
1733 t.Errorf("Getwd: %v", err)
1734 return
1735 }
1736 if pwd != d {
1737 t.Errorf("Getwd() = %q, want %q", pwd, d)
1738 return
1739 }
1740 f1, err := Stat(pwd)
1741 if err != nil {
1742 t.Error(err)
1743 return
1744 }
1745 if !SameFile(f0, f1) {
1746 t.Errorf(`Samefile(Stat("."), Getwd()) reports false (%s != %s)`, f0.Name(), f1.Name())
1747 return
1748 }
1749 }(i)
1750 }
1751 if err = Chdir(d); err != nil {
1752 t.Fatalf("Chdir: %v", err)
1753 }
1754
1755
1756 d, err = Getwd()
1757 if err != nil {
1758 t.Fatalf("Getwd: %v", err)
1759 }
1760 close(hold)
1761 wg.Wait()
1762 }
1763
1764 func TestSeek(t *testing.T) {
1765 t.Parallel()
1766
1767 f := newFile(t)
1768
1769 const data = "hello, world\n"
1770 io.WriteString(f, data)
1771
1772 type test struct {
1773 in int64
1774 whence int
1775 out int64
1776 }
1777 var tests = []test{
1778 {0, io.SeekCurrent, int64(len(data))},
1779 {0, io.SeekStart, 0},
1780 {5, io.SeekStart, 5},
1781 {0, io.SeekEnd, int64(len(data))},
1782 {0, io.SeekStart, 0},
1783 {-1, io.SeekEnd, int64(len(data)) - 1},
1784 {1 << 33, io.SeekStart, 1 << 33},
1785 {1 << 33, io.SeekEnd, 1<<33 + int64(len(data))},
1786
1787
1788 {1<<32 - 1, io.SeekStart, 1<<32 - 1},
1789 {0, io.SeekCurrent, 1<<32 - 1},
1790 {2<<32 - 1, io.SeekStart, 2<<32 - 1},
1791 {0, io.SeekCurrent, 2<<32 - 1},
1792 }
1793 for i, tt := range tests {
1794 off, err := f.Seek(tt.in, tt.whence)
1795 if off != tt.out || err != nil {
1796 if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 && runtime.GOOS == "linux" {
1797 mounts, _ := ReadFile("/proc/mounts")
1798 if strings.Contains(string(mounts), "reiserfs") {
1799
1800 t.Skipf("skipping test known to fail on reiserfs; https://golang.org/issue/91")
1801 }
1802 }
1803 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
1804 }
1805 }
1806 }
1807
1808 func TestSeekError(t *testing.T) {
1809 switch runtime.GOOS {
1810 case "js", "plan9", "wasip1":
1811 t.Skipf("skipping test on %v", runtime.GOOS)
1812 }
1813 t.Parallel()
1814
1815 r, w, err := Pipe()
1816 if err != nil {
1817 t.Fatal(err)
1818 }
1819 _, err = r.Seek(0, 0)
1820 if err == nil {
1821 t.Fatal("Seek on pipe should fail")
1822 }
1823 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE {
1824 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err)
1825 }
1826 _, err = w.Seek(0, 0)
1827 if err == nil {
1828 t.Fatal("Seek on pipe should fail")
1829 }
1830 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE {
1831 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err)
1832 }
1833 }
1834
1835 type openErrorTest struct {
1836 path string
1837 mode int
1838 error error
1839 }
1840
1841 var openErrorTests = []openErrorTest{
1842 {
1843 sfdir + "/no-such-file",
1844 O_RDONLY,
1845 syscall.ENOENT,
1846 },
1847 {
1848 sfdir,
1849 O_WRONLY,
1850 syscall.EISDIR,
1851 },
1852 {
1853 sfdir + "/" + sfname + "/no-such-file",
1854 O_WRONLY,
1855 syscall.ENOTDIR,
1856 },
1857 }
1858
1859 func TestOpenError(t *testing.T) {
1860 t.Parallel()
1861
1862 for _, tt := range openErrorTests {
1863 f, err := OpenFile(tt.path, tt.mode, 0)
1864 if err == nil {
1865 t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
1866 f.Close()
1867 continue
1868 }
1869 perr, ok := err.(*PathError)
1870 if !ok {
1871 t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err)
1872 }
1873 if perr.Err != tt.error {
1874 if runtime.GOOS == "plan9" {
1875 syscallErrStr := perr.Err.Error()
1876 expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1)
1877 if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
1878
1879
1880
1881 if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) {
1882 continue
1883 }
1884 t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
1885 }
1886 continue
1887 }
1888 if runtime.GOOS == "dragonfly" {
1889
1890
1891 if tt.error == syscall.EISDIR && perr.Err == syscall.EACCES {
1892 continue
1893 }
1894 }
1895 t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error())
1896 }
1897 }
1898 }
1899
1900 func TestOpenNoName(t *testing.T) {
1901 f, err := Open("")
1902 if err == nil {
1903 f.Close()
1904 t.Fatal(`Open("") succeeded`)
1905 }
1906 }
1907
1908 func runBinHostname(t *testing.T) string {
1909
1910 r, w, err := Pipe()
1911 if err != nil {
1912 t.Fatal(err)
1913 }
1914 defer r.Close()
1915
1916 path, err := exec.LookPath("hostname")
1917 if err != nil {
1918 if errors.Is(err, exec.ErrNotFound) {
1919 t.Skip("skipping test; test requires hostname but it does not exist")
1920 }
1921 t.Fatal(err)
1922 }
1923
1924 argv := []string{"hostname"}
1925 if runtime.GOOS == "aix" {
1926 argv = []string{"hostname", "-s"}
1927 }
1928 p, err := StartProcess(path, argv, &ProcAttr{Files: []*File{nil, w, Stderr}})
1929 if err != nil {
1930 t.Fatal(err)
1931 }
1932 w.Close()
1933
1934 var b strings.Builder
1935 io.Copy(&b, r)
1936 _, err = p.Wait()
1937 if err != nil {
1938 t.Fatalf("run hostname Wait: %v", err)
1939 }
1940 err = p.Kill()
1941 if err == nil {
1942 t.Errorf("expected an error from Kill running 'hostname'")
1943 }
1944 output := b.String()
1945 if n := len(output); n > 0 && output[n-1] == '\n' {
1946 output = output[0 : n-1]
1947 }
1948 if output == "" {
1949 t.Fatalf("/bin/hostname produced no output")
1950 }
1951
1952 return output
1953 }
1954
1955 func testWindowsHostname(t *testing.T, hostname string) {
1956 cmd := testenv.Command(t, "hostname")
1957 out, err := cmd.Output()
1958 if err != nil {
1959 t.Fatalf("Failed to execute hostname command: %v %s", err, out)
1960 }
1961 want := strings.Trim(string(out), "\r\n")
1962 if hostname != want {
1963 t.Fatalf("Hostname() = %q != system hostname of %q", hostname, want)
1964 }
1965 }
1966
1967 func TestHostname(t *testing.T) {
1968 t.Parallel()
1969
1970 hostname, err := Hostname()
1971 if err != nil {
1972 t.Fatal(err)
1973 }
1974 if hostname == "" {
1975 t.Fatal("Hostname returned empty string and no error")
1976 }
1977 if strings.Contains(hostname, "\x00") {
1978 t.Fatalf("unexpected zero byte in hostname: %q", hostname)
1979 }
1980
1981
1982
1983 switch runtime.GOOS {
1984 case "android", "plan9":
1985
1986 return
1987 case "windows":
1988 testWindowsHostname(t, hostname)
1989 return
1990 }
1991
1992 testenv.MustHaveExec(t)
1993
1994
1995
1996
1997 want := runBinHostname(t)
1998 if hostname != want {
1999 host, _, ok := strings.Cut(hostname, ".")
2000 if !ok || host != want {
2001 t.Errorf("Hostname() = %q, want %q", hostname, want)
2002 }
2003 }
2004 }
2005
2006 func TestReadAt(t *testing.T) {
2007 t.Parallel()
2008
2009 f := newFile(t)
2010
2011 const data = "hello, world\n"
2012 io.WriteString(f, data)
2013
2014 b := make([]byte, 5)
2015 n, err := f.ReadAt(b, 7)
2016 if err != nil || n != len(b) {
2017 t.Fatalf("ReadAt 7: %d, %v", n, err)
2018 }
2019 if string(b) != "world" {
2020 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
2021 }
2022 }
2023
2024
2025
2026
2027
2028 func TestReadAtOffset(t *testing.T) {
2029 t.Parallel()
2030
2031 f := newFile(t)
2032
2033 const data = "hello, world\n"
2034 io.WriteString(f, data)
2035
2036 f.Seek(0, 0)
2037 b := make([]byte, 5)
2038
2039 n, err := f.ReadAt(b, 7)
2040 if err != nil || n != len(b) {
2041 t.Fatalf("ReadAt 7: %d, %v", n, err)
2042 }
2043 if string(b) != "world" {
2044 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
2045 }
2046
2047 n, err = f.Read(b)
2048 if err != nil || n != len(b) {
2049 t.Fatalf("Read: %d, %v", n, err)
2050 }
2051 if string(b) != "hello" {
2052 t.Fatalf("Read: have %q want %q", string(b), "hello")
2053 }
2054 }
2055
2056
2057 func TestReadAtNegativeOffset(t *testing.T) {
2058 t.Parallel()
2059
2060 f := newFile(t)
2061
2062 const data = "hello, world\n"
2063 io.WriteString(f, data)
2064
2065 f.Seek(0, 0)
2066 b := make([]byte, 5)
2067
2068 n, err := f.ReadAt(b, -10)
2069
2070 const wantsub = "negative offset"
2071 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 {
2072 t.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub)
2073 }
2074 }
2075
2076 func TestWriteAt(t *testing.T) {
2077 t.Parallel()
2078
2079 f := newFile(t)
2080
2081 const data = "hello, world\n"
2082 io.WriteString(f, data)
2083
2084 n, err := f.WriteAt([]byte("WORLD"), 7)
2085 if err != nil || n != 5 {
2086 t.Fatalf("WriteAt 7: %d, %v", n, err)
2087 }
2088
2089 b, err := ReadFile(f.Name())
2090 if err != nil {
2091 t.Fatalf("ReadFile %s: %v", f.Name(), err)
2092 }
2093 if string(b) != "hello, WORLD\n" {
2094 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
2095 }
2096 }
2097
2098
2099 func TestWriteAtNegativeOffset(t *testing.T) {
2100 t.Parallel()
2101
2102 f := newFile(t)
2103
2104 n, err := f.WriteAt([]byte("WORLD"), -10)
2105
2106 const wantsub = "negative offset"
2107 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 {
2108 t.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub)
2109 }
2110 }
2111
2112
2113 func TestWriteAtInAppendMode(t *testing.T) {
2114 defer chtmpdir(t)()
2115 f, err := OpenFile("write_at_in_append_mode.txt", O_APPEND|O_CREATE, 0666)
2116 if err != nil {
2117 t.Fatalf("OpenFile: %v", err)
2118 }
2119 defer f.Close()
2120
2121 _, err = f.WriteAt([]byte(""), 1)
2122 if err != ErrWriteAtInAppendMode {
2123 t.Fatalf("f.WriteAt returned %v, expected %v", err, ErrWriteAtInAppendMode)
2124 }
2125 }
2126
2127 func writeFile(t *testing.T, fname string, flag int, text string) string {
2128 f, err := OpenFile(fname, flag, 0666)
2129 if err != nil {
2130 t.Fatalf("Open: %v", err)
2131 }
2132 n, err := io.WriteString(f, text)
2133 if err != nil {
2134 t.Fatalf("WriteString: %d, %v", n, err)
2135 }
2136 f.Close()
2137 data, err := ReadFile(fname)
2138 if err != nil {
2139 t.Fatalf("ReadFile: %v", err)
2140 }
2141 return string(data)
2142 }
2143
2144 func TestAppend(t *testing.T) {
2145 defer chtmpdir(t)()
2146 const f = "append.txt"
2147 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
2148 if s != "new" {
2149 t.Fatalf("writeFile: have %q want %q", s, "new")
2150 }
2151 s = writeFile(t, f, O_APPEND|O_RDWR, "|append")
2152 if s != "new|append" {
2153 t.Fatalf("writeFile: have %q want %q", s, "new|append")
2154 }
2155 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append")
2156 if s != "new|append|append" {
2157 t.Fatalf("writeFile: have %q want %q", s, "new|append|append")
2158 }
2159 err := Remove(f)
2160 if err != nil {
2161 t.Fatalf("Remove: %v", err)
2162 }
2163 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append")
2164 if s != "new&append" {
2165 t.Fatalf("writeFile: after append have %q want %q", s, "new&append")
2166 }
2167 s = writeFile(t, f, O_CREATE|O_RDWR, "old")
2168 if s != "old&append" {
2169 t.Fatalf("writeFile: after create have %q want %q", s, "old&append")
2170 }
2171 s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
2172 if s != "new" {
2173 t.Fatalf("writeFile: after truncate have %q want %q", s, "new")
2174 }
2175 }
2176
2177 func TestStatDirWithTrailingSlash(t *testing.T) {
2178 t.Parallel()
2179
2180
2181 path := t.TempDir()
2182
2183
2184 if _, err := Stat(path); err != nil {
2185 t.Fatalf("stat %s failed: %s", path, err)
2186 }
2187
2188
2189 path += "/"
2190 if _, err := Stat(path); err != nil {
2191 t.Fatalf("stat %s failed: %s", path, err)
2192 }
2193 }
2194
2195 func TestNilProcessStateString(t *testing.T) {
2196 var ps *ProcessState
2197 s := ps.String()
2198 if s != "<nil>" {
2199 t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>")
2200 }
2201 }
2202
2203 func TestSameFile(t *testing.T) {
2204 defer chtmpdir(t)()
2205 fa, err := Create("a")
2206 if err != nil {
2207 t.Fatalf("Create(a): %v", err)
2208 }
2209 fa.Close()
2210 fb, err := Create("b")
2211 if err != nil {
2212 t.Fatalf("Create(b): %v", err)
2213 }
2214 fb.Close()
2215
2216 ia1, err := Stat("a")
2217 if err != nil {
2218 t.Fatalf("Stat(a): %v", err)
2219 }
2220 ia2, err := Stat("a")
2221 if err != nil {
2222 t.Fatalf("Stat(a): %v", err)
2223 }
2224 if !SameFile(ia1, ia2) {
2225 t.Errorf("files should be same")
2226 }
2227
2228 ib, err := Stat("b")
2229 if err != nil {
2230 t.Fatalf("Stat(b): %v", err)
2231 }
2232 if SameFile(ia1, ib) {
2233 t.Errorf("files should be different")
2234 }
2235 }
2236
2237 func testDevNullFileInfo(t *testing.T, statname, devNullName string, fi FileInfo) {
2238 pre := fmt.Sprintf("%s(%q): ", statname, devNullName)
2239 if fi.Size() != 0 {
2240 t.Errorf(pre+"wrong file size have %d want 0", fi.Size())
2241 }
2242 if fi.Mode()&ModeDevice == 0 {
2243 t.Errorf(pre+"wrong file mode %q: ModeDevice is not set", fi.Mode())
2244 }
2245 if fi.Mode()&ModeCharDevice == 0 {
2246 t.Errorf(pre+"wrong file mode %q: ModeCharDevice is not set", fi.Mode())
2247 }
2248 if fi.Mode().IsRegular() {
2249 t.Errorf(pre+"wrong file mode %q: IsRegular returns true", fi.Mode())
2250 }
2251 }
2252
2253 func testDevNullFile(t *testing.T, devNullName string) {
2254 f, err := Open(devNullName)
2255 if err != nil {
2256 t.Fatalf("Open(%s): %v", devNullName, err)
2257 }
2258 defer f.Close()
2259
2260 fi, err := f.Stat()
2261 if err != nil {
2262 t.Fatalf("Stat(%s): %v", devNullName, err)
2263 }
2264 testDevNullFileInfo(t, "f.Stat", devNullName, fi)
2265
2266 fi, err = Stat(devNullName)
2267 if err != nil {
2268 t.Fatalf("Stat(%s): %v", devNullName, err)
2269 }
2270 testDevNullFileInfo(t, "Stat", devNullName, fi)
2271 }
2272
2273 func TestDevNullFile(t *testing.T) {
2274 t.Parallel()
2275
2276 testDevNullFile(t, DevNull)
2277 if runtime.GOOS == "windows" {
2278 testDevNullFile(t, "./nul")
2279 testDevNullFile(t, "//./nul")
2280 }
2281 }
2282
2283 var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output")
2284
2285 func TestLargeWriteToConsole(t *testing.T) {
2286 if !*testLargeWrite {
2287 t.Skip("skipping console-flooding test; enable with -large_write")
2288 }
2289 b := make([]byte, 32000)
2290 for i := range b {
2291 b[i] = '.'
2292 }
2293 b[len(b)-1] = '\n'
2294 n, err := Stdout.Write(b)
2295 if err != nil {
2296 t.Fatalf("Write to os.Stdout failed: %v", err)
2297 }
2298 if n != len(b) {
2299 t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n)
2300 }
2301 n, err = Stderr.Write(b)
2302 if err != nil {
2303 t.Fatalf("Write to os.Stderr failed: %v", err)
2304 }
2305 if n != len(b) {
2306 t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n)
2307 }
2308 }
2309
2310 func TestStatDirModeExec(t *testing.T) {
2311 if runtime.GOOS == "wasip1" {
2312 t.Skip("Chmod is not supported on " + runtime.GOOS)
2313 }
2314 t.Parallel()
2315
2316 const mode = 0111
2317
2318 path := t.TempDir()
2319 if err := Chmod(path, 0777); err != nil {
2320 t.Fatalf("Chmod %q 0777: %v", path, err)
2321 }
2322
2323 dir, err := Stat(path)
2324 if err != nil {
2325 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
2326 }
2327 if dir.Mode()&mode != mode {
2328 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode)
2329 }
2330 }
2331
2332 func TestStatStdin(t *testing.T) {
2333 switch runtime.GOOS {
2334 case "android", "plan9":
2335 t.Skipf("%s doesn't have /bin/sh", runtime.GOOS)
2336 }
2337
2338 if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
2339 st, err := Stdin.Stat()
2340 if err != nil {
2341 t.Fatalf("Stat failed: %v", err)
2342 }
2343 fmt.Println(st.Mode() & ModeNamedPipe)
2344 Exit(0)
2345 }
2346
2347 exe, err := Executable()
2348 if err != nil {
2349 t.Skipf("can't find executable: %v", err)
2350 }
2351
2352 testenv.MustHaveExec(t)
2353 t.Parallel()
2354
2355 fi, err := Stdin.Stat()
2356 if err != nil {
2357 t.Fatal(err)
2358 }
2359 switch mode := fi.Mode(); {
2360 case mode&ModeCharDevice != 0 && mode&ModeDevice != 0:
2361 case mode&ModeNamedPipe != 0:
2362 default:
2363 t.Fatalf("unexpected Stdin mode (%v), want ModeCharDevice or ModeNamedPipe", mode)
2364 }
2365
2366 cmd := testenv.Command(t, exe, "-test.run=^TestStatStdin$")
2367 cmd = testenv.CleanCmdEnv(cmd)
2368 cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
2369
2370 cmd.Stdin = strings.NewReader("output")
2371
2372 output, err := cmd.CombinedOutput()
2373 if err != nil {
2374 t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
2375 }
2376
2377
2378 if len(output) < 1 || output[0] != 'p' {
2379 t.Fatalf("Child process reports stdin is not pipe '%v'", string(output))
2380 }
2381 }
2382
2383 func TestStatRelativeSymlink(t *testing.T) {
2384 testenv.MustHaveSymlink(t)
2385 t.Parallel()
2386
2387 tmpdir := t.TempDir()
2388 target := filepath.Join(tmpdir, "target")
2389 f, err := Create(target)
2390 if err != nil {
2391 t.Fatal(err)
2392 }
2393 defer f.Close()
2394
2395 st, err := f.Stat()
2396 if err != nil {
2397 t.Fatal(err)
2398 }
2399
2400 link := filepath.Join(tmpdir, "link")
2401 err = Symlink(filepath.Base(target), link)
2402 if err != nil {
2403 t.Fatal(err)
2404 }
2405
2406 st1, err := Stat(link)
2407 if err != nil {
2408 t.Fatal(err)
2409 }
2410
2411 if !SameFile(st, st1) {
2412 t.Error("Stat doesn't follow relative symlink")
2413 }
2414
2415 if runtime.GOOS == "windows" {
2416 Remove(link)
2417 err = Symlink(target[len(filepath.VolumeName(target)):], link)
2418 if err != nil {
2419 t.Fatal(err)
2420 }
2421
2422 st1, err := Stat(link)
2423 if err != nil {
2424 t.Fatal(err)
2425 }
2426
2427 if !SameFile(st, st1) {
2428 t.Error("Stat doesn't follow relative symlink")
2429 }
2430 }
2431 }
2432
2433 func TestReadAtEOF(t *testing.T) {
2434 t.Parallel()
2435
2436 f := newFile(t)
2437
2438 _, err := f.ReadAt(make([]byte, 10), 0)
2439 switch err {
2440 case io.EOF:
2441
2442 case nil:
2443 t.Fatalf("ReadAt succeeded")
2444 default:
2445 t.Fatalf("ReadAt failed: %s", err)
2446 }
2447 }
2448
2449 func TestLongPath(t *testing.T) {
2450 t.Parallel()
2451
2452 tmpdir := t.TempDir()
2453
2454
2455 sizes := []int{247, 248, 249, 400}
2456 for len(tmpdir) < 400 {
2457 tmpdir += "/dir3456789"
2458 }
2459 for _, sz := range sizes {
2460 t.Run(fmt.Sprintf("length=%d", sz), func(t *testing.T) {
2461 sizedTempDir := tmpdir[:sz-1] + "x"
2462
2463
2464
2465 if err := MkdirAll(sizedTempDir, 0755); err != nil {
2466 t.Fatalf("MkdirAll failed: %v", err)
2467 }
2468 data := []byte("hello world\n")
2469 if err := WriteFile(sizedTempDir+"/foo.txt", data, 0644); err != nil {
2470 t.Fatalf("os.WriteFile() failed: %v", err)
2471 }
2472 if err := Rename(sizedTempDir+"/foo.txt", sizedTempDir+"/bar.txt"); err != nil {
2473 t.Fatalf("Rename failed: %v", err)
2474 }
2475 mtime := time.Now().Truncate(time.Minute)
2476 if err := Chtimes(sizedTempDir+"/bar.txt", mtime, mtime); err != nil {
2477 t.Fatalf("Chtimes failed: %v", err)
2478 }
2479 names := []string{"bar.txt"}
2480 if testenv.HasSymlink() {
2481 if err := Symlink(sizedTempDir+"/bar.txt", sizedTempDir+"/symlink.txt"); err != nil {
2482 t.Fatalf("Symlink failed: %v", err)
2483 }
2484 names = append(names, "symlink.txt")
2485 }
2486 if testenv.HasLink() {
2487 if err := Link(sizedTempDir+"/bar.txt", sizedTempDir+"/link.txt"); err != nil {
2488 t.Fatalf("Link failed: %v", err)
2489 }
2490 names = append(names, "link.txt")
2491 }
2492 for _, wantSize := range []int64{int64(len(data)), 0} {
2493 for _, name := range names {
2494 path := sizedTempDir + "/" + name
2495 dir, err := Stat(path)
2496 if err != nil {
2497 t.Fatalf("Stat(%q) failed: %v", path, err)
2498 }
2499 filesize := size(path, t)
2500 if dir.Size() != filesize || filesize != wantSize {
2501 t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize)
2502 }
2503 if runtime.GOOS != "wasip1" {
2504 err = Chmod(path, dir.Mode())
2505 if err != nil {
2506 t.Fatalf("Chmod(%q) failed: %v", path, err)
2507 }
2508 }
2509 }
2510 if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil {
2511 t.Fatalf("Truncate failed: %v", err)
2512 }
2513 }
2514 })
2515 }
2516 }
2517
2518 func testKillProcess(t *testing.T, processKiller func(p *Process)) {
2519 testenv.MustHaveExec(t)
2520 t.Parallel()
2521
2522
2523 cmd := testenv.Command(t, Args[0])
2524 cmd.Env = append(cmd.Environ(), "GO_OS_TEST_DRAIN_STDIN=1")
2525 stdout, err := cmd.StdoutPipe()
2526 if err != nil {
2527 t.Fatal(err)
2528 }
2529 stdin, err := cmd.StdinPipe()
2530 if err != nil {
2531 t.Fatal(err)
2532 }
2533 err = cmd.Start()
2534 if err != nil {
2535 t.Fatalf("Failed to start test process: %v", err)
2536 }
2537
2538 defer func() {
2539 if err := cmd.Wait(); err == nil {
2540 t.Errorf("Test process succeeded, but expected to fail")
2541 }
2542 stdin.Close()
2543 }()
2544
2545
2546
2547 io.Copy(io.Discard, stdout)
2548
2549 processKiller(cmd.Process)
2550 }
2551
2552 func TestKillStartProcess(t *testing.T) {
2553 testKillProcess(t, func(p *Process) {
2554 err := p.Kill()
2555 if err != nil {
2556 t.Fatalf("Failed to kill test process: %v", err)
2557 }
2558 })
2559 }
2560
2561 func TestGetppid(t *testing.T) {
2562 if runtime.GOOS == "plan9" {
2563
2564 t.Skipf("skipping test on plan9; see issue 8206")
2565 }
2566
2567 if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
2568 fmt.Print(Getppid())
2569 Exit(0)
2570 }
2571
2572 testenv.MustHaveExec(t)
2573 t.Parallel()
2574
2575 cmd := testenv.Command(t, Args[0], "-test.run=^TestGetppid$")
2576 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
2577
2578
2579 output, err := cmd.CombinedOutput()
2580 if err != nil {
2581 t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
2582 }
2583
2584 childPpid := string(output)
2585 ourPid := fmt.Sprintf("%d", Getpid())
2586 if childPpid != ourPid {
2587 t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid)
2588 }
2589 }
2590
2591 func TestKillFindProcess(t *testing.T) {
2592 testKillProcess(t, func(p *Process) {
2593 p2, err := FindProcess(p.Pid)
2594 if err != nil {
2595 t.Fatalf("Failed to find test process: %v", err)
2596 }
2597 err = p2.Kill()
2598 if err != nil {
2599 t.Fatalf("Failed to kill test process: %v", err)
2600 }
2601 })
2602 }
2603
2604 var nilFileMethodTests = []struct {
2605 name string
2606 f func(*File) error
2607 }{
2608 {"Chdir", func(f *File) error { return f.Chdir() }},
2609 {"Close", func(f *File) error { return f.Close() }},
2610 {"Chmod", func(f *File) error { return f.Chmod(0) }},
2611 {"Chown", func(f *File) error { return f.Chown(0, 0) }},
2612 {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }},
2613 {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
2614 {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
2615 {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
2616 {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }},
2617 {"Stat", func(f *File) error { _, err := f.Stat(); return err }},
2618 {"Sync", func(f *File) error { return f.Sync() }},
2619 {"Truncate", func(f *File) error { return f.Truncate(0) }},
2620 {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }},
2621 {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }},
2622 {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }},
2623 }
2624
2625
2626 func TestNilFileMethods(t *testing.T) {
2627 t.Parallel()
2628
2629 for _, tt := range nilFileMethodTests {
2630 var file *File
2631 got := tt.f(file)
2632 if got != ErrInvalid {
2633 t.Errorf("%v should fail when f is nil; got %v", tt.name, got)
2634 }
2635 }
2636 }
2637
2638 func mkdirTree(t *testing.T, root string, level, max int) {
2639 if level >= max {
2640 return
2641 }
2642 level++
2643 for i := 'a'; i < 'c'; i++ {
2644 dir := filepath.Join(root, string(i))
2645 if err := Mkdir(dir, 0700); err != nil {
2646 t.Fatal(err)
2647 }
2648 mkdirTree(t, dir, level, max)
2649 }
2650 }
2651
2652
2653
2654 func TestRemoveAllRace(t *testing.T) {
2655 if runtime.GOOS == "windows" {
2656
2657
2658
2659
2660 t.Skip("skipping on windows")
2661 }
2662 if runtime.GOOS == "dragonfly" {
2663 testenv.SkipFlaky(t, 52301)
2664 }
2665
2666 n := runtime.GOMAXPROCS(16)
2667 defer runtime.GOMAXPROCS(n)
2668 root, err := MkdirTemp("", "issue")
2669 if err != nil {
2670 t.Fatal(err)
2671 }
2672 mkdirTree(t, root, 1, 6)
2673 hold := make(chan struct{})
2674 var wg sync.WaitGroup
2675 for i := 0; i < 4; i++ {
2676 wg.Add(1)
2677 go func() {
2678 defer wg.Done()
2679 <-hold
2680 err := RemoveAll(root)
2681 if err != nil {
2682 t.Errorf("unexpected error: %T, %q", err, err)
2683 }
2684 }()
2685 }
2686 close(hold)
2687 wg.Wait()
2688 }
2689
2690
2691 func TestPipeThreads(t *testing.T) {
2692 switch runtime.GOOS {
2693 case "illumos", "solaris":
2694 t.Skip("skipping on Solaris and illumos; issue 19111")
2695 case "windows":
2696 t.Skip("skipping on Windows; issue 19098")
2697 case "plan9":
2698 t.Skip("skipping on Plan 9; does not support runtime poller")
2699 case "js":
2700 t.Skip("skipping on js; no support for os.Pipe")
2701 case "wasip1":
2702 t.Skip("skipping on wasip1; no support for os.Pipe")
2703 }
2704
2705 threads := 100
2706
2707
2708 if runtime.GOOS == "openbsd" {
2709 threads = 50
2710 }
2711
2712 r := make([]*File, threads)
2713 w := make([]*File, threads)
2714 for i := 0; i < threads; i++ {
2715 rp, wp, err := Pipe()
2716 if err != nil {
2717 for j := 0; j < i; j++ {
2718 r[j].Close()
2719 w[j].Close()
2720 }
2721 t.Fatal(err)
2722 }
2723 r[i] = rp
2724 w[i] = wp
2725 }
2726
2727 defer debug.SetMaxThreads(debug.SetMaxThreads(threads / 2))
2728
2729 creading := make(chan bool, threads)
2730 cdone := make(chan bool, threads)
2731 for i := 0; i < threads; i++ {
2732 go func(i int) {
2733 var b [1]byte
2734 creading <- true
2735 if _, err := r[i].Read(b[:]); err != nil {
2736 t.Error(err)
2737 }
2738 if err := r[i].Close(); err != nil {
2739 t.Error(err)
2740 }
2741 cdone <- true
2742 }(i)
2743 }
2744
2745 for i := 0; i < threads; i++ {
2746 <-creading
2747 }
2748
2749
2750
2751
2752 for i := 0; i < threads; i++ {
2753 if _, err := w[i].Write([]byte{0}); err != nil {
2754 t.Error(err)
2755 }
2756 if err := w[i].Close(); err != nil {
2757 t.Error(err)
2758 }
2759 <-cdone
2760 }
2761 }
2762
2763 func testDoubleCloseError(path string) func(*testing.T) {
2764 return func(t *testing.T) {
2765 t.Parallel()
2766
2767 file, err := Open(path)
2768 if err != nil {
2769 t.Fatal(err)
2770 }
2771 if err := file.Close(); err != nil {
2772 t.Fatalf("unexpected error from Close: %v", err)
2773 }
2774 if err := file.Close(); err == nil {
2775 t.Error("second Close did not fail")
2776 } else if pe, ok := err.(*PathError); !ok {
2777 t.Errorf("second Close: got %T, want %T", err, pe)
2778 } else if pe.Err != ErrClosed {
2779 t.Errorf("second Close: got %q, want %q", pe.Err, ErrClosed)
2780 } else {
2781 t.Logf("second close returned expected error %q", err)
2782 }
2783 }
2784 }
2785
2786 func TestDoubleCloseError(t *testing.T) {
2787 t.Parallel()
2788 t.Run("file", testDoubleCloseError(filepath.Join(sfdir, sfname)))
2789 t.Run("dir", testDoubleCloseError(sfdir))
2790 }
2791
2792 func TestUserCacheDir(t *testing.T) {
2793 t.Parallel()
2794
2795 dir, err := UserCacheDir()
2796 if err != nil {
2797 t.Skipf("skipping: %v", err)
2798 }
2799 if dir == "" {
2800 t.Fatalf("UserCacheDir returned %q; want non-empty path or error", dir)
2801 }
2802
2803 fi, err := Stat(dir)
2804 if err != nil {
2805 if IsNotExist(err) {
2806 t.Log(err)
2807 return
2808 }
2809 t.Fatal(err)
2810 }
2811 if !fi.IsDir() {
2812 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
2813 }
2814 }
2815
2816 func TestUserConfigDir(t *testing.T) {
2817 t.Parallel()
2818
2819 dir, err := UserConfigDir()
2820 if err != nil {
2821 t.Skipf("skipping: %v", err)
2822 }
2823 if dir == "" {
2824 t.Fatalf("UserConfigDir returned %q; want non-empty path or error", dir)
2825 }
2826
2827 fi, err := Stat(dir)
2828 if err != nil {
2829 if IsNotExist(err) {
2830 t.Log(err)
2831 return
2832 }
2833 t.Fatal(err)
2834 }
2835 if !fi.IsDir() {
2836 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
2837 }
2838 }
2839
2840 func TestUserHomeDir(t *testing.T) {
2841 t.Parallel()
2842
2843 dir, err := UserHomeDir()
2844 if dir == "" && err == nil {
2845 t.Fatal("UserHomeDir returned an empty string but no error")
2846 }
2847 if err != nil {
2848
2849
2850 t.Skipf("skipping: %v", err)
2851 }
2852
2853 fi, err := Stat(dir)
2854 if err != nil {
2855 if IsNotExist(err) {
2856
2857
2858
2859 t.Log(err)
2860 return
2861 }
2862 t.Fatal(err)
2863 }
2864 if !fi.IsDir() {
2865 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
2866 }
2867 }
2868
2869 func TestDirSeek(t *testing.T) {
2870 t.Parallel()
2871
2872 wd, err := Getwd()
2873 if err != nil {
2874 t.Fatal(err)
2875 }
2876 f, err := Open(wd)
2877 if err != nil {
2878 t.Fatal(err)
2879 }
2880 dirnames1, err := f.Readdirnames(0)
2881 if err != nil {
2882 t.Fatal(err)
2883 }
2884
2885 ret, err := f.Seek(0, 0)
2886 if err != nil {
2887 t.Fatal(err)
2888 }
2889 if ret != 0 {
2890 t.Fatalf("seek result not zero: %d", ret)
2891 }
2892
2893 dirnames2, err := f.Readdirnames(0)
2894 if err != nil {
2895 t.Fatal(err)
2896 }
2897
2898 if len(dirnames1) != len(dirnames2) {
2899 t.Fatalf("listings have different lengths: %d and %d\n", len(dirnames1), len(dirnames2))
2900 }
2901 for i, n1 := range dirnames1 {
2902 n2 := dirnames2[i]
2903 if n1 != n2 {
2904 t.Fatalf("different name i=%d n1=%s n2=%s\n", i, n1, n2)
2905 }
2906 }
2907 }
2908
2909 func TestReaddirSmallSeek(t *testing.T) {
2910
2911
2912
2913 t.Parallel()
2914
2915 wd, err := Getwd()
2916 if err != nil {
2917 t.Fatal(err)
2918 }
2919 df, err := Open(filepath.Join(wd, "testdata", "issue37161"))
2920 if err != nil {
2921 t.Fatal(err)
2922 }
2923 names1, err := df.Readdirnames(1)
2924 if err != nil {
2925 t.Fatal(err)
2926 }
2927 if _, err = df.Seek(0, 0); err != nil {
2928 t.Fatal(err)
2929 }
2930 names2, err := df.Readdirnames(0)
2931 if err != nil {
2932 t.Fatal(err)
2933 }
2934 if len(names2) != 3 {
2935 t.Fatalf("first names: %v, second names: %v", names1, names2)
2936 }
2937 }
2938
2939
2940
2941 func isDeadlineExceeded(err error) bool {
2942 if !IsTimeout(err) {
2943 return false
2944 }
2945 if !errors.Is(err, ErrDeadlineExceeded) {
2946 return false
2947 }
2948 return true
2949 }
2950
2951
2952 func TestOpenFileKeepsPermissions(t *testing.T) {
2953 t.Parallel()
2954
2955 dir := t.TempDir()
2956 name := filepath.Join(dir, "x")
2957 f, err := Create(name)
2958 if err != nil {
2959 t.Fatal(err)
2960 }
2961 if err := f.Close(); err != nil {
2962 t.Error(err)
2963 }
2964 f, err = OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, 0)
2965 if err != nil {
2966 t.Fatal(err)
2967 }
2968 if fi, err := f.Stat(); err != nil {
2969 t.Error(err)
2970 } else if fi.Mode()&0222 == 0 {
2971 t.Errorf("f.Stat.Mode after OpenFile is %v, should be writable", fi.Mode())
2972 }
2973 if err := f.Close(); err != nil {
2974 t.Error(err)
2975 }
2976 if fi, err := Stat(name); err != nil {
2977 t.Error(err)
2978 } else if fi.Mode()&0222 == 0 {
2979 t.Errorf("Stat after OpenFile is %v, should be writable", fi.Mode())
2980 }
2981 }
2982
2983 func forceMFTUpdateOnWindows(t *testing.T, path string) {
2984 t.Helper()
2985
2986 if runtime.GOOS != "windows" {
2987 return
2988 }
2989
2990
2991
2992 if err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
2993 if err != nil {
2994 t.Fatal(err)
2995 }
2996 info, err := d.Info()
2997 if err != nil {
2998 t.Fatal(err)
2999 }
3000 stat, err := Stat(path)
3001 if err != nil {
3002 t.Fatal(err)
3003 }
3004 if stat.ModTime() == info.ModTime() {
3005 return nil
3006 }
3007 if err := Chtimes(path, stat.ModTime(), stat.ModTime()); err != nil {
3008 t.Log(err)
3009 }
3010 return nil
3011 }); err != nil {
3012 t.Fatal(err)
3013 }
3014 }
3015
3016 func TestDirFS(t *testing.T) {
3017 t.Parallel()
3018
3019 forceMFTUpdateOnWindows(t, "./testdata/dirfs")
3020
3021 fsys := DirFS("./testdata/dirfs")
3022 if err := fstest.TestFS(fsys, "a", "b", "dir/x"); err != nil {
3023 t.Fatal(err)
3024 }
3025
3026 rdfs, ok := fsys.(fs.ReadDirFS)
3027 if !ok {
3028 t.Error("expected DirFS result to implement fs.ReadDirFS")
3029 }
3030 if _, err := rdfs.ReadDir("nonexistent"); err == nil {
3031 t.Error("fs.ReadDir of nonexistent directory succeeded")
3032 }
3033
3034
3035
3036 const nonesuch = "dir/nonesuch"
3037 _, err := fsys.Open(nonesuch)
3038 if err == nil {
3039 t.Error("fs.Open of nonexistent file succeeded")
3040 } else {
3041 if !strings.Contains(err.Error(), nonesuch) {
3042 t.Errorf("error %q does not contain %q", err, nonesuch)
3043 }
3044 if strings.Contains(err.(*PathError).Path, "testdata") {
3045 t.Errorf("error %q contains %q", err, "testdata")
3046 }
3047 }
3048
3049
3050 d := DirFS(".")
3051 _, err = d.Open(`testdata\dirfs`)
3052 if err == nil {
3053 t.Fatalf(`Open testdata\dirfs succeeded`)
3054 }
3055
3056
3057 _, err = d.Open(`NUL`)
3058 if err == nil {
3059 t.Errorf(`Open NUL succeeded`)
3060 }
3061 }
3062
3063 func TestDirFSRootDir(t *testing.T) {
3064 t.Parallel()
3065
3066 cwd, err := Getwd()
3067 if err != nil {
3068 t.Fatal(err)
3069 }
3070 cwd = cwd[len(filepath.VolumeName(cwd)):]
3071 cwd = filepath.ToSlash(cwd)
3072 cwd = strings.TrimPrefix(cwd, "/")
3073
3074
3075 d := DirFS("/")
3076 f, err := d.Open(cwd + "/testdata/dirfs/a")
3077 if err != nil {
3078 t.Fatal(err)
3079 }
3080 f.Close()
3081 }
3082
3083 func TestDirFSEmptyDir(t *testing.T) {
3084 t.Parallel()
3085
3086 d := DirFS("")
3087 cwd, _ := Getwd()
3088 for _, path := range []string{
3089 "testdata/dirfs/a",
3090 filepath.ToSlash(cwd) + "/testdata/dirfs/a",
3091 } {
3092 _, err := d.Open(path)
3093 if err == nil {
3094 t.Fatalf(`DirFS("").Open(%q) succeeded`, path)
3095 }
3096 }
3097 }
3098
3099 func TestDirFSPathsValid(t *testing.T) {
3100 if runtime.GOOS == "windows" {
3101 t.Skipf("skipping on Windows")
3102 }
3103 t.Parallel()
3104
3105 d := t.TempDir()
3106 if err := WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil {
3107 t.Fatal(err)
3108 }
3109 if err := WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil {
3110 t.Fatal(err)
3111 }
3112
3113 fsys := DirFS(d)
3114 err := fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error {
3115 if fs.ValidPath(e.Name()) {
3116 t.Logf("%q ok", e.Name())
3117 } else {
3118 t.Errorf("%q INVALID", e.Name())
3119 }
3120 return nil
3121 })
3122 if err != nil {
3123 t.Fatal(err)
3124 }
3125 }
3126
3127 func TestReadFileProc(t *testing.T) {
3128 t.Parallel()
3129
3130
3131
3132
3133
3134
3135 name := "/proc/sys/fs/pipe-max-size"
3136 if _, err := Stat(name); err != nil {
3137 t.Skip(err)
3138 }
3139 data, err := ReadFile(name)
3140 if err != nil {
3141 t.Fatal(err)
3142 }
3143 if len(data) == 0 || data[len(data)-1] != '\n' {
3144 t.Fatalf("read %s: not newline-terminated: %q", name, data)
3145 }
3146 }
3147
3148 func TestDirFSReadFileProc(t *testing.T) {
3149 t.Parallel()
3150
3151 fsys := DirFS("/")
3152 name := "proc/sys/fs/pipe-max-size"
3153 if _, err := fs.Stat(fsys, name); err != nil {
3154 t.Skip()
3155 }
3156 data, err := fs.ReadFile(fsys, name)
3157 if err != nil {
3158 t.Fatal(err)
3159 }
3160 if len(data) == 0 || data[len(data)-1] != '\n' {
3161 t.Fatalf("read %s: not newline-terminated: %q", name, data)
3162 }
3163 }
3164
3165 func TestWriteStringAlloc(t *testing.T) {
3166 if runtime.GOOS == "js" {
3167 t.Skip("js allocates a lot during File.WriteString")
3168 }
3169 d := t.TempDir()
3170 f, err := Create(filepath.Join(d, "whiteboard.txt"))
3171 if err != nil {
3172 t.Fatal(err)
3173 }
3174 defer f.Close()
3175 allocs := testing.AllocsPerRun(100, func() {
3176 f.WriteString("I will not allocate when passed a string longer than 32 bytes.\n")
3177 })
3178 if allocs != 0 {
3179 t.Errorf("expected 0 allocs for File.WriteString, got %v", allocs)
3180 }
3181 }
3182
3183
3184 func TestPipeIOCloseRace(t *testing.T) {
3185
3186 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
3187 t.Skipf("skipping on %s: no pipes", runtime.GOOS)
3188 }
3189 t.Parallel()
3190
3191 r, w, err := Pipe()
3192 if err != nil {
3193 t.Fatal(err)
3194 }
3195
3196 var wg sync.WaitGroup
3197 wg.Add(3)
3198
3199 go func() {
3200 defer wg.Done()
3201 for {
3202 n, err := w.Write([]byte("hi"))
3203 if err != nil {
3204
3205
3206 switch {
3207 case errors.Is(err, ErrClosed),
3208 strings.Contains(err.Error(), "broken pipe"),
3209 strings.Contains(err.Error(), "pipe is being closed"),
3210 strings.Contains(err.Error(), "hungup channel"):
3211
3212 default:
3213
3214 t.Error(err)
3215 }
3216 return
3217 }
3218 if n != 2 {
3219 t.Errorf("wrote %d bytes, expected 2", n)
3220 return
3221 }
3222 }
3223 }()
3224
3225 go func() {
3226 defer wg.Done()
3227 for {
3228 var buf [2]byte
3229 n, err := r.Read(buf[:])
3230 if err != nil {
3231 if err != io.EOF && !errors.Is(err, ErrClosed) {
3232 t.Error(err)
3233 }
3234 return
3235 }
3236 if n != 2 {
3237 t.Errorf("read %d bytes, want 2", n)
3238 }
3239 }
3240 }()
3241
3242 go func() {
3243 defer wg.Done()
3244
3245
3246
3247
3248 time.Sleep(time.Millisecond)
3249
3250 if err := r.Close(); err != nil {
3251 t.Error(err)
3252 }
3253 if err := w.Close(); err != nil {
3254 t.Error(err)
3255 }
3256 }()
3257
3258 wg.Wait()
3259 }
3260
3261
3262 func TestPipeCloseRace(t *testing.T) {
3263
3264 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
3265 t.Skipf("skipping on %s: no pipes", runtime.GOOS)
3266 }
3267 t.Parallel()
3268
3269 r, w, err := Pipe()
3270 if err != nil {
3271 t.Fatal(err)
3272 }
3273 var wg sync.WaitGroup
3274 c := make(chan error, 4)
3275 f := func() {
3276 defer wg.Done()
3277 c <- r.Close()
3278 c <- w.Close()
3279 }
3280 wg.Add(2)
3281 go f()
3282 go f()
3283 nils, errs := 0, 0
3284 for i := 0; i < 4; i++ {
3285 err := <-c
3286 if err == nil {
3287 nils++
3288 } else {
3289 errs++
3290 }
3291 }
3292 if nils != 2 || errs != 2 {
3293 t.Errorf("got nils %d errs %d, want 2 2", nils, errs)
3294 }
3295 }
3296
3297 func TestRandomLen(t *testing.T) {
3298 for range 5 {
3299 dir, err := MkdirTemp(t.TempDir(), "*")
3300 if err != nil {
3301 t.Fatal(err)
3302 }
3303 base := filepath.Base(dir)
3304 if len(base) > 10 {
3305 t.Errorf("MkdirTemp returned len %d: %s", len(base), base)
3306 }
3307 }
3308 for range 5 {
3309 f, err := CreateTemp(t.TempDir(), "*")
3310 if err != nil {
3311 t.Fatal(err)
3312 }
3313 base := filepath.Base(f.Name())
3314 f.Close()
3315 if len(base) > 10 {
3316 t.Errorf("CreateTemp returned len %d: %s", len(base), base)
3317 }
3318 }
3319 }
3320
3321 func TestCopyFS(t *testing.T) {
3322 t.Parallel()
3323
3324
3325 forceMFTUpdateOnWindows(t, "./testdata/dirfs")
3326 fsys := DirFS("./testdata/dirfs")
3327 tmpDir := t.TempDir()
3328 if err := CopyFS(tmpDir, fsys); err != nil {
3329 t.Fatal("CopyFS:", err)
3330 }
3331 forceMFTUpdateOnWindows(t, tmpDir)
3332 tmpFsys := DirFS(tmpDir)
3333 if err := fstest.TestFS(tmpFsys, "a", "b", "dir/x"); err != nil {
3334 t.Fatal("TestFS:", err)
3335 }
3336 if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
3337 if d.IsDir() {
3338 return nil
3339 }
3340
3341 data, err := fs.ReadFile(fsys, path)
3342 if err != nil {
3343 return err
3344 }
3345 newData, err := fs.ReadFile(tmpFsys, path)
3346 if err != nil {
3347 return err
3348 }
3349 if !bytes.Equal(data, newData) {
3350 return errors.New("file " + path + " contents differ")
3351 }
3352 return nil
3353 }); err != nil {
3354 t.Fatal("comparing two directories:", err)
3355 }
3356
3357
3358
3359 if err := CopyFS(tmpDir, fsys); !errors.Is(err, fs.ErrExist) {
3360 t.Errorf("CopyFS should have failed and returned error when there is"+
3361 "any existing file in the destination directory (in disk filesystem), "+
3362 "got: %v, expected any error that indicates <file exists>", err)
3363 }
3364
3365
3366 fsys = fstest.MapFS{
3367 "william": {Data: []byte("Shakespeare\n")},
3368 "carl": {Data: []byte("Gauss\n")},
3369 "daVinci": {Data: []byte("Leonardo\n")},
3370 "einstein": {Data: []byte("Albert\n")},
3371 "dir/newton": {Data: []byte("Sir Isaac\n")},
3372 }
3373 tmpDir = t.TempDir()
3374 if err := CopyFS(tmpDir, fsys); err != nil {
3375 t.Fatal("CopyFS:", err)
3376 }
3377 forceMFTUpdateOnWindows(t, tmpDir)
3378 tmpFsys = DirFS(tmpDir)
3379 if err := fstest.TestFS(tmpFsys, "william", "carl", "daVinci", "einstein", "dir/newton"); err != nil {
3380 t.Fatal("TestFS:", err)
3381 }
3382 if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
3383 if d.IsDir() {
3384 return nil
3385 }
3386
3387 data, err := fs.ReadFile(fsys, path)
3388 if err != nil {
3389 return err
3390 }
3391 newData, err := fs.ReadFile(tmpFsys, path)
3392 if err != nil {
3393 return err
3394 }
3395 if !bytes.Equal(data, newData) {
3396 return errors.New("file " + path + " contents differ")
3397 }
3398 return nil
3399 }); err != nil {
3400 t.Fatal("comparing two directories:", err)
3401 }
3402
3403
3404
3405 if err := CopyFS(tmpDir, fsys); !errors.Is(err, fs.ErrExist) {
3406 t.Errorf("CopyFS should have failed and returned error when there is"+
3407 "any existing file in the destination directory (in memory filesystem), "+
3408 "got: %v, expected any error that indicates <file exists>", err)
3409 }
3410 }
3411
3412 func TestCopyFSWithSymlinks(t *testing.T) {
3413
3414 testenv.MustHaveSymlink(t)
3415
3416
3417 tmpDir := t.TempDir()
3418 outsideDir, err := MkdirTemp(tmpDir, "copyfs_out_")
3419 if err != nil {
3420 t.Fatalf("MkdirTemp: %v", err)
3421 }
3422 outsideFile := filepath.Join(outsideDir, "file.out.txt")
3423
3424 if err := WriteFile(outsideFile, []byte("Testing CopyFS outside"), 0644); err != nil {
3425 t.Fatalf("WriteFile: %v", err)
3426 }
3427
3428
3429 insideDir, err := MkdirTemp(tmpDir, "copyfs_in_")
3430 if err != nil {
3431 t.Fatalf("MkdirTemp: %v", err)
3432 }
3433 insideFile := filepath.Join(insideDir, "file.in.txt")
3434 if err := WriteFile(insideFile, []byte("Testing CopyFS inside"), 0644); err != nil {
3435 t.Fatalf("WriteFile: %v", err)
3436 }
3437
3438
3439 linkInDir := filepath.Join(insideDir, "in_symlinks")
3440 if err := Mkdir(linkInDir, 0755); err != nil {
3441 t.Fatalf("Mkdir: %v", err)
3442 }
3443 linkOutDir := filepath.Join(insideDir, "out_symlinks")
3444 if err := Mkdir(linkOutDir, 0755); err != nil {
3445 t.Fatalf("Mkdir: %v", err)
3446 }
3447
3448
3449 outLinkFile := filepath.Join(linkOutDir, "file.abs.out.link")
3450 if err := Symlink(outsideFile, outLinkFile); err != nil {
3451 t.Fatalf("Symlink: %v", err)
3452 }
3453
3454
3455 relOutsideFile, err := filepath.Rel(filepath.Join(linkOutDir, "."), outsideFile)
3456 if err != nil {
3457 t.Fatalf("filepath.Rel: %v", err)
3458 }
3459 relOutLinkFile := filepath.Join(linkOutDir, "file.rel.out.link")
3460 if err := Symlink(relOutsideFile, relOutLinkFile); err != nil {
3461 t.Fatalf("Symlink: %v", err)
3462 }
3463
3464
3465 relInsideFile, err := filepath.Rel(filepath.Join(linkInDir, "."), insideFile)
3466 if err != nil {
3467 t.Fatalf("filepath.Rel: %v", err)
3468 }
3469 relInLinkFile := filepath.Join(linkInDir, "file.rel.in.link")
3470 if err := Symlink(relInsideFile, relInLinkFile); err != nil {
3471 t.Fatalf("Symlink: %v", err)
3472 }
3473
3474
3475 forceMFTUpdateOnWindows(t, insideDir)
3476 fsys := DirFS(insideDir)
3477 tmpDupDir, err := MkdirTemp(tmpDir, "copyfs_dup_")
3478 if err != nil {
3479 t.Fatalf("MkdirTemp: %v", err)
3480 }
3481
3482
3483
3484
3485 if err := CopyFS(tmpDupDir, fsys); !errors.Is(err, ErrInvalid) {
3486 t.Fatalf("got %v, want ErrInvalid", err)
3487 }
3488 t.Skip("skip the subsequent test and wait for #49580")
3489
3490 forceMFTUpdateOnWindows(t, tmpDupDir)
3491 tmpFsys := DirFS(tmpDupDir)
3492 if err := fstest.TestFS(tmpFsys, "file.in.txt", "out_symlinks/file.abs.out.link", "out_symlinks/file.rel.out.link", "in_symlinks/file.rel.in.link"); err != nil {
3493 t.Fatal("TestFS:", err)
3494 }
3495 if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
3496 if d.IsDir() {
3497 return nil
3498 }
3499
3500 fi, err := d.Info()
3501 if err != nil {
3502 return err
3503 }
3504 if filepath.Ext(path) == ".link" {
3505 if fi.Mode()&ModeSymlink == 0 {
3506 return errors.New("original file " + path + " should be a symlink")
3507 }
3508 tmpfi, err := fs.Stat(tmpFsys, path)
3509 if err != nil {
3510 return err
3511 }
3512 if tmpfi.Mode()&ModeSymlink != 0 {
3513 return errors.New("copied file " + path + " should not be a symlink")
3514 }
3515 }
3516
3517 data, err := fs.ReadFile(fsys, path)
3518 if err != nil {
3519 return err
3520 }
3521 newData, err := fs.ReadFile(tmpFsys, path)
3522 if err != nil {
3523 return err
3524 }
3525 if !bytes.Equal(data, newData) {
3526 return errors.New("file " + path + " contents differ")
3527 }
3528
3529 var target string
3530 switch fileName := filepath.Base(path); fileName {
3531 case "file.abs.out.link", "file.rel.out.link":
3532 target = outsideFile
3533 case "file.rel.in.link":
3534 target = insideFile
3535 }
3536 if len(target) > 0 {
3537 targetData, err := ReadFile(target)
3538 if err != nil {
3539 return err
3540 }
3541 if !bytes.Equal(targetData, newData) {
3542 return errors.New("file " + path + " contents differ from target")
3543 }
3544 }
3545
3546 return nil
3547 }); err != nil {
3548 t.Fatal("comparing two directories:", err)
3549 }
3550 }
3551
View as plain text