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 dir := makefs(t, []string{
1783 "is-a-file",
1784 "is-a-dir/",
1785 })
1786 t.Run("NoRoot", func(t *testing.T) { testOpenError(t, dir, false) })
1787 t.Run("InRoot", func(t *testing.T) { testOpenError(t, dir, true) })
1788 }
1789 func testOpenError(t *testing.T, dir string, rooted bool) {
1790 t.Parallel()
1791 var r *Root
1792 if rooted {
1793 var err error
1794 r, err = OpenRoot(dir)
1795 if err != nil {
1796 t.Fatal(err)
1797 }
1798 defer r.Close()
1799 }
1800 for _, tt := range []struct {
1801 path string
1802 mode int
1803 error error
1804 }{{
1805 "no-such-file",
1806 O_RDONLY,
1807 syscall.ENOENT,
1808 }, {
1809 "is-a-dir",
1810 O_WRONLY,
1811 syscall.EISDIR,
1812 }, {
1813 "is-a-file/no-such-file",
1814 O_WRONLY,
1815 syscall.ENOTDIR,
1816 }} {
1817 var f *File
1818 var err error
1819 var name string
1820 if rooted {
1821 name = fmt.Sprintf("Root(%q).OpenFile(%q, %d)", dir, tt.path, tt.mode)
1822 f, err = r.OpenFile(tt.path, tt.mode, 0)
1823 } else {
1824 path := filepath.Join(dir, tt.path)
1825 name = fmt.Sprintf("OpenFile(%q, %d)", path, tt.mode)
1826 f, err = OpenFile(path, tt.mode, 0)
1827 }
1828 if err == nil {
1829 t.Errorf("%v succeeded", name)
1830 f.Close()
1831 continue
1832 }
1833 perr, ok := err.(*PathError)
1834 if !ok {
1835 t.Errorf("%v returns error of %T type; want *PathError", name, err)
1836 }
1837 if perr.Err != tt.error {
1838 if runtime.GOOS == "plan9" {
1839 syscallErrStr := perr.Err.Error()
1840 expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1)
1841 if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
1842
1843
1844
1845 if tt.error == syscall.EISDIR &&
1846 (strings.HasSuffix(syscallErrStr, syscall.EPERM.Error()) ||
1847 strings.HasSuffix(syscallErrStr, syscall.EACCES.Error())) {
1848 continue
1849 }
1850 t.Errorf("%v = _, %q; want suffix %q", name, syscallErrStr, expectedErrStr)
1851 }
1852 continue
1853 }
1854 if runtime.GOOS == "dragonfly" {
1855
1856
1857 if tt.error == syscall.EISDIR && perr.Err == syscall.EACCES {
1858 continue
1859 }
1860 }
1861 t.Errorf("%v = _, %q; want %q", name, perr.Err.Error(), tt.error.Error())
1862 }
1863 }
1864 }
1865
1866 func TestOpenNoName(t *testing.T) {
1867 f, err := Open("")
1868 if err == nil {
1869 f.Close()
1870 t.Fatal(`Open("") succeeded`)
1871 }
1872 }
1873
1874 func runBinHostname(t *testing.T) string {
1875
1876 r, w, err := Pipe()
1877 if err != nil {
1878 t.Fatal(err)
1879 }
1880 defer r.Close()
1881
1882 path, err := exec.LookPath("hostname")
1883 if err != nil {
1884 if errors.Is(err, exec.ErrNotFound) {
1885 t.Skip("skipping test; test requires hostname but it does not exist")
1886 }
1887 t.Fatal(err)
1888 }
1889
1890 argv := []string{"hostname"}
1891 if runtime.GOOS == "aix" {
1892 argv = []string{"hostname", "-s"}
1893 }
1894 p, err := StartProcess(path, argv, &ProcAttr{Files: []*File{nil, w, Stderr}})
1895 if err != nil {
1896 t.Fatal(err)
1897 }
1898 w.Close()
1899
1900 var b strings.Builder
1901 io.Copy(&b, r)
1902 _, err = p.Wait()
1903 if err != nil {
1904 t.Fatalf("run hostname Wait: %v", err)
1905 }
1906 err = p.Kill()
1907 if err == nil {
1908 t.Errorf("expected an error from Kill running 'hostname'")
1909 }
1910 output := b.String()
1911 if n := len(output); n > 0 && output[n-1] == '\n' {
1912 output = output[0 : n-1]
1913 }
1914 if output == "" {
1915 t.Fatalf("/bin/hostname produced no output")
1916 }
1917
1918 return output
1919 }
1920
1921 func testWindowsHostname(t *testing.T, hostname string) {
1922 cmd := testenv.Command(t, "hostname")
1923 out, err := cmd.Output()
1924 if err != nil {
1925 t.Fatalf("Failed to execute hostname command: %v %s", err, out)
1926 }
1927 want := strings.Trim(string(out), "\r\n")
1928 if hostname != want {
1929 t.Fatalf("Hostname() = %q != system hostname of %q", hostname, want)
1930 }
1931 }
1932
1933 func TestHostname(t *testing.T) {
1934 t.Parallel()
1935
1936 hostname, err := Hostname()
1937 if err != nil {
1938 t.Fatal(err)
1939 }
1940 if hostname == "" {
1941 t.Fatal("Hostname returned empty string and no error")
1942 }
1943 if strings.Contains(hostname, "\x00") {
1944 t.Fatalf("unexpected zero byte in hostname: %q", hostname)
1945 }
1946
1947
1948
1949 switch runtime.GOOS {
1950 case "android", "plan9":
1951
1952 return
1953 case "windows":
1954 testWindowsHostname(t, hostname)
1955 return
1956 }
1957
1958 testenv.MustHaveExec(t)
1959
1960
1961
1962
1963 want := runBinHostname(t)
1964 if hostname != want {
1965 host, _, ok := strings.Cut(hostname, ".")
1966 if !ok || host != want {
1967 t.Errorf("Hostname() = %q, want %q", hostname, want)
1968 }
1969 }
1970 }
1971
1972 func TestReadAt(t *testing.T) {
1973 t.Parallel()
1974
1975 f := newFile(t)
1976
1977 const data = "hello, world\n"
1978 io.WriteString(f, data)
1979
1980 b := make([]byte, 5)
1981 n, err := f.ReadAt(b, 7)
1982 if err != nil || n != len(b) {
1983 t.Fatalf("ReadAt 7: %d, %v", n, err)
1984 }
1985 if string(b) != "world" {
1986 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
1987 }
1988 }
1989
1990
1991
1992
1993
1994 func TestReadAtOffset(t *testing.T) {
1995 t.Parallel()
1996
1997 f := newFile(t)
1998
1999 const data = "hello, world\n"
2000 io.WriteString(f, data)
2001
2002 f.Seek(0, 0)
2003 b := make([]byte, 5)
2004
2005 n, err := f.ReadAt(b, 7)
2006 if err != nil || n != len(b) {
2007 t.Fatalf("ReadAt 7: %d, %v", n, err)
2008 }
2009 if string(b) != "world" {
2010 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
2011 }
2012
2013 n, err = f.Read(b)
2014 if err != nil || n != len(b) {
2015 t.Fatalf("Read: %d, %v", n, err)
2016 }
2017 if string(b) != "hello" {
2018 t.Fatalf("Read: have %q want %q", string(b), "hello")
2019 }
2020 }
2021
2022
2023 func TestReadAtNegativeOffset(t *testing.T) {
2024 t.Parallel()
2025
2026 f := newFile(t)
2027
2028 const data = "hello, world\n"
2029 io.WriteString(f, data)
2030
2031 f.Seek(0, 0)
2032 b := make([]byte, 5)
2033
2034 n, err := f.ReadAt(b, -10)
2035
2036 const wantsub = "negative offset"
2037 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 {
2038 t.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub)
2039 }
2040 }
2041
2042 func TestWriteAt(t *testing.T) {
2043 t.Parallel()
2044
2045 f := newFile(t)
2046
2047 const data = "hello, world\n"
2048 io.WriteString(f, data)
2049
2050 n, err := f.WriteAt([]byte("WORLD"), 7)
2051 if err != nil || n != 5 {
2052 t.Fatalf("WriteAt 7: %d, %v", n, err)
2053 }
2054
2055 b, err := ReadFile(f.Name())
2056 if err != nil {
2057 t.Fatalf("ReadFile %s: %v", f.Name(), err)
2058 }
2059 if string(b) != "hello, WORLD\n" {
2060 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
2061 }
2062 }
2063
2064
2065 func TestWriteAtNegativeOffset(t *testing.T) {
2066 t.Parallel()
2067
2068 f := newFile(t)
2069
2070 n, err := f.WriteAt([]byte("WORLD"), -10)
2071
2072 const wantsub = "negative offset"
2073 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 {
2074 t.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub)
2075 }
2076 }
2077
2078
2079 func TestWriteAtInAppendMode(t *testing.T) {
2080 t.Chdir(t.TempDir())
2081 f, err := OpenFile("write_at_in_append_mode.txt", O_APPEND|O_CREATE, 0666)
2082 if err != nil {
2083 t.Fatalf("OpenFile: %v", err)
2084 }
2085 defer f.Close()
2086
2087 _, err = f.WriteAt([]byte(""), 1)
2088 if err != ErrWriteAtInAppendMode {
2089 t.Fatalf("f.WriteAt returned %v, expected %v", err, ErrWriteAtInAppendMode)
2090 }
2091 }
2092
2093 func writeFile(t *testing.T, r *Root, fname string, flag int, text string) string {
2094 t.Helper()
2095 var f *File
2096 var err error
2097 if r == nil {
2098 f, err = OpenFile(fname, flag, 0666)
2099 } else {
2100 f, err = r.OpenFile(fname, flag, 0666)
2101 }
2102 if err != nil {
2103 t.Fatalf("Open: %v", err)
2104 }
2105 n, err := io.WriteString(f, text)
2106 if err != nil {
2107 t.Fatalf("WriteString: %d, %v", n, err)
2108 }
2109 f.Close()
2110 data, err := ReadFile(fname)
2111 if err != nil {
2112 t.Fatalf("ReadFile: %v", err)
2113 }
2114 return string(data)
2115 }
2116
2117 func TestAppend(t *testing.T) {
2118 testMaybeRooted(t, func(t *testing.T, r *Root) {
2119 const f = "append.txt"
2120 s := writeFile(t, r, f, O_CREATE|O_TRUNC|O_RDWR, "new")
2121 if s != "new" {
2122 t.Fatalf("writeFile: have %q want %q", s, "new")
2123 }
2124 s = writeFile(t, r, f, O_APPEND|O_RDWR, "|append")
2125 if s != "new|append" {
2126 t.Fatalf("writeFile: have %q want %q", s, "new|append")
2127 }
2128 s = writeFile(t, r, f, O_CREATE|O_APPEND|O_RDWR, "|append")
2129 if s != "new|append|append" {
2130 t.Fatalf("writeFile: have %q want %q", s, "new|append|append")
2131 }
2132 err := Remove(f)
2133 if err != nil {
2134 t.Fatalf("Remove: %v", err)
2135 }
2136 s = writeFile(t, r, f, O_CREATE|O_APPEND|O_RDWR, "new&append")
2137 if s != "new&append" {
2138 t.Fatalf("writeFile: after append have %q want %q", s, "new&append")
2139 }
2140 s = writeFile(t, r, f, O_CREATE|O_RDWR, "old")
2141 if s != "old&append" {
2142 t.Fatalf("writeFile: after create have %q want %q", s, "old&append")
2143 }
2144 s = writeFile(t, r, f, O_CREATE|O_TRUNC|O_RDWR, "new")
2145 if s != "new" {
2146 t.Fatalf("writeFile: after truncate have %q want %q", s, "new")
2147 }
2148 })
2149 }
2150
2151
2152 func TestFilePermissions(t *testing.T) {
2153 if Getuid() == 0 {
2154 t.Skip("skipping test when running as root")
2155 }
2156 for _, test := range []struct {
2157 name string
2158 mode FileMode
2159 }{
2160 {"r", 0o444},
2161 {"w", 0o222},
2162 {"rw", 0o666},
2163 } {
2164 t.Run(test.name, func(t *testing.T) {
2165 switch runtime.GOOS {
2166 case "windows":
2167 if test.mode&0444 == 0 {
2168 t.Skip("write-only files not supported on " + runtime.GOOS)
2169 }
2170 case "wasip1":
2171 t.Skip("file permissions not supported on " + runtime.GOOS)
2172 }
2173 testMaybeRooted(t, func(t *testing.T, r *Root) {
2174 const filename = "f"
2175 var f *File
2176 var err error
2177 if r == nil {
2178 f, err = OpenFile(filename, O_RDWR|O_CREATE|O_EXCL, test.mode)
2179 } else {
2180 f, err = r.OpenFile(filename, O_RDWR|O_CREATE|O_EXCL, test.mode)
2181 }
2182 if err != nil {
2183 t.Fatal(err)
2184 }
2185 f.Close()
2186 b, err := ReadFile(filename)
2187 if test.mode&0o444 != 0 {
2188 if err != nil {
2189 t.Errorf("ReadFile = %v; want success", err)
2190 }
2191 } else {
2192 if err == nil {
2193 t.Errorf("ReadFile = %q, <nil>; want failure", string(b))
2194 }
2195 }
2196 _, err = Stat(filename)
2197 if err != nil {
2198 t.Errorf("Stat = %v; want success", err)
2199 }
2200 err = WriteFile(filename, nil, 0666)
2201 if test.mode&0o222 != 0 {
2202 if err != nil {
2203 t.Errorf("WriteFile = %v; want success", err)
2204 b, err := ReadFile(filename)
2205 t.Errorf("ReadFile: %v", err)
2206 t.Errorf("file contents: %q", b)
2207 }
2208 } else {
2209 if err == nil {
2210 t.Errorf("WriteFile(%q) = <nil>; want failure", filename)
2211 st, err := Stat(filename)
2212 if err == nil {
2213 t.Errorf("mode: %s", st.Mode())
2214 }
2215 b, err := ReadFile(filename)
2216 t.Errorf("ReadFile: %v", err)
2217 t.Errorf("file contents: %q", b)
2218 }
2219 }
2220 })
2221 })
2222 }
2223
2224 }
2225
2226
2227 func TestFileRDWRFlags(t *testing.T) {
2228 for _, test := range []struct {
2229 name string
2230 flag int
2231 }{
2232 {"O_RDONLY", O_RDONLY},
2233 {"O_WRONLY", O_WRONLY},
2234 {"O_RDWR", O_RDWR},
2235 } {
2236 t.Run(test.name, func(t *testing.T) {
2237 testMaybeRooted(t, func(t *testing.T, r *Root) {
2238 const filename = "f"
2239 content := []byte("content")
2240 if err := WriteFile(filename, content, 0666); err != nil {
2241 t.Fatal(err)
2242 }
2243 var f *File
2244 var err error
2245 if r == nil {
2246 f, err = OpenFile(filename, test.flag, 0)
2247 } else {
2248 f, err = r.OpenFile(filename, test.flag, 0)
2249 }
2250 if err != nil {
2251 t.Fatal(err)
2252 }
2253 defer f.Close()
2254 got, err := io.ReadAll(f)
2255 if test.flag == O_WRONLY {
2256 if err == nil {
2257 t.Errorf("read file: %q, %v; want error", got, err)
2258 }
2259 } else {
2260 if err != nil || !bytes.Equal(got, content) {
2261 t.Errorf("read file: %q, %v; want %q, <nil>", got, err, content)
2262 }
2263 }
2264 if _, err := f.Seek(0, 0); err != nil {
2265 t.Fatalf("f.Seek: %v", err)
2266 }
2267 newcontent := []byte("CONTENT")
2268 _, err = f.Write(newcontent)
2269 if test.flag == O_RDONLY {
2270 if err == nil {
2271 t.Errorf("write file: succeeded, want error")
2272 }
2273 } else {
2274 if err != nil {
2275 t.Errorf("write file: %v, want success", err)
2276 }
2277 }
2278 f.Close()
2279 got, err = ReadFile(filename)
2280 if err != nil {
2281 t.Fatal(err)
2282 }
2283 want := content
2284 if test.flag != O_RDONLY {
2285 want = newcontent
2286 }
2287 if !bytes.Equal(got, want) {
2288 t.Fatalf("after write, file contains %q, want %q", got, want)
2289 }
2290 })
2291 })
2292 }
2293 }
2294
2295 func TestStatDirWithTrailingSlash(t *testing.T) {
2296 t.Parallel()
2297
2298
2299 path := t.TempDir()
2300
2301
2302 if _, err := Stat(path); err != nil {
2303 t.Fatalf("stat %s failed: %s", path, err)
2304 }
2305
2306
2307 path += "/"
2308 if _, err := Stat(path); err != nil {
2309 t.Fatalf("stat %s failed: %s", path, err)
2310 }
2311 }
2312
2313 func TestNilProcessStateString(t *testing.T) {
2314 var ps *ProcessState
2315 s := ps.String()
2316 if s != "<nil>" {
2317 t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>")
2318 }
2319 }
2320
2321 func TestSameFile(t *testing.T) {
2322 t.Chdir(t.TempDir())
2323 fa, err := Create("a")
2324 if err != nil {
2325 t.Fatalf("Create(a): %v", err)
2326 }
2327 fa.Close()
2328 fb, err := Create("b")
2329 if err != nil {
2330 t.Fatalf("Create(b): %v", err)
2331 }
2332 fb.Close()
2333
2334 ia1, err := Stat("a")
2335 if err != nil {
2336 t.Fatalf("Stat(a): %v", err)
2337 }
2338 ia2, err := Stat("a")
2339 if err != nil {
2340 t.Fatalf("Stat(a): %v", err)
2341 }
2342 if !SameFile(ia1, ia2) {
2343 t.Errorf("files should be same")
2344 }
2345
2346 ib, err := Stat("b")
2347 if err != nil {
2348 t.Fatalf("Stat(b): %v", err)
2349 }
2350 if SameFile(ia1, ib) {
2351 t.Errorf("files should be different")
2352 }
2353 }
2354
2355 func testDevNullFileInfo(t *testing.T, statname, devNullName string, fi FileInfo) {
2356 pre := fmt.Sprintf("%s(%q): ", statname, devNullName)
2357 if fi.Size() != 0 {
2358 t.Errorf(pre+"wrong file size have %d want 0", fi.Size())
2359 }
2360 if fi.Mode()&ModeDevice == 0 {
2361 t.Errorf(pre+"wrong file mode %q: ModeDevice is not set", fi.Mode())
2362 }
2363 if fi.Mode()&ModeCharDevice == 0 {
2364 t.Errorf(pre+"wrong file mode %q: ModeCharDevice is not set", fi.Mode())
2365 }
2366 if fi.Mode().IsRegular() {
2367 t.Errorf(pre+"wrong file mode %q: IsRegular returns true", fi.Mode())
2368 }
2369 }
2370
2371 func testDevNullFile(t *testing.T, devNullName string) {
2372 f, err := Open(devNullName)
2373 if err != nil {
2374 t.Fatalf("Open(%s): %v", devNullName, err)
2375 }
2376 defer f.Close()
2377
2378 fi, err := f.Stat()
2379 if err != nil {
2380 t.Fatalf("Stat(%s): %v", devNullName, err)
2381 }
2382 testDevNullFileInfo(t, "f.Stat", devNullName, fi)
2383
2384 fi, err = Stat(devNullName)
2385 if err != nil {
2386 t.Fatalf("Stat(%s): %v", devNullName, err)
2387 }
2388 testDevNullFileInfo(t, "Stat", devNullName, fi)
2389 }
2390
2391 func TestDevNullFile(t *testing.T) {
2392 t.Parallel()
2393
2394 testDevNullFile(t, DevNull)
2395 if runtime.GOOS == "windows" {
2396 testDevNullFile(t, "./nul")
2397 testDevNullFile(t, "//./nul")
2398 }
2399 }
2400
2401 var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output")
2402
2403 func TestLargeWriteToConsole(t *testing.T) {
2404 if !*testLargeWrite {
2405 t.Skip("skipping console-flooding test; enable with -large_write")
2406 }
2407 b := make([]byte, 32000)
2408 for i := range b {
2409 b[i] = '.'
2410 }
2411 b[len(b)-1] = '\n'
2412 n, err := Stdout.Write(b)
2413 if err != nil {
2414 t.Fatalf("Write to os.Stdout failed: %v", err)
2415 }
2416 if n != len(b) {
2417 t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n)
2418 }
2419 n, err = Stderr.Write(b)
2420 if err != nil {
2421 t.Fatalf("Write to os.Stderr failed: %v", err)
2422 }
2423 if n != len(b) {
2424 t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n)
2425 }
2426 }
2427
2428 func TestStatDirModeExec(t *testing.T) {
2429 if runtime.GOOS == "wasip1" {
2430 t.Skip("Chmod is not supported on " + runtime.GOOS)
2431 }
2432 t.Parallel()
2433
2434 const mode = 0111
2435
2436 path := t.TempDir()
2437 if err := Chmod(path, 0777); err != nil {
2438 t.Fatalf("Chmod %q 0777: %v", path, err)
2439 }
2440
2441 dir, err := Stat(path)
2442 if err != nil {
2443 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
2444 }
2445 if dir.Mode()&mode != mode {
2446 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode)
2447 }
2448 }
2449
2450 func TestStatStdin(t *testing.T) {
2451 switch runtime.GOOS {
2452 case "android", "plan9":
2453 t.Skipf("%s doesn't have /bin/sh", runtime.GOOS)
2454 }
2455
2456 if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
2457 st, err := Stdin.Stat()
2458 if err != nil {
2459 t.Fatalf("Stat failed: %v", err)
2460 }
2461 fmt.Println(st.Mode() & ModeNamedPipe)
2462 Exit(0)
2463 }
2464
2465 t.Parallel()
2466 exe := testenv.Executable(t)
2467
2468 fi, err := Stdin.Stat()
2469 if err != nil {
2470 t.Fatal(err)
2471 }
2472 switch mode := fi.Mode(); {
2473 case mode&ModeCharDevice != 0 && mode&ModeDevice != 0:
2474 case mode&ModeNamedPipe != 0:
2475 default:
2476 t.Fatalf("unexpected Stdin mode (%v), want ModeCharDevice or ModeNamedPipe", mode)
2477 }
2478
2479 cmd := testenv.Command(t, exe, "-test.run=^TestStatStdin$")
2480 cmd = testenv.CleanCmdEnv(cmd)
2481 cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
2482
2483 cmd.Stdin = strings.NewReader("output")
2484
2485 output, err := cmd.CombinedOutput()
2486 if err != nil {
2487 t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
2488 }
2489
2490
2491 if len(output) < 1 || output[0] != 'p' {
2492 t.Fatalf("Child process reports stdin is not pipe '%v'", string(output))
2493 }
2494 }
2495
2496 func TestStatRelativeSymlink(t *testing.T) {
2497 testenv.MustHaveSymlink(t)
2498 t.Parallel()
2499
2500 tmpdir := t.TempDir()
2501 target := filepath.Join(tmpdir, "target")
2502 f, err := Create(target)
2503 if err != nil {
2504 t.Fatal(err)
2505 }
2506 defer f.Close()
2507
2508 st, err := f.Stat()
2509 if err != nil {
2510 t.Fatal(err)
2511 }
2512
2513 link := filepath.Join(tmpdir, "link")
2514 err = Symlink(filepath.Base(target), link)
2515 if err != nil {
2516 t.Fatal(err)
2517 }
2518
2519 st1, err := Stat(link)
2520 if err != nil {
2521 t.Fatal(err)
2522 }
2523
2524 if !SameFile(st, st1) {
2525 t.Error("Stat doesn't follow relative symlink")
2526 }
2527
2528 if runtime.GOOS == "windows" {
2529 Remove(link)
2530 err = Symlink(target[len(filepath.VolumeName(target)):], link)
2531 if err != nil {
2532 t.Fatal(err)
2533 }
2534
2535 st1, err := Stat(link)
2536 if err != nil {
2537 t.Fatal(err)
2538 }
2539
2540 if !SameFile(st, st1) {
2541 t.Error("Stat doesn't follow relative symlink")
2542 }
2543 }
2544 }
2545
2546 func TestReadAtEOF(t *testing.T) {
2547 t.Parallel()
2548
2549 f := newFile(t)
2550
2551 _, err := f.ReadAt(make([]byte, 10), 0)
2552 switch err {
2553 case io.EOF:
2554
2555 case nil:
2556 t.Fatalf("ReadAt succeeded")
2557 default:
2558 t.Fatalf("ReadAt failed: %s", err)
2559 }
2560 }
2561
2562 func TestLongPath(t *testing.T) {
2563 t.Parallel()
2564
2565 tmpdir := t.TempDir()
2566
2567
2568 sizes := []int{247, 248, 249, 400}
2569 for len(tmpdir) < 400 {
2570 tmpdir += "/dir3456789"
2571 }
2572 for _, sz := range sizes {
2573 t.Run(fmt.Sprintf("length=%d", sz), func(t *testing.T) {
2574 sizedTempDir := tmpdir[:sz-1] + "x"
2575
2576
2577
2578 if err := MkdirAll(sizedTempDir, 0755); err != nil {
2579 t.Fatalf("MkdirAll failed: %v", err)
2580 }
2581 data := []byte("hello world\n")
2582 if err := WriteFile(sizedTempDir+"/foo.txt", data, 0644); err != nil {
2583 t.Fatalf("os.WriteFile() failed: %v", err)
2584 }
2585 if err := Rename(sizedTempDir+"/foo.txt", sizedTempDir+"/bar.txt"); err != nil {
2586 t.Fatalf("Rename failed: %v", err)
2587 }
2588 mtime := time.Now().Truncate(time.Minute)
2589 if err := Chtimes(sizedTempDir+"/bar.txt", mtime, mtime); err != nil {
2590 t.Fatalf("Chtimes failed: %v", err)
2591 }
2592 names := []string{"bar.txt"}
2593 if testenv.HasSymlink() {
2594 if err := Symlink(sizedTempDir+"/bar.txt", sizedTempDir+"/symlink.txt"); err != nil {
2595 t.Fatalf("Symlink failed: %v", err)
2596 }
2597 names = append(names, "symlink.txt")
2598 }
2599 if testenv.HasLink() {
2600 if err := Link(sizedTempDir+"/bar.txt", sizedTempDir+"/link.txt"); err != nil {
2601 t.Fatalf("Link failed: %v", err)
2602 }
2603 names = append(names, "link.txt")
2604 }
2605 for _, wantSize := range []int64{int64(len(data)), 0} {
2606 for _, name := range names {
2607 path := sizedTempDir + "/" + name
2608 dir, err := Stat(path)
2609 if err != nil {
2610 t.Fatalf("Stat(%q) failed: %v", path, err)
2611 }
2612 filesize := size(path, t)
2613 if dir.Size() != filesize || filesize != wantSize {
2614 t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize)
2615 }
2616 if runtime.GOOS != "wasip1" {
2617 err = Chmod(path, dir.Mode())
2618 if err != nil {
2619 t.Fatalf("Chmod(%q) failed: %v", path, err)
2620 }
2621 }
2622 }
2623 if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil {
2624 t.Fatalf("Truncate failed: %v", err)
2625 }
2626 }
2627 })
2628 }
2629 }
2630
2631 func testKillProcess(t *testing.T, processKiller func(p *Process)) {
2632 t.Parallel()
2633
2634
2635 cmd := testenv.Command(t, testenv.Executable(t))
2636 cmd.Env = append(cmd.Environ(), "GO_OS_TEST_DRAIN_STDIN=1")
2637 stdout, err := cmd.StdoutPipe()
2638 if err != nil {
2639 t.Fatal(err)
2640 }
2641 stdin, err := cmd.StdinPipe()
2642 if err != nil {
2643 t.Fatal(err)
2644 }
2645 err = cmd.Start()
2646 if err != nil {
2647 t.Fatalf("Failed to start test process: %v", err)
2648 }
2649
2650 defer func() {
2651 if err := cmd.Wait(); err == nil {
2652 t.Errorf("Test process succeeded, but expected to fail")
2653 }
2654 stdin.Close()
2655 }()
2656
2657
2658
2659 io.Copy(io.Discard, stdout)
2660
2661 processKiller(cmd.Process)
2662 }
2663
2664 func TestKillStartProcess(t *testing.T) {
2665 testKillProcess(t, func(p *Process) {
2666 err := p.Kill()
2667 if err != nil {
2668 t.Fatalf("Failed to kill test process: %v", err)
2669 }
2670 })
2671 }
2672
2673 func TestGetppid(t *testing.T) {
2674 if runtime.GOOS == "plan9" {
2675
2676 t.Skipf("skipping test on plan9; see issue 8206")
2677 }
2678
2679 if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
2680 fmt.Print(Getppid())
2681 Exit(0)
2682 }
2683
2684 t.Parallel()
2685
2686 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestGetppid$")
2687 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
2688
2689
2690 output, err := cmd.CombinedOutput()
2691 if err != nil {
2692 t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
2693 }
2694
2695 childPpid := string(output)
2696 ourPid := fmt.Sprintf("%d", Getpid())
2697 if childPpid != ourPid {
2698 t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid)
2699 }
2700 }
2701
2702 func TestKillFindProcess(t *testing.T) {
2703 testKillProcess(t, func(p *Process) {
2704 p2, err := FindProcess(p.Pid)
2705 if err != nil {
2706 t.Fatalf("Failed to find test process: %v", err)
2707 }
2708 err = p2.Kill()
2709 if err != nil {
2710 t.Fatalf("Failed to kill test process: %v", err)
2711 }
2712 })
2713 }
2714
2715 var nilFileMethodTests = []struct {
2716 name string
2717 f func(*File) error
2718 }{
2719 {"Chdir", func(f *File) error { return f.Chdir() }},
2720 {"Close", func(f *File) error { return f.Close() }},
2721 {"Chmod", func(f *File) error { return f.Chmod(0) }},
2722 {"Chown", func(f *File) error { return f.Chown(0, 0) }},
2723 {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }},
2724 {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
2725 {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
2726 {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
2727 {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }},
2728 {"Stat", func(f *File) error { _, err := f.Stat(); return err }},
2729 {"Sync", func(f *File) error { return f.Sync() }},
2730 {"Truncate", func(f *File) error { return f.Truncate(0) }},
2731 {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }},
2732 {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }},
2733 {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }},
2734 }
2735
2736
2737 func TestNilFileMethods(t *testing.T) {
2738 t.Parallel()
2739
2740 for _, tt := range nilFileMethodTests {
2741 var file *File
2742 got := tt.f(file)
2743 if got != ErrInvalid {
2744 t.Errorf("%v should fail when f is nil; got %v", tt.name, got)
2745 }
2746 }
2747 }
2748
2749 func mkdirTree(t *testing.T, root string, level, max int) {
2750 if level >= max {
2751 return
2752 }
2753 level++
2754 for i := 'a'; i < 'c'; i++ {
2755 dir := filepath.Join(root, string(i))
2756 if err := Mkdir(dir, 0700); err != nil {
2757 t.Fatal(err)
2758 }
2759 mkdirTree(t, dir, level, max)
2760 }
2761 }
2762
2763
2764
2765 func TestRemoveAllRace(t *testing.T) {
2766 if runtime.GOOS == "windows" {
2767
2768
2769
2770
2771 t.Skip("skipping on windows")
2772 }
2773 if runtime.GOOS == "dragonfly" {
2774 testenv.SkipFlaky(t, 52301)
2775 }
2776
2777 n := runtime.GOMAXPROCS(16)
2778 defer runtime.GOMAXPROCS(n)
2779 root := t.TempDir()
2780 mkdirTree(t, root, 1, 6)
2781 hold := make(chan struct{})
2782 var wg sync.WaitGroup
2783 for i := 0; i < 4; i++ {
2784 wg.Add(1)
2785 go func() {
2786 defer wg.Done()
2787 <-hold
2788 err := RemoveAll(root)
2789 if err != nil {
2790 t.Errorf("unexpected error: %T, %q", err, err)
2791 }
2792 }()
2793 }
2794 close(hold)
2795 wg.Wait()
2796 }
2797
2798
2799 func TestPipeThreads(t *testing.T) {
2800 switch runtime.GOOS {
2801 case "aix":
2802 t.Skip("skipping on aix; issue 70131")
2803 case "illumos", "solaris":
2804 t.Skip("skipping on Solaris and illumos; issue 19111")
2805 case "windows":
2806 t.Skip("skipping on Windows; issue 19098")
2807 case "plan9":
2808 t.Skip("skipping on Plan 9; does not support runtime poller")
2809 case "js":
2810 t.Skip("skipping on js; no support for os.Pipe")
2811 case "wasip1":
2812 t.Skip("skipping on wasip1; no support for os.Pipe")
2813 }
2814
2815 threads := 100
2816
2817 r := make([]*File, threads)
2818 w := make([]*File, threads)
2819 for i := 0; i < threads; i++ {
2820 rp, wp, err := Pipe()
2821 if err != nil {
2822 for j := 0; j < i; j++ {
2823 r[j].Close()
2824 w[j].Close()
2825 }
2826 t.Fatal(err)
2827 }
2828 r[i] = rp
2829 w[i] = wp
2830 }
2831
2832 defer debug.SetMaxThreads(debug.SetMaxThreads(threads / 2))
2833
2834 creading := make(chan bool, threads)
2835 cdone := make(chan bool, threads)
2836 for i := 0; i < threads; i++ {
2837 go func(i int) {
2838 var b [1]byte
2839 creading <- true
2840 if _, err := r[i].Read(b[:]); err != nil {
2841 t.Error(err)
2842 }
2843 if err := r[i].Close(); err != nil {
2844 t.Error(err)
2845 }
2846 cdone <- true
2847 }(i)
2848 }
2849
2850 for i := 0; i < threads; i++ {
2851 <-creading
2852 }
2853
2854
2855
2856
2857 for i := 0; i < threads; i++ {
2858 if _, err := w[i].Write([]byte{0}); err != nil {
2859 t.Error(err)
2860 }
2861 if err := w[i].Close(); err != nil {
2862 t.Error(err)
2863 }
2864 <-cdone
2865 }
2866 }
2867
2868 func testDoubleCloseError(path string) func(*testing.T) {
2869 return func(t *testing.T) {
2870 t.Parallel()
2871
2872 file, err := Open(path)
2873 if err != nil {
2874 t.Fatal(err)
2875 }
2876 if err := file.Close(); err != nil {
2877 t.Fatalf("unexpected error from Close: %v", err)
2878 }
2879 if err := file.Close(); err == nil {
2880 t.Error("second Close did not fail")
2881 } else if pe, ok := err.(*PathError); !ok {
2882 t.Errorf("second Close: got %T, want %T", err, pe)
2883 } else if pe.Err != ErrClosed {
2884 t.Errorf("second Close: got %q, want %q", pe.Err, ErrClosed)
2885 } else {
2886 t.Logf("second close returned expected error %q", err)
2887 }
2888 }
2889 }
2890
2891 func TestDoubleCloseError(t *testing.T) {
2892 t.Parallel()
2893 t.Run("file", testDoubleCloseError(filepath.Join(sfdir, sfname)))
2894 t.Run("dir", testDoubleCloseError(sfdir))
2895 }
2896
2897 func TestUserCacheDir(t *testing.T) {
2898 t.Parallel()
2899
2900 dir, err := UserCacheDir()
2901 if err != nil {
2902 t.Skipf("skipping: %v", err)
2903 }
2904 if dir == "" {
2905 t.Fatalf("UserCacheDir returned %q; want non-empty path or error", dir)
2906 }
2907
2908 fi, err := Stat(dir)
2909 if err != nil {
2910 if IsNotExist(err) {
2911 t.Log(err)
2912 return
2913 }
2914 t.Fatal(err)
2915 }
2916 if !fi.IsDir() {
2917 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
2918 }
2919 }
2920
2921 func TestUserCacheDirXDGConfigDirEnvVar(t *testing.T) {
2922 switch runtime.GOOS {
2923 case "windows", "darwin", "plan9":
2924 t.Skip("$XDG_CACHE_HOME is effective only on Unix systems")
2925 }
2926
2927 wd, err := Getwd()
2928 if err != nil {
2929 t.Fatal(err)
2930 }
2931 t.Setenv("XDG_CACHE_HOME", wd)
2932
2933 dir, err := UserCacheDir()
2934 if err != nil {
2935 t.Fatal(err)
2936 }
2937 if dir != wd {
2938 t.Fatalf("UserCacheDir returned %q; want the value of $XDG_CACHE_HOME %q", dir, wd)
2939 }
2940
2941 t.Setenv("XDG_CACHE_HOME", "some-dir")
2942 _, err = UserCacheDir()
2943 if err == nil {
2944 t.Fatal("UserCacheDir succeeded though $XDG_CACHE_HOME contains a relative path")
2945 }
2946 }
2947
2948 func TestUserConfigDir(t *testing.T) {
2949 t.Parallel()
2950
2951 dir, err := UserConfigDir()
2952 if err != nil {
2953 t.Skipf("skipping: %v", err)
2954 }
2955 if dir == "" {
2956 t.Fatalf("UserConfigDir returned %q; want non-empty path or error", dir)
2957 }
2958
2959 fi, err := Stat(dir)
2960 if err != nil {
2961 if IsNotExist(err) {
2962 t.Log(err)
2963 return
2964 }
2965 t.Fatal(err)
2966 }
2967 if !fi.IsDir() {
2968 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
2969 }
2970 }
2971
2972 func TestUserConfigDirXDGConfigDirEnvVar(t *testing.T) {
2973 switch runtime.GOOS {
2974 case "windows", "darwin", "plan9":
2975 t.Skip("$XDG_CONFIG_HOME is effective only on Unix systems")
2976 }
2977
2978 wd, err := Getwd()
2979 if err != nil {
2980 t.Fatal(err)
2981 }
2982 t.Setenv("XDG_CONFIG_HOME", wd)
2983
2984 dir, err := UserConfigDir()
2985 if err != nil {
2986 t.Fatal(err)
2987 }
2988 if dir != wd {
2989 t.Fatalf("UserConfigDir returned %q; want the value of $XDG_CONFIG_HOME %q", dir, wd)
2990 }
2991
2992 t.Setenv("XDG_CONFIG_HOME", "some-dir")
2993 _, err = UserConfigDir()
2994 if err == nil {
2995 t.Fatal("UserConfigDir succeeded though $XDG_CONFIG_HOME contains a relative path")
2996 }
2997 }
2998
2999 func TestUserHomeDir(t *testing.T) {
3000 t.Parallel()
3001
3002 dir, err := UserHomeDir()
3003 if dir == "" && err == nil {
3004 t.Fatal("UserHomeDir returned an empty string but no error")
3005 }
3006 if err != nil {
3007
3008
3009 t.Skipf("skipping: %v", err)
3010 }
3011
3012 fi, err := Stat(dir)
3013 if err != nil {
3014 if IsNotExist(err) {
3015
3016
3017
3018 t.Log(err)
3019 return
3020 }
3021 t.Fatal(err)
3022 }
3023 if !fi.IsDir() {
3024 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
3025 }
3026 }
3027
3028 func TestDirSeek(t *testing.T) {
3029 t.Parallel()
3030
3031 wd, err := Getwd()
3032 if err != nil {
3033 t.Fatal(err)
3034 }
3035 f, err := Open(wd)
3036 if err != nil {
3037 t.Fatal(err)
3038 }
3039 dirnames1, err := f.Readdirnames(0)
3040 if err != nil {
3041 t.Fatal(err)
3042 }
3043
3044 ret, err := f.Seek(0, 0)
3045 if err != nil {
3046 t.Fatal(err)
3047 }
3048 if ret != 0 {
3049 t.Fatalf("seek result not zero: %d", ret)
3050 }
3051
3052 dirnames2, err := f.Readdirnames(0)
3053 if err != nil {
3054 t.Fatal(err)
3055 }
3056
3057 if len(dirnames1) != len(dirnames2) {
3058 t.Fatalf("listings have different lengths: %d and %d\n", len(dirnames1), len(dirnames2))
3059 }
3060 for i, n1 := range dirnames1 {
3061 n2 := dirnames2[i]
3062 if n1 != n2 {
3063 t.Fatalf("different name i=%d n1=%s n2=%s\n", i, n1, n2)
3064 }
3065 }
3066 }
3067
3068 func TestReaddirSmallSeek(t *testing.T) {
3069
3070
3071
3072 t.Parallel()
3073
3074 wd, err := Getwd()
3075 if err != nil {
3076 t.Fatal(err)
3077 }
3078 df, err := Open(filepath.Join(wd, "testdata", "issue37161"))
3079 if err != nil {
3080 t.Fatal(err)
3081 }
3082 names1, err := df.Readdirnames(1)
3083 if err != nil {
3084 t.Fatal(err)
3085 }
3086 if _, err = df.Seek(0, 0); err != nil {
3087 t.Fatal(err)
3088 }
3089 names2, err := df.Readdirnames(0)
3090 if err != nil {
3091 t.Fatal(err)
3092 }
3093 if len(names2) != 3 {
3094 t.Fatalf("first names: %v, second names: %v", names1, names2)
3095 }
3096 }
3097
3098
3099
3100 func isDeadlineExceeded(err error) bool {
3101 if !IsTimeout(err) {
3102 return false
3103 }
3104 if !errors.Is(err, ErrDeadlineExceeded) {
3105 return false
3106 }
3107 return true
3108 }
3109
3110
3111 func TestOpenFileKeepsPermissions(t *testing.T) {
3112 t.Run("OpenFile", func(t *testing.T) {
3113 testOpenFileKeepsPermissions(t, OpenFile)
3114 })
3115 t.Run("RootOpenFile", func(t *testing.T) {
3116 testOpenFileKeepsPermissions(t, func(name string, flag int, perm FileMode) (*File, error) {
3117 dir, file := filepath.Split(name)
3118 r, err := OpenRoot(dir)
3119 if err != nil {
3120 return nil, err
3121 }
3122 defer r.Close()
3123 return r.OpenFile(file, flag, perm)
3124 })
3125 })
3126 }
3127 func testOpenFileKeepsPermissions(t *testing.T, openf func(name string, flag int, perm FileMode) (*File, error)) {
3128 t.Parallel()
3129
3130 dir := t.TempDir()
3131 name := filepath.Join(dir, "x")
3132 f, err := Create(name)
3133 if err != nil {
3134 t.Fatal(err)
3135 }
3136 if err := f.Close(); err != nil {
3137 t.Error(err)
3138 }
3139 f, err = openf(name, O_WRONLY|O_CREATE|O_TRUNC, 0)
3140 if err != nil {
3141 t.Fatal(err)
3142 }
3143 if fi, err := f.Stat(); err != nil {
3144 t.Error(err)
3145 } else if fi.Mode()&0222 == 0 {
3146 t.Errorf("f.Stat.Mode after OpenFile is %v, should be writable", fi.Mode())
3147 }
3148 if err := f.Close(); err != nil {
3149 t.Error(err)
3150 }
3151 if fi, err := Stat(name); err != nil {
3152 t.Error(err)
3153 } else if fi.Mode()&0222 == 0 {
3154 t.Errorf("Stat after OpenFile is %v, should be writable", fi.Mode())
3155 }
3156 }
3157
3158 func forceMFTUpdateOnWindows(t *testing.T, path string) {
3159 t.Helper()
3160
3161 if runtime.GOOS != "windows" {
3162 return
3163 }
3164
3165
3166
3167 if err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
3168 if err != nil {
3169 t.Fatal(err)
3170 }
3171 info, err := d.Info()
3172 if err != nil {
3173 t.Fatal(err)
3174 }
3175 stat, err := Stat(path)
3176 if err != nil {
3177 t.Fatal(err)
3178 }
3179 if stat.ModTime() == info.ModTime() {
3180 return nil
3181 }
3182 if err := Chtimes(path, stat.ModTime(), stat.ModTime()); err != nil {
3183 t.Log(err)
3184 }
3185 return nil
3186 }); err != nil {
3187 t.Fatal(err)
3188 }
3189 }
3190
3191 func TestDirFS(t *testing.T) {
3192 t.Parallel()
3193 testDirFS(t, DirFS("./testdata/dirfs"))
3194 }
3195
3196 func TestRootDirFS(t *testing.T) {
3197 t.Parallel()
3198 r, err := OpenRoot("./testdata/dirfs")
3199 if err != nil {
3200 t.Fatal(err)
3201 }
3202 testDirFS(t, r.FS())
3203 }
3204
3205 func testDirFS(t *testing.T, fsys fs.FS) {
3206 forceMFTUpdateOnWindows(t, "./testdata/dirfs")
3207
3208 if err := fstest.TestFS(fsys, "a", "b", "dir/x"); err != nil {
3209 t.Fatal(err)
3210 }
3211
3212 rdfs, ok := fsys.(fs.ReadDirFS)
3213 if !ok {
3214 t.Error("expected DirFS result to implement fs.ReadDirFS")
3215 }
3216 if _, err := rdfs.ReadDir("nonexistent"); err == nil {
3217 t.Error("fs.ReadDir of nonexistent directory succeeded")
3218 }
3219
3220
3221
3222 const nonesuch = "dir/nonesuch"
3223 _, err := fsys.Open(nonesuch)
3224 if err == nil {
3225 t.Error("fs.Open of nonexistent file succeeded")
3226 } else {
3227 if !strings.Contains(err.Error(), nonesuch) {
3228 t.Errorf("error %q does not contain %q", err, nonesuch)
3229 }
3230 if strings.Contains(err.(*PathError).Path, "testdata") {
3231 t.Errorf("error %q contains %q", err, "testdata")
3232 }
3233 }
3234
3235
3236 d := DirFS(".")
3237 _, err = d.Open(`testdata\dirfs`)
3238 if err == nil {
3239 t.Fatalf(`Open testdata\dirfs succeeded`)
3240 }
3241
3242
3243 _, err = d.Open(`NUL`)
3244 if err == nil {
3245 t.Errorf(`Open NUL succeeded`)
3246 }
3247 }
3248
3249 func TestDirFSRootDir(t *testing.T) {
3250 t.Parallel()
3251
3252 cwd, err := Getwd()
3253 if err != nil {
3254 t.Fatal(err)
3255 }
3256 cwd = cwd[len(filepath.VolumeName(cwd)):]
3257 cwd = filepath.ToSlash(cwd)
3258 cwd = strings.TrimPrefix(cwd, "/")
3259
3260
3261 d := DirFS("/")
3262 f, err := d.Open(cwd + "/testdata/dirfs/a")
3263 if err != nil {
3264 t.Fatal(err)
3265 }
3266 f.Close()
3267 }
3268
3269 func TestDirFSEmptyDir(t *testing.T) {
3270 t.Parallel()
3271
3272 d := DirFS("")
3273 cwd, _ := Getwd()
3274 for _, path := range []string{
3275 "testdata/dirfs/a",
3276 filepath.ToSlash(cwd) + "/testdata/dirfs/a",
3277 } {
3278 _, err := d.Open(path)
3279 if err == nil {
3280 t.Fatalf(`DirFS("").Open(%q) succeeded`, path)
3281 }
3282 }
3283 }
3284
3285 func TestDirFSPathsValid(t *testing.T) {
3286 if runtime.GOOS == "windows" {
3287 t.Skipf("skipping on Windows")
3288 }
3289 t.Parallel()
3290
3291 d := t.TempDir()
3292 if err := WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil {
3293 t.Fatal(err)
3294 }
3295 if err := WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil {
3296 t.Fatal(err)
3297 }
3298
3299 fsys := DirFS(d)
3300 err := fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error {
3301 if fs.ValidPath(e.Name()) {
3302 t.Logf("%q ok", e.Name())
3303 } else {
3304 t.Errorf("%q INVALID", e.Name())
3305 }
3306 return nil
3307 })
3308 if err != nil {
3309 t.Fatal(err)
3310 }
3311 }
3312
3313 func TestReadFileProc(t *testing.T) {
3314 t.Parallel()
3315
3316
3317
3318
3319
3320
3321 name := "/proc/sys/fs/pipe-max-size"
3322 if _, err := Stat(name); err != nil {
3323 t.Skip(err)
3324 }
3325 data, err := ReadFile(name)
3326 if err != nil {
3327 t.Fatal(err)
3328 }
3329 if len(data) == 0 || data[len(data)-1] != '\n' {
3330 t.Fatalf("read %s: not newline-terminated: %q", name, data)
3331 }
3332 }
3333
3334 func TestDirFSReadFileProc(t *testing.T) {
3335 t.Parallel()
3336
3337 fsys := DirFS("/")
3338 name := "proc/sys/fs/pipe-max-size"
3339 if _, err := fs.Stat(fsys, name); err != nil {
3340 t.Skip()
3341 }
3342 data, err := fs.ReadFile(fsys, name)
3343 if err != nil {
3344 t.Fatal(err)
3345 }
3346 if len(data) == 0 || data[len(data)-1] != '\n' {
3347 t.Fatalf("read %s: not newline-terminated: %q", name, data)
3348 }
3349 }
3350
3351 func TestWriteStringAlloc(t *testing.T) {
3352 if runtime.GOOS == "js" {
3353 t.Skip("js allocates a lot during File.WriteString")
3354 }
3355 d := t.TempDir()
3356 f, err := Create(filepath.Join(d, "whiteboard.txt"))
3357 if err != nil {
3358 t.Fatal(err)
3359 }
3360 defer f.Close()
3361 allocs := testing.AllocsPerRun(100, func() {
3362 f.WriteString("I will not allocate when passed a string longer than 32 bytes.\n")
3363 })
3364 if allocs != 0 {
3365 t.Errorf("expected 0 allocs for File.WriteString, got %v", allocs)
3366 }
3367 }
3368
3369
3370 func TestPipeIOCloseRace(t *testing.T) {
3371
3372 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
3373 t.Skipf("skipping on %s: no pipes", runtime.GOOS)
3374 }
3375 t.Parallel()
3376
3377 r, w, err := Pipe()
3378 if err != nil {
3379 t.Fatal(err)
3380 }
3381
3382 var wg sync.WaitGroup
3383 wg.Add(3)
3384
3385 go func() {
3386 defer wg.Done()
3387 for {
3388 n, err := w.Write([]byte("hi"))
3389 if err != nil {
3390
3391
3392 switch {
3393 case errors.Is(err, ErrClosed),
3394 strings.Contains(err.Error(), "broken pipe"),
3395 strings.Contains(err.Error(), "pipe is being closed"),
3396 strings.Contains(err.Error(), "hungup channel"):
3397
3398 default:
3399
3400 t.Error(err)
3401 }
3402 return
3403 }
3404 if n != 2 {
3405 t.Errorf("wrote %d bytes, expected 2", n)
3406 return
3407 }
3408 }
3409 }()
3410
3411 go func() {
3412 defer wg.Done()
3413 for {
3414 var buf [2]byte
3415 n, err := r.Read(buf[:])
3416 if err != nil {
3417 if err != io.EOF && !errors.Is(err, ErrClosed) {
3418 t.Error(err)
3419 }
3420 return
3421 }
3422 if n != 2 {
3423 t.Errorf("read %d bytes, want 2", n)
3424 }
3425 }
3426 }()
3427
3428 go func() {
3429 defer wg.Done()
3430
3431
3432
3433
3434 time.Sleep(time.Millisecond)
3435
3436 if err := r.Close(); err != nil {
3437 t.Error(err)
3438 }
3439 if err := w.Close(); err != nil {
3440 t.Error(err)
3441 }
3442 }()
3443
3444 wg.Wait()
3445 }
3446
3447
3448 func TestPipeCloseRace(t *testing.T) {
3449
3450 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
3451 t.Skipf("skipping on %s: no pipes", runtime.GOOS)
3452 }
3453 t.Parallel()
3454
3455 r, w, err := Pipe()
3456 if err != nil {
3457 t.Fatal(err)
3458 }
3459 var wg sync.WaitGroup
3460 c := make(chan error, 4)
3461 f := func() {
3462 defer wg.Done()
3463 c <- r.Close()
3464 c <- w.Close()
3465 }
3466 wg.Add(2)
3467 go f()
3468 go f()
3469 nils, errs := 0, 0
3470 for i := 0; i < 4; i++ {
3471 err := <-c
3472 if err == nil {
3473 nils++
3474 } else {
3475 errs++
3476 }
3477 }
3478 if nils != 2 || errs != 2 {
3479 t.Errorf("got nils %d errs %d, want 2 2", nils, errs)
3480 }
3481 }
3482
3483 func TestRandomLen(t *testing.T) {
3484 for range 5 {
3485 dir, err := MkdirTemp(t.TempDir(), "*")
3486 if err != nil {
3487 t.Fatal(err)
3488 }
3489 base := filepath.Base(dir)
3490 if len(base) > 10 {
3491 t.Errorf("MkdirTemp returned len %d: %s", len(base), base)
3492 }
3493 }
3494 for range 5 {
3495 f, err := CreateTemp(t.TempDir(), "*")
3496 if err != nil {
3497 t.Fatal(err)
3498 }
3499 base := filepath.Base(f.Name())
3500 f.Close()
3501 if len(base) > 10 {
3502 t.Errorf("CreateTemp returned len %d: %s", len(base), base)
3503 }
3504 }
3505 }
3506
3507 func TestCopyFS(t *testing.T) {
3508 t.Parallel()
3509
3510
3511 forceMFTUpdateOnWindows(t, "./testdata/dirfs")
3512 fsys := DirFS("./testdata/dirfs")
3513 tmpDir := t.TempDir()
3514 if err := CopyFS(tmpDir, fsys); err != nil {
3515 t.Fatal("CopyFS:", err)
3516 }
3517 forceMFTUpdateOnWindows(t, tmpDir)
3518 tmpFsys := DirFS(tmpDir)
3519 if err := fstest.TestFS(tmpFsys, "a", "b", "dir/x"); err != nil {
3520 t.Fatal("TestFS:", err)
3521 }
3522 if err := verifyCopyFS(t, fsys, tmpFsys); err != nil {
3523 t.Fatal("comparing two directories:", err)
3524 }
3525
3526
3527
3528 if err := CopyFS(tmpDir, fsys); !errors.Is(err, fs.ErrExist) {
3529 t.Errorf("CopyFS should have failed and returned error when there is"+
3530 "any existing file in the destination directory (in disk filesystem), "+
3531 "got: %v, expected any error that indicates <file exists>", err)
3532 }
3533
3534
3535 fsys = fstest.MapFS{
3536 "william": {Data: []byte("Shakespeare\n")},
3537 "carl": {Data: []byte("Gauss\n")},
3538 "daVinci": {Data: []byte("Leonardo\n")},
3539 "einstein": {Data: []byte("Albert\n")},
3540 "dir/newton": {Data: []byte("Sir Isaac\n")},
3541 }
3542 tmpDir = t.TempDir()
3543 if err := CopyFS(tmpDir, fsys); err != nil {
3544 t.Fatal("CopyFS:", err)
3545 }
3546 forceMFTUpdateOnWindows(t, tmpDir)
3547 tmpFsys = DirFS(tmpDir)
3548 if err := fstest.TestFS(tmpFsys, "william", "carl", "daVinci", "einstein", "dir/newton"); err != nil {
3549 t.Fatal("TestFS:", err)
3550 }
3551 if err := verifyCopyFS(t, fsys, tmpFsys); err != nil {
3552 t.Fatal("comparing two directories:", err)
3553 }
3554
3555
3556
3557 if err := CopyFS(tmpDir, fsys); !errors.Is(err, fs.ErrExist) {
3558 t.Errorf("CopyFS should have failed and returned error when there is"+
3559 "any existing file in the destination directory (in memory filesystem), "+
3560 "got: %v, expected any error that indicates <file exists>", err)
3561 }
3562 }
3563
3564
3565
3566 func verifyCopyFS(t *testing.T, originFS, copiedFS fs.FS) error {
3567 testDir := filepath.Join(t.TempDir(), "test")
3568
3569
3570 if err := Mkdir(testDir, ModePerm); err != nil {
3571 return fmt.Errorf("mkdir %q failed: %v", testDir, err)
3572 }
3573 dirStat, err := Stat(testDir)
3574 if err != nil {
3575 return fmt.Errorf("stat dir %q failed: %v", testDir, err)
3576 }
3577 wantDirMode := dirStat.Mode()
3578
3579 f, err := Create(filepath.Join(testDir, "tmp"))
3580 if err != nil {
3581 return fmt.Errorf("open %q failed: %v", filepath.Join(testDir, "tmp"), err)
3582 }
3583 defer f.Close()
3584 wantFileRWStat, err := f.Stat()
3585 if err != nil {
3586 return fmt.Errorf("stat file %q failed: %v", f.Name(), err)
3587 }
3588 wantFileRWMode := wantFileRWStat.Mode()
3589
3590 return fs.WalkDir(originFS, ".", func(path string, d fs.DirEntry, err error) error {
3591 if d.IsDir() {
3592
3593 if d.Name() == "." {
3594 return nil
3595 }
3596
3597 dinfo, err := fs.Stat(copiedFS, path)
3598 if err != nil {
3599 return err
3600 }
3601
3602 if dinfo.Mode() != wantDirMode {
3603 return fmt.Errorf("dir %q mode is %v, want %v",
3604 d.Name(), dinfo.Mode(), wantDirMode)
3605 }
3606 return nil
3607 }
3608
3609 fInfo, err := originFS.Open(path)
3610 if err != nil {
3611 return err
3612 }
3613 defer fInfo.Close()
3614 copiedInfo, err := copiedFS.Open(path)
3615 if err != nil {
3616 return err
3617 }
3618 defer copiedInfo.Close()
3619
3620
3621 data, err := io.ReadAll(fInfo)
3622 if err != nil {
3623 return err
3624 }
3625 newData, err := io.ReadAll(copiedInfo)
3626 if err != nil {
3627 return err
3628 }
3629 if !bytes.Equal(data, newData) {
3630 return fmt.Errorf("file %q content is %s, want %s", path, newData, data)
3631 }
3632
3633 fStat, err := fInfo.Stat()
3634 if err != nil {
3635 return err
3636 }
3637 copiedStat, err := copiedInfo.Stat()
3638 if err != nil {
3639 return err
3640 }
3641
3642
3643
3644 if copiedStat.Mode()&0111&wantFileRWMode != fStat.Mode()&0111&wantFileRWMode {
3645 return fmt.Errorf("file %q execute mode is %v, want %v",
3646 path, copiedStat.Mode()&0111, fStat.Mode()&0111)
3647 }
3648
3649 rwMode := copiedStat.Mode() &^ 0111
3650 if rwMode != wantFileRWMode {
3651 return fmt.Errorf("file %q rw mode is %v, want %v",
3652 path, rwMode, wantFileRWStat.Mode())
3653 }
3654 return nil
3655 })
3656 }
3657
3658 func TestCopyFSWithSymlinks(t *testing.T) {
3659
3660 testenv.MustHaveSymlink(t)
3661
3662
3663 tmpDir := t.TempDir()
3664 outsideDir := filepath.Join(tmpDir, "copyfs_out")
3665 if err := Mkdir(outsideDir, 0755); err != nil {
3666 t.Fatalf("Mkdir: %v", err)
3667 }
3668 outsideFile := filepath.Join(outsideDir, "file.out.txt")
3669
3670 if err := WriteFile(outsideFile, []byte("Testing CopyFS outside"), 0644); err != nil {
3671 t.Fatalf("WriteFile: %v", err)
3672 }
3673
3674
3675 insideDir := filepath.Join(tmpDir, "copyfs_in")
3676 if err := Mkdir(insideDir, 0755); err != nil {
3677 t.Fatalf("Mkdir: %v", err)
3678 }
3679 insideFile := filepath.Join(insideDir, "file.in.txt")
3680 if err := WriteFile(insideFile, []byte("Testing CopyFS inside"), 0644); err != nil {
3681 t.Fatalf("WriteFile: %v", err)
3682 }
3683
3684
3685 linkInDir := filepath.Join(insideDir, "in_symlinks")
3686 if err := Mkdir(linkInDir, 0755); err != nil {
3687 t.Fatalf("Mkdir: %v", err)
3688 }
3689 linkOutDir := filepath.Join(insideDir, "out_symlinks")
3690 if err := Mkdir(linkOutDir, 0755); err != nil {
3691 t.Fatalf("Mkdir: %v", err)
3692 }
3693
3694
3695 outLinkFile := filepath.Join(linkOutDir, "file.abs.out.link")
3696 if err := Symlink(outsideFile, outLinkFile); err != nil {
3697 t.Fatalf("Symlink: %v", err)
3698 }
3699
3700
3701 relOutsideFile, err := filepath.Rel(filepath.Join(linkOutDir, "."), outsideFile)
3702 if err != nil {
3703 t.Fatalf("filepath.Rel: %v", err)
3704 }
3705 relOutLinkFile := filepath.Join(linkOutDir, "file.rel.out.link")
3706 if err := Symlink(relOutsideFile, relOutLinkFile); err != nil {
3707 t.Fatalf("Symlink: %v", err)
3708 }
3709
3710
3711 relInsideFile, err := filepath.Rel(filepath.Join(linkInDir, "."), insideFile)
3712 if err != nil {
3713 t.Fatalf("filepath.Rel: %v", err)
3714 }
3715 relInLinkFile := filepath.Join(linkInDir, "file.rel.in.link")
3716 if err := Symlink(relInsideFile, relInLinkFile); err != nil {
3717 t.Fatalf("Symlink: %v", err)
3718 }
3719
3720
3721 forceMFTUpdateOnWindows(t, insideDir)
3722 fsys := DirFS(insideDir)
3723 tmpDupDir := filepath.Join(tmpDir, "copyfs_dup")
3724 if err := Mkdir(tmpDupDir, 0755); err != nil {
3725 t.Fatalf("Mkdir: %v", err)
3726 }
3727
3728
3729
3730
3731 if err := CopyFS(tmpDupDir, fsys); !errors.Is(err, ErrInvalid) {
3732 t.Fatalf("got %v, want ErrInvalid", err)
3733 }
3734 t.Skip("skip the subsequent test and wait for #49580")
3735
3736 forceMFTUpdateOnWindows(t, tmpDupDir)
3737 tmpFsys := DirFS(tmpDupDir)
3738 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 {
3739 t.Fatal("TestFS:", err)
3740 }
3741 if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
3742 if d.IsDir() {
3743 return nil
3744 }
3745
3746 fi, err := d.Info()
3747 if err != nil {
3748 return err
3749 }
3750 if filepath.Ext(path) == ".link" {
3751 if fi.Mode()&ModeSymlink == 0 {
3752 return errors.New("original file " + path + " should be a symlink")
3753 }
3754 tmpfi, err := fs.Stat(tmpFsys, path)
3755 if err != nil {
3756 return err
3757 }
3758 if tmpfi.Mode()&ModeSymlink != 0 {
3759 return errors.New("copied file " + path + " should not be a symlink")
3760 }
3761 }
3762
3763 data, err := fs.ReadFile(fsys, path)
3764 if err != nil {
3765 return err
3766 }
3767 newData, err := fs.ReadFile(tmpFsys, path)
3768 if err != nil {
3769 return err
3770 }
3771 if !bytes.Equal(data, newData) {
3772 return errors.New("file " + path + " contents differ")
3773 }
3774
3775 var target string
3776 switch fileName := filepath.Base(path); fileName {
3777 case "file.abs.out.link", "file.rel.out.link":
3778 target = outsideFile
3779 case "file.rel.in.link":
3780 target = insideFile
3781 }
3782 if len(target) > 0 {
3783 targetData, err := ReadFile(target)
3784 if err != nil {
3785 return err
3786 }
3787 if !bytes.Equal(targetData, newData) {
3788 return errors.New("file " + path + " contents differ from target")
3789 }
3790 }
3791
3792 return nil
3793 }); err != nil {
3794 t.Fatal("comparing two directories:", err)
3795 }
3796 }
3797
3798 func TestAppendDoesntOverwrite(t *testing.T) {
3799 testMaybeRooted(t, func(t *testing.T, r *Root) {
3800 name := "file"
3801 if err := WriteFile(name, []byte("hello"), 0666); err != nil {
3802 t.Fatal(err)
3803 }
3804 var f *File
3805 var err error
3806 if r == nil {
3807 f, err = OpenFile(name, O_APPEND|O_WRONLY, 0)
3808 } else {
3809 f, err = r.OpenFile(name, O_APPEND|O_WRONLY, 0)
3810 }
3811 if err != nil {
3812 t.Fatal(err)
3813 }
3814 if _, err := f.Write([]byte(" world")); err != nil {
3815 f.Close()
3816 t.Fatal(err)
3817 }
3818 if err := f.Close(); err != nil {
3819 t.Fatal(err)
3820 }
3821 got, err := ReadFile(name)
3822 if err != nil {
3823 t.Fatal(err)
3824 }
3825 want := "hello world"
3826 if string(got) != want {
3827 t.Fatalf("got %q, want %q", got, want)
3828 }
3829 })
3830 }
3831
3832 func TestRemoveReadOnlyFile(t *testing.T) {
3833 testMaybeRooted(t, func(t *testing.T, r *Root) {
3834 if err := WriteFile("file", []byte("1"), 0); err != nil {
3835 t.Fatal(err)
3836 }
3837 var err error
3838 if r == nil {
3839 err = Remove("file")
3840 } else {
3841 err = r.Remove("file")
3842 }
3843 if err != nil {
3844 t.Fatalf("Remove read-only file: %v", err)
3845 }
3846 if _, err := Stat("file"); !IsNotExist(err) {
3847 t.Fatalf("Stat read-only file after removal: %v (want IsNotExist)", err)
3848 }
3849 })
3850 }
3851
3852 func TestOpenFileDevNull(t *testing.T) {
3853
3854 t.Parallel()
3855
3856 f, err := OpenFile(DevNull, O_WRONLY|O_CREATE|O_TRUNC, 0o644)
3857 if err != nil {
3858 t.Fatalf("OpenFile(DevNull): %v", err)
3859 }
3860 f.Close()
3861 }
3862
View as plain text