Alioth Code Coverage

fuse.rs0.00%

1// Copyright 2025 Google LLC
2//
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 at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// 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 and
13// limitations under the License.
14
15pub mod bindings;
16pub mod passthrough;
17
18use std::ffi::FromBytesUntilNulError;
19use std::fmt::Debug;
20use std::fs::File;
21use std::io::{Error as IoError, IoSlice, IoSliceMut};
22
23use alioth_macros::trace_error;
24use snafu::Snafu;
25
26use crate::errors::DebugTrace;
27
28use 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)))]
39pub 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
62impl 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
69impl 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
85pub type Result<T, E = Error> = std::result::Result<T, E>;
86
87macro_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
95macro_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
118pub 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
131pub 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