Skip to content

Commit

Permalink
feat(option): rework option handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Yato202010 committed Nov 13, 2024
1 parent da83b75 commit 3bbab75
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 123 deletions.
28 changes: 5 additions & 23 deletions src/os/linux/fuseoverlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
* implementation inspired by libmount crate
* https://github.com/tailhook/libmount/blob/master/src/overlay.rs
*/
pub mod opt;
mod opt;
pub use opt::*;

use cfg_if::cfg_if;
use std::{
Expand All @@ -14,9 +15,8 @@ use std::{
use tracing::{debug, error};

use crate::{
common::fs::Filesystem,
os::{linux::fuseoverlay::opt::FuseOverlayFsOption, AsCString, AsPath},
LinuxFilesystem, MountOption, PartitionID, StackableFilesystem,
set_option_helper, AsCString, AsPath, Filesystem, LinuxFilesystem, MountOption, PartitionID,
StackableFilesystem,
};

#[derive(Debug)]
Expand Down Expand Up @@ -317,25 +317,7 @@ impl Filesystem for FuseOverlayFs {

impl LinuxFilesystem<FuseOverlayFsOption> for FuseOverlayFs {
fn set_option(&mut self, option: impl Into<MountOption<FuseOverlayFsOption>>) -> Result<()> {
let option = option.into();
for (i, opt) in self.options.clone().iter().enumerate() {
// If Option is already set with another value, overwrite it
if matches!((opt,&option), (MountOption::FsSpecific(s), MountOption::FsSpecific(o)) if std::mem::discriminant(s) == std::mem::discriminant(o))
| matches!((opt,&option), (s,o) if std::mem::discriminant(s) == std::mem::discriminant(o))
{
self.options[i] = option.clone();
return Ok(());
}
// Check option incompatibility
if opt.incompatible(&option) {
return Err(io::Error::new(
io::ErrorKind::Unsupported,
"Incompatible mount option combinaison",
));
}
}
self.options.push(option);
Ok(())
set_option_helper(&mut self.options, option)
}

fn remove_option(&mut self, option: impl Into<MountOption<FuseOverlayFsOption>>) -> Result<()> {
Expand Down
37 changes: 36 additions & 1 deletion src/os/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ pub mod overlay;
#[cfg(feature = "overlayfs")]
pub use overlay::OverlayFs;

pub(crate) use option::set_option_helper;
pub use option::{FsOption, LinuxFilesystem, MountOption};
pub(crate) use recover_state::{restore_fsdata, FsData};

/// Provide utility to recover filesystem state from the information provided by the system
#[allow(dead_code)]
Expand All @@ -36,7 +38,9 @@ mod recover_state {
}

/// Retrieve filesystem data from system information
pub fn restore_fsdata<P: AsRef<Path>, O: FsOption>(path: P) -> Result<Option<FsData<O>>> {
pub(crate) fn restore_fsdata<P: AsRef<Path>, O: FsOption>(
path: P,
) -> Result<Option<FsData<O>>> {
let fd = unsafe {
let mtab = CStr::from_bytes_with_nul_unchecked(b"/etc/mtab\0");
setmntent(mtab.as_ptr(), "r".as_ptr() as *const i8)
Expand Down Expand Up @@ -88,6 +92,37 @@ mod option {
fn options(&self) -> &[MountOption<O>];
}

pub(crate) fn set_option_helper<T, O>(
options: &mut Vec<MountOption<T>>,
option: O,
) -> Result<()>
where
T: FsOption + PartialEq,
O: Into<MountOption<T>>,
{
let option = option.into();
let mut idx = None;
for (i, opt) in options.iter().enumerate() {
if opt == &option {
return Ok(());
} else if matches!((opt,&option), (MountOption::FsSpecific(s), MountOption::FsSpecific(o)) if std::mem::discriminant(s) == std::mem::discriminant(o))
{
idx = Some(i);
} else if opt.incompatible(&option) {
return Err(std::io::Error::new(
std::io::ErrorKind::Unsupported,
"Incompatible mount option combination",
));
}
}
if let Some(idx) = idx {
options[idx] = option;
} else {
options.push(option);
}
Ok(())
}

pub trait FsOption: Sized + Clone + Display + FromStr {
/// Get defaults mount options for this filesystem
fn defaults() -> Vec<Self>;
Expand Down
80 changes: 27 additions & 53 deletions src/os/linux/overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,23 @@
*
*/

pub mod opt;
mod opt;
pub use opt::*;

use nix::{
mount::{mount, umount2, MntFlags, MsFlags},
unistd::getuid,
};
use std::{
ffi::{CStr, CString},
io::{self, Error, Result},
io::{Error, ErrorKind, Result},
path::{Path, PathBuf},
};
use tracing::{debug, error};

use crate::{
common::fs::{Filesystem, StateRecovery},
os::{
linux::overlay::opt::OverlayFsOption,
linux::recover_state::{restore_fsdata, FsData},
AsCString, AsPath, LinuxFilesystem, MountOption,
},
PartitionID, StackableFilesystem,
restore_fsdata, set_option_helper, AsCString, AsPath, Filesystem, FsData, LinuxFilesystem,
MountOption, PartitionID, StackableFilesystem, StateRecovery,
};

#[derive(Debug)]
Expand Down Expand Up @@ -76,8 +72,8 @@ impl OverlayFs {
{
let lower: Vec<PathBuf> = lower.map(|x| x.as_ref().to_path_buf()).collect();
if lower.len() < 2 {
return Err(io::Error::new(
io::ErrorKind::Other,
return Err(Error::new(
ErrorKind::Other,
"overlay FileSystem need a least 2 lower directory to work",
));
}
Expand All @@ -103,8 +99,8 @@ impl OverlayFs {
D: AsRef<Path>,
{
if PartitionID::try_from(upper.as_ref())? != PartitionID::try_from(work.as_ref())? {
return Err(io::Error::new(
io::ErrorKind::Other,
return Err(Error::new(
ErrorKind::Other,
"overlay FileSystem need the upper dir and the work dir to be on the same FileSystem",
));
}
Expand All @@ -130,15 +126,12 @@ impl OverlayFs {
!= PartitionID::try_from(
self.upper
.as_ref()
.ok_or(io::Error::new(
io::ErrorKind::NotFound,
"upper directory not set",
))?
.ok_or(Error::new(ErrorKind::NotFound, "upper directory not set"))?
.as_path(),
)?
{
return Err(io::Error::new(
io::ErrorKind::Other,
return Err(Error::new(
ErrorKind::Other,
"overlay FileSystem need the upper dir and the work dir to be on the same FileSystem",
));
}
Expand All @@ -154,7 +147,6 @@ impl Filesystem for OverlayFs {
debug!("Damascus: partition already mounted");
return Ok(self.target.as_path().to_path_buf());
}
// let mut flags = MsFlags::MS_NOATIME.union(MsFlags::MS_NODIRATIME);
let mut flags = MsFlags::empty();
let mut options = String::new();
options.push_str("lowerdir=");
Expand Down Expand Up @@ -186,7 +178,10 @@ impl Filesystem for OverlayFs {
Some(unsafe { CStr::from_bytes_with_nul(b"overlay\0").unwrap_unchecked() }),
flags,
Some(unsafe { CString::from_vec_with_nul_unchecked(args).as_bytes() }),
)?;
)
.inspect_err(|_x| {
dbg!(&self);
})?;
self.id = Some(PartitionID::try_from(self.target.as_path())?);
Ok(self.target.as_path().to_path_buf())
}
Expand Down Expand Up @@ -223,8 +218,8 @@ impl Filesystem for OverlayFs {
#[inline]
fn set_target(&mut self, target: &dyn AsRef<Path>) -> Result<()> {
if self.id.is_some() {
return Err(io::Error::new(
io::ErrorKind::Other,
return Err(Error::new(
ErrorKind::Other,
"mount point cannot be change when the FileSystem is mounted",
));
}
Expand All @@ -243,25 +238,7 @@ impl Filesystem for OverlayFs {

impl LinuxFilesystem<OverlayFsOption> for OverlayFs {
fn set_option(&mut self, option: impl Into<MountOption<OverlayFsOption>>) -> Result<()> {
let option = option.into();
for (i, opt) in self.options.clone().iter().enumerate() {
// If Option is already set with another value, overwrite it
if matches!((opt,&option), (MountOption::FsSpecific(s), MountOption::FsSpecific(o)) if std::mem::discriminant(s) == std::mem::discriminant(o))
| matches!((opt,&option), (s,o) if std::mem::discriminant(s) == std::mem::discriminant(o))
{
self.options[i] = option.clone();
return Ok(());
}
// Check option incompatibility
if opt.incompatible(&option) {
return Err(io::Error::new(
io::ErrorKind::Unsupported,
"Incompatible mount option combinaison",
));
}
}
self.options.push(option);
Ok(())
set_option_helper(&mut self.options, option)
}

fn remove_option(&mut self, option: impl Into<MountOption<OverlayFsOption>>) -> Result<()> {
Expand All @@ -287,8 +264,8 @@ impl StackableFilesystem for OverlayFs {
#[inline]
fn set_lower(&mut self, lower: Vec<PathBuf>) -> Result<()> {
if self.id.is_some() {
return Err(io::Error::new(
io::ErrorKind::Other,
return Err(Error::new(
ErrorKind::Other,
"upper layer cannot be change when the FileSystem is mounted",
));
}
Expand All @@ -307,20 +284,17 @@ impl StackableFilesystem for OverlayFs {
!= PartitionID::try_from(
self.work
.as_ref()
.ok_or(io::Error::new(
io::ErrorKind::NotFound,
"work directory not set",
))?
.ok_or(Error::new(ErrorKind::NotFound, "work directory not set"))?
.as_path(),
)?
{
return Err(io::Error::new(
io::ErrorKind::Other,
return Err(Error::new(
ErrorKind::Other,
"overlay FileSystem need the upper dir and the work dir to be on the same FileSystem",
));
} else if self.id.is_some() {
return Err(io::Error::new(
io::ErrorKind::Other,
return Err(Error::new(
ErrorKind::Other,
"upper layer cannot be change when the FileSystem is mounted",
));
}
Expand All @@ -333,7 +307,7 @@ impl StateRecovery for OverlayFs {
fn recover<P: AsRef<Path>>(path: P) -> Result<Self> {
let path = path.as_ref();
let data: FsData<OverlayFsOption> = restore_fsdata(path)?.ok_or(Error::new(
io::ErrorKind::NotFound,
ErrorKind::NotFound,
"OverlayFs not found at mount point : ".to_string() + &path.to_string_lossy(),
))?;
let mut lower = vec![];
Expand Down
3 changes: 1 addition & 2 deletions src/os/linux/overlay/opt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,8 @@ pub enum OverlayFsOption {
impl FsOption for OverlayFsOption {
fn defaults() -> Vec<Self> {
vec![
OverlayFsOption::RedirectDir(RedirectDir::On),
OverlayFsOption::Index(true),
OverlayFsOption::Xino(Xino::On),
OverlayFsOption::Xino(Xino::Auto),
]
}

Expand Down
28 changes: 5 additions & 23 deletions src/os/linux/unionfs_fuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
* https://github.com/tailhook/libmount/blob/master/src/overlay.rs
*/

pub mod opt;
mod opt;
pub use opt::*;

use cfg_if::cfg_if;
use std::{
Expand All @@ -14,10 +15,9 @@ use std::{
};
use tracing::{debug, error};

use crate::os::set_option_helper;
use crate::{
common::fs::Filesystem,
os::{linux::unionfs_fuse::opt::UnionFsFuseOption, AsCString, AsPath},
LinuxFilesystem, MountOption, PartitionID, StackableFilesystem,
AsCString, AsPath, Filesystem, LinuxFilesystem, MountOption, PartitionID, StackableFilesystem,
};

#[derive(Debug)]
Expand Down Expand Up @@ -271,25 +271,7 @@ impl LinuxFilesystem<UnionFsFuseOption> for UnionFsFuse {
&mut self,
option: impl Into<crate::MountOption<UnionFsFuseOption>>,
) -> Result<()> {
let option = option.into();
for (i, opt) in self.options.clone().iter().enumerate() {
// If Option is already set with another value, overwrite it
if matches!((opt,&option), (MountOption::FsSpecific(s), MountOption::FsSpecific(o)) if std::mem::discriminant(s) == std::mem::discriminant(o))
| matches!((opt,&option), (s,o) if std::mem::discriminant(s) == std::mem::discriminant(o))
{
self.options[i] = option.clone();
return Ok(());
}
// Check option incompatibility
if opt.incompatible(&option) {
return Err(io::Error::new(
io::ErrorKind::Unsupported,
"Incompatible mount option combinaison",
));
}
}
self.options.push(option);
Ok(())
set_option_helper(&mut self.options, option.into())
}

fn remove_option(
Expand Down
Loading

0 comments on commit 3bbab75

Please sign in to comment.