fuse.rs0.00%
1
// Copyright 2025 Google LLC2
//3
// Licensed under the Apache License, Version 2.0 (the "License");4
// you may not use this file except in compliance with the License.5
// You may obtain a copy of the License at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// distributed under the License is distributed on an "AS IS" BASIS,11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12
// See the License for the specific language governing permissions and13
// limitations under the License.14
15
pub mod bindings;16
pub mod passthrough;17
18
use std::ffi::FromBytesUntilNulError;19
use std::fmt::Debug;20
use std::fs::File;21
use std::io::{Error as IoError, IoSlice, IoSliceMut};22
23
use alioth_macros::trace_error;24
use snafu::Snafu;25
26
use crate::errors::DebugTrace;27
28
use self::bindings::{29
FuseAttrOut, FuseCreateIn, FuseCreateOut, FuseEntryOut, FuseFlushIn, FuseForgetIn,30
FuseGetattrIn, FuseInHeader, FuseInitIn, FuseInitOut, FuseIoctlIn, FuseIoctlOut, FuseOpcode,31
FuseOpenIn, FuseOpenOut, FusePollIn, FusePollOut, FuseReadIn, FuseReleaseIn, FuseRename2In,32
FuseRenameIn, FuseSetupmappingFlag, FuseSetupmappingIn, FuseSyncfsIn, FuseWriteIn,33
FuseWriteOut,34
};35
36
#[trace_error]37
#[derive(Snafu, DebugTrace)]38
#[snafu(module, visibility(pub), context(suffix(false)))]39
pub enum Error {40
#[snafu(display("Error from OS"), context(false))]41
System { error: std::io::Error },42
#[snafu(display("Node id {id:#x} does not exist"))]43
NodeId { id: u64 },44
#[snafu(display("Invalid C String "), context(false))]45
InvalidCString { error: FromBytesUntilNulError },46
#[snafu(display("Unsupported flag {flag:#x} of {op:?}"))]47
Unsupported { op: FuseOpcode, flag: u32 },48
#[snafu(display("Directory was not opened"))]49
DirNotOpened,50
#[snafu(display("Invalid access mode {mode:#x}"))]51
InvalidAccMode { mode: i32 },52
#[snafu(display("File was not opened"))]53
FileNotOpened,54
#[snafu(display("Invalid file handle"))]55
InvalidFileHandle,56
#[snafu(display("Failed to setup DAX mappings"))]57
DaxMapping {58
source: Box<dyn DebugTrace + Send + Sync + 'static>,59
},60
}61
62
impl From<&IoError> for Error {63
fn from(e: &IoError) -> Self {64
let code = e.raw_os_error().unwrap_or(libc::EINVAL);65
IoError::from_raw_os_error(code).into()66
}67
}68
69
impl Error {70
pub fn error_code(&self) -> i32 {71
match self {72
Error::System { error, .. } => error.raw_os_error().unwrap_or(libc::EINVAL),73
Error::NodeId { .. } => libc::ENOENT,74
Error::InvalidCString { .. } => libc::EINVAL,75
Error::Unsupported { .. } => libc::EOPNOTSUPP,76
Error::DirNotOpened { .. } => libc::EBADF,77
Error::InvalidAccMode { .. } => libc::EINVAL,78
Error::FileNotOpened { .. } => libc::EBADF,79
Error::InvalidFileHandle { .. } => libc::EBADF,80
Error::DaxMapping { .. } => libc::EINVAL,81
}82
}83
}84
85
pub type Result<T, E = Error> = std::result::Result<T, E>;86
87
macro_rules! fuse_no_impl {88
($hdr:expr, $in_:expr) => {{89
log::debug!("unimplemented: hdr: {:?}, in: {:?}", $hdr, $in_);90
let err: IoError = IoError::from_raw_os_error(libc::ENOSYS);91
Err(Error::from(err))92
}};93
}94
95
macro_rules! fuse_method {96
($name:ident, & $in_ty:ty, & $in_buf:ty, $out_ty:ty) => {97
fn $name(&mut self, hdr: &FuseInHeader, in_: &$in_ty, _buf: &$in_buf) -> Result<$out_ty> {98
fuse_no_impl!(hdr, in_)99
}100
};101
($name:ident, & $in_ty:ty, &mut $out_buf:ty) => {102
fn $name(103
&mut self,104
hdr: &FuseInHeader,105
in_: &$in_ty,106
_buf: &mut $out_buf,107
) -> Result<usize> {108
fuse_no_impl!(hdr, in_)109
}110
};111
($name:ident, & $in_ty:ty, $out_ty:ty) => {112
fn $name(&mut self, hdr: &FuseInHeader, in_: &$in_ty) -> Result<$out_ty> {113
fuse_no_impl!(hdr, in_)114
}115
};116
}117
118
pub trait DaxRegion: Debug + Send + Sync + 'static {119
fn map(120
&self,121
m_offset: u64,122
fd: &File,123
f_offset: u64,124
len: u64,125
flag: FuseSetupmappingFlag,126
) -> Result<()>;127
128
fn unmap(&self, m_offset: u64, len: u64) -> Result<()>;129
}130
131
pub trait Fuse {132
fuse_method!(init, &FuseInitIn, FuseInitOut);133
fuse_method!(get_attr, &FuseGetattrIn, FuseAttrOut);134
fuse_method!(open, &FuseOpenIn, FuseOpenOut);135
fuse_method!(open_dir, &FuseOpenIn, FuseOpenOut);136
fuse_method!(read_dir, &FuseReadIn, &mut [u8]);137
fuse_method!(release_dir, &FuseReleaseIn, ());138
fuse_method!(lookup, &[u8], FuseEntryOut);139
fuse_method!(forget, &FuseForgetIn, ());140
fuse_method!(read, &FuseReadIn, &mut [IoSliceMut]);141
fuse_method!(poll, &FusePollIn, FusePollOut);142
fuse_method!(flush, &FuseFlushIn, ());143
fuse_method!(release, &FuseReleaseIn, ());144
fuse_method!(syncfs, &FuseSyncfsIn, ());145
fuse_method!(ioctl, &FuseIoctlIn, FuseIoctlOut);146
fuse_method!(get_xattr, &[u8], &mut [u8]);147
fuse_method!(set_xattr, &[u8], ());148
fuse_method!(create, &FuseCreateIn, &[u8], FuseCreateOut);149
fuse_method!(write, &FuseWriteIn, &[IoSlice], FuseWriteOut);150
fuse_method!(unlink, &[u8], ());151
fuse_method!(rmdir, &[u8], ());152
fuse_method!(rename, &FuseRenameIn, &[u8], ());153
fuse_method!(rename2, &FuseRename2In, &[u8], ());154
fuse_method!(setup_mapping, &FuseSetupmappingIn, ());155
fuse_method!(remove_mapping, &[u8], ());156
fn set_dax_region(&mut self, dax_region: Box<dyn DaxRegion>);157
}158