@@ -9,8 +9,10 @@ package unix
9
9
10
10
import (
11
11
"bytes"
12
+ "fmt"
12
13
"runtime"
13
14
"sort"
15
+ "strings"
14
16
"sync"
15
17
"syscall"
16
18
"unsafe"
@@ -55,7 +57,13 @@ func (d *Dirent) NameString() string {
55
57
if d == nil {
56
58
return ""
57
59
}
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
+ }
59
67
}
60
68
61
69
func (sa * SockaddrInet4 ) sockaddr () (unsafe.Pointer , _Socklen , error ) {
@@ -1230,6 +1238,14 @@ func Readdir(dir uintptr) (*Dirent, error) {
1230
1238
return & ent , err
1231
1239
}
1232
1240
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
+
1233
1249
func Closedir (dir uintptr ) error {
1234
1250
_ , _ , e := syscall_syscall (SYS_CLOSEDIR , dir , 0 , 0 )
1235
1251
if e != 0 {
@@ -1821,3 +1837,158 @@ func Unmount(name string, mtm int) (err error) {
1821
1837
}
1822
1838
return err
1823
1839
}
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