Normalise the backend API

This makes the following changes, before:

    type backend interface {
        // Test a boolean value whether a File with the name and type exists.
        Test(t FileType, name string) (bool, error)

        // Remove removes a File with type t and name.
        Remove(t FileType, name string) error
    }

After:

    type backend interface {
        // Test a boolean value whether a File with the name and type exists.
        Test(h Handle) (bool, error)

        // Remove removes a File with type t and name.
        Remove(h Handle) error
    }
This commit is contained in:
Alexander Neumann 2017-01-25 17:48:35 +01:00
parent d55b56edd3
commit b9bddeff39
22 changed files with 139 additions and 118 deletions

View file

@ -133,7 +133,8 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
} }
if !opts.DryRun { if !opts.DryRun {
err = repo.Backend().Remove(restic.SnapshotFile, id.String()) h := restic.Handle{Type: restic.SnapshotFile, Name: id.String()}
err = repo.Backend().Remove(h)
if err != nil { if err != nil {
return err return err
} }
@ -201,7 +202,8 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
if !opts.DryRun { if !opts.DryRun {
for _, sn := range remove { for _, sn := range remove {
err = repo.Backend().Remove(restic.SnapshotFile, sn.ID().String()) h := restic.Handle{Type: restic.SnapshotFile, Name: sn.ID().String()}
err = repo.Backend().Remove(h)
if err != nil { if err != nil {
return err return err
} }

View file

@ -87,7 +87,8 @@ func deleteKey(repo *repository.Repository, name string) error {
return errors.Fatal("refusing to remove key currently used to access repository") return errors.Fatal("refusing to remove key currently used to access repository")
} }
err := repo.Backend().Remove(restic.KeyFile, name) h := restic.Handle{Type: restic.KeyFile, Name: name}
err := repo.Backend().Remove(h)
if err != nil { if err != nil {
return err return err
} }
@ -107,7 +108,8 @@ func changePassword(gopts GlobalOptions, repo *repository.Repository) error {
return errors.Fatalf("creating new key failed: %v\n", err) return errors.Fatalf("creating new key failed: %v\n", err)
} }
err = repo.Backend().Remove(restic.KeyFile, repo.KeyName()) h := restic.Handle{Type: restic.KeyFile, Name: repo.KeyName()}
err = repo.Backend().Remove(h)
if err != nil { if err != nil {
return err return err
} }

View file

@ -219,7 +219,8 @@ func runPrune(gopts GlobalOptions) error {
} }
for packID := range removePacks { for packID := range removePacks {
err = repo.Backend().Remove(restic.DataFile, packID.String()) h := restic.Handle{Type: restic.DataFile, Name: packID.String()}
err = repo.Backend().Remove(h)
if err != nil { if err != nil {
Warnf("unable to remove file %v from the repository\n", packID.Str()) Warnf("unable to remove file %v from the repository\n", packID.Str())
} }
@ -239,7 +240,8 @@ func runPrune(gopts GlobalOptions) error {
var supersedes restic.IDs var supersedes restic.IDs
for idxID := range repo.List(restic.IndexFile, done) { for idxID := range repo.List(restic.IndexFile, done) {
err := repo.Backend().Remove(restic.IndexFile, idxID.String()) h := restic.Handle{Type: restic.IndexFile, Name: idxID.String()}
err := repo.Backend().Remove(h)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "unable to remove index %v: %v\n", idxID.Str(), err) fmt.Fprintf(os.Stderr, "unable to remove index %v: %v\n", idxID.Str(), err)
} }

View file

@ -39,7 +39,7 @@ func randomID() restic.ID {
func forgetfulBackend() restic.Backend { func forgetfulBackend() restic.Backend {
be := &mock.Backend{} be := &mock.Backend{}
be.TestFn = func(t restic.FileType, name string) (bool, error) { be.TestFn = func(h restic.Handle) (bool, error) {
return false, nil return false, nil
} }
@ -55,7 +55,7 @@ func forgetfulBackend() restic.Backend {
return restic.FileInfo{}, errors.New("not found") return restic.FileInfo{}, errors.New("not found")
} }
be.RemoveFn = func(t restic.FileType, name string) error { be.RemoveFn = func(h restic.Handle) error {
return nil return nil
} }

View file

@ -9,10 +9,10 @@ type Backend interface {
Location() string Location() string
// Test a boolean value whether a File with the name and type exists. // Test a boolean value whether a File with the name and type exists.
Test(t FileType, name string) (bool, error) Test(h Handle) (bool, error)
// Remove removes a File with type t and name. // Remove removes a File with type t and name.
Remove(t FileType, name string) error Remove(h Handle) error
// Close the backend // Close the backend
Close() error Close() error

View file

@ -219,9 +219,9 @@ func (b *Local) Stat(h restic.Handle) (restic.FileInfo, error) {
} }
// 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 restic.FileType, name string) (bool, error) { func (b *Local) Test(h restic.Handle) (bool, error) {
debug.Log("Test %v %v", t, name) debug.Log("Test %v", h)
_, err := fs.Stat(filename(b.p, t, name)) _, err := fs.Stat(filename(b.p, h.Type, h.Name))
if err != nil { if err != nil {
if os.IsNotExist(errors.Cause(err)) { if os.IsNotExist(errors.Cause(err)) {
return false, nil return false, nil
@ -233,9 +233,9 @@ func (b *Local) Test(t restic.FileType, name string) (bool, error) {
} }
// Remove removes the blob with the given name and type. // Remove removes the blob with the given name and type.
func (b *Local) Remove(t restic.FileType, name string) error { func (b *Local) Remove(h restic.Handle) error {
debug.Log("Remove %v %v", t, name) debug.Log("Remove %v", h)
fn := filename(b.p, t, name) fn := filename(b.p, h.Type, h.Name)
// reset read-only flag // reset read-only flag
err := fs.Chmod(fn, 0666) err := fs.Chmod(fn, 0666)

View file

@ -13,12 +13,7 @@ import (
"restic/debug" "restic/debug"
) )
type entry struct { type memMap map[restic.Handle][]byte
Type restic.FileType
Name string
}
type memMap map[entry][]byte
// make sure that MemoryBackend implements backend.Backend // make sure that MemoryBackend implements backend.Backend
var _ restic.Backend = &MemoryBackend{} var _ restic.Backend = &MemoryBackend{}
@ -42,13 +37,13 @@ func New() *MemoryBackend {
} }
// Test returns whether a file exists. // Test returns whether a file exists.
func (be *MemoryBackend) Test(t restic.FileType, name string) (bool, error) { func (be *MemoryBackend) Test(h restic.Handle) (bool, error) {
be.m.Lock() be.m.Lock()
defer be.m.Unlock() defer be.m.Unlock()
debug.Log("test %v %v", t, name) debug.Log("Test %v", h)
if _, ok := be.data[entry{t, name}]; ok { if _, ok := be.data[h]; ok {
return true, nil return true, nil
} }
@ -68,7 +63,7 @@ func (be *MemoryBackend) Save(h restic.Handle, rd io.Reader) error {
h.Name = "" h.Name = ""
} }
if _, ok := be.data[entry{h.Type, h.Name}]; ok { if _, ok := be.data[h]; ok {
return errors.New("file already exists") return errors.New("file already exists")
} }
@ -77,7 +72,7 @@ func (be *MemoryBackend) Save(h restic.Handle, rd io.Reader) error {
return err return err
} }
be.data[entry{h.Type, h.Name}] = buf be.data[h] = buf
debug.Log("saved %v bytes at %v", len(buf), h) debug.Log("saved %v bytes at %v", len(buf), h)
return nil return nil
@ -104,11 +99,11 @@ func (be *MemoryBackend) Load(h restic.Handle, length int, offset int64) (io.Rea
return nil, errors.New("offset is negative") return nil, errors.New("offset is negative")
} }
if _, ok := be.data[entry{h.Type, h.Name}]; !ok { if _, ok := be.data[h]; !ok {
return nil, errors.New("no such data") return nil, errors.New("no such data")
} }
buf := be.data[entry{h.Type, h.Name}] buf := be.data[h]
if offset > int64(len(buf)) { if offset > int64(len(buf)) {
return nil, errors.New("offset beyond end of file") return nil, errors.New("offset beyond end of file")
} }
@ -118,7 +113,7 @@ func (be *MemoryBackend) Load(h restic.Handle, length int, offset int64) (io.Rea
buf = buf[:length] buf = buf[:length]
} }
return backend.Closer{bytes.NewReader(buf)}, nil return backend.Closer{Reader: bytes.NewReader(buf)}, nil
} }
// Stat returns information about a file in the backend. // Stat returns information about a file in the backend.
@ -136,7 +131,7 @@ func (be *MemoryBackend) Stat(h restic.Handle) (restic.FileInfo, error) {
debug.Log("stat %v", h) debug.Log("stat %v", h)
e, ok := be.data[entry{h.Type, h.Name}] e, ok := be.data[h]
if !ok { if !ok {
return restic.FileInfo{}, errors.New("no such data") return restic.FileInfo{}, errors.New("no such data")
} }
@ -145,17 +140,17 @@ func (be *MemoryBackend) Stat(h restic.Handle) (restic.FileInfo, error) {
} }
// Remove deletes a file from the backend. // Remove deletes a file from the backend.
func (be *MemoryBackend) Remove(t restic.FileType, name string) error { func (be *MemoryBackend) Remove(h restic.Handle) error {
be.m.Lock() be.m.Lock()
defer be.m.Unlock() defer be.m.Unlock()
debug.Log("get %v %v", t, name) debug.Log("Remove %v", h)
if _, ok := be.data[entry{t, name}]; !ok { if _, ok := be.data[h]; !ok {
return errors.New("no such data") return errors.New("no such data")
} }
delete(be.data, entry{t, name}) delete(be.data, h)
return nil return nil
} }

View file

@ -194,8 +194,8 @@ func (b *restBackend) Stat(h restic.Handle) (restic.FileInfo, error) {
} }
// 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 *restBackend) Test(t restic.FileType, name string) (bool, error) { func (b *restBackend) Test(h restic.Handle) (bool, error) {
_, err := b.Stat(restic.Handle{Type: t, Name: name}) _, err := b.Stat(h)
if err != nil { if err != nil {
return false, nil return false, nil
} }
@ -204,8 +204,7 @@ func (b *restBackend) Test(t restic.FileType, name string) (bool, error) {
} }
// Remove removes the blob with the given name and type. // Remove removes the blob with the given name and type.
func (b *restBackend) Remove(t restic.FileType, name string) error { func (b *restBackend) Remove(h restic.Handle) error {
h := restic.Handle{Type: t, Name: name}
if err := h.Valid(); err != nil { if err := h.Valid(); err != nil {
return err return err
} }

View file

@ -37,7 +37,7 @@ func init() {
return nil, err return nil, err
} }
exists, err := be.Test(restic.ConfigFile, "") exists, err := be.Test(restic.Handle{Type: restic.ConfigFile, Name: ""})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -55,11 +55,11 @@ func Open(cfg Config) (restic.Backend, error) {
return be, nil return be, nil
} }
func (be *s3) s3path(t restic.FileType, name string) string { func (be *s3) s3path(h restic.Handle) string {
if t == restic.ConfigFile { if h.Type == restic.ConfigFile {
return path.Join(be.prefix, string(t)) return path.Join(be.prefix, string(h.Type))
} }
return path.Join(be.prefix, string(t), name) return path.Join(be.prefix, string(h.Type), h.Name)
} }
func (be *s3) createConnections() { func (be *s3) createConnections() {
@ -82,7 +82,7 @@ func (be *s3) Save(h restic.Handle, rd io.Reader) (err error) {
debug.Log("Save %v", h) debug.Log("Save %v", h)
objName := be.s3path(h.Type, h.Name) objName := be.s3path(h)
// Check key does not already exist // Check key does not already exist
_, err = be.client.StatObject(be.bucketname, objName) _, err = be.client.StatObject(be.bucketname, objName)
@ -123,7 +123,7 @@ func (be *s3) Load(h restic.Handle, length int, offset int64) (io.ReadCloser, er
var obj *minio.Object var obj *minio.Object
objName := be.s3path(h.Type, h.Name) objName := be.s3path(h)
<-be.connChan <-be.connChan
defer func() { defer func() {
@ -186,7 +186,7 @@ func (be *s3) Load(h restic.Handle, length int, offset int64) (io.ReadCloser, er
func (be *s3) Stat(h restic.Handle) (bi restic.FileInfo, err error) { func (be *s3) Stat(h restic.Handle) (bi restic.FileInfo, err error) {
debug.Log("%v", h) debug.Log("%v", h)
objName := be.s3path(h.Type, h.Name) objName := be.s3path(h)
var obj *minio.Object var obj *minio.Object
obj, err = be.client.GetObject(be.bucketname, objName) obj, err = be.client.GetObject(be.bucketname, objName)
@ -213,9 +213,9 @@ func (be *s3) Stat(h restic.Handle) (bi restic.FileInfo, err error) {
} }
// 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 *s3) Test(t restic.FileType, name string) (bool, error) { func (be *s3) Test(h restic.Handle) (bool, error) {
found := false found := false
objName := be.s3path(t, name) objName := be.s3path(h)
_, err := be.client.StatObject(be.bucketname, objName) _, err := be.client.StatObject(be.bucketname, objName)
if err == nil { if err == nil {
found = true found = true
@ -226,10 +226,10 @@ func (be *s3) Test(t restic.FileType, name string) (bool, error) {
} }
// Remove removes the blob with the given name and type. // Remove removes the blob with the given name and type.
func (be *s3) Remove(t restic.FileType, name string) error { func (be *s3) Remove(h restic.Handle) error {
objName := be.s3path(t, name) objName := be.s3path(h)
err := be.client.RemoveObject(be.bucketname, objName) err := be.client.RemoveObject(be.bucketname, objName)
debug.Log("%v %v -> err %v", t, name, err) debug.Log("Remove(%v) -> err %v", h, err)
return errors.Wrap(err, "client.RemoveObject") return errors.Wrap(err, "client.RemoveObject")
} }
@ -240,7 +240,7 @@ func (be *s3) List(t restic.FileType, done <-chan struct{}) <-chan string {
debug.Log("listing %v", t) debug.Log("listing %v", t)
ch := make(chan string) ch := make(chan string)
prefix := be.s3path(t, "") + "/" prefix := be.s3path(restic.Handle{Type: t}) + "/"
listresp := be.client.ListObjects(be.bucketname, prefix, true, done) listresp := be.client.ListObjects(be.bucketname, prefix, true, done)
@ -268,7 +268,7 @@ func (be *s3) removeKeys(t restic.FileType) error {
done := make(chan struct{}) done := make(chan struct{})
defer close(done) defer close(done)
for key := range be.List(restic.DataFile, done) { for key := range be.List(restic.DataFile, done) {
err := be.Remove(restic.DataFile, key) err := be.Remove(restic.Handle{Type: restic.DataFile, Name: key})
if err != nil { if err != nil {
return err return err
} }
@ -293,7 +293,7 @@ func (be *s3) Delete() error {
} }
} }
return be.Remove(restic.ConfigFile, "") return be.Remove(restic.Handle{Type: restic.ConfigFile})
} }
// Close does nothing // Close does nothing

View file

@ -44,7 +44,7 @@ func init() {
return nil, err return nil, err
} }
exists, err := be.Test(restic.ConfigFile, "") exists, err := be.Test(restic.Handle{Type: restic.ConfigFile})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -259,11 +259,11 @@ func (r *SFTP) mkdirAll(dir string, mode os.FileMode) error {
} }
// Rename temp file to final name according to type and name. // Rename temp file to final name according to type and name.
func (r *SFTP) renameFile(oldname string, t restic.FileType, name string) error { func (r *SFTP) renameFile(oldname string, h restic.Handle) error {
filename := r.filename(t, name) filename := r.filename(h)
// create directories if necessary // create directories if necessary
if t == restic.DataFile { if h.Type == restic.DataFile {
err := r.mkdirAll(path.Dir(filename), backend.Modes.Dir) err := r.mkdirAll(path.Dir(filename), backend.Modes.Dir)
if err != nil { if err != nil {
return err return err
@ -297,22 +297,22 @@ func Join(parts ...string) string {
} }
// Construct path for given restic.Type and name. // Construct path for given restic.Type and name.
func (r *SFTP) filename(t restic.FileType, name string) string { func (r *SFTP) filename(h restic.Handle) string {
if t == restic.ConfigFile { if h.Type == restic.ConfigFile {
return Join(r.p, "config") return Join(r.p, "config")
} }
return Join(r.dirname(t, name), name) return Join(r.dirname(h), h.Name)
} }
// Construct directory for given backend.Type. // Construct directory for given backend.Type.
func (r *SFTP) dirname(t restic.FileType, name string) string { func (r *SFTP) dirname(h restic.Handle) string {
var n string var n string
switch t { switch h.Type {
case restic.DataFile: case restic.DataFile:
n = backend.Paths.Data n = backend.Paths.Data
if len(name) > 2 { if len(h.Name) > 2 {
n = Join(n, name[:2]) n = Join(n, h.Name[:2])
} }
case restic.SnapshotFile: case restic.SnapshotFile:
n = backend.Paths.Snapshots n = backend.Paths.Snapshots
@ -354,7 +354,7 @@ func (r *SFTP) Save(h restic.Handle, rd io.Reader) (err error) {
return errors.Wrap(err, "Close") return errors.Wrap(err, "Close")
} }
err = r.renameFile(filename, h.Type, h.Name) err = r.renameFile(filename, h)
debug.Log("save %v: rename %v: %v", debug.Log("save %v: rename %v: %v",
h, path.Base(filename), err) h, path.Base(filename), err)
return err return err
@ -373,7 +373,7 @@ func (r *SFTP) Load(h restic.Handle, length int, offset int64) (io.ReadCloser, e
return nil, errors.New("offset is negative") return nil, errors.New("offset is negative")
} }
f, err := r.c.Open(r.filename(h.Type, h.Name)) f, err := r.c.Open(r.filename(h))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -395,7 +395,7 @@ func (r *SFTP) Load(h restic.Handle, length int, offset int64) (io.ReadCloser, e
// Stat returns information about a blob. // Stat returns information about a blob.
func (r *SFTP) Stat(h restic.Handle) (restic.FileInfo, error) { func (r *SFTP) Stat(h restic.Handle) (restic.FileInfo, error) {
debug.Log("stat %v", h) debug.Log("Stat(%v)", h)
if err := r.clientError(); err != nil { if err := r.clientError(); err != nil {
return restic.FileInfo{}, err return restic.FileInfo{}, err
} }
@ -404,7 +404,7 @@ func (r *SFTP) Stat(h restic.Handle) (restic.FileInfo, error) {
return restic.FileInfo{}, err return restic.FileInfo{}, err
} }
fi, err := r.c.Lstat(r.filename(h.Type, h.Name)) fi, err := r.c.Lstat(r.filename(h))
if err != nil { if err != nil {
return restic.FileInfo{}, errors.Wrap(err, "Lstat") return restic.FileInfo{}, errors.Wrap(err, "Lstat")
} }
@ -413,13 +413,13 @@ func (r *SFTP) Stat(h restic.Handle) (restic.FileInfo, error) {
} }
// 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 restic.FileType, name string) (bool, error) { func (r *SFTP) Test(h restic.Handle) (bool, error) {
debug.Log("type %v, name %v", t, name) debug.Log("Test(%v)", h)
if err := r.clientError(); err != nil { if err := r.clientError(); err != nil {
return false, err return false, err
} }
_, err := r.c.Lstat(r.filename(t, name)) _, err := r.c.Lstat(r.filename(h))
if os.IsNotExist(errors.Cause(err)) { if os.IsNotExist(errors.Cause(err)) {
return false, nil return false, nil
} }
@ -432,13 +432,13 @@ func (r *SFTP) Test(t restic.FileType, name string) (bool, error) {
} }
// Remove removes the content stored at name. // Remove removes the content stored at name.
func (r *SFTP) Remove(t restic.FileType, name string) error { func (r *SFTP) Remove(h restic.Handle) error {
debug.Log("type %v, name %v", t, name) debug.Log("Remove(%v)", h)
if err := r.clientError(); err != nil { if err := r.clientError(); err != nil {
return err return err
} }
return r.c.Remove(r.filename(t, name)) return r.c.Remove(r.filename(h))
} }
// List returns a channel that yields all names of blobs of type t. A // List returns a channel that yields all names of blobs of type t. A
@ -453,7 +453,7 @@ func (r *SFTP) List(t restic.FileType, done <-chan struct{}) <-chan string {
if t == restic.DataFile { if t == restic.DataFile {
// read first level // read first level
basedir := r.dirname(t, "") basedir := r.dirname(restic.Handle{Type: t})
list1, err := r.c.ReadDir(basedir) list1, err := r.c.ReadDir(basedir)
if err != nil { if err != nil {
@ -486,7 +486,7 @@ func (r *SFTP) List(t restic.FileType, done <-chan struct{}) <-chan string {
} }
} }
} else { } else {
entries, err := r.c.ReadDir(r.dirname(t, "")) entries, err := r.c.ReadDir(r.dirname(restic.Handle{Type: t}))
if err != nil { if err != nil {
return return
} }

View file

@ -130,7 +130,7 @@ func TestCreateWithConfig(t testing.TB) {
} }
// remove config // remove config
err = b.Remove(restic.ConfigFile, "") err = b.Remove(restic.Handle{Type: restic.ConfigFile, Name: ""})
if err != nil { if err != nil {
t.Fatalf("unexpected error removing config: %v", err) t.Fatalf("unexpected error removing config: %v", err)
} }
@ -270,7 +270,7 @@ func TestLoad(t testing.TB) {
} }
} }
test.OK(t, b.Remove(restic.DataFile, id.String())) test.OK(t, b.Remove(handle))
} }
type errorCloser struct { type errorCloser struct {
@ -319,7 +319,7 @@ func TestSave(t testing.TB) {
t.Fatalf("Stat() returned different size, want %q, got %d", len(data), fi.Size) t.Fatalf("Stat() returned different size, want %q, got %d", len(data), fi.Size)
} }
err = b.Remove(h.Type, h.Name) err = b.Remove(h)
if err != nil { if err != nil {
t.Fatalf("error removing item: %v", err) t.Fatalf("error removing item: %v", err)
} }
@ -401,7 +401,7 @@ func TestSaveFilenames(t testing.TB) {
t.Errorf("test %d: returned wrong bytes", i) t.Errorf("test %d: returned wrong bytes", i)
} }
err = b.Remove(h.Type, h.Name) err = b.Remove(h)
if err != nil { if err != nil {
t.Errorf("test %d failed: Remove() returned %v", i, err) t.Errorf("test %d failed: Remove() returned %v", i, err)
continue continue
@ -419,10 +419,12 @@ var testStrings = []struct {
{"4e54d2c721cbdb730f01b10b62dec622962b36966ec685880effa63d71c808f2", "foo/../../baz"}, {"4e54d2c721cbdb730f01b10b62dec622962b36966ec685880effa63d71c808f2", "foo/../../baz"},
} }
func store(t testing.TB, b restic.Backend, tpe restic.FileType, data []byte) { func store(t testing.TB, b restic.Backend, tpe restic.FileType, data []byte) restic.Handle {
id := restic.Hash(data) id := restic.Hash(data)
err := b.Save(restic.Handle{Name: id.String(), Type: tpe}, bytes.NewReader(data)) h := restic.Handle{Name: id.String(), Type: tpe}
err := b.Save(h, bytes.NewReader(data))
test.OK(t, err) test.OK(t, err)
return h
} }
// TestBackend tests all functions of the backend. // TestBackend tests all functions of the backend.
@ -440,12 +442,12 @@ func TestBackend(t testing.TB) {
test.OK(t, err) test.OK(t, err)
// test if blob is already in repository // test if blob is already in repository
ret, err := b.Test(tpe, id.String()) h := restic.Handle{Type: tpe, Name: id.String()}
ret, err := b.Test(h)
test.OK(t, err) test.OK(t, err)
test.Assert(t, !ret, "blob was found to exist before creating") test.Assert(t, !ret, "blob was found to exist before creating")
// try to stat a not existing blob // try to stat a not existing blob
h := restic.Handle{Type: tpe, Name: id.String()}
_, err = b.Stat(h) _, err = b.Stat(h)
test.Assert(t, err != nil, "blob data could be extracted before creation") test.Assert(t, err != nil, "blob data could be extracted before creation")
@ -454,7 +456,7 @@ func TestBackend(t testing.TB) {
test.Assert(t, err != nil, "blob reader could be obtained before creation") test.Assert(t, err != nil, "blob reader could be obtained before creation")
// try to get string out, should fail // try to get string out, should fail
ret, err = b.Test(tpe, id.String()) ret, err = b.Test(h)
test.OK(t, err) test.OK(t, err)
test.Assert(t, !ret, "id %q was found (but should not have)", ts.id) test.Assert(t, !ret, "id %q was found (but should not have)", ts.id)
} }
@ -498,16 +500,17 @@ func TestBackend(t testing.TB) {
test.Assert(t, err != nil, "expected error, got %v", err) test.Assert(t, err != nil, "expected error, got %v", err)
// remove and recreate // remove and recreate
err = b.Remove(tpe, ts.id) h := restic.Handle{Type: tpe, Name: ts.id}
err = b.Remove(h)
test.OK(t, err) test.OK(t, err)
// test that the blob is gone // test that the blob is gone
ok, err := b.Test(tpe, ts.id) ok, err := b.Test(h)
test.OK(t, err) test.OK(t, err)
test.Assert(t, ok == false, "removed blob still present") test.Assert(t, ok == false, "removed blob still present")
// create blob // create blob
err = b.Save(restic.Handle{Type: tpe, Name: ts.id}, strings.NewReader(ts.data)) err = b.Save(h, strings.NewReader(ts.data))
test.OK(t, err) test.OK(t, err)
// list items // list items
@ -542,12 +545,14 @@ func TestBackend(t testing.TB) {
id, err := restic.ParseID(ts.id) id, err := restic.ParseID(ts.id)
test.OK(t, err) test.OK(t, err)
found, err := b.Test(tpe, id.String()) h := restic.Handle{Type: tpe, Name: id.String()}
found, err := b.Test(h)
test.OK(t, err) test.OK(t, err)
test.OK(t, b.Remove(tpe, id.String())) test.OK(t, b.Remove(h))
found, err = b.Test(tpe, id.String()) found, err = b.Test(h)
test.OK(t, err) test.OK(t, err)
test.Assert(t, !found, fmt.Sprintf("id %q not found after removal", id)) test.Assert(t, !found, fmt.Sprintf("id %q not found after removal", id))
} }

View file

@ -187,7 +187,8 @@ func packIDTester(repo restic.Repository, inChan <-chan restic.ID, errChan chan<
defer wg.Done() defer wg.Done()
for id := range inChan { for id := range inChan {
ok, err := repo.Backend().Test(restic.DataFile, id.String()) h := restic.Handle{Type: restic.DataFile, Name: id.String()}
ok, err := repo.Backend().Test(h)
if err != nil { if err != nil {
err = PackError{ID: id, Err: err} err = PackError{ID: id, Err: err}
} else { } else {

View file

@ -73,8 +73,11 @@ func TestMissingPack(t *testing.T) {
repo := repository.TestOpenLocal(t, repodir) repo := repository.TestOpenLocal(t, repodir)
packID := "657f7fb64f6a854fff6fe9279998ee09034901eded4e6db9bcee0e59745bbce6" packHandle := restic.Handle{
test.OK(t, repo.Backend().Remove(restic.DataFile, packID)) Type: restic.DataFile,
Name: "657f7fb64f6a854fff6fe9279998ee09034901eded4e6db9bcee0e59745bbce6",
}
test.OK(t, repo.Backend().Remove(packHandle))
chkr := checker.New(repo) chkr := checker.New(repo)
hints, errs := chkr.LoadIndex() hints, errs := chkr.LoadIndex()
@ -92,7 +95,7 @@ func TestMissingPack(t *testing.T) {
"expected exactly one error, got %v", len(errs)) "expected exactly one error, got %v", len(errs))
if err, ok := errs[0].(checker.PackError); ok { if err, ok := errs[0].(checker.PackError); ok {
test.Equals(t, packID, err.ID.String()) test.Equals(t, packHandle.Name, err.ID.String())
} else { } else {
t.Errorf("expected error returned by checker.Packs() to be PackError, got %v", err) t.Errorf("expected error returned by checker.Packs() to be PackError, got %v", err)
} }
@ -105,9 +108,12 @@ func TestUnreferencedPack(t *testing.T) {
repo := repository.TestOpenLocal(t, repodir) repo := repository.TestOpenLocal(t, repodir)
// index 3f1a only references pack 60e0 // index 3f1a only references pack 60e0
indexID := "3f1abfcb79c6f7d0a3be517d2c83c8562fba64ef2c8e9a3544b4edaf8b5e3b44"
packID := "60e0438dcb978ec6860cc1f8c43da648170ee9129af8f650f876bad19f8f788e" packID := "60e0438dcb978ec6860cc1f8c43da648170ee9129af8f650f876bad19f8f788e"
test.OK(t, repo.Backend().Remove(restic.IndexFile, indexID)) indexHandle := restic.Handle{
Type: restic.IndexFile,
Name: "3f1abfcb79c6f7d0a3be517d2c83c8562fba64ef2c8e9a3544b4edaf8b5e3b44",
}
test.OK(t, repo.Backend().Remove(indexHandle))
chkr := checker.New(repo) chkr := checker.New(repo)
hints, errs := chkr.LoadIndex() hints, errs := chkr.LoadIndex()
@ -137,8 +143,11 @@ func TestUnreferencedBlobs(t *testing.T) {
repo := repository.TestOpenLocal(t, repodir) repo := repository.TestOpenLocal(t, repodir)
snID := "51d249d28815200d59e4be7b3f21a157b864dc343353df9d8e498220c2499b02" snapshotHandle := restic.Handle{
test.OK(t, repo.Backend().Remove(restic.SnapshotFile, snID)) Type: restic.SnapshotFile,
Name: "51d249d28815200d59e4be7b3f21a157b864dc343353df9d8e498220c2499b02",
}
test.OK(t, repo.Backend().Remove(snapshotHandle))
unusedBlobsBySnapshot := restic.IDs{ unusedBlobsBySnapshot := restic.IDs{
restic.TestParseID("58c748bbe2929fdf30c73262bd8313fe828f8925b05d1d4a87fe109082acb849"), restic.TestParseID("58c748bbe2929fdf30c73262bd8313fe828f8925b05d1d4a87fe109082acb849"),

View file

@ -234,7 +234,8 @@ func TestSave(t *testing.T) {
for id := range idx.IndexIDs { for id := range idx.IndexIDs {
t.Logf("remove index %v", id.Str()) t.Logf("remove index %v", id.Str())
err = repo.Backend().Remove(restic.IndexFile, id.String()) h := restic.Handle{Type: restic.IndexFile, Name: id.String()}
err = repo.Backend().Remove(h)
if err != nil { if err != nil {
t.Errorf("error removing index %v: %v", id, err) t.Errorf("error removing index %v: %v", id, err)
} }
@ -275,7 +276,8 @@ func TestIndexSave(t *testing.T) {
for id := range idx.IndexIDs { for id := range idx.IndexIDs {
t.Logf("remove index %v", id.Str()) t.Logf("remove index %v", id.Str())
err = repo.Backend().Remove(restic.IndexFile, id.String()) h := restic.Handle{Type: restic.IndexFile, Name: id.String()}
err = repo.Backend().Remove(h)
if err != nil { if err != nil {
t.Errorf("error removing index %v: %v", id, err) t.Errorf("error removing index %v: %v", id, err)
} }

View file

@ -186,7 +186,7 @@ func (l *Lock) Unlock() error {
return nil return nil
} }
return l.repo.Backend().Remove(LockFile, l.lockID.String()) return l.repo.Backend().Remove(Handle{Type: LockFile, Name: l.lockID.String()})
} }
var staleTimeout = 30 * time.Minute var staleTimeout = 30 * time.Minute
@ -234,7 +234,7 @@ func (l *Lock) Refresh() error {
return err return err
} }
err = l.repo.Backend().Remove(LockFile, l.lockID.String()) err = l.repo.Backend().Remove(Handle{Type: LockFile, Name: l.lockID.String()})
if err != nil { if err != nil {
return err return err
} }
@ -289,7 +289,7 @@ func RemoveStaleLocks(repo Repository) error {
} }
if lock.Stale() { if lock.Stale() {
return repo.Backend().Remove(LockFile, id.String()) return repo.Backend().Remove(Handle{Type: LockFile, Name: id.String()})
} }
return nil return nil
@ -299,6 +299,6 @@ func RemoveStaleLocks(repo Repository) error {
// RemoveAllLocks removes all locks forcefully. // RemoveAllLocks removes all locks forcefully.
func RemoveAllLocks(repo Repository) error { func RemoveAllLocks(repo Repository) error {
return eachLock(repo, func(id ID, lock *Lock, err error) error { return eachLock(repo, func(id ID, lock *Lock, err error) error {
return repo.Backend().Remove(LockFile, id.String()) return repo.Backend().Remove(Handle{Type: LockFile, Name: id.String()})
}) })
} }

View file

@ -102,7 +102,8 @@ func createFakeLock(repo restic.Repository, t time.Time, pid int) (restic.ID, er
} }
func removeLock(repo restic.Repository, id restic.ID) error { func removeLock(repo restic.Repository, id restic.ID) error {
return repo.Backend().Remove(restic.LockFile, id.String()) h := restic.Handle{Type: restic.LockFile, Name: id.String()}
return repo.Backend().Remove(h)
} }
var staleLockTests = []struct { var staleLockTests = []struct {
@ -162,7 +163,8 @@ func TestLockStale(t *testing.T) {
} }
func lockExists(repo restic.Repository, t testing.TB, id restic.ID) bool { func lockExists(repo restic.Repository, t testing.TB, id restic.ID) bool {
exists, err := repo.Backend().Test(restic.LockFile, id.String()) h := restic.Handle{Type: restic.LockFile, Name: id.String()}
exists, err := repo.Backend().Test(h)
OK(t, err) OK(t, err)
return exists return exists

View file

@ -14,8 +14,8 @@ type Backend struct {
LoadFn func(h restic.Handle, length int, offset int64) (io.ReadCloser, error) LoadFn func(h restic.Handle, length int, offset int64) (io.ReadCloser, error)
StatFn func(h restic.Handle) (restic.FileInfo, error) StatFn func(h restic.Handle) (restic.FileInfo, error)
ListFn func(restic.FileType, <-chan struct{}) <-chan string ListFn func(restic.FileType, <-chan struct{}) <-chan string
RemoveFn func(restic.FileType, string) error RemoveFn func(h restic.Handle) error
TestFn func(restic.FileType, string) (bool, error) TestFn func(h restic.Handle) (bool, error)
DeleteFn func() error DeleteFn func() error
LocationFn func() string LocationFn func() string
} }
@ -77,21 +77,21 @@ func (m *Backend) List(t restic.FileType, done <-chan struct{}) <-chan string {
} }
// Remove data from the backend. // Remove data from the backend.
func (m *Backend) Remove(t restic.FileType, name string) error { func (m *Backend) Remove(h restic.Handle) error {
if m.RemoveFn == nil { if m.RemoveFn == nil {
return errors.New("not implemented") return errors.New("not implemented")
} }
return m.RemoveFn(t, name) return m.RemoveFn(h)
} }
// Test for the existence of a specific item. // Test for the existence of a specific item.
func (m *Backend) Test(t restic.FileType, name string) (bool, error) { func (m *Backend) Test(h restic.Handle) (bool, error) {
if m.TestFn == nil { if m.TestFn == nil {
return false, errors.New("not implemented") return false, errors.New("not implemented")
} }
return m.TestFn(t, name) return m.TestFn(h)
} }
// Delete all data. // Delete all data.

View file

@ -55,7 +55,8 @@ func RebuildIndex(repo restic.Repository) error {
debug.Log("new index saved as %v", id.Str()) debug.Log("new index saved as %v", id.Str())
for indexID := range oldIndexes { for indexID := range oldIndexes {
err := repo.Backend().Remove(restic.IndexFile, indexID.String()) h := restic.Handle{Type: restic.IndexFile, Name: indexID.String()}
err := repo.Backend().Remove(h)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "unable to remove index %v: %v\n", indexID.Str(), err) fmt.Fprintf(os.Stderr, "unable to remove index %v: %v\n", indexID.Str(), err)
} }

View file

@ -123,7 +123,8 @@ func Repack(repo restic.Repository, packs restic.IDSet, keepBlobs restic.BlobSet
} }
for packID := range packs { for packID := range packs {
err := repo.Backend().Remove(restic.DataFile, packID.String()) h := restic.Handle{Type: restic.DataFile, Name: packID.String()}
err := repo.Backend().Remove(h)
if err != nil { if err != nil {
debug.Log("error removing pack %v: %v", packID.Str(), err) debug.Log("error removing pack %v: %v", packID.Str(), err)
return err return err

View file

@ -380,7 +380,7 @@ func (r *Repository) SearchKey(password string, maxKeys int) error {
// Init creates a new master key with the supplied password, initializes and // Init creates a new master key with the supplied password, initializes and
// saves the repository config. // saves the repository config.
func (r *Repository) Init(password string) error { func (r *Repository) Init(password string) error {
has, err := r.be.Test(restic.ConfigFile, "") has, err := r.be.Test(restic.Handle{Type: restic.ConfigFile})
if err != nil { if err != nil {
return err return err
} }