diff --git a/internal/restorer/restorer.go b/internal/restorer/restorer.go index 641b05877..160497110 100644 --- a/internal/restorer/restorer.go +++ b/internal/restorer/restorer.go @@ -197,6 +197,12 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) error { } } + // make sure the target directory exists + err = fs.MkdirAll(dst, 0777) // umask takes care of dir permissions + if err != nil { + return errors.Wrap(err, "MkdirAll") + } + idx := restic.NewHardlinkIndex() return res.traverseTree(ctx, dst, string(filepath.Separator), *res.sn.Tree, treeVisitor{ enterDir: func(node *restic.Node, target, location string) error { diff --git a/internal/restorer/restorer_test.go b/internal/restorer/restorer_test.go index 4fde75edd..b57b6f409 100644 --- a/internal/restorer/restorer_test.go +++ b/internal/restorer/restorer_test.go @@ -202,6 +202,16 @@ func TestRestorer(t *testing.T) { "dir/file": "file in dir", }, }, + { + Snapshot: Snapshot{ + Nodes: map[string]Node{ + "topfile": File{"top-level file"}, + }, + }, + Files: map[string]string{ + "topfile": "top-level file", + }, + }, // test cases with invalid/constructed names { @@ -273,6 +283,9 @@ func TestRestorer(t *testing.T) { tempdir, cleanup := rtest.TempDir(t) defer cleanup() + // make sure we're creating a new subdir of the tempdir + tempdir = filepath.Join(tempdir, "target") + res.SelectFilter = func(item, dstpath string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool) { t.Logf("restore %v to %v", item, dstpath) if !fs.HasPathPrefix(tempdir, dstpath) {