From b515acb162904e1ebed73a33bbfc471bb9bcb41a Mon Sep 17 00:00:00 2001 From: Matthew Palmer <9059517+56KBs@users.noreply.github.com> Date: Fri, 11 Mar 2022 16:15:54 +0000 Subject: [PATCH 1/2] [disk][windows] Support LabelWithContext & SerialNumberWithContext Add support for LabelWithContext & SerialNumberWithContext, additionally returning this data back for the IOCountersWithContext function. --- disk/disk_windows.go | 163 ++++++++++++++++++++++++++++--------------- 1 file changed, 107 insertions(+), 56 deletions(-) diff --git a/disk/disk_windows.go b/disk/disk_windows.go index b7f0c515e..0092e9856 100644 --- a/disk/disk_windows.go +++ b/disk/disk_windows.go @@ -6,12 +6,15 @@ package disk import ( "bytes" "context" + "errors" "fmt" + "strconv" "syscall" "unsafe" - "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/windows" + + "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/windows/registry" ) @@ -93,55 +96,27 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro } 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() - warnings.Add(err) + i, err := getVolumeInformation(string(v)) + if err != nil && !errors.Is(err, errDeviceNotReady) && !errors.Is(err, errInvalidDriveType) { continue } - // 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") - } - d := PartitionStat{ - Mountpoint: path, - Device: path, - Fstype: string(bytes.Replace(lpFileSystemNameBuffer, []byte("\x00"), []byte(""), -1)), - Opts: opts, - } - ret = append(ret, d) + opts := []string{"rw"} + if i.FileSystemFlags&fileReadOnlyVolume != 0 { + opts = []string{"ro"} + } + if i.FileSystemFlags&fileFileCompression != 0 { + opts = append(opts, "compress") + } + + path := string(v) + ":" + d := PartitionStat{ + Mountpoint: path, + Device: path, + Fstype: i.FileSystemName, + Opts: opts, } + ret = append(ret, d) } } return ret, warnings.Reference() @@ -159,7 +134,8 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC } for _, v := range lpBuffer[:lpBufferLen] { if 'A' <= v && v <= 'Z' { - path := string(rune(v)) + ":" + vStr := string(rune(v)) + path := vStr + ":" typepath, _ := windows.UTF16PtrFromString(path) typeret := windows.GetDriveType(typepath) if typeret == 0 { @@ -184,14 +160,22 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC if err != nil { return drivemap, err } + + i, err := getVolumeInformation(vStr) + if err != nil { + return nil, err + } + drivemap[path] = IOCountersStat{ - 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, + 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, + SerialNumber: strconv.FormatInt(i.SerialNumber, 10), + Label: i.Label, } } } @@ -199,9 +183,76 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC } func SerialNumberWithContext(ctx context.Context, name string) (string, error) { - return "", common.ErrNotImplementedError + i, err := getVolumeInformation(name) + if err != nil { + return "", err + } + + return strconv.FormatInt(i.SerialNumber, 10), nil } func LabelWithContext(ctx context.Context, name string) (string, error) { - return "", common.ErrNotImplementedError + i, err := getVolumeInformation(name) + if err != nil { + return "", err + } + + return i.Label, nil +} + +type volumeInformation struct { + Label string + SerialNumber int64 + MaximumComponentLength int64 + FileSystemFlags int64 + FileSystemName string +} + +var ( + errDeviceNotReady = errors.New("device not ready") + errInvalidDriveType = errors.New("invalid drive type specified") +) + +// getVolumeInformation returns all the information gathered from GetVolumeInformationW +func getVolumeInformation(name string) (*volumeInformation, error) { + path := name + ":" + typepath, _ := windows.UTF16PtrFromString(path) + typeret, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(typepath))) + if typeret == 0 { + return nil, windows.GetLastError() + } + + if typeret == windows.DRIVE_REMOVABLE || typeret == windows.DRIVE_FIXED || typeret == windows.DRIVE_REMOTE || typeret == windows.DRIVE_CDROM { + lpVolumeNameBuffer := make([]byte, 256) + lpVolumeSerialNumber := int64(0) + lpMaximumComponentLength := int64(0) + lpFileSystemFlags := int64(0) + lpFileSystemNameBuffer := make([]byte, 256) + volpath, _ := windows.UTF16PtrFromString(name + ":/") + 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 { + return nil, errDeviceNotReady // device is not ready will happen if there is no disk in the drive + } + return nil, err + } + + return &volumeInformation{ + Label: string(bytes.Replace(lpVolumeNameBuffer, []byte("\x00"), []byte(""), -1)), + SerialNumber: lpVolumeSerialNumber, + MaximumComponentLength: lpMaximumComponentLength, + FileSystemFlags: lpFileSystemFlags, + FileSystemName: string(bytes.Replace(lpFileSystemNameBuffer, []byte("\x00"), []byte(""), -1)), + }, nil + } + + return nil, errInvalidDriveType } From d7c791252a45b26f40217ad7af7b1d288f80e86c Mon Sep 17 00:00:00 2001 From: Frank Spitulski Date: Wed, 19 Oct 2022 19:19:59 -0700 Subject: [PATCH 2/2] rebase on master --- disk/disk_windows.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/disk/disk_windows.go b/disk/disk_windows.go index 0092e9856..fb61bb0f4 100644 --- a/disk/disk_windows.go +++ b/disk/disk_windows.go @@ -96,7 +96,7 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro } for _, v := range lpBuffer { if v >= 65 && v <= 90 { - i, err := getVolumeInformation(string(v)) + i, err := getVolumeInformation(string(v), &warnings) if err != nil && !errors.Is(err, errDeviceNotReady) && !errors.Is(err, errInvalidDriveType) { continue } @@ -161,7 +161,7 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC return drivemap, err } - i, err := getVolumeInformation(vStr) + i, err := getVolumeInformation(vStr, nil) if err != nil { return nil, err } @@ -183,7 +183,7 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC } func SerialNumberWithContext(ctx context.Context, name string) (string, error) { - i, err := getVolumeInformation(name) + i, err := getVolumeInformation(name, nil) if err != nil { return "", err } @@ -192,7 +192,7 @@ func SerialNumberWithContext(ctx context.Context, name string) (string, error) { } func LabelWithContext(ctx context.Context, name string) (string, error) { - i, err := getVolumeInformation(name) + i, err := getVolumeInformation(name, nil) if err != nil { return "", err } @@ -214,12 +214,16 @@ var ( ) // getVolumeInformation returns all the information gathered from GetVolumeInformationW -func getVolumeInformation(name string) (*volumeInformation, error) { +func getVolumeInformation(name string, warnings *common.Warnings) (*volumeInformation, error) { path := name + ":" typepath, _ := windows.UTF16PtrFromString(path) typeret, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(typepath))) if typeret == 0 { - return nil, windows.GetLastError() + err := windows.GetLastError() + if warnings != nil { + warnings.Add(err) + } + return nil, err } if typeret == windows.DRIVE_REMOVABLE || typeret == windows.DRIVE_FIXED || typeret == windows.DRIVE_REMOTE || typeret == windows.DRIVE_CDROM { @@ -242,6 +246,9 @@ func getVolumeInformation(name string) (*volumeInformation, error) { if typeret == 5 || typeret == 2 { return nil, errDeviceNotReady // device is not ready will happen if there is no disk in the drive } + if warnings != nil { + warnings.Add(err) + } return nil, err }