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