From 44924ba043eb3367ef29a69c6694c716031cd83b Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sat, 21 Jul 2018 22:39:12 +0200 Subject: [PATCH] restorer: Fix traverseTree traverseTree() was meant to call enterDir() whenever a directory is selected for restore, either explicitly or implicitly (=contains a file which is to be restored). After restoring a file, leaveDir() is called in reverse order for all intermediate directories so that the metadata can be restored. When a directory is selected implicitly, the metadata for it is restored. This is different from the previous restorer behavior, which created implicitly selected intermediate directories with permissions 0700 (only user can read/write it). This commit changes the behavior back to the old one. Only a directory is explicitly selected for restore, enterDir()/leaveDir() are called for it. Otherwise, only visitNode() is called, so visitNode() needs to make sure the parent directory exists. If the directory is explicitly included, leaveDir() will then restore the metadata correctly. When we decide to change the behavior (restore metadata for all intermediate directories, even if selected implicitly), we should do that in the selection functions, not here. This finally resolves #1870 --- internal/restorer/restorer.go | 45 +++++++++++------------------------ 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/internal/restorer/restorer.go b/internal/restorer/restorer.go index 160497110..73e844ac0 100644 --- a/internal/restorer/restorer.go +++ b/internal/restorer/restorer.go @@ -99,36 +99,16 @@ func (res *Restorer) traverseTree(ctx context.Context, target, location string, return err } - enteredDir := false if node.Type == "dir" { if node.Subtree == nil { return errors.Errorf("Dir without subtree in tree %v", treeID.Str()) } - // ifedorenko: apparently a dir can be selected explicitly or implicitly when a child is selected - // to support implicit selection, visit the directory from within visitor#visitNode if selectedForRestore { - enteredDir = true err = sanitizeError(visitor.enterDir(node, nodeTarget, nodeLocation)) if err != nil { return err } - } else { - _visitor := visitor - visitor = treeVisitor{ - enterDir: _visitor.enterDir, - visitNode: func(node *restic.Node, nodeTarget, nodeLocation string) error { - if !enteredDir { - enteredDir = true - derr := sanitizeError(_visitor.enterDir(node, nodeTarget, nodeLocation)) - if derr != nil { - return derr - } - } - return _visitor.visitNode(node, nodeTarget, nodeLocation) - }, - leaveDir: _visitor.leaveDir, - } } if childMayBeSelected { @@ -137,25 +117,21 @@ func (res *Restorer) traverseTree(ctx context.Context, target, location string, return err } } - } - if selectedForRestore && node.Type != "dir" { - err = sanitizeError(visitor.visitNode(node, nodeTarget, nodeLocation)) - if err != nil { - err = res.Error(nodeLocation, node, errors.Wrap(err, "restoreNodeTo")) + if selectedForRestore { + err = sanitizeError(visitor.leaveDir(node, nodeTarget, nodeLocation)) if err != nil { return err } } + + continue } - if enteredDir { - err = sanitizeError(visitor.leaveDir(node, nodeTarget, nodeLocation)) + if selectedForRestore { + err = sanitizeError(visitor.visitNode(node, nodeTarget, nodeLocation)) if err != nil { - err = res.Error(nodeLocation, node, errors.Wrap(err, "RestoreTimestamps")) - if err != nil { - return err - } + return err } } } @@ -211,6 +187,13 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) error { return fs.MkdirAll(target, 0700) }, visitNode: func(node *restic.Node, target, location string) error { + // create parent dir with default permissions + // #leaveDir restores dir metadata after visiting all children + err := fs.MkdirAll(filepath.Dir(target), 0700) + if err != nil { + return err + } + return res.restoreNodeTo(ctx, node, target, location, idx) }, leaveDir: func(node *restic.Node, target, location string) error {