garbage 0.4.3

CLI tool for interacting with the freedesktop trashcan
Documentation
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())
  }
}