github.com/lovishpuri/go-40569/src@v0.0.0-20230519171745-f8623e7c56cf/os/os_test.go (about)

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