async_fusex/
fuse_request.rs

1//! The implementation for FUSE request
2
3use std::fmt;
4
5use clippy_utilities::Cast;
6use tracing::debug;
7
8use super::context::ProtoVersion;
9use super::de::{DeserializeError, Deserializer};
10#[cfg(feature = "abi-7-19")]
11use super::protocol::FuseFAllocateIn;
12#[cfg(feature = "abi-7-23")]
13use super::protocol::FuseRename2In;
14use super::protocol::{
15    FuseAccessIn, FuseBMapIn, FuseCopyFileRangeIn, FuseCreateIn, FuseFSyncIn, FuseFlushIn,
16    FuseForgetIn, FuseGetXAttrIn, FuseInHeader, FuseInitIn, FuseInterruptIn, FuseLSeekIn,
17    FuseLinkIn, FuseLockIn, FuseMkDirIn, FuseMkNodIn, FuseOpCode, FuseOpenIn, FuseReadIn,
18    FuseReleaseIn, FuseRenameIn, FuseSetAttrIn, FuseSetXAttrIn, FuseWriteIn,
19};
20#[cfg(feature = "abi-7-16")]
21use super::protocol::{FuseBatchForgetIn, FuseForgetOne};
22#[cfg(feature = "abi-7-11")]
23use super::protocol::{FuseIoCtlIn, FusePollIn};
24
25/// FUSE operation
26#[derive(Debug)]
27pub enum Operation<'a> {
28    /// FUSE_LOOKUP = 1
29    Lookup {
30        /// The directory name to look up
31        name: &'a str,
32    },
33    /// FUSE_FORGET = 2
34    Forget {
35        /// The number of lookups to forget
36        arg: &'a FuseForgetIn,
37    },
38    /// FUSE_GETATTR = 3
39    GetAttr,
40    /// FUSE_SETATTR = 4
41    SetAttr {
42        /// The attributes to be set
43        arg: &'a FuseSetAttrIn,
44    },
45    /// FUSE_READLINK = 5
46    ReadLink,
47    /// FUSE_SYMLINK = 6
48    SymLink {
49        /// The link name to create
50        name: &'a str,
51        /// The contents of the symbolic link
52        link: &'a str,
53    },
54    /// FUSE_MKNOD = 8
55    MkNod {
56        /// The FUSE mknod request
57        arg: &'a FuseMkNodIn,
58        /// The file name to create
59        name: &'a str,
60    },
61    /// FUSE_MKDIR = 9
62    MkDir {
63        /// The FUSE mkdir request input
64        arg: &'a FuseMkDirIn,
65        /// The directory name to create
66        name: &'a str,
67    },
68    /// FUSE_UNLINK = 10
69    Unlink {
70        /// The file name to remove
71        name: &'a str,
72    },
73    /// FUSE_RMDIR = 11
74    RmDir {
75        /// The directory name to remove
76        name: &'a str,
77    },
78    /// FUSE_RENAME = 12
79    Rename {
80        /// The FUSE rename request
81        arg: &'a FuseRenameIn,
82        /// The old name
83        oldname: &'a str,
84        /// The new name
85        newname: &'a str,
86    },
87    /// FUSE_LINK = 13
88    Link {
89        /// The FUSE link request
90        arg: &'a FuseLinkIn,
91        /// The new name
92        name: &'a str,
93    },
94    /// FUSE_OPEN = 14
95    Open {
96        /// The FUSE open request
97        arg: &'a FuseOpenIn,
98    },
99    /// FUSE_READ = 15
100    Read {
101        /// The FUSE read request
102        arg: &'a FuseReadIn,
103    },
104    /// FUSE_WRITE = 16
105    Write {
106        /// The FUSE write request
107        arg: &'a FuseWriteIn,
108        /// The FUSE write request data
109        data: &'a [u8],
110    },
111    /// FUSE_STATFS = 17
112    StatFs,
113    /// FUSE_RELEASE = 18
114    Release {
115        /// The FUSE release request
116        arg: &'a FuseReleaseIn,
117    },
118    /// FUSE_FSYNC = 20
119    FSync {
120        /// The FUSE fsync request
121        arg: &'a FuseFSyncIn,
122    },
123    /// FUSE_SETXATTR = 21
124    SetXAttr {
125        /// The FUSE set extended attribute request
126        arg: &'a FuseSetXAttrIn,
127        /// The extended attribute name
128        name: &'a str,
129        /// The extended attribute value
130        value: &'a [u8],
131    },
132    /// FUSE_GETXATTR = 22
133    GetXAttr {
134        /// The FUSE get extended attribute request
135        arg: &'a FuseGetXAttrIn,
136        /// The extended attribute name
137        name: &'a str,
138    },
139    /// FUSE_LISTXATTR = 23
140    ListXAttr {
141        /// The FUSE list extended attribute request
142        arg: &'a FuseGetXAttrIn,
143    },
144    /// FUSE_REMOVEXATTR = 24
145    RemoveXAttr {
146        /// The name of the extended attribute to remove
147        name: &'a str,
148    },
149    /// FUSE_FLUSH = 25
150    Flush {
151        /// The FUSE flush request
152        arg: &'a FuseFlushIn,
153    },
154    /// FUSE_INIT = 26
155    Init {
156        /// The FUSE init request
157        arg: &'a FuseInitIn,
158    },
159    /// FUSE_OPENDIR = 27
160    OpenDir {
161        /// The FUSE open directory request
162        arg: &'a FuseOpenIn,
163    },
164    /// FUSE_READDIR = 28
165    ReadDir {
166        /// The FUSE read directory request
167        arg: &'a FuseReadIn,
168    },
169    /// FUSE_RELEASEDIR = 29
170    ReleaseDir {
171        /// The FUSE release directory request
172        arg: &'a FuseReleaseIn,
173    },
174    /// FUSE_FSYNCDIR = 30
175    FSyncDir {
176        /// The FUSE fsync directory request
177        arg: &'a FuseFSyncIn,
178    },
179    /// FUSE_GETLK = 31
180    GetLk {
181        /// The FUSE get lock request
182        arg: &'a FuseLockIn,
183    },
184    /// FUSE_SETLK = 32
185    SetLk {
186        /// The FUSE set lock request
187        arg: &'a FuseLockIn,
188    },
189    /// FUSE_SETLKW = 33
190    SetLkW {
191        /// The FUSE set lock wait request
192        arg: &'a FuseLockIn,
193    },
194    /// FUSE_ACCESS = 34
195    Access {
196        /// The FUSE access request
197        arg: &'a FuseAccessIn,
198    },
199    /// FUSE_CREATE = 35
200    Create {
201        /// The FUSE create request
202        arg: &'a FuseCreateIn,
203        /// The file name to create
204        name: &'a str,
205    },
206    /// FUSE_INTERRUPT = 36
207    Interrupt {
208        /// The FUSE interrupt request
209        arg: &'a FuseInterruptIn,
210    },
211    /// FUSE_BMAP = 37
212    BMap {
213        /// The FUSE bmap request
214        arg: &'a FuseBMapIn,
215    },
216    /// FUSE_DESTROY = 38
217    Destroy,
218    /// FUSE_IOCTL = 39
219    #[cfg(feature = "abi-7-11")]
220    IoCtl {
221        /// The FUSE ioctl request
222        arg: &'a FuseIoCtlIn,
223        /// The ioctl request data
224        data: &'a [u8],
225    },
226    /// FUSE_POLL = 40
227    #[cfg(feature = "abi-7-11")]
228    Poll {
229        /// The FUSE poll request
230        arg: &'a FusePollIn,
231    },
232    /// FUSE_NOTIFY_REPLY = 41
233    #[cfg(feature = "abi-7-15")]
234    NotifyReply {
235        /// FUSE notify reply data
236        data: &'a [u8],
237    },
238    /// FUSE_BATCH_FORGET = 42
239    #[cfg(feature = "abi-7-16")]
240    BatchForget {
241        /// The FUSE batch forget request
242        arg: &'a FuseBatchForgetIn,
243        /// The slice of nodes to forget
244        nodes: &'a [FuseForgetOne],
245    },
246    /// FUSE_FALLOCATE = 43
247    #[cfg(feature = "abi-7-19")]
248    FAllocate {
249        /// The FUSE fallocate request
250        arg: &'a FuseFAllocateIn,
251    },
252    /// FUSE_READDIRPLUS = 44,
253    #[cfg(feature = "abi-7-21")]
254    ReadDirPlus {
255        /// The FUSE read directory plus request
256        arg: &'a FuseReadIn,
257    },
258    /// FUSE_RENAME2 = 45,
259    ///
260    /// Available when the protocol version is greater than 7.22.
261    /// This is checked by the kernel so that won't receive such a
262    /// request.
263    ///
264    /// https://github.com/torvalds/linux/blob/8f6f76a6a29f36d2f3e4510d0bde5046672f6924/fs/fuse/dir.c#L1077C2-L1088C3
265    #[cfg(feature = "abi-7-23")]
266    Rename2 {
267        /// The FUSE rename2 request
268        arg: &'a FuseRename2In,
269        /// The old file name
270        oldname: &'a str,
271        /// The new file name
272        newname: &'a str,
273    },
274    /// FUSE_LSEEK = 46,
275    // #[cfg(feature = "abi-7-24")]
276    LSeek {
277        /// The FUSE lseek request
278        arg: &'a FuseLSeekIn,
279    },
280    /// FUSE_COPY_FILE_RANGE = 47,
281    // #[cfg(feature = "abi-7-28")]
282    CopyFileRange {
283        /// The FUSE copy file range request
284        arg: &'a FuseCopyFileRangeIn,
285    },
286    /// CUSE_INIT = 4096
287    #[cfg(feature = "abi-7-11")]
288    CuseInit {
289        /// The CUSE init request
290        arg: &'a FuseInitIn,
291    },
292}
293
294impl<'a> Operation<'a> {
295    /// Build FUSE operation from op-code
296    #[allow(clippy::too_many_lines)]
297    fn parse(
298        n: u32,
299        data: &mut Deserializer<'a>,
300        #[allow(unused_variables)] proto_version: ProtoVersion,
301    ) -> Result<Self, DeserializeError> {
302        let opcode = match n {
303            1 => FuseOpCode::FUSE_LOOKUP,
304            2 => FuseOpCode::FUSE_FORGET,
305            3 => FuseOpCode::FUSE_GETATTR,
306            4 => FuseOpCode::FUSE_SETATTR,
307            5 => FuseOpCode::FUSE_READLINK,
308            6 => FuseOpCode::FUSE_SYMLINK,
309            8 => FuseOpCode::FUSE_MKNOD,
310            9 => FuseOpCode::FUSE_MKDIR,
311            10 => FuseOpCode::FUSE_UNLINK,
312            11 => FuseOpCode::FUSE_RMDIR,
313            12 => FuseOpCode::FUSE_RENAME,
314            13 => FuseOpCode::FUSE_LINK,
315            14 => FuseOpCode::FUSE_OPEN,
316            15 => FuseOpCode::FUSE_READ,
317            16 => FuseOpCode::FUSE_WRITE,
318            17 => FuseOpCode::FUSE_STATFS,
319            18 => FuseOpCode::FUSE_RELEASE,
320            20 => FuseOpCode::FUSE_FSYNC,
321            21 => FuseOpCode::FUSE_SETXATTR,
322            22 => FuseOpCode::FUSE_GETXATTR,
323            23 => FuseOpCode::FUSE_LISTXATTR,
324            24 => FuseOpCode::FUSE_REMOVEXATTR,
325            25 => FuseOpCode::FUSE_FLUSH,
326            26 => FuseOpCode::FUSE_INIT,
327            27 => FuseOpCode::FUSE_OPENDIR,
328            28 => FuseOpCode::FUSE_READDIR,
329            29 => FuseOpCode::FUSE_RELEASEDIR,
330            30 => FuseOpCode::FUSE_FSYNCDIR,
331            31 => FuseOpCode::FUSE_GETLK,
332            32 => FuseOpCode::FUSE_SETLK,
333            33 => FuseOpCode::FUSE_SETLKW,
334            34 => FuseOpCode::FUSE_ACCESS,
335            35 => FuseOpCode::FUSE_CREATE,
336            36 => FuseOpCode::FUSE_INTERRUPT,
337            37 => FuseOpCode::FUSE_BMAP,
338            38 => FuseOpCode::FUSE_DESTROY,
339            #[cfg(feature = "abi-7-11")]
340            39 => FuseOpCode::FUSE_IOCTL,
341            #[cfg(feature = "abi-7-11")]
342            40 => FuseOpCode::FUSE_POLL,
343            #[cfg(feature = "abi-7-15")]
344            41 => FuseOpCode::FUSE_NOTIFY_REPLY,
345            #[cfg(feature = "abi-7-16")]
346            42 => FuseOpCode::FUSE_BATCH_FORGET,
347            #[cfg(feature = "abi-7-19")]
348            43 => FuseOpCode::FUSE_FALLOCATE,
349            #[cfg(feature = "abi-7-21")]
350            44 => FuseOpCode::FUSE_READDIRPLUS,
351            #[cfg(feature = "abi-7-23")]
352            45 => FuseOpCode::FUSE_RENAME2,
353            // #[cfg(feature = "abi-7-24")]
354            46 => FuseOpCode::FUSE_LSEEK,
355            // #[cfg(feature = "abi-7-28")]
356            47 => FuseOpCode::FUSE_COPY_FILE_RANGE,
357            #[cfg(feature = "abi-7-11")]
358            4096 => FuseOpCode::CUSE_INIT,
359
360            code => return Err(DeserializeError::UnknownOpCode { code, unique: None }),
361        };
362
363        Ok(match opcode {
364            FuseOpCode::FUSE_LOOKUP => Operation::Lookup {
365                name: data.fetch_str()?,
366            },
367            FuseOpCode::FUSE_FORGET => Operation::Forget {
368                arg: data.fetch_ref()?,
369            },
370            FuseOpCode::FUSE_GETATTR => Operation::GetAttr,
371            FuseOpCode::FUSE_SETATTR => Operation::SetAttr {
372                arg: data.fetch_ref()?,
373            },
374            FuseOpCode::FUSE_READLINK => Operation::ReadLink,
375            FuseOpCode::FUSE_SYMLINK => Operation::SymLink {
376                name: data.fetch_str()?,
377                link: data.fetch_str()?,
378            },
379            FuseOpCode::FUSE_MKNOD => Operation::MkNod {
380                arg: data.fetch_ref()?,
381                name: data.fetch_str()?,
382            },
383            FuseOpCode::FUSE_MKDIR => Operation::MkDir {
384                arg: data.fetch_ref()?,
385                name: data.fetch_str()?,
386            },
387            FuseOpCode::FUSE_UNLINK => Operation::Unlink {
388                name: data.fetch_str()?,
389            },
390            FuseOpCode::FUSE_RMDIR => Operation::RmDir {
391                name: data.fetch_str()?,
392            },
393            FuseOpCode::FUSE_RENAME => Operation::Rename {
394                arg: data.fetch_ref()?,
395                oldname: data.fetch_str()?,
396                newname: data.fetch_str()?,
397            },
398            FuseOpCode::FUSE_LINK => Operation::Link {
399                arg: data.fetch_ref()?,
400                name: data.fetch_str()?,
401            },
402            FuseOpCode::FUSE_OPEN => Operation::Open {
403                arg: data.fetch_ref()?,
404            },
405            FuseOpCode::FUSE_READ => Operation::Read {
406                arg: data.fetch_ref()?,
407            },
408            FuseOpCode::FUSE_WRITE => Operation::Write {
409                arg: data.fetch_ref()?,
410                data: data.fetch_all_bytes(),
411            },
412            FuseOpCode::FUSE_STATFS => Operation::StatFs,
413            FuseOpCode::FUSE_RELEASE => Operation::Release {
414                arg: data.fetch_ref()?,
415            },
416            FuseOpCode::FUSE_FSYNC => Operation::FSync {
417                arg: data.fetch_ref()?,
418            },
419            FuseOpCode::FUSE_SETXATTR => Operation::SetXAttr {
420                arg: data.fetch_ref()?,
421                name: data.fetch_str()?,
422                value: data.fetch_all_bytes(),
423            },
424            FuseOpCode::FUSE_GETXATTR => Operation::GetXAttr {
425                arg: data.fetch_ref()?,
426                name: data.fetch_str()?,
427            },
428            FuseOpCode::FUSE_LISTXATTR => Operation::ListXAttr {
429                arg: data.fetch_ref()?,
430            },
431            FuseOpCode::FUSE_REMOVEXATTR => Operation::RemoveXAttr {
432                name: data.fetch_str()?,
433            },
434            FuseOpCode::FUSE_FLUSH => Operation::Flush {
435                arg: data.fetch_ref()?,
436            },
437            FuseOpCode::FUSE_INIT => Operation::Init {
438                arg: data.fetch_ref()?,
439            },
440            FuseOpCode::FUSE_OPENDIR => Operation::OpenDir {
441                arg: data.fetch_ref()?,
442            },
443            FuseOpCode::FUSE_READDIR => Operation::ReadDir {
444                arg: data.fetch_ref()?,
445            },
446            FuseOpCode::FUSE_RELEASEDIR => Operation::ReleaseDir {
447                arg: data.fetch_ref()?,
448            },
449            FuseOpCode::FUSE_FSYNCDIR => Operation::FSyncDir {
450                arg: data.fetch_ref()?,
451            },
452            FuseOpCode::FUSE_GETLK => Operation::GetLk {
453                arg: data.fetch_ref()?,
454            },
455            FuseOpCode::FUSE_SETLK => Operation::SetLk {
456                arg: data.fetch_ref()?,
457            },
458            FuseOpCode::FUSE_SETLKW => Operation::SetLkW {
459                arg: data.fetch_ref()?,
460            },
461            FuseOpCode::FUSE_ACCESS => Operation::Access {
462                arg: data.fetch_ref()?,
463            },
464            FuseOpCode::FUSE_CREATE => Operation::Create {
465                arg: data.fetch_ref()?,
466                name: data.fetch_str()?,
467            },
468            FuseOpCode::FUSE_INTERRUPT => Operation::Interrupt {
469                arg: data.fetch_ref()?,
470            },
471            FuseOpCode::FUSE_BMAP => Operation::BMap {
472                arg: data.fetch_ref()?,
473            },
474            FuseOpCode::FUSE_DESTROY => Operation::Destroy,
475            #[cfg(feature = "abi-7-11")]
476            FuseOpCode::FUSE_IOCTL => Operation::IoCtl {
477                arg: data.fetch_ref()?,
478                data: data.fetch_all_bytes(),
479            },
480            #[cfg(feature = "abi-7-11")]
481            FuseOpCode::FUSE_POLL => Operation::Poll {
482                arg: data.fetch_ref()?,
483            },
484            #[cfg(feature = "abi-7-15")]
485            FuseOpCode::FUSE_NOTIFY_REPLY => Operation::NotifyReply {
486                data: data.fetch_all_bytes(),
487            },
488            #[cfg(feature = "abi-7-16")]
489            FuseOpCode::FUSE_BATCH_FORGET => Operation::BatchForget {
490                arg: data.fetch_ref()?,
491                nodes: data.fetch_all_as_slice()?,
492            },
493            #[cfg(feature = "abi-7-19")]
494            FuseOpCode::FUSE_FALLOCATE => Operation::FAllocate {
495                arg: data.fetch_ref()?,
496            },
497            #[cfg(feature = "abi-7-21")]
498            FuseOpCode::FUSE_READDIRPLUS => Operation::ReadDirPlus {
499                arg: data.fetch_ref()?,
500            },
501            #[cfg(feature = "abi-7-23")]
502            FuseOpCode::FUSE_RENAME2 => Operation::Rename2 {
503                arg: data.fetch_ref()?,
504                oldname: data.fetch_str()?,
505                newname: data.fetch_str()?,
506            },
507            // #[cfg(feature = "abi-7-24")]
508            FuseOpCode::FUSE_LSEEK => Operation::LSeek {
509                arg: data.fetch_ref()?,
510            },
511            // #[cfg(feature = "abi-7-28")]
512            FuseOpCode::FUSE_COPY_FILE_RANGE => Operation::CopyFileRange {
513                arg: data.fetch_ref()?,
514            },
515            #[cfg(feature = "abi-7-11")]
516            FuseOpCode::CUSE_INIT => Operation::CuseInit {
517                arg: data.fetch_ref()?,
518            },
519        })
520    }
521}
522
523impl fmt::Display for Operation<'_> {
524    /// Format FUSE operation to display
525    #[allow(clippy::too_many_lines)]
526    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527        match *self {
528            Operation::Lookup { name } => write!(f, "LOOKUP name={name:?}"),
529            Operation::Forget { arg } => write!(f, "FORGET nlookup={}", arg.nlookup),
530            Operation::GetAttr => write!(f, "GETATTR"),
531            Operation::SetAttr { arg } => write!(f, "SETATTR valid={:#x}", arg.valid),
532            Operation::ReadLink => write!(f, "READLINK"),
533            Operation::SymLink { name, link } => {
534                write!(f, "SYMLINK name={name:?}, link={link:?}")
535            }
536            Operation::MkNod { arg, name } => write!(
537                f,
538                "MKNOD name={:?}, mode={:#05o}, rdev={}",
539                name, arg.mode, arg.rdev
540            ),
541            Operation::MkDir { arg, name } => {
542                write!(f, "MKDIR name={:?}, mode={:#05o}", name, arg.mode)
543            }
544            Operation::Unlink { name } => write!(f, "UNLINK name={name:?}"),
545            Operation::RmDir { name } => write!(f, "RMDIR name={name:?}"),
546            Operation::Rename {
547                arg,
548                oldname,
549                newname,
550            } => write!(
551                f,
552                "RENAME name={:?}, newdir={:#018x}, newname={:?}",
553                oldname, arg.newdir, newname
554            ),
555            Operation::Link { arg, name } => {
556                write!(f, "LINK name={:?}, oldnodeid={:#018x}", name, arg.oldnodeid)
557            }
558            Operation::Open { arg } => write!(f, "OPEN flags={:#x}", arg.flags),
559            Operation::Read { arg } => write!(
560                f,
561                "READ fh={}, offset={}, size={}",
562                arg.fh, arg.offset, arg.size
563            ),
564            Operation::Write { arg, .. } => write!(
565                f,
566                "WRITE fh={}, offset={}, size={}, write flags={:#x}",
567                arg.fh, arg.offset, arg.size, arg.write_flags
568            ),
569            Operation::StatFs => write!(f, "STATFS"),
570            Operation::Release { arg } => write!(
571                f,
572                "RELEASE fh={}, flags={:#x}, release flags={:#x}, lock owner={}",
573                arg.fh, arg.flags, arg.release_flags, arg.lock_owner
574            ),
575            Operation::FSync { arg } => {
576                write!(f, "FSYNC fh={}, fsync flags={:#x}", arg.fh, arg.fsync_flags)
577            }
578            Operation::SetXAttr { arg, name, .. } => write!(
579                f,
580                "SETXATTR name={:?}, size={}, flags={:#x}",
581                name, arg.size, arg.flags
582            ),
583            Operation::GetXAttr { arg, name } => {
584                write!(f, "GETXATTR name={:?}, size={}", name, arg.size)
585            }
586            Operation::ListXAttr { arg } => write!(f, "LISTXATTR size={}", arg.size),
587            Operation::RemoveXAttr { name } => write!(f, "REMOVEXATTR name={name:?}"),
588            Operation::Flush { arg } => {
589                write!(f, "FLUSH fh={}, lock owner={}", arg.fh, arg.lock_owner)
590            }
591            Operation::Init { arg } => write!(
592                f,
593                "INIT kernel ABI={}.{}, flags={:#x}, max readahead={}",
594                arg.major, arg.minor, arg.flags, arg.max_readahead
595            ),
596            Operation::OpenDir { arg } => write!(f, "OPENDIR flags={:#x}", arg.flags),
597            Operation::ReadDir { arg } => write!(
598                f,
599                "READDIR fh={}, offset={}, size={}",
600                arg.fh, arg.offset, arg.size
601            ),
602            Operation::ReleaseDir { arg } => write!(
603                f,
604                "RELEASEDIR fh={}, flags={:#x}, release flags={:#x}, lock owner={}",
605                arg.fh, arg.flags, arg.release_flags, arg.lock_owner
606            ),
607            Operation::FSyncDir { arg } => write!(
608                f,
609                "FSYNCDIR fh={}, fsync flags={:#x}",
610                arg.fh, arg.fsync_flags
611            ),
612            Operation::GetLk { arg } => write!(f, "GETLK fh={}, lock owner={}", arg.fh, arg.owner),
613            Operation::SetLk { arg } => write!(f, "SETLK fh={}, lock owner={}", arg.fh, arg.owner),
614            Operation::SetLkW { arg } => {
615                write!(f, "SETLKW fh={}, lock owner={}", arg.fh, arg.owner)
616            }
617            Operation::Access { arg } => write!(f, "ACCESS mask={:#05o}", arg.mask),
618            Operation::Create { arg, name } => write!(
619                f,
620                "CREATE name={:?}, mode={:#05o}, flags={:#x}",
621                name, arg.mode, arg.flags,
622            ),
623            Operation::Interrupt { arg } => write!(f, "INTERRUPT unique={}", arg.unique),
624            Operation::BMap { arg } => {
625                write!(f, "BMAP blocksize={}, ids={}", arg.blocksize, arg.block)
626            }
627            Operation::Destroy => write!(f, "DESTROY"),
628
629            #[cfg(feature = "abi-7-11")]
630            Operation::IoCtl { arg, data } => write!(
631                f,
632                "IOCTL fh={}, flags {:#x}, cmd={}, arg={}, data={:?}",
633                arg.fh, arg.flags, arg.cmd, arg.arg, data,
634            ),
635            #[cfg(feature = "abi-7-11")]
636            Operation::Poll { arg } => {
637                write!(
638                    f,
639                    "POLL fh={}, kh={}, flags={:#x} ",
640                    arg.fh, arg.kh, arg.flags
641                )
642            }
643            #[cfg(feature = "abi-7-15")]
644            Operation::NotifyReply { data } => write!(f, "NOTIFY REPLY data={data:?}"),
645            #[cfg(feature = "abi-7-16")]
646            Operation::BatchForget { arg, nodes } => {
647                write!(f, "BATCH FORGOT count={}, nodes={:?}", arg.count, nodes)
648            }
649            #[cfg(feature = "abi-7-19")]
650            Operation::FAllocate { arg } => write!(
651                f,
652                "FALLOCATE fh={}, offset={}, length={}, mode={:#05o}",
653                arg.fh, arg.offset, arg.length, arg.mode,
654            ),
655            #[cfg(feature = "abi-7-21")]
656            Operation::ReadDirPlus { arg } => write!(
657                f,
658                "READDIRPLUS fh={}, offset={}, size={}",
659                arg.fh, arg.offset, arg.size,
660            ),
661            #[cfg(feature = "abi-7-23")]
662            Operation::Rename2 {
663                arg,
664                oldname,
665                newname,
666            } => write!(
667                f,
668                "RENAME2 name={:?}, newdir={:#018x}, newname={:?}, flags={:#x}",
669                oldname, arg.newdir, newname, arg.flags,
670            ),
671            // #[cfg(feature = "abi-7-24")]
672            Operation::LSeek { arg } => write!(
673                f,
674                "LSEEK fh={}, offset={}, whence={}",
675                arg.fh, arg.offset, arg.whence,
676            ),
677            // #[cfg(feature = "abi-7-28")]
678            Operation::CopyFileRange { arg } => write!(
679                f,
680                "COPYFILERANGE src fh={}, dst fh={}, flags={:#?}",
681                arg.fh_in, arg.fh_out, arg.flags,
682            ),
683            #[cfg(feature = "abi-7-11")]
684            Operation::CuseInit { arg } => write!(
685                f,
686                "CUSE INIT kernel ABI={}.{}, flags={:#x}, max readahead={}",
687                arg.major, arg.minor, arg.flags, arg.max_readahead,
688            ),
689        }
690    }
691}
692
693/// FUSE request
694#[derive(Debug)]
695pub struct Request<'a> {
696    /// FUSE request header
697    header: &'a FuseInHeader,
698    /// FUSE request operation
699    operation: Operation<'a>,
700}
701
702impl fmt::Display for Request<'_> {
703    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
704        write!(
705            f,
706            "fuse={} ino={} operation={}",
707            self.header.unique, self.header.nodeid, self.operation,
708        )
709    }
710}
711
712impl<'a> Request<'a> {
713    /// Build FUSE request
714    pub fn new(bytes: &'a [u8], proto_version: ProtoVersion) -> Result<Self, DeserializeError> {
715        let data_len = bytes.len();
716        let mut de = Deserializer::new(bytes);
717        // Parse header
718        let header = de.fetch_ref::<FuseInHeader>()?;
719        // Check data size
720        debug_assert!(
721            data_len >= header.len.cast(), // TODO: why not daten_len == header.len?
722            "failed to assert {} >= {}",
723            data_len,
724            header.len,
725        );
726        // Parse/check operation arguments
727        let operation = Operation::parse(header.opcode, &mut de, proto_version).map_err(|e| {
728            if let DeserializeError::UnknownOpCode { code, .. } = e {
729                DeserializeError::UnknownOpCode {
730                    code,
731                    unique: Some(header.unique),
732                }
733            } else {
734                e
735            }
736        })?;
737        if de.remaining_len() > 0 {
738            debug!(
739                "request bytes is not completely consumed: \
740                    bytes.len() = {}, header = {:?}, de.remaining_len() = {}, de = {:?}",
741                bytes.len(),
742                header,
743                de.remaining_len(),
744                de
745            );
746        }
747
748        Ok(Self { header, operation })
749    }
750
751    /// Returns the unique identifier of this request.
752    ///
753    /// The FUSE kernel driver assigns a unique id to every concurrent request.
754    /// This allows to distinguish between multiple concurrent requests. The
755    /// unique id of a request may be reused in later requests after it has
756    /// completed.
757    #[inline]
758    #[must_use]
759    pub const fn unique(&self) -> u64 {
760        self.header.unique
761    }
762
763    /// Returns the node ID of the inode this request is targeted to.
764    #[inline]
765    #[must_use]
766    pub const fn nodeid(&self) -> u64 {
767        self.header.nodeid
768    }
769
770    /// Returns the UID that the process that triggered this request runs under.
771    #[allow(dead_code)]
772    #[inline]
773    #[must_use]
774    pub const fn uid(&self) -> u32 {
775        self.header.uid
776    }
777
778    /// Returns the GID that the process that triggered this request runs under.
779    #[allow(dead_code)]
780    #[inline]
781    #[must_use]
782    pub const fn gid(&self) -> u32 {
783        self.header.gid
784    }
785
786    /// Returns the PID of the process that triggered this request.
787    #[allow(dead_code)]
788    #[inline]
789    #[must_use]
790    pub const fn pid(&self) -> u32 {
791        self.header.pid
792    }
793
794    /// Returns the byte length of this request.
795    #[allow(dead_code)]
796    #[inline]
797    #[must_use]
798    pub const fn len(&self) -> u32 {
799        self.header.len
800    }
801
802    /// Returns if the byte length of this request is 0.
803    #[allow(dead_code)]
804    #[inline]
805    #[must_use]
806    pub const fn is_empty(&self) -> bool {
807        self.header.len == 0
808    }
809
810    /// Returns the filesystem operation (and its arguments) of this request.
811    #[inline]
812    #[must_use]
813    pub const fn operation(&self) -> &Operation<'_> {
814        &self.operation
815    }
816}