@@ -6,6 +6,7 @@
import (
"io"
+ "sync/atomic"
"syscall"
"unsafe"
)
@@ -29,27 +30,42 @@
return len(n)
}
-var elen int
+var nameMax int32
func (file *File) readdirnames(n int) (names []string, err error) {
- if elen == 0 {
- var dummy syscall.Dirent
- elen = (int(unsafe.Offsetof(dummy.Name)) +
- libc_pathconf(syscall.StringBytePtr(file.name), syscall.PC_NAME_MAX) +
- 1)
- }
+ if file.dirinfo == nil {
+ p, err := syscall.BytePtrFromString(file.name)
+ if err != nil {
+ return nil, err
+ }
- if file.dirinfo == nil {
+ elen := int(atomic.LoadInt32(&nameMax))
+ if elen == 0 {
+ syscall.Entersyscall()
+ plen := libc_pathconf(p, syscall.PC_NAME_MAX)
+ syscall.Exitsyscall()
+ if plen < 1024 {
+ plen = 1024
+ }
+ var dummy syscall.Dirent
+ elen = int(unsafe.Offsetof(dummy.Name)) + plen + 1
+ atomic.StoreInt32(&nameMax, int32(elen))
+ }
+
+ syscall.Entersyscall()
+ r := libc_opendir(p)
+ errno := syscall.GetErrno()
+ syscall.Exitsyscall()
+ if r == nil {
+ return nil, &PathError{"opendir", file.name, errno}
+ }
+
file.dirinfo = new(dirInfo)
file.dirinfo.buf = make([]byte, elen)
- p := syscall.StringBytePtr(file.name)
- syscall.Entersyscall()
- r := libc_opendir(p)
- syscall.Exitsyscall()
file.dirinfo.dir = r
}
- entry_dirent := (*syscall.Dirent)(unsafe.Pointer(&file.dirinfo.buf[0]))
+ entryDirent := (*syscall.Dirent)(unsafe.Pointer(&file.dirinfo.buf[0]))
size := n
if size <= 0 {
@@ -59,24 +75,20 @@
names = make([]string, 0, size) // Empty with room to grow.
- dir := file.dirinfo.dir
- if dir == nil {
- return names, NewSyscallError("opendir", syscall.GetErrno())
- }
-
for n != 0 {
- var result *syscall.Dirent
- pr := &result
+ var dirent *syscall.Dirent
+ pr := &dirent
syscall.Entersyscall()
- i := libc_readdir_r(dir, entry_dirent, pr)
+ i := libc_readdir_r(file.dirinfo.dir, entryDirent, pr)
syscall.Exitsyscall()
if i != 0 {
return names, NewSyscallError("readdir_r", i)
}
- if result == nil {
+ if dirent == nil {
break // EOF
}
- var name = string(result.Name[0:clen(result.Name[0:])])
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:clen(bytes[:])])
if name == "." || name == ".." { // Useless names
continue
}
@@ -108,8 +108,13 @@
}
if file.dirinfo != nil {
- if libc_closedir(file.dirinfo.dir) < 0 && err == nil {
- err = &PathError{"closedir", file.name, syscall.GetErrno()}
+ syscall.Entersyscall()
+ i := libc_closedir(file.dirinfo.dir)
+ errno := syscall.GetErrno()
+ syscall.Exitsyscall()
+ file.dirinfo = nil
+ if i < 0 && err == nil {
+ err = &PathError{"closedir", file.name, errno}
}
}