diff --git a/internal/restorer/fileswriter_unix.go b/internal/restorer/fileswriter_unix.go index 554a4ab5a..159168aab 100644 --- a/internal/restorer/fileswriter_unix.go +++ b/internal/restorer/fileswriter_unix.go @@ -23,37 +23,30 @@ func (fw *filesWriter) OpenFile(createSize int64, path string, fileInfo *fileInf // been created. Otherwise it opens the file with only write only option. func (fw *filesWriter) openFile(createSize int64, path string, _ *fileInfo) (file *os.File, err error) { if createSize >= 0 { - file, err = openFileWithCreate(path) + file, err = fs.OpenFile(path, fs.O_CREATE|fs.O_WRONLY|fs.O_NOFOLLOW, 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. - err = fs.ResetPermissions(path) - if err != nil { + if err = fs.ResetPermissions(path); err != nil { return nil, err } - file, err = openFileWithTruncWrite(path) + if file, err = fs.OpenFile(path, fs.O_WRONLY|fs.O_NOFOLLOW, 0600); err != nil { + return nil, err + } + } else if err != nil && (errors.Is(err, syscall.ELOOP) || errors.Is(err, syscall.EISDIR)) { + // symlink or directory, try to remove it later on + file = nil + } else if err != nil { + return nil, err } } else { - flags := os.O_WRONLY - file, err = os.OpenFile(path, flags, 0600) + file, err = openFile(path) } return file, err } -// openFileWithCreate opens the file with os.O_CREATE flag along with os.O_TRUNC and os.O_WRONLY. -func openFileWithCreate(path string) (file *os.File, err error) { - flags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY - return os.OpenFile(path, flags, 0600) -} - -// openFileWithTruncWrite opens the file without os.O_CREATE flag along with os.O_TRUNC and os.O_WRONLY. -func openFileWithTruncWrite(path string) (file *os.File, err error) { - flags := os.O_TRUNC | os.O_WRONLY - return os.OpenFile(path, flags, 0600) -} - // CleanupPath performs clean up for the specified path. func CleanupPath(_ string) { // no-op diff --git a/internal/restorer/fileswriter_windows.go b/internal/restorer/fileswriter_windows.go index fccc93425..6a53cee5f 100644 --- a/internal/restorer/fileswriter_windows.go +++ b/internal/restorer/fileswriter_windows.go @@ -27,26 +27,30 @@ import ( // less streams, then the extra streams need to be removed from the main file. The stream names are present // as the value in the generic attribute TypeHasAds. func createOrOpenFile(path string, createSize int64, fileInfo *fileInfo, allowRecursiveDelete bool) (*os.File, error) { - var mainPath string - mainPath, f, err := openFileImpl(path, createSize, fileInfo) - if err != nil && 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(mainPath); err != nil { + if createSize >= 0 { + var mainPath string + mainPath, f, err := openFileImpl(path, createSize, fileInfo) + if err != nil && 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(mainPath); err != nil { + return nil, err + } + if f, err = fs.OpenFile(path, fs.O_WRONLY|fs.O_NOFOLLOW, 0600); err != nil { + return nil, err + } + } else if err != nil && (errors.Is(err, syscall.ELOOP) || errors.Is(err, syscall.EISDIR)) { + // symlink or directory, try to remove it later on + f = nil + } else if err != nil { return nil, err } - if f, err = fs.OpenFile(path, fs.O_WRONLY|fs.O_NOFOLLOW, 0600); err != nil { - return nil, err - } - } else if err != nil && (errors.Is(err, syscall.ELOOP) || errors.Is(err, syscall.EISDIR)) { - // symlink or directory, try to remove it later on - f = nil - } else if err != nil { - return nil, err + return postCreateFile(f, path, createSize, allowRecursiveDelete, fileInfo.sparse) + } else { + return openFile(path) } - return postCreateFile(f, path, createSize, allowRecursiveDelete, fileInfo.sparse) } // openFileImpl is the actual open file implementation. @@ -122,7 +126,7 @@ func handleCreateFileNonAds(path string, fileIn *os.File, isAlreadyExists bool) return fileIn, nil } else { // If the non-ads file did not exist, try creating the file with create flag. - return os.OpenFile(path, fs.O_CREATE|fs.O_WRONLY|fs.O_NOFOLLOW, 0600) + return fs.OpenFile(path, fs.O_CREATE|fs.O_WRONLY|fs.O_NOFOLLOW, 0600) } } @@ -137,7 +141,7 @@ func handleCreateFileAds(path string, fileIn *os.File, hasAds, isAds, isAlreadyE // If the ads related file did not exist, first check if it is a hasAds or isAds if isAds { // If it is an ads file, then we can simple open it with create options without worrying about overwriting. - return os.OpenFile(path, fs.O_CREATE|fs.O_WRONLY|fs.O_NOFOLLOW, 0600) + return fs.OpenFile(path, fs.O_CREATE|fs.O_WRONLY|fs.O_NOFOLLOW, 0600) } if hasAds { // If it is the main file which has ads files attached, we will check again if the main file wasn't created @@ -148,7 +152,7 @@ func handleCreateFileAds(path string, fileIn *os.File, hasAds, isAds, isAlreadyE // We confirmed that the main file still doesn't exist after syncing. // Hence creating the file with the create flag. // Directly open the main file with create option as it should not be encrypted. - return os.OpenFile(path, fs.O_CREATE|fs.O_WRONLY|fs.O_NOFOLLOW, 0600) + return fs.OpenFile(path, fs.O_CREATE|fs.O_WRONLY|fs.O_NOFOLLOW, 0600) } else { // Some other error occured so stop processing and return it. return nil, err diff --git a/internal/restorer/restorer_test.go b/internal/restorer/restorer_test.go index 83ea0dc41..586ef7bbc 100644 --- a/internal/restorer/restorer_test.go +++ b/internal/restorer/restorer_test.go @@ -83,7 +83,6 @@ type Dir struct { Mode os.FileMode ModTime time.Time attributes *FileAttributes - isAds bool hasAds bool }