diff --git a/disk.go b/disk.go index 79179a10fcc8a95f46fa707b0972869d0066e9aa..7f2e003bcf04745db081023f3efab513f64e12cb 100644 --- a/disk.go +++ b/disk.go @@ -10,6 +10,13 @@ type Disk_usage struct { UsedPercent float64 `json:"usedPercent"` } +type Disk_partition struct { + Device string `json:"device"` + Mountpoint string `json:"mountpoint"` + Fstype string `json:"fstype"` + Opts string `json:"opts"` +} + type Disk_IO_Counters struct { ReadCount uint64 `json:"readCount"` WriteCount uint64 `json:"writeCount"` diff --git a/disk_test.go b/disk_test.go index 2f38c0eec2cca16dd729e4b7e8a31270aa49cac0..c76c37cf1fcb7ebb1307991748f91748e33e3802 100644 --- a/disk_test.go +++ b/disk_test.go @@ -21,3 +21,14 @@ func TestDisk_usage(t *testing.T) { d, _ := json.Marshal(v) fmt.Printf("%s\n", d) } + +func TestDisk_partitions(t *testing.T) { + disk := NewDisk() + + v, err := disk.Disk_partitions() + if err != nil { + t.Errorf("error %v", err) + } + d, _ := json.Marshal(v) + fmt.Printf("%s\n", d) +} diff --git a/disk_windows.go b/disk_windows.go index baca9a8aca8fe4fb7e6a708f8607d2d18c4d3b8b..f271444c6c96662fbfa7837d085f82084dc3882a 100644 --- a/disk_windows.go +++ b/disk_windows.go @@ -3,13 +3,21 @@ package main import ( + "bytes" "syscall" "unsafe" ) var ( - procGetDiskFreeSpaceExW = modkernel32.NewProc("GetDiskFreeSpaceExW") - //GetLogicalDriveStrings, _ = syscall.GetProcAddress(modkernel32, "GetLogicalDriveStringsW") + procGetDiskFreeSpaceExW = modkernel32.NewProc("GetDiskFreeSpaceExW") + procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW") + procGetDriveType = modkernel32.NewProc("GetDriveTypeW") + provGetVolumeInformation = modKernel32.NewProc("GetVolumeInformationW") +) + +var ( + FILE_FILE_COMPRESSION = int64(16) // 0x00000010 + FILE_READ_ONLY_VOLUME = int64(524288) // 0x00080000 ) func (d Disk) Disk_usage(path string) (Disk_usage, error) { @@ -19,13 +27,13 @@ func (d Disk) Disk_usage(path string) (Disk_usage, error) { lpFreeBytesAvailable := int64(0) lpTotalNumberOfBytes := int64(0) lpTotalNumberOfFreeBytes := int64(0) - diskret, _, _ := procGetDiskFreeSpaceExW.Call( + diskret, _, err := procGetDiskFreeSpaceExW.Call( uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))), uintptr(unsafe.Pointer(&lpFreeBytesAvailable)), uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)), uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes))) if diskret == 0 { - return ret, syscall.GetLastError() + return ret, err } ret.Total = uint64(lpTotalNumberOfBytes) // ret.Free = uint64(lpFreeBytesAvailable) // python psutil does not use this @@ -35,3 +43,65 @@ func (d Disk) Disk_usage(path string) (Disk_usage, error) { return ret, nil } + +func (d Disk) Disk_partitions() ([]Disk_partition, error) { + ret := make([]Disk_partition, 0) + 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) + ":" + if path == "A:" || path == "B:" { // skip floppy drives + continue + } + typepath, _ := syscall.UTF16PtrFromString(path) + typeret, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(typepath))) + if typeret == 0 { + return ret, syscall.GetLastError() + } + // 2: DRIVE_REMOVABLE 3: DRIVE_FIXED 5: DRIVE_CDROM + + if typeret == 2 || typeret == 3 || typeret == 5 { + lpVolumeNameBuffer := make([]byte, 256) + lpVolumeSerialNumber := int64(0) + lpMaximumComponentLength := int64(0) + lpFileSystemFlags := int64(0) + lpFileSystemNameBuffer := make([]byte, 256) + volpath, _ := syscall.UTF16PtrFromString(string(v) + ":/") + driveret, _, err := provGetVolumeInformation.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 { + return ret, err + } + opts := "rw" + if lpFileSystemFlags&FILE_READ_ONLY_VOLUME != 0 { + opts = "ro" + } + if lpFileSystemFlags&FILE_FILE_COMPRESSION != 0 { + opts += ".compress" + } + + d := Disk_partition{ + Mountpoint: path, + Device: path, + Fstype: string(bytes.Replace(lpFileSystemNameBuffer, []byte("\x00"), []byte(""), -1)), + Opts: opts, + } + ret = append(ret, d) + } + } + } + return ret, nil +}