mirror of
https://github.com/restic/restic.git
synced 2025-12-04 00:21:46 +00:00
Major restructure, bundle blobs
This commit also breaks the repository format.
This commit is contained in:
@@ -3,6 +3,7 @@ package backend
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -96,3 +97,33 @@ outer:
|
||||
|
||||
return IDSize, nil
|
||||
}
|
||||
|
||||
// wrap around io.LimitedReader that implements io.ReadCloser
|
||||
type blobReader struct {
|
||||
f io.Closer
|
||||
rd io.Reader
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (l *blobReader) Read(p []byte) (int, error) {
|
||||
n, err := l.rd.Read(p)
|
||||
if err == io.EOF {
|
||||
l.Close()
|
||||
}
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (l *blobReader) Close() error {
|
||||
if !l.closed {
|
||||
err := l.f.Close()
|
||||
l.closed = true
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LimitReader(f io.ReadCloser, n int64) *blobReader {
|
||||
return &blobReader{f: f, rd: io.LimitReader(f, n)}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
Version = 1
|
||||
)
|
||||
|
||||
// A Backend manages blobs of data.
|
||||
// A Backend manages data stored somewhere.
|
||||
type Backend interface {
|
||||
// Location returns a string that specifies the location of the repository,
|
||||
// like a URL.
|
||||
@@ -31,6 +31,10 @@ type Backend interface {
|
||||
// Get returns an io.ReadCloser for the Blob with the given name of type t.
|
||||
Get(t Type, name string) (io.ReadCloser, error)
|
||||
|
||||
// GetReader returns an io.ReadCloser for the Blob with the given name of
|
||||
// type t at offset and length.
|
||||
GetReader(t Type, name string, offset, length uint) (io.ReadCloser, error)
|
||||
|
||||
// Test a boolean value whether a Blob with the name and type exists.
|
||||
Test(t Type, name string) (bool, error)
|
||||
|
||||
|
||||
@@ -302,6 +302,26 @@ func (b *Local) Get(t backend.Type, name string) (io.ReadCloser, error) {
|
||||
return os.Open(filename(b.p, t, name))
|
||||
}
|
||||
|
||||
// GetReader returns an io.ReadCloser for the Blob with the given name of
|
||||
// type t at offset and length. If length is 0, the reader reads until EOF.
|
||||
func (b *Local) GetReader(t backend.Type, name string, offset, length uint) (io.ReadCloser, error) {
|
||||
f, err := os.Open(filename(b.p, t, name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = f.Seek(int64(offset), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if length == 0 {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
return backend.LimitReader(f, int64(length)), nil
|
||||
}
|
||||
|
||||
// Test returns true if a blob of the given type and name exists in the backend.
|
||||
func (b *Local) Test(t backend.Type, name string) (bool, error) {
|
||||
_, err := os.Stat(filename(b.p, t, name))
|
||||
|
||||
@@ -436,6 +436,26 @@ func (r *SFTP) Get(t backend.Type, name string) (io.ReadCloser, error) {
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// GetReader returns an io.ReadCloser for the Blob with the given name of
|
||||
// type t at offset and length. If length is 0, the reader reads until EOF.
|
||||
func (r *SFTP) GetReader(t backend.Type, name string, offset, length uint) (io.ReadCloser, error) {
|
||||
f, err := r.c.Open(r.filename(t, name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = f.Seek(int64(offset), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if length == 0 {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
return backend.LimitReader(f, int64(length)), nil
|
||||
}
|
||||
|
||||
// Test returns true if a blob of the given type and name exists in the backend.
|
||||
func (r *SFTP) Test(t backend.Type, name string) (bool, error) {
|
||||
_, err := r.c.Lstat(r.filename(t, name))
|
||||
|
||||
Reference in New Issue
Block a user