Skip to content

Commit

Permalink
- offer a mount handle after mount operation
Browse files Browse the repository at this point in the history
- use this handle on ctrl+c event
- fix clippy
  • Loading branch information
radumarias committed May 19, 2024
1 parent 995b8a8 commit ce02f21
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 108 deletions.
2 changes: 1 addition & 1 deletion clippy.toml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
allowed-duplicate-crates = ["syn", "socket2", "windows-sys", "windows-targets", "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", 'windows_x86_64_gnu', "windows_x86_64_gnullvm", "windows_x86_64_msvc", "memoffset", "nix", "parking_lot_core", "polling", "redox_syscall", "regex-automata", "regex-syntax", "rustix", "sha2", "bitflags", "block-buffer", "crypto-common", "digest", "event-listener", "event-listener-strategy", "fastrand", "futures-lite", "async-io", "async-lock", "heck", "linux-raw-sys"]
allowed-duplicate-crates = ["syn", "socket2", "windows-sys", "windows-targets", "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", 'windows_x86_64_gnu', "windows_x86_64_gnullvm", "windows_x86_64_msvc", "memoffset", "nix", "parking_lot_core", "polling", "redox_syscall", "regex-automata", "regex-syntax", "rustix", "sha2", "bitflags", "block-buffer", "crypto-common", "digest", "event-listener", "event-listener-strategy", "fastrand", "futures-lite", "async-io", "async-lock", "heck", "linux-raw-sys", "arrayvec", "cfg-if"]
6 changes: 1 addition & 5 deletions src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,7 @@ pub fn decrypt_file_name(

#[instrument(skip(password, salt))]
#[allow(clippy::missing_errors_doc)]
pub fn derive_key(
password: &SecretString,
cipher: Cipher,
salt: &Vec<u8>,
) -> Result<SecretVec<u8>> {
pub fn derive_key(password: &SecretString, cipher: Cipher, salt: &[u8]) -> Result<SecretVec<u8>> {
let mut dk = vec![];
let key_len = cipher.key_len();
dk.resize(key_len, 0);
Expand Down
9 changes: 5 additions & 4 deletions src/crypto/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,17 +513,18 @@ impl CryptoReader for FileCryptoReader {}
// impl CryptoReader for ChunkedFileCryptoReader {}

mod bench {
use crate::crypto;
use crate::crypto::Cipher;
use rand::RngCore;
use secrecy::SecretVec;
use std::io;
use std::io::Seek;
use std::io::Write;
use std::sync::Arc;
use test::{black_box, Bencher};

use rand::RngCore;
use secrecy::SecretVec;

use crate::crypto;
use crate::crypto::writer::CryptoWriter;
use crate::crypto::Cipher;

#[bench]
fn bench_reader_10mb_cha_cha20poly1305_file(b: &mut Bencher) {
Expand Down
7 changes: 5 additions & 2 deletions src/crypto/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,6 @@ impl CryptoWriterSeek<File> for FileCryptoWriter {}

#[cfg(test)]
mod test {
use blake3::portable::hash1;
use std::io;
use std::io::Write;
use std::io::{Read, Seek};
Expand Down Expand Up @@ -932,7 +931,8 @@ mod test {
mod bench {
use ::test::{black_box, Bencher};
use std::io;
use std::io::{Error, SeekFrom, Write};
use std::io::Write;
use std::io::{Error, SeekFrom};
use std::io::{Read, Seek};
use std::sync::Arc;

Expand Down Expand Up @@ -1064,6 +1064,9 @@ mod bench {
}

impl Seek for RandomReader {
#[allow(clippy::cast_possible_wrap)]
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let new_pos = match pos {
SeekFrom::Start(pos) => pos as i64,
Expand Down
99 changes: 61 additions & 38 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::cell::RefCell;
use std::ffi::OsStr;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::{env, io, panic, process};

use anyhow::Result;
Expand All @@ -19,7 +22,8 @@ use tracing_subscriber::EnvFilter;

use rencfs::crypto::Cipher;
use rencfs::encryptedfs::{EncryptedFs, FsError, PasswordProvider};
use rencfs::{is_debug, mount};
use rencfs::mount::MountPoint;
use rencfs::{async_util, is_debug, mount};

mod keyring;

Expand Down Expand Up @@ -160,14 +164,6 @@ fn get_cli_args() -> ArgMatches {
.action(ArgAction::SetTrue)
.help("If we should try to umount the mountpoint before starting the FUSE server. This can be useful when the previous run crashed or was forced kll and the mountpoint is still mounted."),
)
.arg(
Arg::new("auto_unmount")
.long("auto_unmount")
.short('x')
.default_value("true")
.action(ArgAction::SetTrue)
.help("Automatically unmount on process exit"),
)
.arg(
Arg::new("allow-root")
.long("allow-root")
Expand Down Expand Up @@ -336,29 +332,6 @@ async fn run_mount(cipher: Cipher, matches: &ArgMatches) -> Result<()> {
});
}

let auto_unmount = matches.get_flag("auto_unmount");
let mountpoint_kill = mountpoint.clone();
// unmount on process kill
set_handler(move || {
info!("Received signal to exit");
let mut status: Option<ExitStatusError> = None;
remove_pass();
if auto_unmount {
info!("Unmounting {}", mountpoint_kill);
}
umount(mountpoint_kill.as_str())
.map_err(|err| {
error!(err = %err);
status.replace(ExitStatusError::Failure(1));
})
.ok();

process::exit(status.map_or(0, |x| match x {
ExitStatusError::Failure(status) => status,
}));
})
.unwrap();

#[allow(clippy::items_after_statements)]
struct PasswordProviderImpl {}
#[allow(clippy::items_after_statements)]
Expand All @@ -380,7 +353,6 @@ async fn run_mount(cipher: Cipher, matches: &ArgMatches) -> Result<()> {
}
}
}

let mut mount_point = mount::create_mount_point(
Path::new(&mountpoint).to_path_buf(),
Path::new(&data_dir).to_path_buf(),
Expand All @@ -391,11 +363,62 @@ async fn run_mount(cipher: Cipher, matches: &ArgMatches) -> Result<()> {
matches.get_flag("direct-io"),
matches.get_flag("suid"),
);
mount_point.mount().await?;

remove_pass();

info!("Bye!");
let mount_handle = mount_point.mount().await.map_err(|err| {
error!(err = %err);
ExitStatusError::Failure(1)
})?;
let mut mount_handle = Arc::new(Mutex::new(Some(Some(mount_handle))));
let mount_handle_clone = mount_handle.clone();
// cleanup on process kill
set_handler(move || {
// can't use tracing methods here as guard cannot be dropper to flush content before we exit
eprintln!("Received signal to exit");
let mut status: Option<ExitStatusError> = None;
remove_pass();
eprintln!("Unmounting {}", mountpoint);
// create new tokio runtime
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
let _ = rt
.block_on(async {
mount_handle_clone
.lock()
.unwrap()
.replace(None)
.unwrap()
.unwrap()
.umount()
.await?;
Ok::<(), io::Error>(())
})
.map_err(|err| {
eprintln!("Error: {}", err);
status.replace(ExitStatusError::Failure(1));
err
});
eprintln!("Bye!");
process::exit(status.map_or(0, |x| match x {
ExitStatusError::Failure(status) => status,
}));
})?;

// mount_handle
// .lock()
// .unwrap()
// .as_mut()
// .unwrap()
// .as_mut()
// .unwrap()
// .await?;
task::spawn_blocking(|| {
let rt = tokio::runtime::Handle::current();
rt.block_on(async {
tokio::time::sleep(tokio::time::Duration::from_secs(u64::MAX)).await;
})
})
.await?;

Ok(())
}
Expand Down
66 changes: 58 additions & 8 deletions src/mount.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,77 @@
use crate::crypto::Cipher;
use crate::encryptedfs::{FsResult, PasswordProvider};
use async_trait::async_trait;
use futures_util::FutureExt;
use std::future::Future;
use std::io;
use std::path::PathBuf;
use std::pin::Pin;
use std::task::{Context, Poll};

#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
use linux::Fuse3MountPoint as MountPointImpl;
use linux::MountHandleInnerImpl;
#[cfg(target_os = "linux")]
use linux::MountPointImpl;

#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "macos")]
use macos::MacOsFuse3MountPoint as MountPointImpl;
use macos::MountHandleInnerImpl;
#[cfg(target_os = "macos")]
use macos::MountPointImpl;

#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "windows")]
use windows::WindowsMountPoint as MountPointImpl;
use windows::MountHandleInnerImpl;
#[cfg(target_os = "windows")]
use windows::MountPointImpl;

#[async_trait]
#[allow(clippy::module_name_repetitions)]
#[allow(clippy::struct_excessive_bools)]
pub trait MountPoint {
async fn mount(&mut self) -> FsResult<()>;
async fn umount(&mut self) -> FsResult<()>;
fn new(
mountpoint: PathBuf,
data_dir: PathBuf,
password_provider: Box<dyn PasswordProvider>,
cipher: Cipher,
allow_root: bool,
allow_other: bool,
direct_io: bool,
suid_support: bool,
) -> Self
where
Self: Sized;
async fn mount(mut self) -> FsResult<MountHandle>;
}

pub struct MountHandle {
inner: MountHandleInnerImpl,
}
impl MountHandle {
pub async fn umount(mut self) -> io::Result<()> {
self.inner.umount().await
}
}

impl Future for MountHandle {
type Output = io::Result<()>;

fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.inner.poll_unpin(cx)
}
}

#[async_trait]
pub(crate) trait MountHandleInner: Future<Output = io::Result<()>> {
async fn umount(mut self) -> io::Result<()>;
}

#[must_use]
#[allow(clippy::struct_excessive_bools)]
pub fn create_mount_point(
mountpoint: PathBuf,
data_dir: PathBuf,
Expand All @@ -31,8 +81,8 @@ pub fn create_mount_point(
allow_other: bool,
direct_io: bool,
suid_support: bool,
) -> Box<dyn MountPoint> {
Box::new(MountPointImpl::new(
) -> impl MountPoint {
MountPointImpl::new(
mountpoint,
data_dir,
password_provider,
Expand All @@ -41,5 +91,5 @@ pub fn create_mount_point(
allow_other,
direct_io,
suid_support,
))
)
}
Loading

0 comments on commit ce02f21

Please sign in to comment.