Source file src/os/os_windows_test.go

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package os_test
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"internal/poll"
    11  	"internal/syscall/windows"
    12  	"internal/syscall/windows/registry"
    13  	"internal/testenv"
    14  	"io"
    15  	"io/fs"
    16  	"os"
    17  	osexec "os/exec"
    18  	"path/filepath"
    19  	"reflect"
    20  	"runtime"
    21  	"sort"
    22  	"strings"
    23  	"syscall"
    24  	"testing"
    25  	"unicode/utf16"
    26  	"unsafe"
    27  )
    28  
    29  // For TestRawConnReadWrite.
    30  type syscallDescriptor = syscall.Handle
    31  
    32  // chdir changes the current working directory to the named directory,
    33  // and then restore the original working directory at the end of the test.
    34  func chdir(t *testing.T, dir string) {
    35  	olddir, err := os.Getwd()
    36  	if err != nil {
    37  		t.Fatalf("chdir: %v", err)
    38  	}
    39  	if err := os.Chdir(dir); err != nil {
    40  		t.Fatalf("chdir %s: %v", dir, err)
    41  	}
    42  
    43  	t.Cleanup(func() {
    44  		if err := os.Chdir(olddir); err != nil {
    45  			t.Errorf("chdir to original working directory %s: %v", olddir, err)
    46  			os.Exit(1)
    47  		}
    48  	})
    49  }
    50  
    51  func TestSameWindowsFile(t *testing.T) {
    52  	temp, err := os.MkdirTemp("", "TestSameWindowsFile")
    53  	if err != nil {
    54  		t.Fatal(err)
    55  	}
    56  	defer os.RemoveAll(temp)
    57  	chdir(t, temp)
    58  
    59  	f, err := os.Create("a")
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  	f.Close()
    64  
    65  	ia1, err := os.Stat("a")
    66  	if err != nil {
    67  		t.Fatal(err)
    68  	}
    69  
    70  	path, err := filepath.Abs("a")
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	ia2, err := os.Stat(path)
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  	if !os.SameFile(ia1, ia2) {
    79  		t.Errorf("files should be same")
    80  	}
    81  
    82  	p := filepath.VolumeName(path) + filepath.Base(path)
    83  	if err != nil {
    84  		t.Fatal(err)
    85  	}
    86  	ia3, err := os.Stat(p)
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	if !os.SameFile(ia1, ia3) {
    91  		t.Errorf("files should be same")
    92  	}
    93  }
    94  
    95  type dirLinkTest struct {
    96  	name    string
    97  	mklink  func(link, target string) error
    98  	issueNo int // correspondent issue number (for broken tests)
    99  }
   100  
   101  func testDirLinks(t *testing.T, tests []dirLinkTest) {
   102  	tmpdir, err := os.MkdirTemp("", "testDirLinks")
   103  	if err != nil {
   104  		t.Fatal(err)
   105  	}
   106  	defer os.RemoveAll(tmpdir)
   107  	chdir(t, tmpdir)
   108  
   109  	dir := filepath.Join(tmpdir, "dir")
   110  	err = os.Mkdir(dir, 0777)
   111  	if err != nil {
   112  		t.Fatal(err)
   113  	}
   114  	fi, err := os.Stat(dir)
   115  	if err != nil {
   116  		t.Fatal(err)
   117  	}
   118  	err = os.WriteFile(filepath.Join(dir, "abc"), []byte("abc"), 0644)
   119  	if err != nil {
   120  		t.Fatal(err)
   121  	}
   122  	for _, test := range tests {
   123  		link := filepath.Join(tmpdir, test.name+"_link")
   124  		err := test.mklink(link, dir)
   125  		if err != nil {
   126  			t.Errorf("creating link for %q test failed: %v", test.name, err)
   127  			continue
   128  		}
   129  
   130  		data, err := os.ReadFile(filepath.Join(link, "abc"))
   131  		if err != nil {
   132  			t.Errorf("failed to read abc file: %v", err)
   133  			continue
   134  		}
   135  		if string(data) != "abc" {
   136  			t.Errorf(`abc file is expected to have "abc" in it, but has %v`, data)
   137  			continue
   138  		}
   139  
   140  		if test.issueNo > 0 {
   141  			t.Logf("skipping broken %q test: see issue %d", test.name, test.issueNo)
   142  			continue
   143  		}
   144  
   145  		fi1, err := os.Stat(link)
   146  		if err != nil {
   147  			t.Errorf("failed to stat link %v: %v", link, err)
   148  			continue
   149  		}
   150  		if !fi1.IsDir() {
   151  			t.Errorf("%q should be a directory", link)
   152  			continue
   153  		}
   154  		if fi1.Name() != filepath.Base(link) {
   155  			t.Errorf("Stat(%q).Name() = %q, want %q", link, fi1.Name(), filepath.Base(link))
   156  			continue
   157  		}
   158  		if !os.SameFile(fi, fi1) {
   159  			t.Errorf("%q should point to %q", link, dir)
   160  			continue
   161  		}
   162  
   163  		fi2, err := os.Lstat(link)
   164  		if err != nil {
   165  			t.Errorf("failed to lstat link %v: %v", link, err)
   166  			continue
   167  		}
   168  		if m := fi2.Mode(); m&fs.ModeSymlink == 0 {
   169  			t.Errorf("%q should be a link, but is not (mode=0x%x)", link, uint32(m))
   170  			continue
   171  		}
   172  		if m := fi2.Mode(); m&fs.ModeDir != 0 {
   173  			t.Errorf("%q should be a link, not a directory (mode=0x%x)", link, uint32(m))
   174  			continue
   175  		}
   176  	}
   177  }
   178  
   179  // reparseData is used to build reparse buffer data required for tests.
   180  type reparseData struct {
   181  	substituteName namePosition
   182  	printName      namePosition
   183  	pathBuf        []uint16
   184  }
   185  
   186  type namePosition struct {
   187  	offset uint16
   188  	length uint16
   189  }
   190  
   191  func (rd *reparseData) addUTF16s(s []uint16) (offset uint16) {
   192  	off := len(rd.pathBuf) * 2
   193  	rd.pathBuf = append(rd.pathBuf, s...)
   194  	return uint16(off)
   195  }
   196  
   197  func (rd *reparseData) addString(s string) (offset, length uint16) {
   198  	p := syscall.StringToUTF16(s)
   199  	return rd.addUTF16s(p), uint16(len(p)-1) * 2 // do not include terminating NUL in the length (as per PrintNameLength and SubstituteNameLength documentation)
   200  }
   201  
   202  func (rd *reparseData) addSubstituteName(name string) {
   203  	rd.substituteName.offset, rd.substituteName.length = rd.addString(name)
   204  }
   205  
   206  func (rd *reparseData) addPrintName(name string) {
   207  	rd.printName.offset, rd.printName.length = rd.addString(name)
   208  }
   209  
   210  func (rd *reparseData) addStringNoNUL(s string) (offset, length uint16) {
   211  	p := syscall.StringToUTF16(s)
   212  	p = p[:len(p)-1]
   213  	return rd.addUTF16s(p), uint16(len(p)) * 2
   214  }
   215  
   216  func (rd *reparseData) addSubstituteNameNoNUL(name string) {
   217  	rd.substituteName.offset, rd.substituteName.length = rd.addStringNoNUL(name)
   218  }
   219  
   220  func (rd *reparseData) addPrintNameNoNUL(name string) {
   221  	rd.printName.offset, rd.printName.length = rd.addStringNoNUL(name)
   222  }
   223  
   224  // pathBuffeLen returns length of rd pathBuf in bytes.
   225  func (rd *reparseData) pathBuffeLen() uint16 {
   226  	return uint16(len(rd.pathBuf)) * 2
   227  }
   228  
   229  // Windows REPARSE_DATA_BUFFER contains union member, and cannot be
   230  // translated into Go directly. _REPARSE_DATA_BUFFER type is to help
   231  // construct alternative versions of Windows REPARSE_DATA_BUFFER with
   232  // union part of SymbolicLinkReparseBuffer or MountPointReparseBuffer type.
   233  type _REPARSE_DATA_BUFFER struct {
   234  	header windows.REPARSE_DATA_BUFFER_HEADER
   235  	detail [syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]byte
   236  }
   237  
   238  func createDirLink(link string, rdb *_REPARSE_DATA_BUFFER) error {
   239  	err := os.Mkdir(link, 0777)
   240  	if err != nil {
   241  		return err
   242  	}
   243  
   244  	linkp := syscall.StringToUTF16(link)
   245  	fd, err := syscall.CreateFile(&linkp[0], syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING,
   246  		syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
   247  	if err != nil {
   248  		return err
   249  	}
   250  	defer syscall.CloseHandle(fd)
   251  
   252  	buflen := uint32(rdb.header.ReparseDataLength) + uint32(unsafe.Sizeof(rdb.header))
   253  	var bytesReturned uint32
   254  	return syscall.DeviceIoControl(fd, windows.FSCTL_SET_REPARSE_POINT,
   255  		(*byte)(unsafe.Pointer(&rdb.header)), buflen, nil, 0, &bytesReturned, nil)
   256  }
   257  
   258  func createMountPoint(link string, target *reparseData) error {
   259  	var buf *windows.MountPointReparseBuffer
   260  	buflen := uint16(unsafe.Offsetof(buf.PathBuffer)) + target.pathBuffeLen() // see ReparseDataLength documentation
   261  	byteblob := make([]byte, buflen)
   262  	buf = (*windows.MountPointReparseBuffer)(unsafe.Pointer(&byteblob[0]))
   263  	buf.SubstituteNameOffset = target.substituteName.offset
   264  	buf.SubstituteNameLength = target.substituteName.length
   265  	buf.PrintNameOffset = target.printName.offset
   266  	buf.PrintNameLength = target.printName.length
   267  	pbuflen := len(target.pathBuf)
   268  	copy((*[2048]uint16)(unsafe.Pointer(&buf.PathBuffer[0]))[:pbuflen:pbuflen], target.pathBuf)
   269  
   270  	var rdb _REPARSE_DATA_BUFFER
   271  	rdb.header.ReparseTag = windows.IO_REPARSE_TAG_MOUNT_POINT
   272  	rdb.header.ReparseDataLength = buflen
   273  	copy(rdb.detail[:], byteblob)
   274  
   275  	return createDirLink(link, &rdb)
   276  }
   277  
   278  func TestDirectoryJunction(t *testing.T) {
   279  	var tests = []dirLinkTest{
   280  		{
   281  			// Create link similar to what mklink does, by inserting \??\ at the front of absolute target.
   282  			name: "standard",
   283  			mklink: func(link, target string) error {
   284  				var t reparseData
   285  				t.addSubstituteName(`\??\` + target)
   286  				t.addPrintName(target)
   287  				return createMountPoint(link, &t)
   288  			},
   289  		},
   290  		{
   291  			// Do as junction utility https://technet.microsoft.com/en-au/sysinternals/bb896768.aspx does - set PrintNameLength to 0.
   292  			name: "have_blank_print_name",
   293  			mklink: func(link, target string) error {
   294  				var t reparseData
   295  				t.addSubstituteName(`\??\` + target)
   296  				t.addPrintName("")
   297  				return createMountPoint(link, &t)
   298  			},
   299  		},
   300  	}
   301  	output, _ := osexec.Command("cmd", "/c", "mklink", "/?").Output()
   302  	mklinkSupportsJunctionLinks := strings.Contains(string(output), " /J ")
   303  	if mklinkSupportsJunctionLinks {
   304  		tests = append(tests,
   305  			dirLinkTest{
   306  				name: "use_mklink_cmd",
   307  				mklink: func(link, target string) error {
   308  					output, err := osexec.Command("cmd", "/c", "mklink", "/J", link, target).CombinedOutput()
   309  					if err != nil {
   310  						t.Errorf("failed to run mklink %v %v: %v %q", link, target, err, output)
   311  					}
   312  					return nil
   313  				},
   314  			},
   315  		)
   316  	} else {
   317  		t.Log(`skipping "use_mklink_cmd" test, mklink does not supports directory junctions`)
   318  	}
   319  	testDirLinks(t, tests)
   320  }
   321  
   322  func enableCurrentThreadPrivilege(privilegeName string) error {
   323  	ct, err := windows.GetCurrentThread()
   324  	if err != nil {
   325  		return err
   326  	}
   327  	var t syscall.Token
   328  	err = windows.OpenThreadToken(ct, syscall.TOKEN_QUERY|windows.TOKEN_ADJUST_PRIVILEGES, false, &t)
   329  	if err != nil {
   330  		return err
   331  	}
   332  	defer syscall.CloseHandle(syscall.Handle(t))
   333  
   334  	var tp windows.TOKEN_PRIVILEGES
   335  
   336  	privStr, err := syscall.UTF16PtrFromString(privilegeName)
   337  	if err != nil {
   338  		return err
   339  	}
   340  	err = windows.LookupPrivilegeValue(nil, privStr, &tp.Privileges[0].Luid)
   341  	if err != nil {
   342  		return err
   343  	}
   344  	tp.PrivilegeCount = 1
   345  	tp.Privileges[0].Attributes = windows.SE_PRIVILEGE_ENABLED
   346  	return windows.AdjustTokenPrivileges(t, false, &tp, 0, nil, nil)
   347  }
   348  
   349  func createSymbolicLink(link string, target *reparseData, isrelative bool) error {
   350  	var buf *windows.SymbolicLinkReparseBuffer
   351  	buflen := uint16(unsafe.Offsetof(buf.PathBuffer)) + target.pathBuffeLen() // see ReparseDataLength documentation
   352  	byteblob := make([]byte, buflen)
   353  	buf = (*windows.SymbolicLinkReparseBuffer)(unsafe.Pointer(&byteblob[0]))
   354  	buf.SubstituteNameOffset = target.substituteName.offset
   355  	buf.SubstituteNameLength = target.substituteName.length
   356  	buf.PrintNameOffset = target.printName.offset
   357  	buf.PrintNameLength = target.printName.length
   358  	if isrelative {
   359  		buf.Flags = windows.SYMLINK_FLAG_RELATIVE
   360  	}
   361  	pbuflen := len(target.pathBuf)
   362  	copy((*[2048]uint16)(unsafe.Pointer(&buf.PathBuffer[0]))[:pbuflen:pbuflen], target.pathBuf)
   363  
   364  	var rdb _REPARSE_DATA_BUFFER
   365  	rdb.header.ReparseTag = syscall.IO_REPARSE_TAG_SYMLINK
   366  	rdb.header.ReparseDataLength = buflen
   367  	copy(rdb.detail[:], byteblob)
   368  
   369  	return createDirLink(link, &rdb)
   370  }
   371  
   372  func TestDirectorySymbolicLink(t *testing.T) {
   373  	var tests []dirLinkTest
   374  	output, _ := osexec.Command("cmd", "/c", "mklink", "/?").Output()
   375  	mklinkSupportsDirectorySymbolicLinks := strings.Contains(string(output), " /D ")
   376  	if mklinkSupportsDirectorySymbolicLinks {
   377  		tests = append(tests,
   378  			dirLinkTest{
   379  				name: "use_mklink_cmd",
   380  				mklink: func(link, target string) error {
   381  					output, err := osexec.Command("cmd", "/c", "mklink", "/D", link, target).CombinedOutput()
   382  					if err != nil {
   383  						t.Errorf("failed to run mklink %v %v: %v %q", link, target, err, output)
   384  					}
   385  					return nil
   386  				},
   387  			},
   388  		)
   389  	} else {
   390  		t.Log(`skipping "use_mklink_cmd" test, mklink does not supports directory symbolic links`)
   391  	}
   392  
   393  	// The rest of these test requires SeCreateSymbolicLinkPrivilege to be held.
   394  	runtime.LockOSThread()
   395  	defer runtime.UnlockOSThread()
   396  
   397  	err := windows.ImpersonateSelf(windows.SecurityImpersonation)
   398  	if err != nil {
   399  		t.Fatal(err)
   400  	}
   401  	defer windows.RevertToSelf()
   402  
   403  	err = enableCurrentThreadPrivilege("SeCreateSymbolicLinkPrivilege")
   404  	if err != nil {
   405  		t.Skipf(`skipping some tests, could not enable "SeCreateSymbolicLinkPrivilege": %v`, err)
   406  	}
   407  	tests = append(tests,
   408  		dirLinkTest{
   409  			name: "use_os_pkg",
   410  			mklink: func(link, target string) error {
   411  				return os.Symlink(target, link)
   412  			},
   413  		},
   414  		dirLinkTest{
   415  			// Create link similar to what mklink does, by inserting \??\ at the front of absolute target.
   416  			name: "standard",
   417  			mklink: func(link, target string) error {
   418  				var t reparseData
   419  				t.addPrintName(target)
   420  				t.addSubstituteName(`\??\` + target)
   421  				return createSymbolicLink(link, &t, false)
   422  			},
   423  		},
   424  		dirLinkTest{
   425  			name: "relative",
   426  			mklink: func(link, target string) error {
   427  				var t reparseData
   428  				t.addSubstituteNameNoNUL(filepath.Base(target))
   429  				t.addPrintNameNoNUL(filepath.Base(target))
   430  				return createSymbolicLink(link, &t, true)
   431  			},
   432  		},
   433  	)
   434  	testDirLinks(t, tests)
   435  }
   436  
   437  func TestNetworkSymbolicLink(t *testing.T) {
   438  	testenv.MustHaveSymlink(t)
   439  
   440  	const _NERR_ServerNotStarted = syscall.Errno(2114)
   441  
   442  	dir, err := os.MkdirTemp("", "TestNetworkSymbolicLink")
   443  	if err != nil {
   444  		t.Fatal(err)
   445  	}
   446  	defer os.RemoveAll(dir)
   447  
   448  	chdir(t, dir)
   449  
   450  	shareName := "GoSymbolicLinkTestShare" // hope no conflictions
   451  	sharePath := filepath.Join(dir, shareName)
   452  	testDir := "TestDir"
   453  
   454  	err = os.MkdirAll(filepath.Join(sharePath, testDir), 0777)
   455  	if err != nil {
   456  		t.Fatal(err)
   457  	}
   458  
   459  	wShareName, err := syscall.UTF16PtrFromString(shareName)
   460  	if err != nil {
   461  		t.Fatal(err)
   462  	}
   463  	wSharePath, err := syscall.UTF16PtrFromString(sharePath)
   464  	if err != nil {
   465  		t.Fatal(err)
   466  	}
   467  
   468  	p := windows.SHARE_INFO_2{
   469  		Netname:     wShareName,
   470  		Type:        windows.STYPE_DISKTREE,
   471  		Remark:      nil,
   472  		Permissions: 0,
   473  		MaxUses:     1,
   474  		CurrentUses: 0,
   475  		Path:        wSharePath,
   476  		Passwd:      nil,
   477  	}
   478  
   479  	err = windows.NetShareAdd(nil, 2, (*byte)(unsafe.Pointer(&p)), nil)
   480  	if err != nil {
   481  		if err == syscall.ERROR_ACCESS_DENIED {
   482  			t.Skip("you don't have enough privileges to add network share")
   483  		}
   484  		if err == _NERR_ServerNotStarted {
   485  			t.Skip(_NERR_ServerNotStarted.Error())
   486  		}
   487  		t.Fatal(err)
   488  	}
   489  	defer func() {
   490  		err := windows.NetShareDel(nil, wShareName, 0)
   491  		if err != nil {
   492  			t.Fatal(err)
   493  		}
   494  	}()
   495  
   496  	UNCPath := `\\localhost\` + shareName + `\`
   497  
   498  	fi1, err := os.Stat(sharePath)
   499  	if err != nil {
   500  		t.Fatal(err)
   501  	}
   502  	fi2, err := os.Stat(UNCPath)
   503  	if err != nil {
   504  		t.Fatal(err)
   505  	}
   506  	if !os.SameFile(fi1, fi2) {
   507  		t.Fatalf("%q and %q should be the same directory, but not", sharePath, UNCPath)
   508  	}
   509  
   510  	target := filepath.Join(UNCPath, testDir)
   511  	link := "link"
   512  
   513  	err = os.Symlink(target, link)
   514  	if err != nil {
   515  		t.Fatal(err)
   516  	}
   517  	defer os.Remove(link)
   518  
   519  	got, err := os.Readlink(link)
   520  	if err != nil {
   521  		t.Fatal(err)
   522  	}
   523  	if got != target {
   524  		t.Errorf(`os.Readlink("%s"): got %v, want %v`, link, got, target)
   525  	}
   526  
   527  	got, err = filepath.EvalSymlinks(link)
   528  	if err != nil {
   529  		t.Fatal(err)
   530  	}
   531  	if got != target {
   532  		t.Errorf(`filepath.EvalSymlinks("%s"): got %v, want %v`, link, got, target)
   533  	}
   534  }
   535  
   536  func TestStartProcessAttr(t *testing.T) {
   537  	p, err := os.StartProcess(os.Getenv("COMSPEC"), []string{"/c", "cd"}, new(os.ProcAttr))
   538  	if err != nil {
   539  		return
   540  	}
   541  	defer p.Wait()
   542  	t.Fatalf("StartProcess expected to fail, but succeeded.")
   543  }
   544  
   545  func TestShareNotExistError(t *testing.T) {
   546  	if testing.Short() {
   547  		t.Skip("slow test that uses network; skipping")
   548  	}
   549  	_, err := os.Stat(`\\no_such_server\no_such_share\no_such_file`)
   550  	if err == nil {
   551  		t.Fatal("stat succeeded, but expected to fail")
   552  	}
   553  	if !os.IsNotExist(err) {
   554  		t.Fatalf("os.Stat failed with %q, but os.IsNotExist(err) is false", err)
   555  	}
   556  }
   557  
   558  func TestBadNetPathError(t *testing.T) {
   559  	const ERROR_BAD_NETPATH = syscall.Errno(53)
   560  	if !os.IsNotExist(ERROR_BAD_NETPATH) {
   561  		t.Fatal("os.IsNotExist(syscall.Errno(53)) is false, but want true")
   562  	}
   563  }
   564  
   565  func TestStatDir(t *testing.T) {
   566  	defer chtmpdir(t)()
   567  
   568  	f, err := os.Open(".")
   569  	if err != nil {
   570  		t.Fatal(err)
   571  	}
   572  	defer f.Close()
   573  
   574  	fi, err := f.Stat()
   575  	if err != nil {
   576  		t.Fatal(err)
   577  	}
   578  
   579  	err = os.Chdir("..")
   580  	if err != nil {
   581  		t.Fatal(err)
   582  	}
   583  
   584  	fi2, err := f.Stat()
   585  	if err != nil {
   586  		t.Fatal(err)
   587  	}
   588  
   589  	if !os.SameFile(fi, fi2) {
   590  		t.Fatal("race condition occurred")
   591  	}
   592  }
   593  
   594  func TestOpenVolumeName(t *testing.T) {
   595  	tmpdir, err := os.MkdirTemp("", "TestOpenVolumeName")
   596  	if err != nil {
   597  		t.Fatal(err)
   598  	}
   599  	defer os.RemoveAll(tmpdir)
   600  	chdir(t, tmpdir)
   601  
   602  	want := []string{"file1", "file2", "file3", "gopher.txt"}
   603  	sort.Strings(want)
   604  	for _, name := range want {
   605  		err := os.WriteFile(filepath.Join(tmpdir, name), nil, 0777)
   606  		if err != nil {
   607  			t.Fatal(err)
   608  		}
   609  	}
   610  
   611  	f, err := os.Open(filepath.VolumeName(tmpdir))
   612  	if err != nil {
   613  		t.Fatal(err)
   614  	}
   615  	defer f.Close()
   616  
   617  	have, err := f.Readdirnames(-1)
   618  	if err != nil {
   619  		t.Fatal(err)
   620  	}
   621  	sort.Strings(have)
   622  
   623  	if strings.Join(want, "/") != strings.Join(have, "/") {
   624  		t.Fatalf("unexpected file list %q, want %q", have, want)
   625  	}
   626  }
   627  
   628  func TestDeleteReadOnly(t *testing.T) {
   629  	tmpdir := t.TempDir()
   630  	p := filepath.Join(tmpdir, "a")
   631  	// This sets FILE_ATTRIBUTE_READONLY.
   632  	f, err := os.OpenFile(p, os.O_CREATE, 0400)
   633  	if err != nil {
   634  		t.Fatal(err)
   635  	}
   636  	f.Close()
   637  
   638  	if err = os.Chmod(p, 0400); err != nil {
   639  		t.Fatal(err)
   640  	}
   641  	if err = os.Remove(p); err != nil {
   642  		t.Fatal(err)
   643  	}
   644  }
   645  
   646  func TestStatSymlinkLoop(t *testing.T) {
   647  	testenv.MustHaveSymlink(t)
   648  
   649  	defer chtmpdir(t)()
   650  
   651  	err := os.Symlink("x", "y")
   652  	if err != nil {
   653  		t.Fatal(err)
   654  	}
   655  	defer os.Remove("y")
   656  
   657  	err = os.Symlink("y", "x")
   658  	if err != nil {
   659  		t.Fatal(err)
   660  	}
   661  	defer os.Remove("x")
   662  
   663  	_, err = os.Stat("x")
   664  	if _, ok := err.(*fs.PathError); !ok {
   665  		t.Errorf("expected *PathError, got %T: %v\n", err, err)
   666  	}
   667  }
   668  
   669  func TestReadStdin(t *testing.T) {
   670  	old := poll.ReadConsole
   671  	defer func() {
   672  		poll.ReadConsole = old
   673  	}()
   674  
   675  	p, err := syscall.GetCurrentProcess()
   676  	if err != nil {
   677  		t.Fatalf("Unable to get handle to current process: %v", err)
   678  	}
   679  	var stdinDuplicate syscall.Handle
   680  	err = syscall.DuplicateHandle(p, syscall.Handle(syscall.Stdin), p, &stdinDuplicate, 0, false, syscall.DUPLICATE_SAME_ACCESS)
   681  	if err != nil {
   682  		t.Fatalf("Unable to duplicate stdin: %v", err)
   683  	}
   684  	testConsole := os.NewConsoleFile(stdinDuplicate, "test")
   685  
   686  	var tests = []string{
   687  		"abc",
   688  		"äöü",
   689  		"\u3042",
   690  		"“hi”™",
   691  		"hello\x1aworld",
   692  		"\U0001F648\U0001F649\U0001F64A",
   693  	}
   694  
   695  	for _, consoleSize := range []int{1, 2, 3, 10, 16, 100, 1000} {
   696  		for _, readSize := range []int{1, 2, 3, 4, 5, 8, 10, 16, 20, 50, 100} {
   697  			for _, s := range tests {
   698  				t.Run(fmt.Sprintf("c%d/r%d/%s", consoleSize, readSize, s), func(t *testing.T) {
   699  					s16 := utf16.Encode([]rune(s))
   700  					poll.ReadConsole = func(h syscall.Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) error {
   701  						if inputControl != nil {
   702  							t.Fatalf("inputControl not nil")
   703  						}
   704  						n := int(toread)
   705  						if n > consoleSize {
   706  							n = consoleSize
   707  						}
   708  						n = copy((*[10000]uint16)(unsafe.Pointer(buf))[:n:n], s16)
   709  						s16 = s16[n:]
   710  						*read = uint32(n)
   711  						t.Logf("read %d -> %d", toread, *read)
   712  						return nil
   713  					}
   714  
   715  					var all []string
   716  					var buf []byte
   717  					chunk := make([]byte, readSize)
   718  					for {
   719  						n, err := testConsole.Read(chunk)
   720  						buf = append(buf, chunk[:n]...)
   721  						if err == io.EOF {
   722  							all = append(all, string(buf))
   723  							if len(all) >= 5 {
   724  								break
   725  							}
   726  							buf = buf[:0]
   727  						} else if err != nil {
   728  							t.Fatalf("reading %q: error: %v", s, err)
   729  						}
   730  						if len(buf) >= 2000 {
   731  							t.Fatalf("reading %q: stuck in loop: %q", s, buf)
   732  						}
   733  					}
   734  
   735  					want := strings.Split(s, "\x1a")
   736  					for len(want) < 5 {
   737  						want = append(want, "")
   738  					}
   739  					if !reflect.DeepEqual(all, want) {
   740  						t.Errorf("reading %q:\nhave %x\nwant %x", s, all, want)
   741  					}
   742  				})
   743  			}
   744  		}
   745  	}
   746  }
   747  
   748  func TestStatPagefile(t *testing.T) {
   749  	fi, err := os.Stat(`c:\pagefile.sys`)
   750  	if err == nil {
   751  		if fi.Name() == "" {
   752  			t.Fatal(`FileInfo of c:\pagefile.sys has empty name`)
   753  		}
   754  		return
   755  	}
   756  	if os.IsNotExist(err) {
   757  		t.Skip(`skipping because c:\pagefile.sys is not found`)
   758  	}
   759  	t.Fatal(err)
   760  }
   761  
   762  // syscallCommandLineToArgv calls syscall.CommandLineToArgv
   763  // and converts returned result into []string.
   764  func syscallCommandLineToArgv(cmd string) ([]string, error) {
   765  	var argc int32
   766  	argv, err := syscall.CommandLineToArgv(&syscall.StringToUTF16(cmd)[0], &argc)
   767  	if err != nil {
   768  		return nil, err
   769  	}
   770  	defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
   771  
   772  	var args []string
   773  	for _, v := range (*argv)[:argc] {
   774  		args = append(args, syscall.UTF16ToString((*v)[:]))
   775  	}
   776  	return args, nil
   777  }
   778  
   779  // compareCommandLineToArgvWithSyscall ensures that
   780  // os.CommandLineToArgv(cmd) and syscall.CommandLineToArgv(cmd)
   781  // return the same result.
   782  func compareCommandLineToArgvWithSyscall(t *testing.T, cmd string) {
   783  	syscallArgs, err := syscallCommandLineToArgv(cmd)
   784  	if err != nil {
   785  		t.Fatal(err)
   786  	}
   787  	args := os.CommandLineToArgv(cmd)
   788  	if want, have := fmt.Sprintf("%q", syscallArgs), fmt.Sprintf("%q", args); want != have {
   789  		t.Errorf("testing os.commandLineToArgv(%q) failed: have %q want %q", cmd, args, syscallArgs)
   790  		return
   791  	}
   792  }
   793  
   794  func TestCmdArgs(t *testing.T) {
   795  	tmpdir := t.TempDir()
   796  
   797  	const prog = `
   798  package main
   799  
   800  import (
   801  	"fmt"
   802  	"os"
   803  )
   804  
   805  func main() {
   806  	fmt.Printf("%q", os.Args)
   807  }
   808  `
   809  	src := filepath.Join(tmpdir, "main.go")
   810  	if err := os.WriteFile(src, []byte(prog), 0666); err != nil {
   811  		t.Fatal(err)
   812  	}
   813  
   814  	exe := filepath.Join(tmpdir, "main.exe")
   815  	cmd := osexec.Command(testenv.GoToolPath(t), "build", "-o", exe, src)
   816  	cmd.Dir = tmpdir
   817  	out, err := cmd.CombinedOutput()
   818  	if err != nil {
   819  		t.Fatalf("building main.exe failed: %v\n%s", err, out)
   820  	}
   821  
   822  	var cmds = []string{
   823  		``,
   824  		` a b c`,
   825  		` "`,
   826  		` ""`,
   827  		` """`,
   828  		` "" a`,
   829  		` "123"`,
   830  		` \"123\"`,
   831  		` \"123 456\"`,
   832  		` \\"`,
   833  		` \\\"`,
   834  		` \\\\\"`,
   835  		` \\\"x`,
   836  		` """"\""\\\"`,
   837  		` abc`,
   838  		` \\\\\""x"""y z`,
   839  		"\tb\t\"x\ty\"",
   840  		` "Брад" d e`,
   841  		// examples from https://msdn.microsoft.com/en-us/library/17w5ykft.aspx
   842  		` "abc" d e`,
   843  		` a\\b d"e f"g h`,
   844  		` a\\\"b c d`,
   845  		` a\\\\"b c" d e`,
   846  		// http://daviddeley.com/autohotkey/parameters/parameters.htm#WINARGV
   847  		// from 5.4  Examples
   848  		` CallMeIshmael`,
   849  		` "Call Me Ishmael"`,
   850  		` Cal"l Me I"shmael`,
   851  		` CallMe\"Ishmael`,
   852  		` "CallMe\"Ishmael"`,
   853  		` "Call Me Ishmael\\"`,
   854  		` "CallMe\\\"Ishmael"`,
   855  		` a\\\b`,
   856  		` "a\\\b"`,
   857  		// from 5.5  Some Common Tasks
   858  		` "\"Call Me Ishmael\""`,
   859  		` "C:\TEST A\\"`,
   860  		` "\"C:\TEST A\\\""`,
   861  		// from 5.6  The Microsoft Examples Explained
   862  		` "a b c"  d  e`,
   863  		` "ab\"c"  "\\"  d`,
   864  		` a\\\b d"e f"g h`,
   865  		` a\\\"b c d`,
   866  		` a\\\\"b c" d e`,
   867  		// from 5.7  Double Double Quote Examples (pre 2008)
   868  		` "a b c""`,
   869  		` """CallMeIshmael"""  b  c`,
   870  		` """Call Me Ishmael"""`,
   871  		` """"Call Me Ishmael"" b c`,
   872  	}
   873  	for _, cmd := range cmds {
   874  		compareCommandLineToArgvWithSyscall(t, "test"+cmd)
   875  		compareCommandLineToArgvWithSyscall(t, `"cmd line"`+cmd)
   876  		compareCommandLineToArgvWithSyscall(t, exe+cmd)
   877  
   878  		// test both syscall.EscapeArg and os.commandLineToArgv
   879  		args := os.CommandLineToArgv(exe + cmd)
   880  		out, err := osexec.Command(args[0], args[1:]...).CombinedOutput()
   881  		if err != nil {
   882  			t.Fatalf("running %q failed: %v\n%v", args, err, string(out))
   883  		}
   884  		if want, have := fmt.Sprintf("%q", args), string(out); want != have {
   885  			t.Errorf("wrong output of executing %q: have %q want %q", args, have, want)
   886  			continue
   887  		}
   888  	}
   889  }
   890  
   891  func findOneDriveDir() (string, error) {
   892  	// as per https://stackoverflow.com/questions/42519624/how-to-determine-location-of-onedrive-on-windows-7-and-8-in-c
   893  	const onedrivekey = `SOFTWARE\Microsoft\OneDrive`
   894  	k, err := registry.OpenKey(registry.CURRENT_USER, onedrivekey, registry.READ)
   895  	if err != nil {
   896  		return "", fmt.Errorf("OpenKey(%q) failed: %v", onedrivekey, err)
   897  	}
   898  	defer k.Close()
   899  
   900  	path, _, err := k.GetStringValue("UserFolder")
   901  	if err != nil {
   902  		return "", fmt.Errorf("reading UserFolder failed: %v", err)
   903  	}
   904  	return path, nil
   905  }
   906  
   907  // TestOneDrive verifies that OneDrive folder is a directory and not a symlink.
   908  func TestOneDrive(t *testing.T) {
   909  	dir, err := findOneDriveDir()
   910  	if err != nil {
   911  		t.Skipf("Skipping, because we did not find OneDrive directory: %v", err)
   912  	}
   913  	testDirStats(t, dir)
   914  }
   915  
   916  func TestWindowsDevNullFile(t *testing.T) {
   917  	testDevNullFile(t, "NUL", true)
   918  	testDevNullFile(t, "nul", true)
   919  	testDevNullFile(t, "Nul", true)
   920  
   921  	f1, err := os.Open("NUL")
   922  	if err != nil {
   923  		t.Fatal(err)
   924  	}
   925  	defer f1.Close()
   926  
   927  	fi1, err := f1.Stat()
   928  	if err != nil {
   929  		t.Fatal(err)
   930  	}
   931  
   932  	f2, err := os.Open("nul")
   933  	if err != nil {
   934  		t.Fatal(err)
   935  	}
   936  	defer f2.Close()
   937  
   938  	fi2, err := f2.Stat()
   939  	if err != nil {
   940  		t.Fatal(err)
   941  	}
   942  
   943  	if !os.SameFile(fi1, fi2) {
   944  		t.Errorf(`"NUL" and "nul" are not the same file`)
   945  	}
   946  }
   947  
   948  // TestSymlinkCreation verifies that creating a symbolic link
   949  // works on Windows when developer mode is active.
   950  // This is supported starting Windows 10 (1703, v10.0.14972).
   951  func TestSymlinkCreation(t *testing.T) {
   952  	if !testenv.HasSymlink() && !isWindowsDeveloperModeActive() {
   953  		t.Skip("Windows developer mode is not active")
   954  	}
   955  	t.Parallel()
   956  
   957  	temp := t.TempDir()
   958  	dummyFile := filepath.Join(temp, "file")
   959  	if err := os.WriteFile(dummyFile, []byte(""), 0644); err != nil {
   960  		t.Fatal(err)
   961  	}
   962  
   963  	linkFile := filepath.Join(temp, "link")
   964  	if err := os.Symlink(dummyFile, linkFile); err != nil {
   965  		t.Fatal(err)
   966  	}
   967  }
   968  
   969  // isWindowsDeveloperModeActive checks whether or not the developer mode is active on Windows 10.
   970  // Returns false for prior Windows versions.
   971  // see https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development
   972  func isWindowsDeveloperModeActive() bool {
   973  	key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock", registry.READ)
   974  	if err != nil {
   975  		return false
   976  	}
   977  
   978  	val, _, err := key.GetIntegerValue("AllowDevelopmentWithoutDevLicense")
   979  	if err != nil {
   980  		return false
   981  	}
   982  
   983  	return val != 0
   984  }
   985  
   986  // TestRootRelativeDirSymlink verifies that symlinks to paths relative to the
   987  // drive root (beginning with "\" but no volume name) are created with the
   988  // correct symlink type.
   989  // (See https://golang.org/issue/39183#issuecomment-632175728.)
   990  func TestRootRelativeDirSymlink(t *testing.T) {
   991  	testenv.MustHaveSymlink(t)
   992  	t.Parallel()
   993  
   994  	temp := t.TempDir()
   995  	dir := filepath.Join(temp, "dir")
   996  	if err := os.Mkdir(dir, 0755); err != nil {
   997  		t.Fatal(err)
   998  	}
   999  
  1000  	volumeRelDir := strings.TrimPrefix(dir, filepath.VolumeName(dir)) // leaves leading backslash
  1001  
  1002  	link := filepath.Join(temp, "link")
  1003  	err := os.Symlink(volumeRelDir, link)
  1004  	if err != nil {
  1005  		t.Fatal(err)
  1006  	}
  1007  	t.Logf("Symlink(%#q, %#q)", volumeRelDir, link)
  1008  
  1009  	f, err := os.Open(link)
  1010  	if err != nil {
  1011  		t.Fatal(err)
  1012  	}
  1013  	defer f.Close()
  1014  	if fi, err := f.Stat(); err != nil {
  1015  		t.Fatal(err)
  1016  	} else if !fi.IsDir() {
  1017  		t.Errorf("Open(%#q).Stat().IsDir() = false; want true", f.Name())
  1018  	}
  1019  }
  1020  
  1021  // TestWorkingDirectoryRelativeSymlink verifies that symlinks to paths relative
  1022  // to the current working directory for the drive, such as "C:File.txt", are
  1023  // correctly converted to absolute links of the correct symlink type (per
  1024  // https://docs.microsoft.com/en-us/windows/win32/fileio/creating-symbolic-links).
  1025  func TestWorkingDirectoryRelativeSymlink(t *testing.T) {
  1026  	testenv.MustHaveSymlink(t)
  1027  
  1028  	// Construct a directory to be symlinked.
  1029  	temp := t.TempDir()
  1030  	if v := filepath.VolumeName(temp); len(v) < 2 || v[1] != ':' {
  1031  		t.Skipf("Can't test relative symlinks: t.TempDir() (%#q) does not begin with a drive letter.", temp)
  1032  	}
  1033  
  1034  	absDir := filepath.Join(temp, `dir\sub`)
  1035  	if err := os.MkdirAll(absDir, 0755); err != nil {
  1036  		t.Fatal(err)
  1037  	}
  1038  
  1039  	// Change to the temporary directory and construct a
  1040  	// working-directory-relative symlink.
  1041  	oldwd, err := os.Getwd()
  1042  	if err != nil {
  1043  		t.Fatal(err)
  1044  	}
  1045  	defer func() {
  1046  		if err := os.Chdir(oldwd); err != nil {
  1047  			t.Fatal(err)
  1048  		}
  1049  	}()
  1050  	if err := os.Chdir(temp); err != nil {
  1051  		t.Fatal(err)
  1052  	}
  1053  	t.Logf("Chdir(%#q)", temp)
  1054  
  1055  	wdRelDir := filepath.VolumeName(temp) + `dir\sub` // no backslash after volume.
  1056  	absLink := filepath.Join(temp, "link")
  1057  	err = os.Symlink(wdRelDir, absLink)
  1058  	if err != nil {
  1059  		t.Fatal(err)
  1060  	}
  1061  	t.Logf("Symlink(%#q, %#q)", wdRelDir, absLink)
  1062  
  1063  	// Now change back to the original working directory and verify that the
  1064  	// symlink still refers to its original path and is correctly marked as a
  1065  	// directory.
  1066  	if err := os.Chdir(oldwd); err != nil {
  1067  		t.Fatal(err)
  1068  	}
  1069  	t.Logf("Chdir(%#q)", oldwd)
  1070  
  1071  	resolved, err := os.Readlink(absLink)
  1072  	if err != nil {
  1073  		t.Errorf("Readlink(%#q): %v", absLink, err)
  1074  	} else if resolved != absDir {
  1075  		t.Errorf("Readlink(%#q) = %#q; want %#q", absLink, resolved, absDir)
  1076  	}
  1077  
  1078  	linkFile, err := os.Open(absLink)
  1079  	if err != nil {
  1080  		t.Fatal(err)
  1081  	}
  1082  	defer linkFile.Close()
  1083  
  1084  	linkInfo, err := linkFile.Stat()
  1085  	if err != nil {
  1086  		t.Fatal(err)
  1087  	}
  1088  	if !linkInfo.IsDir() {
  1089  		t.Errorf("Open(%#q).Stat().IsDir() = false; want true", absLink)
  1090  	}
  1091  
  1092  	absInfo, err := os.Stat(absDir)
  1093  	if err != nil {
  1094  		t.Fatal(err)
  1095  	}
  1096  
  1097  	if !os.SameFile(absInfo, linkInfo) {
  1098  		t.Errorf("SameFile(Stat(%#q), Open(%#q).Stat()) = false; want true", absDir, absLink)
  1099  	}
  1100  }
  1101  
  1102  // TestStatOfInvalidName is regression test for issue #24999.
  1103  func TestStatOfInvalidName(t *testing.T) {
  1104  	_, err := os.Stat("*.go")
  1105  	if err == nil {
  1106  		t.Fatal(`os.Stat("*.go") unexpectedly succeeded`)
  1107  	}
  1108  }
  1109  
  1110  // findUnusedDriveLetter searches mounted drive list on the system
  1111  // (starting from Z: and ending at D:) for unused drive letter.
  1112  // It returns path to the found drive root directory (like Z:\) or error.
  1113  func findUnusedDriveLetter() (string, error) {
  1114  	// Do not use A: and B:, because they are reserved for floppy drive.
  1115  	// Do not use C:, because it is normally used for main drive.
  1116  	for l := 'Z'; l >= 'D'; l-- {
  1117  		p := string(l) + `:\`
  1118  		_, err := os.Stat(p)
  1119  		if os.IsNotExist(err) {
  1120  			return p, nil
  1121  		}
  1122  	}
  1123  	return "", errors.New("Could not find unused drive letter.")
  1124  }
  1125  
  1126  func TestRootDirAsTemp(t *testing.T) {
  1127  	testenv.MustHaveExec(t)
  1128  
  1129  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
  1130  		fmt.Print(os.TempDir())
  1131  		os.Exit(0)
  1132  	}
  1133  
  1134  	newtmp, err := findUnusedDriveLetter()
  1135  	if err != nil {
  1136  		t.Fatal(err)
  1137  	}
  1138  
  1139  	cmd := osexec.Command(os.Args[0], "-test.run=TestRootDirAsTemp")
  1140  	cmd.Env = os.Environ()
  1141  	cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
  1142  	cmd.Env = append(cmd.Env, "TMP="+newtmp)
  1143  	cmd.Env = append(cmd.Env, "TEMP="+newtmp)
  1144  	output, err := cmd.CombinedOutput()
  1145  	if err != nil {
  1146  		t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
  1147  	}
  1148  	if want, have := newtmp, string(output); have != want {
  1149  		t.Fatalf("unexpected child process output %q, want %q", have, want)
  1150  	}
  1151  }
  1152  
  1153  func testReadlink(t *testing.T, path, want string) {
  1154  	got, err := os.Readlink(path)
  1155  	if err != nil {
  1156  		t.Error(err)
  1157  		return
  1158  	}
  1159  	if got != want {
  1160  		t.Errorf(`Readlink(%q): got %q, want %q`, path, got, want)
  1161  	}
  1162  }
  1163  
  1164  func mklink(t *testing.T, link, target string) {
  1165  	output, err := osexec.Command("cmd", "/c", "mklink", link, target).CombinedOutput()
  1166  	if err != nil {
  1167  		t.Fatalf("failed to run mklink %v %v: %v %q", link, target, err, output)
  1168  	}
  1169  }
  1170  
  1171  func mklinkj(t *testing.T, link, target string) {
  1172  	output, err := osexec.Command("cmd", "/c", "mklink", "/J", link, target).CombinedOutput()
  1173  	if err != nil {
  1174  		t.Fatalf("failed to run mklink %v %v: %v %q", link, target, err, output)
  1175  	}
  1176  }
  1177  
  1178  func mklinkd(t *testing.T, link, target string) {
  1179  	output, err := osexec.Command("cmd", "/c", "mklink", "/D", link, target).CombinedOutput()
  1180  	if err != nil {
  1181  		t.Fatalf("failed to run mklink %v %v: %v %q", link, target, err, output)
  1182  	}
  1183  }
  1184  
  1185  func TestWindowsReadlink(t *testing.T) {
  1186  	tmpdir, err := os.MkdirTemp("", "TestWindowsReadlink")
  1187  	if err != nil {
  1188  		t.Fatal(err)
  1189  	}
  1190  	defer os.RemoveAll(tmpdir)
  1191  
  1192  	// Make sure tmpdir is not a symlink, otherwise tests will fail.
  1193  	tmpdir, err = filepath.EvalSymlinks(tmpdir)
  1194  	if err != nil {
  1195  		t.Fatal(err)
  1196  	}
  1197  	chdir(t, tmpdir)
  1198  
  1199  	vol := filepath.VolumeName(tmpdir)
  1200  	output, err := osexec.Command("cmd", "/c", "mountvol", vol, "/L").CombinedOutput()
  1201  	if err != nil {
  1202  		t.Fatalf("failed to run mountvol %v /L: %v %q", vol, err, output)
  1203  	}
  1204  	ntvol := strings.Trim(string(output), " \n\r")
  1205  
  1206  	dir := filepath.Join(tmpdir, "dir")
  1207  	err = os.MkdirAll(dir, 0777)
  1208  	if err != nil {
  1209  		t.Fatal(err)
  1210  	}
  1211  
  1212  	absdirjlink := filepath.Join(tmpdir, "absdirjlink")
  1213  	mklinkj(t, absdirjlink, dir)
  1214  	testReadlink(t, absdirjlink, dir)
  1215  
  1216  	ntdirjlink := filepath.Join(tmpdir, "ntdirjlink")
  1217  	mklinkj(t, ntdirjlink, ntvol+absdirjlink[len(filepath.VolumeName(absdirjlink)):])
  1218  	testReadlink(t, ntdirjlink, absdirjlink)
  1219  
  1220  	ntdirjlinktolink := filepath.Join(tmpdir, "ntdirjlinktolink")
  1221  	mklinkj(t, ntdirjlinktolink, ntvol+absdirjlink[len(filepath.VolumeName(absdirjlink)):])
  1222  	testReadlink(t, ntdirjlinktolink, absdirjlink)
  1223  
  1224  	mklinkj(t, "reldirjlink", "dir")
  1225  	testReadlink(t, "reldirjlink", dir) // relative directory junction resolves to absolute path
  1226  
  1227  	// Make sure we have sufficient privilege to run mklink command.
  1228  	testenv.MustHaveSymlink(t)
  1229  
  1230  	absdirlink := filepath.Join(tmpdir, "absdirlink")
  1231  	mklinkd(t, absdirlink, dir)
  1232  	testReadlink(t, absdirlink, dir)
  1233  
  1234  	ntdirlink := filepath.Join(tmpdir, "ntdirlink")
  1235  	mklinkd(t, ntdirlink, ntvol+absdirlink[len(filepath.VolumeName(absdirlink)):])
  1236  	testReadlink(t, ntdirlink, absdirlink)
  1237  
  1238  	mklinkd(t, "reldirlink", "dir")
  1239  	testReadlink(t, "reldirlink", "dir")
  1240  
  1241  	file := filepath.Join(tmpdir, "file")
  1242  	err = os.WriteFile(file, []byte(""), 0666)
  1243  	if err != nil {
  1244  		t.Fatal(err)
  1245  	}
  1246  
  1247  	filelink := filepath.Join(tmpdir, "filelink")
  1248  	mklink(t, filelink, file)
  1249  	testReadlink(t, filelink, file)
  1250  
  1251  	linktofilelink := filepath.Join(tmpdir, "linktofilelink")
  1252  	mklink(t, linktofilelink, ntvol+filelink[len(filepath.VolumeName(filelink)):])
  1253  	testReadlink(t, linktofilelink, filelink)
  1254  
  1255  	mklink(t, "relfilelink", "file")
  1256  	testReadlink(t, "relfilelink", "file")
  1257  }
  1258  
  1259  // os.Mkdir(os.DevNull) fails.
  1260  func TestMkdirDevNull(t *testing.T) {
  1261  	err := os.Mkdir(os.DevNull, 777)
  1262  	oserr, ok := err.(*fs.PathError)
  1263  	if !ok {
  1264  		t.Fatalf("error (%T) is not *fs.PathError", err)
  1265  	}
  1266  	errno, ok := oserr.Err.(syscall.Errno)
  1267  	if !ok {
  1268  		t.Fatalf("error (%T) is not syscall.Errno", oserr)
  1269  	}
  1270  	if errno != syscall.ENOTDIR {
  1271  		t.Fatalf("error %d is not syscall.ENOTDIR", errno)
  1272  	}
  1273  }
  1274  

View as plain text