sys: windows: use golang.org/x/sys/windows

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2020-03-09 13:05:53 +01:00
parent 92cfc5b1fb
commit 7b06192f61
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C

View File

@ -23,11 +23,10 @@ import (
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"syscall"
"unsafe" "unsafe"
winio "github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim" "github.com/Microsoft/hcsshim"
"golang.org/x/sys/windows"
) )
const ( const (
@ -41,7 +40,8 @@ func MkdirAllWithACL(path string, perm os.FileMode) error {
return mkdirall(path, true) return mkdirall(path, true)
} }
// MkdirAll implementation that is volume path aware for Windows. // MkdirAll implementation that is volume path aware for 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, false)
} }
@ -49,7 +49,7 @@ func MkdirAll(path string, _ os.FileMode) error {
// 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, applyACL bool) error {
if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) { if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) {
return nil return nil
} }
@ -66,7 +66,7 @@ func mkdirall(path string, adminAndLocalSystem bool) error {
return &os.PathError{ return &os.PathError{
Op: "mkdir", Op: "mkdir",
Path: path, Path: path,
Err: syscall.ENOTDIR, Err: windows.ERROR_PATH_NOT_FOUND,
} }
} }
@ -83,14 +83,14 @@ 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(path[0:j-1], false)
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 os.Mkdir or mkdirWithACL and use its result.
if adminAndLocalSystem { if applyACL {
err = mkdirWithACL(path) err = mkdirWithACL(path)
} else { } else {
err = os.Mkdir(path, 0) err = os.Mkdir(path, 0)
@ -111,26 +111,26 @@ func mkdirall(path string, adminAndLocalSystem bool) error {
// mkdirWithACL creates a new directory. If there is an error, it will be of // mkdirWithACL creates a new directory. If there is an error, it will be of
// type *PathError. . // type *PathError. .
// //
// This is a modified and combined version of os.Mkdir and syscall.Mkdir // This is a modified and combined version of os.Mkdir and windows.Mkdir
// 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) error {
sa := syscall.SecurityAttributes{Length: 0} sa := windows.SecurityAttributes{Length: 0}
sd, err := winio.SddlToSecurityDescriptor(SddlAdministratorsLocalSystem) sd, err := windows.SecurityDescriptorFromString(SddlAdministratorsLocalSystem)
if err != nil { if err != nil {
return &os.PathError{Op: "mkdir", Path: name, Err: err} return &os.PathError{Op: "mkdir", Path: name, Err: err}
} }
sa.Length = uint32(unsafe.Sizeof(sa)) sa.Length = uint32(unsafe.Sizeof(sa))
sa.InheritHandle = 1 sa.InheritHandle = 1
sa.SecurityDescriptor = uintptr(unsafe.Pointer(&sd[0])) sa.SecurityDescriptor = sd
namep, err := syscall.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 := syscall.CreateDirectory(namep, &sa) e := windows.CreateDirectory(namep, &sa)
if e != nil { if e != nil {
return &os.PathError{Op: "mkdir", Path: name, Err: e} return &os.PathError{Op: "mkdir", Path: name, Err: e}
} }
@ -153,7 +153,7 @@ func IsAbs(path string) bool {
return true return true
} }
// The origin of the functions below here are the golang OS and syscall packages, // The origin of the functions below here are the golang OS and windows packages,
// slightly modified to only cope with files, not directories due to the // slightly modified to only cope with files, not directories due to the
// specific use case. // specific use case.
// //
@ -183,76 +183,76 @@ func OpenSequential(name string) (*os.File, error) {
// If there is an error, it will be of type *PathError. // If there is an error, it will be of type *PathError.
func OpenFileSequential(name string, flag int, _ os.FileMode) (*os.File, error) { func OpenFileSequential(name string, flag int, _ os.FileMode) (*os.File, error) {
if name == "" { if name == "" {
return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOENT} return nil, &os.PathError{Op: "open", Path: name, Err: windows.ERROR_FILE_NOT_FOUND}
} }
r, errf := syscallOpenFileSequential(name, flag, 0) r, errf := windowsOpenFileSequential(name, flag, 0)
if errf == nil { if errf == nil {
return r, nil return r, nil
} }
return nil, &os.PathError{Op: "open", Path: name, Err: errf} return nil, &os.PathError{Op: "open", Path: name, Err: errf}
} }
func syscallOpenFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) { func windowsOpenFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) {
r, e := syscallOpenSequential(name, flag|syscall.O_CLOEXEC, 0) r, e := windowsOpenSequential(name, flag|windows.O_CLOEXEC, 0)
if e != nil { if e != nil {
return nil, e return nil, e
} }
return os.NewFile(uintptr(r), name), nil return os.NewFile(uintptr(r), name), nil
} }
func makeInheritSa() *syscall.SecurityAttributes { func makeInheritSa() *windows.SecurityAttributes {
var sa syscall.SecurityAttributes var sa windows.SecurityAttributes
sa.Length = uint32(unsafe.Sizeof(sa)) sa.Length = uint32(unsafe.Sizeof(sa))
sa.InheritHandle = 1 sa.InheritHandle = 1
return &sa return &sa
} }
func syscallOpenSequential(path string, mode int, _ uint32) (fd syscall.Handle, err error) { func windowsOpenSequential(path string, mode int, _ uint32) (fd windows.Handle, err error) {
if len(path) == 0 { if len(path) == 0 {
return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND return windows.InvalidHandle, windows.ERROR_FILE_NOT_FOUND
} }
pathp, err := syscall.UTF16PtrFromString(path) pathp, err := windows.UTF16PtrFromString(path)
if err != nil { if err != nil {
return syscall.InvalidHandle, err return windows.InvalidHandle, err
} }
var access uint32 var access uint32
switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) { switch mode & (windows.O_RDONLY | windows.O_WRONLY | windows.O_RDWR) {
case syscall.O_RDONLY: case windows.O_RDONLY:
access = syscall.GENERIC_READ access = windows.GENERIC_READ
case syscall.O_WRONLY: case windows.O_WRONLY:
access = syscall.GENERIC_WRITE access = windows.GENERIC_WRITE
case syscall.O_RDWR: case windows.O_RDWR:
access = syscall.GENERIC_READ | syscall.GENERIC_WRITE access = windows.GENERIC_READ | windows.GENERIC_WRITE
} }
if mode&syscall.O_CREAT != 0 { if mode&windows.O_CREAT != 0 {
access |= syscall.GENERIC_WRITE access |= windows.GENERIC_WRITE
} }
if mode&syscall.O_APPEND != 0 { if mode&windows.O_APPEND != 0 {
access &^= syscall.GENERIC_WRITE access &^= windows.GENERIC_WRITE
access |= syscall.FILE_APPEND_DATA access |= windows.FILE_APPEND_DATA
} }
sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE) sharemode := uint32(windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE)
var sa *syscall.SecurityAttributes var sa *windows.SecurityAttributes
if mode&syscall.O_CLOEXEC == 0 { if mode&windows.O_CLOEXEC == 0 {
sa = makeInheritSa() sa = makeInheritSa()
} }
var createmode uint32 var createmode uint32
switch { switch {
case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL): case mode&(windows.O_CREAT|windows.O_EXCL) == (windows.O_CREAT | windows.O_EXCL):
createmode = syscall.CREATE_NEW createmode = windows.CREATE_NEW
case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC): case mode&(windows.O_CREAT|windows.O_TRUNC) == (windows.O_CREAT | windows.O_TRUNC):
createmode = syscall.CREATE_ALWAYS createmode = windows.CREATE_ALWAYS
case mode&syscall.O_CREAT == syscall.O_CREAT: case mode&windows.O_CREAT == windows.O_CREAT:
createmode = syscall.OPEN_ALWAYS createmode = windows.OPEN_ALWAYS
case mode&syscall.O_TRUNC == syscall.O_TRUNC: case mode&windows.O_TRUNC == windows.O_TRUNC:
createmode = syscall.TRUNCATE_EXISTING createmode = windows.TRUNCATE_EXISTING
default: default:
createmode = syscall.OPEN_EXISTING createmode = windows.OPEN_EXISTING
} }
// Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang. // Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang.
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN
h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0) h, e := windows.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0)
return h, e return h, e
} }