diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index 94c0dd30d..96a89b035 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -567,7 +567,7 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts global.Options, te return err } - var targetFS fs.FS = fs.Local{} + targetFS := fs.NewLocal() if runtime.GOOS == "windows" && opts.UseFsSnapshot { if err = fs.HasSufficientPrivilegesForVSS(); err != nil { return err diff --git a/cmd/restic/cmd_key_integration_test.go b/cmd/restic/cmd_key_integration_test.go index 35e949020..eaa3fd085 100644 --- a/cmd/restic/cmd_key_integration_test.go +++ b/cmd/restic/cmd_key_integration_test.go @@ -65,9 +65,11 @@ func testRunKeyAddNewKeyUserHost(t testing.TB, gopts global.Options) { _ = withTermStatus(t, gopts, func(ctx context.Context, gopts global.Options) error { repo, err := global.OpenRepository(ctx, gopts, progress.NewNoopPrinter()) rtest.OK(t, err) - key, err := repository.SearchKey(ctx, repo, testKeyNewPassword, 2, "") + err = repo.SearchKey(ctx, testKeyNewPassword, 2, "") rtest.OK(t, err) + key, err := repository.LoadKey(ctx, repo, repo.KeyID()) + rtest.OK(t, err) rtest.Equals(t, "john", key.Username) rtest.Equals(t, "example.com", key.Hostname) return nil @@ -107,9 +109,11 @@ func testRunKeyPasswdUserHost(t testing.TB, newPassword string, gopts global.Opt _ = withTermStatus(t, gopts, func(ctx context.Context, gopts global.Options) error { repo, err := global.OpenRepository(ctx, gopts, progress.NewNoopPrinter()) rtest.OK(t, err) - key, err := repository.SearchKey(ctx, repo, testKeyNewPassword, 1, "") + err = repo.SearchKey(ctx, testKeyNewPassword, 1, "") rtest.OK(t, err) + key, err := repository.LoadKey(ctx, repo, repo.KeyID()) + rtest.OK(t, err) rtest.Equals(t, "john", key.Username) rtest.Equals(t, "example.com", key.Hostname) return nil diff --git a/cmd/restic/lock.go b/cmd/restic/lock.go index a1b6ad5cb..38fc79a0c 100644 --- a/cmd/restic/lock.go +++ b/cmd/restic/lock.go @@ -16,7 +16,7 @@ func internalOpenWithLocked(ctx context.Context, gopts global.Options, dryRun bo unlock := func() {} if !dryRun { - var lock *repository.Unlocker + var lock repository.Unlocker lock, ctx, err = repository.Lock(ctx, repo, exclusive, gopts.RetryLock, func(msg string) { if !gopts.JSON { diff --git a/internal/archiver/archiver.go b/internal/archiver/archiver.go index 312119884..4693b6b03 100644 --- a/internal/archiver/archiver.go +++ b/internal/archiver/archiver.go @@ -67,8 +67,8 @@ func (s *ItemStats) Add(other ItemStats) { s.TreeSizeInRepo += other.TreeSizeInRepo } -// ToNoder returns a data.Node for a File. -type ToNoder interface { +// toNoder returns a data.Node for a File. +type toNoder interface { ToNode(ignoreXattrListError bool, warnf func(format string, args ...any)) (*data.Node, error) } @@ -149,9 +149,9 @@ type Options struct { SaveTreeConcurrency uint } -// ApplyDefaults returns a copy of o with the default options set for all unset +// applyDefaults returns a copy of o with the default options set for all unset // fields. -func (o Options) ApplyDefaults() Options { +func (o Options) applyDefaults() Options { if o.ReadConcurrency == 0 { // two is a sweet spot for almost all situations. We've done some // experiments documented here: @@ -178,7 +178,7 @@ func New(repo archiverRepo, filesystem fs.FS, opts Options) *Archiver { SelectByName: func(_ string) bool { return true }, Select: func(_ string, _ *fs.ExtendedFileInfo, _ fs.FS) bool { return true }, FS: filesystem, - Options: opts.ApplyDefaults(), + Options: opts.applyDefaults(), CompleteItem: func(string, *data.Node, *data.Node, ItemStats, time.Duration) {}, StartFile: func(string) {}, @@ -249,7 +249,7 @@ func (arch *Archiver) trackItem(item string, previous, current *data.Node, s Ite } // nodeFromFileInfo returns the restic node from an os.FileInfo. -func (arch *Archiver) nodeFromFileInfo(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*data.Node, error) { +func (arch *Archiver) nodeFromFileInfo(snPath, filename string, meta toNoder, ignoreXattrListError bool) (*data.Node, error) { node, err := meta.ToNode(ignoreXattrListError, func(format string, args ...any) { _ = arch.error(filename, fmt.Errorf(format, args...)) }) @@ -781,9 +781,9 @@ func (arch *Archiver) dirPathToNode(snPath, target string) (node *data.Node, err // // Paths returned with Explicit true are those the user listed literally; paths // inserted from directory expansion have Explicit false. -func resolveRelativeTargets(filesys fs.FS, targets []string) ([]BackupTarget, error) { +func resolveRelativeTargets(filesys fs.FS, targets []string) ([]backupTarget, error) { debug.Log("targets before resolving: %v", targets) - result := make([]BackupTarget, 0, len(targets)) + result := make([]backupTarget, 0, len(targets)) for _, target := range targets { if target != "" && filesys.VolumeName(target) == target { // special case to allow users to also specify a volume name "C:" instead of a path "C:\" @@ -793,7 +793,7 @@ func resolveRelativeTargets(filesys fs.FS, targets []string) ([]BackupTarget, er } pc, _ := pathComponents(filesys, target, false) if len(pc) > 0 { - result = append(result, BackupTarget{Path: target, Explicit: true}) + result = append(result, backupTarget{Path: target, Explicit: true}) continue } @@ -805,7 +805,7 @@ func resolveRelativeTargets(filesys fs.FS, targets []string) ([]BackupTarget, er sort.Strings(entries) for _, name := range entries { - result = append(result, BackupTarget{ + result = append(result, backupTarget{ Path: filesys.Join(target, name), Explicit: false, }) diff --git a/internal/archiver/archiver_test.go b/internal/archiver/archiver_test.go index 104818910..d54d9fb5d 100644 --- a/internal/archiver/archiver_test.go +++ b/internal/archiver/archiver_test.go @@ -136,7 +136,7 @@ func TestArchiverSaveFile(t *testing.T) { defer cancel() tempdir, repo := prepareTempdirRepoSrc(t, TestDir{"file": testfile}) - node, stats := saveFile(t, repo, filepath.Join(tempdir, "file"), fs.Track{FS: fs.Local{}}) + node, stats := saveFile(t, repo, filepath.Join(tempdir, "file"), fs.Track{FS: fs.NewLocal()}) TestEnsureFileContent(ctx, t, repo, "file", node, testfile) if stats.DataSize != uint64(len(testfile.Content)) { @@ -211,7 +211,7 @@ func TestArchiverSave(t *testing.T) { tempdir, repo := prepareTempdirRepoSrc(t, TestDir{"file": testfile}) - arch := New(repo, fs.Track{FS: fs.Local{}}, Options{}) + arch := New(repo, fs.Track{FS: fs.NewLocal()}, Options{}) arch.Error = func(item string, err error) error { t.Errorf("archiver error for %v: %v", item, err) return err @@ -357,7 +357,7 @@ func BenchmarkArchiverSaveFileSmall(b *testing.B) { tempdir, repo := prepareTempdirRepoSrc(b, d) b.StartTimer() - _, stats := saveFile(b, repo, filepath.Join(tempdir, "file"), fs.Track{FS: fs.Local{}}) + _, stats := saveFile(b, repo, filepath.Join(tempdir, "file"), fs.Track{FS: fs.NewLocal()}) b.StopTimer() if stats.DataSize != fileSize { @@ -389,7 +389,7 @@ func BenchmarkArchiverSaveFileLarge(b *testing.B) { tempdir, repo := prepareTempdirRepoSrc(b, d) b.StartTimer() - _, stats := saveFile(b, repo, filepath.Join(tempdir, "file"), fs.Track{FS: fs.Local{}}) + _, stats := saveFile(b, repo, filepath.Join(tempdir, "file"), fs.Track{FS: fs.NewLocal()}) b.StopTimer() if stats.DataSize != fileSize { @@ -479,7 +479,7 @@ func TestArchiverSaveFileIncremental(t *testing.T) { for i := 0; i < 3; i++ { appendToFile(t, testfile, data) - node, _ := saveFile(t, repo, testfile, fs.Track{FS: fs.Local{}}) + node, _ := saveFile(t, repo, testfile, fs.Track{FS: fs.NewLocal()}) t.Logf("node blobs: %v", node.Content) @@ -691,7 +691,7 @@ func TestFileChanged(t *testing.T) { } save(t, filename, content) - fs := &fs.Local{} + fs := fs.NewLocal() fiBefore, err := fs.Lstat(filename) rtest.OK(t, err) node := nodeFromFile(t, fs, filename) @@ -735,7 +735,7 @@ func TestFilChangedSpecialCases(t *testing.T) { t.Run("type-change", func(t *testing.T) { fi := lstat(t, filename) - node := nodeFromFile(t, &fs.Local{}, filename) + node := nodeFromFile(t, fs.NewLocal(), filename) node.Type = data.NodeTypeSymlink if !fileChanged(fi, node, 0) { t.Fatal("node with changed type detected as unchanged") @@ -837,7 +837,7 @@ func TestArchiverSaveDir(t *testing.T) { t.Run("", func(t *testing.T) { tempdir, repo := prepareTempdirRepoSrc(t, test.src) - testFS := fs.Track{FS: fs.Local{}} + testFS := fs.Track{FS: fs.NewLocal()} arch := New(repo, testFS, Options{}) arch.summary = &Summary{} @@ -907,7 +907,7 @@ func TestArchiverSaveDirIncremental(t *testing.T) { // save the empty directory several times in a row, then have a look if the // archiver did save the same tree several times for i := 0; i < 5; i++ { - testFS := fs.Track{FS: fs.Local{}} + testFS := fs.Track{FS: fs.NewLocal()} arch := New(repo, testFS, Options{}) arch.summary = &Summary{} @@ -1089,7 +1089,7 @@ func TestArchiverSaveTree(t *testing.T) { t.Run("", func(t *testing.T) { tempdir, repo := prepareTempdirRepoSrc(t, test.src) - testFS := fs.Track{FS: fs.Local{}} + testFS := fs.Track{FS: fs.NewLocal()} arch := New(repo, testFS, Options{}) arch.summary = &Summary{} @@ -1388,7 +1388,7 @@ func TestArchiverSnapshot(t *testing.T) { tempdir, repo := prepareTempdirRepoSrc(t, test.src) - arch := New(repo, fs.Track{FS: fs.Local{}}, Options{}) + arch := New(repo, fs.Track{FS: fs.NewLocal()}, Options{}) chdir := tempdir if test.chdir != "" { @@ -1487,7 +1487,7 @@ func TestResolveRelativeTargetsSpecial(t *testing.T) { t.Skip("skip test on unix") } - targets, err := resolveRelativeTargets(&fs.Local{}, test.targets) + targets, err := resolveRelativeTargets(fs.NewLocal(), test.targets) rtest.OK(t, err) paths := make([]string, len(targets)) for i, tgt := range targets { @@ -1609,7 +1609,7 @@ func TestArchiverSnapshotSelect(t *testing.T) { tempdir, repo := prepareTempdirRepoSrc(t, test.src) - arch := New(repo, fs.Track{FS: fs.Local{}}, Options{}) + arch := New(repo, fs.Track{FS: fs.NewLocal()}, Options{}) arch.Select = test.selFn back := rtest.Chdir(t, tempdir) @@ -1717,7 +1717,7 @@ func TestArchiverExplicitBackupTarget(t *testing.T) { tempdir, repo := prepareTempdirRepoSrc(t, test.src) - arch := New(repo, fs.Track{FS: fs.Local{}}, Options{}) + arch := New(repo, fs.Track{FS: fs.NewLocal()}, Options{}) arch.Select = test.selFn back := rtest.Chdir(t, tempdir) @@ -1884,7 +1884,7 @@ func TestArchiverParent(t *testing.T) { tempdir, repo := prepareTempdirRepoSrc(t, test.src) testFS := &MockFS{ - FS: fs.Track{FS: fs.Local{}}, + FS: fs.Track{FS: fs.NewLocal()}, bytesRead: make(map[string]int), } @@ -2078,7 +2078,7 @@ func TestArchiverErrorReporting(t *testing.T) { test.prepare(t) } - arch := New(repo, fs.Track{FS: fs.Local{}}, Options{}) + arch := New(repo, fs.Track{FS: fs.NewLocal()}, Options{}) arch.Error = test.errFn target := test.targets @@ -2159,7 +2159,7 @@ func TestArchiverContextCanceled(t *testing.T) { back := rtest.Chdir(t, tempdir) defer back() - arch := New(repo, fs.Track{FS: fs.Local{}}, Options{}) + arch := New(repo, fs.Track{FS: fs.NewLocal()}, Options{}) _, snapshotID, _, err := arch.Snapshot(ctx, []string{"."}, SnapshotOptions{Time: time.Now()}) @@ -2301,7 +2301,7 @@ func TestArchiverAbortEarlyOnError(t *testing.T) { defer back() testFS := &TrackFS{ - FS: fs.Track{FS: fs.Local{}}, + FS: fs.Track{FS: fs.NewLocal()}, opened: make(map[string]uint), } @@ -2434,7 +2434,7 @@ func TestMetadataChanged(t *testing.T) { // get metadata fi := lstat(t, "testfile") - localFS := &fs.Local{} + localFS := fs.NewLocal() meta, err := localFS.OpenFile("testfile", fs.O_NOFOLLOW, true) rtest.OK(t, err) want, err := meta.ToNode(false, t.Logf) @@ -2535,7 +2535,7 @@ func TestRacyFileTypeSwap(t *testing.T) { tempfile := filepath.Join(tempdir, realName) statfs := &overrideFS{ - FS: fs.Local{}, + FS: fs.NewLocal(), overrideFI: fakeFI, resetFIOnRead: true, } @@ -2582,7 +2582,7 @@ func TestMetadataBackupErrorFiltering(t *testing.T) { filename := filepath.Join(tempdir, "file") repo := repository.TestRepository(t) - arch := New(repo, fs.Local{}, Options{}) + arch := New(repo, fs.NewLocal(), Options{}) var filteredErr error replacementErr := fmt.Errorf("replacement") @@ -2631,7 +2631,7 @@ func TestIrregularFile(t *testing.T) { fi.Mode = (fi.Mode &^ os.ModeType) | os.ModeIrregular override := &overrideFS{ - FS: fs.Local{}, + FS: fs.NewLocal(), overrideFI: fi, overrideNode: &data.Node{ Type: data.NodeTypeIrregular, @@ -2692,7 +2692,7 @@ func TestDisappearedFile(t *testing.T) { // depending on the underlying FS implementation a missing file may be detected by OpenFile or // the subsequent file.Stat() call. Thus test both cases. for _, errorOnOpen := range []bool{false, true} { - arch := New(repo, fs.Track{FS: &missingFS{FS: &fs.Local{}, errorOnOpen: errorOnOpen}}, Options{}) + arch := New(repo, fs.Track{FS: &missingFS{FS: fs.NewLocal(), errorOnOpen: errorOnOpen}}, Options{}) _, excluded, err := arch.save(ctx, "/", filepath.Join(tempdir, "testdir"), nil, false) rtest.OK(t, err) rtest.Assert(t, excluded, "testfile should have been excluded") diff --git a/internal/archiver/archiver_unix_test.go b/internal/archiver/archiver_unix_test.go index 978dc1b80..f548b655c 100644 --- a/internal/archiver/archiver_unix_test.go +++ b/internal/archiver/archiver_unix_test.go @@ -12,8 +12,8 @@ import ( ) func statAndSnapshot(t *testing.T, repo archiverRepo, name string) (*data.Node, *data.Node) { - want := nodeFromFile(t, &fs.Local{}, name) - _, node := snapshot(t, repo, &fs.Local{}, nil, name) + want := nodeFromFile(t, fs.NewLocal(), name) + _, node := snapshot(t, repo, fs.NewLocal(), nil, name) return want, node } diff --git a/internal/archiver/exclude_test.go b/internal/archiver/exclude_test.go index 9bfa5d83f..4080f25f0 100644 --- a/internal/archiver/exclude_test.go +++ b/internal/archiver/exclude_test.go @@ -49,7 +49,7 @@ func TestIsExcludedByFile(t *testing.T) { if tc.content == "" { h = "" } - if got := isExcludedByFile(foo, tagFilename, h, newRejectionCache(), &fs.Local{}, func(msg string, args ...interface{}) { t.Logf(msg, args...) }); tc.want != got { + if got := isExcludedByFile(foo, tagFilename, h, newRejectionCache(), fs.NewLocal(), func(msg string, args ...interface{}) { t.Logf(msg, args...) }); tc.want != got { t.Fatalf("expected %v, got %v", tc.want, got) } }) @@ -111,8 +111,8 @@ func TestMultipleIsExcludedByFile(t *testing.T) { if err != nil { return err } - excludedByFoo := fooExclude(p, nil, &fs.Local{}) - excludedByBar := barExclude(p, nil, &fs.Local{}) + excludedByFoo := fooExclude(p, nil, fs.NewLocal()) + excludedByBar := barExclude(p, nil, fs.NewLocal()) excluded := excludedByFoo || excludedByBar // the log message helps debugging in case the test fails t.Logf("%q: %v || %v = %v", p, excludedByFoo, excludedByBar, excluded) @@ -243,7 +243,7 @@ func TestDeviceMap(t *testing.T) { for _, test := range tests { t.Run("", func(t *testing.T) { - res, err := deviceMap.IsAllowed(filepath.FromSlash(test.item), test.deviceID, &fs.Local{}) + res, err := deviceMap.IsAllowed(filepath.FromSlash(test.item), test.deviceID, fs.NewLocal()) if err != nil { t.Fatal(err) } diff --git a/internal/archiver/file_saver.go b/internal/archiver/file_saver.go index 3407cae16..313f1d19b 100644 --- a/internal/archiver/file_saver.go +++ b/internal/archiver/file_saver.go @@ -26,7 +26,7 @@ type fileSaver struct { CompleteBlob func(bytes uint64) - NodeFromFileInfo func(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*data.Node, error) + NodeFromFileInfo func(snPath, filename string, meta toNoder, ignoreXattrListError bool) (*data.Node, error) } // newFileSaver returns a new file saver. A worker pool with fileWorkers is diff --git a/internal/archiver/file_saver_test.go b/internal/archiver/file_saver_test.go index 4dbf78548..1af322be0 100644 --- a/internal/archiver/file_saver_test.go +++ b/internal/archiver/file_saver_test.go @@ -41,7 +41,7 @@ func startFileSaver(ctx context.Context, t testing.TB, _ fs.FS) (*fileSaver, *mo saver := &mockSaver{saved: make(map[string]int)} s := newFileSaver(ctx, wg, saver, pol, workers) - s.NodeFromFileInfo = func(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*data.Node, error) { + s.NodeFromFileInfo = func(snPath, filename string, meta toNoder, ignoreXattrListError bool) (*data.Node, error) { return meta.ToNode(ignoreXattrListError, t.Logf) } @@ -57,7 +57,7 @@ func TestFileSaver(t *testing.T) { completeFn := func(*data.Node, ItemStats) {} files := createTestFiles(t, 15) - testFs := fs.Local{} + testFs := fs.NewLocal() s, saver, ctx, wg := startFileSaver(ctx, t, testFs) var results []futureNode diff --git a/internal/archiver/scanner_test.go b/internal/archiver/scanner_test.go index a47952388..c2ec8fdb8 100644 --- a/internal/archiver/scanner_test.go +++ b/internal/archiver/scanner_test.go @@ -92,7 +92,7 @@ func TestScanner(t *testing.T) { t.Fatal(err) } - sc := NewScanner(fs.Track{FS: fs.Local{}}) + sc := NewScanner(fs.Track{FS: fs.NewLocal()}) if test.selFn != nil { sc.Select = test.selFn } @@ -231,7 +231,7 @@ func TestScannerError(t *testing.T) { test.prepare(t) } - sc := NewScanner(fs.Track{FS: fs.Local{}}) + sc := NewScanner(fs.Track{FS: fs.NewLocal()}) if test.selFn != nil { sc.Select = test.selFn } @@ -299,7 +299,7 @@ func TestScannerCancel(t *testing.T) { t.Fatal(err) } - sc := NewScanner(fs.Track{FS: fs.Local{}}) + sc := NewScanner(fs.Track{FS: fs.NewLocal()}) var lastStats ScanStats sc.Result = func(item string, s ScanStats) { lastStats = s diff --git a/internal/archiver/testing.go b/internal/archiver/testing.go index 6f1195c29..3a3bafce1 100644 --- a/internal/archiver/testing.go +++ b/internal/archiver/testing.go @@ -20,7 +20,7 @@ import ( // TestSnapshot creates a new snapshot of path. func TestSnapshot(t testing.TB, repo restic.Repository, path string, parent *restic.ID) *data.Snapshot { - arch := New(repo, fs.Local{}, Options{}) + arch := New(repo, fs.NewLocal(), Options{}) opts := SnapshotOptions{ Time: time.Now(), Hostname: "localhost", diff --git a/internal/archiver/testing_test.go b/internal/archiver/testing_test.go index a217abe25..6c395b94e 100644 --- a/internal/archiver/testing_test.go +++ b/internal/archiver/testing_test.go @@ -467,7 +467,7 @@ func TestTestEnsureSnapshot(t *testing.T) { repo := repository.TestRepository(t) - arch := New(repo, fs.Local{}, Options{}) + arch := New(repo, fs.NewLocal(), Options{}) opts := SnapshotOptions{ Time: time.Now(), Hostname: "localhost", diff --git a/internal/archiver/tree.go b/internal/archiver/tree.go index c7700665a..9e760752b 100644 --- a/internal/archiver/tree.go +++ b/internal/archiver/tree.go @@ -274,16 +274,16 @@ func unrollTree(f fs.FS, t *tree) error { return nil } -// BackupTarget is a resolved backup path and whether the user passed this path +// backupTarget is a resolved backup path and whether the user passed this path // literally. Paths inserted when expanding a target with no path components // (for example ".") have Explicit false so include/exclude rules still apply. -type BackupTarget struct { +type backupTarget struct { Path string Explicit bool } // newTree creates a Tree from the target files/directories. -func newTree(fs fs.FS, targets []BackupTarget) (*tree, error) { +func newTree(fs fs.FS, targets []backupTarget) (*tree, error) { debug.Log("targets: %v", targets) tree := &tree{} seen := make(map[string]struct{}) diff --git a/internal/archiver/tree_test.go b/internal/archiver/tree_test.go index e1b8a4b36..f2c948f37 100644 --- a/internal/archiver/tree_test.go +++ b/internal/archiver/tree_test.go @@ -14,10 +14,10 @@ import ( // debug.Log requires Tree.String. var _ fmt.Stringer = tree{} -func testBackupTargets(paths []string) []BackupTarget { - tgts := make([]BackupTarget, len(paths)) +func testBackupTargets(paths []string) []backupTarget { + tgts := make([]backupTarget, len(paths)) for i, p := range paths { - tgts[i] = BackupTarget{Path: p, Explicit: true} + tgts[i] = backupTarget{Path: p, Explicit: true} } return tgts } @@ -98,7 +98,7 @@ func TestPathComponents(t *testing.T) { t.Skip("skip test on unix") } - c, v := pathComponents(fs.Local{}, filepath.FromSlash(test.p), test.rel) + c, v := pathComponents(fs.NewLocal(), filepath.FromSlash(test.p), test.rel) if !cmp.Equal(test.c, c) { t.Error(test.c, c) } @@ -137,7 +137,7 @@ func TestRootDirectory(t *testing.T) { t.Skip("skip test on unix") } - root := rootDirectory(fs.Local{}, filepath.FromSlash(test.target)) + root := rootDirectory(fs.NewLocal(), filepath.FromSlash(test.target)) want := filepath.FromSlash(test.root) if root != want { t.Fatalf("wrong root directory, want %v, got %v", want, root) @@ -455,7 +455,7 @@ func TestTree(t *testing.T) { back := rtest.Chdir(t, tempdir) defer back() - tree, err := newTree(fs.Local{}, testBackupTargets(test.targets)) + tree, err := newTree(fs.NewLocal(), testBackupTargets(test.targets)) if test.mustError { if err == nil { t.Fatal("expected error, got nil") diff --git a/internal/bloblru/cache.go b/internal/bloblru/cache.go index 9981f8a87..514e608ff 100644 --- a/internal/bloblru/cache.go +++ b/internal/bloblru/cache.go @@ -44,9 +44,9 @@ func New(size int) *Cache { return c } -// Add adds key id with value blob to c. +// add adds key id with value blob to c. // It may return an evicted buffer for reuse. -func (c *Cache) Add(id restic.ID, blob []byte) (old []byte) { +func (c *Cache) add(id restic.ID, blob []byte) (old []byte) { debug.Log("bloblru.Cache: add %v", id) size := cap(blob) + overhead @@ -77,7 +77,7 @@ func (c *Cache) Add(id restic.ID, blob []byte) (old []byte) { return old } -func (c *Cache) Get(id restic.ID) ([]byte, bool) { +func (c *Cache) get(id restic.ID) ([]byte, bool) { c.mu.Lock() blob, ok := c.c.Get(id) c.mu.Unlock() @@ -89,7 +89,7 @@ func (c *Cache) Get(id restic.ID) ([]byte, bool) { func (c *Cache) GetOrCompute(id restic.ID, compute func() ([]byte, error)) ([]byte, error) { // check if already cached - blob, ok := c.Get(id) + blob, ok := c.get(id) if ok { return blob, nil } @@ -124,7 +124,7 @@ func (c *Cache) GetOrCompute(id restic.ID, compute func() ([]byte, error)) ([]by // takes over, caches the computed value and cleans up its channel in c.inProgress. // Then goroutine A continues, does not detect a parallel computation and would try // to call compute() again. - blob, ok = c.Get(id) + blob, ok = c.get(id) if ok { return blob, nil } @@ -132,7 +132,7 @@ func (c *Cache) GetOrCompute(id restic.ID, compute func() ([]byte, error)) ([]by // download it blob, err := compute() if err == nil { - c.Add(id, blob) + c.add(id, blob) } return blob, err diff --git a/internal/bloblru/cache_test.go b/internal/bloblru/cache_test.go index d25daf764..5fe7bc73c 100644 --- a/internal/bloblru/cache_test.go +++ b/internal/bloblru/cache_test.go @@ -25,8 +25,8 @@ func TestCache(t *testing.T) { c := New(cacheSize) addAndCheck := func(id restic.ID, exp []byte) { - c.Add(id, exp) - blob, ok := c.Get(id) + c.add(id, exp) + blob, ok := c.get(id) rtest.Assert(t, ok, "blob %v added but not found in cache", id) rtest.Equals(t, &exp[0], &blob[0]) rtest.Equals(t, exp, blob) @@ -38,13 +38,13 @@ func TestCache(t *testing.T) { addAndCheck(id2, make([]byte, 1, 30*kiB)) addAndCheck(id3, make([]byte, 1, 10*kiB)) - _, ok := c.Get(id2) + _, ok := c.get(id2) rtest.Assert(t, ok, "blob %v not present", id2) - _, ok = c.Get(id1) + _, ok = c.get(id1) rtest.Assert(t, !ok, "blob %v present, but should have been evicted", id1) - c.Add(id1, make([]byte, 1+c.size)) - _, ok = c.Get(id1) + c.add(id1, make([]byte, 1+c.size)) + _, ok = c.get(id1) rtest.Assert(t, !ok, "blob %v too large but still added to cache") c.c.Remove(id1) @@ -141,6 +141,6 @@ func BenchmarkAdd(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - c.Add(ids[i%nblobs], buf[:sizes[i%nblobs]]) + c.add(ids[i%nblobs], buf[:sizes[i%nblobs]]) } } diff --git a/internal/data/node.go b/internal/data/node.go index f97224364..e7be9914c 100644 --- a/internal/data/node.go +++ b/internal/data/node.go @@ -32,8 +32,8 @@ type ExtendedAttribute struct { // and not create GenericAttributes for them. type GenericAttributeType string -// OSType is the type created to represent each specific OS -type OSType string +// osType is the type created to represent each specific OS +type osType string const ( // When new GenericAttributeType are defined, they must be added in the init function as well. @@ -56,14 +56,14 @@ func init() { } // genericAttributesForOS maintains a map of known genericAttributesForOS to the OSType -var genericAttributesForOS = map[GenericAttributeType]OSType{} +var genericAttributesForOS = map[GenericAttributeType]osType{} // storeGenericAttributeType adds and entry in genericAttributesForOS map func storeGenericAttributeType(attributeTypes ...GenericAttributeType) { for _, attributeType := range attributeTypes { // Get the OS attribute type from the GenericAttributeType osAttributeName := strings.Split(string(attributeType), ".")[0] - genericAttributesForOS[attributeType] = OSType(osAttributeName) + genericAttributesForOS[attributeType] = osType(osAttributeName) } } @@ -114,13 +114,6 @@ type Node struct { Path string `json:"-"` } -// Nodes is a slice of nodes that can be sorted. -type Nodes []*Node - -func (n Nodes) Len() int { return len(n) } -func (n Nodes) Less(i, j int) bool { return n[i].Name < n[j].Name } -func (n Nodes) Swap(i, j int) { n[i], n[j] = n[j], n[i] } - func (node Node) String() string { var mode os.FileMode switch node.Type { @@ -154,11 +147,11 @@ func (node Node) GetExtendedAttribute(a string) []byte { return nil } -// FixTime returns a time.Time which can safely be used to marshal as JSON. If +// fixTime returns a time.Time which can safely be used to marshal as JSON. If // the timestamp is earlier than year zero, the year is set to zero. In the same // way, if the year is larger than 9999, the year is set to 9999. Other than // the year nothing is changed. -func FixTime(t time.Time) time.Time { +func fixTime(t time.Time) time.Time { switch { case t.Year() < 0000: return t.AddDate(-t.Year(), 0, 0) @@ -172,9 +165,9 @@ func FixTime(t time.Time) time.Time { func (node Node) MarshalJSON() ([]byte, error) { // make sure invalid timestamps for mtime and atime are converted to // something we can actually save. - node.ModTime = FixTime(node.ModTime) - node.AccessTime = FixTime(node.AccessTime) - node.ChangeTime = FixTime(node.ChangeTime) + node.ModTime = fixTime(node.ModTime) + node.AccessTime = fixTime(node.AccessTime) + node.ChangeTime = fixTime(node.ChangeTime) type nodeJSON Node nj := nodeJSON(node) diff --git a/internal/data/node_test.go b/internal/data/node_test.go index f1b651efe..06a527cfd 100644 --- a/internal/data/node_test.go +++ b/internal/data/node_test.go @@ -51,7 +51,7 @@ func TestFixTime(t *testing.T) { for _, test := range tests { t.Run("", func(t *testing.T) { - res := FixTime(test.src) + res := fixTime(test.src) if !res.Equal(test.want) { t.Fatalf("wrong result for %v, want:\n %v\ngot:\n %v", test.src, test.want, res) } diff --git a/internal/data/tree_test.go b/internal/data/tree_test.go index d8f0207e8..b4bc6e20d 100644 --- a/internal/data/tree_test.go +++ b/internal/data/tree_test.go @@ -88,7 +88,7 @@ func TestNodeMarshal(t *testing.T) { } func nodeForFile(t *testing.T, name string) *data.Node { - f, err := (&fs.Local{}).OpenFile(name, fs.O_NOFOLLOW, true) + f, err := fs.NewLocal().OpenFile(name, fs.O_NOFOLLOW, true) rtest.OK(t, err) node, err := f.ToNode(false, t.Logf) rtest.OK(t, err) diff --git a/internal/dump/common_test.go b/internal/dump/common_test.go index bb0347189..042d41f90 100644 --- a/internal/dump/common_test.go +++ b/internal/dump/common_test.go @@ -84,7 +84,7 @@ func WriteTest(t *testing.T, format string, cd CheckDump) { defer cancel() tmpdir, repo, be := prepareTempdirRepoSrc(t, tt.args) - arch := archiver.New(repo, fs.Track{FS: fs.Local{}}, archiver.Options{}) + arch := archiver.New(repo, fs.Track{FS: fs.NewLocal()}, archiver.Options{}) back := rtest.Chdir(t, tmpdir) defer back() diff --git a/internal/fs/file_unix_test.go b/internal/fs/file_unix_test.go index 00d68abb8..1fd31156e 100644 --- a/internal/fs/file_unix_test.go +++ b/internal/fs/file_unix_test.go @@ -17,6 +17,6 @@ func TestReaddirnamesFifo(t *testing.T) { fifoFn := filepath.Join(tempdir, "fifo") rtest.OK(t, mkfifo(fifoFn, 0o600)) - _, err := Readdirnames(&Local{}, fifoFn, 0) + _, err := Readdirnames(NewLocal(), fifoFn, 0) rtest.Assert(t, errors.Is(err, syscall.ENOTDIR), "unexpected error %v", err) } diff --git a/internal/fs/fs_local.go b/internal/fs/fs_local.go index d5a9001a2..e452ace4d 100644 --- a/internal/fs/fs_local.go +++ b/internal/fs/fs_local.go @@ -14,16 +14,21 @@ func init() { } } -// Local is the local file system. Most methods are just passed on to the stdlib. -type Local struct{} +// local is the local file system. Most methods are just passed on to the stdlib. +type local struct{} -// statically ensure that Local implements FS. -var _ FS = &Local{} +// NewLocal returns an FS for the local file system. Most methods are just passed on to the stdlib. +func NewLocal() FS { + return local{} +} + +// statically ensure that local implements FS. +var _ FS = &local{} // VolumeName returns leading volume name. Given "C:\foo\bar" it returns "C:" // on Windows. Given "\\host\share\foo" it returns "\\host\share". On other // platforms it returns "". -func (fs Local) VolumeName(path string) string { +func (fs local) VolumeName(path string) string { return filepath.VolumeName(path) } @@ -35,7 +40,7 @@ func (fs Local) VolumeName(path string) string { // delay actually accessing the underlying filesystem. // // Only the O_NOFOLLOW and O_DIRECTORY flags are supported. -func (fs Local) OpenFile(name string, flag int, metadataOnly bool) (File, error) { +func (fs local) OpenFile(name string, flag int, metadataOnly bool) (File, error) { return newLocalFile(name, flag, metadataOnly) } @@ -43,7 +48,7 @@ func (fs Local) OpenFile(name string, flag int, metadataOnly bool) (File, error) // If the file is a symbolic link, the returned FileInfo // describes the symbolic link. Lstat makes no attempt to follow the link. // If there is an error, it will be of type *PathError. -func (fs Local) Lstat(name string) (*ExtendedFileInfo, error) { +func (fs local) Lstat(name string) (*ExtendedFileInfo, error) { fi, err := os.Lstat(fixpath(name)) if err != nil { return nil, err @@ -55,17 +60,17 @@ func (fs Local) Lstat(name string) (*ExtendedFileInfo, error) { // Separator if necessary. Join calls Clean on the result; in particular, all // empty strings are ignored. On Windows, the result is a UNC path if and only // if the first path element is a UNC path. -func (fs Local) Join(elem ...string) string { +func (fs local) Join(elem ...string) string { return filepath.Join(elem...) } // Separator returns the OS and FS dependent separator for dirs/subdirs/files. -func (fs Local) Separator() string { +func (fs local) Separator() string { return string(filepath.Separator) } // IsAbs reports whether the path is absolute. -func (fs Local) IsAbs(path string) bool { +func (fs local) IsAbs(path string) bool { return filepath.IsAbs(path) } @@ -73,22 +78,22 @@ func (fs Local) IsAbs(path string) bool { // it will be joined with the current working directory to turn it into an // absolute path. The absolute path name for a given file is not guaranteed to // be unique. Abs calls Clean on the result. -func (fs Local) Abs(path string) (string, error) { +func (fs local) Abs(path string) (string, error) { return filepath.Abs(path) } // Clean returns the cleaned path. For details, see filepath.Clean. -func (fs Local) Clean(p string) string { +func (fs local) Clean(p string) string { return filepath.Clean(p) } // Base returns the last element of path. -func (fs Local) Base(path string) string { +func (fs local) Base(path string) string { return filepath.Base(path) } // Dir returns path without the last element. -func (fs Local) Dir(path string) string { +func (fs local) Dir(path string) string { return filepath.Dir(path) } diff --git a/internal/fs/fs_local_test.go b/internal/fs/fs_local_test.go index f980d1c72..9602dfd28 100644 --- a/internal/fs/fs_local_test.go +++ b/internal/fs/fs_local_test.go @@ -61,7 +61,7 @@ func runFSLocalTestcase(t *testing.T, test fsLocalMetadataTestcase) { path := filepath.Join(tmp, "item") test.setup(t, path) - testFs := &Local{} + testFs := NewLocal() flags := 0 if !test.follow { flags |= O_NOFOLLOW @@ -124,7 +124,7 @@ func testFSLocalRead(t *testing.T, makeReadable bool) { } func openReadable(t *testing.T, path string, useMakeReadable bool) File { - testFs := &Local{} + testFs := NewLocal() f, err := testFs.OpenFile(path, O_NOFOLLOW, useMakeReadable) rtest.OK(t, err) if useMakeReadable { @@ -163,7 +163,7 @@ func TestFSLocalReadableRace(t *testing.T) { testdata := "example" rtest.OK(t, os.WriteFile(path, []byte(testdata), 0o600)) - testFs := &Local{} + testFs := NewLocal() f, err := testFs.OpenFile(path, O_NOFOLLOW, true) rtest.OK(t, err) @@ -189,7 +189,7 @@ func TestFSLocalTypeChange(t *testing.T) { testdata := "example" rtest.OK(t, os.WriteFile(path, []byte(testdata), 0o600)) - testFs := &Local{} + testFs := NewLocal() f, err := testFs.OpenFile(path, O_NOFOLLOW, true) rtest.OK(t, err) // cache metadata diff --git a/internal/fs/fs_local_vss.go b/internal/fs/fs_local_vss.go index e79c54d41..1dc5b771c 100644 --- a/internal/fs/fs_local_vss.go +++ b/internal/fs/fs_local_vss.go @@ -25,16 +25,11 @@ func init() { } } -// NewVSSConfig returns a new VSSConfig with the default values filled in. -func NewVSSConfig() VSSConfig { - return VSSConfig{ - Timeout: time.Second * 120, - } -} - // ParseVSSConfig parses a VSS extended options to VSSConfig struct. func ParseVSSConfig(o options.Options) (VSSConfig, error) { - cfg := NewVSSConfig() + cfg := VSSConfig{ + Timeout: time.Second * 120, + } o = o.Extract("vss") if err := o.Apply("vss", &cfg); err != nil { return VSSConfig{}, err @@ -49,14 +44,14 @@ type ErrorHandler func(item string, err error) // MessageHandler is used to report errors/messages via callbacks. type MessageHandler func(msg string, args ...interface{}) -// VolumeFilter is used to filter volumes by their mount point or GUID path. -type VolumeFilter func(volume string) bool +// volumeFilter is used to filter volumes by their mount point or GUID path. +type volumeFilter func(volume string) bool // LocalVss is a wrapper around the local file system which uses windows volume // shadow copy service (VSS) in a transparent way. type LocalVss struct { FS - snapshots map[string]VssSnapshot + snapshots map[string]vssSnapshot failedSnapshots map[string]struct{} mutex sync.RWMutex msgError ErrorHandler @@ -95,8 +90,8 @@ func parseMountPoints(list string, msgError ErrorHandler) (volumes map[string]st // shadow copy service to access locked files. func NewLocalVss(msgError ErrorHandler, msgMessage MessageHandler, cfg VSSConfig) *LocalVss { return &LocalVss{ - FS: Local{}, - snapshots: make(map[string]VssSnapshot), + FS: NewLocal(), + snapshots: make(map[string]vssSnapshot), failedSnapshots: make(map[string]struct{}), msgError: msgError, msgMessage: msgMessage, @@ -112,7 +107,7 @@ func (fs *LocalVss) DeleteSnapshots() { fs.mutex.Lock() defer fs.mutex.Unlock() - activeSnapshots := make(map[string]VssSnapshot) + activeSnapshots := make(map[string]vssSnapshot) for volumeName, snapshot := range fs.snapshots { if err := snapshot.Delete(); err != nil { @@ -190,14 +185,14 @@ func (fs *LocalVss) snapshotPath(path string) string { } else { fs.msgMessage("creating VSS snapshot for [%s]\n", vssVolume) - var includeVolume VolumeFilter + var includeVolume volumeFilter if !fs.excludeAllMountPoints { includeVolume = func(volume string) bool { return fs.isMountPointIncluded(volume) } } - if snapshot, err := NewVssSnapshot(fs.provider, vssVolume, fs.timeout, includeVolume, fs.msgError); err != nil { + if snapshot, err := newVssSnapshot(fs.provider, vssVolume, fs.timeout, includeVolume, fs.msgError); err != nil { fs.msgError(vssVolume, errors.Errorf("failed to create snapshot for [%s]: %s", vssVolume, err)) fs.failedSnapshots[volumeNameLower] = struct{}{} diff --git a/internal/fs/fs_reader.go b/internal/fs/fs_reader.go index a98a44de3..caf3be489 100644 --- a/internal/fs/fs_reader.go +++ b/internal/fs/fs_reader.go @@ -14,11 +14,7 @@ import ( "github.com/restic/restic/internal/errors" ) -// Reader is a file system which provides a directory with a single file. When -// this file is opened for reading, the reader is passed through. The file can -// be opened once, all subsequent open calls return syscall.EIO. For Lstat(), -// the provided FileInfo is returned. -type Reader struct { +type reader struct { items map[string]readerItem } @@ -40,9 +36,13 @@ type readerItem struct { } // statically ensure that Local implements FS. -var _ FS = &Reader{} +var _ FS = &reader{} -func NewReader(name string, r io.ReadCloser, opts ReaderOptions) (*Reader, error) { +// NewReader returns a new FS which provides a directory with a single file. When +// this file is opened for reading, the reader is passed through. The file can +// be opened once, all subsequent open calls return syscall.EIO. For Lstat(), +// the provided FileInfo is returned. +func NewReader(name string, r io.ReadCloser, opts ReaderOptions) (FS, error) { items := make(map[string]readerItem) name = readerCleanPath(name) if name == "/" { @@ -90,7 +90,7 @@ func NewReader(name string, r io.ReadCloser, opts ReaderOptions) (*Reader, error name = parent } - return &Reader{ + return &reader{ items: items, }, nil } @@ -101,11 +101,11 @@ func readerCleanPath(name string) string { // VolumeName returns leading volume name, for the Reader file system it's // always the empty string. -func (fs *Reader) VolumeName(_ string) string { +func (fs *reader) VolumeName(_ string) string { return "" } -func (fs *Reader) OpenFile(name string, flag int, _ bool) (f File, err error) { +func (fs *reader) OpenFile(name string, flag int, _ bool) (f File, err error) { if flag & ^(O_RDONLY|O_NOFOLLOW) != 0 { return nil, pathError("open", name, fmt.Errorf("invalid combination of flags 0x%x", flag)) @@ -141,7 +141,7 @@ func (fs *Reader) OpenFile(name string, flag int, _ bool) (f File, err error) { // Lstat returns the FileInfo structure describing the named file. // If there is an error, it will be of type *os.PathError. -func (fs *Reader) Lstat(name string) (*ExtendedFileInfo, error) { +func (fs *reader) Lstat(name string) (*ExtendedFileInfo, error) { name = readerCleanPath(name) item, ok := fs.items[name] if !ok { @@ -154,17 +154,17 @@ func (fs *Reader) Lstat(name string) (*ExtendedFileInfo, error) { // Separator if necessary. Join calls Clean on the result; in particular, all // empty strings are ignored. On Windows, the result is a UNC path if and only // if the first path element is a UNC path. -func (fs *Reader) Join(elem ...string) string { +func (fs *reader) Join(elem ...string) string { return path.Join(elem...) } // Separator returns the OS and FS dependent separator for dirs/subdirs/files. -func (fs *Reader) Separator() string { +func (fs *reader) Separator() string { return "/" } // IsAbs reports whether the path is absolute. For the Reader, this is always the case. -func (fs *Reader) IsAbs(_ string) bool { +func (fs *reader) IsAbs(_ string) bool { return true } @@ -174,22 +174,22 @@ func (fs *Reader) IsAbs(_ string) bool { // be unique. Abs calls Clean on the result. // // For the Reader, all paths are absolute. -func (fs *Reader) Abs(p string) (string, error) { +func (fs *reader) Abs(p string) (string, error) { return readerCleanPath(p), nil } // Clean returns the cleaned path. For details, see filepath.Clean. -func (fs *Reader) Clean(p string) string { +func (fs *reader) Clean(p string) string { return path.Clean(p) } // Base returns the last element of p. -func (fs *Reader) Base(p string) string { +func (fs *reader) Base(p string) string { return path.Base(p) } // Dir returns p without the last element. -func (fs *Reader) Dir(p string) string { +func (fs *reader) Dir(p string) string { return path.Dir(p) } diff --git a/internal/fs/fs_reader_command.go b/internal/fs/fs_reader_command.go index dabf54659..c2d359d92 100644 --- a/internal/fs/fs_reader_command.go +++ b/internal/fs/fs_reader_command.go @@ -10,10 +10,10 @@ import ( "github.com/restic/restic/internal/errors" ) -// CommandReader wraps a command such that its standard output can be read using +// commandReader wraps a command such that its standard output can be read using // a io.ReadCloser. Close() waits for the command to terminate, reporting // any error back to the caller. -type CommandReader struct { +type commandReader struct { cmd *exec.Cmd stdout io.ReadCloser @@ -28,7 +28,7 @@ type CommandReader struct { alreadyClosedReadErr error } -func NewCommandReader(ctx context.Context, args []string, errorOutput func(msg string, args ...interface{})) (*CommandReader, error) { +func NewCommandReader(ctx context.Context, args []string, errorOutput func(msg string, args ...interface{})) (io.ReadCloser, error) { if len(args) == 0 { return nil, fmt.Errorf("no command was specified as argument") } @@ -56,14 +56,14 @@ func NewCommandReader(ctx context.Context, args []string, errorOutput func(msg s return nil, fmt.Errorf("failed to start command: %w", err) } - return &CommandReader{ + return &commandReader{ cmd: command, stdout: stdout, }, nil } // Read populate the array with data from the process stdout. -func (fp *CommandReader) Read(p []byte) (int, error) { +func (fp *commandReader) Read(p []byte) (int, error) { if fp.alreadyClosedReadErr != nil { return 0, fp.alreadyClosedReadErr } @@ -83,7 +83,7 @@ func (fp *CommandReader) Read(p []byte) (int, error) { return b, err } -func (fp *CommandReader) wait() error { +func (fp *commandReader) wait() error { err := fp.cmd.Wait() if err != nil { // Use a fatal error to abort the snapshot. @@ -92,7 +92,7 @@ func (fp *CommandReader) wait() error { return nil } -func (fp *CommandReader) Close() error { +func (fp *commandReader) Close() error { if fp.waitHandled { return nil } diff --git a/internal/fs/node_test.go b/internal/fs/node_test.go index 806116288..50763fc06 100644 --- a/internal/fs/node_test.go +++ b/internal/fs/node_test.go @@ -23,7 +23,7 @@ func BenchmarkNodeFromFileInfo(t *testing.B) { path := tempfile.Name() rtest.OK(t, tempfile.Close()) - fs := Local{} + fs := NewLocal() f, err := fs.OpenFile(path, O_NOFOLLOW, true) rtest.OK(t, err) _, err = f.Stat() @@ -222,7 +222,7 @@ func TestNodeRestoreAt(t *testing.T) { rtest.OK(t, NodeRestoreMetadata(&test, nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) }, func(_ string) bool { return true }, ownershipByName)) - fs := &Local{} + fs := NewLocal() meta, err := fs.OpenFile(nodePath, O_NOFOLLOW, true) rtest.OK(t, err) n2, err := meta.ToNode(false, t.Logf) diff --git a/internal/fs/node_unix_test.go b/internal/fs/node_unix_test.go index 4489f8f12..6f861d91c 100644 --- a/internal/fs/node_unix_test.go +++ b/internal/fs/node_unix_test.go @@ -115,7 +115,7 @@ func TestNodeFromFileInfo(t *testing.T) { return } - fs := &Local{} + fs := NewLocal() meta, err := fs.OpenFile(test.filename, O_NOFOLLOW, true) rtest.OK(t, err) node, err := meta.ToNode(false, t.Logf) diff --git a/internal/fs/node_windows_test.go b/internal/fs/node_windows_test.go index 06c7bd4ef..5836dc382 100644 --- a/internal/fs/node_windows_test.go +++ b/internal/fs/node_windows_test.go @@ -390,7 +390,7 @@ func restoreAndGetNode(t *testing.T, tempDir string, testNode *data.Node, warnin }, func(_ string) bool { return true }, false) test.OK(t, errors.Wrapf(err, "Failed to restore metadata for: %s", testPath)) - fs := &Local{} + fs := NewLocal() meta, err := fs.OpenFile(testPath, O_NOFOLLOW, true) test.OK(t, err) nodeFromFileInfo, err := meta.ToNode(false, t.Logf) diff --git a/internal/fs/vss.go b/internal/fs/vss.go index 50337e76d..4ceab5624 100644 --- a/internal/fs/vss.go +++ b/internal/fs/vss.go @@ -8,23 +8,23 @@ import ( "github.com/restic/restic/internal/errors" ) -// MountPoint is a dummy for non-windows platforms to let client code compile. -type MountPoint struct { +// mountPoint is a dummy for non-windows platforms to let client code compile. +type mountPoint struct { } // IsSnapshotted is true if this mount point was snapshotted successfully. -func (p *MountPoint) IsSnapshotted() bool { +func (p *mountPoint) IsSnapshotted() bool { return false } // GetSnapshotDeviceObject returns root path to access the snapshot files and folders. -func (p *MountPoint) GetSnapshotDeviceObject() string { +func (p *mountPoint) GetSnapshotDeviceObject() string { return "" } -// VssSnapshot is a dummy for non-windows platforms to let client code compile. -type VssSnapshot struct { - mountPointInfo map[string]MountPoint +// vssSnapshot is a dummy for non-windows platforms to let client code compile. +type vssSnapshot struct { + mountPointInfo map[string]mountPoint } // HasSufficientPrivilegesForVSS returns nil if the user is allowed to use VSS. @@ -38,20 +38,20 @@ func getVolumeNameForVolumeMountPoint(mountPoint string) (string, error) { return mountPoint, nil } -// NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't +// newVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't // finish within the timeout an error is returned. -func NewVssSnapshot(_ string, - _ string, _ time.Duration, _ VolumeFilter, _ ErrorHandler) (VssSnapshot, error) { - return VssSnapshot{}, errors.New("VSS snapshots are only supported on windows") +func newVssSnapshot(_ string, + _ string, _ time.Duration, _ volumeFilter, _ ErrorHandler) (vssSnapshot, error) { + return vssSnapshot{}, errors.New("VSS snapshots are only supported on windows") } // Delete deletes the created snapshot. -func (p *VssSnapshot) Delete() error { +func (p *vssSnapshot) Delete() error { return nil } // GetSnapshotDeviceObject returns root path to access the snapshot files // and folders. -func (p *VssSnapshot) GetSnapshotDeviceObject() string { +func (p *vssSnapshot) GetSnapshotDeviceObject() string { return "" } diff --git a/internal/fs/vss_windows.go b/internal/fs/vss_windows.go index f29affd7f..01ca86774 100644 --- a/internal/fs/vss_windows.go +++ b/internal/fs/vss_windows.go @@ -518,7 +518,7 @@ func (vss *IVssBackupComponents) DeleteSnapshots(snapshotID ole.GUID) (int32, ol // GetSnapshotProperties calls the equivalent VSS api. func (vss *IVssBackupComponents) GetSnapshotProperties(snapshotID ole.GUID, - properties *VssSnapshotProperties) error { + properties *vssSnapshotProperties) error { var result uintptr if runtime.GOARCH == "386" { @@ -537,7 +537,7 @@ func (vss *IVssBackupComponents) GetSnapshotProperties(snapshotID ole.GUID, } // vssFreeSnapshotProperties calls the equivalent VSS api. -func vssFreeSnapshotProperties(properties *VssSnapshotProperties) error { +func vssFreeSnapshotProperties(properties *vssSnapshotProperties) error { proc, err := findVssProc("VssFreeSnapshotProperties") if err != nil { return err @@ -557,9 +557,9 @@ func (vss *IVssBackupComponents) BackupComplete() (*IVSSAsync, error) { return vss.convertToVSSAsync(oleIUnknown, err) } -// VssSnapshotProperties defines the properties of a VSS snapshot as part of the VSS api. +// vssSnapshotProperties defines the properties of a VSS snapshot as part of the VSS api. // nolint:structcheck -type VssSnapshotProperties struct { +type vssSnapshotProperties struct { snapshotID ole.GUID snapshotSetID ole.GUID snapshotsCount uint32 @@ -595,7 +595,7 @@ func vssFreeProviderProperties(p *VssProviderProperties) { // GetSnapshotDeviceObject returns root path to access the snapshot files // and folders. -func (p *VssSnapshotProperties) GetSnapshotDeviceObject() string { +func (p *vssSnapshotProperties) GetSnapshotDeviceObject() string { return ole.UTF16PtrToString(p.snapshotDeviceObject) } @@ -759,38 +759,38 @@ func (vssEnum *IVssEnumObject) Next(count uint, props unsafe.Pointer) (uint, err return uint(fetched), newVssErrorIfResultNotOK("Next() failed", HRESULT(result)) } -// MountPoint wraps all information of a snapshot of a mountpoint on a volume. -type MountPoint struct { +// mountPoint wraps all information of a snapshot of a mountpoint on a volume. +type mountPoint struct { isSnapshotted bool snapshotSetID ole.GUID - snapshotProperties VssSnapshotProperties + snapshotProperties vssSnapshotProperties snapshotDeviceObject string } // IsSnapshotted is true if this mount point was snapshotted successfully. -func (p *MountPoint) IsSnapshotted() bool { +func (p *mountPoint) IsSnapshotted() bool { return p.isSnapshotted } // GetSnapshotDeviceObject returns root path to access the snapshot files and folders. -func (p *MountPoint) GetSnapshotDeviceObject() string { +func (p *mountPoint) GetSnapshotDeviceObject() string { return p.snapshotDeviceObject } -// VssSnapshot wraps windows volume shadow copy api (vss) via a simple +// vssSnapshot wraps windows volume shadow copy api (vss) via a simple // interface to create and delete a vss snapshot. -type VssSnapshot struct { +type vssSnapshot struct { iVssBackupComponents *IVssBackupComponents snapshotID ole.GUID - snapshotProperties VssSnapshotProperties + snapshotProperties vssSnapshotProperties snapshotDeviceObject string - mountPointInfo map[string]MountPoint + mountPointInfo map[string]mountPoint timeout time.Duration } // GetSnapshotDeviceObject returns root path to access the snapshot files // and folders. -func (p *VssSnapshot) GetSnapshotDeviceObject() string { +func (p *vssSnapshot) GetSnapshotDeviceObject() string { return p.snapshotDeviceObject } @@ -883,18 +883,18 @@ func getVolumeNameForVolumeMountPoint(mountPoint string) (string, error) { return syscall.UTF16ToString(volumeNameBuffer), nil } -// NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't +// newVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't // finish within the timeout an error is returned. -func NewVssSnapshot(provider string, - volume string, timeout time.Duration, filter VolumeFilter, msgError ErrorHandler) (VssSnapshot, error) { +func newVssSnapshot(provider string, + volume string, timeout time.Duration, filter volumeFilter, msgError ErrorHandler) (vssSnapshot, error) { is64Bit, err := isRunningOn64BitWindows() if err != nil { - return VssSnapshot{}, newVssTextError(fmt.Sprintf( + return vssSnapshot{}, newVssTextError(fmt.Sprintf( "Failed to detect windows architecture: %s", err.Error())) } if (is64Bit && runtime.GOARCH != "amd64") || (!is64Bit && runtime.GOARCH != "386") { - return VssSnapshot{}, newVssTextError(fmt.Sprintf("executables compiled for %s can't use "+ + return vssSnapshot{}, newVssTextError(fmt.Sprintf("executables compiled for %s can't use "+ "VSS on other architectures. Please use an executable compiled for your platform.", runtime.GOARCH)) } @@ -906,12 +906,12 @@ func NewVssSnapshot(provider string, defer oleIUnknown.Release() } if err != nil { - return VssSnapshot{}, err + return vssSnapshot{}, err } comInterface, err := queryInterface(oleIUnknown, UUID_IVSS) if err != nil { - return VssSnapshot{}, err + return vssSnapshot{}, err } /* @@ -936,39 +936,39 @@ func NewVssSnapshot(provider string, providerID, err := getProviderID(provider) if err != nil { iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } if err := iVssBackupComponents.InitializeForBackup(); err != nil { iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } if err := iVssBackupComponents.SetContext(VSS_CTX_BACKUP); err != nil { iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } // see https://techcommunity.microsoft.com/t5/Storage-at-Microsoft/What-is-the-difference-between-VSS-Full-Backup-and-VSS-Copy/ba-p/423575 if err := iVssBackupComponents.SetBackupState(false, false, VSS_BT_COPY, false); err != nil { iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } err = callAsyncFunctionAndWait(iVssBackupComponents.GatherWriterMetadata, "GatherWriterMetadata", deadline) if err != nil { iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } if isSupported, err := iVssBackupComponents.IsVolumeSupported(providerID, volume); err != nil { iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } else if !isSupported { iVssBackupComponents.Release() - return VssSnapshot{}, newVssTextError(fmt.Sprintf("Snapshots are not supported for volume "+ + return vssSnapshot{}, newVssTextError(fmt.Sprintf("Snapshots are not supported for volume "+ "%s", volume)) } @@ -985,7 +985,7 @@ func NewVssSnapshot(provider string, if err != nil { iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } else { break } @@ -993,10 +993,10 @@ func NewVssSnapshot(provider string, if err := iVssBackupComponents.AddToSnapshotSet(volume, providerID, &snapshotSetID); err != nil { iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } - mountPointInfo := make(map[string]MountPoint) + mountPointInfo := make(map[string]mountPoint) // if filter==nil just don't process mount points for this volume at all if filter != nil { @@ -1004,32 +1004,32 @@ func NewVssSnapshot(provider string, if err != nil { iVssBackupComponents.Release() - return VssSnapshot{}, newVssTextError(fmt.Sprintf( + return vssSnapshot{}, newVssTextError(fmt.Sprintf( "failed to enumerate mount points for volume %s: %s", volume, err)) } - for _, mountPoint := range mountPoints { + for _, mp := range mountPoints { // ensure every mountpoint is available even without a valid // snapshot because we need to consider this when backing up files - mountPointInfo[mountPoint] = MountPoint{isSnapshotted: false} + mountPointInfo[mp] = mountPoint{isSnapshotted: false} - if !filter(mountPoint) { + if !filter(mp) { continue - } else if isSupported, err := iVssBackupComponents.IsVolumeSupported(providerID, mountPoint); err != nil { + } else if isSupported, err := iVssBackupComponents.IsVolumeSupported(providerID, mp); err != nil { continue } else if !isSupported { continue } var mountPointSnapshotSetID ole.GUID - err := iVssBackupComponents.AddToSnapshotSet(mountPoint, providerID, &mountPointSnapshotSetID) + err := iVssBackupComponents.AddToSnapshotSet(mp, providerID, &mountPointSnapshotSetID) if err != nil { iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } - mountPointInfo[mountPoint] = MountPoint{ + mountPointInfo[mp] = mountPoint{ isSnapshotted: true, snapshotSetID: mountPointSnapshotSetID, } @@ -1044,7 +1044,7 @@ func NewVssSnapshot(provider string, // It is not necessary to call BackupComplete before releasing the VSS instance afterwards. iVssBackupComponents.AbortBackup() iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } err = callAsyncFunctionAndWait(iVssBackupComponents.DoSnapshotSet, "DoSnapshotSet", @@ -1052,15 +1052,15 @@ func NewVssSnapshot(provider string, if err != nil { _ = iVssBackupComponents.AbortBackup() iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } - var snapshotProperties VssSnapshotProperties + var snapshotProperties vssSnapshotProperties err = iVssBackupComponents.GetSnapshotProperties(snapshotSetID, &snapshotProperties) if err != nil { _ = iVssBackupComponents.AbortBackup() iVssBackupComponents.Release() - return VssSnapshot{}, err + return vssSnapshot{}, err } for mountPoint, info := range mountPointInfo { @@ -1082,14 +1082,14 @@ func NewVssSnapshot(provider string, mountPointInfo[mountPoint] = info } - return VssSnapshot{ + return vssSnapshot{ iVssBackupComponents, snapshotSetID, snapshotProperties, snapshotProperties.GetSnapshotDeviceObject(), mountPointInfo, time.Until(deadline), }, nil } // Delete deletes the created snapshot. -func (p *VssSnapshot) Delete() error { +func (p *vssSnapshot) Delete() error { var err error if err = vssFreeSnapshotProperties(&p.snapshotProperties); err != nil { return err diff --git a/internal/repository/checker.go b/internal/repository/checker.go index 351dbc247..04beb1ed4 100644 --- a/internal/repository/checker.go +++ b/internal/repository/checker.go @@ -79,8 +79,8 @@ type Checker struct { repo *Repository } -// NewChecker creates a new Checker. -func NewChecker(repo *Repository) *Checker { +// newChecker creates a new Checker. +func newChecker(repo *Repository) *Checker { return &Checker{ repo: repo, } diff --git a/internal/repository/checker_test.go b/internal/repository/checker_test.go index c1a71408c..9710d62d1 100644 --- a/internal/repository/checker_test.go +++ b/internal/repository/checker_test.go @@ -159,7 +159,7 @@ func setupChecker(t *testing.T, wrap func(backend.Backend) backend.Backend) *Che // Re-open the same backend (now containing real pack files) through // the corruption wrapper so the checker reads corrupted data. checkRepo := TestOpenBackend(t, wrap(be)) - chkr := NewChecker(checkRepo) + chkr := newChecker(checkRepo) // make sure the index is loaded err := checkRepo.LoadIndex(context.TODO(), nil) diff --git a/internal/repository/key.go b/internal/repository/key.go index 08f997544..374c984fb 100644 --- a/internal/repository/key.go +++ b/internal/repository/key.go @@ -61,8 +61,8 @@ func createMasterKey(ctx context.Context, s *Repository, password string) (*Key, return AddKey(ctx, s, password, "", "", nil) } -// OpenKey tries do decrypt the key specified by name with the given password. -func OpenKey(ctx context.Context, s *Repository, id restic.ID, password string) (*Key, error) { +// openKey tries do decrypt the key specified by name with the given password. +func openKey(ctx context.Context, s *Repository, id restic.ID, password string) (*Key, error) { k, err := LoadKey(ctx, s, id) if err != nil { debug.Log("LoadKey(%v) returned error %v", id.String(), err) @@ -108,18 +108,18 @@ func OpenKey(ctx context.Context, s *Repository, id restic.ID, password string) return k, nil } -// SearchKey tries to decrypt at most maxKeys keys in the backend with the +// searchKey tries to decrypt at most maxKeys keys in the backend with the // given password. If none could be found, ErrNoKeyFound is returned. When // maxKeys is reached, ErrMaxKeysReached is returned. When setting maxKeys to // zero, all keys in the repo are checked. -func SearchKey(ctx context.Context, s *Repository, password string, maxKeys int, keyHint string) (k *Key, err error) { +func searchKey(ctx context.Context, s *Repository, password string, maxKeys int, keyHint string) (k *Key, err error) { checked := 0 if len(keyHint) > 0 { id, err := restic.Find(ctx, s, restic.KeyFile, keyHint) if err == nil { - key, err := OpenKey(ctx, s, id, password) + key, err := openKey(ctx, s, id, password) if err == nil { debug.Log("successfully opened hinted key %v", id) @@ -143,7 +143,7 @@ func SearchKey(ctx context.Context, s *Repository, password string, maxKeys int, } debug.Log("trying key %q", id.String()) - key, err := OpenKey(ctx, s, id, password) + key, err := openKey(ctx, s, id, password) if err != nil { debug.Log("key %v returned error %v", id.String(), err) diff --git a/internal/repository/lock.go b/internal/repository/lock.go index a50195233..d794f03e7 100644 --- a/internal/repository/lock.go +++ b/internal/repository/lock.go @@ -37,13 +37,13 @@ var lockerInst = &locker{ refreshabilityTimeout: restic.StaleLockTimeout - defaultRefreshInterval*3/2, } -func Lock(ctx context.Context, repo *Repository, exclusive bool, retryLock time.Duration, printRetry func(msg string), logger func(format string, args ...interface{})) (*Unlocker, context.Context, error) { +func Lock(ctx context.Context, repo *Repository, exclusive bool, retryLock time.Duration, printRetry func(msg string), logger func(format string, args ...interface{})) (Unlocker, context.Context, error) { return lockerInst.Lock(ctx, repo, exclusive, retryLock, printRetry, logger) } // Lock wraps the ctx such that it is cancelled when the repository is unlocked // cancelling the original context also stops the lock refresh -func (l *locker) Lock(ctx context.Context, r *Repository, exclusive bool, retryLock time.Duration, printRetry func(msg string), logger func(format string, args ...interface{})) (*Unlocker, context.Context, error) { +func (l *locker) Lock(ctx context.Context, r *Repository, exclusive bool, retryLock time.Duration, printRetry func(msg string), logger func(format string, args ...interface{})) (Unlocker, context.Context, error) { var lock *restic.Lock var err error @@ -102,7 +102,7 @@ retryLoop: go l.refreshLocks(ctx, repo.be, lockInfo, refreshChan, forceRefreshChan, logger) go l.monitorLockRefresh(ctx, lockInfo, refreshChan, forceRefreshChan, logger) - return &Unlocker{lockInfo}, ctx, nil + return &unlocker{lockInfo}, ctx, nil } func minDuration(a, b time.Duration) time.Duration { @@ -261,11 +261,15 @@ func tryRefreshStaleLock(ctx context.Context, be backend.Backend, lock *restic.L return true } -type Unlocker struct { +type Unlocker interface { + Unlock() +} + +type unlocker struct { info *lockContext } -func (l *Unlocker) Unlock() { +func (l *unlocker) Unlock() { l.info.cancel() l.info.refreshWG.Wait() } diff --git a/internal/repository/lock_test.go b/internal/repository/lock_test.go index c31221e42..bdfb6573b 100644 --- a/internal/repository/lock_test.go +++ b/internal/repository/lock_test.go @@ -34,11 +34,11 @@ func openLockTestRepo(t *testing.T, wrapper backendWrapper) (*Repository, backen return TestOpenBackend(t, be), be } -func checkedLockRepo(ctx context.Context, t *testing.T, repo *Repository, lockerInst *locker, retryLock time.Duration) (*Unlocker, context.Context) { +func checkedLockRepo(ctx context.Context, t *testing.T, repo *Repository, lockerInst *locker, retryLock time.Duration) (Unlocker, context.Context) { lock, wrappedCtx, err := lockerInst.Lock(ctx, repo, false, retryLock, func(msg string) {}, func(format string, args ...interface{}) {}) rtest.OK(t, err) rtest.OK(t, wrappedCtx.Err()) - if lock.info.lock.Stale() { + if lock.(*unlocker).info.lock.Stale() { t.Fatal("lock returned stale lock") } return lock, wrappedCtx diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 828559f3b..121d8c5a1 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -180,7 +180,7 @@ func (r *Repository) SetDryRun() { } func (r *Repository) Checker() *Checker { - return NewChecker(r) + return newChecker(r) } // LoadUnpacked loads and decrypts the file with the given type and ID. @@ -862,7 +862,7 @@ func (r *Repository) prepareCache() error { // SearchKey finds a key with the supplied password, afterwards the config is // read and parsed. It tries at most maxKeys key files in the repo. func (r *Repository) SearchKey(ctx context.Context, password string, maxKeys int, keyHint string) error { - key, err := SearchKey(ctx, r, password, maxKeys, keyHint) + key, err := searchKey(ctx, r, password, maxKeys, keyHint) if err != nil { return err } diff --git a/internal/repository/testing.go b/internal/repository/testing.go index 1cdca4110..3aabc02d2 100644 --- a/internal/repository/testing.go +++ b/internal/repository/testing.go @@ -165,7 +165,7 @@ func TestNewLock(_ *testing.T, repo *Repository, exclusive bool) (*restic.Lock, // TestCheckRepo runs the checker on repo. func TestCheckRepo(t testing.TB, repo *Repository) { - chkr := NewChecker(repo) + chkr := newChecker(repo) hints, errs := chkr.LoadIndex(context.TODO(), nil) if len(errs) != 0 { diff --git a/internal/repository/warmup.go b/internal/repository/warmup.go index eca46692a..ef78ddaf4 100644 --- a/internal/repository/warmup.go +++ b/internal/repository/warmup.go @@ -7,18 +7,18 @@ import ( "github.com/restic/restic/internal/restic" ) -type WarmupJob struct { +type warmupJob struct { repo *Repository handlesWarmingUp []backend.Handle } // HandleCount returns the number of handles that are currently warming up. -func (job *WarmupJob) HandleCount() int { +func (job *warmupJob) HandleCount() int { return len(job.handlesWarmingUp) } // Wait waits for all handles to be warm. -func (job *WarmupJob) Wait(ctx context.Context) error { +func (job *warmupJob) Wait(ctx context.Context) error { return job.repo.be.WarmupWait(ctx, job.handlesWarmingUp) } @@ -32,7 +32,7 @@ func (r *Repository) StartWarmup(ctx context.Context, packs restic.IDSet) (resti ) } handlesWarmingUp, err := r.be.Warmup(ctx, handles) - return &WarmupJob{ + return &warmupJob{ repo: r, handlesWarmingUp: handlesWarmingUp, }, err diff --git a/internal/restorer/hardlinks_index.go b/internal/restorer/hardlinks_index.go index 0fe426694..ec6c33a50 100644 --- a/internal/restorer/hardlinks_index.go +++ b/internal/restorer/hardlinks_index.go @@ -4,21 +4,21 @@ import ( "sync" ) -// HardlinkKey is a composed key for finding inodes on a specific device. -type HardlinkKey struct { +// hardlinkKey is a composed key for finding inodes on a specific device. +type hardlinkKey struct { Inode, Device uint64 } // HardlinkIndex maps inodes on devices to associated values. type HardlinkIndex[T any] struct { m sync.Mutex - Index map[HardlinkKey]T + index map[hardlinkKey]T } // NewHardlinkIndex create a new index for hard links func NewHardlinkIndex[T any]() *HardlinkIndex[T] { return &HardlinkIndex[T]{ - Index: make(map[HardlinkKey]T), + index: make(map[hardlinkKey]T), } } @@ -26,7 +26,7 @@ func NewHardlinkIndex[T any]() *HardlinkIndex[T] { func (idx *HardlinkIndex[T]) Has(inode uint64, device uint64) bool { idx.m.Lock() defer idx.m.Unlock() - _, ok := idx.Index[HardlinkKey{inode, device}] + _, ok := idx.index[hardlinkKey{inode, device}] return ok } @@ -35,10 +35,10 @@ func (idx *HardlinkIndex[T]) Has(inode uint64, device uint64) bool { func (idx *HardlinkIndex[T]) Add(inode uint64, device uint64, value T) { idx.m.Lock() defer idx.m.Unlock() - _, ok := idx.Index[HardlinkKey{inode, device}] + _, ok := idx.index[hardlinkKey{inode, device}] if !ok { - idx.Index[HardlinkKey{inode, device}] = value + idx.index[hardlinkKey{inode, device}] = value } } @@ -46,12 +46,12 @@ func (idx *HardlinkIndex[T]) Add(inode uint64, device uint64, value T) { func (idx *HardlinkIndex[T]) Value(inode uint64, device uint64) T { idx.m.Lock() defer idx.m.Unlock() - return idx.Index[HardlinkKey{inode, device}] + return idx.index[hardlinkKey{inode, device}] } // Remove removes a link from the index. func (idx *HardlinkIndex[T]) Remove(inode uint64, device uint64) { idx.m.Lock() defer idx.m.Unlock() - delete(idx.Index, HardlinkKey{inode, device}) + delete(idx.index, hardlinkKey{inode, device}) } diff --git a/internal/restorer/restorer.go b/internal/restorer/restorer.go index ffcd13808..19693d82d 100644 --- a/internal/restorer/restorer.go +++ b/internal/restorer/restorer.go @@ -489,7 +489,7 @@ func (res *Restorer) removeUnexpectedFiles(ctx context.Context, target, location panic("internal error") } - entries, err := fs.Readdirnames(fs.Local{}, target, fs.O_NOFOLLOW) + entries, err := fs.Readdirnames(fs.NewLocal(), target, fs.O_NOFOLLOW) if errors.Is(err, os.ErrNotExist) { return nil } else if err != nil { diff --git a/internal/restorer/restorer_test.go b/internal/restorer/restorer_test.go index ef4533578..4c0c610d3 100644 --- a/internal/restorer/restorer_test.go +++ b/internal/restorer/restorer_test.go @@ -1537,7 +1537,7 @@ func TestRestorerLongPath(t *testing.T) { repo := repository.TestRepository(t) - local := &fs.Local{} + local := fs.NewLocal() sc := archiver.NewScanner(local) rtest.OK(t, sc.Scan(context.TODO(), []string{tmp})) arch := archiver.New(repo, local, archiver.Options{})