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  }