forked from TrueCloudLab/restic
restorer: allow directory to replace existing file
This commit is contained in:
parent
ac729db3ce
commit
ebbd4e26d7
2 changed files with 21 additions and 7 deletions
|
@ -259,6 +259,23 @@ func (res *Restorer) restoreHardlinkAt(node *restic.Node, target, path, location
|
||||||
return res.restoreNodeMetadataTo(node, path, location)
|
return res.restoreNodeMetadataTo(node, path, location)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (res *Restorer) ensureDir(target string) error {
|
||||||
|
fi, err := fs.Lstat(target)
|
||||||
|
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
|
return fmt.Errorf("failed to check for directory: %w", err)
|
||||||
|
}
|
||||||
|
if err == nil && !fi.IsDir() {
|
||||||
|
// try to cleanup unexpected file
|
||||||
|
if err := fs.Remove(target); err != nil {
|
||||||
|
return fmt.Errorf("failed to remove stale item: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create parent dir with default permissions
|
||||||
|
// second pass #leaveDir restores dir metadata after visiting/restoring all children
|
||||||
|
return fs.MkdirAll(target, 0700)
|
||||||
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
|
@ -284,17 +301,12 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) error {
|
||||||
enterDir: func(_ *restic.Node, target, location string) error {
|
enterDir: func(_ *restic.Node, target, location string) error {
|
||||||
debug.Log("first pass, enterDir: mkdir %q, leaveDir should restore metadata", location)
|
debug.Log("first pass, enterDir: mkdir %q, leaveDir should restore metadata", location)
|
||||||
res.opts.Progress.AddFile(0)
|
res.opts.Progress.AddFile(0)
|
||||||
// create dir with default permissions
|
return res.ensureDir(target)
|
||||||
// #leaveDir restores dir metadata after visiting all children
|
|
||||||
return fs.MkdirAll(target, 0700)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
visitNode: func(node *restic.Node, target, location string) error {
|
visitNode: func(node *restic.Node, target, location string) error {
|
||||||
debug.Log("first pass, visitNode: mkdir %q, leaveDir on second pass should restore metadata", location)
|
debug.Log("first pass, visitNode: mkdir %q, leaveDir on second pass should restore metadata", location)
|
||||||
// create parent dir with default permissions
|
if err := res.ensureDir(filepath.Dir(target)); err != nil {
|
||||||
// second pass #leaveDir restores dir metadata after visiting/restoring all children
|
|
||||||
err := fs.MkdirAll(filepath.Dir(target), 0700)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1040,6 +1040,7 @@ func TestRestorerOverwriteSpecial(t *testing.T) {
|
||||||
"link": Symlink{Target: "foo", ModTime: baseTime},
|
"link": Symlink{Target: "foo", ModTime: baseTime},
|
||||||
"file": File{Data: "content: file\n", Inode: 42, Links: 2, ModTime: baseTime},
|
"file": File{Data: "content: file\n", Inode: 42, Links: 2, ModTime: baseTime},
|
||||||
"hardlink": File{Data: "content: file\n", Inode: 42, Links: 2, ModTime: baseTime},
|
"hardlink": File{Data: "content: file\n", Inode: 42, Links: 2, ModTime: baseTime},
|
||||||
|
"newdir": File{Data: "content: dir\n", ModTime: baseTime},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
overwriteSnapshot := Snapshot{
|
overwriteSnapshot := Snapshot{
|
||||||
|
@ -1048,6 +1049,7 @@ func TestRestorerOverwriteSpecial(t *testing.T) {
|
||||||
"link": File{Data: "content: link\n", Inode: 42, Links: 2, ModTime: baseTime.Add(time.Second)},
|
"link": File{Data: "content: link\n", Inode: 42, Links: 2, ModTime: baseTime.Add(time.Second)},
|
||||||
"file": Symlink{Target: "foo2", ModTime: baseTime},
|
"file": Symlink{Target: "foo2", ModTime: baseTime},
|
||||||
"hardlink": File{Data: "content: link\n", Inode: 42, Links: 2, ModTime: baseTime.Add(time.Second)},
|
"hardlink": File{Data: "content: link\n", Inode: 42, Links: 2, ModTime: baseTime.Add(time.Second)},
|
||||||
|
"newdir": Dir{ModTime: baseTime},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue