use std::io;
use std::fmt;
use std::ptr::null;
use std::ffi::{CString, OsStr};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use libc::mount;
use nix::mount::MsFlags;
use {OSError, Error};
use util::{path_to_cstring, as_path};
use explain::{Explainable, exists, user};
use remount::Remount;
#[derive(Debug, Clone)]
pub struct BindMount {
source: CString,
target: CString,
recursive: bool,
readonly: bool,
}
impl BindMount {
pub fn new<A: AsRef<Path>, B: AsRef<Path>>(source: A, target: B)
-> BindMount
{
BindMount {
source: path_to_cstring(source.as_ref()),
target: path_to_cstring(target.as_ref()),
recursive: true,
readonly: false,
}
}
pub fn recursive(mut self, flag: bool) -> BindMount {
self.recursive = flag;
self
}
pub fn readonly(mut self, flag: bool) -> BindMount {
self.readonly = flag;
self
}
pub fn bare_mount(self) -> Result<(), OSError> {
let mut flags = MsFlags::MS_BIND;
if self.recursive {
flags = flags | MsFlags::MS_REC;
}
let rc = unsafe { mount(
self.source.as_ptr(),
self.target.as_ptr(),
null(),
flags.bits(),
null()) };
if rc < 0 {
return Err(
OSError::from_io(io::Error::last_os_error(), Box::new(self)));
}
if self.readonly {
try!(Remount::new(OsStr::from_bytes(self.target.as_bytes()))
.bind(true)
.readonly(true)
.bare_remount());
}
Ok(())
}
pub fn mount(self) -> Result<(), Error> {
self.bare_mount().map_err(OSError::explain)
}
}
impl fmt::Display for BindMount {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if self.recursive {
try!(write!(fmt, "recursive "));
}
write!(fmt, "bind mount {:?} -> {:?}",
as_path(&self.source), as_path(&self.target))
}
}
impl Explainable for BindMount {
fn explain(&self) -> String {
[
format!("source: {}", exists(as_path(&self.source))),
format!("target: {}", exists(as_path(&self.target))),
format!("{}", user()),
].join(", ")
}
}