1//go:build darwin && go1.13
2// +build darwin,go1.13
3
4package fastwalk
5
6import (
7 "strings"
8 "syscall"
9 "unsafe"
10)
11
12// TODO: consider using "go linkname" for everything but "opendir" which is not
13// implemented in the stdlib
14
15// Implemented in the runtime package (runtime/sys_darwin.go)
16func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
17func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
18
19//go:linkname syscall_syscall syscall.syscall
20//go:linkname syscall_syscallPtr syscall.syscallPtr
21
22func closedir(dir uintptr) (err error) {
23 _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, dir, 0, 0)
24 if e1 != 0 {
25 err = errnoErr(e1)
26 }
27 return
28}
29
30var libc_closedir_trampoline_addr uintptr
31
32//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib"
33
34func readdir_r(dir uintptr, entry *syscall.Dirent, result **syscall.Dirent) syscall.Errno {
35 res, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, dir, uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result)))
36 return syscall.Errno(res)
37}
38
39var libc_readdir_r_trampoline_addr uintptr
40
41//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib"
42
43func opendir(path string) (dir uintptr, err error) {
44 // We implent opendir so that we don't have to open a file, duplicate
45 // it's FD, then call fdopendir with it.
46
47 const maxPath = len(syscall.Dirent{}.Name) // Tested by TestFastWalk_LongPath
48
49 var buf [maxPath]byte
50 if len(path) >= len(buf) {
51 return 0, errEINVAL
52 }
53 if strings.IndexByte(path, 0) != -1 {
54 return 0, errEINVAL
55 }
56 copy(buf[:], path)
57 buf[len(path)] = 0
58 r0, _, e1 := syscall_syscallPtr(libc_opendir_trampoline_addr, uintptr(unsafe.Pointer(&buf[0])), 0, 0)
59 if e1 != 0 {
60 err = errnoErr(e1)
61 }
62 return r0, err
63}
64
65var libc_opendir_trampoline_addr uintptr
66
67//go:cgo_import_dynamic libc_opendir opendir "/usr/lib/libSystem.B.dylib"
68
69// Copied from syscall/syscall_unix.go
70
71// Do the interface allocations only once for common
72// Errno values.
73var (
74 errEAGAIN error = syscall.EAGAIN
75 errEINVAL error = syscall.EINVAL
76 errENOENT error = syscall.ENOENT
77)
78
79// errnoErr returns common boxed Errno values, to prevent
80// allocations at runtime.
81func errnoErr(e syscall.Errno) error {
82 switch e {
83 case 0:
84 return nil
85 case syscall.EAGAIN:
86 return errEAGAIN
87 case syscall.EINVAL:
88 return errEINVAL
89 case syscall.ENOENT:
90 return errENOENT
91 }
92 return e
93}