forked from TrueCloudLab/restic
Add Stat() method to backend interface
This commit is contained in:
parent
10b03eee27
commit
919b40c6cf
7 changed files with 97 additions and 0 deletions
|
@ -43,6 +43,9 @@ type Backend interface {
|
||||||
// Load returns the data stored in the backend for h at the given offset
|
// Load returns the data stored in the backend for h at the given offset
|
||||||
// and saves it in p. Load has the same semantics as io.ReaderAt.
|
// and saves it in p. Load has the same semantics as io.ReaderAt.
|
||||||
Load(h Handle, p []byte, off int64) (int, error)
|
Load(h Handle, p []byte, off int64) (int, error)
|
||||||
|
|
||||||
|
// Stat returns information about the blob identified by h.
|
||||||
|
Stat(h Handle) (BlobInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lister implements listing data items stored in a backend.
|
// Lister implements listing data items stored in a backend.
|
||||||
|
@ -59,6 +62,11 @@ type Deleter interface {
|
||||||
Delete() error
|
Delete() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlobInfo is returned by Stat() and contains information about a stored blob.
|
||||||
|
type BlobInfo struct {
|
||||||
|
Size int64
|
||||||
|
}
|
||||||
|
|
||||||
// Blob is old.
|
// Blob is old.
|
||||||
type Blob interface {
|
type Blob interface {
|
||||||
io.Writer
|
io.Writer
|
||||||
|
|
|
@ -252,6 +252,20 @@ func (b *Local) Load(h backend.Handle, p []byte, off int64) (n int, err error) {
|
||||||
return io.ReadFull(f, p)
|
return io.ReadFull(f, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stat returns information about a blob.
|
||||||
|
func (b *Local) Stat(h backend.Handle) (backend.BlobInfo, error) {
|
||||||
|
if err := h.Valid(); err != nil {
|
||||||
|
return backend.BlobInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Stat(filename(b.p, h.Type, h.Name))
|
||||||
|
if err != nil {
|
||||||
|
return backend.BlobInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return backend.BlobInfo{Size: fi.Size()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Test returns true if a blob of the given type and name exists in the backend.
|
// 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) {
|
func (b *Local) Test(t backend.Type, name string) (bool, error) {
|
||||||
_, err := os.Stat(filename(b.p, t, name))
|
_, err := os.Stat(filename(b.p, t, name))
|
||||||
|
|
|
@ -49,6 +49,10 @@ func New() *MemoryBackend {
|
||||||
return memLoad(be, h, p, off)
|
return memLoad(be, h, p, off)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
be.MockBackend.StatFn = func(h backend.Handle) (backend.BlobInfo, error) {
|
||||||
|
return memStat(be, h)
|
||||||
|
}
|
||||||
|
|
||||||
be.MockBackend.RemoveFn = func(t backend.Type, name string) error {
|
be.MockBackend.RemoveFn = func(t backend.Type, name string) error {
|
||||||
return memRemove(be, t, name)
|
return memRemove(be, t, name)
|
||||||
}
|
}
|
||||||
|
@ -195,6 +199,28 @@ func memLoad(be *MemoryBackend, h backend.Handle, p []byte, off int64) (int, err
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func memStat(be *MemoryBackend, h backend.Handle) (backend.BlobInfo, error) {
|
||||||
|
be.m.Lock()
|
||||||
|
defer be.m.Unlock()
|
||||||
|
|
||||||
|
if err := h.Valid(); err != nil {
|
||||||
|
return backend.BlobInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.Type == backend.Config {
|
||||||
|
h.Name = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
debug.Log("MemoryBackend.Stat", "stat %v", h)
|
||||||
|
|
||||||
|
e, ok := be.data[entry{h.Type, h.Name}]
|
||||||
|
if !ok {
|
||||||
|
return backend.BlobInfo{}, errors.New("no such data")
|
||||||
|
}
|
||||||
|
|
||||||
|
return backend.BlobInfo{Size: int64(len(e))}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func memRemove(be *MemoryBackend, t backend.Type, name string) error {
|
func memRemove(be *MemoryBackend, t backend.Type, name string) error {
|
||||||
be.m.Lock()
|
be.m.Lock()
|
||||||
defer be.m.Unlock()
|
defer be.m.Unlock()
|
||||||
|
|
|
@ -11,6 +11,7 @@ type MockBackend struct {
|
||||||
CloseFn func() error
|
CloseFn func() error
|
||||||
CreateFn func() (Blob, error)
|
CreateFn func() (Blob, error)
|
||||||
LoadFn func(h Handle, p []byte, off int64) (int, error)
|
LoadFn func(h Handle, p []byte, off int64) (int, error)
|
||||||
|
StatFn func(h Handle) (BlobInfo, error)
|
||||||
GetReaderFn func(Type, string, uint, uint) (io.ReadCloser, error)
|
GetReaderFn func(Type, string, uint, uint) (io.ReadCloser, error)
|
||||||
ListFn func(Type, <-chan struct{}) <-chan string
|
ListFn func(Type, <-chan struct{}) <-chan string
|
||||||
RemoveFn func(Type, string) error
|
RemoveFn func(Type, string) error
|
||||||
|
@ -51,6 +52,14 @@ func (m *MockBackend) Load(h Handle, p []byte, off int64) (int, error) {
|
||||||
return m.LoadFn(h, p, off)
|
return m.LoadFn(h, p, off)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockBackend) Stat(h Handle) (BlobInfo, error) {
|
||||||
|
if m.StatFn == nil {
|
||||||
|
return BlobInfo{}, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.StatFn(h)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MockBackend) GetReader(t Type, name string, offset, len uint) (io.ReadCloser, error) {
|
func (m *MockBackend) GetReader(t Type, name string, offset, len uint) (io.ReadCloser, error) {
|
||||||
if m.GetReaderFn == nil {
|
if m.GetReaderFn == nil {
|
||||||
return nil, errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
|
|
|
@ -191,6 +191,25 @@ func (be S3Backend) Load(h backend.Handle, p []byte, off int64) (int, error) {
|
||||||
return io.ReadFull(obj, p)
|
return io.ReadFull(obj, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stat returns information about a blob.
|
||||||
|
func (be S3Backend) Stat(h backend.Handle) (backend.BlobInfo, error) {
|
||||||
|
debug.Log("s3.Stat", "%v")
|
||||||
|
path := s3path(h.Type, h.Name)
|
||||||
|
obj, err := be.client.GetObject(be.bucketname, path)
|
||||||
|
if err != nil {
|
||||||
|
debug.Log("s3.Stat", "GetObject() err %v", err)
|
||||||
|
return backend.BlobInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := obj.Stat()
|
||||||
|
if err != nil {
|
||||||
|
debug.Log("s3.Stat", "Stat() err %v", err)
|
||||||
|
return backend.BlobInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return backend.BlobInfo{Size: fi.Size}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Test returns true if a blob of the given type and name exists in the backend.
|
// Test returns true if a blob of the given type and name exists in the backend.
|
||||||
func (be *S3Backend) Test(t backend.Type, name string) (bool, error) {
|
func (be *S3Backend) Test(t backend.Type, name string) (bool, error) {
|
||||||
found := false
|
found := false
|
||||||
|
|
|
@ -395,6 +395,20 @@ func (r *SFTP) Load(h backend.Handle, p []byte, off int64) (n int, err error) {
|
||||||
return io.ReadFull(f, p)
|
return io.ReadFull(f, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stat returns information about a blob.
|
||||||
|
func (r *SFTP) Stat(h backend.Handle) (backend.BlobInfo, error) {
|
||||||
|
if err := h.Valid(); err != nil {
|
||||||
|
return backend.BlobInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := r.c.Lstat(r.filename(h.Type, h.Name))
|
||||||
|
if err != nil {
|
||||||
|
return backend.BlobInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return backend.BlobInfo{Size: fi.Size()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Test returns true if a blob of the given type and name exists in the backend.
|
// 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) {
|
func (r *SFTP) Test(t backend.Type, name string) (bool, error) {
|
||||||
_, err := r.c.Lstat(r.filename(t, name))
|
_, err := r.c.Lstat(r.filename(t, name))
|
||||||
|
|
|
@ -374,6 +374,13 @@ func TestWrite(t testing.TB) {
|
||||||
t.Fatalf("data not equal")
|
t.Fatalf("data not equal")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fi, err := b.Stat(backend.Handle{Type: backend.Data, Name: name})
|
||||||
|
OK(t, err)
|
||||||
|
|
||||||
|
if fi.Size != int64(len(data)) {
|
||||||
|
t.Fatalf("Stat() returned different size, want %q, got %d", len(data), fi.Size)
|
||||||
|
}
|
||||||
|
|
||||||
err = b.Remove(backend.Data, name)
|
err = b.Remove(backend.Data, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error removing item: %v", err)
|
t.Fatalf("error removing item: %v", err)
|
||||||
|
|
Loading…
Reference in a new issue