From f880ff21aa7f176403a5364fd1d423b1dc82727e Mon Sep 17 00:00:00 2001 From: Loic Nageleisen Date: Fri, 7 Jul 2017 11:54:10 +0200 Subject: [PATCH] Fixing restore with excluded An exclude filter is basically a 'wildcard but foo', so even if a childMayMatch, other children of a dir may not, therefore childMayMatch does not matter, but we should not go down unless the dir is selected for restore. --- cmd/restic/cmd_restore.go | 20 +++++++++++++++----- internal/restic/restorer.go | 8 ++++---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/cmd/restic/cmd_restore.go b/cmd/restic/cmd_restore.go index a8fed66a4..ae54ec457 100644 --- a/cmd/restic/cmd_restore.go +++ b/cmd/restic/cmd_restore.go @@ -113,22 +113,32 @@ func runRestore(opts RestoreOptions, gopts GlobalOptions, args []string) error { return nil } - selectExcludeFilter := func(item string, dstpath string, node *restic.Node) (bool, bool) { - matched, childMayMatch, err := filter.List(opts.Exclude, item) + selectExcludeFilter := func(item string, dstpath string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool) { + matched, _, err := filter.List(opts.Exclude, item) if err != nil { Warnf("error for exclude pattern: %v", err) } - return !matched, childMayMatch + // An exclude filter is basically a 'wildcard but foo', + // so even if a childMayMatch, other children of a dir may not, + // therefore childMayMatch does not matter, but we should not go down + // unless the dir is selected for restore + selectedForRestore = !matched + childMayBeSelected = selectedForRestore && node.Type == "dir" + + return selectedForRestore, childMayBeSelected } - selectIncludeFilter := func(item string, dstpath string, node *restic.Node) (bool, bool) { + selectIncludeFilter := func(item string, dstpath string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool) { matched, childMayMatch, err := filter.List(opts.Include, item) if err != nil { Warnf("error for include pattern: %v", err) } - return matched, childMayMatch + selectedForRestore = matched + childMayBeSelected = childMayMatch && node.Type == "dir" + + return selectedForRestore, childMayBeSelected } if len(opts.Exclude) > 0 { diff --git a/internal/restic/restorer.go b/internal/restic/restorer.go index 252a4640b..9aafd5063 100644 --- a/internal/restic/restorer.go +++ b/internal/restic/restorer.go @@ -17,7 +17,7 @@ type Restorer struct { sn *Snapshot Error func(dir string, node *Node, err error) error - SelectFilter func(item string, dstpath string, node *Node) (bool, bool) + SelectFilter func(item string, dstpath string, node *Node) (selectedForRestore bool, childMayBeSelected bool) } var restorerAbortOnAllErrors = func(str string, node *Node, err error) error { return err } @@ -46,9 +46,9 @@ func (res *Restorer) restoreTo(ctx context.Context, dst string, dir string, tree } for _, node := range tree.Nodes { - selectedForRestore, childMayMatch := res.SelectFilter(filepath.Join(dir, node.Name), + selectedForRestore, childMayBeSelected := res.SelectFilter(filepath.Join(dir, node.Name), filepath.Join(dst, dir, node.Name), node) - debug.Log("SelectFilter returned %v %v", selectedForRestore, childMayMatch) + debug.Log("SelectFilter returned %v %v", selectedForRestore, childMayBeSelected) if selectedForRestore { err := res.restoreNodeTo(ctx, node, dir, dst, idx) @@ -57,7 +57,7 @@ func (res *Restorer) restoreTo(ctx context.Context, dst string, dir string, tree } } - if node.Type == "dir" && childMayMatch { + if node.Type == "dir" && childMayBeSelected { if node.Subtree == nil { return errors.Errorf("Dir without subtree in tree %v", treeID.Str()) }