mountpoints 0.2.1

List mount points (windows, linux, macos)
Documentation
use crate::{Error, MountInfo};
use std::ffi::{CStr, OsStr};
use std::os::raw::{c_char, c_int};
use std::os::unix::ffi::OsStrExt;
use std::path::PathBuf;

const MNT_RDONLY: u32 = libc::MNT_RDONLY as u32;

fn _mounts(mut cb: impl FnMut(&libc::statfs, PathBuf) -> Result<(), Error>) -> Result<(), Error> {
    let mut n: i32 = unsafe { libc::getfsstat(std::ptr::null_mut(), 0, libc::MNT_NOWAIT) };
    let mut mntbuf = Vec::<libc::statfs>::new();
    if n > 0 {
        mntbuf.resize_with(n as usize, || unsafe { std::mem::zeroed() });
        let bufsize = mntbuf.len() * std::mem::size_of::<libc::statfs>();
        n = unsafe { libc::getfsstat(mntbuf.as_mut_ptr(), bufsize as c_int, libc::MNT_NOWAIT) };
        if n >= 0 {
            mntbuf.truncate(n as usize);
        }
    }
    if n < 0 {
        return Err(Error::MacOsGetfsstatError(unsafe { *libc::__error() }));
    }
    for p in &mntbuf {
        let mountpath = OsStr::from_bytes(
            unsafe { CStr::from_ptr(p.f_mntonname.as_ptr() as *const c_char) }.to_bytes(),
        );
        cb(p, PathBuf::from(mountpath))?;
    }
    Ok(())
}

pub fn mountinfos() -> Result<Vec<MountInfo>, Error> {
    let mut mountinfos = Vec::new();
    _mounts(|stat, path| {
        mountinfos.push(MountInfo {
            path,
            avail: Some(stat.f_bavail.saturating_mul(u64::from(stat.f_bsize))),
            free: Some(stat.f_bfree.saturating_mul(u64::from(stat.f_bsize))),
            size: Some(stat.f_blocks.saturating_mul(u64::from(stat.f_bsize))),
            name: None,
            format: Some(
                unsafe { CStr::from_ptr(stat.f_fstypename.as_ptr() as *const c_char) }
                    .to_str()
                    .map_err(|_| Error::MacOsUtf8Error)?
                    .into(),
            ),
            readonly: Some((stat.f_flags & MNT_RDONLY) == MNT_RDONLY),
            dummy: false,
            __priv: (),
        });
        Ok(())
    })?;
    Ok(mountinfos)
}

pub fn mountpaths() -> Result<Vec<PathBuf>, Error> {
    let mut mountpaths = Vec::new();
    _mounts(|_, mountpath| {
        mountpaths.push(mountpath);
        Ok(())
    })?;
    Ok(mountpaths)
}