From 08b092777168a3377067531307ffd20dd85becba Mon Sep 17 00:00:00 2001 From: Fazlul Shahriar Date: Tue, 12 Apr 2011 16:58:56 -0700 Subject: [PATCH] os: fix Readdir in Plan 9 'TestReaddir.*' tests now passes. R=golang-dev, lucio, r CC=golang-dev https://golang.org/cl/4381048 --- src/pkg/os/dir_plan9.go | 80 ++++++++++++++++----------------------- src/pkg/os/error_plan9.go | 3 ++ src/pkg/os/file_plan9.go | 7 ++++ src/pkg/os/os_test.go | 16 +++++++- 4 files changed, 57 insertions(+), 49 deletions(-) diff --git a/src/pkg/os/dir_plan9.go b/src/pkg/os/dir_plan9.go index 7bb0642e47..a53c764e38 100644 --- a/src/pkg/os/dir_plan9.go +++ b/src/pkg/os/dir_plan9.go @@ -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 } diff --git a/src/pkg/os/error_plan9.go b/src/pkg/os/error_plan9.go index d6575864e8..3374775b8e 100644 --- a/src/pkg/os/error_plan9.go +++ b/src/pkg/os/error_plan9.go @@ -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") diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go index b79256c51e..c8d0efba40 100644 --- a/src/pkg/os/file_plan9.go +++ b/src/pkg/os/file_plan9.go @@ -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) { } diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go index 71ea45ec7f..551b865085 100644 --- a/src/pkg/os/os_test.go +++ b/src/pkg/os/os_test.go @@ -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)