2
2
mirror of https://github.com/octoleo/restic.git synced 2024-12-22 10:58:55 +00:00

restore: Fix restore to relative path

This commit is contained in:
Alexander Neumann 2017-11-26 18:36:48 +01:00
parent f178cbf93d
commit 0f5e38609f
2 changed files with 107 additions and 0 deletions

View File

@ -67,6 +67,7 @@ func (res *Restorer) restoreTo(ctx context.Context, target, location string, tre
nodeLocation := filepath.Join(location, nodeName) nodeLocation := filepath.Join(location, nodeName)
if target == nodeTarget || !fs.HasPathPrefix(target, nodeTarget) { if target == nodeTarget || !fs.HasPathPrefix(target, nodeTarget) {
debug.Log("target: %v %v", target, nodeTarget)
debug.Log("node %q has invalid target path %q", node.Name, nodeTarget) debug.Log("node %q has invalid target path %q", node.Name, nodeTarget)
err := res.Error(nodeLocation, node, errors.New("node has invalid path")) err := res.Error(nodeLocation, node, errors.New("node has invalid path"))
if err != nil { if err != nil {
@ -145,6 +146,14 @@ func (res *Restorer) restoreNodeTo(ctx context.Context, node *Node, target, loca
// RestoreTo creates the directories and files in the snapshot below dst. // RestoreTo creates the directories and files in the snapshot below dst.
// Before an item is created, res.Filter is called. // Before an item is created, res.Filter is called.
func (res *Restorer) RestoreTo(ctx context.Context, dst string) error { func (res *Restorer) RestoreTo(ctx context.Context, dst string) error {
var err error
if !filepath.IsAbs(dst) {
dst, err = filepath.Abs(dst)
if err != nil {
return errors.Wrap(err, "Abs")
}
}
idx := NewHardlinkIndex() idx := NewHardlinkIndex()
return res.restoreTo(ctx, dst, string(filepath.Separator), *res.sn.Tree, idx) return res.restoreTo(ctx, dst, string(filepath.Separator), *res.sn.Tree, idx)
} }

View File

@ -310,3 +310,101 @@ func TestRestorer(t *testing.T) {
}) })
} }
} }
func chdir(t testing.TB, target string) func() {
prev, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
t.Logf("chdir to %v", target)
err = os.Chdir(target)
if err != nil {
t.Fatal(err)
}
return func() {
t.Logf("chdir back to %v", prev)
err = os.Chdir(prev)
if err != nil {
t.Fatal(err)
}
}
}
func TestRestorerRelative(t *testing.T) {
var tests = []struct {
Snapshot
Files map[string]string
}{
{
Snapshot: Snapshot{
Nodes: map[string]Node{
"foo": File{"content: foo\n"},
"dirtest": Dir{
Nodes: map[string]Node{
"file": File{"content: file\n"},
},
},
},
},
Files: map[string]string{
"foo": "content: foo\n",
"dirtest/file": "content: file\n",
},
},
}
for _, test := range tests {
t.Run("", func(t *testing.T) {
repo, cleanup := repository.TestRepository(t)
defer cleanup()
_, id := saveSnapshot(t, repo, test.Snapshot)
t.Logf("snapshot saved as %v", id.Str())
res, err := restic.NewRestorer(repo, id)
if err != nil {
t.Fatal(err)
}
tempdir, cleanup := rtest.TempDir(t)
defer cleanup()
cleanup = chdir(t, tempdir)
defer cleanup()
errors := make(map[string]string)
res.Error = func(dir string, node *restic.Node, err error) error {
t.Logf("restore returned error for %q in dir %v: %v", node.Name, dir, err)
dir = toSlash(dir)
errors[dir+"#"+node.Name] = err.Error()
return nil
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
err = res.RestoreTo(ctx, "restore")
if err != nil {
t.Fatal(err)
}
for filename, err := range errors {
t.Errorf("unexpected error for %v found: %v", filename, err)
}
for filename, content := range test.Files {
data, err := ioutil.ReadFile(filepath.Join(tempdir, "restore", filepath.FromSlash(filename)))
if err != nil {
t.Errorf("unable to read file %v: %v", filename, err)
continue
}
if !bytes.Equal(data, []byte(content)) {
t.Errorf("file %v has wrong content: want %q, got %q", filename, content, data)
}
}
})
}
}