2
2
mirror of https://github.com/octoleo/restic.git synced 2024-11-23 13:17:42 +00:00

fs: unexport a several windows functions

This commit is contained in:
Michael Eischer 2024-07-21 16:00:47 +02:00
parent cf051e777a
commit 6d3a5260d3
14 changed files with 119 additions and 117 deletions

View File

@ -56,14 +56,14 @@ var (
errEaValueTooLarge = errors.New("extended attribute value too large") errEaValueTooLarge = errors.New("extended attribute value too large")
) )
// ExtendedAttribute represents a single Windows EA. // extendedAttribute represents a single Windows EA.
type ExtendedAttribute struct { type extendedAttribute struct {
Name string Name string
Value []byte Value []byte
Flags uint8 Flags uint8
} }
func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) { func parseEa(b []byte) (ea extendedAttribute, nb []byte, err error) {
var info fileFullEaInformation var info fileFullEaInformation
err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info) err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
if err != nil { if err != nil {
@ -90,9 +90,9 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
return ea, nb, err return ea, nb, err
} }
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION // decodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
// buffer retrieved from BackupRead, ZwQueryEaFile, etc. // buffer retrieved from BackupRead, ZwQueryEaFile, etc.
func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) { func decodeExtendedAttributes(b []byte) (eas []extendedAttribute, err error) {
for len(b) != 0 { for len(b) != 0 {
ea, nb, err := parseEa(b) ea, nb, err := parseEa(b)
if err != nil { if err != nil {
@ -105,7 +105,7 @@ func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
return eas, err return eas, err
} }
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error { func writeEa(buf *bytes.Buffer, ea *extendedAttribute, last bool) error {
if int(uint8(len(ea.Name))) != len(ea.Name) { if int(uint8(len(ea.Name))) != len(ea.Name) {
return errEaNameTooLarge return errEaNameTooLarge
} }
@ -153,9 +153,9 @@ func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
return nil return nil
} }
// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION // encodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION
// buffer for use with BackupWrite, ZwSetEaFile, etc. // buffer for use with BackupWrite, ZwSetEaFile, etc.
func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) { func encodeExtendedAttributes(eas []extendedAttribute) ([]byte, error) {
var buf bytes.Buffer var buf bytes.Buffer
for i := range eas { for i := range eas {
last := false last := false
@ -217,11 +217,11 @@ const (
STATUS_NO_EAS_ON_FILE = -1073741742 STATUS_NO_EAS_ON_FILE = -1073741742
) )
// GetFileEA retrieves the extended attributes for the file represented by `handle`. The // fgetEA retrieves the extended attributes for the file represented by `handle`. The
// `handle` must have been opened with file access flag FILE_READ_EA (0x8). // `handle` must have been opened with file access flag FILE_READ_EA (0x8).
// The extended file attribute names in windows are case-insensitive and when fetching // The extended file attribute names in windows are case-insensitive and when fetching
// the attributes the names are generally returned in UPPER case. // the attributes the names are generally returned in UPPER case.
func GetFileEA(handle windows.Handle) ([]ExtendedAttribute, error) { func fgetEA(handle windows.Handle) ([]extendedAttribute, error) {
// default buffer size to start with // default buffer size to start with
bufLen := 1024 bufLen := 1024
buf := make([]byte, bufLen) buf := make([]byte, bufLen)
@ -246,13 +246,13 @@ func GetFileEA(handle windows.Handle) ([]ExtendedAttribute, error) {
} }
break break
} }
return DecodeExtendedAttributes(buf) return decodeExtendedAttributes(buf)
} }
// SetFileEA sets the extended attributes for the file represented by `handle`. The // fsetEA sets the extended attributes for the file represented by `handle`. The
// handle must have been opened with the file access flag FILE_WRITE_EA(0x10). // handle must have been opened with the file access flag FILE_WRITE_EA(0x10).
func SetFileEA(handle windows.Handle, attrs []ExtendedAttribute) error { func fsetEA(handle windows.Handle, attrs []extendedAttribute) error {
encodedEA, err := EncodeExtendedAttributes(attrs) encodedEA, err := encodeExtendedAttributes(attrs)
if err != nil { if err != nil {
return fmt.Errorf("failed to encoded extended attributes: %w", err) return fmt.Errorf("failed to encoded extended attributes: %w", err)
} }
@ -285,8 +285,8 @@ func setFileEA(handle windows.Handle, iosb *ioStatusBlock, buf *uint8, bufLen ui
return return
} }
// PathSupportsExtendedAttributes returns true if the path supports extended attributes. // pathSupportsExtendedAttributes returns true if the path supports extended attributes.
func PathSupportsExtendedAttributes(path string) (supported bool, err error) { func pathSupportsExtendedAttributes(path string) (supported bool, err error) {
var fileSystemFlags uint32 var fileSystemFlags uint32
utf16Path, err := windows.UTF16PtrFromString(path) utf16Path, err := windows.UTF16PtrFromString(path)
if err != nil { if err != nil {
@ -300,8 +300,8 @@ func PathSupportsExtendedAttributes(path string) (supported bool, err error) {
return supported, nil return supported, nil
} }
// GetVolumePathName returns the volume path name for the given path. // getVolumePathName returns the volume path name for the given path.
func GetVolumePathName(path string) (volumeName string, err error) { func getVolumePathName(path string) (volumeName string, err error) {
utf16Path, err := windows.UTF16PtrFromString(path) utf16Path, err := windows.UTF16PtrFromString(path)
if err != nil { if err != nil {
return "", err return "", err

View File

@ -46,7 +46,7 @@ import (
// under MIT license. // under MIT license.
var ( var (
testEas = []ExtendedAttribute{ testEas = []extendedAttribute{
{Name: "foo", Value: []byte("bar")}, {Name: "foo", Value: []byte("bar")},
{Name: "fizz", Value: []byte("buzz")}, {Name: "fizz", Value: []byte("buzz")},
} }
@ -58,14 +58,14 @@ var (
) )
func TestRoundTripEas(t *testing.T) { func TestRoundTripEas(t *testing.T) {
b, err := EncodeExtendedAttributes(testEas) b, err := encodeExtendedAttributes(testEas)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !reflect.DeepEqual(testEasEncoded, b) { if !reflect.DeepEqual(testEasEncoded, b) {
t.Fatalf("Encoded mismatch %v %v", testEasEncoded, b) t.Fatalf("Encoded mismatch %v %v", testEasEncoded, b)
} }
eas, err := DecodeExtendedAttributes(b) eas, err := decodeExtendedAttributes(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -75,7 +75,7 @@ func TestRoundTripEas(t *testing.T) {
} }
func TestEasDontNeedPaddingAtEnd(t *testing.T) { func TestEasDontNeedPaddingAtEnd(t *testing.T) {
eas, err := DecodeExtendedAttributes(testEasNotPadded) eas, err := decodeExtendedAttributes(testEasNotPadded)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -85,21 +85,21 @@ func TestEasDontNeedPaddingAtEnd(t *testing.T) {
} }
func TestTruncatedEasFailCorrectly(t *testing.T) { func TestTruncatedEasFailCorrectly(t *testing.T) {
_, err := DecodeExtendedAttributes(testEasTruncated) _, err := decodeExtendedAttributes(testEasTruncated)
if err == nil { if err == nil {
t.Fatal("expected error") t.Fatal("expected error")
} }
} }
func TestNilEasEncodeAndDecodeAsNil(t *testing.T) { func TestNilEasEncodeAndDecodeAsNil(t *testing.T) {
b, err := EncodeExtendedAttributes(nil) b, err := encodeExtendedAttributes(nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if len(b) != 0 { if len(b) != 0 {
t.Fatal("expected empty") t.Fatal("expected empty")
} }
eas, err := DecodeExtendedAttributes(nil) eas, err := decodeExtendedAttributes(nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -178,8 +178,8 @@ func setupTestFolder(t *testing.T) string {
return testfolderPath return testfolderPath
} }
func generateTestEAs(t *testing.T, nAttrs int, path string) []ExtendedAttribute { func generateTestEAs(t *testing.T, nAttrs int, path string) []extendedAttribute {
testEAs := make([]ExtendedAttribute, nAttrs) testEAs := make([]extendedAttribute, nAttrs)
for i := 0; i < nAttrs; i++ { for i := 0; i < nAttrs; i++ {
testEAs[i].Name = fmt.Sprintf("TESTEA%d", i+1) testEAs[i].Name = fmt.Sprintf("TESTEA%d", i+1)
testEAs[i].Value = make([]byte, getRandomInt()) testEAs[i].Value = make([]byte, getRandomInt())
@ -231,12 +231,12 @@ func cleanupTestFile(t *testing.T, path string) {
} }
} }
func testSetGetEA(t *testing.T, path string, handle windows.Handle, testEAs []ExtendedAttribute) { func testSetGetEA(t *testing.T, path string, handle windows.Handle, testEAs []extendedAttribute) {
if err := SetFileEA(handle, testEAs); err != nil { if err := fsetEA(handle, testEAs); err != nil {
t.Fatalf("set EA for path %s failed: %s", path, err) t.Fatalf("set EA for path %s failed: %s", path, err)
} }
readEAs, err := GetFileEA(handle) readEAs, err := fgetEA(handle)
if err != nil { if err != nil {
t.Fatalf("get EA for path %s failed: %s", path, err) t.Fatalf("get EA for path %s failed: %s", path, err)
} }
@ -262,7 +262,7 @@ func TestPathSupportsExtendedAttributes(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
supported, err := PathSupportsExtendedAttributes(tc.path) supported, err := pathSupportsExtendedAttributes(tc.path)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
@ -273,7 +273,7 @@ func TestPathSupportsExtendedAttributes(t *testing.T) {
} }
// Test with an invalid path // Test with an invalid path
_, err := PathSupportsExtendedAttributes("Z:\\NonExistentPath-UAS664da5s4dyu56das45f5as") _, err := pathSupportsExtendedAttributes("Z:\\NonExistentPath-UAS664da5s4dyu56das45f5as")
if err == nil { if err == nil {
t.Error("Expected an error for non-existent path, but got nil") t.Error("Expected an error for non-existent path, but got nil")
} }
@ -305,7 +305,7 @@ func TestGetVolumePathName(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
volumeName, err := GetVolumePathName(tc.path) volumeName, err := getVolumePathName(tc.path)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
@ -316,7 +316,7 @@ func TestGetVolumePathName(t *testing.T) {
} }
// Test with an invalid path // Test with an invalid path
_, err := GetVolumePathName("Z:\\NonExistentPath") _, err := getVolumePathName("Z:\\NonExistentPath")
if err == nil { if err == nil {
t.Error("Expected an error for non-existent path, but got nil") t.Error("Expected an error for non-existent path, but got nil")
} }

View File

@ -37,8 +37,8 @@ func isNotSupported(err error) bool {
return false return false
} }
// Chmod changes the mode of the named file to mode. // chmod changes the mode of the named file to mode.
func Chmod(name string, mode os.FileMode) error { func chmod(name string, mode os.FileMode) error {
err := os.Chmod(fixpath(name), mode) err := os.Chmod(fixpath(name), mode)
// ignore the error if the FS does not support setting this mode (e.g. CIFS with gvfs on Linux) // ignore the error if the FS does not support setting this mode (e.g. CIFS with gvfs on Linux)

View File

@ -75,17 +75,17 @@ func TempFile(dir, prefix string) (f *os.File, err error) {
} }
// Chmod changes the mode of the named file to mode. // Chmod changes the mode of the named file to mode.
func Chmod(name string, mode os.FileMode) error { func chmod(name string, mode os.FileMode) error {
return os.Chmod(fixpath(name), mode) return os.Chmod(fixpath(name), mode)
} }
// ClearSystem removes the system attribute from the file. // clearSystem removes the system attribute from the file.
func ClearSystem(path string) error { func clearSystem(path string) error {
return ClearAttribute(path, windows.FILE_ATTRIBUTE_SYSTEM) return clearAttribute(path, windows.FILE_ATTRIBUTE_SYSTEM)
} }
// ClearAttribute removes the specified attribute from the file. // clearAttribute removes the specified attribute from the file.
func ClearAttribute(path string, attribute uint32) error { func clearAttribute(path string, attribute uint32) error {
ptr, err := windows.UTF16PtrFromString(fixpath(path)) ptr, err := windows.UTF16PtrFromString(fixpath(path))
if err != nil { if err != nil {
return err return err
@ -105,8 +105,8 @@ func ClearAttribute(path string, attribute uint32) error {
return nil return nil
} }
// OpenHandleForEA return a file handle for file or dir for setting/getting EAs // openHandleForEA return a file handle for file or dir for setting/getting EAs
func OpenHandleForEA(nodeType restic.NodeType, path string, writeAccess bool) (handle windows.Handle, err error) { func openHandleForEA(nodeType restic.NodeType, path string, writeAccess bool) (handle windows.Handle, err error) {
path = fixpath(path) path = fixpath(path)
fileAccess := windows.FILE_READ_EA fileAccess := windows.FILE_READ_EA
if writeAccess { if writeAccess {

View File

@ -79,7 +79,7 @@ func parseMountPoints(list string, msgError ErrorHandler) (volumes map[string]st
return return
} }
for _, s := range strings.Split(list, ";") { for _, s := range strings.Split(list, ";") {
if v, err := GetVolumeNameForVolumeMountPoint(s); err != nil { if v, err := getVolumeNameForVolumeMountPoint(s); err != nil {
msgError(s, errors.Errorf("failed to parse vss.exclude-volumes [%s]: %s", s, err)) msgError(s, errors.Errorf("failed to parse vss.exclude-volumes [%s]: %s", s, err))
} else { } else {
if volumes == nil { if volumes == nil {
@ -146,7 +146,7 @@ func (fs *LocalVss) isMountPointIncluded(mountPoint string) bool {
return true return true
} }
volume, err := GetVolumeNameForVolumeMountPoint(mountPoint) volume, err := getVolumeNameForVolumeMountPoint(mountPoint)
if err != nil { if err != nil {
fs.msgError(mountPoint, errors.Errorf("failed to get volume from mount point [%s]: %s", mountPoint, err)) fs.msgError(mountPoint, errors.Errorf("failed to get volume from mount point [%s]: %s", mountPoint, err))
return true return true

View File

@ -1,3 +1,4 @@
//go:build windows
// +build windows // +build windows
package fs package fs
@ -120,10 +121,10 @@ func TestVSSConfig(t *testing.T) {
func TestParseMountPoints(t *testing.T) { func TestParseMountPoints(t *testing.T) {
volumeMatch := regexp.MustCompile(`^\\\\\?\\Volume\{[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}\}\\$`) volumeMatch := regexp.MustCompile(`^\\\\\?\\Volume\{[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}\}\\$`)
// It's not a good idea to test functions based on GetVolumeNameForVolumeMountPoint by calling // It's not a good idea to test functions based on getVolumeNameForVolumeMountPoint by calling
// GetVolumeNameForVolumeMountPoint itself, but we have restricted test environment: // getVolumeNameForVolumeMountPoint itself, but we have restricted test environment:
// cannot manage volumes and can only be sure that the mount point C:\ exists // cannot manage volumes and can only be sure that the mount point C:\ exists
sysVolume, err := GetVolumeNameForVolumeMountPoint("C:") sysVolume, err := getVolumeNameForVolumeMountPoint("C:")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -306,7 +306,7 @@ func nodeRestoreMetadata(node *restic.Node, path string, warn func(msg string))
// calling Chmod below will no longer allow any modifications to be made on the file and the // calling Chmod below will no longer allow any modifications to be made on the file and the
// calls above would fail. // calls above would fail.
if node.Type != restic.NodeTypeSymlink { if node.Type != restic.NodeTypeSymlink {
if err := Chmod(path, node.Mode); err != nil { if err := chmod(path, node.Mode); err != nil {
if firsterr == nil { if firsterr == nil {
firsterr = errors.WithStack(err) firsterr = errors.WithStack(err)
} }

View File

@ -85,9 +85,9 @@ func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error
func nodeRestoreExtendedAttributes(node *restic.Node, path string) (err error) { func nodeRestoreExtendedAttributes(node *restic.Node, path string) (err error) {
count := len(node.ExtendedAttributes) count := len(node.ExtendedAttributes)
if count > 0 { if count > 0 {
eas := make([]ExtendedAttribute, count) eas := make([]extendedAttribute, count)
for i, attr := range node.ExtendedAttributes { for i, attr := range node.ExtendedAttributes {
eas[i] = ExtendedAttribute{Name: attr.Name, Value: attr.Value} eas[i] = extendedAttribute{Name: attr.Name, Value: attr.Value}
} }
if errExt := restoreExtendedAttributes(node.Type, path, eas); errExt != nil { if errExt := restoreExtendedAttributes(node.Type, path, eas); errExt != nil {
return errExt return errExt
@ -99,7 +99,7 @@ func nodeRestoreExtendedAttributes(node *restic.Node, path string) (err error) {
// fill extended attributes in the node. This also includes the Generic attributes for windows. // fill extended attributes in the node. This also includes the Generic attributes for windows.
func nodeFillExtendedAttributes(node *restic.Node, path string, _ bool) (err error) { func nodeFillExtendedAttributes(node *restic.Node, path string, _ bool) (err error) {
var fileHandle windows.Handle var fileHandle windows.Handle
if fileHandle, err = OpenHandleForEA(node.Type, path, false); fileHandle == 0 { if fileHandle, err = openHandleForEA(node.Type, path, false); fileHandle == 0 {
return nil return nil
} }
if err != nil { if err != nil {
@ -107,8 +107,8 @@ func nodeFillExtendedAttributes(node *restic.Node, path string, _ bool) (err err
} }
defer closeFileHandle(fileHandle, path) // Replaced inline defer with named function call defer closeFileHandle(fileHandle, path) // Replaced inline defer with named function call
//Get the windows Extended Attributes using the file handle //Get the windows Extended Attributes using the file handle
var extAtts []ExtendedAttribute var extAtts []extendedAttribute
extAtts, err = GetFileEA(fileHandle) extAtts, err = fgetEA(fileHandle)
debug.Log("fillExtendedAttributes(%v) %v", path, extAtts) debug.Log("fillExtendedAttributes(%v) %v", path, extAtts)
if err != nil { if err != nil {
return errors.Errorf("get EA failed for path %v, with: %v", path, err) return errors.Errorf("get EA failed for path %v, with: %v", path, err)
@ -139,9 +139,9 @@ func closeFileHandle(fileHandle windows.Handle, path string) {
// restoreExtendedAttributes handles restore of the Windows Extended Attributes to the specified path. // restoreExtendedAttributes handles restore of the Windows Extended Attributes to the specified path.
// The Windows API requires setting of all the Extended Attributes in one call. // The Windows API requires setting of all the Extended Attributes in one call.
func restoreExtendedAttributes(nodeType restic.NodeType, path string, eas []ExtendedAttribute) (err error) { func restoreExtendedAttributes(nodeType restic.NodeType, path string, eas []extendedAttribute) (err error) {
var fileHandle windows.Handle var fileHandle windows.Handle
if fileHandle, err = OpenHandleForEA(nodeType, path, true); fileHandle == 0 { if fileHandle, err = openHandleForEA(nodeType, path, true); fileHandle == 0 {
return nil return nil
} }
if err != nil { if err != nil {
@ -150,7 +150,7 @@ func restoreExtendedAttributes(nodeType restic.NodeType, path string, eas []Exte
defer closeFileHandle(fileHandle, path) // Replaced inline defer with named function call defer closeFileHandle(fileHandle, path) // Replaced inline defer with named function call
// clear old unexpected xattrs by setting them to an empty value // clear old unexpected xattrs by setting them to an empty value
oldEAs, err := GetFileEA(fileHandle) oldEAs, err := fgetEA(fileHandle)
if err != nil { if err != nil {
return err return err
} }
@ -165,11 +165,11 @@ func restoreExtendedAttributes(nodeType restic.NodeType, path string, eas []Exte
} }
if !found { if !found {
eas = append(eas, ExtendedAttribute{Name: oldEA.Name, Value: nil}) eas = append(eas, extendedAttribute{Name: oldEA.Name, Value: nil})
} }
} }
if err = SetFileEA(fileHandle, eas); err != nil { if err = fsetEA(fileHandle, eas); err != nil {
return errors.Errorf("set EA failed for path %v, with: %v", path, err) return errors.Errorf("set EA failed for path %v, with: %v", path, err)
} }
return nil return nil
@ -230,7 +230,7 @@ func nodeRestoreGenericAttributes(node *restic.Node, path string, warn func(msg
} }
} }
if windowsAttributes.SecurityDescriptor != nil { if windowsAttributes.SecurityDescriptor != nil {
if err := SetSecurityDescriptor(path, windowsAttributes.SecurityDescriptor); err != nil { if err := setSecurityDescriptor(path, windowsAttributes.SecurityDescriptor); err != nil {
errs = append(errs, fmt.Errorf("error restoring security descriptor for: %s : %v", path, err)) errs = append(errs, fmt.Errorf("error restoring security descriptor for: %s : %v", path, err))
} }
} }
@ -296,7 +296,7 @@ func fixEncryptionAttribute(path string, attrs *uint32, pathPointer *uint16) (er
if err != nil { if err != nil {
return fmt.Errorf("failed to encrypt file: failed to reset permissions: %s : %v", path, err) return fmt.Errorf("failed to encrypt file: failed to reset permissions: %s : %v", path, err)
} }
err = ClearSystem(path) err = clearSystem(path)
if err != nil { if err != nil {
return fmt.Errorf("failed to encrypt file: failed to clear system flag: %s : %v", path, err) return fmt.Errorf("failed to encrypt file: failed to clear system flag: %s : %v", path, err)
} }
@ -324,7 +324,7 @@ func fixEncryptionAttribute(path string, attrs *uint32, pathPointer *uint16) (er
if err != nil { if err != nil {
return fmt.Errorf("failed to encrypt file: failed to reset permissions: %s : %v", path, err) return fmt.Errorf("failed to encrypt file: failed to reset permissions: %s : %v", path, err)
} }
err = ClearSystem(path) err = clearSystem(path)
if err != nil { if err != nil {
return fmt.Errorf("failed to decrypt file: failed to clear system flag: %s : %v", path, err) return fmt.Errorf("failed to decrypt file: failed to clear system flag: %s : %v", path, err)
} }
@ -392,7 +392,7 @@ func nodeFillGenericAttributes(node *restic.Node, path string, fi os.FileInfo, s
if err != nil { if err != nil {
return false, err return false, err
} }
if sd, err = GetSecurityDescriptor(path); err != nil { if sd, err = getSecurityDescriptor(path); err != nil {
return allowExtended, err return allowExtended, err
} }
} }
@ -422,7 +422,7 @@ func checkAndStoreEASupport(path string) (isEASupportedVolume bool, err error) {
return eaSupportedValue.(bool), nil return eaSupportedValue.(bool), nil
} }
// If not found, check if EA is supported with manually prepared volume name // If not found, check if EA is supported with manually prepared volume name
isEASupportedVolume, err = PathSupportsExtendedAttributes(volumeName + `\`) isEASupportedVolume, err = pathSupportsExtendedAttributes(volumeName + `\`)
// If the prepared volume name is not valid, we will fetch the actual volume name next. // If the prepared volume name is not valid, we will fetch the actual volume name next.
if err != nil && !errors.Is(err, windows.DNS_ERROR_INVALID_NAME) { if err != nil && !errors.Is(err, windows.DNS_ERROR_INVALID_NAME) {
debug.Log("Error checking if extended attributes are supported for prepared volume name %s: %v", volumeName, err) debug.Log("Error checking if extended attributes are supported for prepared volume name %s: %v", volumeName, err)
@ -431,8 +431,8 @@ func checkAndStoreEASupport(path string) (isEASupportedVolume bool, err error) {
return false, nil return false, nil
} }
} }
// If an entry is not found, get the actual volume name using the GetVolumePathName function // If an entry is not found, get the actual volume name
volumeNameActual, err := GetVolumePathName(path) volumeNameActual, err := getVolumePathName(path)
if err != nil { if err != nil {
debug.Log("Error getting actual volume name %s for path %s: %v", volumeName, path, err) debug.Log("Error getting actual volume name %s for path %s: %v", volumeName, path, err)
// There can be multiple errors like path does not exist, bad network path, etc. // There can be multiple errors like path does not exist, bad network path, etc.
@ -447,7 +447,7 @@ func checkAndStoreEASupport(path string) (isEASupportedVolume bool, err error) {
return eaSupportedValue.(bool), nil return eaSupportedValue.(bool), nil
} }
// If the actual volume name is different and is not in the map, again check if the new volume supports extended attributes with the actual volume name // If the actual volume name is different and is not in the map, again check if the new volume supports extended attributes with the actual volume name
isEASupportedVolume, err = PathSupportsExtendedAttributes(volumeNameActual + `\`) isEASupportedVolume, err = pathSupportsExtendedAttributes(volumeNameActual + `\`)
// Debug log for cases where the prepared volume name is not valid // Debug log for cases where the prepared volume name is not valid
if err != nil { if err != nil {
debug.Log("Error checking if extended attributes are supported for actual volume name %s: %v", volumeNameActual, err) debug.Log("Error checking if extended attributes are supported for actual volume name %s: %v", volumeNameActual, err)

View File

@ -23,10 +23,10 @@ import (
func TestRestoreSecurityDescriptors(t *testing.T) { func TestRestoreSecurityDescriptors(t *testing.T) {
t.Parallel() t.Parallel()
tempDir := t.TempDir() tempDir := t.TempDir()
for i, sd := range TestFileSDs { for i, sd := range testFileSDs {
testRestoreSecurityDescriptor(t, sd, tempDir, restic.NodeTypeFile, fmt.Sprintf("testfile%d", i)) testRestoreSecurityDescriptor(t, sd, tempDir, restic.NodeTypeFile, fmt.Sprintf("testfile%d", i))
} }
for i, sd := range TestDirSDs { for i, sd := range testDirSDs {
testRestoreSecurityDescriptor(t, sd, tempDir, restic.NodeTypeDir, fmt.Sprintf("testdir%d", i)) testRestoreSecurityDescriptor(t, sd, tempDir, restic.NodeTypeDir, fmt.Sprintf("testdir%d", i))
} }
} }
@ -47,13 +47,13 @@ func testRestoreSecurityDescriptor(t *testing.T, sd string, tempDir string, file
sdByteFromRestoredNode := getWindowsAttr(t, testPath, node).SecurityDescriptor sdByteFromRestoredNode := getWindowsAttr(t, testPath, node).SecurityDescriptor
// Get the security descriptor for the test path after the restore. // Get the security descriptor for the test path after the restore.
sdBytesFromRestoredPath, err := GetSecurityDescriptor(testPath) sdBytesFromRestoredPath, err := getSecurityDescriptor(testPath)
test.OK(t, errors.Wrapf(err, "Error while getting the security descriptor for: %s", testPath)) test.OK(t, errors.Wrapf(err, "Error while getting the security descriptor for: %s", testPath))
// Compare the input SD and the SD got from the restored file. // Compare the input SD and the SD got from the restored file.
CompareSecurityDescriptors(t, testPath, sdInputBytes, *sdBytesFromRestoredPath) compareSecurityDescriptors(t, testPath, sdInputBytes, *sdBytesFromRestoredPath)
// Compare the SD got from node constructed from the restored file info and the SD got directly from the restored file. // Compare the SD got from node constructed from the restored file info and the SD got directly from the restored file.
CompareSecurityDescriptors(t, testPath, *sdByteFromRestoredNode, *sdBytesFromRestoredPath) compareSecurityDescriptors(t, testPath, *sdByteFromRestoredNode, *sdBytesFromRestoredPath)
} }
func getNode(name string, fileType restic.NodeType, genericAttributes map[restic.GenericAttributeType]json.RawMessage) restic.Node { func getNode(name string, fileType restic.NodeType, genericAttributes map[restic.GenericAttributeType]json.RawMessage) restic.Node {
@ -312,12 +312,12 @@ func TestRestoreExtendedAttributes(t *testing.T) {
test.OK(t, errors.Wrapf(err, "Error closing file for: %s", testPath)) test.OK(t, errors.Wrapf(err, "Error closing file for: %s", testPath))
}() }()
extAttr, err := GetFileEA(handle) extAttr, err := fgetEA(handle)
test.OK(t, errors.Wrapf(err, "Error getting extended attributes for: %s", testPath)) test.OK(t, errors.Wrapf(err, "Error getting extended attributes for: %s", testPath))
test.Equals(t, len(node.ExtendedAttributes), len(extAttr)) test.Equals(t, len(node.ExtendedAttributes), len(extAttr))
for _, expectedExtAttr := range node.ExtendedAttributes { for _, expectedExtAttr := range node.ExtendedAttributes {
var foundExtAttr *ExtendedAttribute var foundExtAttr *extendedAttribute
for _, ea := range extAttr { for _, ea := range extAttr {
if strings.EqualFold(ea.Name, expectedExtAttr.Name) { if strings.EqualFold(ea.Name, expectedExtAttr.Name) {
foundExtAttr = &ea foundExtAttr = &ea
@ -491,13 +491,13 @@ func TestPrepareVolumeName(t *testing.T) {
test.Equals(t, tc.expectedVolume, volume) test.Equals(t, tc.expectedVolume, volume)
if tc.isRealPath { if tc.isRealPath {
isEASupportedVolume, err := PathSupportsExtendedAttributes(volume + `\`) isEASupportedVolume, err := pathSupportsExtendedAttributes(volume + `\`)
// If the prepared volume name is not valid, we will next fetch the actual volume name. // If the prepared volume name is not valid, we will next fetch the actual volume name.
test.OK(t, err) test.OK(t, err)
test.Equals(t, tc.expectedEASupported, isEASupportedVolume) test.Equals(t, tc.expectedEASupported, isEASupportedVolume)
actualVolume, err := GetVolumePathName(tc.path) actualVolume, err := getVolumePathName(tc.path)
test.OK(t, err) test.OK(t, err)
test.Equals(t, tc.expectedVolume, actualVolume) test.Equals(t, tc.expectedVolume, actualVolume)
} }

View File

@ -19,14 +19,14 @@ var (
onceBackup sync.Once onceBackup sync.Once
onceRestore sync.Once onceRestore sync.Once
// SeBackupPrivilege allows the application to bypass file and directory ACLs to back up files and directories. // seBackupPrivilege allows the application to bypass file and directory ACLs to back up files and directories.
SeBackupPrivilege = "SeBackupPrivilege" seBackupPrivilege = "SeBackupPrivilege"
// SeRestorePrivilege allows the application to bypass file and directory ACLs to restore files and directories. // seRestorePrivilege allows the application to bypass file and directory ACLs to restore files and directories.
SeRestorePrivilege = "SeRestorePrivilege" seRestorePrivilege = "SeRestorePrivilege"
// SeSecurityPrivilege allows read and write access to all SACLs. // seSecurityPrivilege allows read and write access to all SACLs.
SeSecurityPrivilege = "SeSecurityPrivilege" seSecurityPrivilege = "SeSecurityPrivilege"
// SeTakeOwnershipPrivilege allows the application to take ownership of files and directories, regardless of the permissions set on them. // seTakeOwnershipPrivilege allows the application to take ownership of files and directories, regardless of the permissions set on them.
SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege" seTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege"
lowerPrivileges atomic.Bool lowerPrivileges atomic.Bool
) )
@ -40,10 +40,10 @@ var lowBackupSecurityFlags windows.SECURITY_INFORMATION = windows.OWNER_SECURITY
// Flags for restore without admin permissions. If there are no admin permissions, only the DACL from the SD can be restored and owner and group will be set based on the current user. // Flags for restore without admin permissions. If there are no admin permissions, only the DACL from the SD can be restored and owner and group will be set based on the current user.
var lowRestoreSecurityFlags windows.SECURITY_INFORMATION = windows.DACL_SECURITY_INFORMATION | windows.ATTRIBUTE_SECURITY_INFORMATION | windows.PROTECTED_DACL_SECURITY_INFORMATION var lowRestoreSecurityFlags windows.SECURITY_INFORMATION = windows.DACL_SECURITY_INFORMATION | windows.ATTRIBUTE_SECURITY_INFORMATION | windows.PROTECTED_DACL_SECURITY_INFORMATION
// GetSecurityDescriptor takes the path of the file and returns the SecurityDescriptor for the file. // getSecurityDescriptor takes the path of the file and returns the SecurityDescriptor for the file.
// This needs admin permissions or SeBackupPrivilege for getting the full SD. // This needs admin permissions or SeBackupPrivilege for getting the full SD.
// If there are no admin permissions, only the current user's owner, group and DACL will be got. // If there are no admin permissions, only the current user's owner, group and DACL will be got.
func GetSecurityDescriptor(filePath string) (securityDescriptor *[]byte, err error) { func getSecurityDescriptor(filePath string) (securityDescriptor *[]byte, err error) {
onceBackup.Do(enableBackupPrivilege) onceBackup.Do(enableBackupPrivilege)
var sd *windows.SECURITY_DESCRIPTOR var sd *windows.SECURITY_DESCRIPTOR
@ -59,7 +59,7 @@ func GetSecurityDescriptor(filePath string) (securityDescriptor *[]byte, err err
if !useLowerPrivileges && isHandlePrivilegeNotHeldError(err) { if !useLowerPrivileges && isHandlePrivilegeNotHeldError(err) {
// If ERROR_PRIVILEGE_NOT_HELD is encountered, fallback to backups/restores using lower non-admin privileges. // If ERROR_PRIVILEGE_NOT_HELD is encountered, fallback to backups/restores using lower non-admin privileges.
lowerPrivileges.Store(true) lowerPrivileges.Store(true)
return GetSecurityDescriptor(filePath) return getSecurityDescriptor(filePath)
} else if errors.Is(err, windows.ERROR_NOT_SUPPORTED) { } else if errors.Is(err, windows.ERROR_NOT_SUPPORTED) {
return nil, nil return nil, nil
} else { } else {
@ -74,15 +74,15 @@ func GetSecurityDescriptor(filePath string) (securityDescriptor *[]byte, err err
return &sdBytes, nil return &sdBytes, nil
} }
// SetSecurityDescriptor sets the SecurityDescriptor for the file at the specified path. // setSecurityDescriptor sets the SecurityDescriptor for the file at the specified path.
// This needs admin permissions or SeRestorePrivilege, SeSecurityPrivilege and SeTakeOwnershipPrivilege // This needs admin permissions or SeRestorePrivilege, SeSecurityPrivilege and SeTakeOwnershipPrivilege
// for setting the full SD. // for setting the full SD.
// If there are no admin permissions/required privileges, only the DACL from the SD can be set and // If there are no admin permissions/required privileges, only the DACL from the SD can be set and
// owner and group will be set based on the current user. // owner and group will be set based on the current user.
func SetSecurityDescriptor(filePath string, securityDescriptor *[]byte) error { func setSecurityDescriptor(filePath string, securityDescriptor *[]byte) error {
onceRestore.Do(enableRestorePrivilege) onceRestore.Do(enableRestorePrivilege)
// Set the security descriptor on the file // Set the security descriptor on the file
sd, err := SecurityDescriptorBytesToStruct(*securityDescriptor) sd, err := securityDescriptorBytesToStruct(*securityDescriptor)
if err != nil { if err != nil {
return fmt.Errorf("error converting bytes to security descriptor: %w", err) return fmt.Errorf("error converting bytes to security descriptor: %w", err)
} }
@ -120,7 +120,7 @@ func SetSecurityDescriptor(filePath string, securityDescriptor *[]byte) error {
if !useLowerPrivileges && isHandlePrivilegeNotHeldError(err) { if !useLowerPrivileges && isHandlePrivilegeNotHeldError(err) {
// If ERROR_PRIVILEGE_NOT_HELD is encountered, fallback to backups/restores using lower non-admin privileges. // If ERROR_PRIVILEGE_NOT_HELD is encountered, fallback to backups/restores using lower non-admin privileges.
lowerPrivileges.Store(true) lowerPrivileges.Store(true)
return SetSecurityDescriptor(filePath, securityDescriptor) return setSecurityDescriptor(filePath, securityDescriptor)
} else { } else {
return fmt.Errorf("set named security info failed with: %w", err) return fmt.Errorf("set named security info failed with: %w", err)
} }
@ -150,7 +150,7 @@ func setNamedSecurityInfoLow(filePath string, dacl *windows.ACL) error {
// enableBackupPrivilege enables privilege for backing up security descriptors // enableBackupPrivilege enables privilege for backing up security descriptors
func enableBackupPrivilege() { func enableBackupPrivilege() {
err := enableProcessPrivileges([]string{SeBackupPrivilege}) err := enableProcessPrivileges([]string{seBackupPrivilege})
if err != nil { if err != nil {
debug.Log("error enabling backup privilege: %v", err) debug.Log("error enabling backup privilege: %v", err)
} }
@ -158,7 +158,7 @@ func enableBackupPrivilege() {
// enableBackupPrivilege enables privilege for restoring security descriptors // enableBackupPrivilege enables privilege for restoring security descriptors
func enableRestorePrivilege() { func enableRestorePrivilege() {
err := enableProcessPrivileges([]string{SeRestorePrivilege, SeSecurityPrivilege, SeTakeOwnershipPrivilege}) err := enableProcessPrivileges([]string{seRestorePrivilege, seSecurityPrivilege, seTakeOwnershipPrivilege})
if err != nil { if err != nil {
debug.Log("error enabling restore/security privilege: %v", err) debug.Log("error enabling restore/security privilege: %v", err)
} }
@ -174,9 +174,9 @@ func isHandlePrivilegeNotHeldError(err error) bool {
return false return false
} }
// SecurityDescriptorBytesToStruct converts the security descriptor bytes representation // securityDescriptorBytesToStruct converts the security descriptor bytes representation
// into a pointer to windows SECURITY_DESCRIPTOR. // into a pointer to windows SECURITY_DESCRIPTOR.
func SecurityDescriptorBytesToStruct(sd []byte) (*windows.SECURITY_DESCRIPTOR, error) { func securityDescriptorBytesToStruct(sd []byte) (*windows.SECURITY_DESCRIPTOR, error) {
if l := int(unsafe.Sizeof(windows.SECURITY_DESCRIPTOR{})); len(sd) < l { if l := int(unsafe.Sizeof(windows.SECURITY_DESCRIPTOR{})); len(sd) < l {
return nil, fmt.Errorf("securityDescriptor (%d) smaller than expected (%d): %w", len(sd), l, windows.ERROR_INCORRECT_SIZE) return nil, fmt.Errorf("securityDescriptor (%d) smaller than expected (%d): %w", len(sd), l, windows.ERROR_INCORRECT_SIZE)
} }
@ -245,13 +245,13 @@ var (
privNameMutex sync.Mutex privNameMutex sync.Mutex
) )
// PrivilegeError represents an error enabling privileges. // privilegeError represents an error enabling privileges.
type PrivilegeError struct { type privilegeError struct {
privileges []uint64 privileges []uint64
} }
// Error returns the string message for the error. // Error returns the string message for the error.
func (e *PrivilegeError) Error() string { func (e *privilegeError) Error() string {
s := "Could not enable privilege " s := "Could not enable privilege "
if len(e.privileges) > 1 { if len(e.privileges) > 1 {
s = "Could not enable privileges " s = "Could not enable privileges "

View File

@ -28,7 +28,7 @@ func TestSetGetFileSecurityDescriptors(t *testing.T) {
} }
}() }()
testSecurityDescriptors(t, TestFileSDs, testfilePath) testSecurityDescriptors(t, testFileSDs, testfilePath)
} }
func TestSetGetFolderSecurityDescriptors(t *testing.T) { func TestSetGetFolderSecurityDescriptors(t *testing.T) {
@ -40,7 +40,7 @@ func TestSetGetFolderSecurityDescriptors(t *testing.T) {
t.Fatalf("failed to create temporary file: %s", err) t.Fatalf("failed to create temporary file: %s", err)
} }
testSecurityDescriptors(t, TestDirSDs, testfolderPath) testSecurityDescriptors(t, testDirSDs, testfolderPath)
} }
func testSecurityDescriptors(t *testing.T, testSDs []string, testPath string) { func testSecurityDescriptors(t *testing.T, testSDs []string, testPath string) {
@ -48,13 +48,13 @@ func testSecurityDescriptors(t *testing.T, testSDs []string, testPath string) {
sdInputBytes, err := base64.StdEncoding.DecodeString(testSD) sdInputBytes, err := base64.StdEncoding.DecodeString(testSD)
test.OK(t, errors.Wrapf(err, "Error decoding SD: %s", testPath)) test.OK(t, errors.Wrapf(err, "Error decoding SD: %s", testPath))
err = SetSecurityDescriptor(testPath, &sdInputBytes) err = setSecurityDescriptor(testPath, &sdInputBytes)
test.OK(t, errors.Wrapf(err, "Error setting file security descriptor for: %s", testPath)) test.OK(t, errors.Wrapf(err, "Error setting file security descriptor for: %s", testPath))
var sdOutputBytes *[]byte var sdOutputBytes *[]byte
sdOutputBytes, err = GetSecurityDescriptor(testPath) sdOutputBytes, err = getSecurityDescriptor(testPath)
test.OK(t, errors.Wrapf(err, "Error getting file security descriptor for: %s", testPath)) test.OK(t, errors.Wrapf(err, "Error getting file security descriptor for: %s", testPath))
CompareSecurityDescriptors(t, testPath, sdInputBytes, *sdOutputBytes) compareSecurityDescriptors(t, testPath, sdInputBytes, *sdOutputBytes)
} }
} }

View File

@ -13,18 +13,18 @@ import (
) )
var ( var (
TestFileSDs = []string{"AQAUvBQAAAAwAAAAAAAAAEwAAAABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAfAAEAAAAAAAkAKkAEgABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvtAwAAABAUAP8BHwABAQAAAAAABRIAAAAAEBgA/wEfAAECAAAAAAAFIAAAACACAAAAECQA/wEfAAEFAAAAAAAFFQAAAIifWK5WoILqzL0mq+oDAAA=", testFileSDs = []string{"AQAUvBQAAAAwAAAAAAAAAEwAAAABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAfAAEAAAAAAAkAKkAEgABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvtAwAAABAUAP8BHwABAQAAAAAABRIAAAAAEBgA/wEfAAECAAAAAAAFIAAAACACAAAAECQA/wEfAAEFAAAAAAAFFQAAAIifWK5WoILqzL0mq+oDAAA=",
"AQAUvBQAAAAwAAAAAAAAAEwAAAABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAyAAHAAAAAAAUAKkAEgABAQAAAAAABQcAAAAAABQAiQASAAEBAAAAAAAFBwAAAAAAJACpABIAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSar7QMAAAAAJAC/ARMAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSar6gMAAAAAFAD/AR8AAQEAAAAAAAUSAAAAAAAYAP8BHwABAgAAAAAABSAAAAAgAgAAAAAkAP8BHwABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAA", "AQAUvBQAAAAwAAAAAAAAAEwAAAABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAyAAHAAAAAAAUAKkAEgABAQAAAAAABQcAAAAAABQAiQASAAEBAAAAAAAFBwAAAAAAJACpABIAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSar7QMAAAAAJAC/ARMAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSar6gMAAAAAFAD/AR8AAQEAAAAAAAUSAAAAAAAYAP8BHwABAgAAAAAABSAAAAAgAgAAAAAkAP8BHwABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAA",
"AQAUvBQAAAAwAAAA7AAAAEwAAAABBQAAAAAABRUAAAAvr7t03PyHGk2FokNHCAAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAoAAFAAAAAAAkAP8BHwABBQAAAAAABRUAAAAvr7t03PyHGk2FokNHCAAAAAAkAKkAEgABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvtAwAAABAUAP8BHwABAQAAAAAABRIAAAAAEBgA/wEfAAECAAAAAAAFIAAAACACAAAAECQA/wEfAAEFAAAAAAAFFQAAAIifWK5WoILqzL0mq+oDAAACAHQAAwAAAAKAJAC/AQIAAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDtgQAAALAJAC/AQMAAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDPgkAAAJAJAD/AQ8AAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDtQQAAA==", "AQAUvBQAAAAwAAAA7AAAAEwAAAABBQAAAAAABRUAAAAvr7t03PyHGk2FokNHCAAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAoAAFAAAAAAAkAP8BHwABBQAAAAAABRUAAAAvr7t03PyHGk2FokNHCAAAAAAkAKkAEgABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvtAwAAABAUAP8BHwABAQAAAAAABRIAAAAAEBgA/wEfAAECAAAAAAAFIAAAACACAAAAECQA/wEfAAEFAAAAAAAFFQAAAIifWK5WoILqzL0mq+oDAAACAHQAAwAAAAKAJAC/AQIAAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDtgQAAALAJAC/AQMAAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDPgkAAAJAJAD/AQ8AAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDtQQAAA==",
} }
TestDirSDs = []string{"AQAUvBQAAAAwAAAAAAAAAEwAAAABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAfAAEAAAAAAAkAKkAEgABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvtAwAAABMUAP8BHwABAQAAAAAABRIAAAAAExgA/wEfAAECAAAAAAAFIAAAACACAAAAEyQA/wEfAAEFAAAAAAAFFQAAAIifWK5WoILqzL0mq+oDAAA=", testDirSDs = []string{"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",
} }
) )
// IsAdmin checks if current user is an administrator. // isAdmin checks if current user is an administrator.
func IsAdmin() (isAdmin bool, err error) { func isAdmin() (isAdmin bool, err error) {
var sid *windows.SID var sid *windows.SID
err = windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY, 2, windows.SECURITY_BUILTIN_DOMAIN_RID, windows.DOMAIN_ALIAS_RID_ADMINS, err = windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY, 2, windows.SECURITY_BUILTIN_DOMAIN_RID, windows.DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &sid) 0, 0, 0, 0, 0, 0, &sid)
@ -40,15 +40,15 @@ func IsAdmin() (isAdmin bool, err error) {
return member, nil return member, nil
} }
// CompareSecurityDescriptors runs tests for comparing 2 security descriptors in []byte format. // compareSecurityDescriptors runs tests for comparing 2 security descriptors in []byte format.
func CompareSecurityDescriptors(t *testing.T, testPath string, sdInputBytes, sdOutputBytes []byte) { func compareSecurityDescriptors(t *testing.T, testPath string, sdInputBytes, sdOutputBytes []byte) {
sdInput, err := SecurityDescriptorBytesToStruct(sdInputBytes) sdInput, err := securityDescriptorBytesToStruct(sdInputBytes)
test.OK(t, errors.Wrapf(err, "Error converting SD to struct for: %s", testPath)) test.OK(t, errors.Wrapf(err, "Error converting SD to struct for: %s", testPath))
sdOutput, err := SecurityDescriptorBytesToStruct(sdOutputBytes) sdOutput, err := securityDescriptorBytesToStruct(sdOutputBytes)
test.OK(t, errors.Wrapf(err, "Error converting SD to struct for: %s", testPath)) test.OK(t, errors.Wrapf(err, "Error converting SD to struct for: %s", testPath))
isAdmin, err := IsAdmin() isAdmin, err := isAdmin()
test.OK(t, errors.Wrapf(err, "Error checking if user is admin: %s", testPath)) test.OK(t, errors.Wrapf(err, "Error checking if user is admin: %s", testPath))
var ownerExpected *windows.SID var ownerExpected *windows.SID

View File

@ -33,9 +33,9 @@ func HasSufficientPrivilegesForVSS() error {
return errors.New("VSS snapshots are only supported on windows") return errors.New("VSS snapshots are only supported on windows")
} }
// GetVolumeNameForVolumeMountPoint add trailing backslash to input parameter // getVolumeNameForVolumeMountPoint add trailing backslash to input parameter
// and calls the equivalent windows api. // and calls the equivalent windows api.
func GetVolumeNameForVolumeMountPoint(mountPoint string) (string, error) { func getVolumeNameForVolumeMountPoint(mountPoint string) (string, error) {
return mountPoint, nil return mountPoint, nil
} }

View File

@ -22,6 +22,7 @@ import (
type HRESULT uint type HRESULT uint
// HRESULT constant values necessary for using VSS api. // HRESULT constant values necessary for using VSS api.
//
//nolint:golint //nolint:golint
const ( const (
S_OK HRESULT = 0x00000000 S_OK HRESULT = 0x00000000
@ -830,9 +831,9 @@ func HasSufficientPrivilegesForVSS() error {
return err return err
} }
// GetVolumeNameForVolumeMountPoint add trailing backslash to input parameter // getVolumeNameForVolumeMountPoint add trailing backslash to input parameter
// and calls the equivalent windows api. // and calls the equivalent windows api.
func GetVolumeNameForVolumeMountPoint(mountPoint string) (string, error) { func getVolumeNameForVolumeMountPoint(mountPoint string) (string, error) {
if mountPoint != "" && mountPoint[len(mountPoint)-1] != filepath.Separator { if mountPoint != "" && mountPoint[len(mountPoint)-1] != filepath.Separator {
mountPoint += string(filepath.Separator) mountPoint += string(filepath.Separator)
} }