mirror of
https://github.com/golang/go
synced 2024-11-24 21:10:04 -07:00
os: fix Readdir in Plan 9
'TestReaddir.*' tests now passes. R=golang-dev, lucio, r CC=golang-dev https://golang.org/cl/4381048
This commit is contained in:
parent
36b6d1aaf2
commit
08b0927771
@ -8,72 +8,56 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dirInfo int
|
|
||||||
|
|
||||||
var markDirectory dirInfo = ^0
|
|
||||||
|
|
||||||
// Readdir reads the contents of the directory associated with file and
|
// Readdir reads the contents of the directory associated with file and
|
||||||
// returns an array of up to count FileInfo structures, as would be returned
|
// returns an array of up to count FileInfo structures, in directory order.
|
||||||
// by Lstat, in directory order. Subsequent calls on the same file will yield
|
// Subsequent calls on the same file will yield further FileInfos.
|
||||||
// further FileInfos. A negative count means to read the entire directory.
|
// A negative count means to read until EOF.
|
||||||
// Readdir returns the array and an Error, if any.
|
// Readdir returns the array and an Error, if any.
|
||||||
func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
|
func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
|
||||||
// If this file has no dirinfo, create one.
|
// If this file has no dirinfo, create one.
|
||||||
if file.dirinfo == nil {
|
if file.dirinfo == nil {
|
||||||
file.dirinfo = &markDirectory
|
file.dirinfo = new(dirInfo)
|
||||||
}
|
}
|
||||||
|
d := file.dirinfo
|
||||||
size := count
|
size := count
|
||||||
if size < 0 {
|
if size < 0 {
|
||||||
size = 100
|
size = 100
|
||||||
}
|
}
|
||||||
|
result := make([]FileInfo, 0, size) // Empty with room to grow.
|
||||||
result := make([]FileInfo, 0, size)
|
for count != 0 {
|
||||||
var buf [syscall.STATMAX]byte
|
// Refill the buffer if necessary
|
||||||
|
if d.bufp >= d.nbuf {
|
||||||
for {
|
d.bufp = 0
|
||||||
n, e := file.Read(buf[:])
|
var e Error
|
||||||
|
d.nbuf, e = file.Read(d.buf[:])
|
||||||
if e != nil {
|
if e != nil && e != EOF {
|
||||||
|
return nil, &PathError{"readdir", file.name, e}
|
||||||
|
}
|
||||||
if e == EOF {
|
if e == EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if d.nbuf < syscall.STATFIXLEN {
|
||||||
return []FileInfo{}, &PathError{"readdir", file.name, e}
|
return nil, &PathError{"readdir", file.name, Eshortstat}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if n < syscall.STATFIXLEN {
|
// Get a record from buffer
|
||||||
return []FileInfo{}, &PathError{"readdir", file.name, Eshortstat}
|
m, _ := gbit16(d.buf[d.bufp:])
|
||||||
|
m += 2
|
||||||
|
if m < syscall.STATFIXLEN {
|
||||||
|
return nil, &PathError{"readdir", file.name, Eshortstat}
|
||||||
}
|
}
|
||||||
|
dir, e := UnmarshalDir(d.buf[d.bufp : d.bufp+int(m)])
|
||||||
for i := 0; i < n; {
|
if e != nil {
|
||||||
m, _ := gbit16(buf[i:])
|
return nil, &PathError{"readdir", file.name, e}
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
var f FileInfo
|
||||||
|
fileInfoFromStat(&f, dir)
|
||||||
|
result = append(result, f)
|
||||||
|
|
||||||
|
d.bufp += int(m)
|
||||||
|
count--
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,12 +37,15 @@ var (
|
|||||||
Enonexist = NewError("file does not exist")
|
Enonexist = NewError("file does not exist")
|
||||||
Eexist = NewError("file already exists")
|
Eexist = NewError("file already exists")
|
||||||
Eio = NewError("i/o error")
|
Eio = NewError("i/o error")
|
||||||
|
Eperm = NewError("permission denied")
|
||||||
|
|
||||||
EINVAL = Ebadarg
|
EINVAL = Ebadarg
|
||||||
ENOTDIR = Enotdir
|
ENOTDIR = Enotdir
|
||||||
ENOENT = Enonexist
|
ENOENT = Enonexist
|
||||||
EEXIST = Eexist
|
EEXIST = Eexist
|
||||||
EIO = Eio
|
EIO = Eio
|
||||||
|
EACCES = Eperm
|
||||||
|
EISDIR = syscall.EISDIR
|
||||||
|
|
||||||
ENAMETOOLONG = NewError("file name too long")
|
ENAMETOOLONG = NewError("file name too long")
|
||||||
ERANGE = NewError("math result not representable")
|
ERANGE = NewError("math result not representable")
|
||||||
|
@ -9,6 +9,13 @@ import (
|
|||||||
"syscall"
|
"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) {
|
func epipecheck(file *File, e syscall.Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,14 @@ var sysdir = func() (sd *sysDir) {
|
|||||||
"services",
|
"services",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
case "plan9":
|
||||||
|
sd = &sysDir{
|
||||||
|
"/lib/ndb",
|
||||||
|
[]string{
|
||||||
|
"common",
|
||||||
|
"local",
|
||||||
|
},
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
sd = &sysDir{
|
sd = &sysDir{
|
||||||
"/etc",
|
"/etc",
|
||||||
@ -245,8 +253,11 @@ func smallReaddirnames(file *File, length int, t *testing.T) []string {
|
|||||||
func TestReaddirnamesOneAtATime(t *testing.T) {
|
func TestReaddirnamesOneAtATime(t *testing.T) {
|
||||||
// big directory that doesn't change often.
|
// big directory that doesn't change often.
|
||||||
dir := "/usr/bin"
|
dir := "/usr/bin"
|
||||||
if syscall.OS == "windows" {
|
switch syscall.OS {
|
||||||
|
case "windows":
|
||||||
dir = Getenv("SystemRoot") + "\\system32"
|
dir = Getenv("SystemRoot") + "\\system32"
|
||||||
|
case "plan9":
|
||||||
|
dir = "/bin"
|
||||||
}
|
}
|
||||||
file, err := Open(dir)
|
file, err := Open(dir)
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
@ -262,6 +273,9 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
|
|||||||
t.Fatalf("open %q failed: %v", dir, err2)
|
t.Fatalf("open %q failed: %v", dir, err2)
|
||||||
}
|
}
|
||||||
small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
|
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 {
|
for i, n := range all {
|
||||||
if small[i] != n {
|
if small[i] != n {
|
||||||
t.Errorf("small read %q mismatch: %v", small[i], n)
|
t.Errorf("small read %q mismatch: %v", small[i], n)
|
||||||
|
Loading…
Reference in New Issue
Block a user