Skip to content

Commit

Permalink
feat: new mount
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso committed Oct 23, 2024
1 parent 6b4502f commit 1db18f8
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 34 deletions.
22 changes: 13 additions & 9 deletions remotefs-fuse-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod cli;

use remotefs_fuse::{Driver, MountOption};
use remotefs_fuse::{Driver, Mount, MountOption};

fn main() -> anyhow::Result<()> {
let args = argh::from_env::<cli::CliArgs>();
Expand All @@ -11,13 +11,6 @@ fn main() -> anyhow::Result<()> {

let driver = Driver::new(remote);

// setup signal handler
ctrlc::set_handler(move || {
log::warn!(
"Received interrupt signal. Please, umount file system to terminate the process."
);
})?;

log::info!("Mounting remote fs at {}", mount_path.display());

// create the mount point if it does not exist
Expand All @@ -27,7 +20,7 @@ fn main() -> anyhow::Result<()> {
}

// Mount the remote file system
remotefs_fuse::mount(
let mut mount = Mount::mount(
driver,
&mount_path,
&[
Expand All @@ -39,5 +32,16 @@ fn main() -> anyhow::Result<()> {
],
)?;

let mut umount = mount.unmounter();

// setup signal handler
ctrlc::set_handler(move || {
log::info!("Received SIGINT, unmounting filesystem");
umount.umount().expect("Failed to unmount");
})?;

log::info!("Running filesystem event loop");
mount.run()?;

Ok(())
}
20 changes: 3 additions & 17 deletions remotefs-fuse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,10 @@
extern crate log;

mod driver;

use std::path::Path;
mod mount;

#[cfg(target_family = "unix")]
pub use fuser::{spawn_mount2, MountOption};
pub use fuser::MountOption;

pub use self::driver::{Driver, DriverError, DriverResult};

/// Mount a remote filesystem to a local directory.
///
/// The `mount` function will take a [`Driver`] instance and mount it to the provided mountpoint.
pub fn mount<P>(
driver: Driver,
mountpoint: &P,
options: &[MountOption],
) -> Result<(), std::io::Error>
where
P: AsRef<Path>,
{
fuser::mount2(driver, mountpoint, options)
}
pub use self::mount::{Mount, Umount};
61 changes: 61 additions & 0 deletions remotefs-fuse/src/mount.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use std::path::Path;

use fuser::{MountOption, Session, SessionUnmounter};

use crate::Driver;

/// A struct to mount the filesystem.
pub struct Mount {
#[cfg(unix)]
session: Session<Driver>,
}

impl Mount {
/// Mount the filesystem implemented by [`Driver`] to the provided mountpoint.
///
/// You can specify the mount options using the `options` parameter.
pub fn mount(
driver: Driver,
mountpoint: &Path,
options: &[MountOption],
) -> Result<Self, std::io::Error> {
let session = Session::new(driver, mountpoint, options)?;

Ok(Self {
#[cfg(unix)]
session,
})
}

/// Run the filesystem event loop.
///
/// This function will block the current thread.
pub fn run(&mut self) -> Result<(), std::io::Error> {
#[cfg(unix)]
self.session.run()
}

/// Get a handle to unmount the filesystem.
///
/// To umount see [`Umount::umount`].
pub fn unmounter(&mut self) -> Umount {
#[cfg(unix)]
Umount {
umount: self.session.unmount_callable(),
}
}
}

/// A thread-safe handle to unmount the filesystem.
pub struct Umount {
#[cfg(unix)]
umount: SessionUnmounter,
}

impl Umount {
/// Unmount the filesystem.
pub fn umount(&mut self) -> Result<(), std::io::Error> {
#[cfg(unix)]
self.umount.unmount()
}
}
36 changes: 28 additions & 8 deletions remotefs-fuse/tests/fuse/mod.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
use std::path::{Path, PathBuf};
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use std::thread::JoinHandle;
use std::time::Duration;

use fuser::MountOption;
use remotefs_fuse::{Mount, Umount};
use tempfile::TempDir;

use crate::driver::mounted_file_path;

pub type UmountLock = Arc<Mutex<Option<Umount>>>;

/// Mounts the filesystem in a separate thread.
///
/// The filesystem must be unmounted manually and then the thread must be joined.
fn mount(p: &Path) -> JoinHandle<()> {
fn mount(p: &Path) -> (UmountLock, JoinHandle<()>) {
let mountpoint = p.to_path_buf();

let error_flag = Arc::new(AtomicBool::new(false));
let error_flag_t = error_flag.clone();

let umount = Arc::new(Mutex::new(None));
let umount_t = umount.clone();

let join = std::thread::spawn(move || {
let driver = crate::driver::setup_driver();
// this operation is blocking and will not return until the filesystem is unmounted
remotefs_fuse::mount(
driver,
let mut mount = Mount::mount(
crate::driver::setup_driver(),
&mountpoint,
&[
MountOption::AllowRoot,
Expand All @@ -33,6 +37,11 @@ fn mount(p: &Path) -> JoinHandle<()> {
)
.expect("failed to mount");

let umount = mount.unmounter();
*umount_t.lock().unwrap() = Some(umount);

mount.run().expect("failed to run filesystem event loop");

// set the error flag if the filesystem was unmounted
error_flag_t.store(true, std::sync::atomic::Ordering::Relaxed);
});
Expand All @@ -43,14 +52,14 @@ fn mount(p: &Path) -> JoinHandle<()> {
panic!("Failed to mount filesystem");
}

join
(umount, join)
}

#[test]
fn test_should_mount_fs() {
let mnt = TempDir::new().expect("Failed to create tempdir");
// mount
let _join = mount(mnt.path());
let (umounter, join) = mount(mnt.path());
// mounted file exists
let mounted_file_path = PathBuf::from(format!(
"{}{}",
Expand All @@ -59,4 +68,15 @@ fn test_should_mount_fs() {
));
println!("Mounted file path: {:?}", mounted_file_path);
assert!(mounted_file_path.exists());

// unmount
umounter
.lock()
.unwrap()
.as_mut()
.unwrap()
.umount()
.expect("Failed to unmount");

join.join().expect("Failed to join thread");
}

0 comments on commit 1db18f8

Please sign in to comment.