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