@@ -9,8 +9,10 @@ package unix
99
1010import (
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
6169func (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+
12331249func 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+ }
0 commit comments