storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/disk/stat_windows.go (about)

     1  //go:build windows
     2  // +build windows
     3  
     4  /*
     5   * MinIO Cloud Storage, (C) 2015 MinIO, Inc.
     6   *
     7   * Licensed under the Apache License, Version 2.0 (the "License");
     8   * you may not use this file except in compliance with the License.
     9   * You may obtain a copy of the License at
    10   *
    11   *     http://www.apache.org/licenses/LICENSE-2.0
    12   *
    13   * Unless required by applicable law or agreed to in writing, software
    14   * distributed under the License is distributed on an "AS IS" BASIS,
    15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16   * See the License for the specific language governing permissions and
    17   * limitations under the License.
    18   */
    19  
    20  package disk
    21  
    22  import (
    23  	"fmt"
    24  	"os"
    25  	"syscall"
    26  	"unsafe"
    27  
    28  	"golang.org/x/sys/windows"
    29  )
    30  
    31  var (
    32  	kernel32 = windows.NewLazySystemDLL("kernel32.dll")
    33  
    34  	// GetDiskFreeSpaceEx - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx
    35  	// Retrieves information about the amount of space that is available on a disk volume,
    36  	// which is the total amount of space, the total amount of free space, and the total
    37  	// amount of free space available to the user that is associated with the calling thread.
    38  	GetDiskFreeSpaceEx = kernel32.NewProc("GetDiskFreeSpaceExW")
    39  
    40  	// GetDiskFreeSpace - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364935(v=vs.85).aspx
    41  	// Retrieves information about the specified disk, including the amount of free space on the disk.
    42  	GetDiskFreeSpace = kernel32.NewProc("GetDiskFreeSpaceW")
    43  )
    44  
    45  // GetInfo returns total and free bytes available in a directory, e.g. `C:\`.
    46  // It returns free space available to the user (including quota limitations)
    47  //
    48  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx
    49  func GetInfo(path string) (info Info, err error) {
    50  	// Stat to know if the path exists.
    51  	if _, err = os.Stat(path); err != nil {
    52  		return Info{}, err
    53  	}
    54  
    55  	lpFreeBytesAvailable := int64(0)
    56  	lpTotalNumberOfBytes := int64(0)
    57  	lpTotalNumberOfFreeBytes := int64(0)
    58  
    59  	// Extract values safely
    60  	// BOOL WINAPI GetDiskFreeSpaceEx(
    61  	// _In_opt_  LPCTSTR         lpDirectoryName,
    62  	// _Out_opt_ PULARGE_INTEGER lpFreeBytesAvailable,
    63  	// _Out_opt_ PULARGE_INTEGER lpTotalNumberOfBytes,
    64  	// _Out_opt_ PULARGE_INTEGER lpTotalNumberOfFreeBytes
    65  	// );
    66  	_, _, _ = GetDiskFreeSpaceEx.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))),
    67  		uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
    68  		uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
    69  		uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
    70  
    71  	if uint64(lpTotalNumberOfFreeBytes) > uint64(lpTotalNumberOfBytes) {
    72  		return info, fmt.Errorf("detected free space (%d) > total disk space (%d), fs corruption at (%s). please run 'fsck'",
    73  			uint64(lpTotalNumberOfFreeBytes), uint64(lpTotalNumberOfBytes), path)
    74  	}
    75  
    76  	info = Info{
    77  		Total:  uint64(lpTotalNumberOfBytes),
    78  		Free:   uint64(lpTotalNumberOfFreeBytes),
    79  		Used:   uint64(lpTotalNumberOfBytes) - uint64(lpTotalNumberOfFreeBytes),
    80  		FSType: getFSType(path),
    81  	}
    82  
    83  	// Return values of GetDiskFreeSpace()
    84  	lpSectorsPerCluster := uint32(0)
    85  	lpBytesPerSector := uint32(0)
    86  	lpNumberOfFreeClusters := uint32(0)
    87  	lpTotalNumberOfClusters := uint32(0)
    88  
    89  	// Extract values safely
    90  	// BOOL WINAPI GetDiskFreeSpace(
    91  	//   _In_  LPCTSTR lpRootPathName,
    92  	//   _Out_ LPDWORD lpSectorsPerCluster,
    93  	//   _Out_ LPDWORD lpBytesPerSector,
    94  	//   _Out_ LPDWORD lpNumberOfFreeClusters,
    95  	//   _Out_ LPDWORD lpTotalNumberOfClusters
    96  	// );
    97  	_, _, _ = GetDiskFreeSpace.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))),
    98  		uintptr(unsafe.Pointer(&lpSectorsPerCluster)),
    99  		uintptr(unsafe.Pointer(&lpBytesPerSector)),
   100  		uintptr(unsafe.Pointer(&lpNumberOfFreeClusters)),
   101  		uintptr(unsafe.Pointer(&lpTotalNumberOfClusters)))
   102  
   103  	info.Files = uint64(lpTotalNumberOfClusters)
   104  	info.Ffree = uint64(lpNumberOfFreeClusters)
   105  
   106  	return info, nil
   107  }