use crate::umount::{unmount_, Unmount, UnmountDrop};
use crate::{MountBuilder, PropagationType, UnmountFlags};
use std::ptr;
use std::{
ffi::{CString, OsStr},
io,
os::unix::ffi::OsStrExt,
path::Path,
};
#[derive(Debug)]
pub struct Mount {
pub(crate) target: CString,
pub(crate) fstype: String,
#[cfg(feature = "loop")]
pub(crate) loopback: Option<loopdev::LoopDevice>,
pub(crate) loop_path: Option<std::path::PathBuf>,
}
impl Unmount for Mount {
fn unmount(&self, flags: UnmountFlags) -> io::Result<()> {
unsafe {
unmount_(self.target.as_ptr(), flags)?;
}
#[cfg(feature = "loop")]
if let Some(ref loopback) = self.loopback {
loopback.detach()?;
}
Ok(())
}
}
impl Mount {
#[inline]
#[must_use]
pub fn builder<'a>() -> MountBuilder<'a> {
MountBuilder::default()
}
#[inline]
pub fn new(source: impl AsRef<Path>, target: impl AsRef<Path>) -> io::Result<Mount> {
let supported = crate::SupportedFilesystems::new()?;
MountBuilder::default()
.fstype(&supported)
.mount(source, target)
}
#[inline]
#[must_use]
pub fn backing_loop_device(&self) -> Option<&Path> {
self.loop_path.as_deref()
}
#[inline]
#[must_use]
pub fn get_fstype(&self) -> &str {
&self.fstype
}
#[inline]
#[must_use]
pub fn target_path(&self) -> &Path {
Path::new(OsStr::from_bytes(self.target.as_bytes()))
}
#[inline]
#[must_use]
pub fn set_propagation_type(&mut self, propagation_type: PropagationType) -> io::Result<()> {
let result = unsafe {
libc::mount(
ptr::null(),
self.target.as_ptr(),
ptr::null(),
propagation_type.bits(),
ptr::null(),
)
};
match result {
0 => Ok(()),
_err => Err(io::Error::last_os_error()),
}
}
#[inline]
pub(crate) fn from_target_and_fstype(target: CString, fstype: String) -> Self {
Mount {
target,
fstype,
#[cfg(feature = "loop")]
loopback: None,
loop_path: None,
}
}
}
pub struct Mounts(pub Vec<UnmountDrop<Mount>>);
impl Mounts {
pub fn unmount(&mut self, lazy: bool) -> io::Result<()> {
let flags = if lazy {
UnmountFlags::DETACH
} else {
UnmountFlags::empty()
};
self.0
.iter_mut()
.rev()
.try_for_each(|mount| mount.unmount(flags))
}
}
impl Drop for Mounts {
fn drop(&mut self) {
for mount in self.0.drain(..).rev() {
drop(mount);
}
}
}