...

Source file src/github.com/vbatts/tar-split/tar/storage/getter.go

Documentation: github.com/vbatts/tar-split/tar/storage

     1  package storage
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"hash/crc64"
     7  	"io"
     8  	"os"
     9  	"path/filepath"
    10  )
    11  
    12  // FileGetter is the interface for getting a stream of a file payload,
    13  // addressed by name/filename. Presumably, the names will be scoped to relative
    14  // file paths.
    15  type FileGetter interface {
    16  	// Get returns a stream for the provided file path
    17  	Get(filename string) (output io.ReadCloser, err error)
    18  }
    19  
    20  // FilePutter is the interface for storing a stream of a file payload,
    21  // addressed by name/filename.
    22  type FilePutter interface {
    23  	// Put returns the size of the stream received, and the crc64 checksum for
    24  	// the provided stream
    25  	Put(filename string, input io.Reader) (size int64, checksum []byte, err error)
    26  }
    27  
    28  // FileGetPutter is the interface that groups both Getting and Putting file
    29  // payloads.
    30  type FileGetPutter interface {
    31  	FileGetter
    32  	FilePutter
    33  }
    34  
    35  // NewPathFileGetter returns a FileGetter that is for files relative to path
    36  // relpath.
    37  func NewPathFileGetter(relpath string) FileGetter {
    38  	return &pathFileGetter{root: relpath}
    39  }
    40  
    41  type pathFileGetter struct {
    42  	root string
    43  }
    44  
    45  func (pfg pathFileGetter) Get(filename string) (io.ReadCloser, error) {
    46  	return os.Open(filepath.Join(pfg.root, filename))
    47  }
    48  
    49  type bufferFileGetPutter struct {
    50  	files map[string][]byte
    51  }
    52  
    53  func (bfgp bufferFileGetPutter) Get(name string) (io.ReadCloser, error) {
    54  	if _, ok := bfgp.files[name]; !ok {
    55  		return nil, errors.New("no such file")
    56  	}
    57  	b := bytes.NewBuffer(bfgp.files[name])
    58  	return &readCloserWrapper{b}, nil
    59  }
    60  
    61  func (bfgp *bufferFileGetPutter) Put(name string, r io.Reader) (int64, []byte, error) {
    62  	crc := crc64.New(CRCTable)
    63  	buf := bytes.NewBuffer(nil)
    64  	cw := io.MultiWriter(crc, buf)
    65  	i, err := io.Copy(cw, r)
    66  	if err != nil {
    67  		return 0, nil, err
    68  	}
    69  	bfgp.files[name] = buf.Bytes()
    70  	return i, crc.Sum(nil), nil
    71  }
    72  
    73  type readCloserWrapper struct {
    74  	io.Reader
    75  }
    76  
    77  func (w *readCloserWrapper) Close() error { return nil }
    78  
    79  // NewBufferFileGetPutter is a simple in-memory FileGetPutter
    80  //
    81  // Implication is this is memory intensive...
    82  // Probably best for testing or light weight cases.
    83  func NewBufferFileGetPutter() FileGetPutter {
    84  	return &bufferFileGetPutter{
    85  		files: map[string][]byte{},
    86  	}
    87  }
    88  
    89  // NewDiscardFilePutter is a bit bucket FilePutter
    90  func NewDiscardFilePutter() FilePutter {
    91  	return &bitBucketFilePutter{}
    92  }
    93  
    94  type bitBucketFilePutter struct {
    95  	buffer [32 * 1024]byte // 32 kB is the buffer size currently used by io.Copy, as of August 2021.
    96  }
    97  
    98  func (bbfp *bitBucketFilePutter) Put(name string, r io.Reader) (int64, []byte, error) {
    99  	c := crc64.New(CRCTable)
   100  	i, err := io.CopyBuffer(c, r, bbfp.buffer[:])
   101  	return i, c.Sum(nil), err
   102  }
   103  
   104  // CRCTable is the default table used for crc64 sum calculations
   105  var CRCTable = crc64.MakeTable(crc64.ISO)
   106  

View as plain text