k8s.io/kubernetes@v1.29.3/pkg/volume/util/fs/fs_windows.go (about) 1 //go:build windows 2 // +build windows 3 4 /* 5 Copyright 2014 The Kubernetes Authors. 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 fs 21 22 import ( 23 "os" 24 "path/filepath" 25 "syscall" 26 "unsafe" 27 28 "golang.org/x/sys/windows" 29 ) 30 31 var ( 32 modkernel32 = windows.NewLazySystemDLL("kernel32.dll") 33 procGetDiskFreeSpaceEx = modkernel32.NewProc("GetDiskFreeSpaceExW") 34 ) 35 36 type UsageInfo struct { 37 Bytes int64 38 Inodes int64 39 } 40 41 // Info returns (available bytes, byte capacity, byte usage, total inodes, inodes free, inode usage, error) 42 // for the filesystem that path resides upon. 43 func Info(path string) (int64, int64, int64, int64, int64, int64, error) { 44 var freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes int64 45 var err error 46 47 // The equivalent linux call supports calls against files but the syscall for windows 48 // fails for files with error code: The directory name is invalid. (#99173) 49 // https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- 50 // By always ensuring the directory path we meet all uses cases of this function 51 path = filepath.Dir(path) 52 ret, _, err := syscall.Syscall6( 53 procGetDiskFreeSpaceEx.Addr(), 54 4, 55 uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))), 56 uintptr(unsafe.Pointer(&freeBytesAvailable)), 57 uintptr(unsafe.Pointer(&totalNumberOfBytes)), 58 uintptr(unsafe.Pointer(&totalNumberOfFreeBytes)), 59 0, 60 0, 61 ) 62 if ret == 0 { 63 return 0, 0, 0, 0, 0, 0, err 64 } 65 66 return freeBytesAvailable, totalNumberOfBytes, totalNumberOfBytes - freeBytesAvailable, 0, 0, 0, nil 67 } 68 69 // DiskUsage gets disk usage of specified path. 70 func DiskUsage(path string) (UsageInfo, error) { 71 var usage UsageInfo 72 info, err := os.Lstat(path) 73 if err != nil { 74 return usage, err 75 } 76 77 usage.Bytes, err = diskUsage(path, info) 78 return usage, err 79 } 80 81 func diskUsage(currPath string, info os.FileInfo) (int64, error) { 82 var size int64 83 84 if info.Mode()&os.ModeSymlink != 0 { 85 return size, nil 86 } 87 88 size += info.Size() 89 90 if !info.IsDir() { 91 return size, nil 92 } 93 94 dir, err := os.Open(currPath) 95 if err != nil { 96 return size, err 97 } 98 defer dir.Close() 99 100 files, err := dir.Readdir(-1) 101 if err != nil { 102 return size, err 103 } 104 105 for _, file := range files { 106 if file.IsDir() { 107 s, err := diskUsage(filepath.Join(currPath, file.Name()), file) 108 if err != nil { 109 return size, err 110 } 111 size += s 112 } else { 113 size += file.Size() 114 } 115 } 116 return size, nil 117 }