summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Cargo.toml2
-rw-r--r--examples/passthrough.rs9
-rw-r--r--src/fuse/mount.rs37
-rw-r--r--src/fuse/session.rs57
-rw-r--r--src/util.rs10
5 files changed, 93 insertions, 22 deletions
diff --git a/Cargo.toml b/Cargo.toml
index b4c364b..d4ede94 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,5 +26,5 @@ tokio = { version = "1.15.0", features = ["rt", "net", "macros", "sync"] }
clap = "2.34.0"
env_logger = "0.9.0"
futures-util = "0.3.19"
-tokio = { version = "1.15.0", features = ["fs", "io-util", "rt-multi-thread"] }
+tokio = { version = "1.15.0", features = ["fs", "io-util", "rt-multi-thread", "signal"] }
uuid = "0.8.2"
diff --git a/examples/passthrough.rs b/examples/passthrough.rs
index c25d728..5ecb2e8 100644
--- a/examples/passthrough.rs
+++ b/examples/passthrough.rs
@@ -389,5 +389,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
};
- Ok(Runtime::new()?.block_on(main_loop(session, fs))?)
+ let result = Runtime::new()?.block_on(async move {
+ tokio::select! {
+ result = main_loop(session, fs) => result,
+ _ = tokio::signal::ctrl_c() => Ok(()),
+ }
+ });
+
+ Ok(result?)
}
diff --git a/src/fuse/mount.rs b/src/fuse/mount.rs
index 9b03961..c924a9a 100644
--- a/src/fuse/mount.rs
+++ b/src/fuse/mount.rs
@@ -6,6 +6,7 @@ use std::{
io::{AsRawFd, RawFd},
net::UnixStream,
},
+ path::{Path, PathBuf},
process::Command,
};
@@ -97,7 +98,7 @@ impl<O: AsRef<OsStr>> Extend<O> for Options {
pub fn mount_sync<M>(mountpoint: M, options: &Options) -> Result<Start, MountError>
where
- M: AsRef<OsStr>,
+ M: AsRef<Path> + Into<PathBuf>,
{
let (left_side, right_side) = UnixStream::pair()?;
@@ -112,24 +113,18 @@ where
)
.unwrap();
- let mut command = Command::new("fusermount3");
+ let mut command = Command::new(FUSERMOUNT_CMD);
if !options.0.is_empty() {
- command.args(&[
- OsStr::new("-o"),
- &options.0,
- OsStr::new("--"),
- mountpoint.as_ref(),
- ]);
- } else {
- command.arg(mountpoint);
- };
+ command.args(&[OsStr::new("-o"), &options.0]);
+ }
+ command.args(&[OsStr::new("--"), mountpoint.as_ref().as_ref()]);
let mut fusermount = command.env("_FUSE_COMMFD", right_fd.to_string()).spawn()?;
// recvmsg() should fail if fusermount exits (last open fd is closed)
drop(right_side);
- let session_fd = (|| {
+ let session_fd = {
let mut buffer = cmsg_space!(RawFd);
let message = recvmsg(
left_side.as_raw_fd(),
@@ -145,10 +140,10 @@ where
};
session_fd.ok_or(MountError::Fusermount)
- })();
+ };
match session_fd {
- Ok(session_fd) => Ok(Start::new(DumbFd(session_fd))),
+ Ok(session_fd) => Ok(Start::new(DumbFd(session_fd), mountpoint.into())),
Err(error) => {
drop(left_side);
@@ -157,3 +152,17 @@ where
}
}
}
+
+pub(crate) fn unmount_sync<M: AsRef<OsStr>>(mountpoint: M) -> Result<(), MountError> {
+ let status = Command::new(FUSERMOUNT_CMD)
+ .args(&[OsStr::new("-zuq"), OsStr::new("--"), mountpoint.as_ref()])
+ .status()?;
+
+ if status.success() {
+ Ok(())
+ } else {
+ Err(MountError::Fusermount)
+ }
+}
+
+const FUSERMOUNT_CMD: &str = "fusermount3";
diff --git a/src/fuse/session.rs b/src/fuse/session.rs
index d7b6501..55fedcb 100644
--- a/src/fuse/session.rs
+++ b/src/fuse/session.rs
@@ -4,6 +4,7 @@ use std::{
marker::PhantomData,
ops::ControlFlow,
os::unix::io::{IntoRawFd, RawFd},
+ path::PathBuf,
sync::{Arc, Mutex},
};
@@ -22,6 +23,7 @@ use bytemuck::bytes_of;
use smallvec::SmallVec;
use crate::{
+ mount::{unmount_sync, MountError},
proto::{self, InHeader, Structured},
util::{page_size, DumbFd, OutputChain},
Errno, FuseError, FuseResult,
@@ -34,6 +36,7 @@ use super::{
pub struct Start {
session_fd: DumbFd,
+ mountpoint: PathBuf,
}
pub struct Session {
@@ -42,6 +45,7 @@ pub struct Session {
buffers: Mutex<Vec<Buffer>>,
buffer_semaphore: Arc<Semaphore>,
buffer_pages: usize,
+ mountpoint: Mutex<Option<PathBuf>>,
}
pub struct Endpoint<'a> {
@@ -93,6 +97,15 @@ impl Session {
}
}
+ pub fn unmount_sync(&self) -> Result<(), MountError> {
+ let mountpoint = self.mountpoint.lock().unwrap().take();
+ if let Some(mountpoint) = &mountpoint {
+ unmount_sync(mountpoint)?;
+ }
+
+ Ok(())
+ }
+
pub(crate) fn ok(&self, unique: u64, output: OutputChain<'_>) -> FuseResult<()> {
self.send(unique, 0, output)
}
@@ -212,6 +225,24 @@ impl Session {
}
}
+impl Drop for Start {
+ fn drop(&mut self) {
+ if !self.mountpoint.as_os_str().is_empty() {
+ let _ = unmount_sync(&self.mountpoint);
+ }
+ }
+}
+
+impl Drop for Session {
+ fn drop(&mut self) {
+ if let Some(mountpoint) = self.mountpoint.get_mut().unwrap().take() {
+ let _ = unmount_sync(&mountpoint);
+ }
+
+ drop(DumbFd(*self.session_fd.get_ref())); // Close
+ }
+}
+
impl<'o> Dispatch<'o> {
pub fn op(self) -> Op<'o> {
use Dispatch::*;
@@ -253,7 +284,11 @@ impl Endpoint<'_> {
let mut readable = tokio::select! {
readable = session_fd.readable() => readable?,
- _ = session_fd.writable() => return Ok(ControlFlow::Break(())),
+
+ _ = session_fd.writable() => {
+ self.session.mountpoint.lock().unwrap().take();
+ return Ok(ControlFlow::Break(()));
+ }
};
let mut read = |fd: &AsyncFd<RawFd>| read(*fd.get_ref(), buffer);
@@ -264,6 +299,7 @@ impl Endpoint<'_> {
match result {
// Interrupted
+ //TODO: libfuse docs say that this has some side effects
Err(error) if error.kind() == std::io::ErrorKind::NotFound => continue,
result => break result,
@@ -330,11 +366,12 @@ impl Endpoint<'_> {
}
impl Start {
- pub async fn start<F>(self, mut init: F) -> FuseResult<Arc<Session>>
+ pub async fn start<F>(mut self, mut init: F) -> FuseResult<Arc<Session>>
where
F: FnOnce(Op<'_, ops::Init>) -> Done<'_>,
{
- let session_fd = self.session_fd.into_raw_fd();
+ let mountpoint = std::mem::take(&mut self.mountpoint);
+ let session_fd = self.session_fd.take().into_raw_fd();
let flags = OFlag::O_NONBLOCK | OFlag::O_LARGEFILE;
fcntl(session_fd, FcntlArg::F_SETFL(flags)).unwrap();
@@ -353,6 +390,7 @@ impl Start {
buffers: Mutex::new(buffers),
buffer_semaphore: Arc::new(Semaphore::new(buffer_count)),
buffer_pages,
+ mountpoint: Mutex::new(Some(mountpoint)),
};
let mut init_buffer = session.buffers.get_mut().unwrap().pop().unwrap();
@@ -368,8 +406,17 @@ impl Start {
}
}
- pub(crate) fn new(session_fd: DumbFd) -> Self {
- Start { session_fd }
+ pub fn unmount_sync(mut self) -> Result<(), MountError> {
+ // This prevents Start::drop() from unmounting a second time
+ let mountpoint = std::mem::take(&mut self.mountpoint);
+ unmount_sync(&mountpoint)
+ }
+
+ pub(crate) fn new(session_fd: DumbFd, mountpoint: PathBuf) -> Self {
+ Start {
+ session_fd,
+ mountpoint,
+ }
}
}
diff --git a/src/util.rs b/src/util.rs
index c21442f..5da19c8 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -29,6 +29,12 @@ pub struct OutputChain<'a> {
pub struct OutputChainIter<'a>(Option<&'a OutputChain<'a>>);
+impl DumbFd {
+ pub fn take(&mut self) -> DumbFd {
+ DumbFd(std::mem::replace(&mut self.0, -1))
+ }
+}
+
impl IntoRawFd for DumbFd {
fn into_raw_fd(self) -> RawFd {
let fd = self.0;
@@ -39,7 +45,9 @@ impl IntoRawFd for DumbFd {
impl Drop for DumbFd {
fn drop(&mut self) {
- let _ = close(self.0);
+ if !self.0.is_negative() {
+ let _ = close(self.0);
+ }
}
}