From 0966e1ad56670b39a6b55dfc2ad744c63cd1eb00 Mon Sep 17 00:00:00 2001 From: "Paul \"TBBle\" Hampson" Date: Wed, 6 Jan 2021 01:37:59 +1100 Subject: [PATCH] Correct GetVolumeInformation return type handling The _docs_ say it returns 0 for failure, non-zero for success. This implementation is looking for <0 as HRESULT failure, and deriving an Errno from that. The new tests fail with GetFileSystemType as it was defined, e.g., ``` --- FAIL: TestGetFSTypeOfValidButAbsentDrive (0.00s) fs_windows_test.go:41: GetFileSystemType a:\ unexpectedly succeeded ``` when I definitely do not have an A:\ drive. Signed-off-by: Paul "TBBle" Hampson --- pkg/fs/fs_windows.go | 24 ++++---------------- pkg/fs/fs_windows_test.go | 46 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 20 deletions(-) create mode 100644 pkg/fs/fs_windows_test.go diff --git a/pkg/fs/fs_windows.go b/pkg/fs/fs_windows.go index cf7de6d..53bc797 100644 --- a/pkg/fs/fs_windows.go +++ b/pkg/fs/fs_windows.go @@ -3,8 +3,6 @@ package fs import ( "errors" "path/filepath" - "syscall" - "unsafe" "golang.org/x/sys/windows" ) @@ -16,32 +14,18 @@ var ( // GetFileSystemType obtains the type of a file system through GetVolumeInformation. // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx -func GetFileSystemType(path string) (fsType string, hr error) { +func GetFileSystemType(path string) (fsType string, err error) { drive := filepath.VolumeName(path) if len(drive) != 2 { return "", ErrInvalidPath } var ( - modkernel32 = windows.NewLazySystemDLL("kernel32.dll") - procGetVolumeInformation = modkernel32.NewProc("GetVolumeInformationW") - buf = make([]uint16, 255) - size = windows.MAX_PATH + 1 + buf = make([]uint16, 255) + size = uint32(windows.MAX_PATH + 1) ) drive += `\` - n := uintptr(unsafe.Pointer(nil)) - r0, _, _ := syscall.Syscall9(procGetVolumeInformation.Addr(), 8, uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(drive))), n, n, n, n, n, uintptr(unsafe.Pointer(&buf[0])), uintptr(size), 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } + err = windows.GetVolumeInformation(windows.StringToUTF16Ptr(drive), nil, 0, nil, nil, nil, &buf[0], size) fsType = windows.UTF16ToString(buf) return } - -// win32FromHresult is a helper function to get the win32 error code from an HRESULT. -func win32FromHresult(hr uintptr) uintptr { - if hr&0x1fff0000 == 0x00070000 { - return hr & 0xffff - } - return hr -} diff --git a/pkg/fs/fs_windows_test.go b/pkg/fs/fs_windows_test.go new file mode 100644 index 0000000..512b235 --- /dev/null +++ b/pkg/fs/fs_windows_test.go @@ -0,0 +1,46 @@ +package fs + +import ( + "os" + "testing" +) + +func TestGetFSTypeOfKnownDrive(t *testing.T) { + fsType, err := GetFileSystemType("C:\\") + if err != nil { + t.Fatal(err) + } + + if fsType == "" { + t.Fatal("No filesystem type name returned") + } +} + +func TestGetFSTypeOfInvalidPath(t *testing.T) { + _, err := GetFileSystemType("7:\\") + if err != ErrInvalidPath { + t.Fatalf("Expected `ErrInvalidPath`, got %v", err) + } +} + +func TestGetFSTypeOfValidButAbsentDrive(t *testing.T) { + drive := "" + for _, letter := range "abcdefghijklmnopqrstuvwxyz" { + possibleDrive := string(letter) + ":\\" + if _, err := os.Stat(possibleDrive); os.IsNotExist(err) { + drive = possibleDrive + break + } + } + if drive == "" { + t.Skip("Every possible drive exists") + } + + _, err := GetFileSystemType(drive) + if err == nil { + t.Fatalf("GetFileSystemType %s unexpectedly succeeded", drive) + } + if !os.IsNotExist(err) { + t.Fatalf("GetFileSystemType %s failed with %v, expected 'ErrNotExist' or similar", drive, err) + } +}