diff --git a/internal/backend/backend_retry.go b/internal/backend/backend_retry.go index 5d7a58b64..ab7608e93 100644 --- a/internal/backend/backend_retry.go +++ b/internal/backend/backend_retry.go @@ -57,6 +57,7 @@ func (be *RetryBackend) retry(ctx context.Context, msg string, f func() error) e // Save stores the data in the backend under the given handle. func (be *RetryBackend) Save(ctx context.Context, h restic.Handle, rd restic.RewindReader) error { + firstTry := true return be.retry(ctx, fmt.Sprintf("Save(%v)", h), func() error { err := rd.Rewind() if err != nil { @@ -65,8 +66,19 @@ func (be *RetryBackend) Save(ctx context.Context, h restic.Handle, rd restic.Rew err = be.Backend.Save(ctx, h, rd) if err == nil { + if !firstTry { + fi, err := be.Backend.Stat(ctx, h) + if err != nil { + return err + } + if fi.Size != rd.Length() { + return fmt.Errorf("Stat after save found unexpected length %q instead of %q", fi.Size, rd.Length()) + } + } + return nil } + firstTry = false debug.Log("Save(%v) failed with error, removing file: %v", h, err) rerr := be.Backend.Remove(ctx, h) diff --git a/internal/backend/backend_retry_test.go b/internal/backend/backend_retry_test.go index a746032c7..27524134f 100644 --- a/internal/backend/backend_retry_test.go +++ b/internal/backend/backend_retry_test.go @@ -16,6 +16,7 @@ import ( func TestBackendSaveRetry(t *testing.T) { buf := bytes.NewBuffer(nil) errcount := 0 + uploadSize := int64(0) be := &mock.Backend{ SaveFn: func(ctx context.Context, h restic.Handle, rd restic.RewindReader) error { if errcount == 0 { @@ -28,9 +29,13 @@ func TestBackendSaveRetry(t *testing.T) { return errors.New("injected error") } - _, err := io.Copy(buf, rd) + var err error + uploadSize, err = io.Copy(buf, rd) return err }, + StatFn: func(ctx context.Context, h restic.Handle) (restic.FileInfo, error) { + return restic.FileInfo{Name: h.Name, Size: uploadSize}, nil + }, } retryBackend := NewRetryBackend(be, 10, nil)