mirror of
https://github.com/golang/sys.git
synced 2026-02-09 04:06:04 +03:00
In Go 1.17 we will introduce a register-based ABI on some platforms, as well as ABI wrappers to bridge the ABIs. For Darwin syscall wrappers, it needs to be called directly, instead of through wrappers. Currently, it is written as that the syscall functions are defined in assembly and their addresses are taken from Go using funcPC. In Go 1.17 this will result in the address of the ABI wrapper, which is undesired. In the syscall package in the standard library we changed to use a compiler intrinsic internal/abi.FuncPCABI0 to take the address of the syscall function. But that is not available to this repo and not available in older versions of Go. Here we take a different approach: taking the address directly from assembly. This also ensures we get the address of the defined syscall function, not the ABI wrapper. Updates golang/go#45702. Change-Id: Ia7480d0fb0ca4fb9bf2f36d2deb1e3e5e4eb8284 Reviewed-on: https://go-review.googlesource.com/c/sys/+/317894 Trust: Cherry Mui <cherryyz@google.com> Run-TryBot: Cherry Mui <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
109 lines
2.7 KiB
Go
109 lines
2.7 KiB
Go
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build darwin && go1.13
|
|
// +build darwin,go1.13
|
|
|
|
package unix
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/internal/unsafeheader"
|
|
)
|
|
|
|
//sys closedir(dir uintptr) (err error)
|
|
//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
|
|
|
|
func fdopendir(fd int) (dir uintptr, err error) {
|
|
r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0)
|
|
dir = uintptr(r0)
|
|
if e1 != 0 {
|
|
err = errnoErr(e1)
|
|
}
|
|
return
|
|
}
|
|
|
|
var libc_fdopendir_trampoline_addr uintptr
|
|
|
|
//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"
|
|
|
|
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
|
// Simulate Getdirentries using fdopendir/readdir_r/closedir.
|
|
// We store the number of entries to skip in the seek
|
|
// offset of fd. See issue #31368.
|
|
// It's not the full required semantics, but should handle the case
|
|
// of calling Getdirentries or ReadDirent repeatedly.
|
|
// It won't handle assigning the results of lseek to *basep, or handle
|
|
// the directory being edited underfoot.
|
|
skip, err := Seek(fd, 0, 1 /* SEEK_CUR */)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// We need to duplicate the incoming file descriptor
|
|
// because the caller expects to retain control of it, but
|
|
// fdopendir expects to take control of its argument.
|
|
// Just Dup'ing the file descriptor is not enough, as the
|
|
// result shares underlying state. Use Openat to make a really
|
|
// new file descriptor referring to the same directory.
|
|
fd2, err := Openat(fd, ".", O_RDONLY, 0)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
d, err := fdopendir(fd2)
|
|
if err != nil {
|
|
Close(fd2)
|
|
return 0, err
|
|
}
|
|
defer closedir(d)
|
|
|
|
var cnt int64
|
|
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--
|
|
cnt++
|
|
continue
|
|
}
|
|
|
|
reclen := int(entry.Reclen)
|
|
if reclen > len(buf) {
|
|
// Not enough room. Return for now.
|
|
// The counter 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.
|
|
var s []byte
|
|
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&s))
|
|
hdr.Data = unsafe.Pointer(&entry)
|
|
hdr.Cap = reclen
|
|
hdr.Len = reclen
|
|
copy(buf, s)
|
|
|
|
buf = buf[reclen:]
|
|
n += reclen
|
|
cnt++
|
|
}
|
|
// Set the seek offset of the input fd to record
|
|
// how many files we've already returned.
|
|
_, err = Seek(fd, cnt, 0 /* SEEK_SET */)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
|
|
return n, nil
|
|
}
|