Source file src/os/os_test.go

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

View as plain text