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