zsyscall_darwin.go

 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}