diff --git a/cmd/restic/cmd_find.go b/cmd/restic/cmd_find.go index 92e88203f..2e06fa00c 100644 --- a/cmd/restic/cmd_find.go +++ b/cmd/restic/cmd_find.go @@ -336,6 +336,26 @@ func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error }}) } +func (f *Finder) findTree(treeID restic.ID, nodepath string) error { + found := false + if _, ok := f.treeIDs[treeID.String()]; ok { + found = true + } else if _, ok := f.treeIDs[treeID.Str()]; ok { + found = true + } + if found { + f.out.PrintObject("tree", treeID.String(), nodepath, "", f.out.newsn) + f.itemsFound++ + // Terminate if we have found all trees (and we are not + // looking for blobs) + if f.itemsFound >= len(f.treeIDs) && f.blobIDs == nil { + // Return an error to terminate the Walk + return errors.New("OK") + } + } + return nil +} + func (f *Finder) findIDs(ctx context.Context, sn *restic.Snapshot) error { debug.Log("searching IDs in snapshot %s", sn.ID()) @@ -354,26 +374,17 @@ func (f *Finder) findIDs(ctx context.Context, sn *restic.Snapshot) error { } if node == nil { + if nodepath == "/" { + if err := f.findTree(parentTreeID, "/"); err != nil { + return err + } + } return nil } - if node.Type == restic.NodeTypeDir && f.treeIDs != nil { - treeID := node.Subtree - found := false - if _, ok := f.treeIDs[treeID.Str()]; ok { - found = true - } else if _, ok := f.treeIDs[treeID.String()]; ok { - found = true - } - if found { - f.out.PrintObject("tree", treeID.String(), nodepath, "", sn) - f.itemsFound++ - // Terminate if we have found all trees (and we are not - // looking for blobs) - if f.itemsFound >= len(f.treeIDs) && f.blobIDs == nil { - // Return an error to terminate the Walk - return errors.New("OK") - } + if node.Type == "dir" && f.treeIDs != nil { + if err := f.findTree(*node.Subtree, nodepath); err != nil { + return err } } diff --git a/cmd/restic/cmd_find_integration_test.go b/cmd/restic/cmd_find_integration_test.go index dd8ab87fd..9d8c09464 100644 --- a/cmd/restic/cmd_find_integration_test.go +++ b/cmd/restic/cmd_find_integration_test.go @@ -10,11 +10,10 @@ import ( rtest "github.com/restic/restic/internal/test" ) -func testRunFind(t testing.TB, wantJSON bool, gopts GlobalOptions, pattern string) []byte { +func testRunFind(t testing.TB, wantJSON bool, opts FindOptions, gopts GlobalOptions, pattern string) []byte { buf, err := withCaptureStdout(func() error { gopts.JSON = wantJSON - opts := FindOptions{} return runFind(context.TODO(), opts, gopts, []string{pattern}) }) rtest.OK(t, err) @@ -31,14 +30,14 @@ func TestFind(t *testing.T) { testRunBackup(t, "", []string{env.testdata}, opts, env.gopts) testRunCheck(t, env.gopts) - results := testRunFind(t, false, env.gopts, "unexistingfile") + results := testRunFind(t, false, FindOptions{}, env.gopts, "unexistingfile") rtest.Assert(t, len(results) == 0, "unexisting file found in repo (%v)", datafile) - results = testRunFind(t, false, env.gopts, "testfile") + results = testRunFind(t, false, FindOptions{}, env.gopts, "testfile") lines := strings.Split(string(results), "\n") rtest.Assert(t, len(lines) == 2, "expected one file found in repo (%v)", datafile) - results = testRunFind(t, false, env.gopts, "testfile*") + results = testRunFind(t, false, FindOptions{}, env.gopts, "testfile*") lines = strings.Split(string(results), "\n") rtest.Assert(t, len(lines) == 4, "expected three files found in repo (%v)", datafile) } @@ -67,21 +66,29 @@ func TestFindJSON(t *testing.T) { testRunBackup(t, "", []string{env.testdata}, opts, env.gopts) testRunCheck(t, env.gopts) + snapshot, _ := testRunSnapshots(t, env.gopts) - results := testRunFind(t, true, env.gopts, "unexistingfile") + results := testRunFind(t, true, FindOptions{}, env.gopts, "unexistingfile") matches := []testMatches{} rtest.OK(t, json.Unmarshal(results, &matches)) rtest.Assert(t, len(matches) == 0, "expected no match in repo (%v)", datafile) - results = testRunFind(t, true, env.gopts, "testfile") + results = testRunFind(t, true, FindOptions{}, env.gopts, "testfile") rtest.OK(t, json.Unmarshal(results, &matches)) rtest.Assert(t, len(matches) == 1, "expected a single snapshot in repo (%v)", datafile) rtest.Assert(t, len(matches[0].Matches) == 1, "expected a single file to match (%v)", datafile) rtest.Assert(t, matches[0].Hits == 1, "expected hits to show 1 match (%v)", datafile) - results = testRunFind(t, true, env.gopts, "testfile*") + results = testRunFind(t, true, FindOptions{}, env.gopts, "testfile*") rtest.OK(t, json.Unmarshal(results, &matches)) rtest.Assert(t, len(matches) == 1, "expected a single snapshot in repo (%v)", datafile) rtest.Assert(t, len(matches[0].Matches) == 3, "expected 3 files to match (%v)", datafile) rtest.Assert(t, matches[0].Hits == 3, "expected hits to show 3 matches (%v)", datafile) + + results = testRunFind(t, true, FindOptions{TreeID: true}, env.gopts, snapshot.Tree.String()) + rtest.OK(t, json.Unmarshal(results, &matches)) + rtest.Assert(t, len(matches) == 1, "expected a single snapshot in repo (%v)", matches) + rtest.Assert(t, len(matches[0].Matches) == 3, "expected 3 files to match (%v)", matches[0].Matches) + rtest.Assert(t, matches[0].Hits == 3, "expected hits to show 3 matches (%v)", datafile) } +