forked from TrueCloudLab/restic
117 lines
2.5 KiB
Go
117 lines
2.5 KiB
Go
package backend
|
|
|
|
import (
|
|
"bytes"
|
|
"hash"
|
|
"io"
|
|
|
|
"github.com/restic/restic/internal/errors"
|
|
)
|
|
|
|
// RewindReader allows resetting the Reader to the beginning of the data.
|
|
type RewindReader interface {
|
|
io.Reader
|
|
|
|
// Rewind rewinds the reader so the same data can be read again from the
|
|
// start.
|
|
Rewind() error
|
|
|
|
// Length returns the number of bytes that can be read from the Reader
|
|
// after calling Rewind.
|
|
Length() int64
|
|
|
|
// Hash return a hash of the data if requested by the backed.
|
|
Hash() []byte
|
|
}
|
|
|
|
// ByteReader implements a RewindReader for a byte slice.
|
|
type ByteReader struct {
|
|
*bytes.Reader
|
|
Len int64
|
|
hash []byte
|
|
}
|
|
|
|
// Rewind restarts the reader from the beginning of the data.
|
|
func (b *ByteReader) Rewind() error {
|
|
_, err := b.Reader.Seek(0, io.SeekStart)
|
|
return err
|
|
}
|
|
|
|
// Length returns the number of bytes read from the reader after Rewind is
|
|
// called.
|
|
func (b *ByteReader) Length() int64 {
|
|
return b.Len
|
|
}
|
|
|
|
// Hash return a hash of the data if requested by the backed.
|
|
func (b *ByteReader) Hash() []byte {
|
|
return b.hash
|
|
}
|
|
|
|
// statically ensure that *ByteReader implements RewindReader.
|
|
var _ RewindReader = &ByteReader{}
|
|
|
|
// NewByteReader prepares a ByteReader that can then be used to read buf.
|
|
func NewByteReader(buf []byte, hasher hash.Hash) *ByteReader {
|
|
var hash []byte
|
|
if hasher != nil {
|
|
// must never fail according to interface
|
|
_, err := hasher.Write(buf)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
hash = hasher.Sum(nil)
|
|
}
|
|
return &ByteReader{
|
|
Reader: bytes.NewReader(buf),
|
|
Len: int64(len(buf)),
|
|
hash: hash,
|
|
}
|
|
}
|
|
|
|
// statically ensure that *FileReader implements RewindReader.
|
|
var _ RewindReader = &FileReader{}
|
|
|
|
// FileReader implements a RewindReader for an open file.
|
|
type FileReader struct {
|
|
io.ReadSeeker
|
|
Len int64
|
|
hash []byte
|
|
}
|
|
|
|
// Rewind seeks to the beginning of the file.
|
|
func (f *FileReader) Rewind() error {
|
|
_, err := f.ReadSeeker.Seek(0, io.SeekStart)
|
|
return errors.Wrap(err, "Seek")
|
|
}
|
|
|
|
// Length returns the length of the file.
|
|
func (f *FileReader) Length() int64 {
|
|
return f.Len
|
|
}
|
|
|
|
// Hash return a hash of the data if requested by the backed.
|
|
func (f *FileReader) Hash() []byte {
|
|
return f.hash
|
|
}
|
|
|
|
// NewFileReader wraps f in a *FileReader.
|
|
func NewFileReader(f io.ReadSeeker, hash []byte) (*FileReader, error) {
|
|
pos, err := f.Seek(0, io.SeekEnd)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Seek")
|
|
}
|
|
|
|
fr := &FileReader{
|
|
ReadSeeker: f,
|
|
Len: pos,
|
|
hash: hash,
|
|
}
|
|
|
|
err = fr.Rewind()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return fr, nil
|
|
}
|