forked from TrueCloudLab/restic
restore: let filerestorer also handle empty files
This get's rid of the corresponding special cases.
This commit is contained in:
parent
c166ad7daf
commit
30320a249a
3 changed files with 26 additions and 40 deletions
|
@ -120,6 +120,13 @@ func (r *fileRestorer) restoreFiles(ctx context.Context) error {
|
|||
// create packInfo from fileInfo
|
||||
for _, file := range r.files {
|
||||
fileBlobs := file.blobs.(restic.IDs)
|
||||
if len(fileBlobs) == 0 {
|
||||
err := r.restoreEmptyFileAt(file.location)
|
||||
if errFile := r.sanitizeError(file, err); errFile != nil {
|
||||
return errFile
|
||||
}
|
||||
}
|
||||
|
||||
largeFile := len(fileBlobs) > largeFileBlobCount
|
||||
var packsMap map[restic.ID][]fileBlobInfo
|
||||
if largeFile {
|
||||
|
@ -195,6 +202,21 @@ func (r *fileRestorer) restoreFiles(ctx context.Context) error {
|
|||
return wg.Wait()
|
||||
}
|
||||
|
||||
func (r *fileRestorer) restoreEmptyFileAt(location string) error {
|
||||
f, err := createFile(r.targetPath(location), 0, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.progress != nil {
|
||||
r.progress.AddProgress(location, 0, 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type blobToFileOffsetsMapping map[restic.ID]struct {
|
||||
files map[*fileInfo][]int64 // file -> offsets (plural!) of the blob in the file
|
||||
blob restic.Blob
|
||||
|
|
|
@ -206,6 +206,10 @@ func TestFileRestorerBasic(t *testing.T) {
|
|||
{"data3-1", "pack3-1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
blobs: []TestBlob{},
|
||||
},
|
||||
}, nil, sparse)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,31 +203,6 @@ func (res *Restorer) restoreHardlinkAt(node *restic.Node, target, path, location
|
|||
return res.restoreNodeMetadataTo(node, path, location)
|
||||
}
|
||||
|
||||
func (res *Restorer) restoreEmptyFileAt(node *restic.Node, target, location string) error {
|
||||
wr, err := os.OpenFile(target, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
|
||||
if fs.IsAccessDenied(err) {
|
||||
// If file is readonly, clear the readonly flag by resetting the
|
||||
// permissions of the file and try again
|
||||
// as the metadata will be set again in the second pass and the
|
||||
// readonly flag will be applied again if needed.
|
||||
if err = fs.ResetPermissions(target); err != nil {
|
||||
return err
|
||||
}
|
||||
if wr, err = os.OpenFile(target, os.O_TRUNC|os.O_WRONLY, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = wr.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res.progress != nil {
|
||||
res.progress.AddProgress(location, 0, 0)
|
||||
}
|
||||
|
||||
return res.restoreNodeMetadataTo(node, target, location)
|
||||
}
|
||||
|
||||
// RestoreTo creates the directories and files in the snapshot below dst.
|
||||
// Before an item is created, res.Filter is called.
|
||||
func (res *Restorer) RestoreTo(ctx context.Context, dst string) error {
|
||||
|
@ -274,13 +249,6 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) error {
|
|||
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 {
|
||||
|
@ -320,14 +288,6 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) error {
|
|||
return res.restoreNodeTo(ctx, node, target, location)
|
||||
}
|
||||
|
||||
// create empty files, but not hardlinks to empty files
|
||||
if node.Size == 0 && (node.Links < 2 || !idx.Has(node.Inode, node.DeviceID)) {
|
||||
if node.Links > 1 {
|
||||
idx.Add(node.Inode, node.DeviceID, location)
|
||||
}
|
||||
return res.restoreEmptyFileAt(node, target, location)
|
||||
}
|
||||
|
||||
if idx.Has(node.Inode, node.DeviceID) && idx.Value(node.Inode, node.DeviceID) != location {
|
||||
return res.restoreHardlinkAt(node, filerestorer.targetPath(idx.Value(node.Inode, node.DeviceID)), target, location)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue