diff --git a/cmd/restic/cmd_check.go b/cmd/restic/cmd_check.go index 5f03c446b..c637ce89c 100644 --- a/cmd/restic/cmd_check.go +++ b/cmd/restic/cmd_check.go @@ -330,11 +330,28 @@ func runCheck(ctx context.Context, opts CheckOptions, gopts GlobalOptions, args go chkr.ReadPacks(ctx, packs, p, errChan) + var salvagePacks restic.IDs + for err := range errChan { errorsFound = true Warnf("%v\n", err) + if err, ok := err.(*checker.ErrPackData); ok { + if strings.Contains(err.Error(), "wrong data returned, hash is") { + salvagePacks = append(salvagePacks, err.PackID) + } + } } p.Done() + + if len(salvagePacks) > 0 { + Warnf("\nThe repository contains pack files with damaged blobs. These blobs must be removed to repair the repository. This can be done using the following commands:\n\n") + var strIds []string + for _, id := range salvagePacks { + strIds = append(strIds, id.String()) + } + Warnf("restic repair packs %v\nrestic repair snapshots --forget\n\n", strings.Join(strIds, " ")) + Warnf("Corrupted blobs are either caused by hardware problems or bugs in restic. Please open an issue at https://github.com/restic/restic/issues/new/choose for further troubleshooting!\n") + } } switch { diff --git a/internal/checker/checker.go b/internal/checker/checker.go index a5bb43731..59bc20daf 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -90,6 +90,16 @@ func (err *ErrOldIndexFormat) Error() string { return fmt.Sprintf("index %v has old format", err.ID) } +// ErrPackData is returned if errors are discovered while verifying a packfile +type ErrPackData struct { + PackID restic.ID + errs []error +} + +func (e *ErrPackData) Error() string { + return fmt.Sprintf("pack %v contains %v errors: %v", e.PackID, len(e.errs), e.errs) +} + func (c *Checker) LoadSnapshots(ctx context.Context) error { var err error c.snapshots, err = backend.MemorizeList(ctx, c.repo.Backend(), restic.SnapshotFile) @@ -635,7 +645,7 @@ func checkPack(ctx context.Context, r restic.Repository, id restic.ID, blobs []r } if len(errs) > 0 { - return errors.Errorf("pack %v contains %v errors: %v", id, len(errs), errs) + return &ErrPackData{PackID: id, errs: errs} } return nil