use std::ffi::CStr;
use std::io;
use std::mem;
use std::path::PathBuf;
use std::ptr;
use std::str::FromStr;
use nix::libc;
use crate::disk::{FileSystem, Partition};
#[allow(unused)]
pub const MNT_WAIT: libc::c_int = 1;
pub const MNT_NOWAIT: libc::c_int = 2;
extern "C" {
fn getfsstat64(buf: *mut libc::statfs, bufsize: libc::c_int, flags: libc::c_int)
-> libc::c_int;
}
fn mounts() -> io::Result<Vec<libc::statfs>> {
let expected_len = unsafe { getfsstat64(ptr::null_mut(), 0, MNT_NOWAIT) };
let mut mounts: Vec<libc::statfs> = Vec::with_capacity(expected_len as usize);
let result = unsafe {
getfsstat64(
mounts.as_mut_ptr(),
mem::size_of::<libc::statfs>() as libc::c_int * expected_len,
MNT_NOWAIT,
)
};
if result == -1 {
return Err(io::Error::last_os_error());
} else {
debug_assert!(
expected_len == result,
"Expected {} statfs entries, but got {}",
expected_len,
result
);
unsafe {
mounts.set_len(result as usize);
}
}
Ok(mounts)
}
impl From<libc::statfs> for Partition {
fn from(stat: libc::statfs) -> Partition {
let device = unsafe {
CStr::from_ptr(stat.f_mntfromname.as_ptr())
.to_string_lossy()
.to_string()
};
let filesystem = FileSystem::from_str(unsafe {
&CStr::from_ptr(stat.f_fstypename.as_ptr()).to_string_lossy()
})
.unwrap();
let mountpoint = PathBuf::from(unsafe {
CStr::from_ptr(stat.f_mntonname.as_ptr())
.to_string_lossy()
.to_string()
});
let flags = stat.f_flags;
Partition {
device,
mountpoint,
filesystem,
mount_options: "".to_owned(), }
}
}
pub fn partitions() -> io::Result<Vec<Partition>> {
Ok(mounts()?.into_iter().map(Partition::from).collect())
}