Skip to content

Commit

Permalink
make libfuse optional
Browse files Browse the repository at this point in the history
  • Loading branch information
Mic92 committed Oct 5, 2017
1 parent 168fa33 commit 9c53b9f
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 4 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ env_logger = "0.3"
[lib]
name = "fuse"
path = "src/lib.rs"

[features]
libfuse = []
1 change: 1 addition & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ static LIBFUSE_NAME: &str = "fuse";
static LIBFUSE_NAME: &str = "osxfuse";

fn main () {
#[cfg(feature = "libfuse")]
pkg_config::Config::new().atleast_version("2.6.0").probe(LIBFUSE_NAME).unwrap();
}
23 changes: 19 additions & 4 deletions src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ use std::ffi::{CString, CStr, OsStr};
use std::os::unix::ffi::OsStrExt;
use std::path::{PathBuf, Path};
use libc::{self, c_int, c_void, size_t};
use std::os::unix::io::{RawFd, AsRawFd, FromRawFd};
#[cfg(feature = "libfuse")]
use libfuse::{fuse_args, fuse_mount_compat25};
use reply::ReplySender;

/// Helper function to provide options as a fuse_args struct
/// (which contains an argc count and an argv pointer)
#[cfg(feature = "libfuse")]
fn with_fuse_args<T, F: FnOnce(&fuse_args) -> T>(options: &[&OsStr], f: F) -> T {
let mut args = vec![CString::new("rust-fuse").unwrap()];
args.extend(options.iter().map(|s| CString::new(s.as_bytes()).unwrap()));
Expand All @@ -23,14 +26,15 @@ fn with_fuse_args<T, F: FnOnce(&fuse_args) -> T>(options: &[&OsStr], f: F) -> T
#[derive(Debug)]
pub struct Channel {
mountpoint: PathBuf,
fd: c_int,
fd: RawFd,
}

impl Channel {
/// Create a new communication channel to the kernel driver by mounting the
/// given path. The kernel driver will delegate filesystem operations of
/// the given path to the channel. If the channel is dropped, the path is
/// unmounted.
#[cfg(feature = "libfuse")]
pub fn new(mountpoint: &Path, options: &[&OsStr]) -> io::Result<Channel> {
let mountpoint = try!(mountpoint.canonicalize());
with_fuse_args(options, |args| {
Expand Down Expand Up @@ -76,16 +80,26 @@ impl Drop for Channel {
fn drop(&mut self) {
// TODO: send ioctl FUSEDEVIOCSETDAEMONDEAD on macOS before closing the fd
// Close the communication channel to the kernel driver
// (closing it before unnmount prevents sync unmount deadlock)
// (closing it before unmount prevents sync unmount deadlock)
unsafe { libc::close(self.fd); }
// Unmount this channel's mount point
#[cfg(feature = "libfuse")]
let _ = unmount(&self.mountpoint);
}
}

impl FromRawFd for Channel {
/// Creates a channel from a file descriptor of a initialized Fuse.
/// The file descriptor will be closed when `Channel` goes out of scope;
/// however the fuse will be not unmounted.
unsafe fn from_raw_fd(fd: RawFd) -> Channel {
Channel { fd: fd, mountpoint: PathBuf::from("") }
}
}

#[derive(Clone, Copy, Debug)]
pub struct ChannelSender {
fd: c_int,
fd: RawFd,
}

impl ChannelSender {
Expand All @@ -94,7 +108,7 @@ impl ChannelSender {
let iovecs: Vec<_> = buffer.iter().map(|d| {
libc::iovec { iov_base: d.as_ptr() as *mut c_void, iov_len: d.len() as size_t }
}).collect();
let rc = unsafe { libc::writev(self.fd, iovecs.as_ptr(), iovecs.len() as c_int) };
let rc = unsafe { libc::writev(self.fd, iovecs.as_ptr(), iovecs.len() as RawFd) };
if rc < 0 {
Err(io::Error::last_os_error())
} else {
Expand All @@ -112,6 +126,7 @@ impl ReplySender for ChannelSender {
}

/// Unmount an arbitrary mount point
#[cfg(feature = "libfuse")]
pub fn unmount(mountpoint: &Path) -> io::Result<()> {
// fuse_unmount_compat22 unfortunately doesn't return a status. Additionally,
// it attempts to call realpath, which in turn calls into the filesystem. So
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub use session::{Session, BackgroundSession};
mod argument;
mod channel;
mod kernel;
#[cfg(feature = "libfuse")]
mod libfuse;
mod reply;
mod request;
Expand Down Expand Up @@ -382,6 +383,7 @@ pub trait Filesystem {

/// Mount the given filesystem to the given mountpoint. This function will
/// not return until the filesystem is unmounted.
#[cfg(feature = "libfuse")]
pub fn mount<FS: Filesystem, P: AsRef<Path>>(filesystem: FS, mountpoint: &P, options: &[&OsStr]) -> io::Result<()>{
Session::new(filesystem, mountpoint.as_ref(), options).and_then(|mut se| se.run())
}
Expand All @@ -391,6 +393,7 @@ pub fn mount<FS: Filesystem, P: AsRef<Path>>(filesystem: FS, mountpoint: &P, opt
/// and therefore returns immediately. The returned handle should be stored
/// to reference the mounted filesystem. If it's dropped, the filesystem will
/// be unmounted.
#[cfg(feature = "libfuse")]
pub unsafe fn spawn_mount<'a, FS: Filesystem+Send+'a, P: AsRef<Path>>(filesystem: FS, mountpoint: &P, options: &[&OsStr]) -> io::Result<BackgroundSession<'a>> {
Session::new(filesystem, mountpoint.as_ref(), options).and_then(|se| se.spawn())
}
15 changes: 15 additions & 0 deletions src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use std::io;
use std::ffi::OsStr;
use std::fmt;
use std::os::unix::io::{RawFd, FromRawFd};
use std::path::{PathBuf, Path};
use thread_scoped::{scoped, JoinGuard};
use libc::{EAGAIN, EINTR, ENODEV, ENOENT};
Expand Down Expand Up @@ -43,6 +44,7 @@ pub struct Session<FS: Filesystem> {

impl<FS: Filesystem> Session<FS> {
/// Create a new session by mounting the given filesystem to the given mountpoint
#[cfg(feature = "libfuse")]
pub fn new(filesystem: FS, mountpoint: &Path, options: &[&OsStr]) -> io::Result<Session<FS>> {
info!("Mounting {}", mountpoint.display());
Channel::new(mountpoint, options).map(|ch| {
Expand All @@ -57,6 +59,18 @@ impl<FS: Filesystem> Session<FS> {
})
}

/// Create a new session by using a file descriptor "/dev/fuse"
pub fn new_from_fd(filesystem: FS, fd: RawFd) -> Session<FS> {
Session {
filesystem: filesystem,
ch: unsafe { Channel::from_raw_fd(fd) },
proto_major: 0,
proto_minor: 0,
initialized: false,
destroyed: false,
}
}

/// Return path of the mounted filesystem
pub fn mountpoint(&self) -> &Path {
&self.ch.mountpoint()
Expand Down Expand Up @@ -138,6 +152,7 @@ impl<'a> Drop for BackgroundSession<'a> {
info!("Unmounting {}", self.mountpoint.display());
// Unmounting the filesystem will eventually end the session loop,
// drop the session and hence end the background thread.
#[cfg(feature = "libfuse")]
match channel::unmount(&self.mountpoint) {
Ok(()) => (),
Err(err) => error!("Failed to unmount {}: {}", self.mountpoint.display(), err),
Expand Down

0 comments on commit 9c53b9f

Please sign in to comment.