diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index 2ea2a4ec5..635179417 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -411,7 +411,7 @@ func collectTargets(opts BackupOptions, args []string) (targets []string, err er // parent returns the ID of the parent snapshot. If there is none, nil is // returned. -func findParentSnapshot(ctx context.Context, repo restic.Repository, opts BackupOptions, targets []string, timeStampLimit time.Time) (*restic.Snapshot, error) { +func findParentSnapshot(ctx context.Context, repo restic.ListerLoaderUnpacked, opts BackupOptions, targets []string, timeStampLimit time.Time) (*restic.Snapshot, error) { if opts.Force { return nil, nil } diff --git a/cmd/restic/cmd_debug.go b/cmd/restic/cmd_debug.go index 49efb904b..a87e7a0c5 100644 --- a/cmd/restic/cmd_debug.go +++ b/cmd/restic/cmd_debug.go @@ -137,7 +137,7 @@ func printPacks(ctx context.Context, repo *repository.Repository, wr io.Writer) }) } -func dumpIndexes(ctx context.Context, repo restic.Repository, wr io.Writer) error { +func dumpIndexes(ctx context.Context, repo restic.ListerLoaderUnpacked, wr io.Writer) error { return index.ForAllIndexes(ctx, repo, repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error { Printf("index_id: %v\n", id) if err != nil { diff --git a/cmd/restic/cmd_diff.go b/cmd/restic/cmd_diff.go index 7878613e1..06f2be2ae 100644 --- a/cmd/restic/cmd_diff.go +++ b/cmd/restic/cmd_diff.go @@ -61,7 +61,7 @@ func init() { f.BoolVar(&diffOptions.ShowMetadata, "metadata", false, "print changes in metadata") } -func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.Repository, desc string) (*restic.Snapshot, string, error) { +func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.LoaderUnpacked, desc string) (*restic.Snapshot, string, error) { sn, subfolder, err := restic.FindSnapshot(ctx, be, repo, desc) if err != nil { return nil, "", errors.Fatal(err.Error()) @@ -71,7 +71,7 @@ func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.Repository, // Comparer collects all things needed to compare two snapshots. type Comparer struct { - repo restic.Repository + repo restic.BlobLoader opts DiffOptions printChange func(change *Change) } @@ -147,7 +147,7 @@ type DiffStatsContainer struct { } // updateBlobs updates the blob counters in the stats struct. -func updateBlobs(repo restic.Repository, blobs restic.BlobSet, stats *DiffStat) { +func updateBlobs(repo restic.Loader, blobs restic.BlobSet, stats *DiffStat) { for h := range blobs { switch h.Type { case restic.DataBlob: diff --git a/cmd/restic/cmd_dump.go b/cmd/restic/cmd_dump.go index e6020d847..e72b51fa2 100644 --- a/cmd/restic/cmd_dump.go +++ b/cmd/restic/cmd_dump.go @@ -67,7 +67,7 @@ func splitPath(p string) []string { return append(s, f) } -func printFromTree(ctx context.Context, tree *restic.Tree, repo restic.Repository, prefix string, pathComponents []string, d *dump.Dumper) error { +func printFromTree(ctx context.Context, tree *restic.Tree, repo restic.BlobLoader, prefix string, pathComponents []string, d *dump.Dumper) error { // If we print / we need to assume that there are multiple nodes at that // level in the tree. if pathComponents[0] == "" { diff --git a/cmd/restic/cmd_recover.go b/cmd/restic/cmd_recover.go index ae6aff740..499abdf80 100644 --- a/cmd/restic/cmd_recover.go +++ b/cmd/restic/cmd_recover.go @@ -158,7 +158,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions) error { } -func createSnapshot(ctx context.Context, name, hostname string, tags []string, repo restic.Repository, tree *restic.ID) error { +func createSnapshot(ctx context.Context, name, hostname string, tags []string, repo restic.SaverUnpacked, tree *restic.ID) error { sn, err := restic.NewSnapshot([]string{name}, tags, hostname, time.Now()) if err != nil { return errors.Fatalf("unable to save snapshot: %v", err) diff --git a/cmd/restic/cmd_stats.go b/cmd/restic/cmd_stats.go index b0837510d..87c3f8d22 100644 --- a/cmd/restic/cmd_stats.go +++ b/cmd/restic/cmd_stats.go @@ -189,7 +189,7 @@ func runStats(ctx context.Context, opts StatsOptions, gopts GlobalOptions, args return nil } -func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo restic.Repository, opts StatsOptions, stats *statsContainer) error { +func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo restic.Loader, opts StatsOptions, stats *statsContainer) error { if snapshot.Tree == nil { return fmt.Errorf("snapshot %s has nil tree", snapshot.ID().Str()) } @@ -211,7 +211,7 @@ func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo rest return nil } -func statsWalkTree(repo restic.Repository, opts StatsOptions, stats *statsContainer, hardLinkIndex *restorer.HardlinkIndex[struct{}]) walker.WalkFunc { +func statsWalkTree(repo restic.Loader, opts StatsOptions, stats *statsContainer, hardLinkIndex *restorer.HardlinkIndex[struct{}]) walker.WalkFunc { return func(parentTreeID restic.ID, npath string, node *restic.Node, nodeErr error) error { if nodeErr != nil { return nodeErr @@ -363,7 +363,7 @@ func statsDebug(ctx context.Context, repo restic.Repository) error { return nil } -func statsDebugFileType(ctx context.Context, repo restic.Repository, tpe restic.FileType) (*sizeHistogram, error) { +func statsDebugFileType(ctx context.Context, repo restic.Lister, tpe restic.FileType) (*sizeHistogram, error) { hist := newSizeHistogram(2 * repository.MaxPackSize) err := repo.List(ctx, tpe, func(id restic.ID, size int64) error { hist.Add(uint64(size)) diff --git a/internal/archiver/testing.go b/internal/archiver/testing.go index c7482d160..111c1e68c 100644 --- a/internal/archiver/testing.go +++ b/internal/archiver/testing.go @@ -209,7 +209,7 @@ func TestEnsureFiles(t testing.TB, target string, dir TestDir) { } // TestEnsureFileContent checks if the file in the repo is the same as file. -func TestEnsureFileContent(ctx context.Context, t testing.TB, repo restic.Repository, filename string, node *restic.Node, file TestFile) { +func TestEnsureFileContent(ctx context.Context, t testing.TB, repo restic.BlobLoader, filename string, node *restic.Node, file TestFile) { if int(node.Size) != len(file.Content) { t.Fatalf("%v: wrong node size: want %d, got %d", filename, node.Size, len(file.Content)) return @@ -237,7 +237,7 @@ func TestEnsureFileContent(ctx context.Context, t testing.TB, repo restic.Reposi // TestEnsureTree checks that the tree ID in the repo matches dir. On Windows, // Symlinks are ignored. -func TestEnsureTree(ctx context.Context, t testing.TB, prefix string, repo restic.Repository, treeID restic.ID, dir TestDir) { +func TestEnsureTree(ctx context.Context, t testing.TB, prefix string, repo restic.BlobLoader, treeID restic.ID, dir TestDir) { t.Helper() tree, err := restic.LoadTree(ctx, repo, treeID) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index e6a7a9035..5d324795d 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -362,7 +362,7 @@ func (c *Checker) checkTreeWorker(ctx context.Context, trees <-chan restic.TreeI } } -func loadSnapshotTreeIDs(ctx context.Context, lister restic.Lister, repo restic.Repository) (ids restic.IDs, errs []error) { +func loadSnapshotTreeIDs(ctx context.Context, lister restic.Lister, repo restic.LoaderUnpacked) (ids restic.IDs, errs []error) { err := restic.ForAllSnapshots(ctx, lister, repo, nil, func(id restic.ID, sn *restic.Snapshot, err error) error { if err != nil { errs = append(errs, err) diff --git a/internal/dump/common.go b/internal/dump/common.go index 3ca1ced82..7a8d95ae9 100644 --- a/internal/dump/common.go +++ b/internal/dump/common.go @@ -16,11 +16,11 @@ import ( type Dumper struct { cache *bloblru.Cache format string - repo restic.Repository + repo restic.BlobLoader w io.Writer } -func New(format string, repo restic.Repository, w io.Writer) *Dumper { +func New(format string, repo restic.BlobLoader, w io.Writer) *Dumper { return &Dumper{ cache: bloblru.New(64 << 20), format: format, @@ -47,7 +47,7 @@ func (d *Dumper) DumpTree(ctx context.Context, tree *restic.Tree, rootPath strin } } -func sendTrees(ctx context.Context, repo restic.Repository, tree *restic.Tree, rootPath string, ch chan *restic.Node) { +func sendTrees(ctx context.Context, repo restic.BlobLoader, tree *restic.Tree, rootPath string, ch chan *restic.Node) { defer close(ch) for _, root := range tree.Nodes { @@ -58,7 +58,7 @@ func sendTrees(ctx context.Context, repo restic.Repository, tree *restic.Tree, r } } -func sendNodes(ctx context.Context, repo restic.Repository, root *restic.Node, ch chan *restic.Node) error { +func sendNodes(ctx context.Context, repo restic.BlobLoader, root *restic.Node, ch chan *restic.Node) error { select { case ch <- root: case <-ctx.Done(): diff --git a/internal/fuse/dir.go b/internal/fuse/dir.go index c5aaf6f52..763a9640c 100644 --- a/internal/fuse/dir.go +++ b/internal/fuse/dir.go @@ -58,7 +58,7 @@ func unwrapCtxCanceled(err error) error { // replaceSpecialNodes replaces nodes with name "." and "/" by their contents. // Otherwise, the node is returned. -func replaceSpecialNodes(ctx context.Context, repo restic.Repository, node *restic.Node) ([]*restic.Node, error) { +func replaceSpecialNodes(ctx context.Context, repo restic.BlobLoader, node *restic.Node) ([]*restic.Node, error) { if node.Type != "dir" || node.Subtree == nil { return []*restic.Node{node}, nil } diff --git a/internal/fuse/fuse_test.go b/internal/fuse/fuse_test.go index 0a121b986..1053d49a4 100644 --- a/internal/fuse/fuse_test.go +++ b/internal/fuse/fuse_test.go @@ -37,7 +37,7 @@ func testRead(t testing.TB, f fs.Handle, offset, length int, data []byte) { rtest.OK(t, fr.Read(ctx, req, resp)) } -func firstSnapshotID(t testing.TB, repo restic.Repository) (first restic.ID) { +func firstSnapshotID(t testing.TB, repo restic.Lister) (first restic.ID) { err := repo.List(context.TODO(), restic.SnapshotFile, func(id restic.ID, size int64) error { if first.IsNull() { first = id @@ -52,14 +52,14 @@ func firstSnapshotID(t testing.TB, repo restic.Repository) (first restic.ID) { return first } -func loadFirstSnapshot(t testing.TB, repo restic.Repository) *restic.Snapshot { +func loadFirstSnapshot(t testing.TB, repo restic.ListerLoaderUnpacked) *restic.Snapshot { id := firstSnapshotID(t, repo) sn, err := restic.LoadSnapshot(context.TODO(), repo, id) rtest.OK(t, err) return sn } -func loadTree(t testing.TB, repo restic.Repository, id restic.ID) *restic.Tree { +func loadTree(t testing.TB, repo restic.Loader, id restic.ID) *restic.Tree { tree, err := restic.LoadTree(context.TODO(), repo, id) rtest.OK(t, err) return tree diff --git a/internal/index/index_parallel.go b/internal/index/index_parallel.go index d505d756e..3c16d049b 100644 --- a/internal/index/index_parallel.go +++ b/internal/index/index_parallel.go @@ -11,7 +11,7 @@ import ( // ForAllIndexes loads all index files in parallel and calls the given callback. // It is guaranteed that the function is not run concurrently. If the callback // returns an error, this function is cancelled and also returns that error. -func ForAllIndexes(ctx context.Context, lister restic.Lister, repo restic.Repository, +func ForAllIndexes(ctx context.Context, lister restic.Lister, repo restic.ListerLoaderUnpacked, fn func(id restic.ID, index *Index, oldFormat bool, err error) error) error { // decoding an index can take quite some time such that this can be both CPU- or IO-bound diff --git a/internal/repository/repack_test.go b/internal/repository/repack_test.go index 3de077a7d..63845d5b1 100644 --- a/internal/repository/repack_test.go +++ b/internal/repository/repack_test.go @@ -120,7 +120,7 @@ func selectBlobs(t *testing.T, repo restic.Repository, p float32) (list1, list2 return list1, list2 } -func listPacks(t *testing.T, repo restic.Repository) restic.IDSet { +func listPacks(t *testing.T, repo restic.Lister) restic.IDSet { list := restic.NewIDSet() err := repo.List(context.TODO(), restic.PackFile, func(id restic.ID, size int64) error { list.Insert(id) diff --git a/internal/repository/repository_test.go b/internal/repository/repository_test.go index 886486136..0fa8e4d4a 100644 --- a/internal/repository/repository_test.go +++ b/internal/repository/repository_test.go @@ -229,7 +229,7 @@ func TestRepositoryLoadIndex(t *testing.T) { } // loadIndex loads the index id from backend and returns it. -func loadIndex(ctx context.Context, repo restic.Repository, id restic.ID) (*index.Index, error) { +func loadIndex(ctx context.Context, repo restic.LoaderUnpacked, id restic.ID) (*index.Index, error) { buf, err := repo.LoadUnpacked(ctx, restic.IndexFile, id) if err != nil { return nil, err diff --git a/internal/restic/lock.go b/internal/restic/lock.go index 2d7e04f87..8c1001b48 100644 --- a/internal/restic/lock.go +++ b/internal/restic/lock.go @@ -379,7 +379,7 @@ func init() { } // LoadLock loads and unserializes a lock from a repository. -func LoadLock(ctx context.Context, repo Repository, id ID) (*Lock, error) { +func LoadLock(ctx context.Context, repo LoaderUnpacked, id ID) (*Lock, error) { lock := &Lock{} if err := LoadJSONUnpacked(ctx, repo, LockFile, id, lock); err != nil { return nil, err @@ -429,7 +429,7 @@ func RemoveAllLocks(ctx context.Context, repo Repository) (uint, error) { // It is guaranteed that the function is not run concurrently. If the // callback returns an error, this function is cancelled and also returns that error. // If a lock ID is passed via excludeID, it will be ignored. -func ForAllLocks(ctx context.Context, repo Repository, excludeIDs IDSet, fn func(ID, *Lock, error) error) error { +func ForAllLocks(ctx context.Context, repo ListerLoaderUnpacked, excludeIDs IDSet, fn func(ID, *Lock, error) error) error { var m sync.Mutex // For locks decoding is nearly for free, thus just assume were only limited by IO diff --git a/internal/restic/lock_test.go b/internal/restic/lock_test.go index faf3f3593..13b66a432 100644 --- a/internal/restic/lock_test.go +++ b/internal/restic/lock_test.go @@ -120,7 +120,7 @@ func TestExclusiveLockOnLockedRepo(t *testing.T) { rtest.OK(t, elock.Unlock()) } -func createFakeLock(repo restic.Repository, t time.Time, pid int) (restic.ID, error) { +func createFakeLock(repo restic.SaverUnpacked, t time.Time, pid int) (restic.ID, error) { hostname, err := os.Hostname() if err != nil { return restic.ID{}, err @@ -254,7 +254,7 @@ func TestRemoveAllLocks(t *testing.T) { 3, processed) } -func checkSingleLock(t *testing.T, repo restic.Repository) restic.ID { +func checkSingleLock(t *testing.T, repo restic.Lister) restic.ID { t.Helper() var lockID *restic.ID err := repo.List(context.TODO(), restic.LockFile, func(id restic.ID, size int64) error { diff --git a/internal/restic/node.go b/internal/restic/node.go index 7edc41ce8..1d5bb51af 100644 --- a/internal/restic/node.go +++ b/internal/restic/node.go @@ -142,7 +142,7 @@ func (node Node) GetExtendedAttribute(a string) []byte { } // CreateAt creates the node at the given path but does NOT restore node meta data. -func (node *Node) CreateAt(ctx context.Context, path string, repo Repository) error { +func (node *Node) CreateAt(ctx context.Context, path string, repo BlobLoader) error { debug.Log("create node %v at %v", node.Name, path) switch node.Type { @@ -264,7 +264,7 @@ func (node Node) createDirAt(path string) error { return nil } -func (node Node) createFileAt(ctx context.Context, path string, repo Repository) error { +func (node Node) createFileAt(ctx context.Context, path string, repo BlobLoader) error { f, err := fs.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) if err != nil { return errors.WithStack(err) @@ -284,7 +284,7 @@ func (node Node) createFileAt(ctx context.Context, path string, repo Repository) return nil } -func (node Node) writeNodeContent(ctx context.Context, repo Repository, f *os.File) error { +func (node Node) writeNodeContent(ctx context.Context, repo BlobLoader, f *os.File) error { var buf []byte for _, id := range node.Content { buf, err := repo.LoadBlob(ctx, DataBlob, id, buf) diff --git a/internal/restic/repository.go b/internal/restic/repository.go index 1c6c8d39d..66cc22ea9 100644 --- a/internal/restic/repository.go +++ b/internal/restic/repository.go @@ -113,3 +113,8 @@ type MasterIndex interface { type Lister interface { List(ctx context.Context, t FileType, fn func(ID, int64) error) error } + +type ListerLoaderUnpacked interface { + Lister + LoaderUnpacked +} diff --git a/internal/restorer/restorer_test.go b/internal/restorer/restorer_test.go index d0e7dad6f..c33214bc3 100644 --- a/internal/restorer/restorer_test.go +++ b/internal/restorer/restorer_test.go @@ -40,7 +40,7 @@ type Dir struct { ModTime time.Time } -func saveFile(t testing.TB, repo restic.Repository, node File) restic.ID { +func saveFile(t testing.TB, repo restic.BlobSaver, node File) restic.ID { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -52,7 +52,7 @@ func saveFile(t testing.TB, repo restic.Repository, node File) restic.ID { return id } -func saveDir(t testing.TB, repo restic.Repository, nodes map[string]Node, inode uint64) restic.ID { +func saveDir(t testing.TB, repo restic.BlobSaver, nodes map[string]Node, inode uint64) restic.ID { ctx, cancel := context.WithCancel(context.Background()) defer cancel()