Skip to content

Latest commit

 

History

History
241 lines (219 loc) · 7.44 KB

disk_windows.go

File metadata and controls

241 lines (219 loc) · 7.44 KB
 
Dec 22, 2021
Dec 22, 2021
1
//go:build windows
Apr 18, 2014
Apr 18, 2014
2
3
// +build windows
Dec 30, 2014
Dec 30, 2014
4
package disk
Apr 18, 2014
Apr 18, 2014
5
Apr 19, 2014
Apr 19, 2014
6
import (
Apr 19, 2014
Apr 19, 2014
7
"bytes"
Nov 20, 2017
Nov 20, 2017
8
"context"
Mar 13, 2020
Mar 13, 2020
9
10
"fmt"
"syscall"
Apr 19, 2014
Apr 19, 2014
11
"unsafe"
Nov 27, 2014
Nov 27, 2014
12
Oct 20, 2022
Oct 20, 2022
13
"github.com/shirou/gopsutil/v3/internal/common"
Nov 30, 2022
Nov 30, 2022
14
"golang.org/x/sys/windows"
May 5, 2022
May 5, 2022
15
"golang.org/x/sys/windows/registry"
Apr 19, 2014
Apr 19, 2014
16
17
18
)
var (
Nov 27, 2014
Nov 27, 2014
19
20
21
procGetDiskFreeSpaceExW = common.Modkernel32.NewProc("GetDiskFreeSpaceExW")
procGetLogicalDriveStringsW = common.Modkernel32.NewProc("GetLogicalDriveStringsW")
procGetDriveType = common.Modkernel32.NewProc("GetDriveTypeW")
Nov 20, 2018
Nov 20, 2018
22
procGetVolumeInformation = common.Modkernel32.NewProc("GetVolumeInformationW")
Apr 19, 2014
Apr 19, 2014
23
24
25
)
var (
Nov 30, 2021
Nov 30, 2021
26
27
fileFileCompression = int64(16) // 0x00000010
fileReadOnlyVolume = int64(524288) // 0x00080000
Apr 19, 2014
Apr 19, 2014
28
)
Apr 18, 2014
Apr 18, 2014
29
Mar 13, 2020
Mar 13, 2020
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// diskPerformance is an equivalent representation of DISK_PERFORMANCE in the Windows API.
// https://docs.microsoft.com/fr-fr/windows/win32/api/winioctl/ns-winioctl-disk_performance
type diskPerformance struct {
BytesRead int64
BytesWritten int64
ReadTime int64
WriteTime int64
IdleTime int64
ReadCount uint32
WriteCount uint32
QueueDepth uint32
SplitCount uint32
QueryTime int64
StorageDeviceNumber uint32
StorageManagerName [8]uint16
alignmentPadding uint32 // necessary for 32bit support, see https://github.com/elastic/beats/pull/16553
Sep 5, 2015
Sep 5, 2015
46
47
}
May 5, 2022
May 5, 2022
48
49
50
51
52
func init() {
// enable disk performance counters on Windows Server editions (needs to run as admin)
key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Services\PartMgr`, registry.SET_VALUE)
if err == nil {
key.SetDWordValue("EnableCounterForIoctl", 1)
Aug 10, 2023
Aug 10, 2023
53
key.Close()
May 5, 2022
May 5, 2022
54
55
56
}
}
Dec 31, 2017
Dec 31, 2017
57
func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
Apr 19, 2014
Apr 19, 2014
58
59
60
lpFreeBytesAvailable := int64(0)
lpTotalNumberOfBytes := int64(0)
lpTotalNumberOfFreeBytes := int64(0)
Apr 19, 2014
Apr 19, 2014
61
diskret, _, err := procGetDiskFreeSpaceExW.Call(
Jun 2, 2017
Jun 2, 2017
62
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(path))),
Apr 19, 2014
Apr 19, 2014
63
64
65
66
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
if diskret == 0 {
Aug 27, 2015
Aug 27, 2015
67
68
return nil, err
}
Mar 23, 2019
Mar 23, 2019
69
ret := &UsageStat{
Sep 4, 2015
Sep 4, 2015
70
71
72
73
74
Path: path,
Total: uint64(lpTotalNumberOfBytes),
Free: uint64(lpTotalNumberOfFreeBytes),
Used: uint64(lpTotalNumberOfBytes) - uint64(lpTotalNumberOfFreeBytes),
UsedPercent: (float64(lpTotalNumberOfBytes) - float64(lpTotalNumberOfFreeBytes)) / float64(lpTotalNumberOfBytes) * 100,
Aug 27, 2015
Aug 27, 2015
75
76
77
78
// InodesTotal: 0,
// InodesFree: 0,
// InodesUsed: 0,
// InodesUsedPercent: 0,
Apr 19, 2014
Apr 19, 2014
79
}
Apr 18, 2014
Apr 18, 2014
80
81
return ret, nil
}
Apr 19, 2014
Apr 19, 2014
82
Jan 14, 2023
Jan 14, 2023
83
84
// PartitionsWithContext returns disk partitions.
// Since GetVolumeInformation doesn't have a timeout, this method uses context to set deadline by users.
Dec 31, 2017
Dec 31, 2017
85
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
Nov 19, 2022
Nov 19, 2022
86
warnings := Warnings{
Oct 3, 2022
Oct 3, 2022
87
88
Verbose: true,
}
Aug 10, 2023
Aug 10, 2023
89
90
91
92
93
94
95
96
97
98
var errLogicalDrives error
retChan := make(chan PartitionStat)
quitChan := make(chan struct{})
defer close(quitChan)
getPartitions := func() {
defer close(retChan)
lpBuffer := make([]byte, 254)
Mar 14, 2023
Mar 14, 2023
99
Jan 14, 2023
Jan 14, 2023
100
101
102
103
diskret, _, err := procGetLogicalDriveStringsW.Call(
uintptr(len(lpBuffer)),
uintptr(unsafe.Pointer(&lpBuffer[0])))
if diskret == 0 {
Aug 10, 2023
Aug 10, 2023
104
errLogicalDrives = err
Jan 14, 2023
Jan 14, 2023
105
106
107
108
109
110
111
112
113
return
}
for _, v := range lpBuffer {
if v >= 65 && v <= 90 {
path := string(v) + ":"
typepath, _ := windows.UTF16PtrFromString(path)
typeret, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(typepath)))
if typeret == 0 {
err := windows.GetLastError()
Nov 30, 2022
Nov 30, 2022
114
115
116
warnings.Add(err)
continue
}
Jan 14, 2023
Jan 14, 2023
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// 2: DRIVE_REMOVABLE 3: DRIVE_FIXED 4: DRIVE_REMOTE 5: DRIVE_CDROM
if typeret == 2 || typeret == 3 || typeret == 4 || typeret == 5 {
lpVolumeNameBuffer := make([]byte, 256)
lpVolumeSerialNumber := int64(0)
lpMaximumComponentLength := int64(0)
lpFileSystemFlags := int64(0)
lpFileSystemNameBuffer := make([]byte, 256)
volpath, _ := windows.UTF16PtrFromString(string(v) + ":/")
driveret, _, err := procGetVolumeInformation.Call(
uintptr(unsafe.Pointer(volpath)),
uintptr(unsafe.Pointer(&lpVolumeNameBuffer[0])),
uintptr(len(lpVolumeNameBuffer)),
uintptr(unsafe.Pointer(&lpVolumeSerialNumber)),
uintptr(unsafe.Pointer(&lpMaximumComponentLength)),
uintptr(unsafe.Pointer(&lpFileSystemFlags)),
uintptr(unsafe.Pointer(&lpFileSystemNameBuffer[0])),
uintptr(len(lpFileSystemNameBuffer)))
if driveret == 0 {
if typeret == 5 || typeret == 2 {
continue // device is not ready will happen if there is no disk in the drive
}
warnings.Add(err)
continue
}
opts := []string{"rw"}
if lpFileSystemFlags&fileReadOnlyVolume != 0 {
opts = []string{"ro"}
}
if lpFileSystemFlags&fileFileCompression != 0 {
opts = append(opts, "compress")
}
Apr 19, 2014
Apr 19, 2014
149
Aug 10, 2023
Aug 10, 2023
150
151
select {
case retChan <- PartitionStat{
Jan 14, 2023
Jan 14, 2023
152
153
Mountpoint: path,
Device: path,
Aug 10, 2023
Aug 10, 2023
154
Fstype: string(bytes.ReplaceAll(lpFileSystemNameBuffer, []byte("\x00"), []byte(""))),
Jan 14, 2023
Jan 14, 2023
155
Opts: opts,
Aug 10, 2023
Aug 10, 2023
156
157
158
}:
case <-quitChan:
return
Jan 14, 2023
Jan 14, 2023
159
}
Nov 30, 2022
Nov 30, 2022
160
}
Apr 19, 2014
Apr 19, 2014
161
162
}
}
Jan 14, 2023
Jan 14, 2023
163
164
}
Aug 10, 2023
Aug 10, 2023
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
go getPartitions()
var ret []PartitionStat
for {
select {
case p, ok := <-retChan:
if !ok {
if errLogicalDrives != nil {
return ret, errLogicalDrives
}
return ret, warnings.Reference()
}
ret = append(ret, p)
case <-ctx.Done():
return ret, ctx.Err()
}
Apr 19, 2014
Apr 19, 2014
181
182
}
}
Apr 29, 2014
Apr 29, 2014
183
Dec 31, 2017
Dec 31, 2017
184
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
Mar 13, 2020
Mar 13, 2020
185
186
187
// https://github.com/giampaolo/psutil/blob/544e9daa4f66a9f80d7bf6c7886d693ee42f0a13/psutil/arch/windows/disk.c#L83
drivemap := make(map[string]IOCountersStat, 0)
var diskPerformance diskPerformance
Feb 19, 2015
Feb 19, 2015
188
Mar 13, 2020
Mar 13, 2020
189
190
lpBuffer := make([]uint16, 254)
lpBufferLen, err := windows.GetLogicalDriveStrings(uint32(len(lpBuffer)), &lpBuffer[0])
Sep 5, 2015
Sep 5, 2015
191
if err != nil {
Mar 13, 2020
Mar 13, 2020
192
return drivemap, err
Feb 19, 2015
Feb 19, 2015
193
}
Mar 13, 2020
Mar 13, 2020
194
195
for _, v := range lpBuffer[:lpBufferLen] {
if 'A' <= v && v <= 'Z' {
Nov 30, 2022
Nov 30, 2022
196
path := string(rune(v)) + ":"
Mar 13, 2020
Mar 13, 2020
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
typepath, _ := windows.UTF16PtrFromString(path)
typeret := windows.GetDriveType(typepath)
if typeret == 0 {
return drivemap, windows.GetLastError()
}
if typeret != windows.DRIVE_FIXED {
continue
}
szDevice := fmt.Sprintf(`\\.\%s`, path)
const IOCTL_DISK_PERFORMANCE = 0x70020
h, err := windows.CreateFile(syscall.StringToUTF16Ptr(szDevice), 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, 0, 0)
if err != nil {
if err == windows.ERROR_FILE_NOT_FOUND {
continue
}
return drivemap, err
}
defer windows.CloseHandle(h)
Apr 7, 2017
Apr 7, 2017
215
Mar 13, 2020
Mar 13, 2020
216
217
218
219
220
221
var diskPerformanceSize uint32
err = windows.DeviceIoControl(h, IOCTL_DISK_PERFORMANCE, nil, 0, (*byte)(unsafe.Pointer(&diskPerformance)), uint32(unsafe.Sizeof(diskPerformance)), &diskPerformanceSize, nil)
if err != nil {
return drivemap, err
}
drivemap[path] = IOCountersStat{
Nov 30, 2022
Nov 30, 2022
222
223
224
225
226
227
228
ReadBytes: uint64(diskPerformance.BytesRead),
WriteBytes: uint64(diskPerformance.BytesWritten),
ReadCount: uint64(diskPerformance.ReadCount),
WriteCount: uint64(diskPerformance.WriteCount),
ReadTime: uint64(diskPerformance.ReadTime / 10000 / 1000), // convert to ms: https://github.com/giampaolo/psutil/issues/1012
WriteTime: uint64(diskPerformance.WriteTime / 10000 / 1000),
Name: path,
Mar 13, 2020
Mar 13, 2020
229
}
Feb 19, 2015
Feb 19, 2015
230
231
}
}
Mar 13, 2020
Mar 13, 2020
232
return drivemap, nil
Apr 29, 2014
Apr 29, 2014
233
}
Nov 30, 2021
Nov 30, 2021
234
235
func SerialNumberWithContext(ctx context.Context, name string) (string, error) {
Nov 30, 2022
Nov 30, 2022
236
return "", common.ErrNotImplementedError
Nov 30, 2021
Nov 30, 2021
237
238
239
}
func LabelWithContext(ctx context.Context, name string) (string, error) {
Nov 30, 2022
Nov 30, 2022
240
return "", common.ErrNotImplementedError
Nov 30, 2021
Nov 30, 2021
241
}