github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/file/fsnode/leaf.go (about)

     1  package fsnode
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"os"
     7  
     8  	"github.com/Schaudge/grailbase/errors"
     9  	"github.com/Schaudge/grailbase/ioctx"
    10  	"github.com/Schaudge/grailbase/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?