use std::ffi::OsString;
use std::os::unix::io::RawFd;
use nix::unistd;
#[derive(Debug, Clone, Default, Eq, PartialEq)]
pub struct MountOptions {
pub(crate) uid: Option<u32>,
pub(crate) gid: Option<u32>,
pub(crate) fs_name: Option<String>,
pub(crate) rootmode: Option<u32>,
pub(crate) allow_root: bool,
pub(crate) allow_other: bool,
pub(crate) read_only: Option<bool>,
pub(crate) nonempty: bool,
pub(crate) default_permissions: bool,
pub(crate) dont_mask: bool,
pub(crate) no_open_support: bool,
pub(crate) no_open_dir_support: bool,
pub(crate) handle_killpriv: bool,
pub(crate) write_back: bool,
pub(crate) force_readdir_plus: bool,
pub(crate) custom_options: Option<OsString>,
}
impl MountOptions {
pub fn uid(mut self, uid: u32) -> Self {
self.uid.replace(uid);
self
}
pub fn gid(mut self, gid: u32) -> Self {
self.gid.replace(gid);
self
}
pub fn fs_name(mut self, name: impl Into<String>) -> Self {
self.fs_name.replace(name.into());
self
}
pub fn rootmode(mut self, rootmode: u32) -> Self {
self.rootmode.replace(rootmode);
self
}
pub fn allow_root(mut self, allow_root: bool) -> Self {
self.allow_root = allow_root;
self
}
pub fn allow_other(mut self, allow_other: bool) -> Self {
self.allow_other = allow_other;
self
}
pub fn read_only(mut self, read_only: bool) -> Self {
self.read_only.replace(read_only);
self
}
pub fn nonempty(mut self, nonempty: bool) -> Self {
self.nonempty = nonempty;
self
}
pub fn default_permissions(mut self, default_permissions: bool) -> Self {
self.default_permissions = default_permissions;
self
}
pub fn dont_mask(mut self, dont_mask: bool) -> Self {
self.dont_mask = dont_mask;
self
}
pub fn no_open_support(mut self, no_open_support: bool) -> Self {
self.no_open_support = no_open_support;
self
}
pub fn no_open_dir_support(mut self, no_open_dir_support: bool) -> Self {
self.no_open_dir_support = no_open_dir_support;
self
}
pub fn handle_killpriv(mut self, handle_killpriv: bool) -> Self {
self.handle_killpriv = handle_killpriv;
self
}
pub fn write_back(mut self, write_back: bool) -> Self {
self.write_back = write_back;
self
}
pub fn force_readdir_plus(mut self, force_readdir_plus: bool) -> Self {
self.force_readdir_plus = force_readdir_plus;
self
}
pub fn custom_options(mut self, custom_options: impl Into<OsString>) -> Self {
self.custom_options = Some(custom_options.into());
self
}
pub(crate) fn build(&mut self, fd: RawFd) -> OsString {
let mut opts = vec![
format!("fd={}", fd),
format!(
"user_id={}",
self.uid.unwrap_or_else(|| unistd::getuid().as_raw())
),
format!(
"group_id={}",
self.gid.unwrap_or_else(|| unistd::getgid().as_raw())
),
format!("rootmode={}", self.rootmode.unwrap_or(40000)),
];
if self.allow_root {
opts.push("allow_root".to_string());
}
if self.allow_other {
opts.push("allow_other".to_string());
}
if matches!(self.read_only, Some(true)) {
opts.push("ro".to_string());
}
if self.default_permissions {
opts.push("default_permissions".to_string());
}
let mut options = OsString::from(opts.join(","));
if let Some(custom_options) = &self.custom_options {
options.push(",");
options.push(custom_options);
}
options
}
#[cfg(feature = "unprivileged")]
pub(crate) fn build_with_unprivileged(&self) -> OsString {
let mut opts = vec![
format!(
"user_id={}",
self.uid.unwrap_or_else(|| unistd::getuid().as_raw())
),
format!(
"group_id={}",
self.gid.unwrap_or_else(|| unistd::getgid().as_raw())
),
format!("rootmode={}", self.rootmode.unwrap_or(40000)),
format!(
"fsname={}",
self.fs_name.as_ref().unwrap_or(&"fuse".to_string())
),
];
if self.allow_root {
opts.push("allow_root".to_string());
}
if self.allow_other {
opts.push("allow_other".to_string());
}
if matches!(self.read_only, Some(true)) {
opts.push("ro".to_string());
}
if self.default_permissions {
opts.push("default_permissions".to_string());
}
let mut options = OsString::from(opts.join(","));
if let Some(custom_options) = &self.custom_options {
options.push(",");
options.push(custom_options);
}
options
}
}