1819 break |
1835 break |
1820 } |
1836 } |
1821 } |
1837 } |
1822 return err |
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 } |