Skip to content

Commit 95e765b

Browse files
dustin-wardgopherbot
authored andcommitted
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>
1 parent 090e330 commit 95e765b

File tree

5 files changed

+188
-8
lines changed

5 files changed

+188
-8
lines changed

unix/dirent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
6-
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
5+
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
6+
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
77

88
package unix
99

unix/dirent_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
6-
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
5+
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
6+
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
77

88
package unix_test
99

unix/getdirentries_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build darwin || dragonfly || freebsd || openbsd || netbsd
6-
// +build darwin dragonfly freebsd openbsd netbsd
5+
//go:build darwin || dragonfly || freebsd || openbsd || netbsd || zos
6+
// +build darwin dragonfly freebsd openbsd netbsd zos
77

88
package unix_test
99

unix/syscall_zos_s390x.go

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ package unix
99

1010
import (
1111
"bytes"
12+
"fmt"
1213
"runtime"
1314
"sort"
15+
"strings"
1416
"sync"
1517
"syscall"
1618
"unsafe"
@@ -55,7 +57,13 @@ func (d *Dirent) NameString() string {
5557
if d == nil {
5658
return ""
5759
}
58-
return string(d.Name[:d.Namlen])
60+
s := string(d.Name[:])
61+
idx := strings.IndexByte(s, 0)
62+
if idx == -1 {
63+
return s
64+
} else {
65+
return s[:idx]
66+
}
5967
}
6068

6169
func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
@@ -1230,6 +1238,14 @@ func Readdir(dir uintptr) (*Dirent, error) {
12301238
return &ent, err
12311239
}
12321240

1241+
func readdir_r(dirp uintptr, entry *direntLE, result **direntLE) (err error) {
1242+
r0, _, e1 := syscall_syscall(SYS___READDIR_R_A, dirp, uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result)))
1243+
if int64(r0) == -1 {
1244+
err = errnoErr(Errno(e1))
1245+
}
1246+
return
1247+
}
1248+
12331249
func Closedir(dir uintptr) error {
12341250
_, _, e := syscall_syscall(SYS_CLOSEDIR, dir, 0, 0)
12351251
if e != 0 {
@@ -1821,3 +1837,158 @@ func Unmount(name string, mtm int) (err error) {
18211837
}
18221838
return err
18231839
}
1840+
1841+
func fdToPath(dirfd int) (path string, err error) {
1842+
var buffer [1024]byte
1843+
// w_ctrl()
1844+
ret := runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS_W_IOCTL<<4,
1845+
[]uintptr{uintptr(dirfd), 17, 1024, uintptr(unsafe.Pointer(&buffer[0]))})
1846+
if ret == 0 {
1847+
zb := bytes.IndexByte(buffer[:], 0)
1848+
if zb == -1 {
1849+
zb = len(buffer)
1850+
}
1851+
// __e2a_l()
1852+
runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___E2A_L<<4,
1853+
[]uintptr{uintptr(unsafe.Pointer(&buffer[0])), uintptr(zb)})
1854+
return string(buffer[:zb]), nil
1855+
}
1856+
// __errno()
1857+
errno := int(*(*int32)(unsafe.Pointer(runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___ERRNO<<4,
1858+
[]uintptr{}))))
1859+
// __errno2()
1860+
errno2 := int(runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___ERRNO2<<4,
1861+
[]uintptr{}))
1862+
// strerror_r()
1863+
ret = runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS_STRERROR_R<<4,
1864+
[]uintptr{uintptr(errno), uintptr(unsafe.Pointer(&buffer[0])), 1024})
1865+
if ret == 0 {
1866+
zb := bytes.IndexByte(buffer[:], 0)
1867+
if zb == -1 {
1868+
zb = len(buffer)
1869+
}
1870+
return "", fmt.Errorf("%s (errno2=0x%x)", buffer[:zb], errno2)
1871+
} else {
1872+
return "", fmt.Errorf("fdToPath errno %d (errno2=0x%x)", errno, errno2)
1873+
}
1874+
}
1875+
1876+
func direntLeToDirentUnix(dirent *direntLE, dir uintptr, path string) (Dirent, error) {
1877+
var d Dirent
1878+
1879+
d.Ino = uint64(dirent.Ino)
1880+
offset, err := Telldir(dir)
1881+
if err != nil {
1882+
return d, err
1883+
}
1884+
1885+
d.Off = int64(offset)
1886+
s := string(bytes.Split(dirent.Name[:], []byte{0})[0])
1887+
copy(d.Name[:], s)
1888+
1889+
d.Reclen = uint16(24 + len(d.NameString()))
1890+
var st Stat_t
1891+
path = path + "/" + s
1892+
err = Lstat(path, &st)
1893+
if err != nil {
1894+
return d, err
1895+
}
1896+
1897+
d.Type = uint8(st.Mode >> 24)
1898+
return d, err
1899+
}
1900+
1901+
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
1902+
// Simulation of Getdirentries port from the Darwin implementation.
1903+
// COMMENTS FROM DARWIN:
1904+
// It's not the full required semantics, but should handle the case
1905+
// of calling Getdirentries or ReadDirent repeatedly.
1906+
// It won't handle assigning the results of lseek to *basep, or handle
1907+
// the directory being edited underfoot.
1908+
1909+
skip, err := Seek(fd, 0, 1 /* SEEK_CUR */)
1910+
if err != nil {
1911+
return 0, err
1912+
}
1913+
1914+
// Get path from fd to avoid unavailable call (fdopendir)
1915+
path, err := fdToPath(fd)
1916+
if err != nil {
1917+
return 0, err
1918+
}
1919+
d, err := Opendir(path)
1920+
if err != nil {
1921+
return 0, err
1922+
}
1923+
defer Closedir(d)
1924+
1925+
var cnt int64
1926+
for {
1927+
var entryLE direntLE
1928+
var entrypLE *direntLE
1929+
e := readdir_r(d, &entryLE, &entrypLE)
1930+
if e != nil {
1931+
return n, e
1932+
}
1933+
if entrypLE == nil {
1934+
break
1935+
}
1936+
if skip > 0 {
1937+
skip--
1938+
cnt++
1939+
continue
1940+
}
1941+
1942+
// Dirent on zos has a different structure
1943+
entry, e := direntLeToDirentUnix(&entryLE, d, path)
1944+
if e != nil {
1945+
return n, e
1946+
}
1947+
1948+
reclen := int(entry.Reclen)
1949+
if reclen > len(buf) {
1950+
// Not enough room. Return for now.
1951+
// The counter will let us know where we should start up again.
1952+
// Note: this strategy for suspending in the middle and
1953+
// restarting is O(n^2) in the length of the directory. Oh well.
1954+
break
1955+
}
1956+
1957+
// Copy entry into return buffer.
1958+
s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen)
1959+
copy(buf, s)
1960+
1961+
buf = buf[reclen:]
1962+
n += reclen
1963+
cnt++
1964+
}
1965+
// Set the seek offset of the input fd to record
1966+
// how many files we've already returned.
1967+
_, err = Seek(fd, cnt, 0 /* SEEK_SET */)
1968+
if err != nil {
1969+
return n, err
1970+
}
1971+
1972+
return n, nil
1973+
}
1974+
1975+
func ReadDirent(fd int, buf []byte) (n int, err error) {
1976+
var base = (*uintptr)(unsafe.Pointer(new(uint64)))
1977+
return Getdirentries(fd, buf, base)
1978+
}
1979+
1980+
func direntIno(buf []byte) (uint64, bool) {
1981+
return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
1982+
}
1983+
1984+
func direntReclen(buf []byte) (uint64, bool) {
1985+
return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
1986+
}
1987+
1988+
func direntNamlen(buf []byte) (uint64, bool) {
1989+
reclen, ok := direntReclen(buf)
1990+
if !ok {
1991+
return 0, false
1992+
}
1993+
return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
1994+
}

unix/ztypes_zos_s390x.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,14 +339,23 @@ type Statfs_t struct {
339339
Flags uint64
340340
}
341341

342-
type Dirent struct {
342+
type direntLE struct {
343343
Reclen uint16
344344
Namlen uint16
345345
Ino uint32
346346
Extra uintptr
347347
Name [256]byte
348348
}
349349

350+
type Dirent struct {
351+
Ino uint64
352+
Off int64
353+
Reclen uint16
354+
Type uint8
355+
Name [256]uint8
356+
_ [5]byte
357+
}
358+
350359
type FdSet struct {
351360
Bits [64]int32
352361
}

0 commit comments

Comments
 (0)