os: Clean up directory reading code.
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 6 Dec 2012 02:00:13 +0000 (02:00 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 6 Dec 2012 02:00:13 +0000 (02:00 +0000)
From-SVN: r194237

libgo/go/os/dir.go
libgo/go/os/file_unix.go

index a35d525319a6811255cb9c6780e5150b92b67280..d811c9fdd863682e0bf601adbf8a342885780448 100644 (file)
@@ -6,6 +6,7 @@ package os
 
 import (
        "io"
+       "sync/atomic"
        "syscall"
        "unsafe"
 )
@@ -29,27 +30,42 @@ func clen(n []byte) int {
        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 {
-               file.dirinfo = new(dirInfo)
-               file.dirinfo.buf = make([]byte, elen)
-               p := syscall.StringBytePtr(file.name)
+               p, err := syscall.BytePtrFromString(file.name)
+               if err != nil {
+                       return nil, err
+               }
+
+               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)
                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 @@ func (file *File) readdirnames(n int) (names []string, err error) {
 
        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
                }
index f677dbb986ad775bc4b6d898bb884f8393a08814..68f4be88d06853c967df561aa4cdffa441a53759 100644 (file)
@@ -108,8 +108,13 @@ func (file *file) close() error {
        }
 
        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}
                }
        }