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