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}