diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index e42ba81d9..a43c5a17a 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -394,7 +394,7 @@ func collectTargets(opts BackupOptions, args []string) (targets []string, err er func findParentSnapshot(ctx context.Context, repo restic.Repository, opts BackupOptions, targets []string) (parentID *restic.ID, err error) { // Force using a parent if !opts.Force && opts.Parent != "" { - id, err := restic.FindSnapshot(repo, opts.Parent) + id, err := restic.FindSnapshot(ctx, repo, opts.Parent) if err != nil { return nil, errors.Fatalf("invalid id %q: %v", opts.Parent, err) } @@ -496,7 +496,7 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina if !gopts.JSON { p.V("lock repository") } - lock, err := lockRepo(repo) + lock, err := lockRepo(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_cat.go b/cmd/restic/cmd_cat.go index 935a03dbc..ff240572f 100644 --- a/cmd/restic/cmd_cat.go +++ b/cmd/restic/cmd_cat.go @@ -42,7 +42,7 @@ func runCat(gopts GlobalOptions, args []string) error { return err } - lock, err := lockRepo(repo) + lock, err := lockRepo(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err @@ -59,7 +59,7 @@ func runCat(gopts GlobalOptions, args []string) error { } // find snapshot id with prefix - id, err = restic.FindSnapshot(repo, args[1]) + id, err = restic.FindSnapshot(gopts.ctx, repo, args[1]) if err != nil { return errors.Fatalf("could not find snapshot: %v\n", err) } diff --git a/cmd/restic/cmd_check.go b/cmd/restic/cmd_check.go index 3c638ff5a..a4553b3c9 100644 --- a/cmd/restic/cmd_check.go +++ b/cmd/restic/cmd_check.go @@ -158,7 +158,7 @@ func runCheck(opts CheckOptions, gopts GlobalOptions, args []string) error { if !gopts.NoLock { Verbosef("create exclusive lock for repository\n") - lock, err := lockRepoExclusive(repo) + lock, err := lockRepoExclusive(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_copy.go b/cmd/restic/cmd_copy.go index 788c9a7e8..7c37b61e0 100644 --- a/cmd/restic/cmd_copy.go +++ b/cmd/restic/cmd_copy.go @@ -65,13 +65,13 @@ func runCopy(opts CopyOptions, gopts GlobalOptions, args []string) error { return err } - srcLock, err := lockRepo(srcRepo) + srcLock, err := lockRepo(ctx, srcRepo) defer unlockRepo(srcLock) if err != nil { return err } - dstLock, err := lockRepo(dstRepo) + dstLock, err := lockRepo(ctx, dstRepo) defer unlockRepo(dstLock) if err != nil { return err diff --git a/cmd/restic/cmd_debug.go b/cmd/restic/cmd_debug.go index abae130db..b36eefa07 100644 --- a/cmd/restic/cmd_debug.go +++ b/cmd/restic/cmd_debug.go @@ -54,9 +54,9 @@ func prettyPrintJSON(wr io.Writer, item interface{}) error { return err } -func debugPrintSnapshots(repo *repository.Repository, wr io.Writer) error { - return repo.List(context.TODO(), restic.SnapshotFile, func(id restic.ID, size int64) error { - snapshot, err := restic.LoadSnapshot(context.TODO(), repo, id) +func debugPrintSnapshots(ctx context.Context, repo *repository.Repository, wr io.Writer) error { + return repo.List(ctx, restic.SnapshotFile, func(id restic.ID, size int64) error { + snapshot, err := restic.LoadSnapshot(ctx, repo, id) if err != nil { return err } @@ -82,12 +82,12 @@ type Blob struct { Offset uint `json:"offset"` } -func printPacks(repo *repository.Repository, wr io.Writer) error { +func printPacks(ctx context.Context, repo *repository.Repository, wr io.Writer) error { - return repo.List(context.TODO(), restic.PackFile, func(id restic.ID, size int64) error { + return repo.List(ctx, restic.PackFile, func(id restic.ID, size int64) error { h := restic.Handle{Type: restic.PackFile, Name: id.String()} - blobs, err := pack.List(repo.Key(), restic.ReaderAt(repo.Backend(), h), size) + blobs, err := pack.List(repo.Key(), restic.ReaderAt(ctx, repo.Backend(), h), size) if err != nil { Warnf("error for pack %v: %v\n", id.Str(), err) return nil @@ -110,11 +110,11 @@ func printPacks(repo *repository.Repository, wr io.Writer) error { }) } -func dumpIndexes(repo restic.Repository, wr io.Writer) error { - return repo.List(context.TODO(), restic.IndexFile, func(id restic.ID, size int64) error { +func dumpIndexes(ctx context.Context, repo restic.Repository, wr io.Writer) error { + return repo.List(ctx, restic.IndexFile, func(id restic.ID, size int64) error { Printf("index_id: %v\n", id) - idx, err := repository.LoadIndex(context.TODO(), repo, id) + idx, err := repository.LoadIndex(ctx, repo, id) if err != nil { return err } @@ -134,7 +134,7 @@ func runDebugDump(gopts GlobalOptions, args []string) error { } if !gopts.NoLock { - lock, err := lockRepo(repo) + lock, err := lockRepo(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err @@ -145,20 +145,20 @@ func runDebugDump(gopts GlobalOptions, args []string) error { switch tpe { case "indexes": - return dumpIndexes(repo, gopts.stdout) + return dumpIndexes(gopts.ctx, repo, gopts.stdout) case "snapshots": - return debugPrintSnapshots(repo, gopts.stdout) + return debugPrintSnapshots(gopts.ctx, repo, gopts.stdout) case "packs": - return printPacks(repo, gopts.stdout) + return printPacks(gopts.ctx, repo, gopts.stdout) case "all": Printf("snapshots:\n") - err := debugPrintSnapshots(repo, gopts.stdout) + err := debugPrintSnapshots(gopts.ctx, repo, gopts.stdout) if err != nil { return err } Printf("\nindexes:\n") - err = dumpIndexes(repo, gopts.stdout) + err = dumpIndexes(gopts.ctx, repo, gopts.stdout) if err != nil { return err } diff --git a/cmd/restic/cmd_diff.go b/cmd/restic/cmd_diff.go index 1fc8b0458..f1b099ede 100644 --- a/cmd/restic/cmd_diff.go +++ b/cmd/restic/cmd_diff.go @@ -53,7 +53,7 @@ func init() { } func loadSnapshot(ctx context.Context, repo *repository.Repository, desc string) (*restic.Snapshot, error) { - id, err := restic.FindSnapshot(repo, desc) + id, err := restic.FindSnapshot(ctx, repo, desc) if err != nil { return nil, err } @@ -332,7 +332,7 @@ func runDiff(opts DiffOptions, gopts GlobalOptions, args []string) error { } if !gopts.NoLock { - lock, err := lockRepo(repo) + lock, err := lockRepo(ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_dump.go b/cmd/restic/cmd_dump.go index 4a9e57a37..d3ca87923 100644 --- a/cmd/restic/cmd_dump.go +++ b/cmd/restic/cmd_dump.go @@ -140,7 +140,7 @@ func runDump(opts DumpOptions, gopts GlobalOptions, args []string) error { } if !gopts.NoLock { - lock, err := lockRepo(repo) + lock, err := lockRepo(ctx, repo) defer unlockRepo(lock) if err != nil { return err @@ -160,7 +160,7 @@ func runDump(opts DumpOptions, gopts GlobalOptions, args []string) error { Exitf(1, "latest snapshot for criteria not found: %v Paths:%v Hosts:%v", err, opts.Paths, opts.Hosts) } } else { - id, err = restic.FindSnapshot(repo, snapshotIDString) + id, err = restic.FindSnapshot(ctx, repo, snapshotIDString) if err != nil { Exitf(1, "invalid id %q: %v", snapshotIDString, err) } diff --git a/cmd/restic/cmd_find.go b/cmd/restic/cmd_find.go index 84a709b15..c57207c1f 100644 --- a/cmd/restic/cmd_find.go +++ b/cmd/restic/cmd_find.go @@ -529,7 +529,7 @@ func runFind(opts FindOptions, gopts GlobalOptions, args []string) error { } if !gopts.NoLock { - lock, err := lockRepo(repo) + lock, err := lockRepo(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_forget.go b/cmd/restic/cmd_forget.go index d2cc85075..3edaa76e9 100644 --- a/cmd/restic/cmd_forget.go +++ b/cmd/restic/cmd_forget.go @@ -88,7 +88,7 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error { return err } - lock, err := lockRepoExclusive(repo) + lock, err := lockRepoExclusive(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_key.go b/cmd/restic/cmd_key.go index d14ba400e..bbd4f0f90 100644 --- a/cmd/restic/cmd_key.go +++ b/cmd/restic/cmd_key.go @@ -188,7 +188,7 @@ func runKey(gopts GlobalOptions, args []string) error { switch args[0] { case "list": - lock, err := lockRepo(repo) + lock, err := lockRepo(ctx, repo) defer unlockRepo(lock) if err != nil { return err @@ -196,7 +196,7 @@ func runKey(gopts GlobalOptions, args []string) error { return listKeys(ctx, repo, gopts) case "add": - lock, err := lockRepo(repo) + lock, err := lockRepo(ctx, repo) defer unlockRepo(lock) if err != nil { return err @@ -204,20 +204,20 @@ func runKey(gopts GlobalOptions, args []string) error { return addKey(gopts, repo) case "remove": - lock, err := lockRepoExclusive(repo) + lock, err := lockRepoExclusive(ctx, repo) defer unlockRepo(lock) if err != nil { return err } - id, err := restic.Find(repo.Backend(), restic.KeyFile, args[1]) + id, err := restic.Find(ctx, repo.Backend(), restic.KeyFile, args[1]) if err != nil { return err } return deleteKey(gopts.ctx, repo, id) case "passwd": - lock, err := lockRepoExclusive(repo) + lock, err := lockRepoExclusive(ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_list.go b/cmd/restic/cmd_list.go index 3cde6714d..50b55e857 100644 --- a/cmd/restic/cmd_list.go +++ b/cmd/restic/cmd_list.go @@ -40,7 +40,7 @@ func runList(cmd *cobra.Command, opts GlobalOptions, args []string) error { } if !opts.NoLock { - lock, err := lockRepo(repo) + lock, err := lockRepo(opts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_migrate.go b/cmd/restic/cmd_migrate.go index 887641957..4af98005e 100644 --- a/cmd/restic/cmd_migrate.go +++ b/cmd/restic/cmd_migrate.go @@ -99,7 +99,7 @@ func runMigrate(opts MigrateOptions, gopts GlobalOptions, args []string) error { return err } - lock, err := lockRepoExclusive(repo) + lock, err := lockRepoExclusive(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_mount.go b/cmd/restic/cmd_mount.go index 626915dfe..820f68949 100644 --- a/cmd/restic/cmd_mount.go +++ b/cmd/restic/cmd_mount.go @@ -91,7 +91,7 @@ func mount(opts MountOptions, gopts GlobalOptions, mountpoint string) error { } if !gopts.NoLock { - lock, err := lockRepo(repo) + lock, err := lockRepo(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_prune.go b/cmd/restic/cmd_prune.go index 2a386793c..1bb1a51e5 100644 --- a/cmd/restic/cmd_prune.go +++ b/cmd/restic/cmd_prune.go @@ -50,7 +50,7 @@ func runPrune(gopts GlobalOptions) error { return err } - lock, err := lockRepoExclusive(repo) + lock, err := lockRepoExclusive(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_rebuild_index.go b/cmd/restic/cmd_rebuild_index.go index b5f23aad7..87b78b4b4 100644 --- a/cmd/restic/cmd_rebuild_index.go +++ b/cmd/restic/cmd_rebuild_index.go @@ -38,7 +38,7 @@ func runRebuildIndex(gopts GlobalOptions) error { return err } - lock, err := lockRepoExclusive(repo) + lock, err := lockRepoExclusive(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_recover.go b/cmd/restic/cmd_recover.go index 9eca92115..8f11b6860 100644 --- a/cmd/restic/cmd_recover.go +++ b/cmd/restic/cmd_recover.go @@ -43,7 +43,7 @@ func runRecover(gopts GlobalOptions) error { return err } - lock, err := lockRepo(repo) + lock, err := lockRepo(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_restore.go b/cmd/restic/cmd_restore.go index e87bafbba..618dfadf8 100644 --- a/cmd/restic/cmd_restore.go +++ b/cmd/restic/cmd_restore.go @@ -102,7 +102,7 @@ func runRestore(opts RestoreOptions, gopts GlobalOptions, args []string) error { } if !gopts.NoLock { - lock, err := lockRepo(repo) + lock, err := lockRepo(ctx, repo) defer unlockRepo(lock) if err != nil { return err @@ -122,13 +122,13 @@ func runRestore(opts RestoreOptions, gopts GlobalOptions, args []string) error { Exitf(1, "latest snapshot for criteria not found: %v Paths:%v Hosts:%v", err, opts.Paths, opts.Hosts) } } else { - id, err = restic.FindSnapshot(repo, snapshotIDString) + id, err = restic.FindSnapshot(ctx, repo, snapshotIDString) if err != nil { Exitf(1, "invalid id %q: %v", snapshotIDString, err) } } - res, err := restorer.NewRestorer(repo, id) + res, err := restorer.NewRestorer(ctx, repo, id) if err != nil { Exitf(2, "creating restorer failed: %v\n", err) } diff --git a/cmd/restic/cmd_snapshots.go b/cmd/restic/cmd_snapshots.go index cc58479c2..8bc5d5984 100644 --- a/cmd/restic/cmd_snapshots.go +++ b/cmd/restic/cmd_snapshots.go @@ -61,7 +61,7 @@ func runSnapshots(opts SnapshotOptions, gopts GlobalOptions, args []string) erro } if !gopts.NoLock { - lock, err := lockRepo(repo) + lock, err := lockRepo(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_stats.go b/cmd/restic/cmd_stats.go index f26d5a6cc..81ec66843 100644 --- a/cmd/restic/cmd_stats.go +++ b/cmd/restic/cmd_stats.go @@ -91,7 +91,7 @@ func runStats(gopts GlobalOptions, args []string) error { } if !gopts.NoLock { - lock, err := lockRepo(repo) + lock, err := lockRepo(ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/cmd_tag.go b/cmd/restic/cmd_tag.go index 4479f6894..4e1ac46c3 100644 --- a/cmd/restic/cmd_tag.go +++ b/cmd/restic/cmd_tag.go @@ -119,7 +119,7 @@ func runTag(opts TagOptions, gopts GlobalOptions, args []string) error { if !gopts.NoLock { Verbosef("create exclusive lock for repository\n") - lock, err := lockRepoExclusive(repo) + lock, err := lockRepoExclusive(gopts.ctx, repo) defer unlockRepo(lock) if err != nil { return err diff --git a/cmd/restic/find.go b/cmd/restic/find.go index 8d39e177f..70710e2cb 100644 --- a/cmd/restic/find.go +++ b/cmd/restic/find.go @@ -29,7 +29,7 @@ func FindFilteredSnapshots(ctx context.Context, repo *repository.Repository, hos continue } } else { - id, err = restic.FindSnapshot(repo, s) + id, err = restic.FindSnapshot(ctx, repo, s) if err != nil { Warnf("Ignoring %q, it is not a snapshot id\n", s) continue diff --git a/cmd/restic/global.go b/cmd/restic/global.go index bf2efde70..8cae12907 100644 --- a/cmd/restic/global.go +++ b/cmd/restic/global.go @@ -768,9 +768,9 @@ func create(s string, opts options.Options) (restic.Backend, error) { case "b2": return b2.Create(globalOptions.ctx, cfg.(b2.Config), rt) case "rest": - return rest.Create(cfg.(rest.Config), rt) + return rest.Create(globalOptions.ctx, cfg.(rest.Config), rt) case "rclone": - return rclone.Create(cfg.(rclone.Config)) + return rclone.Create(globalOptions.ctx, cfg.(rclone.Config)) } debug.Log("invalid repository scheme: %v", s) diff --git a/cmd/restic/integration_fuse_test.go b/cmd/restic/integration_fuse_test.go index 57a57ae97..3ddf33907 100644 --- a/cmd/restic/integration_fuse_test.go +++ b/cmd/restic/integration_fuse_test.go @@ -6,7 +6,6 @@ package main import ( - "context" "fmt" "os" "path/filepath" @@ -122,7 +121,7 @@ func checkSnapshots(t testing.TB, global GlobalOptions, repo *repository.Reposit } for _, id := range snapshotIDs { - snapshot, err := restic.LoadSnapshot(context.TODO(), repo, id) + snapshot, err := restic.LoadSnapshot(global.ctx, repo, id) rtest.OK(t, err) ts := snapshot.Time.Format(time.RFC3339) diff --git a/cmd/restic/lock.go b/cmd/restic/lock.go index 2b4ac94d5..b0df2b685 100644 --- a/cmd/restic/lock.go +++ b/cmd/restic/lock.go @@ -18,21 +18,21 @@ var globalLocks struct { sync.Mutex } -func lockRepo(repo *repository.Repository) (*restic.Lock, error) { - return lockRepository(repo, false) +func lockRepo(ctx context.Context, repo *repository.Repository) (*restic.Lock, error) { + return lockRepository(ctx, repo, false) } -func lockRepoExclusive(repo *repository.Repository) (*restic.Lock, error) { - return lockRepository(repo, true) +func lockRepoExclusive(ctx context.Context, repo *repository.Repository) (*restic.Lock, error) { + return lockRepository(ctx, repo, true) } -func lockRepository(repo *repository.Repository, exclusive bool) (*restic.Lock, error) { +func lockRepository(ctx context.Context, repo *repository.Repository, exclusive bool) (*restic.Lock, error) { lockFn := restic.NewLock if exclusive { lockFn = restic.NewExclusiveLock } - lock, err := lockFn(context.TODO(), repo) + lock, err := lockFn(ctx, repo) if err != nil { return nil, errors.WithMessage(err, "unable to create lock in backend") } @@ -86,6 +86,10 @@ func refreshLocks(wg *sync.WaitGroup, done <-chan struct{}) { } func unlockRepo(lock *restic.Lock) error { + if lock == nil { + return nil + } + globalLocks.Lock() defer globalLocks.Unlock() diff --git a/internal/backend/rclone/backend.go b/internal/backend/rclone/backend.go index e18d8a998..2f730f238 100644 --- a/internal/backend/rclone/backend.go +++ b/internal/backend/rclone/backend.go @@ -275,8 +275,8 @@ func Open(cfg Config, lim limiter.Limiter) (*Backend, error) { return be, nil } -// Create initializes a new restic repo with clone. -func Create(cfg Config) (*Backend, error) { +// Create initializes a new restic repo with rclone. +func Create(ctx context.Context, cfg Config) (*Backend, error) { be, err := newBackend(cfg, nil) if err != nil { return nil, err @@ -294,7 +294,7 @@ func Create(cfg Config) (*Backend, error) { URL: url, } - restBackend, err := rest.Create(restConfig, debug.RoundTripper(be.tr)) + restBackend, err := rest.Create(ctx, restConfig, debug.RoundTripper(be.tr)) if err != nil { _ = be.Close() return nil, err diff --git a/internal/backend/rclone/backend_test.go b/internal/backend/rclone/backend_test.go index b7f3cebb4..0a8f91aea 100644 --- a/internal/backend/rclone/backend_test.go +++ b/internal/backend/rclone/backend_test.go @@ -1,6 +1,7 @@ package rclone_test import ( + "context" "os/exec" "testing" @@ -27,7 +28,7 @@ func newTestSuite(t testing.TB) *test.Suite { Create: func(config interface{}) (restic.Backend, error) { t.Logf("Create()") cfg := config.(rclone.Config) - be, err := rclone.Create(cfg) + be, err := rclone.Create(context.TODO(), cfg) if e, ok := errors.Cause(err).(*exec.Error); ok && e.Err == exec.ErrNotFound { t.Skipf("program %q not found", e.Name) return nil, nil diff --git a/internal/backend/rest/rest.go b/internal/backend/rest/rest.go index 6473a98b3..4dc271f38 100644 --- a/internal/backend/rest/rest.go +++ b/internal/backend/rest/rest.go @@ -63,13 +63,13 @@ func Open(cfg Config, rt http.RoundTripper) (*Backend, error) { } // Create creates a new REST on server configured in config. -func Create(cfg Config, rt http.RoundTripper) (*Backend, error) { +func Create(ctx context.Context, cfg Config, rt http.RoundTripper) (*Backend, error) { be, err := Open(cfg, rt) if err != nil { return nil, err } - _, err = be.Stat(context.TODO(), restic.Handle{Type: restic.ConfigFile}) + _, err = be.Stat(ctx, restic.Handle{Type: restic.ConfigFile}) if err == nil { return nil, errors.Fatal("config file already exists") } diff --git a/internal/backend/rest/rest_test.go b/internal/backend/rest/rest_test.go index 486f241a9..3f6859626 100644 --- a/internal/backend/rest/rest_test.go +++ b/internal/backend/rest/rest_test.go @@ -86,7 +86,7 @@ func newTestSuite(ctx context.Context, t testing.TB, url *url.URL, minimalData b // CreateFn is a function that creates a temporary repository for the tests. Create: func(config interface{}) (restic.Backend, error) { cfg := config.(rest.Config) - return rest.Create(cfg, tr) + return rest.Create(context.TODO(), cfg, tr) }, // OpenFn is a function that opens a previously created temporary repository. diff --git a/internal/checker/checker_test.go b/internal/checker/checker_test.go index 96047569b..ce12420eb 100644 --- a/internal/checker/checker_test.go +++ b/internal/checker/checker_test.go @@ -574,7 +574,7 @@ func benchmarkSnapshotScaling(t *testing.B, newSnapshots int) { chkr, repo, cleanup := loadBenchRepository(t) defer cleanup() - snID, err := restic.FindSnapshot(repo, "51d249d2") + snID, err := restic.FindSnapshot(context.TODO(), repo, "51d249d2") if err != nil { t.Fatal(err) } diff --git a/internal/pack/pack_test.go b/internal/pack/pack_test.go index 71aac082d..e40e5bd2a 100644 --- a/internal/pack/pack_test.go +++ b/internal/pack/pack_test.go @@ -128,7 +128,7 @@ func TestUnpackReadSeeker(t *testing.T) { handle := restic.Handle{Type: restic.PackFile, Name: id.String()} rtest.OK(t, b.Save(context.TODO(), handle, restic.NewByteReader(packData))) - verifyBlobs(t, bufs, k, restic.ReaderAt(b, handle), packSize) + verifyBlobs(t, bufs, k, restic.ReaderAt(context.TODO(), b, handle), packSize) } func TestShortPack(t *testing.T) { @@ -141,5 +141,5 @@ func TestShortPack(t *testing.T) { handle := restic.Handle{Type: restic.PackFile, Name: id.String()} rtest.OK(t, b.Save(context.TODO(), handle, restic.NewByteReader(packData))) - verifyBlobs(t, bufs, k, restic.ReaderAt(b, handle), packSize) + verifyBlobs(t, bufs, k, restic.ReaderAt(context.TODO(), b, handle), packSize) } diff --git a/internal/repository/key.go b/internal/repository/key.go index 69eb7e04b..2c60f59e8 100644 --- a/internal/repository/key.go +++ b/internal/repository/key.go @@ -57,8 +57,8 @@ var ( // createMasterKey creates a new master key in the given backend and encrypts // it with the password. -func createMasterKey(s *Repository, password string) (*Key, error) { - return AddKey(context.TODO(), s, password, "", "", nil) +func createMasterKey(ctx context.Context, s *Repository, password string) (*Key, error) { + return AddKey(ctx, s, password, "", "", nil) } // OpenKey tries do decrypt the key specified by name with the given password. @@ -116,7 +116,7 @@ func SearchKey(ctx context.Context, s *Repository, password string, maxKeys int, checked := 0 if len(keyHint) > 0 { - id, err := restic.Find(s.Backend(), restic.KeyFile, keyHint) + id, err := restic.Find(ctx, s.Backend(), restic.KeyFile, keyHint) if err == nil { key, err := OpenKey(ctx, s, id, password) diff --git a/internal/repository/master_index.go b/internal/repository/master_index.go index 57b2985a6..6f19a0aad 100644 --- a/internal/repository/master_index.go +++ b/internal/repository/master_index.go @@ -267,7 +267,7 @@ func (mi *MasterIndex) MergeFinalIndexes() { // RebuildIndex combines all known indexes to a new index, leaving out any // packs whose ID is contained in packBlacklist. The new index contains the IDs // of all known indexes in the "supersedes" field. -func (mi *MasterIndex) RebuildIndex(packBlacklist restic.IDSet) (*Index, error) { +func (mi *MasterIndex) RebuildIndex(ctx context.Context, packBlacklist restic.IDSet) (*Index, error) { mi.idxMutex.Lock() defer mi.idxMutex.Unlock() @@ -275,7 +275,7 @@ func (mi *MasterIndex) RebuildIndex(packBlacklist restic.IDSet) (*Index, error) newIndex := NewIndex() - ctx, cancel := context.WithCancel(context.TODO()) + ctx, cancel := context.WithCancel(ctx) defer cancel() for i, idx := range mi.idx { diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 3c6d9665f..635b15253 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -72,8 +72,8 @@ func (r *Repository) UseCache(c *cache.Cache) { // PrefixLength returns the number of bytes required so that all prefixes of // all IDs of type t are unique. -func (r *Repository) PrefixLength(t restic.FileType) (int, error) { - return restic.PrefixLength(r.be, t) +func (r *Repository) PrefixLength(ctx context.Context, t restic.FileType) (int, error) { + return restic.PrefixLength(ctx, r.be, t) } // LoadAndDecrypt loads and decrypts the file with the given type and ID, using @@ -638,7 +638,7 @@ func (r *Repository) Init(ctx context.Context, password string, chunkerPolynomia // init creates a new master key with the supplied password and uses it to save // the config into the repo. func (r *Repository) init(ctx context.Context, password string, cfg restic.Config) error { - key, err := createMasterKey(r, password) + key, err := createMasterKey(ctx, r, password) if err != nil { return err } @@ -679,7 +679,7 @@ func (r *Repository) List(ctx context.Context, t restic.FileType, fn func(restic func (r *Repository) ListPack(ctx context.Context, id restic.ID, size int64) ([]restic.Blob, int64, error) { h := restic.Handle{Type: restic.PackFile, Name: id.String()} - blobs, err := pack.List(r.Key(), restic.ReaderAt(r.Backend(), h), size) + blobs, err := pack.List(r.Key(), restic.ReaderAt(ctx, r.Backend(), h), size) if err != nil { return nil, 0, err } diff --git a/internal/restic/backend_find.go b/internal/restic/backend_find.go index 36b2ba4ca..ec85a957a 100644 --- a/internal/restic/backend_find.go +++ b/internal/restic/backend_find.go @@ -17,10 +17,10 @@ var ErrMultipleIDMatches = errors.New("multiple IDs with prefix found") // Find loads the list of all files of type t and searches for names which // start with prefix. If none is found, nil and ErrNoIDPrefixFound is returned. // If more than one is found, nil and ErrMultipleIDMatches is returned. -func Find(be Lister, t FileType, prefix string) (string, error) { +func Find(ctx context.Context, be Lister, t FileType, prefix string) (string, error) { match := "" - ctx, cancel := context.WithCancel(context.TODO()) + ctx, cancel := context.WithCancel(ctx) defer cancel() err := be.List(ctx, t, func(fi FileInfo) error { @@ -50,11 +50,11 @@ const minPrefixLength = 8 // PrefixLength returns the number of bytes required so that all prefixes of // all names of type t are unique. -func PrefixLength(be Lister, t FileType) (int, error) { +func PrefixLength(ctx context.Context, be Lister, t FileType) (int, error) { // load all IDs of the given type list := make([]string, 0, 100) - ctx, cancel := context.WithCancel(context.TODO()) + ctx, cancel := context.WithCancel(ctx) defer cancel() err := be.List(ctx, t, func(fi FileInfo) error { diff --git a/internal/restic/backend_find_test.go b/internal/restic/backend_find_test.go index d122b4f94..557e1367b 100644 --- a/internal/restic/backend_find_test.go +++ b/internal/restic/backend_find_test.go @@ -38,7 +38,7 @@ func TestFind(t *testing.T) { return nil } - f, err := Find(m, SnapshotFile, "20bdc1402a6fc9b633aa") + f, err := Find(context.TODO(), m, SnapshotFile, "20bdc1402a6fc9b633aa") if err != nil { t.Error(err) } @@ -47,7 +47,7 @@ func TestFind(t *testing.T) { t.Errorf("Wrong match returned want %s, got %s", expectedMatch, f) } - f, err = Find(m, SnapshotFile, "NotAPrefix") + f, err = Find(context.TODO(), m, SnapshotFile, "NotAPrefix") if err != ErrNoIDPrefixFound { t.Error("Expected no snapshots to be found.") } @@ -57,7 +57,7 @@ func TestFind(t *testing.T) { // Try to match with a prefix longer than any ID. extraLengthID := samples[0].String() + "f" - f, err = Find(m, SnapshotFile, extraLengthID) + f, err = Find(context.TODO(), m, SnapshotFile, extraLengthID) if err != ErrNoIDPrefixFound { t.Error("Expected no snapshots to be matched.") } @@ -66,7 +66,7 @@ func TestFind(t *testing.T) { } // Use a prefix that will match the prefix of multiple Ids in `samples`. - f, err = Find(m, SnapshotFile, "20bdc140") + f, err = Find(context.TODO(), m, SnapshotFile, "20bdc140") if err != ErrMultipleIDMatches { t.Error("Expected multiple snapshots to be matched.") } @@ -89,7 +89,7 @@ func TestPrefixLength(t *testing.T) { return nil } - l, err := PrefixLength(m, SnapshotFile) + l, err := PrefixLength(context.TODO(), m, SnapshotFile) if err != nil { t.Error(err) } @@ -98,7 +98,7 @@ func TestPrefixLength(t *testing.T) { } list = samples[:3] - l, err = PrefixLength(m, SnapshotFile) + l, err = PrefixLength(context.TODO(), m, SnapshotFile) if err != nil { t.Error(err) } @@ -107,7 +107,7 @@ func TestPrefixLength(t *testing.T) { } list = samples[3:] - l, err = PrefixLength(m, SnapshotFile) + l, err = PrefixLength(context.TODO(), m, SnapshotFile) if err != nil { t.Error(err) } diff --git a/internal/restic/lock.go b/internal/restic/lock.go index 28807ce69..7047bb52d 100644 --- a/internal/restic/lock.go +++ b/internal/restic/lock.go @@ -284,7 +284,7 @@ func RemoveStaleLocks(ctx context.Context, repo Repository) error { } if lock.Stale() { - return repo.Backend().Remove(context.TODO(), Handle{Type: LockFile, Name: id.String()}) + return repo.Backend().Remove(ctx, Handle{Type: LockFile, Name: id.String()}) } return nil @@ -294,6 +294,6 @@ func RemoveStaleLocks(ctx context.Context, repo Repository) error { // RemoveAllLocks removes all locks forcefully. func RemoveAllLocks(ctx context.Context, repo Repository) error { return repo.List(ctx, LockFile, func(id ID, size int64) error { - return repo.Backend().Remove(context.TODO(), Handle{Type: LockFile, Name: id.String()}) + return repo.Backend().Remove(ctx, Handle{Type: LockFile, Name: id.String()}) }) } diff --git a/internal/restic/readerat.go b/internal/restic/readerat.go index 6e945b43a..6ed2e83f5 100644 --- a/internal/restic/readerat.go +++ b/internal/restic/readerat.go @@ -9,17 +9,20 @@ import ( ) type backendReaderAt struct { - be Backend - h Handle + ctx context.Context + be Backend + h Handle } func (brd backendReaderAt) ReadAt(p []byte, offset int64) (n int, err error) { - return ReadAt(context.TODO(), brd.be, brd.h, offset, p) + return ReadAt(brd.ctx, brd.be, brd.h, offset, p) } -// ReaderAt returns an io.ReaderAt for a file in the backend. -func ReaderAt(be Backend, h Handle) io.ReaderAt { - return backendReaderAt{be: be, h: h} +// ReaderAt returns an io.ReaderAt for a file in the backend. The returned reader +// should not escape the caller function to avoid unexpected interactions with the +// embedded context +func ReaderAt(ctx context.Context, be Backend, h Handle) io.ReaderAt { + return backendReaderAt{ctx: ctx, be: be, h: h} } // ReadAt reads from the backend handle h at the given position. diff --git a/internal/restic/snapshot_find.go b/internal/restic/snapshot_find.go index 184fcd38f..50395c814 100644 --- a/internal/restic/snapshot_find.go +++ b/internal/restic/snapshot_find.go @@ -74,10 +74,10 @@ func FindLatestSnapshot(ctx context.Context, repo Repository, targets []string, // FindSnapshot takes a string and tries to find a snapshot whose ID matches // the string as closely as possible. -func FindSnapshot(repo Repository, s string) (ID, error) { +func FindSnapshot(ctx context.Context, repo Repository, s string) (ID, error) { // find snapshot id with prefix - name, err := Find(repo.Backend(), SnapshotFile, s) + name, err := Find(ctx, repo.Backend(), SnapshotFile, s) if err != nil { return ID{}, err } diff --git a/internal/restorer/filerestorer_test.go b/internal/restorer/filerestorer_test.go index a1b9b17f8..16fce6271 100644 --- a/internal/restorer/filerestorer_test.go +++ b/internal/restorer/filerestorer_test.go @@ -179,26 +179,26 @@ func TestFileRestorerBasic(t *testing.T) { defer cleanup() restoreAndVerify(t, tempdir, []TestFile{ - TestFile{ + { name: "file1", blobs: []TestBlob{ - TestBlob{"data1-1", "pack1-1"}, - TestBlob{"data1-2", "pack1-2"}, + {"data1-1", "pack1-1"}, + {"data1-2", "pack1-2"}, }, }, - TestFile{ + { name: "file2", blobs: []TestBlob{ - TestBlob{"data2-1", "pack2-1"}, - TestBlob{"data2-2", "pack2-2"}, + {"data2-1", "pack2-1"}, + {"data2-2", "pack2-2"}, }, }, - TestFile{ + { name: "file3", blobs: []TestBlob{ // same blob multiple times - TestBlob{"data3-1", "pack3-1"}, - TestBlob{"data3-1", "pack3-1"}, + {"data3-1", "pack3-1"}, + {"data3-1", "pack3-1"}, }, }, }) diff --git a/internal/restorer/restorer.go b/internal/restorer/restorer.go index 48da0212e..c07209071 100644 --- a/internal/restorer/restorer.go +++ b/internal/restorer/restorer.go @@ -24,7 +24,7 @@ type Restorer struct { var restorerAbortOnAllErrors = func(location string, err error) error { return err } // NewRestorer creates a restorer preloaded with the content from the snapshot id. -func NewRestorer(repo restic.Repository, id restic.ID) (*Restorer, error) { +func NewRestorer(ctx context.Context, repo restic.Repository, id restic.ID) (*Restorer, error) { r := &Restorer{ repo: repo, Error: restorerAbortOnAllErrors, @@ -33,7 +33,7 @@ func NewRestorer(repo restic.Repository, id restic.ID) (*Restorer, error) { var err error - r.sn, err = restic.LoadSnapshot(context.TODO(), repo, id) + r.sn, err = restic.LoadSnapshot(ctx, repo, id) if err != nil { return nil, err } diff --git a/internal/restorer/restorer_test.go b/internal/restorer/restorer_test.go index 661191410..f3d43be4d 100644 --- a/internal/restorer/restorer_test.go +++ b/internal/restorer/restorer_test.go @@ -326,7 +326,7 @@ func TestRestorer(t *testing.T) { _, id := saveSnapshot(t, repo, test.Snapshot) t.Logf("snapshot saved as %v", id.Str()) - res, err := NewRestorer(repo, id) + res, err := NewRestorer(context.TODO(), repo, id) if err != nil { t.Fatal(err) } @@ -444,7 +444,7 @@ func TestRestorerRelative(t *testing.T) { _, id := saveSnapshot(t, repo, test.Snapshot) t.Logf("snapshot saved as %v", id.Str()) - res, err := NewRestorer(repo, id) + res, err := NewRestorer(context.TODO(), repo, id) if err != nil { t.Fatal(err) } @@ -676,7 +676,7 @@ func TestRestorerTraverseTree(t *testing.T) { defer cleanup() sn, id := saveSnapshot(t, repo, test.Snapshot) - res, err := NewRestorer(repo, id) + res, err := NewRestorer(context.TODO(), repo, id) if err != nil { t.Fatal(err) } diff --git a/internal/restorer/restorer_unix_test.go b/internal/restorer/restorer_unix_test.go index fc80015c1..f3f23cd16 100644 --- a/internal/restorer/restorer_unix_test.go +++ b/internal/restorer/restorer_unix_test.go @@ -29,7 +29,7 @@ func TestRestorerRestoreEmptyHardlinkedFileds(t *testing.T) { }, }) - res, err := NewRestorer(repo, id) + res, err := NewRestorer(context.TODO(), repo, id) rtest.OK(t, err) res.SelectFilter = func(item string, dstpath string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool) {