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