github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/os/os_windows_test.go (about)

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