commit 7cd259a2e418951032d970bf316a144fda865dc5 from: Stephen J Day date: Wed Nov 11 00:00:46 2015 UTC fs/p9p/new: add readdir helpers Signed-off-by: Stephen J Day commit - 755621adc48bd5d72563edcaa93d627eee0fef24 commit + 7cd259a2e418951032d970bf316a144fda865dc5 blob - /dev/null blob + b3ab9d195896f7f19afc47915087d68419801816 (mode 644) --- /dev/null +++ readdir.go @@ -0,0 +1,88 @@ +package p9pnew + +import ( + "io" + + "golang.org/x/net/context" +) + +// ReaddirAll reads all the directory entries for the resource fid. +func ReaddirAll(session Session, fid Fid) ([]Dir, error) { + panic("not implemented") +} + +// Readdir helps one to implement the server-side of Session.Read on +// directories. +type Readdir struct { + nextfn func() (Dir, error) + buf *Dir // one-item buffer + codec Codec + offset int64 +} + +func NewReaddir(codec Codec, next func() (Dir, error)) *Readdir { + return &Readdir{ + nextfn: next, + codec: codec, + } +} + +func NewFixedReaddir(codec Codec, dir []Dir) *Readdir { + dirs := make([]Dir, len(dir)) + copy(dirs, dir) // make our own copy! + + return NewReaddir(codec, + func() (Dir, error) { + if len(dirs) == 0 { + return Dir{}, io.EOF + } + + d := dirs[0] + dirs = dirs[1:] + return d, nil + }) +} + +func (rd *Readdir) Read(ctx context.Context, p []byte, offset int64) (n int, err error) { + if rd.offset != offset { + return 0, ErrBadoffset + } + + p = p[:0:len(p)] + for len(p) < cap(p) { + var d Dir + if rd.buf != nil { + d = *rd.buf + rd.buf = nil + } else { + d, err = rd.nextfn() + if err != nil { + goto done + } + } + + var dp []byte + dp, err = rd.codec.Marshal(d) + if err != nil { + goto done + } + + if len(p)+len(dp) > cap(p) { + // will over fill buffer. save item and exit. + rd.buf = &d + goto done + } + + p = append(p, dp...) + } + +done: + if err == io.EOF && len(p) > 0 { + // Don't let io.EOF escape if we've written to p. 9p doesn't handle + // this like Go. + err = nil + } + + rd.offset += int64(len(p)) + return len(p), err +}