chore(fs): use x/sys/windows where possible (#10766)
Gets rid of an import of "unsafe". --------- Signed-off-by: greatroar <61184462+greatroar@users.noreply.github.com> Signed-off-by: Jakob Borg <jakob@kastelo.net> Co-authored-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
+26
-53
@@ -5,18 +5,16 @@
|
|||||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
|
"math/bits"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
@@ -72,30 +70,17 @@ func (f *BasicFilesystem) Hide(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *BasicFilesystem) Roots() ([]string, error) {
|
func (f *BasicFilesystem) Roots() ([]string, error) {
|
||||||
kernel32, err := syscall.LoadDLL("kernel32.dll")
|
mask, err := windows.GetLogicalDrives()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
getLogicalDriveStringsHandle, err := kernel32.FindProc("GetLogicalDriveStringsA")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer := [1024]byte{}
|
drives := make([]string, 0, bits.OnesCount32(mask))
|
||||||
bufferSize := uint32(len(buffer))
|
for letter := byte('A'); mask != 0; letter++ {
|
||||||
|
if mask&1 == 1 {
|
||||||
hr, _, _ := getLogicalDriveStringsHandle.Call(uintptr(unsafe.Pointer(&bufferSize)), uintptr(unsafe.Pointer(&buffer)))
|
drives = append(drives, string([]byte{letter, ':', '\\'}))
|
||||||
if hr == 0 {
|
|
||||||
return nil, errors.New("syscall failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
var drives []string
|
|
||||||
parts := bytes.Split(buffer[:], []byte{0})
|
|
||||||
for _, part := range parts {
|
|
||||||
if len(part) == 0 {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
drives = append(drives, string(part))
|
mask >>= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return drives, nil
|
return drives, nil
|
||||||
@@ -119,14 +104,14 @@ func (f *BasicFilesystem) Lchown(name, uid, gid string) error {
|
|||||||
// SetSecurityInfo.
|
// SetSecurityInfo.
|
||||||
|
|
||||||
var si windows.SECURITY_INFORMATION
|
var si windows.SECURITY_INFORMATION
|
||||||
var ownerSID, groupSID *syscall.SID
|
var ownerSID, groupSID *windows.SID
|
||||||
if uid != "" {
|
if uid != "" {
|
||||||
ownerSID, err = syscall.StringToSid(uid)
|
ownerSID, err = windows.StringToSid(uid)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
si |= windows.OWNER_SECURITY_INFORMATION
|
si |= windows.OWNER_SECURITY_INFORMATION
|
||||||
}
|
}
|
||||||
} else if gid != "" {
|
} else if gid != "" {
|
||||||
groupSID, err = syscall.StringToSid(uid)
|
groupSID, err = windows.StringToSid(uid)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
si |= windows.GROUP_SECURITY_INFORMATION
|
si |= windows.GROUP_SECURITY_INFORMATION
|
||||||
}
|
}
|
||||||
@@ -134,7 +119,7 @@ func (f *BasicFilesystem) Lchown(name, uid, gid string) error {
|
|||||||
return errors.New("neither uid nor gid specified")
|
return errors.New("neither uid nor gid specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
return windows.SetSecurityInfo(hdl, windows.SE_FILE_OBJECT, si, (*windows.SID)(ownerSID), (*windows.SID)(groupSID), nil, nil)
|
return windows.SetSecurityInfo(hdl, windows.SE_FILE_OBJECT, si, ownerSID, groupSID, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *BasicFilesystem) Remove(name string) error {
|
func (f *BasicFilesystem) Remove(name string) error {
|
||||||
@@ -218,47 +203,35 @@ func getFinalPathName(in string) (string, error) {
|
|||||||
// Wrap the call to GetFinalPathNameByHandleW
|
// Wrap the call to GetFinalPathNameByHandleW
|
||||||
// The string returned by this function uses the \?\ syntax
|
// The string returned by this function uses the \?\ syntax
|
||||||
// Implies GetFullPathName + GetLongPathName
|
// Implies GetFullPathName + GetLongPathName
|
||||||
kernel32, err := syscall.LoadDLL("kernel32.dll")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
GetFinalPathNameByHandleW, err := kernel32.FindProc("GetFinalPathNameByHandleW")
|
|
||||||
// https://github.com/golang/go/blob/ff048033e4304898245d843e79ed1a0897006c6d/src/internal/syscall/windows/syscall_windows.go#L303
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
inPath, err := syscall.UTF16PtrFromString(in)
|
inPath, err := syscall.UTF16PtrFromString(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// Get a file handler
|
// Get a file handle
|
||||||
h, err := syscall.CreateFile(inPath,
|
h, err := windows.CreateFile(inPath,
|
||||||
syscall.GENERIC_READ,
|
windows.GENERIC_READ,
|
||||||
syscall.FILE_SHARE_READ,
|
windows.FILE_SHARE_READ,
|
||||||
nil,
|
nil,
|
||||||
syscall.OPEN_EXISTING,
|
windows.OPEN_EXISTING,
|
||||||
uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS),
|
windows.FILE_FLAG_BACKUP_SEMANTICS,
|
||||||
0)
|
0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer syscall.CloseHandle(h)
|
defer windows.CloseHandle(h)
|
||||||
// Call GetFinalPathNameByHandleW
|
|
||||||
var VOLUME_NAME_DOS uint32 = 0x0 // not yet defined in syscall
|
const VOLUME_NAME_DOS = 0x0 // not yet defined in x/sys/windows
|
||||||
var bufSize uint32 = syscall.MAX_PATH // 260
|
var bufSize uint32 = windows.MAX_PATH
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
buf := make([]uint16, bufSize)
|
buf := make([]uint16, bufSize)
|
||||||
var ret uintptr
|
var ret uint32
|
||||||
ret, _, err = GetFinalPathNameByHandleW.Call(
|
ret, err = windows.GetFinalPathNameByHandle(
|
||||||
uintptr(h), // HANDLE hFile
|
h, &buf[0], bufSize, VOLUME_NAME_DOS)
|
||||||
uintptr(unsafe.Pointer(&buf[0])), // LPWSTR lpszFilePath
|
|
||||||
uintptr(bufSize), // DWORD cchFilePath
|
|
||||||
uintptr(VOLUME_NAME_DOS), // DWORD dwFlags
|
|
||||||
)
|
|
||||||
// The returned value is the actual length of the norm path
|
// The returned value is the actual length of the norm path
|
||||||
// After Win 10 build 1607, MAX_PATH limitations have been removed
|
// After Win 10 build 1607, MAX_PATH limitations have been removed
|
||||||
// so it is necessary to check newBufSize
|
// so it is necessary to check newBufSize
|
||||||
newBufSize := uint32(ret) + 1
|
newBufSize := ret + 1
|
||||||
if ret == 0 || newBufSize > bufSize*100 {
|
if ret == 0 || newBufSize > bufSize*100 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,3 +234,29 @@ func TestRepro9677MissingMtimeFS(t *testing.T) {
|
|||||||
newFS := NewFilesystem(FilesystemTypeFake, fmt.Sprintf("%v?insens=true&timeprecisionsecond=true", t.Name()), &OptionDetectCaseConflicts{}, NewMtimeOption(mtimeDB, ""))
|
newFS := NewFilesystem(FilesystemTypeFake, fmt.Sprintf("%v?insens=true&timeprecisionsecond=true", t.Name()), &OptionDetectCaseConflicts{}, NewMtimeOption(mtimeDB, ""))
|
||||||
checkMtime(newFS)
|
checkMtime(newFS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBasicFilesystemRoots(t *testing.T) {
|
||||||
|
var bfs BasicFilesystem
|
||||||
|
roots, err := bfs.Roots()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// The expected results depends on the system and we can't say too much,
|
||||||
|
// but do some sanity checking.
|
||||||
|
t.Logf("%d roots: %+v", len(roots), roots)
|
||||||
|
if len(roots) > 25 {
|
||||||
|
t.Errorf("suspiciously large number of filesystem roots: %d", len(roots))
|
||||||
|
}
|
||||||
|
rm := make(map[string]struct{})
|
||||||
|
for _, root := range roots {
|
||||||
|
if root == "" {
|
||||||
|
t.Error("empty root")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := rm[root]; ok {
|
||||||
|
t.Errorf("duplicate root %q", root)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rm[root] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user