github.com/grailbio/base@v0.0.11/file/fsnode/leaf.go (about) 1 package fsnode 2 3 import ( 4 "bytes" 5 "context" 6 "os" 7 8 "github.com/grailbio/base/errors" 9 "github.com/grailbio/base/ioctx" 10 "github.com/grailbio/base/ioctx/fsctx" 11 ) 12 13 type funcLeaf struct { 14 FileInfo 15 // open is called when OpenFile is called. See Leaf.OpenFile. 16 open func(context.Context, int) (fsctx.File, error) 17 } 18 19 // FuncLeaf constructs a Leaf from an open function. 20 // It's invoked every time; implementations should do their own caching if desired. 21 func FuncLeaf(info FileInfo, open func(ctx context.Context, flag int) (fsctx.File, error)) Leaf { 22 return funcLeaf{info, open} 23 } 24 func (l funcLeaf) OpenFile(ctx context.Context, flag int) (fsctx.File, error) { 25 return l.open(ctx, flag) 26 } 27 func (l funcLeaf) FSNodeT() {} 28 29 type ( 30 readerAtLeaf struct { 31 FileInfo 32 ioctx.ReaderAt 33 } 34 readerAtFile struct { 35 readerAtLeaf 36 off int64 37 } 38 ) 39 40 // ReaderAtLeaf constructs a Leaf whose file reads from r. 41 // Cacheability of both metadata and content is governed by info. 42 func ReaderAtLeaf(info FileInfo, r ioctx.ReaderAt) Leaf { return readerAtLeaf{info, r} } 43 44 func (r readerAtLeaf) OpenFile(context.Context, int) (fsctx.File, error) { 45 return &readerAtFile{r, 0}, nil 46 } 47 func (l readerAtLeaf) FSNodeT() {} 48 49 func (f *readerAtFile) Stat(context.Context) (os.FileInfo, error) { 50 if f.ReaderAt == nil { 51 return nil, os.ErrClosed 52 } 53 return f.FileInfo, nil 54 } 55 func (f *readerAtFile) Read(ctx context.Context, dst []byte) (int, error) { 56 if f.ReaderAt == nil { 57 return 0, os.ErrClosed 58 } 59 n, err := f.ReadAt(ctx, dst, f.off) 60 f.off += int64(n) 61 return n, err 62 } 63 func (f *readerAtFile) Write(context.Context, []byte) (int, error) { 64 return 0, errors.E(errors.NotSupported, f.Name(), "is read-only") 65 } 66 func (f *readerAtFile) Close(context.Context) error { 67 if f.ReaderAt == nil { 68 return os.ErrClosed 69 } 70 f.ReaderAt = nil 71 return nil 72 } 73 74 // ConstLeaf constructs a leaf with constant contents. Caller must not modify content after call. 75 // Uses content's size (ignoring existing info.Size). 76 func ConstLeaf(info FileInfo, content []byte) Leaf { 77 info = info.WithSize(int64(len(content))) 78 return ReaderAtLeaf(info, ioctx.FromStdReaderAt(bytes.NewReader(content))) 79 } 80 81 // TODO: From *os.File?