1use crate::bytes::{Bytes, FillBytes};
2use polyfuse_kernel::*;
3use std::{convert::TryInto as _, ffi::OsStr, fmt, mem, os::unix::prelude::*, time::Duration};
4use zerocopy::IntoBytes as _;
5
6#[repr(transparent)]
8pub struct FileAttr {
9 attr: fuse_attr,
10}
11
12impl FileAttr {
13 #[inline]
14 fn from_attr_mut(attr: &mut fuse_attr) -> &mut FileAttr {
15 unsafe { &mut *(attr as *mut fuse_attr as *mut FileAttr) }
16 }
17
18 #[inline]
20 pub fn ino(&mut self, ino: u64) {
21 self.attr.ino = ino;
22 }
23
24 #[inline]
26 pub fn size(&mut self, size: u64) {
27 self.attr.size = size;
28 }
29
30 #[inline]
32 pub fn mode(&mut self, mode: u32) {
33 self.attr.mode = mode;
34 }
35
36 #[inline]
38 pub fn nlink(&mut self, nlink: u32) {
39 self.attr.nlink = nlink;
40 }
41
42 #[inline]
44 pub fn uid(&mut self, uid: u32) {
45 self.attr.uid = uid;
46 }
47
48 #[inline]
50 pub fn gid(&mut self, gid: u32) {
51 self.attr.gid = gid;
52 }
53
54 #[inline]
56 pub fn rdev(&mut self, rdev: u32) {
57 self.attr.rdev = rdev;
58 }
59
60 #[inline]
62 pub fn blksize(&mut self, blksize: u32) {
63 self.attr.blksize = blksize;
64 }
65
66 #[inline]
68 pub fn blocks(&mut self, blocks: u64) {
69 self.attr.blocks = blocks;
70 }
71
72 #[inline]
74 pub fn atime(&mut self, atime: Duration) {
75 self.attr.atime = atime.as_secs();
76 self.attr.atimensec = atime.subsec_nanos();
77 }
78
79 #[inline]
81 pub fn mtime(&mut self, mtime: Duration) {
82 self.attr.mtime = mtime.as_secs();
83 self.attr.mtimensec = mtime.subsec_nanos();
84 }
85
86 #[inline]
88 pub fn ctime(&mut self, ctime: Duration) {
89 self.attr.ctime = ctime.as_secs();
90 self.attr.ctimensec = ctime.subsec_nanos();
91 }
92}
93
94#[derive(Default)]
95pub struct EntryOut {
96 out: fuse_entry_out,
97}
98
99impl fmt::Debug for EntryOut {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 f.debug_struct("EntryOut").finish()
103 }
104}
105
106impl Bytes for EntryOut {
107 #[inline]
108 fn size(&self) -> usize {
109 self.out.as_bytes().len()
110 }
111
112 #[inline]
113 fn count(&self) -> usize {
114 1
115 }
116
117 #[inline]
118 fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
119 dst.put(self.out.as_bytes());
120 }
121}
122
123impl EntryOut {
124 #[inline]
126 pub fn attr(&mut self) -> &mut FileAttr {
127 FileAttr::from_attr_mut(&mut self.out.attr)
128 }
129
130 #[inline]
137 pub fn ino(&mut self, ino: u64) {
138 self.out.nodeid = ino;
139 }
140
141 pub fn generation(&mut self, generation: u64) {
148 self.out.generation = generation;
149 }
150
151 pub fn ttl_attr(&mut self, ttl: Duration) {
157 self.out.attr_valid = ttl.as_secs();
158 self.out.attr_valid_nsec = ttl.subsec_nanos();
159 }
160
161 pub fn ttl_entry(&mut self, ttl: Duration) {
167 self.out.entry_valid = ttl.as_secs();
168 self.out.entry_valid_nsec = ttl.subsec_nanos();
169 }
170}
171
172#[derive(Default)]
173pub struct AttrOut {
174 out: fuse_attr_out,
175}
176
177impl fmt::Debug for AttrOut {
178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179 f.debug_struct("AttrOut").finish()
181 }
182}
183
184impl AttrOut {
185 #[inline]
187 pub fn attr(&mut self) -> &mut FileAttr {
188 FileAttr::from_attr_mut(&mut self.out.attr)
189 }
190
191 pub fn ttl(&mut self, ttl: Duration) {
193 self.out.attr_valid = ttl.as_secs();
194 self.out.attr_valid_nsec = ttl.subsec_nanos();
195 }
196}
197
198impl Bytes for AttrOut {
199 #[inline]
200 fn size(&self) -> usize {
201 self.out.as_bytes().len()
202 }
203
204 #[inline]
205 fn count(&self) -> usize {
206 1
207 }
208
209 #[inline]
210 fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
211 dst.put(self.out.as_bytes());
212 }
213}
214
215#[derive(Default)]
216pub struct OpenOut {
217 out: fuse_open_out,
218}
219
220impl fmt::Debug for OpenOut {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 f.debug_struct("OpenOut").finish()
224 }
225}
226
227impl Bytes for OpenOut {
228 #[inline]
229 fn size(&self) -> usize {
230 self.out.as_bytes().len()
231 }
232
233 #[inline]
234 fn count(&self) -> usize {
235 1
236 }
237
238 #[inline]
239 fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
240 dst.put(self.out.as_bytes());
241 }
242}
243
244impl OpenOut {
245 pub fn fh(&mut self, fh: u64) {
247 self.out.fh = fh;
248 }
249
250 #[inline]
251 fn set_flag(&mut self, flag: u32, enabled: bool) {
252 if enabled {
253 self.out.open_flags |= flag;
254 } else {
255 self.out.open_flags &= !flag;
256 }
257 }
258
259 pub fn direct_io(&mut self, enabled: bool) {
261 self.set_flag(FOPEN_DIRECT_IO, enabled);
262 }
263
264 pub fn keep_cache(&mut self, enabled: bool) {
267 self.set_flag(FOPEN_KEEP_CACHE, enabled);
268 }
269
270 pub fn nonseekable(&mut self, enabled: bool) {
272 self.set_flag(FOPEN_NONSEEKABLE, enabled);
273 }
274
275 pub fn cache_dir(&mut self, enabled: bool) {
279 self.set_flag(FOPEN_CACHE_DIR, enabled);
280 }
281}
282
283#[derive(Default)]
284pub struct WriteOut {
285 out: fuse_write_out,
286}
287
288impl fmt::Debug for WriteOut {
289 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290 f.debug_struct("WriteOut").finish()
292 }
293}
294
295impl Bytes for WriteOut {
296 #[inline]
297 fn size(&self) -> usize {
298 self.out.as_bytes().len()
299 }
300
301 #[inline]
302 fn count(&self) -> usize {
303 1
304 }
305
306 #[inline]
307 fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
308 dst.put(self.out.as_bytes());
309 }
310}
311
312impl WriteOut {
313 pub fn size(&mut self, size: u32) {
314 self.out.size = size;
315 }
316}
317
318#[derive(Default)]
319pub struct StatfsOut {
320 out: fuse_statfs_out,
321}
322
323impl fmt::Debug for StatfsOut {
324 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
325 f.debug_struct("StatfsOut").finish()
327 }
328}
329
330impl Bytes for StatfsOut {
331 #[inline]
332 fn size(&self) -> usize {
333 self.out.as_bytes().len()
334 }
335
336 #[inline]
337 fn count(&self) -> usize {
338 1
339 }
340
341 #[inline]
342 fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
343 dst.put(self.out.as_bytes());
344 }
345}
346
347impl StatfsOut {
348 pub fn statfs(&mut self) -> &mut Statfs {
350 Statfs::from_kstatfs_mut(&mut self.out.st)
351 }
352}
353
354#[derive(Default)]
355pub struct Statfs {
356 st: fuse_kstatfs,
357}
358
359impl Statfs {
360 #[inline]
361 fn from_kstatfs_mut(st: &mut fuse_kstatfs) -> &mut Statfs {
362 unsafe { &mut *(st as *mut fuse_kstatfs as *mut Statfs) }
363 }
364
365 pub fn bsize(&mut self, bsize: u32) {
367 self.st.bsize = bsize;
368 }
369
370 pub fn frsize(&mut self, frsize: u32) {
372 self.st.frsize = frsize;
373 }
374
375 pub fn blocks(&mut self, blocks: u64) {
377 self.st.blocks = blocks;
378 }
379
380 pub fn bfree(&mut self, bfree: u64) {
382 self.st.bfree = bfree;
383 }
384
385 pub fn bavail(&mut self, bavail: u64) {
387 self.st.bavail = bavail;
388 }
389
390 pub fn files(&mut self, files: u64) {
392 self.st.files = files;
393 }
394
395 pub fn ffree(&mut self, ffree: u64) {
397 self.st.ffree = ffree;
398 }
399
400 pub fn namelen(&mut self, namelen: u32) {
402 self.st.namelen = namelen;
403 }
404}
405
406#[derive(Default)]
407pub struct XattrOut {
408 out: fuse_getxattr_out,
409}
410
411impl fmt::Debug for XattrOut {
412 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
413 f.debug_struct("XattrOut").finish()
415 }
416}
417
418impl Bytes for XattrOut {
419 #[inline]
420 fn size(&self) -> usize {
421 self.out.as_bytes().len()
422 }
423
424 #[inline]
425 fn count(&self) -> usize {
426 1
427 }
428
429 #[inline]
430 fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
431 dst.put(self.out.as_bytes());
432 }
433}
434
435impl XattrOut {
436 pub fn size(&mut self, size: u32) {
437 self.out.size = size;
438 }
439}
440
441#[derive(Default)]
442pub struct LkOut {
443 out: fuse_lk_out,
444}
445
446impl fmt::Debug for LkOut {
447 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 f.debug_struct("LkOut").finish()
450 }
451}
452
453impl Bytes for LkOut {
454 #[inline]
455 fn size(&self) -> usize {
456 self.out.as_bytes().len()
457 }
458
459 #[inline]
460 fn count(&self) -> usize {
461 1
462 }
463
464 #[inline]
465 fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
466 dst.put(self.out.as_bytes());
467 }
468}
469
470impl LkOut {
471 pub fn file_lock(&mut self) -> &mut FileLock {
472 FileLock::from_file_lock_mut(&mut self.out.lk)
473 }
474}
475
476#[repr(transparent)]
477pub struct FileLock {
478 lk: fuse_file_lock,
479}
480
481impl FileLock {
482 #[inline]
483 fn from_file_lock_mut(lk: &mut fuse_file_lock) -> &mut Self {
484 unsafe { &mut *(lk as *mut fuse_file_lock as *mut Self) }
485 }
486
487 pub fn typ(&mut self, typ: u32) {
489 self.lk.typ = typ;
490 }
491
492 pub fn start(&mut self, start: u64) {
494 self.lk.start = start;
495 }
496
497 pub fn end(&mut self, end: u64) {
499 self.lk.end = end;
500 }
501
502 pub fn pid(&mut self, pid: u32) {
504 self.lk.pid = pid;
505 }
506}
507
508#[derive(Default)]
509pub struct BmapOut {
510 out: fuse_bmap_out,
511}
512
513impl fmt::Debug for BmapOut {
514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
515 f.debug_struct("BmapOut").finish()
517 }
518}
519
520impl Bytes for BmapOut {
521 #[inline]
522 fn size(&self) -> usize {
523 self.out.as_bytes().len()
524 }
525
526 #[inline]
527 fn count(&self) -> usize {
528 1
529 }
530
531 #[inline]
532 fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
533 dst.put(self.out.as_bytes());
534 }
535}
536
537impl BmapOut {
538 pub fn block(&mut self, block: u64) {
539 self.out.block = block;
540 }
541}
542
543#[derive(Default)]
544pub struct PollOut {
545 out: fuse_poll_out,
546}
547
548impl fmt::Debug for PollOut {
549 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
550 f.debug_struct("PollOut").finish()
552 }
553}
554
555impl Bytes for PollOut {
556 #[inline]
557 fn size(&self) -> usize {
558 self.out.as_bytes().len()
559 }
560
561 #[inline]
562 fn count(&self) -> usize {
563 1
564 }
565
566 #[inline]
567 fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
568 dst.put(self.out.as_bytes());
569 }
570}
571
572impl PollOut {
573 pub fn revents(&mut self, revents: u32) {
574 self.out.revents = revents;
575 }
576}
577
578pub struct ReaddirOut {
579 buf: Vec<u8>,
580}
581
582impl fmt::Debug for ReaddirOut {
583 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
584 f.debug_struct("ReaddirOut").finish()
586 }
587}
588
589impl Bytes for ReaddirOut {
590 #[inline]
591 fn size(&self) -> usize {
592 self.buf.size()
593 }
594
595 #[inline]
596 fn count(&self) -> usize {
597 self.buf.count()
598 }
599
600 fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
601 self.buf.fill_bytes(dst)
602 }
603}
604
605impl ReaddirOut {
606 pub fn new(capacity: usize) -> Self {
607 Self {
608 buf: Vec::with_capacity(capacity),
609 }
610 }
611
612 pub fn entry(&mut self, name: &OsStr, ino: u64, typ: u32, off: u64) -> bool {
613 let name = name.as_bytes();
614 let remaining = self.buf.capacity() - self.buf.len();
615
616 let entry_size = mem::size_of::<fuse_dirent>() + name.len();
617 let aligned_entry_size = aligned(entry_size);
618
619 if remaining < aligned_entry_size {
620 return true;
621 }
622
623 let dirent = fuse_dirent {
624 ino,
625 off,
626 namelen: name.len().try_into().expect("name length is too long"),
627 typ,
628 name: [],
629 };
630 let lenbefore = self.buf.len();
631 self.buf.extend_from_slice(dirent.as_bytes());
632 self.buf.extend_from_slice(name);
633 self.buf.resize(lenbefore + aligned_entry_size, 0);
634
635 false
636 }
637}
638
639#[inline]
640const fn aligned(len: usize) -> usize {
641 (len + mem::size_of::<u64>() - 1) & !(mem::size_of::<u64>() - 1)
642}