1
0
Fork 0
mirror of https://github.com/restic/restic.git synced 2025-01-03 05:35:43 +00:00

Address review comments

This commit is contained in:
aneesh-n 2024-08-04 10:23:39 -06:00
parent 8c8a066c0e
commit 9dedba6dfc
No known key found for this signature in database
GPG key ID: 6F5A52831C046F44
2 changed files with 55 additions and 67 deletions

View file

@ -53,16 +53,6 @@ var (
errInvalidEaBuffer = errors.New("invalid extended attribute buffer") errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
errEaNameTooLarge = errors.New("extended attribute name too large") errEaNameTooLarge = errors.New("extended attribute name too large")
errEaValueTooLarge = errors.New("extended attribute value too large") errEaValueTooLarge = errors.New("extended attribute value too large")
kernel32dll = syscall.NewLazyDLL("kernel32.dll")
procGetVolumeInformationW = kernel32dll.NewProc("GetVolumeInformationW")
)
const (
// fileSupportsExtendedAttributes is a bitmask that indicates whether the file system supports extended attributes.
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_fs_attribute_information
fileSupportsExtendedAttributes = 0x00800000
) )
// ExtendedAttribute represents a single Windows EA. // ExtendedAttribute represents a single Windows EA.
@ -295,32 +285,16 @@ func setFileEA(handle windows.Handle, iosb *ioStatusBlock, buf *uint8, bufLen ui
} }
// PathSupportsExtendedAttributes returns true if the path supports extended attributes. // PathSupportsExtendedAttributes returns true if the path supports extended attributes.
func PathSupportsExtendedAttributes(path string) (bool, error) { func PathSupportsExtendedAttributes(path string) (supported bool, err error) {
var ( var fileSystemFlags uint32
volumeName [syscall.MAX_PATH + 1]uint16
fsName [syscall.MAX_PATH + 1]uint16
volumeSerial uint32
maxComponentLen uint32
fileSystemFlags uint32
)
utf16Path, err := windows.UTF16PtrFromString(path) utf16Path, err := windows.UTF16PtrFromString(path)
if err != nil { if err != nil {
return false, err return false, err
} }
ret, _, err := procGetVolumeInformationW.Call( err = windows.GetVolumeInformation(utf16Path, nil, 0, nil, nil, &fileSystemFlags, nil, 0)
uintptr(unsafe.Pointer(utf16Path)), if err != nil {
uintptr(unsafe.Pointer(&volumeName[0])),
uintptr(len(volumeName)),
uintptr(unsafe.Pointer(&volumeSerial)),
uintptr(unsafe.Pointer(&maxComponentLen)),
uintptr(unsafe.Pointer(&fileSystemFlags)),
uintptr(unsafe.Pointer(&fsName[0])),
uintptr(len(fsName)),
)
if ret == 0 {
return false, err return false, err
} }
supported = (fileSystemFlags & windows.FILE_SUPPORTS_EXTENDED_ATTRIBUTES) != 0
supportsEAs := (fileSystemFlags & fileSupportsExtendedAttributes) != 0 return supported, nil
return supportsEAs, nil
} }

View file

@ -8,6 +8,7 @@ import (
"reflect" "reflect"
"runtime" "runtime"
"strings" "strings"
"sync"
"syscall" "syscall"
"unsafe" "unsafe"
@ -33,8 +34,8 @@ var (
procEncryptFile = modAdvapi32.NewProc("EncryptFileW") procEncryptFile = modAdvapi32.NewProc("EncryptFileW")
procDecryptFile = modAdvapi32.NewProc("DecryptFileW") procDecryptFile = modAdvapi32.NewProc("DecryptFileW")
// eaUnsupportedVolumesMap is a map of volumes that do not support extended attributes. // eaSupportedVolumesMap is a map of volumes to boolean values indicating if they support extended attributes.
eaUnsupportedVolumesMap = map[string]bool{} eaSupportedVolumesMap = sync.Map{}
) )
// mknod is not supported on Windows. // mknod is not supported on Windows.
@ -354,45 +355,58 @@ func decryptFile(pathPointer *uint16) error {
} }
// fillGenericAttributes fills in the generic attributes for windows like File Attributes, // fillGenericAttributes fills in the generic attributes for windows like File Attributes,
// Created time etc. // Created time and Security Descriptors.
// It also checks if the volume supports extended attributes and stores the result in a map
// so that it does not have to be checked again for subsequent calls for paths in the same volume.
func (node *Node) fillGenericAttributes(path string, fi os.FileInfo, stat *statT) (allowExtended bool, err error) { func (node *Node) fillGenericAttributes(path string, fi os.FileInfo, stat *statT) (allowExtended bool, err error) {
if strings.Contains(filepath.Base(path), ":") { if strings.Contains(filepath.Base(path), ":") {
//Do not process for Alternate Data Streams in Windows // Do not process for Alternate Data Streams in Windows
// Also do not allow processing of extended attributes for ADS. // Also do not allow processing of extended attributes for ADS.
return false, nil return false, nil
} }
if strings.HasSuffix(filepath.Clean(path), `\`) { volumeName := filepath.VolumeName(path)
// This path is a volume allowExtended, err = checkAndStoreEASupport(volumeName)
supportsEAs, err := fs.PathSupportsExtendedAttributes(path) if err != nil {
if err != nil { return false, err
return false, err
}
if supportsEAs {
delete(eaUnsupportedVolumesMap, filepath.VolumeName(path))
} else {
// Add the volume to the map of volumes that do not support extended attributes.
eaUnsupportedVolumesMap[filepath.VolumeName(path)] = true
}
return supportsEAs, nil
} else {
// Do not process file attributes and created time for windows directories like
// C:, D:
// Filepath.Clean(path) ends with '\' for Windows root drives only.
var sd *[]byte
if node.Type == "file" || node.Type == "dir" {
if sd, err = fs.GetSecurityDescriptor(path); err != nil {
return true, err
}
}
// Add Windows attributes
node.GenericAttributes, err = WindowsAttrsToGenericAttributes(WindowsAttributes{
CreationTime: getCreationTime(fi, path),
FileAttributes: &stat.FileAttributes,
SecurityDescriptor: sd,
})
return !eaUnsupportedVolumesMap[filepath.VolumeName(path)], err
} }
if strings.HasSuffix(filepath.Clean(path), `\`) {
// filepath.Clean(path) ends with '\' for Windows root volume paths only
// Do not process file attributes, created time and sd for windows root volume paths
// Security descriptors are not supported for root volume paths.
// Though file attributes and created time are supported for root volume paths,
// we ignore them and we do not want to replace them during every restore.
return allowExtended, nil
}
var sd *[]byte
if node.Type == "file" || node.Type == "dir" {
if sd, err = fs.GetSecurityDescriptor(path); err != nil {
return true, err
}
}
// Add Windows attributes
node.GenericAttributes, err = WindowsAttrsToGenericAttributes(WindowsAttributes{
CreationTime: getCreationTime(fi, path),
FileAttributes: &stat.FileAttributes,
SecurityDescriptor: sd,
})
return allowExtended, err
}
// checkAndStoreEASupport checks if a volume supports extended attributes and stores the result in a map
// If the result is already in the map, it returns the result from the map.
func checkAndStoreEASupport(volumeName string) (isEASupportedVolume bool, err error) {
eaSupportedValue, exists := eaSupportedVolumesMap.Load(volumeName)
if exists {
return eaSupportedValue.(bool), nil
}
// Add backslash to the volume name to ensure it is a valid path
isEASupportedVolume, err = fs.PathSupportsExtendedAttributes(volumeName + `\`)
if err == nil {
eaSupportedVolumesMap.Store(volumeName, isEASupportedVolume)
}
return isEASupportedVolume, err
} }
// windowsAttrsToGenericAttributes converts the WindowsAttributes to a generic attributes map using reflection // windowsAttrsToGenericAttributes converts the WindowsAttributes to a generic attributes map using reflection