Blob


1 package p9p
3 import (
4 "io"
6 "context"
7 )
9 // ReaddirAll reads all the directory entries for the resource fid.
10 func ReaddirAll(session Session, fid Fid) ([]Dir, error) {
11 panic("not implemented")
12 }
14 // Readdir helps one to implement the server-side of Session.Read on
15 // directories.
16 type Readdir struct {
17 nextfn func() (Dir, error)
18 buf *Dir // one-item buffer
19 codec Codec
20 offset int64
21 }
23 // NewReaddir returns a new Readdir to assist implementing server-side Readdir.
24 // The codec will be used to decode messages with Dir entries. The provided
25 // function next will be called until io.EOF is returned.
26 func NewReaddir(codec Codec, next func() (Dir, error)) *Readdir {
27 return &Readdir{
28 nextfn: next,
29 codec: codec,
30 }
31 }
33 // NewFixedReaddir returns a Readdir that will returned a fixed set of
34 // directory entries.
35 func NewFixedReaddir(codec Codec, dir []Dir) *Readdir {
36 dirs := make([]Dir, len(dir))
37 copy(dirs, dir) // make our own copy!
39 return NewReaddir(codec,
40 func() (Dir, error) {
41 if len(dirs) == 0 {
42 return Dir{}, io.EOF
43 }
45 d := dirs[0]
46 dirs = dirs[1:]
47 return d, nil
48 })
49 }
51 func (rd *Readdir) Read(ctx context.Context, p []byte, offset int64) (n int, err error) {
52 if rd.offset != offset {
53 return 0, ErrBadoffset
54 }
56 p = p[:0:len(p)]
57 for len(p) < cap(p) {
58 var d Dir
59 if rd.buf != nil {
60 d = *rd.buf
61 rd.buf = nil
62 } else {
63 d, err = rd.nextfn()
64 if err != nil {
65 goto done
66 }
67 }
69 var dp []byte
70 dp, err = rd.codec.Marshal(d)
71 if err != nil {
72 goto done
73 }
75 if len(p)+len(dp) > cap(p) {
76 // will over fill buffer. save item and exit.
77 rd.buf = &d
78 goto done
79 }
81 p = append(p, dp...)
82 }
84 done:
85 if err == io.EOF {
86 // Don't let io.EOF escape. EOF is indicated by a zero-length result
87 // with no error.
88 err = nil
89 }
91 rd.offset += int64(len(p))
92 return len(p), err
93 }