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 request::check_name;
25pub use session::Session;
26pub use session::SessionInfo;
27
28use lx::LxStr;
29use lx::LxString;
30use protocol::*;
31use std::time::Duration;
32use zerocopy::FromBytes;
33use zerocopy::FromZeros;
34use zerocopy::Immutable;
35use zerocopy::IntoBytes;
36use zerocopy::KnownLayout;
37
38#[repr(C)]
44#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
45pub struct CreateOut {
46 pub entry: fuse_entry_out,
47 pub open: fuse_open_out,
48}
49
50pub trait Fuse {
59 fn lookup(&self, _request: &Request, _name: &LxStr) -> lx::Result<fuse_entry_out> {
63 Err(lx::Error::ENOSYS)
64 }
65
66 fn forget(&self, _node_id: u64, _lookup_count: u64) {
73 }
75
76 fn get_attr(&self, _request: &Request, _flags: u32, _fh: u64) -> lx::Result<fuse_attr_out> {
83 Err(lx::Error::ENOSYS)
84 }
85
86 fn set_attr(&self, _request: &Request, _arg: &fuse_setattr_in) -> lx::Result<fuse_attr_out> {
88 Err(lx::Error::ENOSYS)
89 }
90
91 fn read_link(&self, _request: &Request) -> lx::Result<LxString> {
93 Err(lx::Error::ENOSYS)
94 }
95
96 fn symlink(
98 &self,
99 _request: &Request,
100 _name: &LxStr,
101 _target: &LxStr,
102 ) -> lx::Result<fuse_entry_out> {
103 Err(lx::Error::ENOSYS)
104 }
105
106 fn mknod(
109 &self,
110 _request: &Request,
111 _name: &LxStr,
112 _arg: &fuse_mknod_in,
113 ) -> lx::Result<fuse_entry_out> {
114 Err(lx::Error::ENOSYS)
115 }
116
117 fn mkdir(
119 &self,
120 _request: &Request,
121 _name: &LxStr,
122 _arg: &fuse_mkdir_in,
123 ) -> lx::Result<fuse_entry_out> {
124 Err(lx::Error::ENOSYS)
125 }
126
127 fn unlink(&self, _request: &Request, _name: &LxStr) -> lx::Result<()> {
129 Err(lx::Error::ENOSYS)
130 }
131
132 fn rmdir(&self, _request: &Request, _name: &LxStr) -> lx::Result<()> {
134 Err(lx::Error::ENOSYS)
135 }
136
137 fn rename(
142 &self,
143 _request: &Request,
144 _name: &LxStr,
145 _new_dir: u64,
146 _new_name: &LxStr,
147 _flags: u32,
148 ) -> lx::Result<()> {
149 Err(lx::Error::ENOSYS)
150 }
151
152 fn link(&self, _request: &Request, _name: &LxStr, _target: u64) -> lx::Result<fuse_entry_out> {
154 Err(lx::Error::ENOSYS)
155 }
156
157 fn open(&self, _request: &Request, _flags: u32) -> lx::Result<fuse_open_out> {
163 Err(lx::Error::ENOSYS)
164 }
165
166 fn read(&self, _request: &Request, _arg: &fuse_read_in) -> lx::Result<Vec<u8>> {
168 Err(lx::Error::ENOSYS)
169 }
170
171 fn write(&self, _request: &Request, _arg: &fuse_write_in, _data: &[u8]) -> lx::Result<usize> {
173 Err(lx::Error::ENOSYS)
174 }
175
176 fn statfs(&self, _request: &Request) -> lx::Result<fuse_kstatfs> {
178 Err(lx::Error::ENOSYS)
179 }
180
181 fn release(&self, _request: &Request, _arg: &fuse_release_in) -> lx::Result<()> {
186 Ok(())
187 }
188
189 fn fsync(&self, _request: &Request, _fh: u64, _flags: u32) -> lx::Result<()> {
191 Err(lx::Error::ENOSYS)
192 }
193
194 fn set_xattr(
196 &self,
197 _request: &Request,
198 _name: &LxStr,
199 _value: &[u8],
200 _flags: u32,
201 ) -> lx::Result<()> {
202 Err(lx::Error::ENOSYS)
203 }
204
205 fn get_xattr(&self, _request: &Request, _name: &LxStr, _size: u32) -> lx::Result<Vec<u8>> {
207 Err(lx::Error::ENOSYS)
208 }
209
210 fn get_xattr_size(&self, _request: &Request, _name: &LxStr) -> lx::Result<u32> {
212 Err(lx::Error::ENOSYS)
213 }
214
215 fn list_xattr(&self, _request: &Request, _size: u32) -> lx::Result<Vec<u8>> {
217 Err(lx::Error::ENOSYS)
218 }
219
220 fn list_xattr_size(&self, _request: &Request) -> lx::Result<u32> {
222 Err(lx::Error::ENOSYS)
223 }
224
225 fn remove_xattr(&self, _request: &Request, _name: &LxStr) -> lx::Result<()> {
227 Err(lx::Error::ENOSYS)
228 }
229
230 fn flush(&self, _request: &Request, _arg: &fuse_flush_in) -> lx::Result<()> {
236 Err(lx::Error::ENOSYS)
237 }
238
239 fn init(&self, _info: &mut SessionInfo) {}
241
242 fn open_dir(&self, _request: &Request, _flags: u32) -> lx::Result<fuse_open_out> {
248 Err(lx::Error::ENOSYS)
249 }
250
251 fn read_dir(&self, _request: &Request, _arg: &fuse_read_in) -> lx::Result<Vec<u8>> {
255 Err(lx::Error::ENOSYS)
256 }
257
258 fn release_dir(&self, _request: &Request, _arg: &fuse_release_in) -> lx::Result<()> {
263 Ok(())
264 }
265
266 fn fsync_dir(&self, _request: &Request, _fh: u64, _flags: u32) -> lx::Result<()> {
268 Err(lx::Error::ENOSYS)
269 }
270
271 fn get_lock(&self, _request: &Request, _arg: &fuse_lk_in) -> lx::Result<fuse_file_lock> {
273 Err(lx::Error::ENOSYS)
274 }
275
276 fn set_lock(&self, _request: &Request, _arg: &fuse_lk_in, _sleep: bool) -> lx::Result<()> {
280 Err(lx::Error::ENOSYS)
281 }
282
283 fn access(&self, _request: &Request, _mask: u32) -> lx::Result<()> {
285 Err(lx::Error::ENOSYS)
286 }
287
288 fn create(
292 &self,
293 _request: &Request,
294 _name: &LxStr,
295 _arg: &fuse_create_in,
296 ) -> lx::Result<CreateOut> {
297 Err(lx::Error::ENOSYS)
298 }
299
300 fn block_map(&self, _request: &Request, _block: u64, _block_size: u32) -> lx::Result<u64> {
304 Err(lx::Error::ENOSYS)
305 }
306
307 fn destroy(&self) {}
315
316 fn ioctl(
323 &self,
324 _request: &Request,
325 _arg: &fuse_ioctl_in,
326 _data: &[u8],
327 ) -> lx::Result<(i32, Vec<u8>)> {
328 Err(lx::Error::ENOSYS)
329 }
330
331 fn fallocate(&self, _request: &Request, _arg: &fuse_fallocate_in) -> lx::Result<()> {
333 Err(lx::Error::ENOSYS)
334 }
335
336 fn read_dir_plus(&self, _request: &Request, _arg: &fuse_read_in) -> lx::Result<Vec<u8>> {
343 Err(lx::Error::ENOSYS)
344 }
345
346 fn lseek(&self, _request: &Request, _fh: u64, _offset: u64, _whence: u32) -> lx::Result<u64> {
348 Err(lx::Error::ENOSYS)
349 }
350
351 fn copy_file_range(
354 &self,
355 _request: &Request,
356 _arg: &fuse_copy_file_range_in,
357 ) -> lx::Result<usize> {
358 Err(lx::Error::ENOSYS)
359 }
360
361 fn setup_mapping(
363 &self,
364 request: &Request,
365 mapper: &dyn Mapper,
366 arg: &fuse_setupmapping_in,
367 ) -> lx::Result<()> {
368 let _ = (request, mapper, arg);
369 Err(lx::Error::ENOSYS)
370 }
371
372 fn remove_mapping(
374 &self,
375 request: &Request,
376 mapper: &dyn Mapper,
377 moffset: u64,
378 len: u64,
379 ) -> lx::Result<()> {
380 let _ = (request, mapper, moffset, len);
381 Err(lx::Error::ENOSYS)
382 }
383
384 fn get_statx(
391 &self,
392 _request: &Request,
393 _fh: u64,
394 _getattr_flags: u32,
395 _flags: StatxFlags,
396 _mask: lx::StatExMask,
397 ) -> lx::Result<fuse_statx_out> {
398 Err(lx::Error::ENOSYS)
399 }
400}
401
402#[cfg(windows)]
403pub type FileRef<'a> = std::os::windows::io::BorrowedHandle<'a>;
404#[cfg(unix)]
405pub type FileRef<'a> = std::os::unix::io::BorrowedFd<'a>;
406
407pub trait Mapper {
411 fn map(
413 &self,
414 offset: u64,
415 file: FileRef<'_>,
416 file_offset: u64,
417 len: u64,
418 writable: bool,
419 ) -> lx::Result<()>;
420
421 fn unmap(&self, offset: u64, len: u64) -> lx::Result<()>;
423
424 fn clear(&self);
426}
427
428impl fuse_entry_out {
429 pub fn new(node_id: u64, entry_valid: Duration, attr_valid: Duration, attr: fuse_attr) -> Self {
431 Self {
432 nodeid: node_id,
433 generation: 0,
434 entry_valid: entry_valid.as_secs(),
435 entry_valid_nsec: entry_valid.subsec_nanos(),
436 attr_valid: attr_valid.as_secs(),
437 attr_valid_nsec: attr_valid.subsec_nanos(),
438 attr,
439 }
440 }
441
442 pub fn new_dot(ino: u64, mode: u32) -> Self {
443 let mut entry = Self::new_zeroed();
444 entry.attr.ino = ino;
445 entry.attr.mode = mode;
446 entry
447 }
448}
449
450impl fuse_attr_out {
451 pub fn new(valid: Duration, attr: fuse_attr) -> Self {
453 Self {
454 attr_valid: valid.as_secs(),
455 attr_valid_nsec: valid.subsec_nanos(),
456 dummy: 0,
457 attr,
458 }
459 }
460}
461
462impl fuse_statx_out {
463 pub fn new(valid: Duration, flags: StatxFlags, statx: fuse_statx) -> Self {
465 Self {
466 attr_valid: valid.as_secs(),
467 attr_valid_nsec: valid.subsec_nanos(),
468 flags,
469 statx,
470 _rsvd: [0; 2],
471 }
472 }
473}
474
475impl fuse_open_out {
476 pub fn new(fh: u64, open_flags: u32) -> Self {
478 Self {
479 fh,
480 open_flags,
481 padding: 0,
482 }
483 }
484}
485
486impl fuse_kstatfs {
487 pub fn new(
489 blocks: u64,
490 bfree: u64,
491 bavail: u64,
492 files: u64,
493 ffree: u64,
494 bsize: u32,
495 namelen: u32,
496 frsize: u32,
497 ) -> Self {
498 Self {
499 blocks,
500 bfree,
501 bavail,
502 files,
503 ffree,
504 bsize,
505 namelen,
506 frsize,
507 padding: 0,
508 spare: Default::default(),
509 }
510 }
511}