Source file
src/os/os_windows_test.go
1
2
3
4
5 package os_test
6
7 import (
8 "errors"
9 "fmt"
10 "internal/godebug"
11 "internal/poll"
12 "internal/syscall/windows"
13 "internal/syscall/windows/registry"
14 "internal/testenv"
15 "io"
16 "io/fs"
17 "os"
18 "os/exec"
19 "path/filepath"
20 "reflect"
21 "runtime"
22 "slices"
23 "sort"
24 "strings"
25 "syscall"
26 "testing"
27 "unicode/utf16"
28 "unsafe"
29 )
30
31 var winsymlink = godebug.New("winsymlink")
32 var winreadlinkvolume = godebug.New("winreadlinkvolume")
33
34
35 type syscallDescriptor = syscall.Handle
36
37
38
39 func chdir(t *testing.T, dir string) {
40 olddir, err := os.Getwd()
41 if err != nil {
42 t.Fatalf("chdir: %v", err)
43 }
44 if err := os.Chdir(dir); err != nil {
45 t.Fatalf("chdir %s: %v", dir, err)
46 }
47
48 t.Cleanup(func() {
49 if err := os.Chdir(olddir); err != nil {
50 t.Errorf("chdir to original working directory %s: %v", olddir, err)
51 os.Exit(1)
52 }
53 })
54 }
55
56 func TestSameWindowsFile(t *testing.T) {
57 temp := t.TempDir()
58 chdir(t, temp)
59
60 f, err := os.Create("a")
61 if err != nil {
62 t.Fatal(err)
63 }
64 f.Close()
65
66 ia1, err := os.Stat("a")
67 if err != nil {
68 t.Fatal(err)
69 }
70
71 path, err := filepath.Abs("a")
72 if err != nil {
73 t.Fatal(err)
74 }
75 ia2, err := os.Stat(path)
76 if err != nil {
77 t.Fatal(err)
78 }
79 if !os.SameFile(ia1, ia2) {
80 t.Errorf("files should be same")
81 }
82
83 p := filepath.VolumeName(path) + filepath.Base(path)
84 if err != nil {
85 t.Fatal(err)
86 }
87 ia3, err := os.Stat(p)
88 if err != nil {
89 t.Fatal(err)
90 }
91 if !os.SameFile(ia1, ia3) {
92 t.Errorf("files should be same")
93 }
94 }
95
96 type dirLinkTest struct {
97 name string
98 mklink func(link, target string) error
99 isMountPoint bool
100 }
101
102 func testDirLinks(t *testing.T, tests []dirLinkTest) {
103 tmpdir := t.TempDir()
104 chdir(t, tmpdir)
105
106 dir := filepath.Join(tmpdir, "dir")
107 err := os.Mkdir(dir, 0777)
108 if err != nil {
109 t.Fatal(err)
110 }
111 fi, err := os.Stat(dir)
112 if err != nil {
113 t.Fatal(err)
114 }
115 err = os.WriteFile(filepath.Join(dir, "abc"), []byte("abc"), 0644)
116 if err != nil {
117 t.Fatal(err)
118 }
119 for _, test := range tests {
120 link := filepath.Join(tmpdir, test.name+"_link")
121 err := test.mklink(link, dir)
122 if err != nil {
123 t.Errorf("creating link for %q test failed: %v", test.name, err)
124 continue
125 }
126
127 data, err := os.ReadFile(filepath.Join(link, "abc"))
128 if err != nil {
129 t.Errorf("failed to read abc file: %v", err)
130 continue
131 }
132 if string(data) != "abc" {
133 t.Errorf(`abc file is expected to have "abc" in it, but has %v`, data)
134 continue
135 }
136
137 fi1, err := os.Stat(link)
138 if err != nil {
139 t.Errorf("failed to stat link %v: %v", link, err)
140 continue
141 }
142 if tp := fi1.Mode().Type(); tp != fs.ModeDir {
143 t.Errorf("Stat(%q) is type %v; want %v", link, tp, fs.ModeDir)
144 continue
145 }
146 if fi1.Name() != filepath.Base(link) {
147 t.Errorf("Stat(%q).Name() = %q, want %q", link, fi1.Name(), filepath.Base(link))
148 continue
149 }
150 if !os.SameFile(fi, fi1) {
151 t.Errorf("%q should point to %q", link, dir)
152 continue
153 }
154
155 fi2, err := os.Lstat(link)
156 if err != nil {
157 t.Errorf("failed to lstat link %v: %v", link, err)
158 continue
159 }
160 var wantType fs.FileMode
161 if test.isMountPoint && winsymlink.Value() != "0" {
162
163 wantType = fs.ModeIrregular
164 } else {
165
166 wantType = fs.ModeSymlink
167 }
168 if tp := fi2.Mode().Type(); tp != wantType {
169 t.Errorf("Lstat(%q) is type %v; want %v", link, tp, wantType)
170 }
171 }
172 }
173
174
175 type reparseData struct {
176 substituteName namePosition
177 printName namePosition
178 pathBuf []uint16
179 }
180
181 type namePosition struct {
182 offset uint16
183 length uint16
184 }
185
186 func (rd *reparseData) addUTF16s(s []uint16) (offset uint16) {
187 off := len(rd.pathBuf) * 2
188 rd.pathBuf = append(rd.pathBuf, s...)
189 return uint16(off)
190 }
191
192 func (rd *reparseData) addString(s string) (offset, length uint16) {
193 p := syscall.StringToUTF16(s)
194 return rd.addUTF16s(p), uint16(len(p)-1) * 2
195 }
196
197 func (rd *reparseData) addSubstituteName(name string) {
198 rd.substituteName.offset, rd.substituteName.length = rd.addString(name)
199 }
200
201 func (rd *reparseData) addPrintName(name string) {
202 rd.printName.offset, rd.printName.length = rd.addString(name)
203 }
204
205 func (rd *reparseData) addStringNoNUL(s string) (offset, length uint16) {
206 p := syscall.StringToUTF16(s)
207 p = p[:len(p)-1]
208 return rd.addUTF16s(p), uint16(len(p)) * 2
209 }
210
211 func (rd *reparseData) addSubstituteNameNoNUL(name string) {
212 rd.substituteName.offset, rd.substituteName.length = rd.addStringNoNUL(name)
213 }
214
215 func (rd *reparseData) addPrintNameNoNUL(name string) {
216 rd.printName.offset, rd.printName.length = rd.addStringNoNUL(name)
217 }
218
219
220 func (rd *reparseData) pathBuffeLen() uint16 {
221 return uint16(len(rd.pathBuf)) * 2
222 }
223
224
225
226
227
228 type _REPARSE_DATA_BUFFER struct {
229 header windows.REPARSE_DATA_BUFFER_HEADER
230 detail [syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]byte
231 }
232
233 func createDirLink(link string, rdb *_REPARSE_DATA_BUFFER) error {
234 err := os.Mkdir(link, 0777)
235 if err != nil {
236 return err
237 }
238
239 linkp := syscall.StringToUTF16(link)
240 fd, err := syscall.CreateFile(&linkp[0], syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING,
241 syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
242 if err != nil {
243 return err
244 }
245 defer syscall.CloseHandle(fd)
246
247 buflen := uint32(rdb.header.ReparseDataLength) + uint32(unsafe.Sizeof(rdb.header))
248 var bytesReturned uint32
249 return syscall.DeviceIoControl(fd, windows.FSCTL_SET_REPARSE_POINT,
250 (*byte)(unsafe.Pointer(&rdb.header)), buflen, nil, 0, &bytesReturned, nil)
251 }
252
253 func createMountPoint(link string, target *reparseData) error {
254 var buf *windows.MountPointReparseBuffer
255 buflen := uint16(unsafe.Offsetof(buf.PathBuffer)) + target.pathBuffeLen()
256 byteblob := make([]byte, buflen)
257 buf = (*windows.MountPointReparseBuffer)(unsafe.Pointer(&byteblob[0]))
258 buf.SubstituteNameOffset = target.substituteName.offset
259 buf.SubstituteNameLength = target.substituteName.length
260 buf.PrintNameOffset = target.printName.offset
261 buf.PrintNameLength = target.printName.length
262 pbuflen := len(target.pathBuf)
263 copy((*[2048]uint16)(unsafe.Pointer(&buf.PathBuffer[0]))[:pbuflen:pbuflen], target.pathBuf)
264
265 var rdb _REPARSE_DATA_BUFFER
266 rdb.header.ReparseTag = windows.IO_REPARSE_TAG_MOUNT_POINT
267 rdb.header.ReparseDataLength = buflen
268 copy(rdb.detail[:], byteblob)
269
270 return createDirLink(link, &rdb)
271 }
272
273 func TestDirectoryJunction(t *testing.T) {
274 var tests = []dirLinkTest{
275 {
276
277 name: "standard",
278 isMountPoint: true,
279 mklink: func(link, target string) error {
280 var t reparseData
281 t.addSubstituteName(`\??\` + target)
282 t.addPrintName(target)
283 return createMountPoint(link, &t)
284 },
285 },
286 {
287
288 name: "have_blank_print_name",
289 isMountPoint: true,
290 mklink: func(link, target string) error {
291 var t reparseData
292 t.addSubstituteName(`\??\` + target)
293 t.addPrintName("")
294 return createMountPoint(link, &t)
295 },
296 },
297 }
298 output, _ := testenv.Command(t, "cmd", "/c", "mklink", "/?").Output()
299 mklinkSupportsJunctionLinks := strings.Contains(string(output), " /J ")
300 if mklinkSupportsJunctionLinks {
301 tests = append(tests,
302 dirLinkTest{
303 name: "use_mklink_cmd",
304 isMountPoint: true,
305 mklink: func(link, target string) error {
306 output, err := testenv.Command(t, "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()
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 pbuflen := len(target.pathBuf)
360 copy((*[2048]uint16)(unsafe.Pointer(&buf.PathBuffer[0]))[:pbuflen:pbuflen], target.pathBuf)
361
362 var rdb _REPARSE_DATA_BUFFER
363 rdb.header.ReparseTag = syscall.IO_REPARSE_TAG_SYMLINK
364 rdb.header.ReparseDataLength = buflen
365 copy(rdb.detail[:], byteblob)
366
367 return createDirLink(link, &rdb)
368 }
369
370 func TestDirectorySymbolicLink(t *testing.T) {
371 var tests []dirLinkTest
372 output, _ := testenv.Command(t, "cmd", "/c", "mklink", "/?").Output()
373 mklinkSupportsDirectorySymbolicLinks := strings.Contains(string(output), " /D ")
374 if mklinkSupportsDirectorySymbolicLinks {
375 tests = append(tests,
376 dirLinkTest{
377 name: "use_mklink_cmd",
378 mklink: func(link, target string) error {
379 output, err := testenv.Command(t, "cmd", "/c", "mklink", "/D", link, target).CombinedOutput()
380 if err != nil {
381 t.Errorf("failed to run mklink %v %v: %v %q", link, target, err, output)
382 }
383 return nil
384 },
385 },
386 )
387 } else {
388 t.Log(`skipping "use_mklink_cmd" test, mklink does not supports directory symbolic links`)
389 }
390
391
392 runtime.LockOSThread()
393 defer runtime.UnlockOSThread()
394
395 err := windows.ImpersonateSelf(windows.SecurityImpersonation)
396 if err != nil {
397 t.Fatal(err)
398 }
399 defer windows.RevertToSelf()
400
401 err = enableCurrentThreadPrivilege("SeCreateSymbolicLinkPrivilege")
402 if err != nil {
403 t.Skipf(`skipping some tests, could not enable "SeCreateSymbolicLinkPrivilege": %v`, err)
404 }
405 tests = append(tests,
406 dirLinkTest{
407 name: "use_os_pkg",
408 mklink: func(link, target string) error {
409 return os.Symlink(target, link)
410 },
411 },
412 dirLinkTest{
413
414 name: "standard",
415 mklink: func(link, target string) error {
416 var t reparseData
417 t.addPrintName(target)
418 t.addSubstituteName(`\??\` + target)
419 return createSymbolicLink(link, &t, false)
420 },
421 },
422 dirLinkTest{
423 name: "relative",
424 mklink: func(link, target string) error {
425 var t reparseData
426 t.addSubstituteNameNoNUL(filepath.Base(target))
427 t.addPrintNameNoNUL(filepath.Base(target))
428 return createSymbolicLink(link, &t, true)
429 },
430 },
431 )
432 testDirLinks(t, tests)
433 }
434
435 func mustHaveWorkstation(t *testing.T) {
436 mar, err := windows.OpenSCManager(nil, nil, windows.SERVICE_QUERY_STATUS)
437 if err != nil {
438 return
439 }
440 defer syscall.CloseHandle(mar)
441
442 srv, err := windows.OpenService(mar, syscall.StringToUTF16Ptr("LanmanWorkstation"), windows.SERVICE_QUERY_STATUS)
443 if err != nil {
444 return
445 }
446 defer syscall.CloseHandle(srv)
447 var state windows.SERVICE_STATUS
448 err = windows.QueryServiceStatus(srv, &state)
449 if err != nil {
450 return
451 }
452 if state.CurrentState != windows.SERVICE_RUNNING {
453 t.Skip("Requires the Windows service Workstation, but it is detected that it is not enabled.")
454 }
455 }
456
457 func TestNetworkSymbolicLink(t *testing.T) {
458 testenv.MustHaveSymlink(t)
459
460 const _NERR_ServerNotStarted = syscall.Errno(2114)
461
462 dir := t.TempDir()
463 chdir(t, dir)
464
465 pid := os.Getpid()
466 shareName := fmt.Sprintf("GoSymbolicLinkTestShare%d", pid)
467 sharePath := filepath.Join(dir, shareName)
468 testDir := "TestDir"
469
470 err := os.MkdirAll(filepath.Join(sharePath, testDir), 0777)
471 if err != nil {
472 t.Fatal(err)
473 }
474
475 wShareName, err := syscall.UTF16PtrFromString(shareName)
476 if err != nil {
477 t.Fatal(err)
478 }
479 wSharePath, err := syscall.UTF16PtrFromString(sharePath)
480 if err != nil {
481 t.Fatal(err)
482 }
483
484
485
486
487
488
489
490
491
492
493 const permissions = 0
494
495 p := windows.SHARE_INFO_2{
496 Netname: wShareName,
497 Type: windows.STYPE_DISKTREE | windows.STYPE_TEMPORARY,
498 Remark: nil,
499 Permissions: permissions,
500 MaxUses: 1,
501 CurrentUses: 0,
502 Path: wSharePath,
503 Passwd: nil,
504 }
505
506 err = windows.NetShareAdd(nil, 2, (*byte)(unsafe.Pointer(&p)), nil)
507 if err != nil {
508 if err == syscall.ERROR_ACCESS_DENIED || err == _NERR_ServerNotStarted {
509 t.Skipf("skipping: NetShareAdd: %v", err)
510 }
511 t.Fatal(err)
512 }
513 defer func() {
514 err := windows.NetShareDel(nil, wShareName, 0)
515 if err != nil {
516 t.Fatal(err)
517 }
518 }()
519
520 UNCPath := `\\localhost\` + shareName + `\`
521
522 fi1, err := os.Stat(sharePath)
523 if err != nil {
524 t.Fatal(err)
525 }
526 fi2, err := os.Stat(UNCPath)
527 if err != nil {
528 mustHaveWorkstation(t)
529 t.Fatal(err)
530 }
531 if !os.SameFile(fi1, fi2) {
532 t.Fatalf("%q and %q should be the same directory, but not", sharePath, UNCPath)
533 }
534
535 target := filepath.Join(UNCPath, testDir)
536 link := "link"
537
538 err = os.Symlink(target, link)
539 if err != nil {
540 t.Fatal(err)
541 }
542 defer os.Remove(link)
543
544 got, err := os.Readlink(link)
545 if err != nil {
546 t.Fatal(err)
547 }
548 if got != target {
549 t.Errorf(`os.Readlink(%#q): got %v, want %v`, link, got, target)
550 }
551
552 got, err = filepath.EvalSymlinks(link)
553 if err != nil {
554 t.Fatal(err)
555 }
556 if got != target {
557 t.Errorf(`filepath.EvalSymlinks(%#q): got %v, want %v`, link, got, target)
558 }
559 }
560
561 func TestStatLxSymLink(t *testing.T) {
562 if _, err := exec.LookPath("wsl"); err != nil {
563 t.Skip("skipping: WSL not detected")
564 }
565
566 temp := t.TempDir()
567 chdir(t, temp)
568
569 const target = "target"
570 const link = "link"
571
572 _, err := testenv.Command(t, "wsl", "/bin/mkdir", target).Output()
573 if err != nil {
574
575 t.Skipf("skipping: WSL is not correctly installed: %v", err)
576 }
577
578 _, err = testenv.Command(t, "wsl", "/bin/ln", "-s", target, link).Output()
579 if err != nil {
580 t.Fatal(err)
581 }
582
583 fi, err := os.Lstat(link)
584 if err != nil {
585 t.Fatal(err)
586 }
587 if m := fi.Mode(); m&fs.ModeSymlink != 0 {
588
589 t.Skip("skipping: WSL created reparse tag IO_REPARSE_TAG_SYMLINK instead of an IO_REPARSE_TAG_LX_SYMLINK")
590 }
591
592
593 _, err = os.Stat(link)
594 const ERROR_CANT_ACCESS_FILE = syscall.Errno(1920)
595 if err == nil || !errors.Is(err, ERROR_CANT_ACCESS_FILE) {
596 t.Fatalf("os.Stat(%q): got %v, want ERROR_CANT_ACCESS_FILE", link, err)
597 }
598 }
599
600 func TestStartProcessAttr(t *testing.T) {
601 t.Parallel()
602
603 p, err := os.StartProcess(os.Getenv("COMSPEC"), []string{"/c", "cd"}, new(os.ProcAttr))
604 if err != nil {
605 return
606 }
607 defer p.Wait()
608 t.Fatalf("StartProcess expected to fail, but succeeded.")
609 }
610
611 func TestShareNotExistError(t *testing.T) {
612 if testing.Short() {
613 t.Skip("slow test that uses network; skipping")
614 }
615 t.Parallel()
616
617 _, err := os.Stat(`\\no_such_server\no_such_share\no_such_file`)
618 if err == nil {
619 t.Fatal("stat succeeded, but expected to fail")
620 }
621 if !os.IsNotExist(err) {
622 t.Fatalf("os.Stat failed with %q, but os.IsNotExist(err) is false", err)
623 }
624 }
625
626 func TestBadNetPathError(t *testing.T) {
627 const ERROR_BAD_NETPATH = syscall.Errno(53)
628 if !os.IsNotExist(ERROR_BAD_NETPATH) {
629 t.Fatal("os.IsNotExist(syscall.Errno(53)) is false, but want true")
630 }
631 }
632
633 func TestStatDir(t *testing.T) {
634 defer chtmpdir(t)()
635
636 f, err := os.Open(".")
637 if err != nil {
638 t.Fatal(err)
639 }
640 defer f.Close()
641
642 fi, err := f.Stat()
643 if err != nil {
644 t.Fatal(err)
645 }
646
647 err = os.Chdir("..")
648 if err != nil {
649 t.Fatal(err)
650 }
651
652 fi2, err := f.Stat()
653 if err != nil {
654 t.Fatal(err)
655 }
656
657 if !os.SameFile(fi, fi2) {
658 t.Fatal("race condition occurred")
659 }
660 }
661
662 func TestOpenVolumeName(t *testing.T) {
663 tmpdir := t.TempDir()
664 chdir(t, tmpdir)
665
666 want := []string{"file1", "file2", "file3", "gopher.txt"}
667 sort.Strings(want)
668 for _, name := range want {
669 err := os.WriteFile(filepath.Join(tmpdir, name), nil, 0777)
670 if err != nil {
671 t.Fatal(err)
672 }
673 }
674
675 f, err := os.Open(filepath.VolumeName(tmpdir))
676 if err != nil {
677 t.Fatal(err)
678 }
679 defer f.Close()
680
681 have, err := f.Readdirnames(-1)
682 if err != nil {
683 t.Fatal(err)
684 }
685 sort.Strings(have)
686
687 if strings.Join(want, "/") != strings.Join(have, "/") {
688 t.Fatalf("unexpected file list %q, want %q", have, want)
689 }
690 }
691
692 func TestDeleteReadOnly(t *testing.T) {
693 t.Parallel()
694
695 tmpdir := t.TempDir()
696 p := filepath.Join(tmpdir, "a")
697
698 f, err := os.OpenFile(p, os.O_CREATE, 0400)
699 if err != nil {
700 t.Fatal(err)
701 }
702 f.Close()
703
704 if err = os.Chmod(p, 0400); err != nil {
705 t.Fatal(err)
706 }
707 if err = os.Remove(p); err != nil {
708 t.Fatal(err)
709 }
710 }
711
712 func TestReadStdin(t *testing.T) {
713 old := poll.ReadConsole
714 defer func() {
715 poll.ReadConsole = old
716 }()
717
718 p, err := syscall.GetCurrentProcess()
719 if err != nil {
720 t.Fatalf("Unable to get handle to current process: %v", err)
721 }
722 var stdinDuplicate syscall.Handle
723 err = syscall.DuplicateHandle(p, syscall.Handle(syscall.Stdin), p, &stdinDuplicate, 0, false, syscall.DUPLICATE_SAME_ACCESS)
724 if err != nil {
725 t.Fatalf("Unable to duplicate stdin: %v", err)
726 }
727 testConsole := os.NewConsoleFile(stdinDuplicate, "test")
728
729 var tests = []string{
730 "abc",
731 "äöü",
732 "\u3042",
733 "“hi”™",
734 "hello\x1aworld",
735 "\U0001F648\U0001F649\U0001F64A",
736 }
737
738 for _, consoleSize := range []int{1, 2, 3, 10, 16, 100, 1000} {
739 for _, readSize := range []int{1, 2, 3, 4, 5, 8, 10, 16, 20, 50, 100} {
740 for _, s := range tests {
741 t.Run(fmt.Sprintf("c%d/r%d/%s", consoleSize, readSize, s), func(t *testing.T) {
742 s16 := utf16.Encode([]rune(s))
743 poll.ReadConsole = func(h syscall.Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) error {
744 if inputControl != nil {
745 t.Fatalf("inputControl not nil")
746 }
747 n := int(toread)
748 if n > consoleSize {
749 n = consoleSize
750 }
751 n = copy((*[10000]uint16)(unsafe.Pointer(buf))[:n:n], s16)
752 s16 = s16[n:]
753 *read = uint32(n)
754 t.Logf("read %d -> %d", toread, *read)
755 return nil
756 }
757
758 var all []string
759 var buf []byte
760 chunk := make([]byte, readSize)
761 for {
762 n, err := testConsole.Read(chunk)
763 buf = append(buf, chunk[:n]...)
764 if err == io.EOF {
765 all = append(all, string(buf))
766 if len(all) >= 5 {
767 break
768 }
769 buf = buf[:0]
770 } else if err != nil {
771 t.Fatalf("reading %q: error: %v", s, err)
772 }
773 if len(buf) >= 2000 {
774 t.Fatalf("reading %q: stuck in loop: %q", s, buf)
775 }
776 }
777
778 want := strings.Split(s, "\x1a")
779 for len(want) < 5 {
780 want = append(want, "")
781 }
782 if !reflect.DeepEqual(all, want) {
783 t.Errorf("reading %q:\nhave %x\nwant %x", s, all, want)
784 }
785 })
786 }
787 }
788 }
789 }
790
791 func TestStatPagefile(t *testing.T) {
792 t.Parallel()
793
794 const path = `c:\pagefile.sys`
795 fi, err := os.Stat(path)
796 if err == nil {
797 if fi.Name() == "" {
798 t.Fatalf("Stat(%q).Name() is empty", path)
799 }
800 t.Logf("Stat(%q).Size() = %v", path, fi.Size())
801 return
802 }
803 if os.IsNotExist(err) {
804 t.Skip(`skipping because c:\pagefile.sys is not found`)
805 }
806 t.Fatal(err)
807 }
808
809
810
811 func syscallCommandLineToArgv(cmd string) ([]string, error) {
812 var argc int32
813 argv, err := syscall.CommandLineToArgv(&syscall.StringToUTF16(cmd)[0], &argc)
814 if err != nil {
815 return nil, err
816 }
817 defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
818
819 var args []string
820 for _, v := range (*argv)[:argc] {
821 args = append(args, syscall.UTF16ToString((*v)[:]))
822 }
823 return args, nil
824 }
825
826
827
828
829 func compareCommandLineToArgvWithSyscall(t *testing.T, cmd string) {
830 syscallArgs, err := syscallCommandLineToArgv(cmd)
831 if err != nil {
832 t.Fatal(err)
833 }
834 args := os.CommandLineToArgv(cmd)
835 if want, have := fmt.Sprintf("%q", syscallArgs), fmt.Sprintf("%q", args); want != have {
836 t.Errorf("testing os.commandLineToArgv(%q) failed: have %q want %q", cmd, args, syscallArgs)
837 return
838 }
839 }
840
841 func TestCmdArgs(t *testing.T) {
842 if testing.Short() {
843 t.Skipf("in short mode; skipping test that builds a binary")
844 }
845 t.Parallel()
846
847 tmpdir := t.TempDir()
848
849 const prog = `
850 package main
851
852 import (
853 "fmt"
854 "os"
855 )
856
857 func main() {
858 fmt.Printf("%q", os.Args)
859 }
860 `
861 src := filepath.Join(tmpdir, "main.go")
862 if err := os.WriteFile(src, []byte(prog), 0666); err != nil {
863 t.Fatal(err)
864 }
865
866 exe := filepath.Join(tmpdir, "main.exe")
867 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src)
868 cmd.Dir = tmpdir
869 out, err := cmd.CombinedOutput()
870 if err != nil {
871 t.Fatalf("building main.exe failed: %v\n%s", err, out)
872 }
873
874 var cmds = []string{
875 ``,
876 ` a b c`,
877 ` "`,
878 ` ""`,
879 ` """`,
880 ` "" a`,
881 ` "123"`,
882 ` \"123\"`,
883 ` \"123 456\"`,
884 ` \\"`,
885 ` \\\"`,
886 ` \\\\\"`,
887 ` \\\"x`,
888 ` """"\""\\\"`,
889 ` abc`,
890 ` \\\\\""x"""y z`,
891 "\tb\t\"x\ty\"",
892 ` "Брад" d e`,
893
894 ` "abc" d e`,
895 ` a\\b d"e f"g h`,
896 ` a\\\"b c d`,
897 ` a\\\\"b c" d e`,
898
899
900 ` CallMeIshmael`,
901 ` "Call Me Ishmael"`,
902 ` Cal"l Me I"shmael`,
903 ` CallMe\"Ishmael`,
904 ` "CallMe\"Ishmael"`,
905 ` "Call Me Ishmael\\"`,
906 ` "CallMe\\\"Ishmael"`,
907 ` a\\\b`,
908 ` "a\\\b"`,
909
910 ` "\"Call Me Ishmael\""`,
911 ` "C:\TEST A\\"`,
912 ` "\"C:\TEST A\\\""`,
913
914 ` "a b c" d e`,
915 ` "ab\"c" "\\" d`,
916 ` a\\\b d"e f"g h`,
917 ` a\\\"b c d`,
918 ` a\\\\"b c" d e`,
919
920 ` "a b c""`,
921 ` """CallMeIshmael""" b c`,
922 ` """Call Me Ishmael"""`,
923 ` """"Call Me Ishmael"" b c`,
924 }
925 for _, cmd := range cmds {
926 compareCommandLineToArgvWithSyscall(t, "test"+cmd)
927 compareCommandLineToArgvWithSyscall(t, `"cmd line"`+cmd)
928 compareCommandLineToArgvWithSyscall(t, exe+cmd)
929
930
931 args := os.CommandLineToArgv(exe + cmd)
932 out, err := testenv.Command(t, args[0], args[1:]...).CombinedOutput()
933 if err != nil {
934 t.Fatalf("running %q failed: %v\n%v", args, err, string(out))
935 }
936 if want, have := fmt.Sprintf("%q", args), string(out); want != have {
937 t.Errorf("wrong output of executing %q: have %q want %q", args, have, want)
938 continue
939 }
940 }
941 }
942
943 func findOneDriveDir() (string, error) {
944
945 const onedrivekey = `SOFTWARE\Microsoft\OneDrive`
946 k, err := registry.OpenKey(registry.CURRENT_USER, onedrivekey, registry.READ)
947 if err != nil {
948 return "", fmt.Errorf("OpenKey(%q) failed: %v", onedrivekey, err)
949 }
950 defer k.Close()
951
952 path, valtype, err := k.GetStringValue("UserFolder")
953 if err != nil {
954 return "", fmt.Errorf("reading UserFolder failed: %v", err)
955 }
956
957 if valtype == registry.EXPAND_SZ {
958 expanded, err := registry.ExpandString(path)
959 if err != nil {
960 return "", fmt.Errorf("expanding UserFolder failed: %v", err)
961 }
962 path = expanded
963 }
964
965 return path, nil
966 }
967
968
969 func TestOneDrive(t *testing.T) {
970 t.Parallel()
971
972 dir, err := findOneDriveDir()
973 if err != nil {
974 t.Skipf("Skipping, because we did not find OneDrive directory: %v", err)
975 }
976 testDirStats(t, dir)
977 }
978
979 func TestWindowsDevNullFile(t *testing.T) {
980 t.Parallel()
981
982 f1, err := os.Open("NUL")
983 if err != nil {
984 t.Fatal(err)
985 }
986 defer f1.Close()
987
988 fi1, err := f1.Stat()
989 if err != nil {
990 t.Fatal(err)
991 }
992
993 f2, err := os.Open("nul")
994 if err != nil {
995 t.Fatal(err)
996 }
997 defer f2.Close()
998
999 fi2, err := f2.Stat()
1000 if err != nil {
1001 t.Fatal(err)
1002 }
1003
1004 if !os.SameFile(fi1, fi2) {
1005 t.Errorf(`"NUL" and "nul" are not the same file`)
1006 }
1007 }
1008
1009 func TestFileStatNUL(t *testing.T) {
1010 t.Parallel()
1011
1012 f, err := os.Open("NUL")
1013 if err != nil {
1014 t.Fatal(err)
1015 }
1016 fi, err := f.Stat()
1017 if err != nil {
1018 t.Fatal(err)
1019 }
1020 if got, want := fi.Mode(), os.ModeDevice|os.ModeCharDevice|0666; got != want {
1021 t.Errorf("Open(%q).Stat().Mode() = %v, want %v", "NUL", got, want)
1022 }
1023 }
1024
1025 func TestStatNUL(t *testing.T) {
1026 t.Parallel()
1027
1028 fi, err := os.Stat("NUL")
1029 if err != nil {
1030 t.Fatal(err)
1031 }
1032 if got, want := fi.Mode(), os.ModeDevice|os.ModeCharDevice|0666; got != want {
1033 t.Errorf("Stat(%q).Mode() = %v, want %v", "NUL", got, want)
1034 }
1035 }
1036
1037
1038
1039
1040 func TestSymlinkCreation(t *testing.T) {
1041 if !testenv.HasSymlink() && !isWindowsDeveloperModeActive() {
1042 t.Skip("Windows developer mode is not active")
1043 }
1044 t.Parallel()
1045
1046 temp := t.TempDir()
1047 dummyFile := filepath.Join(temp, "file")
1048 if err := os.WriteFile(dummyFile, []byte(""), 0644); err != nil {
1049 t.Fatal(err)
1050 }
1051
1052 linkFile := filepath.Join(temp, "link")
1053 if err := os.Symlink(dummyFile, linkFile); err != nil {
1054 t.Fatal(err)
1055 }
1056 }
1057
1058
1059
1060
1061 func isWindowsDeveloperModeActive() bool {
1062 key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock", registry.READ)
1063 if err != nil {
1064 return false
1065 }
1066
1067 val, _, err := key.GetIntegerValue("AllowDevelopmentWithoutDevLicense")
1068 if err != nil {
1069 return false
1070 }
1071
1072 return val != 0
1073 }
1074
1075
1076
1077
1078
1079 func TestRootRelativeDirSymlink(t *testing.T) {
1080 testenv.MustHaveSymlink(t)
1081 t.Parallel()
1082
1083 temp := t.TempDir()
1084 dir := filepath.Join(temp, "dir")
1085 if err := os.Mkdir(dir, 0755); err != nil {
1086 t.Fatal(err)
1087 }
1088
1089 volumeRelDir := strings.TrimPrefix(dir, filepath.VolumeName(dir))
1090
1091 link := filepath.Join(temp, "link")
1092 err := os.Symlink(volumeRelDir, link)
1093 if err != nil {
1094 t.Fatal(err)
1095 }
1096 t.Logf("Symlink(%#q, %#q)", volumeRelDir, link)
1097
1098 f, err := os.Open(link)
1099 if err != nil {
1100 t.Fatal(err)
1101 }
1102 defer f.Close()
1103 if fi, err := f.Stat(); err != nil {
1104 t.Fatal(err)
1105 } else if !fi.IsDir() {
1106 t.Errorf("Open(%#q).Stat().IsDir() = false; want true", f.Name())
1107 }
1108 }
1109
1110
1111
1112
1113
1114 func TestWorkingDirectoryRelativeSymlink(t *testing.T) {
1115 testenv.MustHaveSymlink(t)
1116
1117
1118 temp := t.TempDir()
1119 if v := filepath.VolumeName(temp); len(v) < 2 || v[1] != ':' {
1120 t.Skipf("Can't test relative symlinks: t.TempDir() (%#q) does not begin with a drive letter.", temp)
1121 }
1122
1123 absDir := filepath.Join(temp, `dir\sub`)
1124 if err := os.MkdirAll(absDir, 0755); err != nil {
1125 t.Fatal(err)
1126 }
1127
1128
1129
1130 oldwd, err := os.Getwd()
1131 if err != nil {
1132 t.Fatal(err)
1133 }
1134 defer func() {
1135 if err := os.Chdir(oldwd); err != nil {
1136 t.Fatal(err)
1137 }
1138 }()
1139 if err := os.Chdir(temp); err != nil {
1140 t.Fatal(err)
1141 }
1142 t.Logf("Chdir(%#q)", temp)
1143
1144 wdRelDir := filepath.VolumeName(temp) + `dir\sub`
1145 absLink := filepath.Join(temp, "link")
1146 err = os.Symlink(wdRelDir, absLink)
1147 if err != nil {
1148 t.Fatal(err)
1149 }
1150 t.Logf("Symlink(%#q, %#q)", wdRelDir, absLink)
1151
1152
1153
1154
1155 if err := os.Chdir(oldwd); err != nil {
1156 t.Fatal(err)
1157 }
1158 t.Logf("Chdir(%#q)", oldwd)
1159
1160 resolved, err := os.Readlink(absLink)
1161 if err != nil {
1162 t.Errorf("Readlink(%#q): %v", absLink, err)
1163 } else if resolved != absDir {
1164 t.Errorf("Readlink(%#q) = %#q; want %#q", absLink, resolved, absDir)
1165 }
1166
1167 linkFile, err := os.Open(absLink)
1168 if err != nil {
1169 t.Fatal(err)
1170 }
1171 defer linkFile.Close()
1172
1173 linkInfo, err := linkFile.Stat()
1174 if err != nil {
1175 t.Fatal(err)
1176 }
1177 if !linkInfo.IsDir() {
1178 t.Errorf("Open(%#q).Stat().IsDir() = false; want true", absLink)
1179 }
1180
1181 absInfo, err := os.Stat(absDir)
1182 if err != nil {
1183 t.Fatal(err)
1184 }
1185
1186 if !os.SameFile(absInfo, linkInfo) {
1187 t.Errorf("SameFile(Stat(%#q), Open(%#q).Stat()) = false; want true", absDir, absLink)
1188 }
1189 }
1190
1191
1192 func TestStatOfInvalidName(t *testing.T) {
1193 t.Parallel()
1194
1195 _, err := os.Stat("*.go")
1196 if err == nil {
1197 t.Fatal(`os.Stat("*.go") unexpectedly succeeded`)
1198 }
1199 }
1200
1201
1202
1203
1204 func findUnusedDriveLetter() (string, error) {
1205
1206
1207 for l := 'Z'; l >= 'D'; l-- {
1208 p := string(l) + `:\`
1209 _, err := os.Stat(p)
1210 if os.IsNotExist(err) {
1211 return p, nil
1212 }
1213 }
1214 return "", errors.New("Could not find unused drive letter.")
1215 }
1216
1217 func TestRootDirAsTemp(t *testing.T) {
1218 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
1219 fmt.Print(os.TempDir())
1220 os.Exit(0)
1221 }
1222
1223 testenv.MustHaveExec(t)
1224 t.Parallel()
1225
1226 exe, err := os.Executable()
1227 if err != nil {
1228 t.Fatal(err)
1229 }
1230
1231 newtmp, err := findUnusedDriveLetter()
1232 if err != nil {
1233 t.Skip(err)
1234 }
1235
1236 cmd := testenv.Command(t, exe, "-test.run=^TestRootDirAsTemp$")
1237 cmd.Env = cmd.Environ()
1238 cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
1239 cmd.Env = append(cmd.Env, "TMP="+newtmp)
1240 cmd.Env = append(cmd.Env, "TEMP="+newtmp)
1241 output, err := cmd.CombinedOutput()
1242 if err != nil {
1243 t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
1244 }
1245 if want, have := newtmp, string(output); have != want {
1246 t.Fatalf("unexpected child process output %q, want %q", have, want)
1247 }
1248 }
1249
1250
1251
1252 func replaceDriveWithVolumeID(t *testing.T, path string) string {
1253 t.Helper()
1254 cmd := testenv.Command(t, "cmd", "/c", "mountvol", filepath.VolumeName(path), "/L")
1255 out, err := cmd.CombinedOutput()
1256 if err != nil {
1257 t.Fatalf("%v: %v\n%s", cmd, err, out)
1258 }
1259 vol := strings.Trim(string(out), " \n\r")
1260 return filepath.Join(vol, path[len(filepath.VolumeName(path)):])
1261 }
1262
1263 func TestReadlink(t *testing.T) {
1264 tests := []struct {
1265 junction bool
1266 dir bool
1267 drive bool
1268 relative bool
1269 }{
1270 {junction: true, dir: true, drive: true, relative: false},
1271 {junction: true, dir: true, drive: false, relative: false},
1272 {junction: true, dir: true, drive: false, relative: true},
1273 {junction: false, dir: true, drive: true, relative: false},
1274 {junction: false, dir: true, drive: false, relative: false},
1275 {junction: false, dir: true, drive: false, relative: true},
1276 {junction: false, dir: false, drive: true, relative: false},
1277 {junction: false, dir: false, drive: false, relative: false},
1278 {junction: false, dir: false, drive: false, relative: true},
1279 }
1280 for _, tt := range tests {
1281 tt := tt
1282 var name string
1283 if tt.junction {
1284 name = "junction"
1285 } else {
1286 name = "symlink"
1287 }
1288 if tt.dir {
1289 name += "_dir"
1290 } else {
1291 name += "_file"
1292 }
1293 if tt.drive {
1294 name += "_drive"
1295 } else {
1296 name += "_volume"
1297 }
1298 if tt.relative {
1299 name += "_relative"
1300 } else {
1301 name += "_absolute"
1302 }
1303
1304 t.Run(name, func(t *testing.T) {
1305 if !tt.relative {
1306 t.Parallel()
1307 }
1308
1309 tmpdir, err := filepath.EvalSymlinks(t.TempDir())
1310 if err != nil {
1311 t.Fatal(err)
1312 }
1313 link := filepath.Join(tmpdir, "link")
1314 target := filepath.Join(tmpdir, "target")
1315 if tt.dir {
1316 if err := os.MkdirAll(target, 0777); err != nil {
1317 t.Fatal(err)
1318 }
1319 } else {
1320 if err := os.WriteFile(target, nil, 0666); err != nil {
1321 t.Fatal(err)
1322 }
1323 }
1324 var want string
1325 if tt.relative {
1326 relTarget := filepath.Base(target)
1327 if tt.junction {
1328 want = target
1329 } else {
1330 want = relTarget
1331 }
1332 chdir(t, tmpdir)
1333 link = filepath.Base(link)
1334 target = relTarget
1335 } else {
1336 if tt.drive {
1337 want = target
1338 } else {
1339 volTarget := replaceDriveWithVolumeID(t, target)
1340 if winreadlinkvolume.Value() == "0" {
1341 want = target
1342 } else {
1343 want = volTarget
1344 }
1345 target = volTarget
1346 }
1347 }
1348 if tt.junction {
1349 cmd := testenv.Command(t, "cmd", "/c", "mklink", "/J", link, target)
1350 if out, err := cmd.CombinedOutput(); err != nil {
1351 t.Fatalf("%v: %v\n%s", cmd, err, out)
1352 }
1353 } else {
1354 if err := os.Symlink(target, link); err != nil {
1355 t.Fatalf("Symlink(%#q, %#q): %v", target, link, err)
1356 }
1357 }
1358 got, err := os.Readlink(link)
1359 if err != nil {
1360 t.Fatal(err)
1361 }
1362 if got != want {
1363 t.Fatalf("Readlink(%#q) = %#q; want %#q", target, got, want)
1364 }
1365 })
1366 }
1367 }
1368
1369 func TestOpenDirTOCTOU(t *testing.T) {
1370 t.Parallel()
1371
1372
1373
1374 tmpdir := t.TempDir()
1375 dir := filepath.Join(tmpdir, "dir")
1376 if err := os.Mkdir(dir, 0777); err != nil {
1377 t.Fatal(err)
1378 }
1379 f, err := os.Open(dir)
1380 if err != nil {
1381 t.Fatal(err)
1382 }
1383 newpath := filepath.Join(tmpdir, "dir1")
1384 err = os.Rename(dir, newpath)
1385 if err == nil || !errors.Is(err, windows.ERROR_SHARING_VIOLATION) {
1386 f.Close()
1387 t.Fatalf("Rename(%q, %q) = %v; want windows.ERROR_SHARING_VIOLATION", dir, newpath, err)
1388 }
1389 f.Close()
1390 err = os.Rename(dir, newpath)
1391 if err != nil {
1392 t.Error(err)
1393 }
1394 }
1395
1396 func TestAppExecLinkStat(t *testing.T) {
1397
1398
1399
1400
1401 appdata := os.Getenv("LOCALAPPDATA")
1402 if appdata == "" {
1403 t.Skipf("skipping: LOCALAPPDATA not set")
1404 }
1405
1406 pythonExeName := "python3.exe"
1407 pythonPath := filepath.Join(appdata, `Microsoft\WindowsApps`, pythonExeName)
1408
1409 lfi, err := os.Lstat(pythonPath)
1410 if err != nil {
1411 t.Skip("skipping test, because Python 3 is not installed via the Windows App Store on this system; see https://golang.org/issue/42919")
1412 }
1413
1414
1415
1416 linkName, err := os.Readlink(pythonPath)
1417 if err == nil {
1418 t.Errorf("os.Readlink(%q) = %q, but expected an error\n(should be an APPEXECLINK reparse point, not a symlink)", pythonPath, linkName)
1419 }
1420
1421 sfi, err := os.Stat(pythonPath)
1422 if err != nil {
1423 t.Fatalf("Stat %s: %v", pythonPath, err)
1424 }
1425
1426 if lfi.Name() != sfi.Name() {
1427 t.Logf("os.Lstat(%q) = %+v", pythonPath, lfi)
1428 t.Logf("os.Stat(%q) = %+v", pythonPath, sfi)
1429 t.Errorf("files should be same")
1430 }
1431
1432 if lfi.Name() != pythonExeName {
1433 t.Errorf("Stat %s: got %q, but wanted %q", pythonPath, lfi.Name(), pythonExeName)
1434 }
1435 if tp := lfi.Mode().Type(); tp != fs.ModeIrregular {
1436
1437
1438 t.Errorf("%q should not be a an irregular file (mode=0x%x)", pythonPath, uint32(tp))
1439 }
1440
1441 if sfi.Name() != pythonExeName {
1442 t.Errorf("Stat %s: got %q, but wanted %q", pythonPath, sfi.Name(), pythonExeName)
1443 }
1444 if m := sfi.Mode(); m&fs.ModeSymlink != 0 {
1445 t.Errorf("%q should be a file, not a link (mode=0x%x)", pythonPath, uint32(m))
1446 }
1447 if m := sfi.Mode(); m&fs.ModeDir != 0 {
1448 t.Errorf("%q should be a file, not a directory (mode=0x%x)", pythonPath, uint32(m))
1449 }
1450 if m := sfi.Mode(); m&fs.ModeIrregular == 0 {
1451
1452
1453 t.Errorf("%q should not be a regular file (mode=0x%x)", pythonPath, uint32(m))
1454 }
1455
1456 p, err := exec.LookPath(pythonPath)
1457 if err != nil {
1458 t.Errorf("exec.LookPath(%q): %v", pythonPath, err)
1459 }
1460 if p != pythonPath {
1461 t.Errorf("exec.LookPath(%q) = %q; want %q", pythonPath, p, pythonPath)
1462 }
1463 }
1464
1465 func TestIllformedUTF16FileName(t *testing.T) {
1466 dir := t.TempDir()
1467 const sep = string(os.PathSeparator)
1468 if !strings.HasSuffix(dir, sep) {
1469 dir += sep
1470 }
1471
1472
1473 namew := []uint16{0x2e, 0xdc6d, 0xdc73, 0xdc79, 0xdc73, 0x30, 0x30, 0x30, 0x31, 0}
1474
1475
1476
1477
1478 dirw := utf16.Encode([]rune(dir))
1479 pathw := append(dirw, namew...)
1480 fd, err := syscall.CreateFile(&pathw[0], syscall.GENERIC_ALL, 0, nil, syscall.CREATE_NEW, 0, 0)
1481 if err != nil {
1482 t.Fatal(err)
1483 }
1484 syscall.CloseHandle(fd)
1485
1486 name := syscall.UTF16ToString(namew)
1487 path := filepath.Join(dir, name)
1488
1489 fi, err := os.Lstat(path)
1490 if err != nil {
1491 t.Fatal(err)
1492 }
1493 if got := fi.Name(); got != name {
1494 t.Errorf("got %q, want %q", got, name)
1495 }
1496
1497 f, err := os.Open(dir)
1498 if err != nil {
1499 t.Fatal(err)
1500 }
1501 files, err := f.Readdirnames(0)
1502 f.Close()
1503 if err != nil {
1504 t.Fatal(err)
1505 }
1506 if !slices.Contains(files, name) {
1507 t.Error("file not listed")
1508 }
1509
1510
1511 err = os.RemoveAll(dir)
1512 if err != nil {
1513 t.Error(err)
1514 }
1515 }
1516
1517 func TestUTF16Alloc(t *testing.T) {
1518 allowsPerRun := func(want int, f func()) {
1519 t.Helper()
1520 got := int(testing.AllocsPerRun(5, f))
1521 if got != want {
1522 t.Errorf("got %d allocs, want %d", got, want)
1523 }
1524 }
1525 allowsPerRun(1, func() {
1526 syscall.UTF16ToString([]uint16{'a', 'b', 'c'})
1527 })
1528 allowsPerRun(1, func() {
1529 syscall.UTF16FromString("abc")
1530 })
1531 }
1532
1533 func TestNewFileInvalid(t *testing.T) {
1534 t.Parallel()
1535 if f := os.NewFile(uintptr(syscall.InvalidHandle), "invalid"); f != nil {
1536 t.Errorf("NewFile(InvalidHandle) got %v want nil", f)
1537 }
1538 }
1539
1540 func TestReadDirPipe(t *testing.T) {
1541 dir := `\\.\pipe\`
1542 fi, err := os.Stat(dir)
1543 if err != nil || !fi.IsDir() {
1544 t.Skipf("%s is not a directory", dir)
1545 }
1546 _, err = os.ReadDir(dir)
1547 if err != nil {
1548 t.Errorf("ReadDir(%q) = %v", dir, err)
1549 }
1550 }
1551
1552 func TestReadDirNoFileID(t *testing.T) {
1553 *os.AllowReadDirFileID = false
1554 defer func() { *os.AllowReadDirFileID = true }()
1555
1556 dir := t.TempDir()
1557 pathA := filepath.Join(dir, "a")
1558 pathB := filepath.Join(dir, "b")
1559 if err := os.WriteFile(pathA, nil, 0666); err != nil {
1560 t.Fatal(err)
1561 }
1562 if err := os.WriteFile(pathB, nil, 0666); err != nil {
1563 t.Fatal(err)
1564 }
1565
1566 files, err := os.ReadDir(dir)
1567 if err != nil {
1568 t.Fatal(err)
1569 }
1570 if len(files) != 2 {
1571 t.Fatalf("ReadDir(%q) = %v; want 2 files", dir, files)
1572 }
1573
1574
1575 f1, err := files[0].Info()
1576 if err != nil {
1577 t.Fatal(err)
1578 }
1579 f2, err := files[1].Info()
1580 if err != nil {
1581 t.Fatal(err)
1582 }
1583 if !os.SameFile(f1, f1) {
1584 t.Errorf("SameFile(%v, %v) = false; want true", f1, f1)
1585 }
1586 if !os.SameFile(f2, f2) {
1587 t.Errorf("SameFile(%v, %v) = false; want true", f2, f2)
1588 }
1589 if os.SameFile(f1, f2) {
1590 t.Errorf("SameFile(%v, %v) = true; want false", f1, f2)
1591 }
1592
1593
1594 f1s, err := os.Stat(pathA)
1595 if err != nil {
1596 t.Fatal(err)
1597 }
1598 f2s, err := os.Stat(pathB)
1599 if err != nil {
1600 t.Fatal(err)
1601 }
1602 if !os.SameFile(f1, f1s) {
1603 t.Errorf("SameFile(%v, %v) = false; want true", f1, f1s)
1604 }
1605 if !os.SameFile(f2, f2s) {
1606 t.Errorf("SameFile(%v, %v) = false; want true", f2, f2s)
1607 }
1608 }
1609
View as plain text