use std::borrow::Cow;
use std::ffi::OsStr;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;
use anyhow::Result;
use libc::c_ulong;
use crate::mountinfo::Parser;
use crate::{mountinfo, utils};
#[derive(Debug)]
pub struct MountPoint {
pub mount_id: c_ulong,
pub parent_id: c_ulong,
pub major: c_ulong,
pub minor: c_ulong,
pub root: PathBuf,
pub mount_point: PathBuf,
}
fn get_path(s: Cow<OsStr>) -> PathBuf {
Path::new(&s).to_path_buf()
}
impl From<mountinfo::MountPoint<'_>> for MountPoint {
fn from(mp: mountinfo::MountPoint) -> Self {
MountPoint {
mount_id: mp.mount_id,
parent_id: mp.parent_id,
major: mp.major,
minor: mp.minor,
root: get_path(mp.root),
mount_point: get_path(mp.mount_point),
}
}
}
#[derive(Debug)]
pub struct Mounts(Vec<MountPoint>);
impl Mounts {
pub fn read() -> Result<Mounts> {
let pid = process::id();
let path = Path::new("/")
.join("proc")
.join(pid.to_string())
.join("mountinfo");
let mut buf = Vec::new();
{
let mut file = File::open(path)?;
file.read_to_end(&mut buf)?;
}
let parser = Parser::new(&buf);
let mut mounts = Vec::new();
trace!("Parsed mount table:");
for mp in parser {
let mp = mp?;
let mp = MountPoint::from(mp);
trace!(?mp);
mounts.push(mp);
}
Ok(Mounts(mounts))
}
pub fn get_mount_point(&self, path: impl AsRef<Path>) -> Option<PathBuf> {
let path = utils::into_absolute(path).ok()?;
self
.0
.iter()
.filter(|mp| path.starts_with(&mp.mount_point))
.max_by_key(|mp| mp.mount_point.components().count())
.map(|mp| mp.mount_point.to_path_buf())
}
}