use crate::error::{NeofetchError, Result};
use human_bytes::human_bytes;
use std::fmt::Display;
#[derive(Debug, Clone)]
pub struct Disk {
pub name: String,
pub total: u64,
pub used: u64,
}
impl Display for Disk {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let used = human_bytes(self.used as f64);
let total = human_bytes(self.total as f64);
let percent = if self.total > 0 {
(self.used as f64 / self.total as f64) * 100.0
} else {
0.0
};
write!(f, "{} / {} ({:.0}%)", used, total, percent)
}
}
#[cfg(windows)]
pub async fn get_disk() -> Result<Vec<Disk>> {
use serde::Deserialize;
use crate::platform::wmi_query;
#[derive(Deserialize, Debug, Clone)]
#[serde(rename = "Win32_logicaldisk")]
struct Logicaldisk {
#[serde(rename = "DeviceID")]
device_id: String,
#[serde(rename = "FreeSpace")]
free_space: Option<u64>,
#[serde(rename = "Size")]
size: Option<u64>,
}
let results: Vec<Logicaldisk> = wmi_query()
.await
.map_err(|e| NeofetchError::wmi_error(format!("WMI query failed: {}", e)))?;
let mut disks = Vec::new();
for disk in results {
if let (Some(size), Some(free_space)) = (disk.size, disk.free_space)
&& size > 0
{
disks.push(Disk {
name: disk.device_id.trim_end_matches(':').to_string(),
total: size,
used: size.saturating_sub(free_space),
});
}
}
disks.sort_by(|a, b| a.name.cmp(&b.name));
Ok(disks)
}
#[cfg(unix)]
fn get_filesystem_info(path: &str) -> Result<Disk> {
use std::ffi::CString;
let path_cstr = CString::new(path)
.map_err(|_| NeofetchError::parse_error("path", "invalid path string"))?;
let mut stat: libc::statvfs = unsafe { std::mem::zeroed() };
let result = unsafe { libc::statvfs(path_cstr.as_ptr(), &mut stat) };
if result != 0 {
return Err(NeofetchError::system_call(format!(
"statvfs failed for {}",
path
)));
}
let total = stat.f_blocks as u64 * stat.f_frsize as u64;
let available = stat.f_bavail as u64 * stat.f_frsize as u64;
Ok(Disk {
name: path.to_string(),
total,
used: total.saturating_sub(available),
})
}
#[cfg(unix)]
pub async fn get_disk() -> Result<Vec<Disk>> {
let root_disk = get_filesystem_info("/")?;
Ok(vec![root_disk])
}