mirror of
https://github.com/restic/restic.git
synced 2025-08-12 11:57:56 +00:00
restore: New --verify flag to verify restored files content
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
This commit is contained in:
@@ -2,8 +2,10 @@ package restorer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/restic/restic/internal/crypto"
|
||||
"github.com/restic/restic/internal/errors"
|
||||
|
||||
"github.com/restic/restic/internal/debug"
|
||||
@@ -218,3 +220,51 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) error {
|
||||
func (res *Restorer) Snapshot() *restic.Snapshot {
|
||||
return res.sn
|
||||
}
|
||||
|
||||
// VerifyFiles reads all snapshot files and verifies their contents
|
||||
func (res *Restorer) VerifyFiles(ctx context.Context, dst string) (int, error) {
|
||||
// TODO multithreaded?
|
||||
|
||||
count := 0
|
||||
err := res.traverseTree(ctx, dst, string(filepath.Separator), *res.sn.Tree, treeVisitor{
|
||||
enterDir: func(node *restic.Node, target, location string) error { return nil },
|
||||
visitNode: func(node *restic.Node, target, location string) error {
|
||||
if node.Type != "file" {
|
||||
return nil
|
||||
}
|
||||
|
||||
count++
|
||||
stat, err := os.Stat(target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if int64(node.Size) != stat.Size() {
|
||||
return errors.Errorf("Invalid file size: expected %d got %d", node.Size, stat.Size())
|
||||
}
|
||||
|
||||
offset := int64(0)
|
||||
for _, blobID := range node.Content {
|
||||
rd, err := os.Open(target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
blobs, _ := res.repo.Index().Lookup(blobID, restic.DataBlob)
|
||||
length := blobs[0].Length - uint(crypto.Extension)
|
||||
buf := make([]byte, length) // TODO do I want to reuse the buffer somehow?
|
||||
_, err = rd.ReadAt(buf, offset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !blobID.Equal(restic.Hash(buf)) {
|
||||
return errors.Errorf("Unexpected contents starting at offset %d", offset)
|
||||
}
|
||||
offset += int64(length)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
leaveDir: func(node *restic.Node, target, location string) error { return nil },
|
||||
})
|
||||
|
||||
return count, err
|
||||
}
|
||||
|
Reference in New Issue
Block a user