Merge pull request #7531 from thaJeztah/sys_windows

sys: optimize and refactor MkdirAllWithACL()
This commit is contained in:
Derek McGowan 2022-10-19 21:50:11 -07:00 committed by GitHub
commit e282d0f2a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -25,28 +25,36 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
const ( // SddlAdministratorsLocalSystem is local administrators plus NT AUTHORITY\System.
// SddlAdministratorsLocalSystem is local administrators plus NT AUTHORITY\System const SddlAdministratorsLocalSystem = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)"
SddlAdministratorsLocalSystem = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)"
)
// MkdirAllWithACL is a wrapper for MkdirAll that creates a directory // volumePath is a regular expression to check if a path is a Windows
// ACL'd for Builtin Administrators and Local System. // volume path (e.g., "\\?\Volume{4c1b02c1-d990-11dc-99ae-806e6f6e6963}"
func MkdirAllWithACL(path string, perm os.FileMode) error { // or "\\?\Volume{4c1b02c1-d990-11dc-99ae-806e6f6e6963}\").
return mkdirall(path, true) var volumePath = regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}\\?$`)
// MkdirAllWithACL is a custom version of os.MkdirAll modified for use on Windows
// so that it is both volume path aware, and to create a directory
// an appropriate SDDL defined ACL for Builtin Administrators and Local System.
func MkdirAllWithACL(path string, _ os.FileMode) error {
sa, err := makeSecurityAttributes(SddlAdministratorsLocalSystem)
if err != nil {
return &os.PathError{Op: "mkdirall", Path: path, Err: err}
}
return mkdirall(path, sa)
} }
// MkdirAll implementation that is volume path aware for Windows. It can be used // MkdirAll is a custom version of os.MkdirAll that is volume path aware for
// as a drop-in replacement for os.MkdirAll() // Windows. It can be used as a drop-in replacement for os.MkdirAll.
func MkdirAll(path string, _ os.FileMode) error { func MkdirAll(path string, _ os.FileMode) error {
return mkdirall(path, false) return mkdirall(path, nil)
} }
// mkdirall is a custom version of os.MkdirAll modified for use on Windows // mkdirall is a custom version of os.MkdirAll modified for use on Windows
// so that it is both volume path aware, and can create a directory with // so that it is both volume path aware, and can create a directory with
// a DACL. // a DACL.
func mkdirall(path string, adminAndLocalSystem bool) error { func mkdirall(path string, perm *windows.SecurityAttributes) error {
if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) { if volumePath.MatchString(path) {
return nil return nil
} }
@ -59,11 +67,7 @@ func mkdirall(path string, adminAndLocalSystem bool) error {
if dir.IsDir() { if dir.IsDir() {
return nil return nil
} }
return &os.PathError{ return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
Op: "mkdir",
Path: path,
Err: syscall.ENOTDIR,
}
} }
// Slow path: make sure parent exists and then call Mkdir for path. // Slow path: make sure parent exists and then call Mkdir for path.
@ -78,20 +82,15 @@ func mkdirall(path string, adminAndLocalSystem bool) error {
} }
if j > 1 { if j > 1 {
// Create parent // Create parent.
err = mkdirall(path[0:j-1], adminAndLocalSystem) err = mkdirall(fixRootDirectory(path[:j-1]), perm)
if err != nil { if err != nil {
return err return err
} }
} }
// Parent now exists; invoke os.Mkdir or mkdirWithACL and use its result. // Parent now exists; invoke Mkdir and use its result.
if adminAndLocalSystem { err = mkdirWithACL(path, perm)
err = mkdirWithACL(path)
} else {
err = os.Mkdir(path, 0)
}
if err != nil { if err != nil {
// Handle arguments like "foo/." by // Handle arguments like "foo/." by
// double-checking that directory doesn't exist. // double-checking that directory doesn't exist.
@ -111,24 +110,42 @@ func mkdirall(path string, adminAndLocalSystem bool) error {
// in golang to cater for creating a directory am ACL permitting full // in golang to cater for creating a directory am ACL permitting full
// access, with inheritance, to any subfolder/file for Built-in Administrators // access, with inheritance, to any subfolder/file for Built-in Administrators
// and Local System. // and Local System.
func mkdirWithACL(name string) error { func mkdirWithACL(name string, sa *windows.SecurityAttributes) error {
sa := windows.SecurityAttributes{Length: 0} if sa == nil {
sd, err := windows.SecurityDescriptorFromString(SddlAdministratorsLocalSystem) return os.Mkdir(name, 0)
if err != nil {
return &os.PathError{Op: "mkdir", Path: name, Err: err}
} }
sa.Length = uint32(unsafe.Sizeof(sa))
sa.InheritHandle = 1
sa.SecurityDescriptor = sd
namep, err := windows.UTF16PtrFromString(name) namep, err := windows.UTF16PtrFromString(name)
if err != nil { if err != nil {
return &os.PathError{Op: "mkdir", Path: name, Err: err} return &os.PathError{Op: "mkdir", Path: name, Err: err}
} }
e := windows.CreateDirectory(namep, &sa) err = windows.CreateDirectory(namep, sa)
if e != nil { if err != nil {
return &os.PathError{Op: "mkdir", Path: name, Err: e} return &os.PathError{Op: "mkdir", Path: name, Err: err}
} }
return nil return nil
} }
// fixRootDirectory fixes a reference to a drive's root directory to
// have the required trailing slash.
func fixRootDirectory(p string) string {
if len(p) == len(`\\?\c:`) {
if os.IsPathSeparator(p[0]) && os.IsPathSeparator(p[1]) && p[2] == '?' && os.IsPathSeparator(p[3]) && p[5] == ':' {
return p + `\`
}
}
return p
}
func makeSecurityAttributes(sddl string) (*windows.SecurityAttributes, error) {
var sa windows.SecurityAttributes
sa.Length = uint32(unsafe.Sizeof(sa))
sa.InheritHandle = 1
var err error
sa.SecurityDescriptor, err = windows.SecurityDescriptorFromString(sddl)
if err != nil {
return nil, err
}
return &sa, nil
}