github.com/searKing/golang/go@v1.2.117/os/disk_windows.go (about) 1 // Copyright 2022 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build windows 6 7 // Code borrowed from https://github.com/minio/minio/blob/master/internal/disk/stat_windows.go 8 9 package os 10 11 import ( 12 "fmt" 13 "os" 14 "syscall" 15 "unsafe" 16 17 "golang.org/x/sys/windows" 18 ) 19 20 var ( 21 kernel32 = windows.NewLazySystemDLL("kernel32.dll") 22 23 // GetDiskFreeSpaceEx - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx 24 // Retrieves information about the amount of space that is available on a disk volume, 25 // which is the total amount of space, the total amount of free space, and the total 26 // amount of free space available to the user that is associated with the calling thread. 27 GetDiskFreeSpaceEx = kernel32.NewProc("GetDiskFreeSpaceExW") 28 29 // GetDiskFreeSpace - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364935(v=vs.85).aspx 30 // Retrieves information about the specified disk, including the amount of free space on the disk. 31 GetDiskFreeSpace = kernel32.NewProc("GetDiskFreeSpaceW") 32 ) 33 34 // DiskUsage returns total and free bytes available in a directory, e.g. `C:\`. 35 // It returns free space available to the user (including quota limitations) 36 // 37 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx 38 func DiskUsage(path string) (total int64, free int64, avail int64, inodes int64, inodesFree int64, err error) { 39 // Stat to know if the path exists. 40 if _, err = os.Stat(path); err != nil { 41 return 0, 0, 0, 0, 0, err 42 } 43 44 lpFreeBytesAvailable := int64(0) 45 lpTotalNumberOfBytes := int64(0) 46 lpTotalNumberOfFreeBytes := int64(0) 47 48 // Extract values safely 49 // BOOL WINAPI GetDiskFreeSpaceEx( 50 // _In_opt_ LPCTSTR lpDirectoryName, 51 // _Out_opt_ PULARGE_INTEGER lpFreeBytesAvailable, 52 // _Out_opt_ PULARGE_INTEGER lpTotalNumberOfBytes, 53 // _Out_opt_ PULARGE_INTEGER lpTotalNumberOfFreeBytes 54 // ); 55 _, _, _ = GetDiskFreeSpaceEx.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))), 56 uintptr(unsafe.Pointer(&lpFreeBytesAvailable)), 57 uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)), 58 uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes))) 59 60 if uint64(lpTotalNumberOfFreeBytes) > uint64(lpTotalNumberOfBytes) { 61 return 0, 0, 0, 0, 0, fmt.Errorf("detected free space (%d) > total disk space (%d), fs corruption at (%s). please run 'fsck'", 62 uint64(lpTotalNumberOfFreeBytes), uint64(lpTotalNumberOfBytes), path) 63 } 64 65 // Return values of GetDiskFreeSpace() 66 lpSectorsPerCluster := uint32(0) 67 lpBytesPerSector := uint32(0) 68 lpNumberOfFreeClusters := uint32(0) 69 lpTotalNumberOfClusters := uint32(0) 70 71 // Extract values safely 72 // BOOL WINAPI GetDiskFreeSpace( 73 // _In_ LPCTSTR lpRootPathName, 74 // _Out_ LPDWORD lpSectorsPerCluster, 75 // _Out_ LPDWORD lpBytesPerSector, 76 // _Out_ LPDWORD lpNumberOfFreeClusters, 77 // _Out_ LPDWORD lpTotalNumberOfClusters 78 // ); 79 _, _, _ = GetDiskFreeSpace.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))), 80 uintptr(unsafe.Pointer(&lpSectorsPerCluster)), 81 uintptr(unsafe.Pointer(&lpBytesPerSector)), 82 uintptr(unsafe.Pointer(&lpNumberOfFreeClusters)), 83 uintptr(unsafe.Pointer(&lpTotalNumberOfClusters))) 84 85 return lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes, lpFreeBytesAvailable, int64(lpTotalNumberOfClusters), int64(lpNumberOfFreeClusters), err 86 }