]> Cypherpunks repositories - gostls13.git/commitdiff
os: fix Readdir in Plan 9
authorFazlul Shahriar <fshahriar@gmail.com>
Tue, 12 Apr 2011 23:58:56 +0000 (16:58 -0700)
committerRob Pike <r@golang.org>
Tue, 12 Apr 2011 23:58:56 +0000 (16:58 -0700)
'TestReaddir.*' tests now passes.

R=golang-dev, lucio, r
CC=golang-dev
https://golang.org/cl/4381048

src/pkg/os/dir_plan9.go
src/pkg/os/error_plan9.go
src/pkg/os/file_plan9.go
src/pkg/os/os_test.go

index 7bb0642e47971d1d95a6b5f61fa9310119424fab..a53c764e382efed1ef7e955f6f0d76caa2498714 100644 (file)
@@ -8,72 +8,56 @@ import (
        "syscall"
 )
 
-type dirInfo int
-
-var markDirectory dirInfo = ^0
-
 // Readdir reads the contents of the directory associated with file and
-// returns an array of up to count FileInfo structures, as would be returned
-// by Lstat, in directory order.  Subsequent calls on the same file will yield
-// further FileInfos. A negative count means to read the entire directory.
+// returns an array of up to count FileInfo structures, in directory order. 
+// Subsequent calls on the same file will yield further FileInfos.
+// A negative count means to read until EOF.
 // Readdir returns the array and an Error, if any.
 func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
        // If this file has no dirinfo, create one.
        if file.dirinfo == nil {
-               file.dirinfo = &markDirectory
+               file.dirinfo = new(dirInfo)
        }
-
+       d := file.dirinfo
        size := count
        if size < 0 {
                size = 100
        }
-
-       result := make([]FileInfo, 0, size)
-       var buf [syscall.STATMAX]byte
-
-       for {
-               n, e := file.Read(buf[:])
-
-               if e != nil {
+       result := make([]FileInfo, 0, size) // Empty with room to grow.
+       for count != 0 {
+               // Refill the buffer if necessary
+               if d.bufp >= d.nbuf {
+                       d.bufp = 0
+                       var e Error
+                       d.nbuf, e = file.Read(d.buf[:])
+                       if e != nil && e != EOF {
+                               return nil, &PathError{"readdir", file.name, e}
+                       }
                        if e == EOF {
                                break
                        }
-
-                       return []FileInfo{}, &PathError{"readdir", file.name, e}
+                       if d.nbuf < syscall.STATFIXLEN {
+                               return nil, &PathError{"readdir", file.name, Eshortstat}
+                       }
                }
 
-               if n < syscall.STATFIXLEN {
-                       return []FileInfo{}, &PathError{"readdir", file.name, Eshortstat}
+               // Get a record from buffer
+               m, _ := gbit16(d.buf[d.bufp:])
+               m += 2
+               if m < syscall.STATFIXLEN {
+                       return nil, &PathError{"readdir", file.name, Eshortstat}
                }
-
-               for i := 0; i < n; {
-                       m, _ := gbit16(buf[i:])
-                       m += 2
-
-                       if m < syscall.STATFIXLEN {
-                               return []FileInfo{}, &PathError{"readdir", file.name, Eshortstat}
-                       }
-
-                       d, e := UnmarshalDir(buf[i : i+int(m)])
-
-                       if e != nil {
-                               return []FileInfo{}, &PathError{"readdir", file.name, e}
-                       }
-
-                       var f FileInfo
-                       fileInfoFromStat(&f, d)
-
-                       result = append(result, f)
-
-                       // a negative count means to read until EOF.
-                       if count > 0 && len(result) >= count {
-                               break
-                       }
-
-                       i += int(m)
+               dir, e := UnmarshalDir(d.buf[d.bufp : d.bufp+int(m)])
+               if e != nil {
+                       return nil, &PathError{"readdir", file.name, e}
                }
-       }
+               var f FileInfo
+               fileInfoFromStat(&f, dir)
+               result = append(result, f)
 
+               d.bufp += int(m)
+               count--
+       }
        return result, nil
 }
 
index d6575864e843d4e1f33ab0518a6a003d03970f04..3374775b8e7d0c4f99bdc4938d4b69e0d3ddb240 100644 (file)
@@ -37,12 +37,15 @@ var (
        Enonexist  = NewError("file does not exist")
        Eexist     = NewError("file already exists")
        Eio        = NewError("i/o error")
+       Eperm      = NewError("permission denied")
 
        EINVAL  = Ebadarg
        ENOTDIR = Enotdir
        ENOENT  = Enonexist
        EEXIST  = Eexist
        EIO     = Eio
+       EACCES  = Eperm
+       EISDIR  = syscall.EISDIR
 
        ENAMETOOLONG = NewError("file name too long")
        ERANGE       = NewError("math result not representable")
index b79256c51ed1a446a9745ae2a688f6092e4b2465..c8d0efba40532e63147b0415e8fe7b4c5078b872 100644 (file)
@@ -9,6 +9,13 @@ import (
        "syscall"
 )
 
+// Auxiliary information if the File describes a directory
+type dirInfo struct {
+       buf  [syscall.STATMAX]byte // buffer for directory I/O
+       nbuf int                   // length of buf; return value from Read
+       bufp int                   // location of next record in buf.
+}
+
 func epipecheck(file *File, e syscall.Error) {
 }
 
index 71ea45ec7ff464c2ac39f0ccaa1e50d0189252f5..551b86508570bb470c6985d02be2177234f01301 100644 (file)
@@ -45,6 +45,14 @@ var sysdir = func() (sd *sysDir) {
                                "services",
                        },
                }
+       case "plan9":
+               sd = &sysDir{
+                       "/lib/ndb",
+                       []string{
+                               "common",
+                               "local",
+                       },
+               }
        default:
                sd = &sysDir{
                        "/etc",
@@ -245,8 +253,11 @@ func smallReaddirnames(file *File, length int, t *testing.T) []string {
 func TestReaddirnamesOneAtATime(t *testing.T) {
        // big directory that doesn't change often.
        dir := "/usr/bin"
-       if syscall.OS == "windows" {
+       switch syscall.OS {
+       case "windows":
                dir = Getenv("SystemRoot") + "\\system32"
+       case "plan9":
+               dir = "/bin"
        }
        file, err := Open(dir)
        defer file.Close()
@@ -262,6 +273,9 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
                t.Fatalf("open %q failed: %v", dir, err2)
        }
        small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
+       if len(small) < len(all) {
+               t.Fatalf("len(small) is %d, less than %d", len(small), len(all))
+       }
        for i, n := range all {
                if small[i] != n {
                        t.Errorf("small read %q mismatch: %v", small[i], n)