2
2
mirror of https://github.com/octoleo/restic.git synced 2024-12-23 19:38:57 +00:00

restore: let filerestorer also handle empty files

This get's rid of the corresponding special cases.
This commit is contained in:
Michael Eischer 2024-05-30 23:06:15 +02:00
parent c166ad7daf
commit 30320a249a
3 changed files with 26 additions and 40 deletions

View File

@ -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

View File

@ -206,6 +206,10 @@ func TestFileRestorerBasic(t *testing.T) {
{"data3-1", "pack3-1"},
},
},
{
name: "empty",
blobs: []TestBlob{},
},
}, nil, sparse)
}
}

View File

@ -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)
}