1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use super::{fuse2_sys::*, with_fuse_args, MountOption};
use log::warn;
use std::{
ffi::CString,
fs::File,
io,
os::unix::prelude::{FromRawFd, OsStrExt},
path::Path,
sync::Arc,
};
/// Ensures that an os error is never 0/Success
fn ensure_last_os_error() -> io::Error {
let err = io::Error::last_os_error();
match err.raw_os_error() {
Some(0) => io::Error::new(io::ErrorKind::Other, "Unspecified Error"),
_ => err,
}
}
#[derive(Debug)]
pub struct Mount {
mountpoint: CString,
}
impl Mount {
pub fn new(mountpoint: &Path, options: &[MountOption]) -> io::Result<(Arc<File>, Mount)> {
let mountpoint = CString::new(mountpoint.as_os_str().as_bytes()).unwrap();
with_fuse_args(options, |args| {
let fd = unsafe { fuse_mount_compat25(mountpoint.as_ptr(), args) };
if fd < 0 {
Err(ensure_last_os_error())
} else {
let file = unsafe { File::from_raw_fd(fd) };
Ok((Arc::new(file), Mount { mountpoint }))
}
})
}
}
impl Drop for Mount {
fn drop(&mut self) {
use std::io::ErrorKind::PermissionDenied;
// fuse_unmount_compat22 unfortunately doesn't return a status. Additionally,
// it attempts to call realpath, which in turn calls into the filesystem. So
// if the filesystem returns an error, the unmount does not take place, with
// no indication of the error available to the caller. So we call unmount
// directly, which is what osxfuse does anyway, since we already converted
// to the real path when we first mounted.
if let Err(err) = super::libc_umount(&self.mountpoint) {
// Linux always returns EPERM for non-root users. We have to let the
// library go through the setuid-root "fusermount -u" to unmount.
if err.kind() == PermissionDenied {
#[cfg(not(any(
target_os = "macos",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "bitrig",
target_os = "netbsd"
)))]
unsafe {
fuse_unmount_compat22(self.mountpoint.as_ptr());
return;
}
}
warn!("umount failed with {:?}", err);
}
}
}