#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#[cfg(target_os = "macos")]
use std::io::ErrorKind;
#[cfg(any(
all(target_os = "linux", feature = "unprivileged"),
target_os = "macos"
))]
use std::io::{self};
#[cfg(target_os = "macos")]
use std::path::Path;
#[cfg(any(
all(target_os = "linux", feature = "unprivileged"),
target_os = "macos"
))]
use std::path::PathBuf;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub use errno::Errno;
pub use helper::{mode_from_kind_and_perm, perm_from_mode_and_kind};
pub use mount_options::MountOptions;
use nix::sys::stat::mode_t;
use raw::abi::{
FATTR_ATIME, FATTR_ATIME_NOW, FATTR_CTIME, FATTR_GID, FATTR_LOCKOWNER, FATTR_MODE, FATTR_MTIME,
FATTR_MTIME_NOW, FATTR_SIZE, FATTR_UID, fuse_setattr_in,
};
#[cfg(target_os = "macos")]
use raw::abi::{FATTR_BKUPTIME, FATTR_CHGTIME, FATTR_CRTIME, FATTR_FLAGS};
mod errno;
mod helper;
mod mount_options;
pub mod notify;
pub mod path;
pub mod raw;
pub type Inode = u64;
pub type Result<T> = std::result::Result<T, Errno>;
#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum FileType {
NamedPipe,
CharDevice,
BlockDevice,
Directory,
RegularFile,
Symlink,
Socket,
}
impl FileType {
pub const fn const_into_mode_t(self) -> mode_t {
match self {
FileType::NamedPipe => libc::S_IFIFO,
FileType::CharDevice => libc::S_IFCHR,
FileType::BlockDevice => libc::S_IFBLK,
FileType::Directory => libc::S_IFDIR,
FileType::RegularFile => libc::S_IFREG,
FileType::Symlink => libc::S_IFLNK,
FileType::Socket => libc::S_IFSOCK,
}
}
}
impl From<FileType> for mode_t {
fn from(kind: FileType) -> Self {
kind.const_into_mode_t()
}
}
#[derive(Debug, Clone, Default, Eq, PartialEq)]
pub struct SetAttr {
pub mode: Option<mode_t>,
pub uid: Option<u32>,
pub gid: Option<u32>,
pub size: Option<u64>,
pub lock_owner: Option<u64>,
pub atime: Option<Timestamp>,
pub mtime: Option<Timestamp>,
pub ctime: Option<Timestamp>,
#[cfg(target_os = "macos")]
pub crtime: Option<Timestamp>,
#[cfg(target_os = "macos")]
pub chgtime: Option<Timestamp>,
#[cfg(target_os = "macos")]
pub bkuptime: Option<Timestamp>,
#[cfg(target_os = "macos")]
pub flags: Option<u32>,
}
macro_rules! fsai2ts {
( $secs: expr, $nsecs: expr) => {
Some(Timestamp::new($secs as i64, $nsecs))
};
}
impl From<&fuse_setattr_in> for SetAttr {
fn from(setattr_in: &fuse_setattr_in) -> Self {
let mut set_attr = Self::default();
if setattr_in.valid & FATTR_MODE > 0 {
set_attr.mode = Some(setattr_in.mode as mode_t);
}
if setattr_in.valid & FATTR_UID > 0 {
set_attr.uid = Some(setattr_in.uid);
}
if setattr_in.valid & FATTR_GID > 0 {
set_attr.gid = Some(setattr_in.gid);
}
if setattr_in.valid & FATTR_SIZE > 0 {
set_attr.size = Some(setattr_in.size);
}
if setattr_in.valid & FATTR_ATIME > 0 {
set_attr.atime = fsai2ts!(setattr_in.atime, setattr_in.atimensec);
}
if setattr_in.valid & FATTR_ATIME_NOW > 0 {
set_attr.atime = Some(SystemTime::now().into());
}
if setattr_in.valid & FATTR_MTIME > 0 {
set_attr.mtime = fsai2ts!(setattr_in.mtime, setattr_in.mtimensec);
}
if setattr_in.valid & FATTR_MTIME_NOW > 0 {
set_attr.mtime = Some(SystemTime::now().into());
}
if setattr_in.valid & FATTR_LOCKOWNER > 0 {
set_attr.lock_owner = Some(setattr_in.lock_owner);
}
if setattr_in.valid & FATTR_CTIME > 0 {
set_attr.ctime = fsai2ts!(setattr_in.ctime, setattr_in.ctimensec);
}
#[cfg(target_os = "macos")]
if setattr_in.valid & FATTR_CRTIME > 0 {
set_attr.ctime = fsai2ts!(setattr_in.crtime, setattr_in.crtimensec);
}
#[cfg(target_os = "macos")]
if setattr_in.valid & FATTR_CHGTIME > 0 {
set_attr.ctime = fsai2ts!(setattr_in.chgtime, setattr_in.chgtimensec);
}
#[cfg(target_os = "macos")]
if setattr_in.valid & FATTR_BKUPTIME > 0 {
set_attr.ctime = fsai2ts!(setattr_in.bkuptime, setattr_in.bkuptimensec);
}
#[cfg(target_os = "macos")]
if setattr_in.valid & FATTR_FLAGS > 0 {
set_attr.flags = Some(setattr_in.flags);
}
set_attr
}
}
#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Timestamp {
pub sec: i64,
pub nsec: u32,
}
impl Timestamp {
pub fn new(sec: i64, nsec: u32) -> Self {
Timestamp { sec, nsec }
}
}
impl From<SystemTime> for Timestamp {
fn from(t: SystemTime) -> Self {
let d = t
.duration_since(UNIX_EPOCH)
.unwrap_or_else(|_| Duration::from_secs(0));
Timestamp {
sec: d.as_secs().try_into().unwrap_or(i64::MAX),
nsec: d.subsec_nanos(),
}
}
}
#[cfg(all(target_os = "linux", feature = "unprivileged"))]
fn find_fusermount3() -> io::Result<PathBuf> {
which::which("fusermount3")
.map_err(|err| io::Error::other(format!("find fusermount3 binary failed {err:?}")))
}
#[cfg(target_os = "macos")]
fn find_macfuse_mount() -> io::Result<PathBuf> {
if Path::new("/Library/Filesystems/macfuse.fs/Contents/Resources/mount_macfuse").exists() {
Ok(PathBuf::from(
"/Library/Filesystems/macfuse.fs/Contents/Resources/mount_macfuse",
))
} else {
Err(io::Error::new(
ErrorKind::NotFound,
"macfuse mount binary not found, Please install macfuse first.",
))
}
}