shirou_gopsutil/disk/disk_windows.go

167 lines
4.9 KiB
Go
Raw Normal View History

2014-04-18 20:28:00 +08:00
// +build windows
2014-12-30 21:09:05 +08:00
package disk
2014-04-18 20:28:00 +08:00
2014-04-19 23:03:47 +08:00
import (
2014-04-20 00:53:34 +08:00
"bytes"
"context"
2014-04-19 23:03:47 +08:00
"unsafe"
2015-10-19 23:04:57 +08:00
"github.com/shirou/gopsutil/internal/common"
"golang.org/x/sys/windows"
2014-04-19 23:03:47 +08:00
)
var (
2014-11-27 21:28:05 +08:00
procGetDiskFreeSpaceExW = common.Modkernel32.NewProc("GetDiskFreeSpaceExW")
procGetLogicalDriveStringsW = common.Modkernel32.NewProc("GetLogicalDriveStringsW")
procGetDriveType = common.Modkernel32.NewProc("GetDriveTypeW")
2018-11-21 05:04:18 +08:00
procGetVolumeInformation = common.Modkernel32.NewProc("GetVolumeInformationW")
2014-04-20 00:53:34 +08:00
)
var (
2014-08-16 02:05:26 +08:00
FileFileCompression = int64(16) // 0x00000010
FileReadOnlyVolume = int64(524288) // 0x00080000
2014-04-19 23:03:47 +08:00
)
2014-04-18 20:28:00 +08:00
type Win32_PerfFormattedData struct {
Name string
AvgDiskBytesPerRead uint64
AvgDiskBytesPerWrite uint64
AvgDiskReadQueueLength uint64
AvgDiskWriteQueueLength uint64
AvgDisksecPerRead uint64
AvgDisksecPerWrite uint64
}
const WaitMSec = 500
func Usage(path string) (*UsageStat, error) {
2017-12-31 14:25:49 +08:00
return UsageWithContext(context.Background(), path)
}
func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
2014-04-19 23:03:47 +08:00
lpFreeBytesAvailable := int64(0)
lpTotalNumberOfBytes := int64(0)
lpTotalNumberOfFreeBytes := int64(0)
2014-04-20 00:53:34 +08:00
diskret, _, err := procGetDiskFreeSpaceExW.Call(
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(path))),
2014-04-19 23:03:47 +08:00
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
if diskret == 0 {
2015-08-27 23:51:03 +08:00
return nil, err
}
ret := &UsageStat{
Path: path,
Total: uint64(lpTotalNumberOfBytes),
Free: uint64(lpTotalNumberOfFreeBytes),
Used: uint64(lpTotalNumberOfBytes) - uint64(lpTotalNumberOfFreeBytes),
UsedPercent: (float64(lpTotalNumberOfBytes) - float64(lpTotalNumberOfFreeBytes)) / float64(lpTotalNumberOfBytes) * 100,
2015-08-27 23:51:03 +08:00
// InodesTotal: 0,
// InodesFree: 0,
// InodesUsed: 0,
// InodesUsedPercent: 0,
2014-04-19 23:03:47 +08:00
}
2014-04-18 20:28:00 +08:00
return ret, nil
}
2014-04-20 00:53:34 +08:00
func Partitions(all bool) ([]PartitionStat, error) {
2017-12-31 14:25:49 +08:00
return PartitionsWithContext(context.Background(), all)
}
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
var ret []PartitionStat
2014-04-20 00:53:34 +08:00
lpBuffer := make([]byte, 254)
diskret, _, err := procGetLogicalDriveStringsW.Call(
uintptr(len(lpBuffer)),
uintptr(unsafe.Pointer(&lpBuffer[0])))
if diskret == 0 {
return ret, err
}
for _, v := range lpBuffer {
if v >= 65 && v <= 90 {
path := string(v) + ":"
typepath, _ := windows.UTF16PtrFromString(path)
2014-04-20 00:53:34 +08:00
typeret, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(typepath)))
if typeret == 0 {
return ret, windows.GetLastError()
2014-04-20 00:53:34 +08:00
}
// 2: DRIVE_REMOVABLE 3: DRIVE_FIXED 4: DRIVE_REMOTE 5: DRIVE_CDROM
2014-04-20 00:53:34 +08:00
if typeret == 2 || typeret == 3 || typeret == 4 || typeret == 5 {
2014-04-20 00:53:34 +08:00
lpVolumeNameBuffer := make([]byte, 256)
lpVolumeSerialNumber := int64(0)
lpMaximumComponentLength := int64(0)
lpFileSystemFlags := int64(0)
lpFileSystemNameBuffer := make([]byte, 256)
volpath, _ := windows.UTF16PtrFromString(string(v) + ":/")
2018-11-21 05:04:18 +08:00
driveret, _, err := procGetVolumeInformation.Call(
2014-04-20 00:53:34 +08:00
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
}
2014-04-20 00:53:34 +08:00
return ret, err
}
opts := "rw"
2014-08-16 02:05:26 +08:00
if lpFileSystemFlags&FileReadOnlyVolume != 0 {
2014-04-20 00:53:34 +08:00
opts = "ro"
}
2014-08-16 02:05:26 +08:00
if lpFileSystemFlags&FileFileCompression != 0 {
2014-04-20 00:53:34 +08:00
opts += ".compress"
}
d := PartitionStat{
2014-04-20 00:53:34 +08:00
Mountpoint: path,
Device: path,
Fstype: string(bytes.Replace(lpFileSystemNameBuffer, []byte("\x00"), []byte(""), -1)),
Opts: opts,
}
ret = append(ret, d)
}
}
}
return ret, nil
}
2014-04-29 13:59:22 +08:00
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
2017-12-31 14:25:49 +08:00
return IOCountersWithContext(context.Background(), names...)
}
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
ret := make(map[string]IOCountersStat, 0)
var dst []Win32_PerfFormattedData
err := common.WMIQueryWithContext(ctx, "SELECT * FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk", &dst)
if err != nil {
return ret, err
}
for _, d := range dst {
if len(d.Name) > 3 { // not get _Total or Harddrive
continue
}
2017-04-10 21:24:36 +08:00
if len(names) > 0 && !common.StringsHas(names, d.Name) {
continue
}
ret[d.Name] = IOCountersStat{
Name: d.Name,
ReadCount: uint64(d.AvgDiskReadQueueLength),
WriteCount: d.AvgDiskWriteQueueLength,
ReadBytes: uint64(d.AvgDiskBytesPerRead),
WriteBytes: uint64(d.AvgDiskBytesPerWrite),
ReadTime: d.AvgDisksecPerRead,
WriteTime: d.AvgDisksecPerWrite,
}
}
return ret, nil
2014-04-29 13:59:22 +08:00
}