1#![expect(missing_docs)]
8
9#[cfg(unix)]
10mod conn;
11pub mod protocol;
12mod reply;
13mod request;
14mod session;
15mod util;
16
17#[cfg(target_os = "linux")]
18pub use conn::Connection;
19pub use reply::DirEntryWriter;
20pub use reply::ReplySender;
21pub use request::FuseOperation;
22pub use request::Request;
23pub use request::RequestReader;
24pub use session::Session;
25pub use session::SessionInfo;
26
27use lx::LxStr;
28use lx::LxString;
29use protocol::*;
30use std::time::Duration;
31use zerocopy::FromBytes;
32use zerocopy::Immutable;
33use zerocopy::IntoBytes;
34use zerocopy::KnownLayout;
35
36#[repr(C)]
42#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
43pub struct CreateOut {
44 pub entry: fuse_entry_out,
45 pub open: fuse_open_out,
46}
47
48pub trait Fuse {
57 fn lookup(&self, _request: &Request, _name: &LxStr) -> lx::Result<fuse_entry_out> {
61 Err(lx::Error::ENOSYS)
62 }
63
64 fn forget(&self, _node_id: u64, _lookup_count: u64) {
71 }
73
74 fn get_attr(&self, _request: &Request, _flags: u32, _fh: u64) -> lx::Result<fuse_attr_out> {
81 Err(lx::Error::ENOSYS)
82 }
83
84 fn set_attr(&self, _request: &Request, _arg: &fuse_setattr_in) -> lx::Result<fuse_attr_out> {
86 Err(lx::Error::ENOSYS)
87 }
88
89 fn read_link(&self, _request: &Request) -> lx::Result<LxString> {
91 Err(lx::Error::ENOSYS)
92 }
93
94 fn symlink(
96 &self,
97 _request: &Request,
98 _name: &LxStr,
99 _target: &LxStr,
100 ) -> lx::Result<fuse_entry_out> {
101 Err(lx::Error::ENOSYS)
102 }
103
104 fn mknod(
107 &self,
108 _request: &Request,
109 _name: &LxStr,
110 _arg: &fuse_mknod_in,
111 ) -> lx::Result<fuse_entry_out> {
112 Err(lx::Error::ENOSYS)
113 }
114
115 fn mkdir(
117 &self,
118 _request: &Request,
119 _name: &LxStr,
120 _arg: &fuse_mkdir_in,
121 ) -> lx::Result<fuse_entry_out> {
122 Err(lx::Error::ENOSYS)
123 }
124
125 fn unlink(&self, _request: &Request, _name: &LxStr) -> lx::Result<()> {
127 Err(lx::Error::ENOSYS)
128 }
129
130 fn rmdir(&self, _request: &Request, _name: &LxStr) -> lx::Result<()> {
132 Err(lx::Error::ENOSYS)
133 }
134
135 fn rename(
140 &self,
141 _request: &Request,
142 _name: &LxStr,
143 _new_dir: u64,
144 _new_name: &LxStr,
145 _flags: u32,
146 ) -> lx::Result<()> {
147 Err(lx::Error::ENOSYS)
148 }
149
150 fn link(&self, _request: &Request, _name: &LxStr, _target: u64) -> lx::Result<fuse_entry_out> {
152 Err(lx::Error::ENOSYS)
153 }
154
155 fn open(&self, _request: &Request, _flags: u32) -> lx::Result<fuse_open_out> {
161 Err(lx::Error::ENOSYS)
162 }
163
164 fn read(&self, _request: &Request, _arg: &fuse_read_in) -> lx::Result<Vec<u8>> {
166 Err(lx::Error::ENOSYS)
167 }
168
169 fn write(&self, _request: &Request, _arg: &fuse_write_in, _data: &[u8]) -> lx::Result<usize> {
171 Err(lx::Error::ENOSYS)
172 }
173
174 fn statfs(&self, _request: &Request) -> lx::Result<fuse_kstatfs> {
176 Err(lx::Error::ENOSYS)
177 }
178
179 fn release(&self, _request: &Request, _arg: &fuse_release_in) -> lx::Result<()> {
184 Ok(())
185 }
186
187 fn fsync(&self, _request: &Request, _fh: u64, _flags: u32) -> lx::Result<()> {
189 Err(lx::Error::ENOSYS)
190 }
191
192 fn set_xattr(
194 &self,
195 _request: &Request,
196 _name: &LxStr,
197 _value: &[u8],
198 _flags: u32,
199 ) -> lx::Result<()> {
200 Err(lx::Error::ENOSYS)
201 }
202
203 fn get_xattr(&self, _request: &Request, _name: &LxStr, _size: u32) -> lx::Result<Vec<u8>> {
205 Err(lx::Error::ENOSYS)
206 }
207
208 fn get_xattr_size(&self, _request: &Request, _name: &LxStr) -> lx::Result<u32> {
210 Err(lx::Error::ENOSYS)
211 }
212
213 fn list_xattr(&self, _request: &Request, _size: u32) -> lx::Result<Vec<u8>> {
215 Err(lx::Error::ENOSYS)
216 }
217
218 fn list_xattr_size(&self, _request: &Request) -> lx::Result<u32> {
220 Err(lx::Error::ENOSYS)
221 }
222
223 fn remove_xattr(&self, _request: &Request, _name: &LxStr) -> lx::Result<()> {
225 Err(lx::Error::ENOSYS)
226 }
227
228 fn flush(&self, _request: &Request, _arg: &fuse_flush_in) -> lx::Result<()> {
234 Err(lx::Error::ENOSYS)
235 }
236
237 fn init(&self, _info: &mut SessionInfo) {}
239
240 fn open_dir(&self, _request: &Request, _flags: u32) -> lx::Result<fuse_open_out> {
246 Err(lx::Error::ENOSYS)
247 }
248
249 fn read_dir(&self, _request: &Request, _arg: &fuse_read_in) -> lx::Result<Vec<u8>> {
253 Err(lx::Error::ENOSYS)
254 }
255
256 fn release_dir(&self, _request: &Request, _arg: &fuse_release_in) -> lx::Result<()> {
261 Ok(())
262 }
263
264 fn fsync_dir(&self, _request: &Request, _fh: u64, _flags: u32) -> lx::Result<()> {
266 Err(lx::Error::ENOSYS)
267 }
268
269 fn get_lock(&self, _request: &Request, _arg: &fuse_lk_in) -> lx::Result<fuse_file_lock> {
271 Err(lx::Error::ENOSYS)
272 }
273
274 fn set_lock(&self, _request: &Request, _arg: &fuse_lk_in, _sleep: bool) -> lx::Result<()> {
278 Err(lx::Error::ENOSYS)
279 }
280
281 fn access(&self, _request: &Request, _mask: u32) -> lx::Result<()> {
283 Err(lx::Error::ENOSYS)
284 }
285
286 fn create(
290 &self,
291 _request: &Request,
292 _name: &LxStr,
293 _arg: &fuse_create_in,
294 ) -> lx::Result<CreateOut> {
295 Err(lx::Error::ENOSYS)
296 }
297
298 fn block_map(&self, _request: &Request, _block: u64, _block_size: u32) -> lx::Result<u64> {
302 Err(lx::Error::ENOSYS)
303 }
304
305 fn destroy(&self) {}
313
314 fn ioctl(
321 &self,
322 _request: &Request,
323 _arg: &fuse_ioctl_in,
324 _data: &[u8],
325 ) -> lx::Result<(i32, Vec<u8>)> {
326 Err(lx::Error::ENOSYS)
327 }
328
329 fn fallocate(&self, _request: &Request, _arg: &fuse_fallocate_in) -> lx::Result<()> {
331 Err(lx::Error::ENOSYS)
332 }
333
334 fn read_dir_plus(&self, _request: &Request, _arg: &fuse_read_in) -> lx::Result<Vec<u8>> {
341 Err(lx::Error::ENOSYS)
342 }
343
344 fn lseek(&self, _request: &Request, _fh: u64, _offset: u64, _whence: u32) -> lx::Result<u64> {
346 Err(lx::Error::ENOSYS)
347 }
348
349 fn copy_file_range(
352 &self,
353 _request: &Request,
354 _arg: &fuse_copy_file_range_in,
355 ) -> lx::Result<usize> {
356 Err(lx::Error::ENOSYS)
357 }
358
359 fn setup_mapping(
361 &self,
362 request: &Request,
363 mapper: &dyn Mapper,
364 arg: &fuse_setupmapping_in,
365 ) -> lx::Result<()> {
366 let _ = (request, mapper, arg);
367 Err(lx::Error::ENOSYS)
368 }
369
370 fn remove_mapping(
372 &self,
373 request: &Request,
374 mapper: &dyn Mapper,
375 moffset: u64,
376 len: u64,
377 ) -> lx::Result<()> {
378 let _ = (request, mapper, moffset, len);
379 Err(lx::Error::ENOSYS)
380 }
381}
382
383#[cfg(windows)]
384pub type FileRef<'a> = std::os::windows::io::BorrowedHandle<'a>;
385#[cfg(unix)]
386pub type FileRef<'a> = std::os::unix::io::BorrowedFd<'a>;
387
388pub trait Mapper {
392 fn map(
394 &self,
395 offset: u64,
396 file: FileRef<'_>,
397 file_offset: u64,
398 len: u64,
399 writable: bool,
400 ) -> lx::Result<()>;
401
402 fn unmap(&self, offset: u64, len: u64) -> lx::Result<()>;
404
405 fn clear(&self);
407}
408
409impl fuse_entry_out {
410 pub fn new(node_id: u64, entry_valid: Duration, attr_valid: Duration, attr: fuse_attr) -> Self {
412 Self {
413 nodeid: node_id,
414 generation: 0,
415 entry_valid: entry_valid.as_secs(),
416 entry_valid_nsec: entry_valid.subsec_nanos(),
417 attr_valid: attr_valid.as_secs(),
418 attr_valid_nsec: attr_valid.subsec_nanos(),
419 attr,
420 }
421 }
422}
423
424impl fuse_attr_out {
425 pub fn new(valid: Duration, attr: fuse_attr) -> Self {
427 Self {
428 attr_valid: valid.as_secs(),
429 attr_valid_nsec: valid.subsec_nanos(),
430 dummy: 0,
431 attr,
432 }
433 }
434}
435
436impl fuse_open_out {
437 pub fn new(fh: u64, open_flags: u32) -> Self {
439 Self {
440 fh,
441 open_flags,
442 padding: 0,
443 }
444 }
445}
446
447impl fuse_kstatfs {
448 pub fn new(
450 blocks: u64,
451 bfree: u64,
452 bavail: u64,
453 files: u64,
454 ffree: u64,
455 bsize: u32,
456 namelen: u32,
457 frsize: u32,
458 ) -> Self {
459 Self {
460 blocks,
461 bfree,
462 bavail,
463 files,
464 ffree,
465 bsize,
466 namelen,
467 frsize,
468 padding: 0,
469 spare: Default::default(),
470 }
471 }
472}