diff --git a/changelog/unreleased/pull-21883 b/changelog/unreleased/pull-21883 new file mode 100644 index 000000000..48b77f2d9 --- /dev/null +++ b/changelog/unreleased/pull-21883 @@ -0,0 +1,6 @@ +Enhancement: `find --pack` can handle corrupted pack files + +`restic find --pack ` can now also report affected snapshot if a packfile +is corrupted but still present in the repository index. + +https://github.com/restic/restic/pull/21883 diff --git a/cmd/restic/cmd_find.go b/cmd/restic/cmd_find.go index 37ff1b359..618dd062b 100644 --- a/cmd/restic/cmd_find.go +++ b/cmd/restic/cmd_find.go @@ -445,6 +445,17 @@ func (f *Finder) findIDs(ctx context.Context, sn *data.Snapshot) error { var errAllPacksFound = errors.New("all packs found") +func (f *Finder) addBlobHandle(h restic.BlobHandle) { + switch h.Type { + case restic.DataBlob: + f.blobIDs[h.ID.String()] = struct{}{} + case restic.TreeBlob: + f.treeIDs[h.ID.String()] = struct{}{} + default: + panic(fmt.Sprintf("unknown type %v in blob list", h.Type.String())) + } +} + // packsToBlobs converts the list of pack IDs to a list of blob IDs that // belong to those packs. func (f *Finder) packsToBlobs(ctx context.Context, packs []string) error { @@ -468,37 +479,30 @@ func (f *Finder) packsToBlobs(ctx context.Context, packs []string) error { return nil } delete(packIDs, id.Str()) - } else { - // forget found id - delete(packIDs, idStr) + packIDs[idStr] = struct{}{} } debug.Log("Found pack %s", idStr) handles, err := f.repo.ListPackHandles(ctx, id, size) if err != nil { - return err + // ignore error to allow fallback to index + return nil } for _, h := range handles { - switch h.Type { - case restic.DataBlob: - f.blobIDs[h.ID.String()] = struct{}{} - case restic.TreeBlob: - f.treeIDs[h.ID.String()] = struct{}{} - default: - panic(fmt.Sprintf("unknown type %v in blob list", h.Type.String())) - } + f.addBlobHandle(h) } + // forget successfully processed pack + delete(packIDs, idStr) // Stop searching when all packs have been found if len(packIDs) == 0 { return errAllPacksFound } return nil }) - - if err != nil && err != errAllPacksFound { + if err != nil && !errors.Is(err, errAllPacksFound) { return err } - if err != errAllPacksFound { + if len(packIDs) > 0 { // try to resolve unknown pack ids from the index packIDs, err = f.indexPacksToBlobs(ctx, packIDs) if err != nil { @@ -516,7 +520,7 @@ func (f *Finder) packsToBlobs(ctx context.Context, packs []string) error { return errors.Fatalf("unable to find pack(s): %v", list) } - debug.Log("%d blobs found", len(f.blobIDs)) + debug.Log("%d blobs %v trees found", len(f.blobIDs), len(f.treeIDs)) return nil } @@ -542,7 +546,7 @@ func (f *Finder) indexPacksToBlobs(ctx context.Context, packIDs map[string]struc } } if matchingID { - f.blobIDs[pb.Handle().ID.String()] = struct{}{} + f.addBlobHandle(pb.Handle()) indexPackIDs[idStr] = struct{}{} } }) @@ -554,13 +558,6 @@ func (f *Finder) indexPacksToBlobs(ctx context.Context, packIDs map[string]struc delete(packIDs, id) } - if len(indexPackIDs) > 0 { - list := make([]string, 0, len(indexPackIDs)) - for h := range indexPackIDs { - list = append(list, h) - } - f.printer.E("some pack files are missing from the repository, getting their blobs from the repository index: %v\n\n", list) - } return packIDs, nil }