From 8072b999a61745b7a350ad6d94f16b1277534ba8 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sun, 3 Nov 2024 16:38:34 +0100 Subject: [PATCH] fs: add file handle helpers --- internal/fs/meta_darwin.go | 25 +++++++++++++++++++++++++ internal/fs/meta_linux.go | 25 +++++++++++++++++++++++++ internal/fs/meta_windows.go | 23 +++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 internal/fs/meta_darwin.go create mode 100644 internal/fs/meta_linux.go diff --git a/internal/fs/meta_darwin.go b/internal/fs/meta_darwin.go new file mode 100644 index 000000000..d7b28db2c --- /dev/null +++ b/internal/fs/meta_darwin.go @@ -0,0 +1,25 @@ +package fs + +import ( + "os" + + "golang.org/x/sys/unix" +) + +func openMetadataHandle(path string, flag int) (*os.File, error) { + flags := O_RDONLY + if flag&O_NOFOLLOW != 0 { + // open symlink instead of following it + flags |= unix.O_SYMLINK + } + if flag&O_DIRECTORY != 0 { + flags |= O_DIRECTORY + } + + f, err := os.OpenFile(path, flags, 0) + if err != nil { + return nil, err + } + _ = setFlags(f) + return f, nil +} diff --git a/internal/fs/meta_linux.go b/internal/fs/meta_linux.go new file mode 100644 index 000000000..a8165fa0a --- /dev/null +++ b/internal/fs/meta_linux.go @@ -0,0 +1,25 @@ +package fs + +import ( + "os" + + "golang.org/x/sys/unix" +) + +func openMetadataHandle(path string, flag int) (*os.File, error) { + // O_PATH|O_NOFOLLOW is necessary to also be able to get a handle to symlinks + flags := unix.O_PATH + if flag&O_NOFOLLOW != 0 { + flags |= O_NOFOLLOW + } + if flag&O_DIRECTORY != 0 { + flags |= O_DIRECTORY + } + + f, err := os.OpenFile(path, flags, 0) + if err != nil { + return nil, err + } + _ = setFlags(f) + return f, nil +} diff --git a/internal/fs/meta_windows.go b/internal/fs/meta_windows.go index c8a1e5bed..24822c0f1 100644 --- a/internal/fs/meta_windows.go +++ b/internal/fs/meta_windows.go @@ -1,6 +1,9 @@ package fs import ( + "os" + "syscall" + "github.com/restic/restic/internal/debug" "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/restic" @@ -58,3 +61,23 @@ func (p *fdMetadataHandle) SecurityDescriptor() (*[]byte, error) { // FIXME return getSecurityDescriptor(p.name) } + +func openMetadataHandle(path string, flag int) (*os.File, error) { + path = fixpath(path) + // OpenFile from go does not request FILE_READ_EA so we need our own low-level implementation + // according to the windows docs, STANDARD_RIGHTS_READ + FILE_FLAG_BACKUP_SEMANTICS disable security checks on access + // if the process holds the SeBackupPrivilege + fileAccess := windows.FILE_READ_EA | windows.FILE_READ_ATTRIBUTES | windows.STANDARD_RIGHTS_READ + shareMode := windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_DELETE + attrs := windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_BACKUP_SEMANTICS + if flag&O_NOFOLLOW != 0 { + attrs |= syscall.FILE_FLAG_OPEN_REPARSE_POINT + } + + utf16Path := windows.StringToUTF16Ptr(path) + handle, err := windows.CreateFile(utf16Path, uint32(fileAccess), uint32(shareMode), nil, windows.OPEN_EXISTING, uint32(attrs), 0) + if err != nil { + return nil, err + } + return os.NewFile(uintptr(handle), path), nil +}