Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore statfs for FreeBSD & OpenBSD #87

Merged
merged 2 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[package]
name = "trash"
version = "3.1.0"
version = "3.1.1"
authors = ["Artur Kovacs <[email protected]>"]
license = "MIT"
readme = "README.md"
Expand Down
57 changes: 56 additions & 1 deletion src/freedesktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ fn get_mount_points() -> Result<Vec<MountPoint>, Error> {
Ok(result)
}

#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
fn get_mount_points() -> Result<Vec<MountPoint>, Error> {
use once_cell::sync::Lazy;
use std::sync::Mutex;
Expand All @@ -693,6 +693,61 @@ fn get_mount_points() -> Result<Vec<MountPoint>, Error> {
static LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
let _lock = LOCK.lock().unwrap();

fn c_buf_to_str(buf: &[libc::c_char]) -> Option<&str> {
let buf: &[u8] = unsafe { std::slice::from_raw_parts(buf.as_ptr() as _, buf.len()) };
if let Some(pos) = buf.iter().position(|x| *x == 0) {
// Shrink buffer to omit the null bytes
std::str::from_utf8(&buf[..pos]).ok()
} else {
std::str::from_utf8(buf).ok()
}
}
let mut fs_infos: *mut libc::statfs = std::ptr::null_mut();
let count = unsafe { libc::getmntinfo(&mut fs_infos, libc::MNT_WAIT) };
if count < 1 {
return Ok(Vec::new());
}
let fs_infos: &[libc::statfs] = unsafe { std::slice::from_raw_parts(fs_infos as _, count as _) };

let mut result = Vec::new();
for fs_info in fs_infos {
if fs_info.f_mntfromname[0] == 0 || fs_info.f_mntonname[0] == 0 {
// If we have missing information, no need to look any further...
continue;
}
let fs_type = c_buf_to_str(&fs_info.f_fstypename).unwrap_or_default();
let mount_to = match c_buf_to_str(&fs_info.f_mntonname) {
Some(m) => m,
None => {
debug!("Cannot get disk mount point, ignoring it.");
continue;
}
};
let mount_from = c_buf_to_str(&fs_info.f_mntfromname).unwrap_or_default();

let mount_point =
MountPoint { mnt_dir: mount_to.into(), _mnt_fsname: mount_from.into(), _mnt_type: fs_type.into() };
result.push(mount_point);
}
Ok(result)
}

#[cfg(target_os = "netbsd")]
fn get_mount_points() -> Result<Vec<MountPoint>, Error> {
use once_cell::sync::Lazy;
use std::sync::Mutex;

// The getmntinfo() function writes the array of structures to an internal
// static object and returns a pointer to that object. Subsequent calls to
// getmntinfo() will modify the same object. This means that the function is
// not threadsafe. To help prevent multiple threads using it concurrently
// via get_mount_points a Mutex is used.
// We understand that threads can still call `libc::getmntinfo(…)` directly
// to bypass the lock and trigger UB.
// NetBSD does not support statfs since 2005, so we need to use statvfs instead.
static LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
let _lock = LOCK.lock().unwrap();

fn c_buf_to_str(buf: &[libc::c_char]) -> Option<&str> {
let buf: &[u8] = unsafe { std::slice::from_raw_parts(buf.as_ptr() as _, buf.len()) };
if let Some(pos) = buf.iter().position(|x| *x == 0) {
Expand Down
Loading