134 lines
2.8 KiB
Go
134 lines
2.8 KiB
Go
// Copyright 2009 The Go9p 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 go9p
|
|
|
|
import (
|
|
"io"
|
|
)
|
|
|
|
// Reads count bytes starting from offset from the file associated with the fid.
|
|
// Returns a slice with the data read, if the operation was successful, or an
|
|
// Error.
|
|
func (clnt *Clnt) Read(fid *Fid, offset uint64, count uint32) ([]byte, error) {
|
|
if count > fid.Iounit {
|
|
count = fid.Iounit
|
|
}
|
|
|
|
tc := clnt.NewFcall()
|
|
err := PackTread(tc, fid.Fid, offset, count)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rc, err := clnt.Rpc(tc)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return rc.Data, nil
|
|
}
|
|
|
|
// Reads up to len(buf) bytes from the File. Returns the number
|
|
// of bytes read, or an Error.
|
|
func (file *File) Read(buf []byte) (int, error) {
|
|
n, err := file.ReadAt(buf, int64(file.offset))
|
|
if err == nil {
|
|
file.offset += uint64(n)
|
|
}
|
|
|
|
return n, err
|
|
}
|
|
|
|
// Reads up to len(buf) bytes from the file starting from offset.
|
|
// Returns the number of bytes read, or an Error.
|
|
func (file *File) ReadAt(buf []byte, offset int64) (int, error) {
|
|
b, err := file.Fid.Clnt.Read(file.Fid, uint64(offset), uint32(len(buf)))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if len(b) == 0 {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
copy(buf, b)
|
|
return len(b), nil
|
|
}
|
|
|
|
// Reads exactly len(buf) bytes from the File starting from offset.
|
|
// Returns the number of bytes read (could be less than len(buf) if
|
|
// end-of-file is reached), or an Error.
|
|
func (file *File) Readn(buf []byte, offset uint64) (int, error) {
|
|
ret := 0
|
|
for len(buf) > 0 {
|
|
n, err := file.ReadAt(buf, int64(offset))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if n == 0 {
|
|
break
|
|
}
|
|
|
|
buf = buf[n:]
|
|
offset += uint64(n)
|
|
ret += n
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
// Reads the content of the directory associated with the File.
|
|
// Returns an array of maximum num entries (if num is 0, returns
|
|
// all entries from the directory). If the operation fails, returns
|
|
// an Error.
|
|
func (file *File) Readdir(num int) ([]*Dir, error) {
|
|
buf := make([]byte, file.Fid.Clnt.Msize-IOHDRSZ)
|
|
dirs := make([]*Dir, 32)
|
|
pos := 0
|
|
offset := file.offset
|
|
defer func() {
|
|
file.offset = offset
|
|
}()
|
|
for {
|
|
n, err := file.Read(buf)
|
|
if err != nil && err != io.EOF {
|
|
return nil, err
|
|
}
|
|
|
|
if n == 0 {
|
|
break
|
|
}
|
|
|
|
for b := buf[0:n]; len(b) > 0; {
|
|
d, _, _, perr := UnpackDir(b, file.Fid.Clnt.Dotu)
|
|
if perr != nil {
|
|
// If we have unpacked anything, it is almost certainly
|
|
// a too-short buffer. So return what we got.
|
|
if pos > 0 {
|
|
return dirs[0:pos], nil
|
|
}
|
|
return nil, perr
|
|
}
|
|
|
|
b = b[d.Size+2:]
|
|
offset += uint64(d.Size + 2)
|
|
if pos >= len(dirs) {
|
|
s := make([]*Dir, len(dirs)+32)
|
|
copy(s, dirs)
|
|
dirs = s
|
|
}
|
|
|
|
dirs[pos] = d
|
|
pos++
|
|
if num != 0 && pos >= num {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return dirs[0:pos], nil
|
|
}
|