mirror of
https://github.com/golang/sys.git
synced 2026-02-08 11:46:04 +03:00
x/sys/unix: make ReadDirent available on zOS
Currently ReadDirent is not available on zOS. This implementation modifies the current darwin implementation to work on zOS. Also make tests available on zOS. Fixes golang/go#54528 Fixes golang/go#54587 Change-Id: I62a09d0068ec8c5fdc849a411ce43bdf14ca3926 Reviewed-on: https://go-review.googlesource.com/c/sys/+/424778 Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Joedian Reid <joedian@golang.org> Reviewed-by: Bill O'Farrell <billotosyr@gmail.com> Run-TryBot: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
This commit is contained in:
committed by
Gopher Robot
parent
090e33056c
commit
95e765b1cc
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package unix
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package unix_test
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin || dragonfly || freebsd || openbsd || netbsd
|
||||
// +build darwin dragonfly freebsd openbsd netbsd
|
||||
//go:build darwin || dragonfly || freebsd || openbsd || netbsd || zos
|
||||
// +build darwin dragonfly freebsd openbsd netbsd zos
|
||||
|
||||
package unix_test
|
||||
|
||||
|
||||
@@ -9,8 +9,10 @@ package unix
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
@@ -55,7 +57,13 @@ func (d *Dirent) NameString() string {
|
||||
if d == nil {
|
||||
return ""
|
||||
}
|
||||
return string(d.Name[:d.Namlen])
|
||||
s := string(d.Name[:])
|
||||
idx := strings.IndexByte(s, 0)
|
||||
if idx == -1 {
|
||||
return s
|
||||
} else {
|
||||
return s[:idx]
|
||||
}
|
||||
}
|
||||
|
||||
func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
@@ -1230,6 +1238,14 @@ func Readdir(dir uintptr) (*Dirent, error) {
|
||||
return &ent, err
|
||||
}
|
||||
|
||||
func readdir_r(dirp uintptr, entry *direntLE, result **direntLE) (err error) {
|
||||
r0, _, e1 := syscall_syscall(SYS___READDIR_R_A, dirp, uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result)))
|
||||
if int64(r0) == -1 {
|
||||
err = errnoErr(Errno(e1))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Closedir(dir uintptr) error {
|
||||
_, _, e := syscall_syscall(SYS_CLOSEDIR, dir, 0, 0)
|
||||
if e != 0 {
|
||||
@@ -1821,3 +1837,158 @@ func Unmount(name string, mtm int) (err error) {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func fdToPath(dirfd int) (path string, err error) {
|
||||
var buffer [1024]byte
|
||||
// w_ctrl()
|
||||
ret := runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS_W_IOCTL<<4,
|
||||
[]uintptr{uintptr(dirfd), 17, 1024, uintptr(unsafe.Pointer(&buffer[0]))})
|
||||
if ret == 0 {
|
||||
zb := bytes.IndexByte(buffer[:], 0)
|
||||
if zb == -1 {
|
||||
zb = len(buffer)
|
||||
}
|
||||
// __e2a_l()
|
||||
runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___E2A_L<<4,
|
||||
[]uintptr{uintptr(unsafe.Pointer(&buffer[0])), uintptr(zb)})
|
||||
return string(buffer[:zb]), nil
|
||||
}
|
||||
// __errno()
|
||||
errno := int(*(*int32)(unsafe.Pointer(runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___ERRNO<<4,
|
||||
[]uintptr{}))))
|
||||
// __errno2()
|
||||
errno2 := int(runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___ERRNO2<<4,
|
||||
[]uintptr{}))
|
||||
// strerror_r()
|
||||
ret = runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS_STRERROR_R<<4,
|
||||
[]uintptr{uintptr(errno), uintptr(unsafe.Pointer(&buffer[0])), 1024})
|
||||
if ret == 0 {
|
||||
zb := bytes.IndexByte(buffer[:], 0)
|
||||
if zb == -1 {
|
||||
zb = len(buffer)
|
||||
}
|
||||
return "", fmt.Errorf("%s (errno2=0x%x)", buffer[:zb], errno2)
|
||||
} else {
|
||||
return "", fmt.Errorf("fdToPath errno %d (errno2=0x%x)", errno, errno2)
|
||||
}
|
||||
}
|
||||
|
||||
func direntLeToDirentUnix(dirent *direntLE, dir uintptr, path string) (Dirent, error) {
|
||||
var d Dirent
|
||||
|
||||
d.Ino = uint64(dirent.Ino)
|
||||
offset, err := Telldir(dir)
|
||||
if err != nil {
|
||||
return d, err
|
||||
}
|
||||
|
||||
d.Off = int64(offset)
|
||||
s := string(bytes.Split(dirent.Name[:], []byte{0})[0])
|
||||
copy(d.Name[:], s)
|
||||
|
||||
d.Reclen = uint16(24 + len(d.NameString()))
|
||||
var st Stat_t
|
||||
path = path + "/" + s
|
||||
err = Lstat(path, &st)
|
||||
if err != nil {
|
||||
return d, err
|
||||
}
|
||||
|
||||
d.Type = uint8(st.Mode >> 24)
|
||||
return d, err
|
||||
}
|
||||
|
||||
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
// Simulation of Getdirentries port from the Darwin implementation.
|
||||
// COMMENTS FROM DARWIN:
|
||||
// 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
|
||||
}
|
||||
|
||||
// Get path from fd to avoid unavailable call (fdopendir)
|
||||
path, err := fdToPath(fd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d, err := Opendir(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer Closedir(d)
|
||||
|
||||
var cnt int64
|
||||
for {
|
||||
var entryLE direntLE
|
||||
var entrypLE *direntLE
|
||||
e := readdir_r(d, &entryLE, &entrypLE)
|
||||
if e != nil {
|
||||
return n, e
|
||||
}
|
||||
if entrypLE == nil {
|
||||
break
|
||||
}
|
||||
if skip > 0 {
|
||||
skip--
|
||||
cnt++
|
||||
continue
|
||||
}
|
||||
|
||||
// Dirent on zos has a different structure
|
||||
entry, e := direntLeToDirentUnix(&entryLE, d, path)
|
||||
if e != nil {
|
||||
return n, e
|
||||
}
|
||||
|
||||
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.
|
||||
s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), 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
|
||||
}
|
||||
|
||||
func ReadDirent(fd int, buf []byte) (n int, err error) {
|
||||
var base = (*uintptr)(unsafe.Pointer(new(uint64)))
|
||||
return Getdirentries(fd, buf, base)
|
||||
}
|
||||
|
||||
func direntIno(buf []byte) (uint64, bool) {
|
||||
return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
|
||||
}
|
||||
|
||||
func direntReclen(buf []byte) (uint64, bool) {
|
||||
return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
|
||||
}
|
||||
|
||||
func direntNamlen(buf []byte) (uint64, bool) {
|
||||
reclen, ok := direntReclen(buf)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ type Statfs_t struct {
|
||||
Flags uint64
|
||||
}
|
||||
|
||||
type Dirent struct {
|
||||
type direntLE struct {
|
||||
Reclen uint16
|
||||
Namlen uint16
|
||||
Ino uint32
|
||||
@@ -347,6 +347,15 @@ type Dirent struct {
|
||||
Name [256]byte
|
||||
}
|
||||
|
||||
type Dirent struct {
|
||||
Ino uint64
|
||||
Off int64
|
||||
Reclen uint16
|
||||
Type uint8
|
||||
Name [256]uint8
|
||||
_ [5]byte
|
||||
}
|
||||
|
||||
type FdSet struct {
|
||||
Bits [64]int32
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user