From a8a935f5fd4f821d7bde73bfeff301f46df93246 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Sat, 17 Oct 2015 19:09:43 -0700 Subject: [PATCH] Improve disk code to return back disk StatFS{} structure ``` StatFS { Total int64 Free int64 FSType string } ``` Provides more information in a cross platform way. --- .travis.yml | 9 ------ pkg/disk/disk.go | 11 +++++++ pkg/disk/disk_test.go | 9 ++++-- pkg/disk/stat_nix.go | 15 ++++++--- pkg/disk/stat_windows.go | 33 +++++++------------ pkg/disk/type_darwin.go | 15 +++------ pkg/disk/type_linux.go | 15 +++------ pkg/disk/type_windows.go | 68 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 116 insertions(+), 59 deletions(-) create mode 100644 pkg/disk/disk.go create mode 100644 pkg/disk/type_windows.go diff --git a/.travis.yml b/.travis.yml index a86033d84..bd9c62698 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,4 @@ language: go -before_install: -- git clone https://github.com/yasm/yasm -- cd yasm -- git checkout v1.2.0 -- "./autogen.sh" -- "./configure" -- make -- export PATH=$PATH:`pwd` -- cd .. script: - make test - make test GOFLAGS="-race" diff --git a/pkg/disk/disk.go b/pkg/disk/disk.go new file mode 100644 index 000000000..33252e725 --- /dev/null +++ b/pkg/disk/disk.go @@ -0,0 +1,11 @@ +package disk + +// StatFS stat fs struct is container which holds following values +// Total - total size of the volume / disk +// Free - free size of the volume / disk +// FSType - file system type string +type StatFS struct { + Total int64 + Free int64 + FSType string +} diff --git a/pkg/disk/disk_test.go b/pkg/disk/disk_test.go index b4649d7b5..8758b7fb1 100644 --- a/pkg/disk/disk_test.go +++ b/pkg/disk/disk_test.go @@ -34,8 +34,11 @@ var _ = Suite(&MySuite{}) func (s *MySuite) TestFree(c *C) { path, err := ioutil.TempDir(os.TempDir(), "minio-") - c.Check(err, IsNil) + c.Assert(err, IsNil) - _, _, err = disk.Stat(path) - c.Check(err, IsNil) + statfs, err := disk.Stat(path) + c.Assert(err, IsNil) + c.Assert(statfs.Total, Not(Equals), 0) + c.Assert(statfs.Free, Not(Equals), 0) + c.Assert(statfs.FSType, Not(Equals), "UNKNOWN") } diff --git a/pkg/disk/stat_nix.go b/pkg/disk/stat_nix.go index aa7078179..0ffb43909 100644 --- a/pkg/disk/stat_nix.go +++ b/pkg/disk/stat_nix.go @@ -23,13 +23,18 @@ import ( ) // Stat returns total and free bytes available in a directory, e.g. `/`. -func Stat(path string) (total, free int64, err error) { +func Stat(path string) (statfs StatFS, err error) { s := syscall.Statfs_t{} err = syscall.Statfs(path, &s) if err != nil { - return + return StatFS{}, err } - total = int64(s.Bsize) * int64(s.Blocks) - free = int64(s.Bsize) * int64(s.Bfree) - return + statfs = StatFS{} + statfs.Total = int64(s.Bsize) * int64(s.Blocks) + statfs.Free = int64(s.Bsize) * int64(s.Bfree) + statfs.FSType, err = getFSType(path) + if err != nil { + return StatFS{}, err + } + return statfs, nil } diff --git a/pkg/disk/stat_windows.go b/pkg/disk/stat_windows.go index c8f60e8a7..9730a5782 100644 --- a/pkg/disk/stat_windows.go +++ b/pkg/disk/stat_windows.go @@ -27,20 +27,14 @@ import ( // It returns free space available to the user (including quota limitations) // // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx -func Stat(path string) (total, free int64, err error) { - kernel32, err := syscall.LoadLibrary("Kernel32.dll") - if err != nil { - return 0, 0, err - } - defer syscall.FreeLibrary(kernel32) +func Stat(path string) (statfs StatFS, err error) { + dll := syscall.MustLoadDLL("kernel32.dll") // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx // Retrieves information about the amount of space that is available on a disk volume, // which is the total amount of space, the total amount of free space, and the total // amount of free space available to the user that is associated with the calling thread. - GetDiskFreeSpaceEx, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GetDiskFreeSpaceExW") - if err != nil { - return 0, 0, err - } + GetDiskFreeSpaceEx := dll.MustFindProc("GetDiskFreeSpaceExW") + lpFreeBytesAvailable := int64(0) lpTotalNumberOfBytes := int64(0) lpTotalNumberOfFreeBytes := int64(0) @@ -52,18 +46,13 @@ func Stat(path string) (total, free int64, err error) { // _Out_opt_ PULARGE_INTEGER lpTotalNumberOfBytes, // _Out_opt_ PULARGE_INTEGER lpTotalNumberOfFreeBytes // ); - r1, _, e1 := syscall.Syscall6(uintptr(GetDiskFreeSpaceEx), 4, - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))), + _, _, _ = GetDiskFreeSpaceEx.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))), uintptr(unsafe.Pointer(&lpFreeBytesAvailable)), uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)), - uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)), 0, 0) - if e1 != 0 { - return 0, 0, error(e1) - } - if r1 == 0 { - return 0, 0, syscall.EINVAL - } - total = int64(lpTotalNumberOfBytes) - free = int64(lpFreeBytesAvailable) - return total, free, nil + uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes))) + statfs = StatFS{} + statfs.Total = int64(lpTotalNumberOfBytes) + statfs.Free = int64(lpFreeBytesAvailable) + statfs.FSType = getFSType(path) + return statfs, nil } diff --git a/pkg/disk/type_darwin.go b/pkg/disk/type_darwin.go index 66293679e..b673b7033 100644 --- a/pkg/disk/type_darwin.go +++ b/pkg/disk/type_darwin.go @@ -28,22 +28,17 @@ var fsType2StringMap = map[string]string{ "11": "HFS", } -// FSType returns the filesystem type of the underlying mounted filesystem -func FSType(path string) (string, error) { +// getFSType returns the filesystem type of the underlying mounted filesystem +func getFSType(path string) (string, error) { s := syscall.Statfs_t{} err := syscall.Statfs(path, &s) if err != nil { return "", err } - return getFSType(s.Type), nil -} - -// getFSType - get filesystem type -func getFSType(fsType uint32) string { - fsTypeHex := strconv.FormatUint(uint64(fsType), 16) + fsTypeHex := strconv.FormatUint(uint64(s.Type), 16) fsTypeString, ok := fsType2StringMap[fsTypeHex] if ok == false { - return "UNKNOWN" + return "UNKNOWN", nil } - return fsTypeString + return fsTypeString, nil } diff --git a/pkg/disk/type_linux.go b/pkg/disk/type_linux.go index 339d28c8a..dcf55da9b 100644 --- a/pkg/disk/type_linux.go +++ b/pkg/disk/type_linux.go @@ -39,22 +39,17 @@ var fsType2StringMap = map[string]string{ "f15f": "ecryptfs", } -// FSType returns the filesystem type of the underlying mounted filesystem -func FSType(path string) (string, error) { +// getFSType returns the filesystem type of the underlying mounted filesystem +func getFSType(path string) (string, error) { s := syscall.Statfs_t{} err := syscall.Statfs(path, &s) if err != nil { return "", err } - return getFSType(s.Type), nil -} - -// getFSType - get filesystem type -func getFSType(fsType int64) string { - fsTypeHex := strconv.FormatInt(fsType, 16) + fsTypeHex := strconv.FormatInt(s.Type, 16) fsTypeString, ok := fsType2StringMap[fsTypeHex] if ok == false { - return "UNKNOWN" + return "UNKNOWN", nil } - return fsTypeString + return fsTypeString, nil } diff --git a/pkg/disk/type_windows.go b/pkg/disk/type_windows.go new file mode 100644 index 000000000..03946af09 --- /dev/null +++ b/pkg/disk/type_windows.go @@ -0,0 +1,68 @@ +// +build windows + +/* + * Minio Cloud Storage, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package disk + +import ( + "path/filepath" + "syscall" + "unsafe" +) + +// getFSType returns the filesystem type of the underlying mounted filesystem +func getFSType(path string) string { + dll := syscall.MustLoadDLL("kernel32.dll") + GetVolumeInformation := dll.MustFindProc("GetVolumeInformationW") + + var volumeNameSize uint32 = 260 + var nFileSystemNameSize, lpVolumeSerialNumber uint32 + var lpFileSystemFlags, lpMaximumComponentLength uint32 + var lpFileSystemNameBuffer, volumeName [260]byte + var ps = syscall.StringToUTF16Ptr(filepath.VolumeName(path)) + + // Extract values safely + // BOOL WINAPI GetVolumeInformation( + // _In_opt_ LPCTSTR lpRootPathName, + // _Out_opt_ LPTSTR lpVolumeNameBuffer, + // _In_ DWORD nVolumeNameSize, + // _Out_opt_ LPDWORD lpVolumeSerialNumber, + // _Out_opt_ LPDWORD lpMaximumComponentLength, + // _Out_opt_ LPDWORD lpFileSystemFlags, + // _Out_opt_ LPTSTR lpFileSystemNameBuffer, + // _In_ DWORD nFileSystemNameSize + // ); + + _, _, _ = GetVolumeInformation.Call(uintptr(unsafe.Pointer(ps)), + uintptr(unsafe.Pointer(&volumeName)), + uintptr(volumeNameSize), + uintptr(unsafe.Pointer(&lpVolumeSerialNumber)), + uintptr(unsafe.Pointer(&lpMaximumComponentLength)), + uintptr(unsafe.Pointer(&lpFileSystemFlags)), + uintptr(unsafe.Pointer(&lpFileSystemNameBuffer)), + uintptr(unsafe.Pointer(&nFileSystemNameSize)), 0) + var bytes []byte + if lpFileSystemNameBuffer[6] == 0 { + bytes = []byte{lpFileSystemNameBuffer[0], lpFileSystemNameBuffer[2], + lpFileSystemNameBuffer[4]} + } else { + bytes = []byte{lpFileSystemNameBuffer[0], lpFileSystemNameBuffer[2], + lpFileSystemNameBuffer[4], lpFileSystemNameBuffer[6]} + } + + return string(bytes) +}