aboutsummaryrefslogtreecommitdiff
path: root/src/syscall/syscall_darwin.go
diff options
context:
space:
mode:
authorKeith Randall <keithr@alum.mit.edu>2019-03-20 10:47:17 -0700
committerKeith Randall <khr@golang.org>2019-04-03 21:27:05 +0000
commit9da6530faab0a58c4c4e02b2f3f4a5c754dcbd4e (patch)
treea49cee6c873b4854bb64ae252f11dc6051869647 /src/syscall/syscall_darwin.go
parent48ef01051ae58265088ee87f3a408224d2cfaec3 (diff)
downloadgo-9da6530faab0a58c4c4e02b2f3f4a5c754dcbd4e.tar.xz
syscall: avoid _getdirentries64 on darwin
Getdirentries is implemented with the __getdirentries64 function in libSystem.dylib. That function works, but it's on Apple's can't-be-used-in-an-app-store-application list. Implement Getdirentries using the underlying fdopendir/readdir_r/closedir. The simulation isn't faithful, and could be slow, but it should handle common cases. Don't use Getdirentries in the stdlib, use fdopendir/readdir_r/closedir instead (via (*os.File).readdirnames). Fixes #30933 Update #28984 RELNOTE=yes Change-Id: Ia6b5d003e5bfe43ba54b1e1d9cfa792cc6511717 Reviewed-on: https://go-review.googlesource.com/c/go/+/168479 Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/syscall/syscall_darwin.go')
-rw-r--r--src/syscall/syscall_darwin.go55
1 files changed, 55 insertions, 0 deletions
diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go
index 80e42b0aec..59669a473d 100644
--- a/src/syscall/syscall_darwin.go
+++ b/src/syscall/syscall_darwin.go
@@ -258,6 +258,7 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
//sys Chown(path string, uid int, gid int) (err error)
//sys Chroot(path string) (err error)
//sys Close(fd int) (err error)
+//sys closedir(dir uintptr) (err error)
//sys Dup(fd int) (nfd int, err error)
//sys Dup2(from int, to int) (err error)
//sys Exchangedata(path1 string, path2 string, options int) (err error)
@@ -301,6 +302,7 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
//sys read(fd int, p []byte) (n int, err error)
+//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
//sys Readlink(path string, buf []byte) (n int, err error)
//sys Rename(from string, to string) (err error)
//sys Revoke(path string) (err error)
@@ -363,12 +365,65 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
return
}
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ // Simulate Getdirentries using fdopendir/readdir_r/closedir.
+ const ptrSize = unsafe.Sizeof(uintptr(0))
+ d, err := fdopendir(fd)
+ if err != nil {
+ return 0, err
+ }
+ defer closedir(d)
+ // We keep the number of records already returned in *basep.
+ // It's not the full required semantics, but should handle the case
+ // of calling Getdirentries repeatedly.
+ // It won't handle assigning the results of lseek to *basep, or handle
+ // the directory being edited underfoot.
+ skip := *basep
+ *basep = 0
+ for {
+ var entry Dirent
+ var entryp *Dirent
+ e := readdir_r(d, &entry, &entryp)
+ if e != 0 {
+ return n, errnoErr(e)
+ }
+ if entryp == nil {
+ break
+ }
+ if skip > 0 {
+ skip--
+ *basep++
+ continue
+ }
+ reclen := int(entry.Reclen)
+ if reclen > len(buf) {
+ // Not enough room. Return for now.
+ // *basep will let us know where we should start up again.
+ // Note: this strategy for suspending in the middle and
+ // restarting is O(n^2) in the length of the directory. Oh well.
+ break
+ }
+ // Copy entry into return buffer.
+ s := struct {
+ ptr unsafe.Pointer
+ siz int
+ cap int
+ }{ptr: unsafe.Pointer(&entry), siz: reclen, cap: reclen}
+ copy(buf, *(*[]byte)(unsafe.Pointer(&s)))
+ buf = buf[reclen:]
+ n += reclen
+ *basep++
+ }
+ return n, nil
+}
+
// Implemented in the runtime package (runtime/sys_darwin.go)
func syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
// Find the entry point for f. See comments in runtime/proc.go for the
// function of the same name.