summaryrefslogtreecommitdiff
path: root/internal/restorer/restorer.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/restorer/restorer.go')
-rw-r--r--internal/restorer/restorer.go52
1 files changed, 46 insertions, 6 deletions
diff --git a/internal/restorer/restorer.go b/internal/restorer/restorer.go
index 4dfe3c3a8..3c60aca1b 100644
--- a/internal/restorer/restorer.go
+++ b/internal/restorer/restorer.go
@@ -10,6 +10,7 @@ import (
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic"
+ restoreui "github.com/restic/restic/internal/ui/restore"
"golang.org/x/sync/errgroup"
)
@@ -20,6 +21,8 @@ type Restorer struct {
sn *restic.Snapshot
sparse bool
+ progress *restoreui.Progress
+
Error func(location string, err error) error
SelectFilter func(item string, dstpath string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool)
}
@@ -27,12 +30,14 @@ type Restorer struct {
var restorerAbortOnAllErrors = func(location string, err error) error { return err }
// NewRestorer creates a restorer preloaded with the content from the snapshot id.
-func NewRestorer(ctx context.Context, repo restic.Repository, sn *restic.Snapshot, sparse bool) *Restorer {
+func NewRestorer(repo restic.Repository, sn *restic.Snapshot, sparse bool,
+ progress *restoreui.Progress) *Restorer {
r := &Restorer{
repo: repo,
sparse: sparse,
Error: restorerAbortOnAllErrors,
SelectFilter: func(string, string, *restic.Node) (bool, bool) { return true, true },
+ progress: progress,
sn: sn,
}
@@ -161,12 +166,14 @@ func (res *Restorer) restoreNodeTo(ctx context.Context, node *restic.Node, targe
err := node.CreateAt(ctx, target, res.repo)
if err != nil {
debug.Log("node.CreateAt(%s) error %v", target, err)
+ return err
}
- if err == nil {
- err = res.restoreNodeMetadataTo(node, target, location)
+
+ if res.progress != nil {
+ res.progress.AddProgress(location, 0, 0)
}
- return err
+ return res.restoreNodeMetadataTo(node, target, location)
}
func (res *Restorer) restoreNodeMetadataTo(node *restic.Node, target, location string) error {
@@ -186,6 +193,11 @@ func (res *Restorer) restoreHardlinkAt(node *restic.Node, target, path, location
if err != nil {
return errors.WithStack(err)
}
+
+ if res.progress != nil {
+ res.progress.AddProgress(location, 0, 0)
+ }
+
// TODO investigate if hardlinks have separate metadata on any supported system
return res.restoreNodeMetadataTo(node, path, location)
}
@@ -200,6 +212,10 @@ func (res *Restorer) restoreEmptyFileAt(node *restic.Node, target, location stri
return err
}
+ if res.progress != nil {
+ res.progress.AddProgress(location, 0, 0)
+ }
+
return res.restoreNodeMetadataTo(node, target, location)
}
@@ -215,7 +231,8 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) error {
}
idx := NewHardlinkIndex()
- filerestorer := newFileRestorer(dst, res.repo.Backend().Load, res.repo.Key(), res.repo.Index().Lookup, res.repo.Connections(), res.sparse)
+ filerestorer := newFileRestorer(dst, res.repo.Backend().Load, res.repo.Key(), res.repo.Index().Lookup,
+ res.repo.Connections(), res.sparse, res.progress)
filerestorer.Error = res.Error
debug.Log("first pass for %q", dst)
@@ -224,6 +241,9 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) error {
_, err = res.traverseTree(ctx, dst, string(filepath.Separator), *res.sn.Tree, treeVisitor{
enterDir: func(node *restic.Node, target, location string) error {
debug.Log("first pass, enterDir: mkdir %q, leaveDir should restore metadata", location)
+ if res.progress != nil {
+ res.progress.AddFile(0)
+ }
// create dir with default permissions
// #leaveDir restores dir metadata after visiting all children
return fs.MkdirAll(target, 0700)
@@ -239,20 +259,34 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) error {
}
if node.Type != "file" {
+ if res.progress != nil {
+ res.progress.AddFile(0)
+ }
return nil
}
if node.Size == 0 {
+ if res.progress != nil {
+ res.progress.AddFile(node.Size)
+ }
return nil // deal with empty files later
}
if node.Links > 1 {
if idx.Has(node.Inode, node.DeviceID) {
+ if res.progress != nil {
+ // a hardlinked file does not increase the restore size
+ res.progress.AddFile(0)
+ }
return nil
}
idx.Add(node.Inode, node.DeviceID, location)
}
+ if res.progress != nil {
+ res.progress.AddFile(node.Size)
+ }
+
filerestorer.addFile(location, node.Content, int64(node.Size))
return nil
@@ -291,7 +325,13 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) error {
return res.restoreNodeMetadataTo(node, target, location)
},
- leaveDir: res.restoreNodeMetadataTo,
+ leaveDir: func(node *restic.Node, target, location string) error {
+ err := res.restoreNodeMetadataTo(node, target, location)
+ if err == nil && res.progress != nil {
+ res.progress.AddProgress(location, 0, 0)
+ }
+ return err
+ },
})
return err
}