| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package os | |
| import ( | |
| "syscall" | |
| ) | |
| // Readdir reads the contents of the directory associated with file and | |
| // returns an array of up to n FileInfo structures, as would be returned | |
| // by Lstat, in directory order. Subsequent calls on the same file will yield | |
| // further FileInfos. | |
| // | |
| // If n > 0, Readdir returns at most n FileInfo structures. In this case, if | |
| // Readdirnames returns an empty slice, it will return a non-nil error | |
| // explaining why. At the end of a directory, the error is os.EOF. | |
| // | |
| // If n <= 0, Readdir returns all the FileInfo from the directory in | |
| // a single slice. In this case, if Readdir succeeds (reads all | |
| // the way to the end of the directory), it returns the slice and a | |
| // nil os.Error. If it encounters an error before the end of the | |
| // directory, Readdir returns the FileInfo read until that point | |
| // and a non-nil error. | |
| func (file *File) Readdir(n int) (fi []FileInfo, err Error) { | |
| // If this file has no dirinfo, create one. | |
| if file.dirinfo == nil { | |
| file.dirinfo = new(dirInfo) | |
| } | |
| d := file.dirinfo | |
| size := n | |
| if size <= 0 { | |
| size = 100 | |
| n = -1 | |
| } | |
| result := make([]FileInfo, 0, size) // Empty with room to grow. | |
| for n != 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 result, &PathError{"readdir", file.name, e} | |
| } | |
| if e == EOF { | |
| break | |
| } | |
| if d.nbuf < syscall.STATFIXLEN { | |
| return result, &PathError{"readdir", file.name, Eshortstat} | |
| } | |
| } | |
| // Get a record from buffer | |
| m, _ := gbit16(d.buf[d.bufp:]) | |
| m += 2 | |
| if m < syscall.STATFIXLEN { | |
| return result, &PathError{"readdir", file.name, Eshortstat} | |
| } | |
| dir, e := UnmarshalDir(d.buf[d.bufp : d.bufp+int(m)]) | |
| if e != nil { | |
| return result, &PathError{"readdir", file.name, e} | |
| } | |
| var f FileInfo | |
| fileInfoFromStat(&f, dir) | |
| result = append(result, f) | |
| d.bufp += int(m) | |
| n-- | |
| } | |
| if n >= 0 && len(result) == 0 { | |
| return result, EOF | |
| } | |
| return result, nil | |
| } | |
| // Readdirnames reads and returns a slice of names from the directory f. | |
| // | |
| // If n > 0, Readdirnames returns at most n names. In this case, if | |
| // Readdirnames returns an empty slice, it will return a non-nil error | |
| // explaining why. At the end of a directory, the error is os.EOF. | |
| // | |
| // If n <= 0, Readdirnames returns all the names from the directory in | |
| // a single slice. In this case, if Readdirnames succeeds (reads all | |
| // the way to the end of the directory), it returns the slice and a | |
| // nil os.Error. If it encounters an error before the end of the | |
| // directory, Readdirnames returns the names read until that point and | |
| // a non-nil error. | |
| func (file *File) Readdirnames(n int) (names []string, err Error) { | |
| fi, err := file.Readdir(n) | |
| names = make([]string, len(fi)) | |
| for i := range fi { | |
| names[i] = fi[i].Name | |
| } | |
| return | |
| } | |
| type Dir struct { | |
| // system-modified data | |
| Type uint16 // server type | |
| Dev uint32 // server subtype | |
| // file data | |
| Qid Qid // unique id from server | |
| Mode uint32 // permissions | |
| Atime uint32 // last read time | |
| Mtime uint32 // last write time | |
| Length uint64 // file length | |
| Name string // last element of path | |
| Uid string // owner name | |
| Gid string // group name | |
| Muid string // last modifier name | |
| } | |
| type Qid struct { | |
| Path uint64 // the file server's unique identification for the file | |
| Vers uint32 // version number for given Path | |
| Type uint8 // the type of the file (syscall.QTDIR for example) | |
| } | |
| var nullDir = Dir{ | |
| ^uint16(0), | |
| ^uint32(0), | |
| Qid{^uint64(0), ^uint32(0), ^uint8(0)}, | |
| ^uint32(0), | |
| ^uint32(0), | |
| ^uint32(0), | |
| ^uint64(0), | |
| "", | |
| "", | |
| "", | |
| "", | |
| } | |
| // Null assigns members of d with special "don't care" values indicating | |
| // they should not be written by syscall.Wstat. | |
| func (d *Dir) Null() { | |
| *d = nullDir | |
| } | |
| // pdir appends a 9P Stat message based on the contents of Dir d to a byte slice b. | |
| func pdir(b []byte, d *Dir) []byte { | |
| n := len(b) | |
| b = pbit16(b, 0) // length, filled in later | |
| b = pbit16(b, d.Type) | |
| b = pbit32(b, d.Dev) | |
| b = pqid(b, d.Qid) | |
| b = pbit32(b, d.Mode) | |
| b = pbit32(b, d.Atime) | |
| b = pbit32(b, d.Mtime) | |
| b = pbit64(b, d.Length) | |
| b = pstring(b, d.Name) | |
| b = pstring(b, d.Uid) | |
| b = pstring(b, d.Gid) | |
| b = pstring(b, d.Muid) | |
| pbit16(b[0:n], uint16(len(b)-(n+2))) | |
| return b | |
| } | |
| // UnmarshalDir reads a 9P Stat message from a 9P protocol message stored in b, | |
| // returning the corresponding Dir struct. | |
| func UnmarshalDir(b []byte) (d *Dir, err Error) { | |
| n := uint16(0) | |
| n, b = gbit16(b) | |
| if int(n) != len(b) { | |
| return nil, Ebadstat | |
| } | |
| d = new(Dir) | |
| d.Type, b = gbit16(b) | |
| d.Dev, b = gbit32(b) | |
| d.Qid, b = gqid(b) | |
| d.Mode, b = gbit32(b) | |
| d.Atime, b = gbit32(b) | |
| d.Mtime, b = gbit32(b) | |
| d.Length, b = gbit64(b) | |
| d.Name, b = gstring(b) | |
| d.Uid, b = gstring(b) | |
| d.Gid, b = gstring(b) | |
| d.Muid, b = gstring(b) | |
| if len(b) != 0 { | |
| return nil, Ebadstat | |
| } | |
| return d, nil | |
| } | |
| // gqid reads the qid part of a 9P Stat message from a 9P protocol message stored in b, | |
| // returning the corresponding Qid struct and the remaining slice of b. | |
| func gqid(b []byte) (Qid, []byte) { | |
| var q Qid | |
| q.Path, b = gbit64(b) | |
| q.Vers, b = gbit32(b) | |
| q.Type, b = gbit8(b) | |
| return q, b | |
| } | |
| // pqid appends a Qid struct q to a 9P message b. | |
| func pqid(b []byte, q Qid) []byte { | |
| b = pbit64(b, q.Path) | |
| b = pbit32(b, q.Vers) | |
| b = pbit8(b, q.Type) | |
| return b | |
| } | |
| // gbit8 reads a byte-sized numeric value from a 9P protocol message stored in b, | |
| // returning the value and the remaining slice of b. | |
| func gbit8(b []byte) (uint8, []byte) { | |
| return uint8(b[0]), b[1:] | |
| } | |
| // gbit16 reads a 16-bit numeric value from a 9P protocol message stored in b, | |
| // returning the value and the remaining slice of b. | |
| func gbit16(b []byte) (uint16, []byte) { | |
| return uint16(b[0]) | uint16(b[1])<<8, b[2:] | |
| } | |
| // gbit32 reads a 32-bit numeric value from a 9P protocol message stored in b, | |
| // returning the value and the remaining slice of b. | |
| func gbit32(b []byte) (uint32, []byte) { | |
| return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:] | |
| } | |
| // gbit64 reads a 64-bit numeric value from a 9P protocol message stored in b, | |
| // returning the value and the remaining slice of b. | |
| func gbit64(b []byte) (uint64, []byte) { | |
| lo, b := gbit32(b) | |
| hi, b := gbit32(b) | |
| return uint64(hi)<<32 | uint64(lo), b | |
| } | |
| // gstring reads a string from a 9P protocol message stored in b, | |
| // returning the value as a Go string and the remaining slice of b. | |
| func gstring(b []byte) (string, []byte) { | |
| n, b := gbit16(b) | |
| return string(b[0:n]), b[n:] | |
| } | |
| // pbit8 appends a byte-sized numeric value x to a 9P message b. | |
| func pbit8(b []byte, x uint8) []byte { | |
| n := len(b) | |
| if n+1 > cap(b) { | |
| nb := make([]byte, n, 100+2*cap(b)) | |
| copy(nb, b) | |
| b = nb | |
| } | |
| b = b[0 : n+1] | |
| b[n] = x | |
| return b | |
| } | |
| // pbit16 appends a 16-bit numeric value x to a 9P message b. | |
| func pbit16(b []byte, x uint16) []byte { | |
| n := len(b) | |
| if n+2 > cap(b) { | |
| nb := make([]byte, n, 100+2*cap(b)) | |
| copy(nb, b) | |
| b = nb | |
| } | |
| b = b[0 : n+2] | |
| b[n] = byte(x) | |
| b[n+1] = byte(x >> 8) | |
| return b | |
| } | |
| // pbit32 appends a 32-bit numeric value x to a 9P message b. | |
| func pbit32(b []byte, x uint32) []byte { | |
| n := len(b) | |
| if n+4 > cap(b) { | |
| nb := make([]byte, n, 100+2*cap(b)) | |
| copy(nb, b) | |
| b = nb | |
| } | |
| b = b[0 : n+4] | |
| b[n] = byte(x) | |
| b[n+1] = byte(x >> 8) | |
| b[n+2] = byte(x >> 16) | |
| b[n+3] = byte(x >> 24) | |
| return b | |
| } | |
| // pbit64 appends a 64-bit numeric value x to a 9P message b. | |
| func pbit64(b []byte, x uint64) []byte { | |
| b = pbit32(b, uint32(x)) | |
| b = pbit32(b, uint32(x>>32)) | |
| return b | |
| } | |
| // pstring appends a Go string s to a 9P message b. | |
| func pstring(b []byte, s string) []byte { | |
| if len(s) >= 1<<16 { | |
| panic(NewError("string too long")) | |
| } | |
| b = pbit16(b, uint16(len(s))) | |
| b = append(b, []byte(s)...) | |
| return b | |
| } |