polyfuse/
op.rs

1use crate::decoder::Decoder;
2use polyfuse_kernel::*;
3use std::{convert::TryFrom, ffi::OsStr, fmt, time::Duration, u32, u64};
4
5#[derive(Debug)]
6pub struct DecodeError {
7    inner: crate::decoder::DecodeError,
8}
9
10impl DecodeError {
11    #[inline]
12    const fn new(inner: crate::decoder::DecodeError) -> Self {
13        Self { inner }
14    }
15}
16
17impl fmt::Display for DecodeError {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        write!(f, "failed to decode request message")
20    }
21}
22
23impl std::error::Error for DecodeError {}
24
25/// The kind of filesystem operation requested by the kernel.
26#[non_exhaustive]
27pub enum Operation<'op, T> {
28    Lookup(Lookup<'op>),
29    Getattr(Getattr<'op>),
30    Setattr(Setattr<'op>),
31    Readlink(Readlink<'op>),
32    Symlink(Symlink<'op>),
33    Mknod(Mknod<'op>),
34    Mkdir(Mkdir<'op>),
35    Unlink(Unlink<'op>),
36    Rmdir(Rmdir<'op>),
37    Rename(Rename<'op>),
38    Link(Link<'op>),
39    Open(Open<'op>),
40    Read(Read<'op>),
41    Write(Write<'op>, T),
42    Release(Release<'op>),
43    Statfs(Statfs<'op>),
44    Fsync(Fsync<'op>),
45    Setxattr(Setxattr<'op>),
46    Getxattr(Getxattr<'op>),
47    Listxattr(Listxattr<'op>),
48    Removexattr(Removexattr<'op>),
49    Flush(Flush<'op>),
50    Opendir(Opendir<'op>),
51    Readdir(Readdir<'op>),
52    Releasedir(Releasedir<'op>),
53    Fsyncdir(Fsyncdir<'op>),
54    Getlk(Getlk<'op>),
55    Setlk(Setlk<'op>),
56    Flock(Flock<'op>),
57    Access(Access<'op>),
58    Create(Create<'op>),
59    Bmap(Bmap<'op>),
60    Fallocate(Fallocate<'op>),
61    CopyFileRange(CopyFileRange<'op>),
62    Poll(Poll<'op>),
63
64    Forget(Forgets<'op>),
65    Interrupt(Interrupt<'op>),
66    NotifyReply(NotifyReply<'op>, T),
67
68    #[doc(hidden)]
69    Unknown,
70}
71
72impl<T> fmt::Debug for Operation<'_, T>
73where
74    T: fmt::Debug,
75{
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        match self {
78            Operation::Lookup(op) => op.fmt(f),
79            Operation::Getattr(op) => op.fmt(f),
80            Operation::Setattr(op) => op.fmt(f),
81            Operation::Readlink(op) => op.fmt(f),
82            Operation::Symlink(op) => op.fmt(f),
83            Operation::Mknod(op) => op.fmt(f),
84            Operation::Mkdir(op) => op.fmt(f),
85            Operation::Unlink(op) => op.fmt(f),
86            Operation::Rmdir(op) => op.fmt(f),
87            Operation::Rename(op) => op.fmt(f),
88            Operation::Link(op) => op.fmt(f),
89            Operation::Open(op) => op.fmt(f),
90            Operation::Read(op) => op.fmt(f),
91            Operation::Release(op) => op.fmt(f),
92            Operation::Statfs(op) => op.fmt(f),
93            Operation::Fsync(op) => op.fmt(f),
94            Operation::Setxattr(op) => op.fmt(f),
95            Operation::Getxattr(op) => op.fmt(f),
96            Operation::Listxattr(op) => op.fmt(f),
97            Operation::Removexattr(op) => op.fmt(f),
98            Operation::Flush(op) => op.fmt(f),
99            Operation::Opendir(op) => op.fmt(f),
100            Operation::Readdir(op) => op.fmt(f),
101            Operation::Releasedir(op) => op.fmt(f),
102            Operation::Fsyncdir(op) => op.fmt(f),
103            Operation::Getlk(op) => op.fmt(f),
104            Operation::Setlk(op) => op.fmt(f),
105            Operation::Flock(op) => op.fmt(f),
106            Operation::Access(op) => op.fmt(f),
107            Operation::Create(op) => op.fmt(f),
108            Operation::Bmap(op) => op.fmt(f),
109            Operation::Fallocate(op) => op.fmt(f),
110            Operation::CopyFileRange(op) => op.fmt(f),
111            Operation::Poll(op) => op.fmt(f),
112            Operation::Forget(op) => op.fmt(f),
113            Operation::Interrupt(op) => op.fmt(f),
114
115            Operation::Write(op, data) => f
116                .debug_struct("Write")
117                .field("op", op)
118                .field("data", data)
119                .finish(),
120            Operation::NotifyReply(op, data) => f
121                .debug_struct("NotifyReply")
122                .field("op", op)
123                .field("data", data)
124                .finish(),
125
126            _ => f.debug_struct("Unknown").finish(),
127        }
128    }
129}
130
131impl<'op, T> Operation<'op, T> {
132    #[inline]
133    pub(crate) fn unknown() -> Self {
134        Self::Unknown
135    }
136
137    pub(crate) fn decode(
138        header: &'op fuse_in_header,
139        arg: &'op [u8],
140        data: T,
141    ) -> Result<Self, DecodeError> {
142        let mut decoder = Decoder::new(arg);
143
144        match fuse_opcode::try_from(header.opcode).ok() {
145            Some(fuse_opcode::FUSE_FORGET) => {
146                let arg: &fuse_forget_in = decoder.fetch().map_err(DecodeError::new)?;
147                let forget = fuse_forget_one {
148                    nodeid: header.nodeid,
149                    nlookup: arg.nlookup,
150                };
151                Ok(Operation::Forget(Forgets {
152                    inner: ForgetsInner::Single(forget),
153                }))
154            }
155            Some(fuse_opcode::FUSE_BATCH_FORGET) => {
156                let arg: &fuse_batch_forget_in = decoder.fetch().map_err(DecodeError::new)?;
157                let forgets = decoder
158                    .fetch_array::<fuse_forget_one>(arg.count as usize)
159                    .map_err(DecodeError::new)?;
160                Ok(Operation::Forget(Forgets {
161                    inner: ForgetsInner::Batch(forgets),
162                }))
163            }
164
165            Some(fuse_opcode::FUSE_INTERRUPT) => {
166                let arg = decoder.fetch().map_err(DecodeError::new)?;
167                Ok(Operation::Interrupt(Interrupt { header, arg }))
168            }
169
170            Some(fuse_opcode::FUSE_NOTIFY_REPLY) => {
171                let arg = decoder.fetch().map_err(DecodeError::new)?;
172                Ok(Operation::NotifyReply(NotifyReply { header, arg }, data))
173            }
174
175            Some(fuse_opcode::FUSE_LOOKUP) => {
176                let name = decoder.fetch_str().map_err(DecodeError::new)?;
177                Ok(Operation::Lookup(Lookup { header, name }))
178            }
179
180            Some(fuse_opcode::FUSE_GETATTR) => {
181                let arg = decoder.fetch().map_err(DecodeError::new)?;
182                Ok(Operation::Getattr(Getattr { header, arg }))
183            }
184
185            Some(fuse_opcode::FUSE_SETATTR) => {
186                let arg = decoder.fetch().map_err(DecodeError::new)?;
187                Ok(Operation::Setattr(Setattr { header, arg }))
188            }
189
190            Some(fuse_opcode::FUSE_READLINK) => Ok(Operation::Readlink(Readlink { header })),
191
192            Some(fuse_opcode::FUSE_SYMLINK) => {
193                let name = decoder.fetch_str().map_err(DecodeError::new)?;
194                let link = decoder.fetch_str().map_err(DecodeError::new)?;
195                Ok(Operation::Symlink(Symlink { header, name, link }))
196            }
197
198            Some(fuse_opcode::FUSE_MKNOD) => {
199                let arg = decoder.fetch().map_err(DecodeError::new)?;
200                let name = decoder.fetch_str().map_err(DecodeError::new)?;
201                Ok(Operation::Mknod(Mknod { header, arg, name }))
202            }
203
204            Some(fuse_opcode::FUSE_MKDIR) => {
205                let arg = decoder.fetch().map_err(DecodeError::new)?;
206                let name = decoder.fetch_str().map_err(DecodeError::new)?;
207                Ok(Operation::Mkdir(Mkdir { header, arg, name }))
208            }
209
210            Some(fuse_opcode::FUSE_UNLINK) => {
211                let name = decoder.fetch_str().map_err(DecodeError::new)?;
212                Ok(Operation::Unlink(Unlink { header, name }))
213            }
214
215            Some(fuse_opcode::FUSE_RMDIR) => {
216                let name = decoder.fetch_str().map_err(DecodeError::new)?;
217                Ok(Operation::Rmdir(Rmdir { header, name }))
218            }
219
220            Some(fuse_opcode::FUSE_RENAME) => {
221                let arg = decoder.fetch().map_err(DecodeError::new)?;
222                let name = decoder.fetch_str().map_err(DecodeError::new)?;
223                let newname = decoder.fetch_str().map_err(DecodeError::new)?;
224                Ok(Operation::Rename(Rename {
225                    header,
226                    arg: RenameArg::V1(arg),
227                    name,
228                    newname,
229                }))
230            }
231            Some(fuse_opcode::FUSE_RENAME2) => {
232                let arg = decoder.fetch().map_err(DecodeError::new)?;
233                let name = decoder.fetch_str().map_err(DecodeError::new)?;
234                let newname = decoder.fetch_str().map_err(DecodeError::new)?;
235                Ok(Operation::Rename(Rename {
236                    header,
237                    arg: RenameArg::V2(arg),
238                    name,
239                    newname,
240                }))
241            }
242
243            Some(fuse_opcode::FUSE_LINK) => {
244                let arg = decoder.fetch().map_err(DecodeError::new)?;
245                let newname = decoder.fetch_str().map_err(DecodeError::new)?;
246                Ok(Operation::Link(Link {
247                    header,
248                    arg,
249                    newname,
250                }))
251            }
252
253            Some(fuse_opcode::FUSE_OPEN) => {
254                let arg = decoder.fetch().map_err(DecodeError::new)?;
255                Ok(Operation::Open(Open { header, arg }))
256            }
257
258            Some(fuse_opcode::FUSE_READ) => {
259                let arg = decoder.fetch().map_err(DecodeError::new)?;
260                Ok(Operation::Read(Read { header, arg }))
261            }
262
263            Some(fuse_opcode::FUSE_WRITE) => {
264                let arg: &fuse_write_in = decoder.fetch().map_err(DecodeError::new)?;
265                Ok(Operation::Write(Write { header, arg }, data))
266            }
267
268            Some(fuse_opcode::FUSE_RELEASE) => {
269                let arg = decoder.fetch().map_err(DecodeError::new)?;
270                Ok(Operation::Release(Release { header, arg }))
271            }
272
273            Some(fuse_opcode::FUSE_STATFS) => Ok(Operation::Statfs(Statfs { header })),
274
275            Some(fuse_opcode::FUSE_FSYNC) => {
276                let arg = decoder.fetch().map_err(DecodeError::new)?;
277                Ok(Operation::Fsync(Fsync { header, arg }))
278            }
279
280            Some(fuse_opcode::FUSE_SETXATTR) => {
281                let arg = decoder
282                    .fetch::<fuse_setxattr_in>()
283                    .map_err(DecodeError::new)?;
284                let name = decoder.fetch_str().map_err(DecodeError::new)?;
285                let value = decoder
286                    .fetch_bytes(arg.size as usize)
287                    .map_err(DecodeError::new)?;
288                Ok(Operation::Setxattr(Setxattr {
289                    header,
290                    arg,
291                    name,
292                    value,
293                }))
294            }
295
296            Some(fuse_opcode::FUSE_GETXATTR) => {
297                let arg: &fuse_getxattr_in = decoder.fetch().map_err(DecodeError::new)?;
298                let name = decoder.fetch_str().map_err(DecodeError::new)?;
299                Ok(Operation::Getxattr(Getxattr { header, arg, name }))
300            }
301
302            Some(fuse_opcode::FUSE_LISTXATTR) => {
303                let arg: &fuse_getxattr_in = decoder.fetch().map_err(DecodeError::new)?;
304                Ok(Operation::Listxattr(Listxattr { header, arg }))
305            }
306
307            Some(fuse_opcode::FUSE_REMOVEXATTR) => {
308                let name = decoder.fetch_str().map_err(DecodeError::new)?;
309                Ok(Operation::Removexattr(Removexattr { header, name }))
310            }
311
312            Some(fuse_opcode::FUSE_FLUSH) => {
313                let arg = decoder.fetch().map_err(DecodeError::new)?;
314                Ok(Operation::Flush(Flush { header, arg }))
315            }
316
317            Some(fuse_opcode::FUSE_OPENDIR) => {
318                let arg = decoder.fetch().map_err(DecodeError::new)?;
319                Ok(Operation::Opendir(Opendir { header, arg }))
320            }
321
322            Some(fuse_opcode::FUSE_READDIR) => {
323                let arg = decoder.fetch().map_err(DecodeError::new)?;
324                Ok(Operation::Readdir(Readdir {
325                    header,
326                    arg,
327                    mode: ReaddirMode::Normal,
328                }))
329            }
330            Some(fuse_opcode::FUSE_READDIRPLUS) => {
331                let arg = decoder.fetch().map_err(DecodeError::new)?;
332                Ok(Operation::Readdir(Readdir {
333                    header,
334                    arg,
335                    mode: ReaddirMode::Plus,
336                }))
337            }
338
339            Some(fuse_opcode::FUSE_RELEASEDIR) => {
340                let arg = decoder.fetch().map_err(DecodeError::new)?;
341                Ok(Operation::Releasedir(Releasedir { header, arg }))
342            }
343
344            Some(fuse_opcode::FUSE_FSYNCDIR) => {
345                let arg = decoder.fetch().map_err(DecodeError::new)?;
346                Ok(Operation::Fsyncdir(Fsyncdir { header, arg }))
347            }
348
349            Some(fuse_opcode::FUSE_GETLK) => {
350                let arg = decoder.fetch().map_err(DecodeError::new)?;
351                Ok(Operation::Getlk(Getlk { header, arg }))
352            }
353
354            Some(opcode @ fuse_opcode::FUSE_SETLK) | Some(opcode @ fuse_opcode::FUSE_SETLKW) => {
355                let arg: &fuse_lk_in = decoder.fetch().map_err(DecodeError::new)?;
356                let sleep = match opcode {
357                    fuse_opcode::FUSE_SETLK => false,
358                    fuse_opcode::FUSE_SETLKW => true,
359                    _ => unreachable!(),
360                };
361
362                if arg.lk_flags & FUSE_LK_FLOCK == 0 {
363                    Ok(Operation::Setlk(Setlk { header, arg, sleep }))
364                } else {
365                    let op = convert_to_flock_op(arg.lk.typ, sleep).unwrap_or(0);
366                    Ok(Operation::Flock(Flock { header, arg, op }))
367                }
368            }
369
370            Some(fuse_opcode::FUSE_ACCESS) => {
371                let arg = decoder.fetch().map_err(DecodeError::new)?;
372                Ok(Operation::Access(Access { header, arg }))
373            }
374
375            Some(fuse_opcode::FUSE_CREATE) => {
376                let arg = decoder.fetch().map_err(DecodeError::new)?;
377                let name = decoder.fetch_str().map_err(DecodeError::new)?;
378                Ok(Operation::Create(Create { header, arg, name }))
379            }
380
381            Some(fuse_opcode::FUSE_BMAP) => {
382                let arg = decoder.fetch().map_err(DecodeError::new)?;
383                Ok(Operation::Bmap(Bmap { header, arg }))
384            }
385
386            Some(fuse_opcode::FUSE_FALLOCATE) => {
387                let arg = decoder.fetch().map_err(DecodeError::new)?;
388                Ok(Operation::Fallocate(Fallocate { header, arg }))
389            }
390
391            Some(fuse_opcode::FUSE_COPY_FILE_RANGE) => {
392                let arg = decoder.fetch().map_err(DecodeError::new)?;
393                Ok(Operation::CopyFileRange(CopyFileRange { header, arg }))
394            }
395
396            Some(fuse_opcode::FUSE_POLL) => {
397                let arg = decoder.fetch().map_err(DecodeError::new)?;
398                Ok(Operation::Poll(Poll { header, arg }))
399            }
400
401            _ => {
402                tracing::warn!("unsupported opcode: {}", header.opcode);
403                Ok(Operation::Unknown)
404            }
405        }
406    }
407}
408
409#[inline]
410fn convert_to_flock_op(lk_type: u32, sleep: bool) -> Option<u32> {
411    const F_RDLCK: u32 = libc::F_RDLCK as u32;
412    const F_WRLCK: u32 = libc::F_WRLCK as u32;
413    const F_UNLCK: u32 = libc::F_UNLCK as u32;
414
415    let mut op = match lk_type {
416        F_RDLCK => libc::LOCK_SH as u32,
417        F_WRLCK => libc::LOCK_EX as u32,
418        F_UNLCK => libc::LOCK_UN as u32,
419        _ => return None,
420    };
421
422    if !sleep {
423        op |= libc::LOCK_NB as u32;
424    }
425    Some(op)
426}
427
428/// The identifier for locking operations.
429#[repr(transparent)]
430#[derive(Copy, Clone, PartialEq, Eq, Hash)]
431pub struct LockOwner(u64);
432
433impl fmt::Debug for LockOwner {
434    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435        write!(f, "LockOwner {{ .. }}")
436    }
437}
438
439impl LockOwner {
440    /// Create a `LockOwner` from the raw value.
441    #[inline]
442    pub const fn from_raw(id: u64) -> Self {
443        Self(id)
444    }
445
446    /// Take the raw value of this identifier.
447    #[inline]
448    pub const fn into_raw(self) -> u64 {
449        self.0
450    }
451}
452
453/// A set of forget information removed from the kernel's internal caches.
454pub struct Forgets<'op> {
455    inner: ForgetsInner<'op>,
456}
457
458impl fmt::Debug for Forgets<'_> {
459    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460        f.debug_set().entries(self.as_ref()).finish()
461    }
462}
463
464enum ForgetsInner<'op> {
465    Single(fuse_forget_one),
466    Batch(&'op [fuse_forget_one]),
467}
468
469impl<'op> std::ops::Deref for Forgets<'op> {
470    type Target = [Forget];
471
472    #[inline]
473    fn deref(&self) -> &Self::Target {
474        let (ptr, len) = match &self.inner {
475            ForgetsInner::Single(forget) => (forget as *const fuse_forget_one, 1),
476            ForgetsInner::Batch(forgets) => (forgets.as_ptr(), forgets.len()),
477        };
478        unsafe {
479            // Safety: Forget has the same layout with fuse_forget_one
480            std::slice::from_raw_parts(ptr as *const Forget, len)
481        }
482    }
483}
484
485/// A forget information.
486#[repr(transparent)]
487pub struct Forget {
488    forget: fuse_forget_one,
489}
490
491impl fmt::Debug for Forget {
492    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493        // TODO: add fields
494        f.debug_struct("Forget").finish()
495    }
496}
497
498impl Forget {
499    /// Return the inode number of the target inode.
500    #[inline]
501    pub fn ino(&self) -> u64 {
502        self.forget.nodeid
503    }
504
505    /// Return the released lookup count of the target inode.
506    #[inline]
507    pub fn nlookup(&self) -> u64 {
508        self.forget.nlookup
509    }
510}
511
512/// A reply to a `NOTIFY_RETRIEVE` notification.
513pub struct NotifyReply<'op> {
514    header: &'op fuse_in_header,
515    arg: &'op fuse_notify_retrieve_in,
516}
517
518impl fmt::Debug for NotifyReply<'_> {
519    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
520        // TODO: add fields
521        f.debug_struct("NotifyReply").finish()
522    }
523}
524
525impl<'op> NotifyReply<'op> {
526    /// Return the unique ID of the corresponding notification message.
527    #[inline]
528    pub fn unique(&self) -> u64 {
529        self.header.unique
530    }
531
532    /// Return the inode number corresponding with the cache data.
533    #[inline]
534    pub fn ino(&self) -> u64 {
535        self.header.nodeid
536    }
537
538    /// Return the starting position of the cache data.
539    #[inline]
540    pub fn offset(&self) -> u64 {
541        self.arg.offset
542    }
543
544    /// Return the length of the retrieved cache data.
545    #[inline]
546    pub fn size(&self) -> u32 {
547        self.arg.size
548    }
549}
550
551/// Interrupt a previous FUSE request.
552pub struct Interrupt<'op> {
553    #[allow(dead_code)]
554    header: &'op fuse_in_header,
555    arg: &'op fuse_interrupt_in,
556}
557
558impl fmt::Debug for Interrupt<'_> {
559    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
560        // TODO: add fields
561        f.debug_struct("Interrupt").finish()
562    }
563}
564
565impl<'op> Interrupt<'op> {
566    /// Return the target unique ID to be interrupted.
567    #[inline]
568    pub fn unique(&self) -> u64 {
569        self.arg.unique
570    }
571}
572
573/// Lookup a directory entry by name.
574///
575/// If a matching entry is found, the filesystem replies to the kernel
576/// with its attribute using `ReplyEntry`.  In addition, the lookup count
577/// of the corresponding inode is incremented on success.
578///
579/// See also the documentation of `ReplyEntry` for tuning the reply parameters.
580pub struct Lookup<'op> {
581    header: &'op fuse_in_header,
582    name: &'op OsStr,
583}
584
585impl fmt::Debug for Lookup<'_> {
586    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
587        // TODO: add fields
588        f.debug_struct("Lookup").finish()
589    }
590}
591
592impl<'op> Lookup<'op> {
593    /// Return the inode number of the parent directory.
594    pub fn parent(&self) -> u64 {
595        self.header.nodeid
596    }
597
598    /// Return the name of the entry to be looked up.
599    pub fn name(&self) -> &OsStr {
600        self.name
601    }
602}
603
604/// Get file attributes.
605///
606/// The obtained attribute values are replied using `ReplyAttr`.
607///
608/// If writeback caching is enabled, the kernel might ignore
609/// some of the attribute values, such as `st_size`.
610pub struct Getattr<'op> {
611    header: &'op fuse_in_header,
612    arg: &'op fuse_getattr_in,
613}
614
615impl fmt::Debug for Getattr<'_> {
616    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
617        // TODO: add fields
618        f.debug_struct("Getattr").finish()
619    }
620}
621
622impl<'op> Getattr<'op> {
623    /// Return the inode number for obtaining the attribute value.
624    pub fn ino(&self) -> u64 {
625        self.header.nodeid
626    }
627
628    /// Return the handle of opened file, if specified.
629    pub fn fh(&self) -> Option<u64> {
630        if self.arg.getattr_flags & FUSE_GETATTR_FH != 0 {
631            Some(self.arg.fh)
632        } else {
633            None
634        }
635    }
636}
637
638/// Set file attributes.
639///
640/// When the setting of attribute values succeeds, the filesystem replies its value
641/// to the kernel using `ReplyAttr`.
642pub struct Setattr<'op> {
643    header: &'op fuse_in_header,
644    arg: &'op fuse_setattr_in,
645}
646
647impl fmt::Debug for Setattr<'_> {
648    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
649        // TODO: add fields
650        f.debug_struct("Setattr").finish()
651    }
652}
653
654impl<'op> Setattr<'op> {
655    #[inline(always)]
656    fn get<R>(&self, flag: u32, f: impl FnOnce(&fuse_setattr_in) -> R) -> Option<R> {
657        if self.arg.valid & flag != 0 {
658            Some(f(&self.arg))
659        } else {
660            None
661        }
662    }
663
664    /// Return the inode number to be set the attribute values.
665    pub fn ino(&self) -> u64 {
666        self.header.nodeid
667    }
668
669    /// Return the handle of opened file, if specified.
670    #[inline]
671    pub fn fh(&self) -> Option<u64> {
672        self.get(FATTR_FH, |arg| arg.fh)
673    }
674
675    /// Return the file mode to be set.
676    #[inline]
677    pub fn mode(&self) -> Option<u32> {
678        self.get(FATTR_MODE, |arg| arg.mode)
679    }
680
681    /// Return the user id to be set.
682    #[inline]
683    pub fn uid(&self) -> Option<u32> {
684        self.get(FATTR_UID, |arg| arg.uid)
685    }
686
687    /// Return the group id to be set.
688    #[inline]
689    pub fn gid(&self) -> Option<u32> {
690        self.get(FATTR_GID, |arg| arg.gid)
691    }
692
693    /// Return the size of the file content to be set.
694    #[inline]
695    pub fn size(&self) -> Option<u64> {
696        self.get(FATTR_SIZE, |arg| arg.size)
697    }
698
699    /// Return the last accessed time to be set.
700    #[inline]
701    pub fn atime(&self) -> Option<SetAttrTime> {
702        self.get(FATTR_ATIME, |arg| {
703            if arg.valid & FATTR_ATIME_NOW != 0 {
704                SetAttrTime::Now
705            } else {
706                SetAttrTime::Timespec(Duration::new(arg.atime, arg.atimensec))
707            }
708        })
709    }
710
711    /// Return the last modified time to be set.
712    #[inline]
713    pub fn mtime(&self) -> Option<SetAttrTime> {
714        self.get(FATTR_MTIME, |arg| {
715            if arg.valid & FATTR_MTIME_NOW != 0 {
716                SetAttrTime::Now
717            } else {
718                SetAttrTime::Timespec(Duration::new(arg.mtime, arg.mtimensec))
719            }
720        })
721    }
722
723    /// Return the last creation time to be set.
724    #[inline]
725    pub fn ctime(&self) -> Option<Duration> {
726        self.get(FATTR_CTIME, |arg| Duration::new(arg.ctime, arg.ctimensec))
727    }
728
729    /// Return the identifier of lock owner.
730    #[inline]
731    pub fn lock_owner(&self) -> Option<LockOwner> {
732        self.get(FATTR_LOCKOWNER, |arg| LockOwner::from_raw(arg.lock_owner))
733    }
734}
735
736/// The time value requested to be set.
737#[derive(Copy, Clone, Debug)]
738#[non_exhaustive]
739pub enum SetAttrTime {
740    /// Set the specified time value.
741    Timespec(Duration),
742
743    /// Set the current time.
744    Now,
745}
746
747/// Read a symbolic link.
748pub struct Readlink<'op> {
749    header: &'op fuse_in_header,
750}
751
752impl fmt::Debug for Readlink<'_> {
753    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
754        // TODO: add fields
755        f.debug_struct("Readlink").finish()
756    }
757}
758
759impl<'op> Readlink<'op> {
760    /// Return the inode number to be read the link value.
761    #[inline]
762    pub fn ino(&self) -> u64 {
763        self.header.nodeid
764    }
765}
766
767/// Create a symbolic link.
768///
769/// When the link is successfully created, the filesystem must send
770/// its attribute values using `ReplyEntry`.
771pub struct Symlink<'op> {
772    header: &'op fuse_in_header,
773    name: &'op OsStr,
774    link: &'op OsStr,
775}
776
777impl fmt::Debug for Symlink<'_> {
778    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
779        // TODO: add fields
780        f.debug_struct("Symlink").finish()
781    }
782}
783
784impl<'op> Symlink<'op> {
785    /// Return the inode number of the parent directory.
786    #[inline]
787    pub fn parent(&self) -> u64 {
788        self.header.nodeid
789    }
790
791    /// Return the name of the symbolic link to create.
792    #[inline]
793    pub fn name(&self) -> &OsStr {
794        self.name
795    }
796
797    /// Return the contents of the symbolic link.
798    #[inline]
799    pub fn link(&self) -> &OsStr {
800        self.link
801    }
802}
803
804/// Create a file node.
805///
806/// When the file node is successfully created, the filesystem must send
807/// its attribute values using `ReplyEntry`.
808pub struct Mknod<'op> {
809    header: &'op fuse_in_header,
810    arg: &'op fuse_mknod_in,
811    name: &'op OsStr,
812}
813
814impl fmt::Debug for Mknod<'_> {
815    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
816        // TODO: add fields
817        f.debug_struct("Mknod").finish()
818    }
819}
820
821impl<'op> Mknod<'op> {
822    /// Return the inode number of the parent directory.
823    #[inline]
824    pub fn parent(&self) -> u64 {
825        self.header.nodeid
826    }
827
828    /// Return the file name to create.
829    #[inline]
830    pub fn name(&self) -> &OsStr {
831        self.name
832    }
833
834    /// Return the file type and permissions used when creating the new file.
835    #[inline]
836    pub fn mode(&self) -> u32 {
837        self.arg.mode
838    }
839
840    /// Return the device number for special file.
841    ///
842    /// This value is meaningful only if the created node is a device file
843    /// (i.e. the file type is specified either `S_IFCHR` or `S_IFBLK`).
844    #[inline]
845    pub fn rdev(&self) -> u32 {
846        self.arg.rdev
847    }
848
849    #[doc(hidden)] // TODO: dox
850    pub fn umask(&self) -> u32 {
851        self.arg.umask
852    }
853}
854
855/// Create a directory node.
856///
857/// When the directory is successfully created, the filesystem must send
858/// its attribute values using `ReplyEntry`.
859pub struct Mkdir<'op> {
860    header: &'op fuse_in_header,
861    arg: &'op fuse_mkdir_in,
862    name: &'op OsStr,
863}
864
865impl fmt::Debug for Mkdir<'_> {
866    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
867        // TODO: add fields
868        f.debug_struct("Mkdir").finish()
869    }
870}
871
872impl<'op> Mkdir<'op> {
873    /// Return the inode number of the parent directory where the directory is created.
874    #[inline]
875    pub fn parent(&self) -> u64 {
876        self.header.nodeid
877    }
878
879    /// Return the name of the directory to be created.
880    #[inline]
881    pub fn name(&self) -> &OsStr {
882        self.name
883    }
884
885    /// Return the file type and permissions used when creating the new directory.
886    #[inline]
887    pub fn mode(&self) -> u32 {
888        self.arg.mode
889    }
890
891    #[doc(hidden)] // TODO: dox
892    pub fn umask(&self) -> u32 {
893        self.arg.umask
894    }
895}
896
897// TODO: description about lookup count.
898
899/// Remove a file.
900pub struct Unlink<'op> {
901    header: &'op fuse_in_header,
902    name: &'op OsStr,
903}
904
905impl fmt::Debug for Unlink<'_> {
906    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
907        // TODO: add fields
908        f.debug_struct("Unlink").finish()
909    }
910}
911
912impl<'op> Unlink<'op> {
913    /// Return the inode number of the parent directory.
914    #[inline]
915    pub fn parent(&self) -> u64 {
916        self.header.nodeid
917    }
918
919    /// Return the file name to be removed.
920    #[inline]
921    pub fn name(&self) -> &OsStr {
922        self.name
923    }
924}
925
926/// Remove a directory.
927pub struct Rmdir<'op> {
928    header: &'op fuse_in_header,
929    name: &'op OsStr,
930}
931
932impl fmt::Debug for Rmdir<'_> {
933    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
934        // TODO: add fields
935        f.debug_struct("Rmdir").finish()
936    }
937}
938
939impl<'op> Rmdir<'op> {
940    // TODO: description about lookup count.
941
942    /// Return the inode number of the parent directory.
943    #[inline]
944    pub fn parent(&self) -> u64 {
945        self.header.nodeid
946    }
947
948    /// Return the directory name to be removed.
949    #[inline]
950    pub fn name(&self) -> &OsStr {
951        self.name
952    }
953}
954
955/// Rename a file.
956pub struct Rename<'op> {
957    header: &'op fuse_in_header,
958    arg: RenameArg<'op>,
959    name: &'op OsStr,
960    newname: &'op OsStr,
961}
962
963enum RenameArg<'op> {
964    V1(&'op fuse_rename_in),
965    V2(&'op fuse_rename2_in),
966}
967
968impl fmt::Debug for Rename<'_> {
969    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
970        // TODO: add fields
971        f.debug_struct("Rename").finish()
972    }
973}
974
975impl<'op> Rename<'op> {
976    /// Return the inode number of the old parent directory.
977    #[inline]
978    pub fn parent(&self) -> u64 {
979        self.header.nodeid
980    }
981
982    /// Return the old name of the target node.
983    #[inline]
984    pub fn name(&self) -> &OsStr {
985        self.name
986    }
987
988    /// Return the inode number of the new parent directory.
989    #[inline]
990    pub fn newparent(&self) -> u64 {
991        match self.arg {
992            RenameArg::V1(arg) => arg.newdir,
993            RenameArg::V2(arg) => arg.newdir,
994        }
995    }
996
997    /// Return the new name of the target node.
998    #[inline]
999    pub fn newname(&self) -> &OsStr {
1000        self.newname
1001    }
1002
1003    /// Return the rename flags.
1004    #[inline]
1005    pub fn flags(&self) -> u32 {
1006        match self.arg {
1007            RenameArg::V1(..) => 0,
1008            RenameArg::V2(arg) => arg.flags,
1009        }
1010    }
1011}
1012
1013/// Create a hard link.
1014///
1015/// When the link is successfully created, the filesystem must send
1016/// its attribute values using `ReplyEntry`.
1017pub struct Link<'op> {
1018    header: &'op fuse_in_header,
1019    arg: &'op fuse_link_in,
1020    newname: &'op OsStr,
1021}
1022
1023impl fmt::Debug for Link<'_> {
1024    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1025        // TODO: add fields
1026        f.debug_struct("Link").finish()
1027    }
1028}
1029
1030impl<'op> Link<'op> {
1031    /// Return the *original* inode number which links to the created hard link.
1032    #[inline]
1033    pub fn ino(&self) -> u64 {
1034        self.arg.oldnodeid
1035    }
1036
1037    /// Return the inode number of the parent directory where the hard link is created.
1038    #[inline]
1039    pub fn newparent(&self) -> u64 {
1040        self.header.nodeid
1041    }
1042
1043    /// Return the name of the hard link to be created.
1044    #[inline]
1045    pub fn newname(&self) -> &OsStr {
1046        self.newname
1047    }
1048}
1049
1050/// Open a file.
1051///
1052/// If the file is successfully opened, the filesystem must send the identifier
1053/// of the opened file handle to the kernel using `ReplyOpen`. This parameter is
1054/// set to a series of requests, such as `read` and `write`, until releasing
1055/// the file, and is able to be utilized as a "pointer" to the state during
1056/// handling the opened file.
1057///
1058/// See also the documentation of `ReplyOpen` for tuning the reply parameters.
1059pub struct Open<'op> {
1060    header: &'op fuse_in_header,
1061    arg: &'op fuse_open_in,
1062}
1063
1064impl fmt::Debug for Open<'_> {
1065    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1066        // TODO: add fields
1067        f.debug_struct("Open").finish()
1068    }
1069}
1070
1071impl<'op> Open<'op> {
1072    // TODO: Description of behavior when writeback caching is enabled.
1073
1074    /// Return the inode number to be opened.
1075    #[inline]
1076    pub fn ino(&self) -> u64 {
1077        self.header.nodeid
1078    }
1079
1080    /// Return the open flags.
1081    ///
1082    /// The creating flags (`O_CREAT`, `O_EXCL` and `O_NOCTTY`) are removed and
1083    /// these flags are handled by the kernel.
1084    ///
1085    /// If the mount option contains `-o default_permissions`, the access mode flags
1086    /// (`O_RDONLY`, `O_WRONLY` and `O_RDWR`) might be handled by the kernel and in that case,
1087    /// these flags are omitted before issuing the request. Otherwise, the filesystem should
1088    /// handle these flags and return an `EACCES` error when provided access mode is
1089    /// invalid.
1090    #[inline]
1091    pub fn flags(&self) -> u32 {
1092        self.arg.flags
1093    }
1094}
1095
1096/// Read data from a file.
1097///
1098/// The total amount of the replied data must be within `size`.
1099///
1100/// When the file is opened in `direct_io` mode, the result replied will be
1101/// reflected in the caller's result of `read` syscall.
1102///
1103/// When the file is not opened in `direct_io` mode (i.e. the page caching is enabled),
1104/// the filesystem should send *exactly* the specified range of file content to the
1105/// kernel. If the length of the passed data is shorter than `size`, the rest of
1106/// the data will be substituted with zeroes.
1107pub struct Read<'op> {
1108    header: &'op fuse_in_header,
1109    arg: &'op fuse_read_in,
1110}
1111
1112impl fmt::Debug for Read<'_> {
1113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1114        // TODO: add fields
1115        f.debug_struct("Read").finish()
1116    }
1117}
1118
1119impl<'op> Read<'op> {
1120    /// Return the inode number to be read.
1121    #[inline]
1122    pub fn ino(&self) -> u64 {
1123        self.header.nodeid
1124    }
1125
1126    /// Return the handle of opened file.
1127    #[inline]
1128    pub fn fh(&self) -> u64 {
1129        self.arg.fh
1130    }
1131
1132    /// Return the starting position of the content to be read.
1133    #[inline]
1134    pub fn offset(&self) -> u64 {
1135        self.arg.offset
1136    }
1137
1138    /// Return the length of the data to be read.
1139    #[inline]
1140    pub fn size(&self) -> u32 {
1141        self.arg.size
1142    }
1143
1144    /// Return the flags specified at opening the file.
1145    #[inline]
1146    pub fn flags(&self) -> u32 {
1147        self.arg.flags
1148    }
1149
1150    /// Return the identifier of lock owner.
1151    #[inline]
1152    pub fn lock_owner(&self) -> Option<LockOwner> {
1153        if self.arg.read_flags & FUSE_READ_LOCKOWNER != 0 {
1154            Some(LockOwner::from_raw(self.arg.lock_owner))
1155        } else {
1156            None
1157        }
1158    }
1159}
1160
1161/// Write data to a file.
1162///
1163/// If the data is successfully written, the filesystem must send the amount of the written
1164/// data using `ReplyWrite`.
1165///
1166/// When the file is opened in `direct_io` mode, the result replied will be reflected
1167/// in the caller's result of `write` syscall.
1168///
1169/// When the file is not opened in `direct_io` mode (i.e. the page caching is enabled),
1170/// the filesystem should receive *exactly* the specified range of file content from the kernel.
1171pub struct Write<'op> {
1172    header: &'op fuse_in_header,
1173    arg: &'op fuse_write_in,
1174}
1175
1176impl fmt::Debug for Write<'_> {
1177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1178        // TODO: add fields
1179        f.debug_struct("Write").finish()
1180    }
1181}
1182
1183impl<'op> Write<'op> {
1184    /// Return the inode number to be written.
1185    #[inline]
1186    pub fn ino(&self) -> u64 {
1187        self.header.nodeid
1188    }
1189
1190    /// Return the handle of opened file.
1191    #[inline]
1192    pub fn fh(&self) -> u64 {
1193        self.arg.fh
1194    }
1195
1196    /// Return the starting position of contents to be written.
1197    #[inline]
1198    pub fn offset(&self) -> u64 {
1199        self.arg.offset
1200    }
1201
1202    /// Return the length of contents to be written.
1203    #[inline]
1204    pub fn size(&self) -> u32 {
1205        self.arg.size
1206    }
1207
1208    /// Return the flags specified at opening the file.
1209    #[inline]
1210    pub fn flags(&self) -> u32 {
1211        self.arg.flags
1212    }
1213
1214    /// Return the identifier of lock owner.
1215    #[inline]
1216    pub fn lock_owner(&self) -> Option<LockOwner> {
1217        if self.arg.write_flags & FUSE_WRITE_LOCKOWNER != 0 {
1218            Some(LockOwner::from_raw(self.arg.lock_owner))
1219        } else {
1220            None
1221        }
1222    }
1223}
1224
1225/// Release an opened file.
1226pub struct Release<'op> {
1227    header: &'op fuse_in_header,
1228    arg: &'op fuse_release_in,
1229}
1230
1231impl fmt::Debug for Release<'_> {
1232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1233        // TODO: add fields
1234        f.debug_struct("Release").finish()
1235    }
1236}
1237
1238impl<'op> Release<'op> {
1239    /// Return the inode number of opened file.
1240    #[inline]
1241    pub fn ino(&self) -> u64 {
1242        self.header.nodeid
1243    }
1244
1245    /// Return the handle of opened file.
1246    #[inline]
1247    pub fn fh(&self) -> u64 {
1248        self.arg.fh
1249    }
1250
1251    /// Return the flags specified at opening the file.
1252    #[inline]
1253    pub fn flags(&self) -> u32 {
1254        self.arg.flags
1255    }
1256
1257    /// Return the identifier of lock owner.
1258    #[inline]
1259    pub fn lock_owner(&self) -> LockOwner {
1260        LockOwner::from_raw(self.arg.lock_owner)
1261    }
1262
1263    /// Return whether the operation indicates a flush.
1264    #[inline]
1265    pub fn flush(&self) -> bool {
1266        self.arg.release_flags & FUSE_RELEASE_FLUSH != 0
1267    }
1268
1269    /// Return whether the `flock` locks for this file should be released.
1270    #[inline]
1271    pub fn flock_release(&self) -> bool {
1272        self.arg.release_flags & FUSE_RELEASE_FLOCK_UNLOCK != 0
1273    }
1274}
1275
1276/// Get the filesystem statistics.
1277///
1278/// The obtained statistics must be sent to the kernel using `ReplyStatfs`.
1279pub struct Statfs<'op> {
1280    header: &'op fuse_in_header,
1281}
1282
1283impl fmt::Debug for Statfs<'_> {
1284    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1285        // TODO: add fields
1286        f.debug_struct("Statfs").finish()
1287    }
1288}
1289
1290impl<'op> Statfs<'op> {
1291    /// Return the inode number or `0` which means "undefined".
1292    #[inline]
1293    pub fn ino(&self) -> u64 {
1294        self.header.nodeid
1295    }
1296}
1297
1298/// Synchronize the file contents.
1299pub struct Fsync<'op> {
1300    header: &'op fuse_in_header,
1301    arg: &'op fuse_fsync_in,
1302}
1303
1304impl fmt::Debug for Fsync<'_> {
1305    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1306        // TODO: add fields
1307        f.debug_struct("Fsync").finish()
1308    }
1309}
1310
1311impl<'op> Fsync<'op> {
1312    /// Return the inode number to be synchronized.
1313    #[inline]
1314    pub fn ino(&self) -> u64 {
1315        self.header.nodeid
1316    }
1317
1318    /// Return the handle of opened file.
1319    #[inline]
1320    pub fn fh(&self) -> u64 {
1321        self.arg.fh
1322    }
1323
1324    /// Return whether to synchronize only the file contents.
1325    ///
1326    /// When this method returns `true`, the metadata does not have to be flushed.
1327    #[inline]
1328    pub fn datasync(&self) -> bool {
1329        self.arg.fsync_flags & FUSE_FSYNC_FDATASYNC != 0
1330    }
1331}
1332
1333/// Set an extended attribute.
1334pub struct Setxattr<'op> {
1335    header: &'op fuse_in_header,
1336    arg: &'op fuse_setxattr_in,
1337    name: &'op OsStr,
1338    value: &'op [u8],
1339}
1340
1341impl fmt::Debug for Setxattr<'_> {
1342    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1343        // TODO: add fields
1344        f.debug_struct("Setxattr").finish()
1345    }
1346}
1347
1348impl<'op> Setxattr<'op> {
1349    /// Return the inode number to set the value of extended attribute.
1350    #[inline]
1351    pub fn ino(&self) -> u64 {
1352        self.header.nodeid
1353    }
1354
1355    /// Return the name of extended attribute to be set.
1356    #[inline]
1357    pub fn name(&self) -> &OsStr {
1358        self.name
1359    }
1360
1361    /// Return the value of extended attribute.
1362    #[inline]
1363    pub fn value(&self) -> &[u8] {
1364        self.value
1365    }
1366
1367    /// Return the flags that specifies the meanings of this operation.
1368    #[inline]
1369    pub fn flags(&self) -> u32 {
1370        self.arg.flags
1371    }
1372}
1373
1374/// Get an extended attribute.
1375///
1376/// This operation needs to switch the reply value according to the
1377/// value of `size`:
1378///
1379/// * When `size` is zero, the filesystem must send the length of the
1380///   attribute value for the specified name using `ReplyXattr`.
1381///
1382/// * Otherwise, returns the attribute value with the specified name.
1383///   The filesystem should send an `ERANGE` error if the specified
1384///   size is too small for the attribute value.
1385pub struct Getxattr<'op> {
1386    header: &'op fuse_in_header,
1387    arg: &'op fuse_getxattr_in,
1388    name: &'op OsStr,
1389}
1390
1391impl fmt::Debug for Getxattr<'_> {
1392    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1393        // TODO: add fields
1394        f.debug_struct("Getxattr").finish()
1395    }
1396}
1397
1398impl<'op> Getxattr<'op> {
1399    /// Return the inode number to be get the extended attribute.
1400    #[inline]
1401    pub fn ino(&self) -> u64 {
1402        self.header.nodeid
1403    }
1404
1405    /// Return the name of the extend attribute.
1406    #[inline]
1407    pub fn name(&self) -> &OsStr {
1408        self.name
1409    }
1410
1411    /// Return the maximum length of the attribute value to be replied.
1412    #[inline]
1413    pub fn size(&self) -> u32 {
1414        self.arg.size
1415    }
1416}
1417
1418/// List extended attribute names.
1419///
1420/// Each element of the attribute names list must be null-terminated.
1421/// As with `Getxattr`, the filesystem must send the data length of the attribute
1422/// names using `ReplyXattr` if `size` is zero.
1423pub struct Listxattr<'op> {
1424    header: &'op fuse_in_header,
1425    arg: &'op fuse_getxattr_in,
1426}
1427
1428impl fmt::Debug for Listxattr<'_> {
1429    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1430        // TODO: add fields
1431        f.debug_struct("Listxattr").finish()
1432    }
1433}
1434
1435impl<'op> Listxattr<'op> {
1436    /// Return the inode number to be obtained the attribute names.
1437    #[inline]
1438    pub fn ino(&self) -> u64 {
1439        self.header.nodeid
1440    }
1441
1442    /// Return the maximum length of the attribute names to be replied.
1443    #[inline]
1444    pub fn size(&self) -> u32 {
1445        self.arg.size
1446    }
1447}
1448
1449/// Remove an extended attribute.
1450pub struct Removexattr<'op> {
1451    header: &'op fuse_in_header,
1452    name: &'op OsStr,
1453}
1454
1455impl fmt::Debug for Removexattr<'_> {
1456    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1457        // TODO: add fields
1458        f.debug_struct("Removexattr").finish()
1459    }
1460}
1461
1462impl<'op> Removexattr<'op> {
1463    /// Return the inode number to remove the extended attribute.
1464    #[inline]
1465    pub fn ino(&self) -> u64 {
1466        self.header.nodeid
1467    }
1468
1469    /// Return the name of extended attribute to be removed.
1470    #[inline]
1471    pub fn name(&self) -> &OsStr {
1472        self.name
1473    }
1474}
1475
1476/// Close a file descriptor.
1477///
1478/// This operation is issued on each `close(2)` syscall
1479/// for a file descriptor.
1480///
1481/// Do not confuse this operation with `Release`.
1482/// Since the file descriptor could be duplicated, the multiple
1483/// flush operations might be issued for one `Open`.
1484/// Also, it is not guaranteed that flush will always be issued
1485/// after some writes.
1486pub struct Flush<'op> {
1487    header: &'op fuse_in_header,
1488    arg: &'op fuse_flush_in,
1489}
1490
1491impl fmt::Debug for Flush<'_> {
1492    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1493        // TODO: add fields
1494        f.debug_struct("Flush").finish()
1495    }
1496}
1497
1498impl<'op> Flush<'op> {
1499    /// Return the inode number of target file.
1500    #[inline]
1501    pub fn ino(&self) -> u64 {
1502        self.header.nodeid
1503    }
1504
1505    /// Return the handle of opened file.
1506    #[inline]
1507    pub fn fh(&self) -> u64 {
1508        self.arg.fh
1509    }
1510
1511    /// Return the identifier of lock owner.
1512    #[inline]
1513    pub fn lock_owner(&self) -> LockOwner {
1514        LockOwner::from_raw(self.arg.lock_owner)
1515    }
1516}
1517
1518/// Open a directory.
1519///
1520/// If the directory is successfully opened, the filesystem must send
1521/// the identifier to the opened directory handle using `ReplyOpen`.
1522pub struct Opendir<'op> {
1523    header: &'op fuse_in_header,
1524    arg: &'op fuse_open_in,
1525}
1526
1527impl fmt::Debug for Opendir<'_> {
1528    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1529        // TODO: add fields
1530        f.debug_struct("Opendir").finish()
1531    }
1532}
1533
1534impl<'op> Opendir<'op> {
1535    /// Return the inode number to be opened.
1536    #[inline]
1537    pub fn ino(&self) -> u64 {
1538        self.header.nodeid
1539    }
1540
1541    /// Return the open flags.
1542    #[inline]
1543    pub fn flags(&self) -> u32 {
1544        self.arg.flags
1545    }
1546}
1547
1548/// Read contents from an opened directory.
1549pub struct Readdir<'op> {
1550    header: &'op fuse_in_header,
1551    arg: &'op fuse_read_in,
1552    mode: ReaddirMode,
1553}
1554
1555#[derive(Clone, Copy, Debug, PartialEq)]
1556pub enum ReaddirMode {
1557    Normal,
1558    Plus,
1559}
1560
1561impl fmt::Debug for Readdir<'_> {
1562    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1563        // TODO: add fields
1564        f.debug_struct("Readdir").finish()
1565    }
1566}
1567
1568impl<'op> Readdir<'op> {
1569    /// Return the inode number to be read.
1570    #[inline]
1571    pub fn ino(&self) -> u64 {
1572        self.header.nodeid
1573    }
1574
1575    /// Return the handle of opened directory.
1576    #[inline]
1577    pub fn fh(&self) -> u64 {
1578        self.arg.fh
1579    }
1580
1581    /// Return the *offset* value to continue reading the directory stream.
1582    #[inline]
1583    pub fn offset(&self) -> u64 {
1584        self.arg.offset
1585    }
1586
1587    /// Return the maximum length of returned data.
1588    #[inline]
1589    pub fn size(&self) -> u32 {
1590        self.arg.size
1591    }
1592
1593    pub fn mode(&self) -> ReaddirMode {
1594        self.mode
1595    }
1596}
1597
1598/// Release an opened directory.
1599pub struct Releasedir<'op> {
1600    header: &'op fuse_in_header,
1601    arg: &'op fuse_release_in,
1602}
1603
1604impl fmt::Debug for Releasedir<'_> {
1605    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1606        // TODO: add fields
1607        f.debug_struct("Releasedir").finish()
1608    }
1609}
1610
1611impl<'op> Releasedir<'op> {
1612    /// Return the inode number of opened directory.
1613    #[inline]
1614    pub fn ino(&self) -> u64 {
1615        self.header.nodeid
1616    }
1617
1618    /// Return the handle of opened directory.
1619    #[inline]
1620    pub fn fh(&self) -> u64 {
1621        self.arg.fh
1622    }
1623
1624    /// Return the flags specified at opening the directory.
1625    #[inline]
1626    pub fn flags(&self) -> u32 {
1627        self.arg.flags
1628    }
1629}
1630
1631/// Synchronize the directory contents.
1632pub struct Fsyncdir<'op> {
1633    header: &'op fuse_in_header,
1634    arg: &'op fuse_fsync_in,
1635}
1636
1637impl fmt::Debug for Fsyncdir<'_> {
1638    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1639        // TODO: add fields
1640        f.debug_struct("Fsyncdir").finish()
1641    }
1642}
1643
1644impl<'op> Fsyncdir<'op> {
1645    /// Return the inode number to be synchronized.
1646    #[inline]
1647    pub fn ino(&self) -> u64 {
1648        self.header.nodeid
1649    }
1650
1651    /// Return the handle of opened directory.
1652    #[inline]
1653    pub fn fh(&self) -> u64 {
1654        self.arg.fh
1655    }
1656
1657    /// Return whether to synchronize only the directory contents.
1658    ///
1659    /// When this method returns `true`, the metadata does not have to be flushed.
1660    #[inline]
1661    pub fn datasync(&self) -> bool {
1662        self.arg.fsync_flags & FUSE_FSYNC_FDATASYNC != 0
1663    }
1664}
1665
1666/// Test for a POSIX file lock.
1667///
1668/// The lock result must be replied using `ReplyLk`.
1669pub struct Getlk<'op> {
1670    header: &'op fuse_in_header,
1671    arg: &'op fuse_lk_in,
1672}
1673
1674impl fmt::Debug for Getlk<'_> {
1675    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1676        // TODO: add fields
1677        f.debug_struct("Getlk").finish()
1678    }
1679}
1680
1681impl<'op> Getlk<'op> {
1682    /// Return the inode number to be tested the lock.
1683    #[inline]
1684    pub fn ino(&self) -> u64 {
1685        self.header.nodeid
1686    }
1687
1688    /// Return the handle of opened file.
1689    #[inline]
1690    pub fn fh(&self) -> u64 {
1691        self.arg.fh
1692    }
1693
1694    /// Return the identifier of lock owner.
1695    #[inline]
1696    pub fn owner(&self) -> LockOwner {
1697        LockOwner::from_raw(self.arg.owner)
1698    }
1699
1700    #[inline]
1701    pub fn typ(&self) -> u32 {
1702        self.arg.lk.typ
1703    }
1704
1705    #[inline]
1706    pub fn start(&self) -> u64 {
1707        self.arg.lk.start
1708    }
1709
1710    #[inline]
1711    pub fn end(&self) -> u64 {
1712        self.arg.lk.end
1713    }
1714
1715    #[inline]
1716    pub fn pid(&self) -> u32 {
1717        self.arg.lk.pid
1718    }
1719}
1720
1721/// Acquire, modify or release a POSIX file lock.
1722pub struct Setlk<'op> {
1723    header: &'op fuse_in_header,
1724    arg: &'op fuse_lk_in,
1725    sleep: bool,
1726}
1727
1728impl fmt::Debug for Setlk<'_> {
1729    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1730        // TODO: add fields
1731        f.debug_struct("Setlk").finish()
1732    }
1733}
1734
1735impl<'op> Setlk<'op> {
1736    /// Return the inode number to be obtained the lock.
1737    #[inline]
1738    pub fn ino(&self) -> u64 {
1739        self.header.nodeid
1740    }
1741
1742    /// Return the handle of opened file.
1743    #[inline]
1744    pub fn fh(&self) -> u64 {
1745        self.arg.fh
1746    }
1747
1748    /// Return the identifier of lock owner.
1749    #[inline]
1750    pub fn owner(&self) -> LockOwner {
1751        LockOwner::from_raw(self.arg.owner)
1752    }
1753
1754    #[inline]
1755    pub fn typ(&self) -> u32 {
1756        self.arg.lk.typ
1757    }
1758
1759    #[inline]
1760    pub fn start(&self) -> u64 {
1761        self.arg.lk.start
1762    }
1763
1764    #[inline]
1765    pub fn end(&self) -> u64 {
1766        self.arg.lk.end
1767    }
1768
1769    #[inline]
1770    pub fn pid(&self) -> u32 {
1771        self.arg.lk.pid
1772    }
1773
1774    /// Return whether the locking operation might sleep until a lock is obtained.
1775    #[inline]
1776    pub fn sleep(&self) -> bool {
1777        self.sleep
1778    }
1779}
1780
1781/// Acquire, modify or release a BSD file lock.
1782pub struct Flock<'op> {
1783    header: &'op fuse_in_header,
1784    arg: &'op fuse_lk_in,
1785    op: u32,
1786}
1787
1788impl fmt::Debug for Flock<'_> {
1789    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1790        // TODO: add fields
1791        f.debug_struct("Flock").finish()
1792    }
1793}
1794
1795impl<'op> Flock<'op> {
1796    /// Return the target inode number.
1797    #[inline]
1798    pub fn ino(&self) -> u64 {
1799        self.header.nodeid
1800    }
1801
1802    /// Return the handle of opened file.
1803    #[inline]
1804    pub fn fh(&self) -> u64 {
1805        self.arg.fh
1806    }
1807
1808    /// Return the identifier of lock owner.
1809    #[inline]
1810    pub fn owner(&self) -> LockOwner {
1811        LockOwner::from_raw(self.arg.owner)
1812    }
1813
1814    /// Return the locking operation.
1815    ///
1816    /// See [`flock(2)`][flock] for details.
1817    ///
1818    /// [flock]: http://man7.org/linux/man-pages/man2/flock.2.html
1819    #[inline]
1820    pub fn op(&self) -> Option<u32> {
1821        Some(self.op)
1822    }
1823}
1824
1825/// Check file access permissions.
1826pub struct Access<'op> {
1827    header: &'op fuse_in_header,
1828    arg: &'op fuse_access_in,
1829}
1830
1831impl fmt::Debug for Access<'_> {
1832    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1833        // TODO: add fields
1834        f.debug_struct("Access").finish()
1835    }
1836}
1837
1838impl<'op> Access<'op> {
1839    /// Return the inode number subject to the access permission check.
1840    #[inline]
1841    pub fn ino(&self) -> u64 {
1842        self.header.nodeid
1843    }
1844
1845    /// Return the requested access mode.
1846    #[inline]
1847    pub fn mask(&self) -> u32 {
1848        self.arg.mask
1849    }
1850}
1851
1852/// Create and open a file.
1853///
1854/// This operation is a combination of `Mknod` and `Open`. If an `ENOSYS` error is returned
1855/// for this operation, those operations will be used instead.
1856///
1857/// If the file is successfully created and opened, a pair of `ReplyEntry` and `ReplyOpen`
1858/// with the corresponding attribute values and the file handle must be sent to the kernel.
1859pub struct Create<'op> {
1860    header: &'op fuse_in_header,
1861    arg: &'op fuse_create_in,
1862    name: &'op OsStr,
1863}
1864
1865impl fmt::Debug for Create<'_> {
1866    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1867        // TODO: add fields
1868        f.debug_struct("Create").finish()
1869    }
1870}
1871
1872impl<'op> Create<'op> {
1873    /// Return the inode number of the parent directory.
1874    ///
1875    /// This is the same as `Mknod::parent`.
1876    #[inline]
1877    pub fn parent(&self) -> u64 {
1878        self.header.nodeid
1879    }
1880
1881    /// Return the file name to crate.
1882    ///
1883    /// This is the same as `Mknod::name`.
1884    #[inline]
1885    pub fn name(&self) -> &OsStr {
1886        self.name
1887    }
1888
1889    /// Return the file type and permissions used when creating the new file.
1890    ///
1891    /// This is the same as `Mknod::mode`.
1892    #[inline]
1893    pub fn mode(&self) -> u32 {
1894        self.arg.mode
1895    }
1896
1897    /// Return the open flags.
1898    ///
1899    /// This is the same as `Open::flags`.
1900    #[inline]
1901    pub fn open_flags(&self) -> u32 {
1902        self.arg.flags
1903    }
1904
1905    #[doc(hidden)] // TODO: dox
1906    #[inline]
1907    pub fn umask(&self) -> u32 {
1908        self.arg.umask
1909    }
1910}
1911
1912/// Map block index within a file to block index within device.
1913///
1914/// The mapping result must be replied using `ReplyBmap`.
1915///
1916/// This operation makes sense only for filesystems that use
1917/// block devices, and is called only when the mount options
1918/// contains `blkdev`.
1919pub struct Bmap<'op> {
1920    header: &'op fuse_in_header,
1921    arg: &'op fuse_bmap_in,
1922}
1923
1924impl fmt::Debug for Bmap<'_> {
1925    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1926        // TODO: add fields
1927        f.debug_struct("Bmap").finish()
1928    }
1929}
1930
1931impl<'op> Bmap<'op> {
1932    /// Return the inode number of the file node to be mapped.
1933    #[inline]
1934    pub fn ino(&self) -> u64 {
1935        self.header.nodeid
1936    }
1937
1938    /// Return the block index to be mapped.
1939    #[inline]
1940    pub fn block(&self) -> u64 {
1941        self.arg.block
1942    }
1943
1944    /// Returns the unit of block index.
1945    #[inline]
1946    pub fn blocksize(&self) -> u32 {
1947        self.arg.blocksize
1948    }
1949}
1950
1951/// Allocate requested space.
1952///
1953/// If this operation is successful, the filesystem shall not report
1954/// the error caused by the lack of free spaces to subsequent write
1955/// requests.
1956pub struct Fallocate<'op> {
1957    header: &'op fuse_in_header,
1958    arg: &'op fuse_fallocate_in,
1959}
1960
1961impl fmt::Debug for Fallocate<'_> {
1962    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1963        // TODO: add fields
1964        f.debug_struct("Fallocate").finish()
1965    }
1966}
1967
1968impl<'op> Fallocate<'op> {
1969    /// Return the number of target inode to be allocated the space.
1970    #[inline]
1971    pub fn ino(&self) -> u64 {
1972        self.header.nodeid
1973    }
1974
1975    /// Return the handle for opened file.
1976    #[inline]
1977    pub fn fh(&self) -> u64 {
1978        self.arg.fh
1979    }
1980
1981    /// Return the starting point of region to be allocated.
1982    #[inline]
1983    pub fn offset(&self) -> u64 {
1984        self.arg.offset
1985    }
1986
1987    /// Return the length of region to be allocated.
1988    #[inline]
1989    pub fn length(&self) -> u64 {
1990        self.arg.length
1991    }
1992
1993    /// Return the mode that specifies how to allocate the region.
1994    ///
1995    /// See [`fallocate(2)`][fallocate] for details.
1996    ///
1997    /// [fallocate]: http://man7.org/linux/man-pages/man2/fallocate.2.html
1998    #[inline]
1999    pub fn mode(&self) -> u32 {
2000        self.arg.mode
2001    }
2002}
2003
2004/// Copy a range of data from an opened file to another.
2005///
2006/// The length of copied data must be replied using `ReplyWrite`.
2007pub struct CopyFileRange<'op> {
2008    header: &'op fuse_in_header,
2009    arg: &'op fuse_copy_file_range_in,
2010}
2011
2012impl fmt::Debug for CopyFileRange<'_> {
2013    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2014        // TODO: add fields
2015        f.debug_struct("CopyFileRange").finish()
2016    }
2017}
2018
2019impl<'op> CopyFileRange<'op> {
2020    /// Return the inode number of source file.
2021    #[inline]
2022    pub fn ino_in(&self) -> u64 {
2023        self.header.nodeid
2024    }
2025
2026    /// Return the file handle of source file.
2027    #[inline]
2028    pub fn fh_in(&self) -> u64 {
2029        self.arg.fh_in
2030    }
2031
2032    /// Return the starting point of source file where the data should be read.
2033    #[inline]
2034    pub fn offset_in(&self) -> u64 {
2035        self.arg.off_in
2036    }
2037
2038    /// Return the inode number of target file.
2039    #[inline]
2040    pub fn ino_out(&self) -> u64 {
2041        self.arg.nodeid_out
2042    }
2043
2044    /// Return the file handle of target file.
2045    #[inline]
2046    pub fn fh_out(&self) -> u64 {
2047        self.arg.fh_out
2048    }
2049
2050    /// Return the starting point of target file where the data should be written.
2051    #[inline]
2052    pub fn offset_out(&self) -> u64 {
2053        self.arg.off_out
2054    }
2055
2056    /// Return the maximum size of data to copy.
2057    #[inline]
2058    pub fn length(&self) -> u64 {
2059        self.arg.len
2060    }
2061
2062    /// Return the flag value for `copy_file_range` syscall.
2063    #[inline]
2064    pub fn flags(&self) -> u64 {
2065        self.arg.flags
2066    }
2067}
2068
2069/// Poll for readiness.
2070///
2071/// The mask of ready poll events must be replied using `ReplyPoll`.
2072pub struct Poll<'op> {
2073    header: &'op fuse_in_header,
2074    arg: &'op fuse_poll_in,
2075}
2076
2077impl fmt::Debug for Poll<'_> {
2078    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2079        f.debug_struct("Poll")
2080            .field("ino", &self.ino())
2081            .field("fh", &self.fh())
2082            .field("events", &self.events())
2083            .field("kh", &self.kh())
2084            .finish()
2085    }
2086}
2087
2088impl<'op> Poll<'op> {
2089    /// Return the inode number to check the I/O readiness.
2090    #[inline]
2091    pub fn ino(&self) -> u64 {
2092        self.header.nodeid
2093    }
2094
2095    /// Return the handle of opened file.
2096    #[inline]
2097    pub fn fh(&self) -> u64 {
2098        self.arg.fh
2099    }
2100
2101    /// Return the requested poll events.
2102    #[inline]
2103    pub fn events(&self) -> u32 {
2104        self.arg.events
2105    }
2106
2107    /// Return the handle to this poll.
2108    ///
2109    /// If the returned value is not `None`, the filesystem should send the notification
2110    /// when the corresponding I/O will be ready.
2111    #[inline]
2112    pub fn kh(&self) -> Option<u64> {
2113        if self.arg.flags & FUSE_POLL_SCHEDULE_NOTIFY != 0 {
2114            Some(self.arg.kh)
2115        } else {
2116            None
2117        }
2118    }
2119}