mirror of
https://github.com/octoleo/restic.git
synced 2024-12-23 03:18:55 +00:00
backend: Add IsNotExist
This commit is contained in:
parent
6f24d038f8
commit
af9ba3be91
@ -152,6 +152,10 @@ func pruneRepository(gopts GlobalOptions, repo restic.Repository) error {
|
||||
|
||||
err = restic.FindUsedBlobs(ctx, repo, *sn.Tree, usedBlobs, seenBlobs)
|
||||
if err != nil {
|
||||
if repo.Backend().IsNotExist(err) {
|
||||
return errors.Fatal("unable to load a tree from the repo: " + err.Error())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,10 @@ type Backend interface {
|
||||
// arbitrary order. A goroutine is started for this, which is stopped when
|
||||
// ctx is cancelled.
|
||||
List(ctx context.Context, t FileType) <-chan string
|
||||
|
||||
// IsNotExist returns true if the error was caused by a non-existing file
|
||||
// in the backend.
|
||||
IsNotExist(err error) bool
|
||||
}
|
||||
|
||||
// FileInfo is returned by Stat() and contains information about a file in the
|
||||
|
@ -151,6 +151,11 @@ func (wr *wrapReader) Close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// IsNotExist returns true if the error is caused by a non-existing file.
|
||||
func (be *b2Backend) IsNotExist(err error) bool {
|
||||
return b2.IsNotExist(errors.Cause(err))
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (be *b2Backend) Load(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error) {
|
||||
|
@ -75,6 +75,11 @@ func (b *Local) Location() string {
|
||||
return b.Path
|
||||
}
|
||||
|
||||
// IsNotExist returns true if the error is caused by a non existing file.
|
||||
func (b *Local) IsNotExist(err error) bool {
|
||||
return os.IsNotExist(errors.Cause(err))
|
||||
}
|
||||
|
||||
// Save stores data in the backend at the handle.
|
||||
func (b *Local) Save(ctx context.Context, h restic.Handle, rd io.Reader) (err error) {
|
||||
debug.Log("Save %v", h)
|
||||
|
@ -19,6 +19,8 @@ type memMap map[restic.Handle][]byte
|
||||
// make sure that MemoryBackend implements backend.Backend
|
||||
var _ restic.Backend = &MemoryBackend{}
|
||||
|
||||
var errNotFound = errors.New("not found")
|
||||
|
||||
// MemoryBackend is a mock backend that uses a map for storing all data in
|
||||
// memory. This should only be used for tests.
|
||||
type MemoryBackend struct {
|
||||
@ -51,6 +53,11 @@ func (be *MemoryBackend) Test(ctx context.Context, h restic.Handle) (bool, error
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// IsNotExist returns true if the file does not exist.
|
||||
func (be *MemoryBackend) IsNotExist(err error) bool {
|
||||
return errors.Cause(err) == errNotFound
|
||||
}
|
||||
|
||||
// Save adds new Data to the backend.
|
||||
func (be *MemoryBackend) Save(ctx context.Context, h restic.Handle, rd io.Reader) error {
|
||||
if err := h.Valid(); err != nil {
|
||||
@ -101,7 +108,7 @@ func (be *MemoryBackend) Load(ctx context.Context, h restic.Handle, length int,
|
||||
}
|
||||
|
||||
if _, ok := be.data[h]; !ok {
|
||||
return nil, errors.New("no such data")
|
||||
return nil, errNotFound
|
||||
}
|
||||
|
||||
buf := be.data[h]
|
||||
@ -134,7 +141,7 @@ func (be *MemoryBackend) Stat(ctx context.Context, h restic.Handle) (restic.File
|
||||
|
||||
e, ok := be.data[h]
|
||||
if !ok {
|
||||
return restic.FileInfo{}, errors.New("no such data")
|
||||
return restic.FileInfo{}, errNotFound
|
||||
}
|
||||
|
||||
return restic.FileInfo{Size: int64(len(e))}, nil
|
||||
@ -148,7 +155,7 @@ func (be *MemoryBackend) Remove(ctx context.Context, h restic.Handle) error {
|
||||
debug.Log("Remove %v", h)
|
||||
|
||||
if _, ok := be.data[h]; !ok {
|
||||
return errors.New("no such data")
|
||||
return errNotFound
|
||||
}
|
||||
|
||||
delete(be.data, h)
|
||||
|
@ -138,6 +138,23 @@ func (b *restBackend) Save(ctx context.Context, h restic.Handle, rd io.Reader) (
|
||||
return nil
|
||||
}
|
||||
|
||||
// ErrIsNotExist is returned whenever the requested file does not exist on the
|
||||
// server.
|
||||
type ErrIsNotExist struct {
|
||||
restic.Handle
|
||||
}
|
||||
|
||||
func (e ErrIsNotExist) Error() string {
|
||||
return fmt.Sprintf("%v does not exist", e.Handle)
|
||||
}
|
||||
|
||||
// IsNotExist returns true if the error was caused by a non-existing file.
|
||||
func (b *restBackend) IsNotExist(err error) bool {
|
||||
err = errors.Cause(err)
|
||||
_, ok := err.(ErrIsNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Load returns a reader that yields the contents of the file at h at the
|
||||
// given offset. If length is nonzero, only a portion of the file is
|
||||
// returned. rd must be closed after use.
|
||||
@ -179,6 +196,11 @@ func (b *restBackend) Load(ctx context.Context, h restic.Handle, length int, off
|
||||
return nil, errors.Wrap(err, "client.Do")
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
_ = resp.Body.Close()
|
||||
return nil, ErrIsNotExist{h}
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 && resp.StatusCode != 206 {
|
||||
_ = resp.Body.Close()
|
||||
return nil, errors.Errorf("unexpected HTTP response (%v): %v", resp.StatusCode, resp.Status)
|
||||
@ -205,6 +227,11 @@ func (b *restBackend) Stat(ctx context.Context, h restic.Handle) (restic.FileInf
|
||||
return restic.FileInfo{}, errors.Wrap(err, "Close")
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
_ = resp.Body.Close()
|
||||
return restic.FileInfo{}, ErrIsNotExist{h}
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return restic.FileInfo{}, errors.Errorf("unexpected HTTP response (%v): %v", resp.StatusCode, resp.Status)
|
||||
}
|
||||
@ -248,6 +275,11 @@ func (b *restBackend) Remove(ctx context.Context, h restic.Handle) error {
|
||||
return errors.Wrap(err, "client.Do")
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
_ = resp.Body.Close()
|
||||
return ErrIsNotExist{h}
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return errors.Errorf("blob not removed, server response: %v (%v)", resp.Status, resp.StatusCode)
|
||||
}
|
||||
|
@ -10,15 +10,16 @@ import (
|
||||
|
||||
// Backend implements a mock backend.
|
||||
type Backend struct {
|
||||
CloseFn func() error
|
||||
SaveFn func(ctx context.Context, h restic.Handle, rd io.Reader) error
|
||||
LoadFn func(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error)
|
||||
StatFn func(ctx context.Context, h restic.Handle) (restic.FileInfo, error)
|
||||
ListFn func(ctx context.Context, t restic.FileType) <-chan string
|
||||
RemoveFn func(ctx context.Context, h restic.Handle) error
|
||||
TestFn func(ctx context.Context, h restic.Handle) (bool, error)
|
||||
DeleteFn func(ctx context.Context) error
|
||||
LocationFn func() string
|
||||
CloseFn func() error
|
||||
IsNotExistFn func(err error) bool
|
||||
SaveFn func(ctx context.Context, h restic.Handle, rd io.Reader) error
|
||||
LoadFn func(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error)
|
||||
StatFn func(ctx context.Context, h restic.Handle) (restic.FileInfo, error)
|
||||
ListFn func(ctx context.Context, t restic.FileType) <-chan string
|
||||
RemoveFn func(ctx context.Context, h restic.Handle) error
|
||||
TestFn func(ctx context.Context, h restic.Handle) (bool, error)
|
||||
DeleteFn func(ctx context.Context) error
|
||||
LocationFn func() string
|
||||
}
|
||||
|
||||
// Close the backend.
|
||||
@ -39,6 +40,15 @@ func (m *Backend) Location() string {
|
||||
return m.LocationFn()
|
||||
}
|
||||
|
||||
// IsNotExist returns true if the error is caused by a missing file.
|
||||
func (m *Backend) IsNotExist(err error) bool {
|
||||
if m.IsNotExistFn == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return m.IsNotExistFn(err)
|
||||
}
|
||||
|
||||
// Save data in the backend.
|
||||
func (m *Backend) Save(ctx context.Context, h restic.Handle, rd io.Reader) error {
|
||||
if m.SaveFn == nil {
|
||||
|
Loading…
Reference in New Issue
Block a user