polyfuse/
reply.rs

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/// Attributes about a file.
7#[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    /// Set the inode number.
19    #[inline]
20    pub fn ino(&mut self, ino: u64) {
21        self.attr.ino = ino;
22    }
23
24    /// Set the size of content.
25    #[inline]
26    pub fn size(&mut self, size: u64) {
27        self.attr.size = size;
28    }
29
30    /// Set the permission of the inode.
31    #[inline]
32    pub fn mode(&mut self, mode: u32) {
33        self.attr.mode = mode;
34    }
35
36    /// Set the number of hard links.
37    #[inline]
38    pub fn nlink(&mut self, nlink: u32) {
39        self.attr.nlink = nlink;
40    }
41
42    /// Set the user ID.
43    #[inline]
44    pub fn uid(&mut self, uid: u32) {
45        self.attr.uid = uid;
46    }
47
48    /// Set the group ID.
49    #[inline]
50    pub fn gid(&mut self, gid: u32) {
51        self.attr.gid = gid;
52    }
53
54    /// Set the device ID.
55    #[inline]
56    pub fn rdev(&mut self, rdev: u32) {
57        self.attr.rdev = rdev;
58    }
59
60    /// Set the block size.
61    #[inline]
62    pub fn blksize(&mut self, blksize: u32) {
63        self.attr.blksize = blksize;
64    }
65
66    /// Set the number of allocated blocks.
67    #[inline]
68    pub fn blocks(&mut self, blocks: u64) {
69        self.attr.blocks = blocks;
70    }
71
72    /// Set the last accessed time.
73    #[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    /// Set the last modification time.
80    #[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    /// Set the last created time.
87    #[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        // TODO: add fields.
102        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    /// Return the object to fill attribute values about this entry.
125    #[inline]
126    pub fn attr(&mut self) -> &mut FileAttr {
127        FileAttr::from_attr_mut(&mut self.out.attr)
128    }
129
130    /// Set the inode number of this entry.
131    ///
132    /// If this value is zero, it means that the entry is *negative*.
133    /// Returning a negative entry is also possible with the `ENOENT` error,
134    /// but the *zeroed* entries also have the ability to specify the lifetime
135    /// of the entry cache by using the `ttl_entry` parameter.
136    #[inline]
137    pub fn ino(&mut self, ino: u64) {
138        self.out.nodeid = ino;
139    }
140
141    /// Set the generation of this entry.
142    ///
143    /// This parameter is used to distinguish the inode from the past one
144    /// when the filesystem reuse inode numbers.  That is, the operations
145    /// must ensure that the pair of entry's inode number and generation
146    /// are unique for the lifetime of the filesystem.
147    pub fn generation(&mut self, generation: u64) {
148        self.out.generation = generation;
149    }
150
151    /// Set the validity timeout for inode attributes.
152    ///
153    /// The operations should set this value to very large
154    /// when the changes of inode attributes are caused
155    /// only by FUSE requests.
156    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    /// Set the validity timeout for the name.
162    ///
163    /// The operations should set this value to very large
164    /// when the changes/deletions of directory entries are
165    /// caused only by FUSE requests.
166    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        // TODO: add fields.
180        f.debug_struct("AttrOut").finish()
181    }
182}
183
184impl AttrOut {
185    /// Return the object to fill attribute values.
186    #[inline]
187    pub fn attr(&mut self) -> &mut FileAttr {
188        FileAttr::from_attr_mut(&mut self.out.attr)
189    }
190
191    /// Set the validity timeout for this attribute.
192    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        // TODO: add fields.
223        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    /// Set the handle of opened file.
246    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    /// Indicates that the direct I/O is used on this file.
260    pub fn direct_io(&mut self, enabled: bool) {
261        self.set_flag(FOPEN_DIRECT_IO, enabled);
262    }
263
264    /// Indicates that the currently cached file data in the kernel
265    /// need not be invalidated.
266    pub fn keep_cache(&mut self, enabled: bool) {
267        self.set_flag(FOPEN_KEEP_CACHE, enabled);
268    }
269
270    /// Indicates that the opened file is not seekable.
271    pub fn nonseekable(&mut self, enabled: bool) {
272        self.set_flag(FOPEN_NONSEEKABLE, enabled);
273    }
274
275    /// Enable caching of entries returned by `readdir`.
276    ///
277    /// This flag is meaningful only for `opendir` operations.
278    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        // TODO: add fields.
291        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        // TODO: add fields.
326        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    /// Return the object to fill the filesystem statistics.
349    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    /// Set the block size.
366    pub fn bsize(&mut self, bsize: u32) {
367        self.st.bsize = bsize;
368    }
369
370    /// Set the fragment size.
371    pub fn frsize(&mut self, frsize: u32) {
372        self.st.frsize = frsize;
373    }
374
375    /// Set the number of blocks in the filesystem.
376    pub fn blocks(&mut self, blocks: u64) {
377        self.st.blocks = blocks;
378    }
379
380    /// Set the number of free blocks.
381    pub fn bfree(&mut self, bfree: u64) {
382        self.st.bfree = bfree;
383    }
384
385    /// Set the number of free blocks for non-priviledge users.
386    pub fn bavail(&mut self, bavail: u64) {
387        self.st.bavail = bavail;
388    }
389
390    /// Set the number of inodes.
391    pub fn files(&mut self, files: u64) {
392        self.st.files = files;
393    }
394
395    /// Set the number of free inodes.
396    pub fn ffree(&mut self, ffree: u64) {
397        self.st.ffree = ffree;
398    }
399
400    /// Set the maximum length of file names.
401    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        // TODO: add fields.
414        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        // TODO: add fields.
449        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    /// Set the type of this lock.
488    pub fn typ(&mut self, typ: u32) {
489        self.lk.typ = typ;
490    }
491
492    /// Set the starting offset to be locked.
493    pub fn start(&mut self, start: u64) {
494        self.lk.start = start;
495    }
496
497    /// Set the ending offset to be locked.
498    pub fn end(&mut self, end: u64) {
499        self.lk.end = end;
500    }
501
502    /// Set the process ID.
503    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        // TODO: add fields.
516        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        // TODO: add fields.
551        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        // TODO: add fields.
585        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}