github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libfs/wrapped_read_file.go (about)

     1  // Copyright 2019 Keybase Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD
     3  // license that can be found in the LICENSE file.
     4  
     5  package libfs
     6  
     7  import (
     8  	"context"
     9  	"io"
    10  	"time"
    11  
    12  	"github.com/keybase/client/go/kbfs/libkbfs"
    13  	"github.com/keybase/client/go/logger"
    14  	"github.com/pkg/errors"
    15  	billy "gopkg.in/src-d/go-billy.v4"
    16  )
    17  
    18  const (
    19  	// Debug tag ID for an individual FS operation.
    20  	ctxFSOpID = "FSID"
    21  )
    22  
    23  type ctxFSTagKey int
    24  
    25  const (
    26  	ctxFSIDKey ctxFSTagKey = iota
    27  )
    28  
    29  // wrappedReadFile is a read-only file that serves data from a given
    30  // `reader` function.
    31  type wrappedReadFile struct {
    32  	name   string
    33  	reader func(context.Context) ([]byte, time.Time, error)
    34  	log    logger.Logger
    35  
    36  	// TODO: proper locking for `nextRead` if we ever use it outside
    37  	// of libkbfs node-wrapping (which always uses `ReadAt`).
    38  	nextRead int
    39  }
    40  
    41  var _ billy.File = (*wrappedReadFile)(nil)
    42  
    43  func (wrf *wrappedReadFile) getDataAndTime() ([]byte, time.Time) {
    44  	ctx := libkbfs.CtxWithRandomIDReplayable(
    45  		context.Background(), ctxFSIDKey, ctxFSOpID, nil)
    46  	data, t, err := wrf.reader(ctx)
    47  	if err != nil {
    48  		wrf.log.CDebugf(ctx, "Couldn't read wrapped file: %+v", err)
    49  		return nil, time.Time{}
    50  	}
    51  	return data, t
    52  }
    53  
    54  func (wrf *wrappedReadFile) Len() int {
    55  	data, _ := wrf.getDataAndTime()
    56  	return len(data)
    57  }
    58  
    59  func (wrf *wrappedReadFile) Name() string {
    60  	return wrf.name
    61  }
    62  
    63  func (wrf *wrappedReadFile) Write(_ []byte) (n int, err error) {
    64  	return 0, errors.New("wrapped read files can't be written")
    65  }
    66  
    67  func (wrf *wrappedReadFile) Read(p []byte) (n int, err error) {
    68  	data, _ := wrf.getDataAndTime()
    69  
    70  	if wrf.nextRead >= len(data) {
    71  		return 0, io.EOF
    72  	}
    73  	n = copy(p, data[wrf.nextRead:])
    74  	wrf.nextRead += n
    75  	return n, nil
    76  }
    77  
    78  func (wrf *wrappedReadFile) ReadAt(p []byte, off int64) (n int, err error) {
    79  	data, _ := wrf.getDataAndTime()
    80  
    81  	if off >= int64(len(data)) {
    82  		return 0, io.EOF
    83  	}
    84  
    85  	n = copy(p, data[off:])
    86  	return n, nil
    87  }
    88  
    89  func (wrf *wrappedReadFile) Seek(offset int64, whence int) (int64, error) {
    90  	newOffset := offset
    91  	switch whence {
    92  	case io.SeekStart:
    93  	case io.SeekCurrent:
    94  		newOffset = int64(wrf.nextRead) + offset
    95  	case io.SeekEnd:
    96  		data, _ := wrf.getDataAndTime()
    97  		newOffset = int64(len(data)) + offset
    98  	}
    99  	if newOffset < 0 {
   100  		return 0, errors.Errorf("Cannot seek to offset %d", newOffset)
   101  	}
   102  
   103  	wrf.nextRead = int(newOffset)
   104  	return newOffset, nil
   105  }
   106  
   107  func (wrf *wrappedReadFile) Close() error {
   108  	return nil
   109  }
   110  
   111  func (wrf *wrappedReadFile) Lock() error {
   112  	return errors.New("wrapped read files can't be locked")
   113  }
   114  
   115  func (wrf *wrappedReadFile) Unlock() error {
   116  	return errors.New("wrapped read files can't be unlocked")
   117  }
   118  
   119  func (wrf *wrappedReadFile) Truncate(size int64) error {
   120  	return errors.New("wrapped read files can't be truncated")
   121  }
   122  
   123  func (wrf *wrappedReadFile) GetInfo() *wrappedReadFileInfo {
   124  	data, t := wrf.getDataAndTime()
   125  	return &wrappedReadFileInfo{
   126  		name:  wrf.Name(),
   127  		size:  int64(len(data)),
   128  		mtime: t,
   129  	}
   130  }