1
2
3
4
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
42
43 func Info(path string) (int64, int64, int64, int64, int64, int64, error) {
44 var freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes int64
45 var err error
46
47
48
49
50
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
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 }
118
View as plain text