mirror of
https://github.com/restic/restic.git
synced 2025-03-30 00:00:14 +01:00
89 lines
3.1 KiB
Go
89 lines
3.1 KiB
Go
//go:build !windows
|
|
// +build !windows
|
|
|
|
package restorer
|
|
|
|
import (
|
|
"os"
|
|
"syscall"
|
|
|
|
"github.com/restic/restic/internal/errors"
|
|
"github.com/restic/restic/internal/fs"
|
|
)
|
|
|
|
// OpenFile opens the file with create, truncate and write only options if
|
|
// createSize is specified greater than 0 i.e. if the file hasn't already
|
|
// been created. Otherwise it opens the file with only write only option.
|
|
func (fw *filesWriter) OpenFile(createSize int64, path string, fileInfo *fileInfo) (file *os.File, err error) {
|
|
return fw.openFile(createSize, path, fileInfo)
|
|
}
|
|
|
|
// OpenFile opens the file with create, truncate and write only options if
|
|
// createSize is specified greater than 0 i.e. if the file hasn't already
|
|
// 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)
|
|
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 {
|
|
return nil, err
|
|
}
|
|
file, err = openFileWithTruncWrite(path)
|
|
}
|
|
} else {
|
|
flags := os.O_WRONLY
|
|
file, err = os.OpenFile(path, flags, 0600)
|
|
}
|
|
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
|
|
}
|
|
|
|
func createOrOpenFile(path string, createSize int64, fileInfo *fileInfo, allowRecursiveDelete bool) (*os.File, error) {
|
|
if createSize >= 0 {
|
|
return createFile(path, createSize, fileInfo, allowRecursiveDelete)
|
|
}
|
|
return openFile(path)
|
|
}
|
|
|
|
func createFile(path string, createSize int64, fileInfo *fileInfo, allowRecursiveDelete bool) (*os.File, error) {
|
|
f, err := fs.OpenFile(path, fs.O_CREATE|fs.O_WRONLY|fs.O_NOFOLLOW, 0600)
|
|
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(path); 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)
|
|
}
|