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