Skip to content

Commit

Permalink
Merge pull request #251 from xbjfk/free-windows
Browse files Browse the repository at this point in the history
free: add Windows support
  • Loading branch information
cakebaker authored Oct 11, 2024
2 parents 851ec31 + 3bd07df commit 65ea2c1
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 6 deletions.
73 changes: 69 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
walkdir = "2.5.0"
prettytable-rs = "0.10.0"
nix = { version = "0.29", default-features = false, features = ["process"] }
windows = { version = "0.58.0" }

[dependencies]
clap = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions src/uu/free/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ clap = { workspace = true }
bytesize = { workspace = true }

sysinfo = { workspace = true }
windows = { workspace = true, features = ["Wdk_System_SystemInformation", "Win32_System_ProcessStatus", "Win32_System_SystemInformation"] }

[lib]
path = "src/free.rs"
Expand Down
39 changes: 37 additions & 2 deletions src/uu/free/src/free.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

#[cfg(target_os = "windows")]
mod windows_util;

use bytesize::{ByteSize, GB, GIB, KB, KIB, MB, MIB, PB, PIB, TB, TIB};
use clap::{arg, crate_version, ArgAction, ArgGroup, ArgMatches, Command};
use std::env;
Expand Down Expand Up @@ -118,10 +121,42 @@ fn parse_meminfo() -> Result<MemInfo, Box<dyn std::error::Error>> {
Ok(mem_info)
}

// TODO: implement function
#[cfg(target_os = "windows")]
fn parse_meminfo() -> Result<MemInfo, Box<dyn std::error::Error>> {
Ok(MemInfo::default())
use std::mem::size_of;
use windows::Win32::System::{
ProcessStatus::{GetPerformanceInfo, PERFORMANCE_INFORMATION},
SystemInformation::{GlobalMemoryStatusEx, MEMORYSTATUSEX},
};

let (pagefile_used, pagefile_total) = windows_util::get_pagefile_usage()?;

let mut status = MEMORYSTATUSEX {
dwLength: size_of::<MEMORYSTATUSEX>() as u32,
..Default::default()
};
unsafe { GlobalMemoryStatusEx(&mut status)? }

let mut perf_info = PERFORMANCE_INFORMATION {
cb: size_of::<PERFORMANCE_INFORMATION>() as u32,
..Default::default()
};
unsafe { GetPerformanceInfo(&mut perf_info, perf_info.cb)? }

let mem_info = MemInfo {
total: status.ullTotalPhys / 1024,
free: (status.ullAvailPhys - (perf_info.SystemCache * perf_info.PageSize) as u64) / 1024,
available: status.ullAvailPhys / 1024,
cached: (perf_info.SystemCache * perf_info.PageSize) as u64 / 1024,
swap_total: (pagefile_total as u64 * perf_info.PageSize as u64) / 1024,
swap_free: ((pagefile_total - pagefile_used) as u64 * perf_info.PageSize as u64) / 1024,
swap_used: (pagefile_used as u64 * perf_info.PageSize as u64) / 1024,
commit_limit: (perf_info.CommitLimit * perf_info.PageSize) as u64 / 1024,
committed: (perf_info.CommitTotal * perf_info.PageSize) as u64 / 1024,
..Default::default()
};

Ok(mem_info)
}

// print total - used - free combo that is used for everything except memory for now
Expand Down
74 changes: 74 additions & 0 deletions src/uu/free/src/windows_util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use std::ffi::c_void;

use windows::{
core::Result,
Wdk::System::SystemInformation::{NtQuerySystemInformation, SYSTEM_INFORMATION_CLASS},
Win32::Foundation::{STATUS_INFO_LENGTH_MISMATCH, STATUS_SUCCESS, UNICODE_STRING},
};

#[repr(C)]
#[derive(Default, Debug)]
#[allow(non_snake_case)]
struct SYSTEM_PAGEFILE_INFORMATION {
NextEntryOffset: u32,
TotalSize: u32,
TotalInUse: u32,
PeakUsage: u32,
PageFileName: UNICODE_STRING,
}

/// Get the usage and total size of all page files.
pub(crate) fn get_pagefile_usage() -> Result<(u32, u32)> {
let mut buf: Vec<u8> = Vec::new();

let mut return_len: u32 = 0;

loop {
let status = unsafe {
NtQuerySystemInformation(
// SystemPageFileInformation
SYSTEM_INFORMATION_CLASS(0x12),
buf.as_mut_ptr() as *mut c_void,
buf.len() as u32,
&mut return_len,
)
};

debug_assert!(buf.len() <= return_len as usize);

if status == STATUS_INFO_LENGTH_MISMATCH {
debug_assert!(return_len > buf.len() as u32);
buf.resize(return_len as usize, 0);
continue;
} else if status == STATUS_SUCCESS {
debug_assert!(return_len == buf.len() as u32);
break;
} else {
return Err(status.into());
}
}

let mut usage = 0;
let mut total = 0;

if return_len > 0 {
let ptr = buf.as_ptr();
let mut offset = 0;
loop {
let ptr_offset =
unsafe { ptr.byte_offset(offset) } as *const SYSTEM_PAGEFILE_INFORMATION;
let record = unsafe { std::ptr::read(ptr_offset) };

usage += record.TotalInUse;
total += record.TotalSize;

offset = record.NextEntryOffset as isize;

if offset == 0 {
break;
}
}
}

Ok((usage, total))
}

0 comments on commit 65ea2c1

Please sign in to comment.