From 781c6a12ae10d642f91393f19cf542a78a325cbe Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Thu, 4 Jun 2026 21:58:23 +0200 Subject: [PATCH] restic: list pack header via ListPackHandles Replace ListPack with ListPackHandles so callers only receive blob handles from pack headers, not layout fields. --- cmd/restic/cmd_copy_integration_test.go | 8 ++++---- cmd/restic/cmd_find.go | 12 ++++++------ internal/repository/debug.go | 4 ++-- internal/repository/repack_test.go | 9 ++++----- internal/repository/repair_pack.go | 2 +- internal/repository/repository.go | 19 ++++++++++++++++--- internal/repository/repository_test.go | 6 +++--- internal/restic/repository.go | 4 ++-- 8 files changed, 38 insertions(+), 26 deletions(-) diff --git a/cmd/restic/cmd_copy_integration_test.go b/cmd/restic/cmd_copy_integration_test.go index 252b2fdfe..2c9bcc984 100644 --- a/cmd/restic/cmd_copy_integration_test.go +++ b/cmd/restic/cmd_copy_integration_test.go @@ -103,17 +103,17 @@ func testPackAndBlobCounts(t testing.TB, gopts global.Options) (countTreePacks i defer unlock() rtest.OK(t, repo.List(context.TODO(), restic.PackFile, func(id restic.ID, size int64) error { - blobs, err := repo.ListPack(context.TODO(), id, size) + handles, err := repo.ListPackHandles(context.TODO(), id, size) rtest.OK(t, err) - rtest.Assert(t, len(blobs) > 0, "a packfile should contain at least one blob") + rtest.Assert(t, len(handles) > 0, "a packfile should contain at least one blob") - switch blobs[0].Type { + switch handles[0].Type { case restic.TreeBlob: countTreePacks++ case restic.DataBlob: countDataPacks++ } - countBlobs += len(blobs) + countBlobs += len(handles) return nil })) return nil diff --git a/cmd/restic/cmd_find.go b/cmd/restic/cmd_find.go index 5254b58a0..9fde55560 100644 --- a/cmd/restic/cmd_find.go +++ b/cmd/restic/cmd_find.go @@ -472,18 +472,18 @@ func (f *Finder) packsToBlobs(ctx context.Context, packs []string) error { delete(packIDs, idStr) } debug.Log("Found pack %s", idStr) - blobs, err := f.repo.ListPack(ctx, id, size) + handles, err := f.repo.ListPackHandles(ctx, id, size) if err != nil { return err } - for _, b := range blobs { - switch b.Type { + for _, h := range handles { + switch h.Type { case restic.DataBlob: - f.blobIDs[b.ID.String()] = struct{}{} + f.blobIDs[h.ID.String()] = struct{}{} case restic.TreeBlob: - f.treeIDs[b.ID.String()] = struct{}{} + f.treeIDs[h.ID.String()] = struct{}{} default: - panic(fmt.Sprintf("unknown type %v in blob list", b.Type.String())) + panic(fmt.Sprintf("unknown type %v in blob list", h.Type.String())) } } // Stop searching when all packs have been found diff --git a/internal/repository/debug.go b/internal/repository/debug.go index c6691380c..29cb5b672 100644 --- a/internal/repository/debug.go +++ b/internal/repository/debug.go @@ -49,7 +49,7 @@ func writePackDumpJSON(wr io.Writer, item any) error { func DumpPacks(ctx context.Context, repo *Repository, wr io.Writer, printer progress.Printer) error { var m sync.Mutex return restic.ParallelList(ctx, repo, restic.PackFile, repo.Connections(), func(ctx context.Context, id restic.ID, size int64) error { - blobs, err := repo.ListPack(ctx, id, size) + blobs, err := repo.listPack(ctx, id, size) if err != nil { printer.E("error for pack %v: %v", id.Str(), err) return nil @@ -135,7 +135,7 @@ func ExaminePack(ctx context.Context, repo *Repository, id restic.ID, opts Exami printer.S(" ========================================") printer.S(" inspect the pack itself") - blobs, err := repo.ListPack(ctx, id, int64(len(buf))) + blobs, err := repo.listPack(ctx, id, int64(len(buf))) if err != nil { return fmt.Errorf("pack %v: %v", id.Str(), err) } diff --git a/internal/repository/repack_test.go b/internal/repository/repack_test.go index 13ba63315..7f9b04d92 100644 --- a/internal/repository/repack_test.go +++ b/internal/repository/repack_test.go @@ -86,13 +86,12 @@ func selectBlobs(t *testing.T, random *rand.Rand, repo restic.Repository, p floa blobs := restic.NewBlobSet() err := repo.List(context.TODO(), restic.PackFile, func(id restic.ID, size int64) error { - entries, err := repo.ListPack(context.TODO(), id, size) + handles, err := repo.ListPackHandles(context.TODO(), id, size) if err != nil { t.Fatalf("error listing pack %v: %v", id, err) } - for _, entry := range entries { - h := restic.BlobHandle{ID: entry.ID, Type: entry.Type} + for _, h := range handles { if blobs.Has(h) { t.Errorf("ignoring duplicate blob %v", h) return nil @@ -100,9 +99,9 @@ func selectBlobs(t *testing.T, random *rand.Rand, repo restic.Repository, p floa blobs.Insert(h) if random.Float32() <= p { - list1.Insert(restic.BlobHandle{ID: entry.ID, Type: entry.Type}) + list1.Insert(h) } else { - list2.Insert(restic.BlobHandle{ID: entry.ID, Type: entry.Type}) + list2.Insert(h) } } return nil diff --git a/internal/repository/repair_pack.go b/internal/repository/repair_pack.go index 735653a4c..bff83b846 100644 --- a/internal/repository/repair_pack.go +++ b/internal/repository/repair_pack.go @@ -76,7 +76,7 @@ func resolveBlobsForPacks(ctx context.Context, repo *Repository, ids restic.IDSe err := repo.List(ctx, restic.PackFile, func(id restic.ID, size int64) error { if ids.Has(id) { - blobs, err := repo.ListPack(ctx, id, size) + blobs, err := repo.listPack(ctx, id, size) if err != nil { return nil } diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 7ae36885d..d9d3f10ce 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -781,7 +781,7 @@ func (r *Repository) createIndexFromPacks(ctx context.Context, packsize map[rest // a worker receives an pack ID from ch, reads the pack contents, and adds them to idx worker := func() error { for fi := range ch { - entries, err := r.ListPack(wgCtx, fi.ID, fi.Size) + entries, err := r.listPack(wgCtx, fi.ID, fi.Size) if err != nil { debug.Log("unable to list pack file %v", fi.ID.Str()) m.Lock() @@ -957,8 +957,8 @@ func (r *Repository) List(ctx context.Context, t restic.FileType, fn func(restic }) } -// ListPack returns the list of blobs saved in the pack id. -func (r *Repository) ListPack(ctx context.Context, id restic.ID, size int64) (restic.Blobs, error) { +// listPack returns blob entries from the pack file header including offsets. +func (r *Repository) listPack(ctx context.Context, id restic.ID, size int64) (restic.Blobs, error) { h := backend.Handle{Type: restic.PackFile, Name: id.String()} entries, _, err := pack.List(r.Key(), backend.ReaderAt(ctx, r.be, h), size) @@ -974,6 +974,19 @@ func (r *Repository) ListPack(ctx context.Context, id restic.ID, size int64) (re return entries, err } +// ListPackHandles returns the blob handles stored in the pack file header. +func (r *Repository) ListPackHandles(ctx context.Context, id restic.ID, size int64) ([]restic.BlobHandle, error) { + blobs, err := r.listPack(ctx, id, size) + if err != nil { + return nil, err + } + handles := make([]restic.BlobHandle, len(blobs)) + for i, blob := range blobs { + handles[i] = blob.BlobHandle + } + return handles, nil +} + // Delete calls backend.Delete() if implemented, and returns an error // otherwise. func (r *Repository) Delete(ctx context.Context) error { diff --git a/internal/repository/repository_test.go b/internal/repository/repository_test.go index f7bb516a3..eddc8bd30 100644 --- a/internal/repository/repository_test.go +++ b/internal/repository/repository_test.go @@ -457,11 +457,11 @@ func TestListPack(t *testing.T) { return nil })) - blobs, err := repo.ListPack(context.TODO(), packID, size) + handles, err := repo.ListPackHandles(context.TODO(), packID, size) rtest.OK(t, err) - rtest.Assert(t, len(blobs) == 1 && blobs[0].ID == id, "unexpected blobs in pack: %v", blobs) + rtest.Assert(t, len(handles) == 1 && handles[0].ID == id, "unexpected blobs in pack: %v", handles) - rtest.Assert(t, !c.Has(backend.Handle{Type: restic.PackFile, Name: packID.String()}), "tree pack should no longer be cached as ListPack does not set IsMetadata in the backend.Handle") + rtest.Assert(t, !c.Has(backend.Handle{Type: restic.PackFile, Name: packID.String()}), "tree pack should no longer be cached as listPack does not set IsMetadata in the backend.Handle") } func TestNoDoubleInit(t *testing.T) { diff --git a/internal/restic/repository.go b/internal/restic/repository.go index 09693621d..561755c6c 100644 --- a/internal/restic/repository.go +++ b/internal/restic/repository.go @@ -32,8 +32,8 @@ type Repository interface { // the index iteration returns immediately with ctx.Err(). This blocks any modification of the index. ListBlobs(ctx context.Context, fn func(PackedBlob)) error ListPacksFromIndex(ctx context.Context, packs IDSet) <-chan PackBlobs - // ListPack returns the list of blobs saved in the pack id. - ListPack(ctx context.Context, id ID, packSize int64) (entries Blobs, err error) + // ListPackHandles returns the blob handles stored in the pack file header. + ListPackHandles(ctx context.Context, id ID, packSize int64) ([]BlobHandle, error) LoadBlob(ctx context.Context, t BlobType, id ID, buf []byte) ([]byte, error) LoadBlobsFromPack(ctx context.Context, packID ID, blobs []BlobHandle, handleBlobFn func(blob BlobHandle, buf []byte, err error) error) error