diff --git a/internal/restorer/fileswriter.go b/internal/restorer/fileswriter.go index cbe89c30c..5e4931c63 100644 --- a/internal/restorer/fileswriter.go +++ b/internal/restorer/fileswriter.go @@ -39,6 +39,48 @@ func newFilesWriter(count int) *filesWriter { } } +func createFile(path string, createSize int64, sparse bool) (*os.File, error) { + var f *os.File + var err error + if f, err = os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600); err != nil { + if !fs.IsAccessDenied(err) { + return nil, 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(path); err != nil { + return nil, err + } + if f, err = os.OpenFile(path, os.O_TRUNC|os.O_WRONLY, 0600); err != nil { + return nil, err + } + } + + if createSize > 0 { + if sparse { + err = truncateSparse(f, createSize) + if err != nil { + _ = f.Close() + return nil, err + } + } else { + err := fs.PreallocateFile(f, createSize) + if err != nil { + // Just log the preallocate error but don't let it cause the restore process to fail. + // Preallocate might return an error if the filesystem (implementation) does not + // support preallocation or our parameters combination to the preallocate call + // This should yield a syscall.ENOTSUP error, but some other errors might also + // show up. + debug.Log("Failed to preallocate %v with size %v: %v", path, createSize, err) + } + } + } + return f, err +} + func (w *filesWriter) writeToFile(path string, blob []byte, offset int64, createSize int64, sparse bool) error { bucket := &w.buckets[uint(xxhash.Sum64String(path))%uint(len(w.buckets))] @@ -53,21 +95,9 @@ func (w *filesWriter) writeToFile(path string, blob []byte, offset int64, create var f *os.File var err error if createSize >= 0 { - if f, err = os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600); err != nil { - 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(path); err != nil { - return nil, err - } - if f, err = os.OpenFile(path, os.O_TRUNC|os.O_WRONLY, 0600); err != nil { - return nil, err - } - } else { - return nil, err - } + f, err = createFile(path, createSize, sparse) + if err != nil { + return nil, err } } else if f, err = os.OpenFile(path, os.O_WRONLY, 0600); err != nil { return nil, err @@ -76,25 +106,6 @@ func (w *filesWriter) writeToFile(path string, blob []byte, offset int64, create wr := &partialFile{File: f, users: 1, sparse: sparse} bucket.files[path] = wr - if createSize >= 0 { - if sparse { - err = truncateSparse(f, createSize) - if err != nil { - return nil, err - } - } else { - err := fs.PreallocateFile(wr.File, createSize) - if err != nil { - // Just log the preallocate error but don't let it cause the restore process to fail. - // Preallocate might return an error if the filesystem (implementation) does not - // support preallocation or our parameters combination to the preallocate call - // This should yield a syscall.ENOTSUP error, but some other errors might also - // show up. - debug.Log("Failed to preallocate %v with size %v: %v", path, createSize, err) - } - } - } - return wr, nil }