Skip to main content

starnix_modules_fuse/
lib.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![recursion_limit = "512"]
6
7use fuchsia_rcu::RcuReadScope;
8use linux_uapi::FUSE_DEV_IOC_PASSTHROUGH_OPEN_V2;
9use starnix_core::mm::{MemoryAccessorExt, PAGE_SIZE};
10use starnix_core::mutable_state::Guard;
11use starnix_core::security;
12use starnix_core::task::waiter::WaiterOptions;
13use starnix_core::task::{CurrentTask, EventHandler, Kernel, WaitCanceler, WaitQueue, Waiter};
14use starnix_core::vfs::buffers::{
15    Buffer, InputBuffer, InputBufferExt as _, OutputBuffer, OutputBufferCallback,
16};
17use starnix_core::vfs::pseudo::dynamic_file::{DynamicFile, DynamicFileBuf, DynamicFileSource};
18use starnix_core::vfs::pseudo::simple_directory::SimpleDirectory;
19use starnix_core::vfs::pseudo::simple_file::SimpleFileNode;
20use starnix_core::vfs::pseudo::vec_directory::{VecDirectory, VecDirectoryEntry};
21use starnix_core::vfs::{
22    AppendLockGuard, CacheMode, CheckAccessReason, DirEntry, DirEntryOps, DirectoryEntryType,
23    DirentSink, FallocMode, FdNumber, FileObject, FileObjectState, FileOps, FileSystem,
24    FileSystemHandle, FileSystemOps, FileSystemOptions, FsNode, FsNodeHandle, FsNodeInfo,
25    FsNodeOps, FsStr, FsString, NamespaceNode, PeekBufferSegmentsCallback, SeekTarget,
26    SymlinkTarget, ValueOrSize, WeakFileHandle, XattrOp, default_eof_offset, default_fcntl,
27    default_ioctl, default_seek, fileops_impl_nonseekable, fileops_impl_noop_sync, fs_args,
28    fs_node_impl_dir_readonly,
29};
30use starnix_lifecycle::AtomicU64Counter;
31use starnix_logging::{log_error, log_trace, log_warn, track_stub};
32use starnix_sync::{
33    AtomicMonotonicInstant, FileOpsCore, LockEqualOrBefore, Locked, Mutex, MutexGuard, RwLock,
34    RwLockReadGuard, RwLockWriteGuard, Unlocked,
35};
36use starnix_syscalls::{SyscallArg, SyscallResult};
37use starnix_types::time::{NANOS_PER_SECOND, duration_from_timespec, time_from_timespec};
38use starnix_types::vfs::default_statfs;
39use starnix_uapi::auth::FsCred;
40use starnix_uapi::device_type::DeviceType;
41use starnix_uapi::errors::{EINTR, EINVAL, ENOENT, ENOSYS, Errno};
42use starnix_uapi::file_mode::{Access, FileMode};
43use starnix_uapi::math::round_up_to_increment;
44use starnix_uapi::open_flags::OpenFlags;
45use starnix_uapi::vfs::FdEvents;
46use starnix_uapi::{
47    FUSE_SUPER_MAGIC, errno, errno_from_code, error, ino_t, mode, off_t, statfs, uapi,
48};
49use std::collections::hash_map::Entry;
50use std::collections::{HashMap, VecDeque};
51use std::ops::{Deref, DerefMut};
52use std::sync::atomic::{AtomicBool, Ordering};
53use std::sync::{Arc, Weak};
54use syncio::zxio_node_attr_has_t;
55use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
56
57const FUSE_ROOT_ID_U64: u64 = uapi::FUSE_ROOT_ID as u64;
58const CONFIGURATION_AVAILABLE_EVENT: u64 = std::u64::MAX;
59
60uapi::check_arch_independent_layout! {
61    fuse_access_in {}
62    fuse_attr {}
63    fuse_attr_out {}
64    fuse_create_in {}
65    fuse_dirent {}
66    fuse_entry_bpf_out {}
67    fuse_entry_out {}
68    fuse_flush_in {}
69    fuse_forget_in {}
70    fuse_getxattr_in {}
71    fuse_getxattr_out {}
72    fuse_in_header {}
73    fuse_init_in {}
74    fuse_init_out {}
75    fuse_interrupt_in {}
76    fuse_link_in {}
77    fuse_lseek_in {}
78    fuse_lseek_out {}
79    fuse_mkdir_in {}
80    fuse_mknod_in {}
81    fuse_opcode {}
82    fuse_open_in {}
83    fuse_open_out {}
84    fuse_out_header {}
85    fuse_poll_in {}
86    fuse_poll_out {}
87    fuse_read_in {}
88    fuse_release_in {}
89    fuse_rename2_in {}
90    fuse_setattr_in {}
91    fuse_setxattr_in {}
92    fuse_statfs_out {}
93    fuse_write_in {}
94    fuse_write_out {}
95}
96
97#[derive(Debug)]
98struct DevFuse {
99    connection: Arc<FuseConnection>,
100}
101
102pub fn open_fuse_device(
103    _locked: &mut Locked<FileOpsCore>,
104    current_task: &CurrentTask,
105    _id: DeviceType,
106    _node: &NamespaceNode,
107    _flags: OpenFlags,
108) -> Result<Box<dyn FileOps>, Errno> {
109    let connection = fuse_connections(current_task.kernel()).new_connection(current_task);
110    Ok(Box::new(DevFuse { connection }))
111}
112
113fn attr_valid_to_duration(
114    attr_valid: u64,
115    attr_valid_nsec: u32,
116) -> Result<zx::MonotonicDuration, Errno> {
117    duration_from_timespec(uapi::timespec {
118        tv_sec: i64::try_from(attr_valid).unwrap_or(std::i64::MAX),
119        tv_nsec: attr_valid_nsec.into(),
120    })
121}
122
123impl FileOps for DevFuse {
124    fileops_impl_nonseekable!();
125    fileops_impl_noop_sync!();
126
127    fn close(
128        self: Box<Self>,
129        _locked: &mut Locked<FileOpsCore>,
130        _file: &FileObjectState,
131        _current_task: &CurrentTask,
132    ) {
133        self.connection.lock().disconnect();
134    }
135
136    fn read(
137        &self,
138        locked: &mut Locked<FileOpsCore>,
139        file: &FileObject,
140        current_task: &CurrentTask,
141        offset: usize,
142        data: &mut dyn OutputBuffer,
143    ) -> Result<usize, Errno> {
144        debug_assert!(offset == 0);
145        file.blocking_op(locked, current_task, FdEvents::POLLIN, None, |_| {
146            self.connection.lock().read(data)
147        })
148    }
149
150    fn write(
151        &self,
152        _locked: &mut Locked<FileOpsCore>,
153        _file: &FileObject,
154        _current_task: &CurrentTask,
155        offset: usize,
156        data: &mut dyn InputBuffer,
157    ) -> Result<usize, Errno> {
158        debug_assert!(offset == 0);
159        self.connection.lock().write(data)
160    }
161
162    fn wait_async(
163        &self,
164        _locked: &mut Locked<FileOpsCore>,
165        _file: &FileObject,
166        _current_task: &CurrentTask,
167        waiter: &Waiter,
168        events: FdEvents,
169        handler: EventHandler,
170    ) -> Option<WaitCanceler> {
171        self.connection.lock().wait_async(waiter, events, handler)
172    }
173
174    fn query_events(
175        &self,
176        _locked: &mut Locked<FileOpsCore>,
177        _file: &FileObject,
178        _current_task: &CurrentTask,
179    ) -> Result<FdEvents, Errno> {
180        Ok(self.connection.lock().query_events())
181    }
182
183    fn ioctl(
184        &self,
185        locked: &mut Locked<Unlocked>,
186        file: &FileObject,
187        current_task: &CurrentTask,
188        request: u32,
189        arg: SyscallArg,
190    ) -> Result<SyscallResult, Errno> {
191        match request {
192            FUSE_DEV_IOC_PASSTHROUGH_OPEN_V2 => {
193                let fd = current_task.read_object::<FdNumber>(arg.into())?;
194                let fd = current_task.get_file(fd)?;
195                let id = {
196                    let mut connection = self.connection.lock();
197                    let (mut id, _) = connection.last_passthrough_id.overflowing_add(1);
198                    let mut entry = connection.registered_passthrough.entry(id);
199                    while id == 0 || matches!(entry, Entry::Occupied(_)) {
200                        let (new_id, _) = id.overflowing_add(1);
201                        id = new_id;
202                        entry = connection.registered_passthrough.entry(id);
203                    }
204                    entry.or_insert_with(|| Arc::downgrade(&fd));
205                    connection.last_passthrough_id = id;
206                    id
207                };
208                Ok(id.into())
209            }
210            _ => default_ioctl(file, locked, current_task, request, arg),
211        }
212    }
213}
214
215pub fn new_fuse_fs(
216    locked: &mut Locked<Unlocked>,
217    current_task: &CurrentTask,
218    options: FileSystemOptions,
219) -> Result<FileSystemHandle, Errno> {
220    let fd = fs_args::parse::<FdNumber>(
221        options.params.get(b"fd").ok_or_else(|| errno!(EINVAL))?.as_ref(),
222    )?;
223    let default_permissions = options.params.get(b"default_permissions").is_some().into();
224    let connection = current_task
225        .live()
226        .files
227        .get(fd)?
228        .downcast_file::<DevFuse>()
229        .ok_or_else(|| errno!(EINVAL))?
230        .connection
231        .clone();
232
233    let fs = FileSystem::new(
234        locked,
235        current_task.kernel(),
236        CacheMode::Cached(current_task.kernel().fs_cache_config()),
237        FuseFs { connection: connection.clone(), default_permissions },
238        options,
239    )?;
240    let fuse_node = FuseNode::new(connection.clone(), FUSE_ROOT_ID_U64, 0);
241    fuse_node.state.lock().nlookup += 1;
242
243    fs.create_root(FUSE_ROOT_ID_U64, fuse_node);
244
245    {
246        let mut state = connection.lock();
247        state.connect();
248        state.execute_operation(
249            locked,
250            current_task,
251            FuseNode::from_node(&fs.root().node),
252            FuseOperation::Init { fs: Arc::downgrade(&fs) },
253        )?;
254    }
255    Ok(fs)
256}
257
258fn fuse_connections(kernel: &Kernel) -> Arc<FuseConnections> {
259    kernel.expando.get::<FuseConnections>()
260}
261
262pub fn new_fusectl_fs(
263    locked: &mut Locked<Unlocked>,
264    current_task: &CurrentTask,
265    options: FileSystemOptions,
266) -> Result<FileSystemHandle, Errno> {
267    let fs =
268        FileSystem::new(locked, current_task.kernel(), CacheMode::Uncached, FuseCtlFs, options)?;
269
270    let root_ino = fs.allocate_ino();
271    fs.create_root_with_info(
272        root_ino,
273        FuseCtlConnectionsDirectory {},
274        FsNodeInfo::new(mode!(IFDIR, 0o755), FsCred::root()),
275    );
276
277    Ok(fs)
278}
279
280#[derive(Debug)]
281struct FuseFs {
282    connection: Arc<FuseConnection>,
283    default_permissions: AtomicBool,
284}
285
286impl FuseFs {
287    /// Downcasts this `fs` to a [`FuseFs`].
288    ///
289    /// # Panics
290    ///
291    /// Panics if the `fs` is not a `FuseFs`.
292    fn from_fs(fs: &FileSystem) -> &FuseFs {
293        fs.downcast_ops::<FuseFs>().expect("FUSE should only handle `FuseFs`s")
294    }
295}
296
297impl FileSystemOps for FuseFs {
298    fn rename(
299        &self,
300        locked: &mut Locked<FileOpsCore>,
301        _fs: &FileSystem,
302        current_task: &CurrentTask,
303        old_parent: &FsNodeHandle,
304        old_name: &FsStr,
305        new_parent: &FsNodeHandle,
306        new_name: &FsStr,
307        _renamed: &FsNodeHandle,
308        _replaced: Option<&FsNodeHandle>,
309    ) -> Result<(), Errno> {
310        self.connection.lock().execute_operation(
311            locked,
312            current_task,
313            FuseNode::from_node(&old_parent),
314            FuseOperation::Rename {
315                old_name: old_name.to_owned(),
316                new_dir: new_parent.node_key(),
317                new_name: new_name.to_owned(),
318            },
319        )?;
320        Ok(())
321    }
322
323    fn uses_external_node_ids(&self) -> bool {
324        true
325    }
326
327    fn statfs(
328        &self,
329        locked: &mut Locked<FileOpsCore>,
330        fs: &FileSystem,
331        current_task: &CurrentTask,
332    ) -> Result<statfs, Errno> {
333        let node = FuseNode::from_node(&fs.root().node);
334        let response = self.connection.lock().execute_operation(
335            locked,
336            current_task,
337            &node,
338            FuseOperation::Statfs,
339        )?;
340        let FuseResponse::Statfs(statfs_out) = response else {
341            return error!(EINVAL);
342        };
343        Ok(statfs {
344            f_type: FUSE_SUPER_MAGIC as i64,
345            f_blocks: statfs_out.st.blocks.try_into().map_err(|_| errno!(EINVAL))?,
346            f_bfree: statfs_out.st.bfree.try_into().map_err(|_| errno!(EINVAL))?,
347            f_bavail: statfs_out.st.bavail.try_into().map_err(|_| errno!(EINVAL))?,
348            f_files: statfs_out.st.files.try_into().map_err(|_| errno!(EINVAL))?,
349            f_ffree: statfs_out.st.ffree.try_into().map_err(|_| errno!(EINVAL))?,
350            f_bsize: statfs_out.st.bsize.try_into().map_err(|_| errno!(EINVAL))?,
351            f_namelen: statfs_out.st.namelen.try_into().map_err(|_| errno!(EINVAL))?,
352            f_frsize: statfs_out.st.frsize.try_into().map_err(|_| errno!(EINVAL))?,
353            ..statfs::default()
354        })
355    }
356    fn name(&self) -> &'static FsStr {
357        "fuse".into()
358    }
359    fn unmount(&self) {
360        self.connection.lock().disconnect();
361    }
362}
363
364#[derive(Debug, Default)]
365struct FuseConnections {
366    connections: Mutex<Vec<Weak<FuseConnection>>>,
367    next_identifier: AtomicU64Counter,
368}
369
370impl FuseConnections {
371    fn new_connection(&self, current_task: &CurrentTask) -> Arc<FuseConnection> {
372        let connection = Arc::new(FuseConnection {
373            id: self.next_identifier.next(),
374            creds: current_task.current_fscred(),
375            state: Default::default(),
376        });
377        self.connections.lock().push(Arc::downgrade(&connection));
378        connection
379    }
380
381    fn for_each<F>(&self, mut f: F)
382    where
383        F: FnMut(Arc<FuseConnection>),
384    {
385        self.connections.lock().retain(|connection| {
386            if let Some(connection) = connection.upgrade() {
387                f(connection);
388                true
389            } else {
390                false
391            }
392        });
393    }
394}
395
396struct FuseCtlFs;
397
398impl FileSystemOps for FuseCtlFs {
399    fn rename(
400        &self,
401        _locked: &mut Locked<FileOpsCore>,
402        _fs: &FileSystem,
403        _current_task: &CurrentTask,
404        _old_parent: &FsNodeHandle,
405        _old_name: &FsStr,
406        _new_parent: &FsNodeHandle,
407        _new_name: &FsStr,
408        _renamed: &FsNodeHandle,
409        _replaced: Option<&FsNodeHandle>,
410    ) -> Result<(), Errno> {
411        error!(ENOTSUP)
412    }
413
414    fn statfs(
415        &self,
416        _locked: &mut Locked<FileOpsCore>,
417        _fs: &FileSystem,
418        _current_task: &CurrentTask,
419    ) -> Result<statfs, Errno> {
420        // Magic number has been extracted from the stat utility.
421        const FUSE_CTL_MAGIC: u32 = 0x65735543;
422        Ok(default_statfs(FUSE_CTL_MAGIC))
423    }
424
425    fn name(&self) -> &'static FsStr {
426        "fusectl".into()
427    }
428}
429
430#[derive(Debug)]
431struct FuseCtlConnectionsDirectory;
432
433impl FsNodeOps for FuseCtlConnectionsDirectory {
434    fs_node_impl_dir_readonly!();
435
436    fn create_file_ops(
437        &self,
438        _locked: &mut Locked<FileOpsCore>,
439        _node: &FsNode,
440        current_task: &CurrentTask,
441        _flags: OpenFlags,
442    ) -> Result<Box<dyn FileOps>, Errno> {
443        let connnections = fuse_connections(current_task.kernel());
444        let mut entries = vec![];
445        connnections.for_each(|connection| {
446            entries.push(VecDirectoryEntry {
447                entry_type: DirectoryEntryType::DIR,
448                name: connection.id.to_string().into(),
449                inode: None,
450            });
451        });
452        Ok(VecDirectory::new_file(entries))
453    }
454
455    fn lookup(
456        &self,
457        _locked: &mut Locked<FileOpsCore>,
458        node: &FsNode,
459        current_task: &CurrentTask,
460        name: &FsStr,
461    ) -> Result<FsNodeHandle, Errno> {
462        let name = std::str::from_utf8(name).map_err(|_| errno!(ENOENT))?;
463        let id = name.parse::<u64>().map_err(|_| errno!(ENOENT))?;
464        let connnections = fuse_connections(current_task.kernel());
465        let mut connection = None;
466        connnections.for_each(|c| {
467            if c.id == id {
468                connection = Some(c);
469            }
470        });
471        let Some(connection) = connection else {
472            return error!(ENOENT);
473        };
474        let fs = node.fs();
475        let dir = SimpleDirectory::new();
476        dir.edit(&fs, |dir| {
477            dir.node(
478                "abort".into(),
479                fs.create_node_and_allocate_node_id(
480                    AbortFile::new_node(connection.clone()),
481                    FsNodeInfo::new(mode!(IFREG, 0o200), connection.creds),
482                ),
483            );
484            dir.node(
485                "waiting".into(),
486                fs.create_node_and_allocate_node_id(
487                    WaitingFile::new_node(connection.clone()),
488                    FsNodeInfo::new(mode!(IFREG, 0o400), connection.creds),
489                ),
490            );
491        });
492
493        let info = FsNodeInfo::new(mode!(IFDIR, 0o500), connection.creds);
494        Ok(fs.create_node_and_allocate_node_id(dir, info))
495    }
496}
497
498#[derive(Debug)]
499struct AbortFile {
500    connection: Arc<FuseConnection>,
501}
502
503impl AbortFile {
504    fn new_node(connection: Arc<FuseConnection>) -> impl FsNodeOps {
505        SimpleFileNode::new(move |_, _| Ok(Self { connection: connection.clone() }))
506    }
507}
508
509impl FileOps for AbortFile {
510    fileops_impl_nonseekable!();
511    fileops_impl_noop_sync!();
512
513    fn read(
514        &self,
515        _locked: &mut Locked<FileOpsCore>,
516        _file: &FileObject,
517        _current_task: &CurrentTask,
518        _offset: usize,
519        _data: &mut dyn OutputBuffer,
520    ) -> Result<usize, Errno> {
521        Ok(0)
522    }
523
524    fn write(
525        &self,
526        _locked: &mut Locked<FileOpsCore>,
527        _file: &FileObject,
528        _current_task: &CurrentTask,
529        _offset: usize,
530        data: &mut dyn InputBuffer,
531    ) -> Result<usize, Errno> {
532        let drained = data.drain();
533        if drained > 0 {
534            self.connection.lock().disconnect();
535        }
536        Ok(drained)
537    }
538}
539
540#[derive(Clone, Debug)]
541struct WaitingFile {
542    connection: Arc<FuseConnection>,
543}
544
545impl WaitingFile {
546    fn new_node(connection: Arc<FuseConnection>) -> impl FsNodeOps {
547        DynamicFile::new_node(Self { connection })
548    }
549}
550
551impl DynamicFileSource for WaitingFile {
552    fn generate(
553        &self,
554        _current_task: &CurrentTask,
555        sink: &mut DynamicFileBuf,
556    ) -> Result<(), Errno> {
557        let value = {
558            let state = self.connection.state.lock();
559            state.operations.len() + state.message_queue.len()
560        };
561        let value = format!("{value}\n");
562        sink.write(value.as_bytes());
563        Ok(())
564    }
565}
566
567#[derive(Debug, Default)]
568struct FuseNodeMutableState {
569    nlookup: u64,
570}
571
572#[derive(Debug)]
573struct FuseNode {
574    connection: Arc<FuseConnection>,
575
576    /// A unique identifier for this node.
577    ///
578    /// This value might not be the same as the inode number ([`FsNodeInfo::ino`]).
579    ///
580    /// See <https://libfuse.github.io/doxygen/structfuse__operations.html#ac39a0b7125a0e5001eb5ff42e05faa5d>
581    /// for more information.
582    nodeid: u64,
583
584    generation: u64,
585    attributes_valid_until: AtomicMonotonicInstant,
586    state: Mutex<FuseNodeMutableState>,
587}
588
589impl FuseNode {
590    fn new(connection: Arc<FuseConnection>, nodeid: u64, generation: u64) -> Self {
591        Self {
592            connection,
593            nodeid,
594            generation,
595            attributes_valid_until: zx::MonotonicInstant::INFINITE_PAST.into(),
596            state: Default::default(),
597        }
598    }
599
600    /// Downcasts this `node` to a [`FuseNode`].
601    ///
602    /// # Panics
603    ///
604    /// Panics if the `node` is not a `FuseNode`.
605    fn from_node(node: &FsNode) -> &FuseNode {
606        node.downcast_ops::<FuseNode>().expect("FUSE should only handle `FuseNode`s")
607    }
608
609    fn default_check_access_with_valid_node_attributes(
610        &self,
611        locked: &mut Locked<FileOpsCore>,
612        node: &FsNode,
613        current_task: &CurrentTask,
614        permission_flags: security::PermissionFlags,
615        reason: CheckAccessReason,
616        info: &RwLock<FsNodeInfo>,
617        audit_context: security::Auditable<'_>,
618    ) -> Result<(), Errno> {
619        let info = self.refresh_expired_node_attributes(locked, current_task, info)?;
620        node.default_check_access_impl(current_task, permission_flags, reason, info, audit_context)
621    }
622
623    fn refresh_expired_node_attributes<'a>(
624        &self,
625        locked: &mut Locked<FileOpsCore>,
626        current_task: &CurrentTask,
627        info: &'a RwLock<FsNodeInfo>,
628    ) -> Result<RwLockReadGuard<'a, FsNodeInfo>, Errno> {
629        // Relaxed because the attributes valid until atomic is not used to synchronize
630        // anything. Its final access is protected by the info lock anyways.
631        const VALID_UNTIL_LOAD_ORDERING: Ordering = Ordering::Relaxed;
632
633        let now = zx::MonotonicInstant::get();
634        if self.attributes_valid_until.load(VALID_UNTIL_LOAD_ORDERING) >= now {
635            let info = info.read();
636
637            // Check the valid_until again after taking the info lock to make sure
638            // that the attributes are still valid. We do this because after we
639            // checked the first time and now, the node's attributes could have been
640            // invalidated or expired.
641            //
642            // But why not only check if the attributes are valid after taking the
643            // lock? Because when we will impact FUSE implementations that don't
644            // support caching, or caching with small valid durations, by always
645            // taking a read lock which we then drop to acquire a write lock. We
646            // slightly pessimize the "happy" path with an extra atomic load so
647            // that we don't overly pessimize the uncached/"slower" path.
648            if self.attributes_valid_until.load(VALID_UNTIL_LOAD_ORDERING) >= now {
649                return Ok(info);
650            }
651        }
652
653        // Force a refresh of our cached attributes.
654        self.fetch_and_refresh_info_impl(locked, current_task, info)
655    }
656
657    fn fetch_and_refresh_info_impl<'a>(
658        &self,
659        locked: &mut Locked<FileOpsCore>,
660        current_task: &CurrentTask,
661        info: &'a RwLock<FsNodeInfo>,
662    ) -> Result<RwLockReadGuard<'a, FsNodeInfo>, Errno> {
663        let response = self.connection.lock().execute_operation(
664            locked,
665            current_task,
666            self,
667            FuseOperation::GetAttr,
668        )?;
669        let uapi::fuse_attr_out { attr_valid, attr_valid_nsec, attr, .. } =
670            if let FuseResponse::Attr(attr) = response {
671                attr
672            } else {
673                return error!(EINVAL);
674            };
675        let mut info = info.write();
676        FuseNode::update_node_info_from_attr(
677            &mut info,
678            attr,
679            attr_valid_to_duration(attr_valid, attr_valid_nsec)?,
680            &self.attributes_valid_until,
681        )?;
682        Ok(RwLockWriteGuard::downgrade(info))
683    }
684
685    fn invalidate_attributes(&self) {
686        self.attributes_valid_until.store(zx::MonotonicInstant::INFINITE_PAST, Ordering::Relaxed);
687    }
688
689    fn update_node_info_from_attr(
690        info: &mut FsNodeInfo,
691        attributes: uapi::fuse_attr,
692        attr_valid_duration: zx::MonotonicDuration,
693        node_attributes_valid_until: &AtomicMonotonicInstant,
694    ) -> Result<(), Errno> {
695        info.mode = FileMode::from_bits(attributes.mode);
696        info.size = attributes.size.try_into().map_err(|_| errno!(EINVAL))?;
697        info.blocks = attributes.blocks.try_into().map_err(|_| errno!(EINVAL))?;
698        info.blksize = attributes.blksize.try_into().map_err(|_| errno!(EINVAL))?;
699        info.uid = attributes.uid;
700        info.gid = attributes.gid;
701        info.link_count = attributes.nlink.try_into().map_err(|_| errno!(EINVAL))?;
702        info.time_status_change = time_from_timespec(uapi::timespec {
703            tv_sec: attributes.ctime as i64,
704            tv_nsec: attributes.ctimensec as i64,
705        })?;
706        info.time_access = time_from_timespec(uapi::timespec {
707            tv_sec: attributes.atime as i64,
708            tv_nsec: attributes.atimensec as i64,
709        })?;
710        info.time_modify = time_from_timespec(uapi::timespec {
711            tv_sec: attributes.mtime as i64,
712            tv_nsec: attributes.mtimensec as i64,
713        })?;
714        info.rdev = DeviceType::from_bits(attributes.rdev as u64);
715
716        node_attributes_valid_until
717            .store(zx::MonotonicInstant::after(attr_valid_duration), Ordering::Relaxed);
718        Ok(())
719    }
720
721    /// Build a FsNodeHandle from a FuseResponse that is expected to be a FuseResponse::Entry.
722    fn fs_node_from_entry(
723        &self,
724        node: &FsNode,
725        name: &FsStr,
726        entry: &uapi::fuse_entry_out,
727    ) -> Result<FsNodeHandle, Errno> {
728        if entry.nodeid == 0 {
729            return error!(ENOENT);
730        }
731        let node = node.fs().get_and_validate_or_create_node(
732            entry.nodeid,
733            |node| {
734                let fuse_node = FuseNode::from_node(&node);
735                fuse_node.generation == entry.generation
736            },
737            || {
738                let fuse_node =
739                    FuseNode::new(self.connection.clone(), entry.nodeid, entry.generation);
740                let mut info = FsNodeInfo::default();
741                FuseNode::update_node_info_from_attr(
742                    &mut info,
743                    entry.attr,
744                    attr_valid_to_duration(entry.attr_valid, entry.attr_valid_nsec)?,
745                    &fuse_node.attributes_valid_until,
746                )?;
747                Ok(FsNode::new_uncached(entry.attr.ino, fuse_node, &node.fs(), info))
748            },
749        )?;
750        // . and .. do not get their lookup count increased.
751        if !DirEntry::is_reserved_name(name) {
752            let fuse_node = FuseNode::from_node(&node);
753            fuse_node.state.lock().nlookup += 1;
754        }
755        Ok(node)
756    }
757}
758
759struct FuseFileObject {
760    connection: Arc<FuseConnection>,
761    /// An optional file handle to redirect all read/write to.
762    passthrough_file: WeakFileHandle,
763    /// The response to the open calls from the userspace process.
764    open_out: uapi::fuse_open_out,
765}
766
767impl FuseFileObject {
768    /// Returns the `FuseNode` associated with the opened file.
769    fn get_fuse_node(file: &FileObject) -> &FuseNode {
770        FuseNode::from_node(file.node())
771    }
772}
773
774impl FileOps for FuseFileObject {
775    fn close(
776        self: Box<Self>,
777        locked: &mut Locked<FileOpsCore>,
778        file: &FileObjectState,
779        current_task: &CurrentTask,
780    ) {
781        let node = FuseNode::from_node(file.node());
782        let is_dir = file.node().is_dir();
783        {
784            let mut connection = self.connection.lock();
785            if let Err(e) = connection.execute_operation(
786                locked,
787                current_task,
788                node,
789                if is_dir {
790                    FuseOperation::ReleaseDir(self.open_out)
791                } else {
792                    FuseOperation::Release(self.open_out)
793                },
794            ) {
795                if e.code != ENOSYS {
796                    log_error!("Error when releasing fh: {e:?}");
797                }
798            }
799            connection.clear_released_passthrough_fds();
800        }
801    }
802
803    fn flush(
804        &self,
805        locked: &mut Locked<FileOpsCore>,
806        file: &FileObject,
807        current_task: &CurrentTask,
808    ) {
809        let node = Self::get_fuse_node(file);
810        if let Err(e) = self.connection.lock().execute_operation(
811            locked,
812            current_task,
813            node,
814            FuseOperation::Flush(self.open_out),
815        ) {
816            log_error!("Error when flushing fh: {e:?}");
817        }
818    }
819
820    fn is_seekable(&self) -> bool {
821        true
822    }
823
824    fn read(
825        &self,
826        locked: &mut Locked<FileOpsCore>,
827        file: &FileObject,
828        current_task: &CurrentTask,
829        offset: usize,
830        data: &mut dyn OutputBuffer,
831    ) -> Result<usize, Errno> {
832        if file.node().info().mode.is_dir() {
833            return error!(EISDIR);
834        }
835        if let Some(file_object) = self.passthrough_file.upgrade() {
836            return file_object.ops().read(locked, &file_object, current_task, offset, data);
837        }
838        let node = Self::get_fuse_node(file);
839        let response = self.connection.lock().execute_operation(
840            locked,
841            current_task,
842            node,
843            FuseOperation::Read(uapi::fuse_read_in {
844                fh: self.open_out.fh,
845                offset: offset.try_into().map_err(|_| errno!(EINVAL))?,
846                size: data.available().try_into().unwrap_or(u32::MAX),
847                read_flags: 0,
848                lock_owner: 0,
849                flags: 0,
850                padding: 0,
851            }),
852        )?;
853        let FuseResponse::Read(read_out) = response else {
854            return error!(EINVAL);
855        };
856        data.write(&read_out)
857    }
858
859    fn write(
860        &self,
861        locked: &mut Locked<FileOpsCore>,
862        file: &FileObject,
863        current_task: &CurrentTask,
864        offset: usize,
865        data: &mut dyn InputBuffer,
866    ) -> Result<usize, Errno> {
867        if file.node().info().mode.is_dir() {
868            return error!(EISDIR);
869        }
870        if let Some(file_object) = self.passthrough_file.upgrade() {
871            return file_object.ops().write(locked, &file_object, current_task, offset, data);
872        }
873        let node = Self::get_fuse_node(file);
874        let content = data.peek_all()?;
875        let response = self.connection.lock().execute_operation(
876            locked,
877            current_task,
878            node,
879            FuseOperation::Write {
880                write_in: uapi::fuse_write_in {
881                    fh: self.open_out.fh,
882                    offset: offset.try_into().map_err(|_| errno!(EINVAL))?,
883                    size: content.len().try_into().map_err(|_| errno!(EINVAL))?,
884                    write_flags: 0,
885                    lock_owner: 0,
886                    flags: 0,
887                    padding: 0,
888                },
889                content,
890            },
891        )?;
892        let FuseResponse::Write(write_out) = response else {
893            return error!(EINVAL);
894        };
895        node.invalidate_attributes();
896
897        let written = write_out.size as usize;
898
899        data.advance(written)?;
900        Ok(written)
901    }
902
903    fn seek(
904        &self,
905        locked: &mut Locked<FileOpsCore>,
906        file: &FileObject,
907        current_task: &CurrentTask,
908        current_offset: off_t,
909        target: SeekTarget,
910    ) -> Result<off_t, Errno> {
911        // Only delegate SEEK_DATA and SEEK_HOLE to the userspace process.
912        if matches!(target, SeekTarget::Data(_) | SeekTarget::Hole(_)) {
913            let node = Self::get_fuse_node(file);
914            let response = self.connection.lock().execute_operation(
915                locked,
916                current_task,
917                node,
918                FuseOperation::Seek(uapi::fuse_lseek_in {
919                    fh: self.open_out.fh,
920                    offset: target.offset().try_into().map_err(|_| errno!(EINVAL))?,
921                    whence: target.whence(),
922                    padding: 0,
923                }),
924            );
925            match response {
926                Ok(response) => {
927                    let FuseResponse::Seek(seek_out) = response else {
928                        return error!(EINVAL);
929                    };
930                    return seek_out.offset.try_into().map_err(|_| errno!(EINVAL));
931                }
932                // If errno is ENOSYS, the userspace process doesn't support the seek operation and
933                // the default seek must be used.
934                Err(errno) if errno == ENOSYS => {}
935                Err(errno) => return Err(errno),
936            };
937        }
938
939        default_seek(current_offset, target, || default_eof_offset(locked, file, current_task))
940    }
941
942    fn sync(&self, _file: &FileObject, _current_task: &CurrentTask) -> Result<(), Errno> {
943        track_stub!(TODO("https://fxbug.dev/352359968"), "FUSE fsync()");
944        Ok(())
945    }
946
947    fn wait_async(
948        &self,
949        _locked: &mut Locked<FileOpsCore>,
950        _file: &FileObject,
951        _current_task: &CurrentTask,
952        _waiter: &Waiter,
953        _events: FdEvents,
954        _handler: EventHandler,
955    ) -> Option<WaitCanceler> {
956        None
957    }
958
959    fn query_events(
960        &self,
961        locked: &mut Locked<FileOpsCore>,
962        file: &FileObject,
963        current_task: &CurrentTask,
964    ) -> Result<FdEvents, Errno> {
965        let node = Self::get_fuse_node(file);
966        let response = self.connection.lock().execute_operation(
967            locked,
968            current_task,
969            node,
970            FuseOperation::Poll(uapi::fuse_poll_in {
971                fh: self.open_out.fh,
972                kh: 0,
973                flags: 0,
974                events: FdEvents::all().bits(),
975            }),
976        )?;
977        let FuseResponse::Poll(poll_out) = response else {
978            return error!(EINVAL);
979        };
980        FdEvents::from_bits(poll_out.revents).ok_or_else(|| errno!(EINVAL))
981    }
982
983    fn readdir(
984        &self,
985        locked: &mut Locked<FileOpsCore>,
986        file: &FileObject,
987        current_task: &CurrentTask,
988        sink: &mut dyn DirentSink,
989    ) -> Result<(), Errno> {
990        let mut state = self.connection.lock();
991        let configuration = state.get_configuration(locked, current_task)?;
992        let use_readdirplus = {
993            if configuration.flags.contains(FuseInitFlags::DO_READDIRPLUS) {
994                if configuration.flags.contains(FuseInitFlags::READDIRPLUS_AUTO) {
995                    sink.offset() == 0
996                } else {
997                    true
998                }
999            } else {
1000                false
1001            }
1002        };
1003        // Request a number of bytes related to the user capacity. If none is given, default to a
1004        // single page of data.
1005        let user_capacity = if let Some(base_user_capacity) = sink.user_capacity() {
1006            if use_readdirplus {
1007                // Add some amount of capacity for the entries.
1008                base_user_capacity * 3 / 2
1009            } else {
1010                base_user_capacity
1011            }
1012        } else {
1013            *PAGE_SIZE as usize
1014        };
1015        let node = Self::get_fuse_node(file);
1016        let response = state.execute_operation(
1017            locked,
1018            current_task,
1019            node,
1020            FuseOperation::Readdir {
1021                read_in: uapi::fuse_read_in {
1022                    fh: self.open_out.fh,
1023                    offset: sink.offset().try_into().map_err(|_| errno!(EINVAL))?,
1024                    size: user_capacity.try_into().map_err(|_| errno!(EINVAL))?,
1025                    read_flags: 0,
1026                    lock_owner: 0,
1027                    flags: 0,
1028                    padding: 0,
1029                },
1030                use_readdirplus,
1031            },
1032        )?;
1033        std::mem::drop(state);
1034        let FuseResponse::Readdir(dirents) = response else {
1035            return error!(EINVAL);
1036        };
1037        let mut sink_result = Ok(());
1038        for (dirent, name, entry) in dirents {
1039            if let Some(entry) = entry {
1040                // nodeid == 0 means the server doesn't want to send entry info.
1041                if entry.nodeid != 0 {
1042                    if let Err(e) = node.fs_node_from_entry(file.node(), name.as_ref(), &entry) {
1043                        log_error!("Unable to prefill entry: {e:?}");
1044                    }
1045                }
1046            }
1047            if sink_result.is_ok() {
1048                sink_result = sink.add(
1049                    dirent.ino,
1050                    dirent.off.try_into().map_err(|_| errno!(EINVAL))?,
1051                    DirectoryEntryType::from_bits(
1052                        dirent.type_.try_into().map_err(|_| errno!(EINVAL))?,
1053                    ),
1054                    name.as_ref(),
1055                );
1056            }
1057        }
1058        sink_result
1059    }
1060
1061    fn ioctl(
1062        &self,
1063        locked: &mut Locked<Unlocked>,
1064        file: &FileObject,
1065        current_task: &CurrentTask,
1066        request: u32,
1067        arg: SyscallArg,
1068    ) -> Result<SyscallResult, Errno> {
1069        track_stub!(TODO("https://fxbug.dev/322875259"), "fuse ioctl");
1070        default_ioctl(file, locked, current_task, request, arg)
1071    }
1072
1073    fn fcntl(
1074        &self,
1075        _file: &FileObject,
1076        _current_task: &CurrentTask,
1077        cmd: u32,
1078        _arg: u64,
1079    ) -> Result<SyscallResult, Errno> {
1080        track_stub!(TODO("https://fxbug.dev/322875764"), "fuse fcntl");
1081        default_fcntl(cmd)
1082    }
1083}
1084
1085struct FuseDirEntry {
1086    valid_until: AtomicMonotonicInstant,
1087}
1088
1089impl Default for FuseDirEntry {
1090    fn default() -> Self {
1091        Self { valid_until: zx::MonotonicInstant::INFINITE_PAST.into() }
1092    }
1093}
1094
1095impl DirEntryOps for FuseDirEntry {
1096    fn revalidate(
1097        &self,
1098        locked: &mut Locked<FileOpsCore>,
1099        current_task: &CurrentTask,
1100        dir_entry: &DirEntry,
1101    ) -> Result<bool, Errno> {
1102        // Relaxed because the attributes valid until atomic is not used to synchronize
1103        // anything.
1104        const VALID_UNTIL_ORDERING: Ordering = Ordering::Relaxed;
1105
1106        let now = zx::MonotonicInstant::get();
1107        if self.valid_until.load(VALID_UNTIL_ORDERING) >= now {
1108            return Ok(true);
1109        }
1110
1111        let node = FuseNode::from_node(&dir_entry.node);
1112        if node.nodeid == FUSE_ROOT_ID_U64 {
1113            // The root node entry is always valid.
1114            return Ok(true);
1115        }
1116
1117        // Perform a lookup on this entry's parent FUSE node to revalidate this
1118        // entry.
1119        let (parent, name) = {
1120            let scope = RcuReadScope::new();
1121            let parent = dir_entry.parent().expect("non-root nodes always has a parent");
1122            let name = dir_entry.local_name(&scope).to_owned();
1123            (parent, name)
1124        };
1125        let parent = FuseNode::from_node(&parent.node);
1126        let FuseEntryOutExtended {
1127            arg:
1128                uapi::fuse_entry_out {
1129                    nodeid,
1130                    generation,
1131                    entry_valid,
1132                    entry_valid_nsec,
1133                    attr,
1134                    attr_valid,
1135                    attr_valid_nsec,
1136                },
1137            ..
1138        } = match parent.connection.lock().execute_operation(
1139            locked,
1140            current_task,
1141            parent,
1142            FuseOperation::Lookup { name },
1143        ) {
1144            Ok(FuseResponse::Entry(entry)) => entry,
1145            Ok(_) => return error!(EINVAL),
1146            Err(errno) => {
1147                if errno == ENOENT {
1148                    // The entry no longer exists.
1149                    return Ok(false);
1150                } else {
1151                    return Err(errno);
1152                };
1153            }
1154        };
1155
1156        if (nodeid != node.nodeid) || (generation != node.generation) {
1157            // A new entry exists with the name. This `DirEntry` is no longer
1158            // valid. The caller should attempt to restart the path walk at this
1159            // node.
1160            return Ok(false);
1161        }
1162
1163        dir_entry.node.update_info(|info| {
1164            FuseNode::update_node_info_from_attr(
1165                info,
1166                attr,
1167                attr_valid_to_duration(attr_valid, attr_valid_nsec)?,
1168                &node.attributes_valid_until,
1169            )?;
1170
1171            self.valid_until.store(
1172                zx::MonotonicInstant::after(attr_valid_to_duration(entry_valid, entry_valid_nsec)?),
1173                VALID_UNTIL_ORDERING,
1174            );
1175
1176            Ok(true)
1177        })
1178    }
1179}
1180
1181// `FuseFs.default_permissions` is not used to synchronize anything.
1182const DEFAULT_PERMISSIONS_ATOMIC_ORDERING: Ordering = Ordering::Relaxed;
1183
1184impl FsNodeOps for FuseNode {
1185    fn check_access(
1186        &self,
1187        locked: &mut Locked<FileOpsCore>,
1188        node: &FsNode,
1189        current_task: &CurrentTask,
1190        permission_flags: security::PermissionFlags,
1191        info: &RwLock<FsNodeInfo>,
1192        reason: CheckAccessReason,
1193        audit_context: security::Auditable<'_>,
1194    ) -> Result<(), Errno> {
1195        // Perform access checks regardless of the reason when userspace configured
1196        // the kernel to perform its default access checks on behalf of the FUSE fs.
1197        if FuseFs::from_fs(&node.fs()).default_permissions.load(DEFAULT_PERMISSIONS_ATOMIC_ORDERING)
1198        {
1199            return self.default_check_access_with_valid_node_attributes(
1200                locked,
1201                node,
1202                current_task,
1203                permission_flags,
1204                reason,
1205                info,
1206                audit_context,
1207            );
1208        }
1209
1210        match reason {
1211            CheckAccessReason::Access | CheckAccessReason::Chdir | CheckAccessReason::Chroot => {
1212                // Per `libfuse`'s low-level handler for `FUSE_ACCESS` requests, the kernel
1213                // is only expected to send `FUSE_ACCESS` requests for the `access` and `chdir`
1214                // family of syscalls when the `default_permissions` flag isn't set on the FUSE
1215                // fs. Seems like `chroot` also triggers a `FUSE_ACCESS` request on Linux.
1216                let response = self.connection.lock().execute_operation(
1217                    locked,
1218                    current_task,
1219                    self,
1220                    FuseOperation::Access {
1221                        mask: (permission_flags.as_access() & Access::ACCESS_MASK).bits() as u32,
1222                    },
1223                )?;
1224
1225                if let FuseResponse::Access(result) = response { result } else { error!(EINVAL) }
1226            }
1227            CheckAccessReason::Exec => self.default_check_access_with_valid_node_attributes(
1228                locked,
1229                node,
1230                current_task,
1231                permission_flags,
1232                reason,
1233                info,
1234                audit_context,
1235            ),
1236            CheckAccessReason::ChangeTimestamps { .. }
1237            | CheckAccessReason::InternalPermissionChecks => {
1238                // Per FUSE's mount options, the kernel does not check file access
1239                // permissions unless the default permissions mount option is set.
1240                //
1241                // See https://www.kernel.org/doc/html/v5.6/filesystems/fuse.html#mount-options.
1242                Ok(())
1243            }
1244        }
1245    }
1246
1247    fn create_dir_entry_ops(&self) -> Box<dyn DirEntryOps> {
1248        Box::new(FuseDirEntry::default())
1249    }
1250
1251    fn create_file_ops(
1252        &self,
1253        locked: &mut Locked<FileOpsCore>,
1254        node: &FsNode,
1255        current_task: &CurrentTask,
1256        flags: OpenFlags,
1257    ) -> Result<Box<dyn FileOps>, Errno> {
1258        // The node already exists. The creation has been handled before calling this method.
1259        let flags = flags & !(OpenFlags::CREAT | OpenFlags::EXCL);
1260        let mode = node.info().mode;
1261        let response = self.connection.lock().execute_operation(
1262            locked,
1263            current_task,
1264            self,
1265            FuseOperation::Open { flags, mode },
1266        )?;
1267        let FuseResponse::Open(open_out) = response else {
1268            return error!(EINVAL);
1269        };
1270        // SAFETY: The data has been read with zerocopy which ensures every bits have been
1271        // initialized.
1272        let passthrough_fh = unsafe { open_out.__bindgen_anon_1.passthrough_fh };
1273        let passthrough_file = if passthrough_fh != 0 {
1274            let mut connection = self.connection.lock();
1275            connection.registered_passthrough.remove(&passthrough_fh).unwrap_or_default()
1276        } else {
1277            Weak::new()
1278        };
1279        Ok(Box::new(FuseFileObject {
1280            connection: self.connection.clone(),
1281            passthrough_file,
1282            open_out,
1283        }))
1284    }
1285
1286    fn lookup(
1287        &self,
1288        locked: &mut Locked<FileOpsCore>,
1289        node: &FsNode,
1290        current_task: &CurrentTask,
1291        name: &FsStr,
1292    ) -> Result<FsNodeHandle, Errno> {
1293        let response = self.connection.lock().execute_operation(
1294            locked,
1295            current_task,
1296            self,
1297            FuseOperation::Lookup { name: name.to_owned() },
1298        )?;
1299        self.fs_node_from_entry(node, name, response.entry().ok_or_else(|| errno!(EINVAL))?)
1300    }
1301
1302    fn mknod(
1303        &self,
1304        locked: &mut Locked<FileOpsCore>,
1305        node: &FsNode,
1306        current_task: &CurrentTask,
1307        name: &FsStr,
1308        mode: FileMode,
1309        dev: DeviceType,
1310        _owner: FsCred,
1311    ) -> Result<FsNodeHandle, Errno> {
1312        let get_entry = |locked: &mut Locked<FileOpsCore>| {
1313            let umask = current_task.fs().umask().bits();
1314            let mut connection = self.connection.lock();
1315
1316            if dev == DeviceType::NONE && !connection.no_create {
1317                match connection.execute_operation(
1318                    locked,
1319                    current_task,
1320                    self,
1321                    FuseOperation::Create(
1322                        uapi::fuse_create_in {
1323                            flags: OpenFlags::CREAT.bits(),
1324                            mode: mode.bits(),
1325                            umask,
1326                            open_flags: 0,
1327                        },
1328                        name.to_owned(),
1329                    ),
1330                ) {
1331                    Ok(response) => {
1332                        let FuseResponse::Create(response) = response else {
1333                            return error!(EINVAL);
1334                        };
1335
1336                        let fuse_node = FuseNode::new(
1337                            self.connection.clone(),
1338                            response.entry.nodeid,
1339                            response.entry.generation,
1340                        );
1341
1342                        // It is unfortunate that we have to immediately release the file (only for
1343                        // it to typically be reopened a short time later), but it will be a little
1344                        // tricky to fix this properly, and there are Fuse implementations that rely
1345                        // on us using create rather than mknod to create regular files.  We will
1346                        // have to tackle this if it shows up as a performance issue.
1347                        if let Err(e) = connection.execute_operation(
1348                            locked,
1349                            current_task,
1350                            &fuse_node,
1351                            FuseOperation::Release(response.open),
1352                        ) {
1353                            log_error!("Error when releasing fh: {e:?}");
1354                        }
1355
1356                        return Ok(response.entry);
1357                    }
1358                    Err(e) if e == ENOSYS => {
1359                        connection.no_create = true;
1360                        // Fall through to use mknod below.
1361                    }
1362                    Err(e) => return Err(e),
1363                }
1364            }
1365
1366            connection
1367                .execute_operation(
1368                    locked,
1369                    current_task,
1370                    self,
1371                    FuseOperation::Mknod {
1372                        mknod_in: uapi::fuse_mknod_in {
1373                            mode: mode.bits(),
1374                            rdev: dev.bits() as u32,
1375                            umask,
1376                            padding: 0,
1377                        },
1378                        name: name.to_owned(),
1379                    },
1380                )?
1381                .entry()
1382                .copied()
1383                .ok_or_else(|| errno!(EINVAL))
1384        };
1385
1386        let entry = get_entry(locked)?;
1387        self.fs_node_from_entry(node, name, &entry)
1388    }
1389
1390    fn mkdir(
1391        &self,
1392        locked: &mut Locked<FileOpsCore>,
1393        node: &FsNode,
1394        current_task: &CurrentTask,
1395        name: &FsStr,
1396        mode: FileMode,
1397        _owner: FsCred,
1398    ) -> Result<FsNodeHandle, Errno> {
1399        let response = self.connection.lock().execute_operation(
1400            locked,
1401            current_task,
1402            self,
1403            FuseOperation::Mkdir {
1404                mkdir_in: uapi::fuse_mkdir_in {
1405                    mode: mode.bits(),
1406                    umask: current_task.fs().umask().bits(),
1407                },
1408                name: name.to_owned(),
1409            },
1410        )?;
1411        self.fs_node_from_entry(node, name, response.entry().ok_or_else(|| errno!(EINVAL))?)
1412    }
1413
1414    fn create_symlink(
1415        &self,
1416        locked: &mut Locked<FileOpsCore>,
1417        node: &FsNode,
1418        current_task: &CurrentTask,
1419        name: &FsStr,
1420        target: &FsStr,
1421        _owner: FsCred,
1422    ) -> Result<FsNodeHandle, Errno> {
1423        let response = self.connection.lock().execute_operation(
1424            locked,
1425            current_task,
1426            self,
1427            FuseOperation::Symlink { target: target.to_owned(), name: name.to_owned() },
1428        )?;
1429        self.fs_node_from_entry(node, name, response.entry().ok_or_else(|| errno!(EINVAL))?)
1430    }
1431
1432    fn readlink(
1433        &self,
1434        locked: &mut Locked<FileOpsCore>,
1435        _node: &FsNode,
1436        current_task: &CurrentTask,
1437    ) -> Result<SymlinkTarget, Errno> {
1438        let response = self.connection.lock().execute_operation(
1439            locked,
1440            current_task,
1441            self,
1442            FuseOperation::Readlink,
1443        )?;
1444        let FuseResponse::Read(read_out) = response else {
1445            return error!(EINVAL);
1446        };
1447        Ok(SymlinkTarget::Path(read_out.into()))
1448    }
1449
1450    fn link(
1451        &self,
1452        locked: &mut Locked<FileOpsCore>,
1453        _node: &FsNode,
1454        current_task: &CurrentTask,
1455        name: &FsStr,
1456        child: &FsNodeHandle,
1457    ) -> Result<(), Errno> {
1458        let child_node = FuseNode::from_node(child);
1459        self.connection
1460            .lock()
1461            .execute_operation(
1462                locked,
1463                current_task,
1464                self,
1465                FuseOperation::Link {
1466                    link_in: uapi::fuse_link_in { oldnodeid: child_node.nodeid },
1467                    name: name.to_owned(),
1468                },
1469            )
1470            .map(|_| ())
1471    }
1472
1473    fn unlink(
1474        &self,
1475        locked: &mut Locked<FileOpsCore>,
1476        _node: &FsNode,
1477        current_task: &CurrentTask,
1478        name: &FsStr,
1479        child: &FsNodeHandle,
1480    ) -> Result<(), Errno> {
1481        let is_dir = child.is_dir();
1482        self.connection
1483            .lock()
1484            .execute_operation(
1485                locked,
1486                current_task,
1487                self,
1488                if is_dir {
1489                    FuseOperation::Rmdir { name: name.to_owned() }
1490                } else {
1491                    FuseOperation::Unlink { name: name.to_owned() }
1492                },
1493            )
1494            .map(|_| ())
1495    }
1496
1497    fn truncate(
1498        &self,
1499        locked: &mut Locked<FileOpsCore>,
1500        _guard: &AppendLockGuard<'_>,
1501        node: &FsNode,
1502        current_task: &CurrentTask,
1503        length: u64,
1504    ) -> Result<(), Errno> {
1505        node.update_info(|info| {
1506            // Truncate is implemented by updating the attributes of the file.
1507            let attributes = uapi::fuse_setattr_in {
1508                size: length,
1509                valid: uapi::FATTR_SIZE,
1510                ..Default::default()
1511            };
1512
1513            let response = self.connection.lock().execute_operation(
1514                locked,
1515                current_task,
1516                self,
1517                FuseOperation::SetAttr(attributes),
1518            )?;
1519            let uapi::fuse_attr_out { attr_valid, attr_valid_nsec, attr, .. } =
1520                if let FuseResponse::Attr(attr) = response {
1521                    attr
1522                } else {
1523                    return error!(EINVAL);
1524                };
1525            FuseNode::update_node_info_from_attr(
1526                info,
1527                attr,
1528                attr_valid_to_duration(attr_valid, attr_valid_nsec)?,
1529                &self.attributes_valid_until,
1530            )?;
1531            Ok(())
1532        })
1533    }
1534
1535    fn allocate(
1536        &self,
1537        _locked: &mut Locked<FileOpsCore>,
1538        _guard: &AppendLockGuard<'_>,
1539        _node: &FsNode,
1540        _current_task: &CurrentTask,
1541        _mode: FallocMode,
1542        _offset: u64,
1543        _length: u64,
1544    ) -> Result<(), Errno> {
1545        track_stub!(TODO("https://fxbug.dev/322875414"), "FsNodeOps::allocate");
1546        error!(ENOTSUP)
1547    }
1548
1549    fn fetch_and_refresh_info<'a>(
1550        &self,
1551        locked: &mut Locked<FileOpsCore>,
1552        _node: &FsNode,
1553        current_task: &CurrentTask,
1554        info: &'a RwLock<FsNodeInfo>,
1555    ) -> Result<RwLockReadGuard<'a, FsNodeInfo>, Errno> {
1556        // NOTE: Do not be tempted to always refresh information here; sadly, there are CTS tests
1557        // that rely on this only updating attributes if they have expired, and this matches what
1558        // Linux appears to do.
1559        self.refresh_expired_node_attributes(locked, current_task, info)
1560    }
1561
1562    fn update_attributes(
1563        &self,
1564        locked: &mut Locked<FileOpsCore>,
1565        _node: &FsNode,
1566        current_task: &CurrentTask,
1567        info: &FsNodeInfo,
1568        has: zxio_node_attr_has_t,
1569    ) -> Result<(), Errno> {
1570        let mut valid = 0u32;
1571        // Nb: We don't have a mechanism for 'FATTR_*TIME_NOW'.
1572        if has.modification_time {
1573            valid |= uapi::FATTR_MTIME;
1574        }
1575        if has.access_time {
1576            valid |= uapi::FATTR_ATIME;
1577        }
1578        if has.mode {
1579            valid |= uapi::FATTR_MODE;
1580        }
1581        if has.uid {
1582            valid |= uapi::FATTR_UID;
1583        }
1584        if has.gid {
1585            valid |= uapi::FATTR_GID;
1586        }
1587
1588        let attributes = uapi::fuse_setattr_in {
1589            valid,
1590            atime: (info.time_access.into_nanos() / NANOS_PER_SECOND) as u64,
1591            mtime: (info.time_modify.into_nanos() / NANOS_PER_SECOND) as u64,
1592            ctime: (info.time_status_change.into_nanos() / NANOS_PER_SECOND) as u64,
1593            atimensec: (info.time_access.into_nanos() % NANOS_PER_SECOND) as u32,
1594            mtimensec: (info.time_modify.into_nanos() % NANOS_PER_SECOND) as u32,
1595            ctimensec: (info.time_status_change.into_nanos() % NANOS_PER_SECOND) as u32,
1596            mode: info.mode.bits(),
1597            uid: info.uid,
1598            gid: info.gid,
1599            ..Default::default()
1600        };
1601
1602        let response = self.connection.lock().execute_operation(
1603            locked,
1604            current_task,
1605            self,
1606            FuseOperation::SetAttr(attributes),
1607        )?;
1608        if let FuseResponse::Attr(_attr) = response { Ok(()) } else { error!(EINVAL) }
1609    }
1610
1611    fn get_xattr(
1612        &self,
1613        locked: &mut Locked<FileOpsCore>,
1614        _node: &FsNode,
1615        current_task: &CurrentTask,
1616        name: &FsStr,
1617        max_size: usize,
1618    ) -> Result<ValueOrSize<FsString>, Errno> {
1619        let response = self.connection.lock().execute_operation(
1620            locked,
1621            current_task,
1622            self,
1623            FuseOperation::GetXAttr {
1624                getxattr_in: uapi::fuse_getxattr_in {
1625                    size: max_size.try_into().map_err(|_| errno!(EINVAL))?,
1626                    padding: 0,
1627                },
1628                name: name.to_owned(),
1629            },
1630        )?;
1631        if let FuseResponse::GetXAttr(result) = response { Ok(result) } else { error!(EINVAL) }
1632    }
1633
1634    fn set_xattr(
1635        &self,
1636        locked: &mut Locked<FileOpsCore>,
1637        _node: &FsNode,
1638        current_task: &CurrentTask,
1639        name: &FsStr,
1640        value: &FsStr,
1641        op: XattrOp,
1642    ) -> Result<(), Errno> {
1643        let mut state = self.connection.lock();
1644        let configuration = state.get_configuration(locked, current_task)?;
1645        state.execute_operation(
1646            locked,
1647            current_task,
1648            self,
1649            FuseOperation::SetXAttr {
1650                setxattr_in: uapi::fuse_setxattr_in {
1651                    size: value.len().try_into().map_err(|_| errno!(EINVAL))?,
1652                    flags: op.into_flags(),
1653                    setxattr_flags: 0,
1654                    padding: 0,
1655                },
1656                is_ext: configuration.flags.contains(FuseInitFlags::SETXATTR_EXT),
1657                name: name.to_owned(),
1658                value: value.to_owned(),
1659            },
1660        )?;
1661        Ok(())
1662    }
1663
1664    fn remove_xattr(
1665        &self,
1666        locked: &mut Locked<FileOpsCore>,
1667        _node: &FsNode,
1668        current_task: &CurrentTask,
1669        name: &FsStr,
1670    ) -> Result<(), Errno> {
1671        self.connection.lock().execute_operation(
1672            locked,
1673            current_task,
1674            self,
1675            FuseOperation::RemoveXAttr { name: name.to_owned() },
1676        )?;
1677        Ok(())
1678    }
1679
1680    fn list_xattrs(
1681        &self,
1682        locked: &mut Locked<FileOpsCore>,
1683        _node: &FsNode,
1684        current_task: &CurrentTask,
1685        max_size: usize,
1686    ) -> Result<ValueOrSize<Vec<FsString>>, Errno> {
1687        let response = self.connection.lock().execute_operation(
1688            locked,
1689            current_task,
1690            self,
1691            FuseOperation::ListXAttr(uapi::fuse_getxattr_in {
1692                size: max_size.try_into().map_err(|_| errno!(EINVAL))?,
1693                padding: 0,
1694            }),
1695        )?;
1696        if let FuseResponse::GetXAttr(result) = response {
1697            Ok(result.map(|s| {
1698                let mut result = s.split(|c| *c == 0).map(FsString::from).collect::<Vec<_>>();
1699                // The returned string ends with a '\0', so the split ends with an empty value that
1700                // needs to be removed.
1701                result.pop();
1702                result
1703            }))
1704        } else {
1705            error!(EINVAL)
1706        }
1707    }
1708
1709    fn forget(
1710        self: Box<Self>,
1711        locked: &mut Locked<FileOpsCore>,
1712        current_task: &CurrentTask,
1713        _info: FsNodeInfo,
1714    ) -> Result<(), Errno> {
1715        let nlookup = self.state.lock().nlookup;
1716        let mut state = self.connection.lock();
1717        if !state.is_connected() {
1718            return Ok(());
1719        }
1720        if nlookup > 0 {
1721            state.execute_operation(
1722                locked,
1723                current_task,
1724                self.as_ref(),
1725                FuseOperation::Forget(uapi::fuse_forget_in { nlookup }),
1726            )?;
1727        };
1728        Ok(())
1729    }
1730
1731    fn node_key(&self, _node: &FsNode) -> ino_t {
1732        self.nodeid
1733    }
1734}
1735
1736/// The state of the connection to the /dev/fuse file descriptor.
1737#[derive(Debug, Default)]
1738enum FuseConnectionState {
1739    #[default]
1740    /// The /dev/fuse device has been opened, but the filesystem has not been mounted yet.
1741    Waiting,
1742    /// The file system is mounted.
1743    Connected,
1744    /// The file system has been unmounted.
1745    Disconnected,
1746}
1747
1748#[derive(Debug)]
1749struct FuseConnection {
1750    /// Connection identifier for fusectl.
1751    id: u64,
1752
1753    /// Credentials of the task that opened the connection.
1754    creds: FsCred,
1755
1756    /// Mutable state of the connection.
1757    state: Mutex<FuseMutableState>,
1758}
1759
1760struct FuseMutableStateGuard<'a>(Guard<'a, FuseConnection, MutexGuard<'a, FuseMutableState>>);
1761
1762impl<'a> Deref for FuseMutableStateGuard<'a> {
1763    type Target = Guard<'a, FuseConnection, MutexGuard<'a, FuseMutableState>>;
1764    fn deref(&self) -> &Self::Target {
1765        &self.0
1766    }
1767}
1768
1769impl<'a> DerefMut for FuseMutableStateGuard<'a> {
1770    fn deref_mut(&mut self) -> &mut Self::Target {
1771        &mut self.0
1772    }
1773}
1774
1775impl FuseConnection {
1776    fn lock<'a>(&'a self) -> FuseMutableStateGuard<'a> {
1777        FuseMutableStateGuard(Guard::<'a, FuseConnection, MutexGuard<'a, FuseMutableState>>::new(
1778            self,
1779            self.state.lock(),
1780        ))
1781    }
1782}
1783
1784#[derive(Clone, Copy, Debug)]
1785struct FuseConfiguration {
1786    flags: FuseInitFlags,
1787}
1788
1789impl TryFrom<uapi::fuse_init_out> for FuseConfiguration {
1790    type Error = Errno;
1791    fn try_from(init_out: uapi::fuse_init_out) -> Result<Self, Errno> {
1792        let flags = FuseInitFlags::try_from(init_out)?;
1793        Ok(Self { flags })
1794    }
1795}
1796
1797/// A per connection state for operations that can be shortcircuited.
1798///
1799/// For a number of Fuse operation, Fuse protocol specifies that if they fail in a specific way,
1800/// they should not be sent to the server again and must be handled in a predefined way. This
1801/// map keep track of these operations for a given connection. If this map contains a result for a
1802/// given opcode, any further attempt to send this opcode to userspace will be answered with the
1803/// content of the map.
1804type OperationsState = HashMap<uapi::fuse_opcode, Result<FuseResponse, Errno>>;
1805
1806#[derive(Debug, Default)]
1807struct FuseMutableState {
1808    /// The state of the mount.
1809    state: FuseConnectionState,
1810
1811    /// Last unique id used to identify messages between the kernel and user space.
1812    last_unique_id: u64,
1813
1814    /// The configuration, negotiated with the client.
1815    configuration: Option<FuseConfiguration>,
1816
1817    /// In progress operations.
1818    operations: HashMap<u64, RunningOperation>,
1819
1820    /// Enqueued messages. These messages have not yet been sent to userspace. There should be
1821    /// multiple queues, but for now, push every messages to the same queue.
1822    /// New messages are added at the end of the queues. Read consume from the front of the queue.
1823    message_queue: VecDeque<FuseKernelMessage>,
1824
1825    /// Queue to notify of new messages.
1826    waiters: WaitQueue,
1827
1828    /// The state of the different operations, to allow short-circuiting the userspace process.
1829    operations_state: OperationsState,
1830
1831    /// If true, then the create operation is not supported in which case mknod will be used.
1832    no_create: bool,
1833
1834    /// Last used id for registered fd for passthrough.
1835    last_passthrough_id: u32,
1836
1837    /// All currently registered fd for passthrough, associated with their id. The elements are
1838    /// cleared when used and regularly to check for closed files.
1839    registered_passthrough: HashMap<u32, WeakFileHandle>,
1840}
1841
1842impl<'a> FuseMutableStateGuard<'a> {
1843    fn wait_for_configuration<L, T>(
1844        &mut self,
1845        locked: &mut Locked<L>,
1846        current_task: &CurrentTask,
1847        f: impl Fn(&FuseConfiguration) -> T,
1848    ) -> Result<T, Errno>
1849    where
1850        L: LockEqualOrBefore<FileOpsCore>,
1851    {
1852        if let Some(configuration) = self.configuration.as_ref() {
1853            return Ok(f(configuration));
1854        }
1855        loop {
1856            if !self.is_connected() {
1857                return error!(ECONNABORTED);
1858            }
1859            let waiter = Waiter::new();
1860            self.waiters.wait_async_value(&waiter, CONFIGURATION_AVAILABLE_EVENT);
1861            if let Some(configuration) = self.configuration.as_ref() {
1862                return Ok(f(configuration));
1863            }
1864            Guard::<'a, FuseConnection, MutexGuard<'a, FuseMutableState>>::unlocked(self, || {
1865                waiter.wait(locked, current_task)
1866            })?;
1867        }
1868    }
1869
1870    fn get_configuration<L>(
1871        &mut self,
1872        locked: &mut Locked<L>,
1873        current_task: &CurrentTask,
1874    ) -> Result<FuseConfiguration, Errno>
1875    where
1876        L: LockEqualOrBefore<FileOpsCore>,
1877    {
1878        self.wait_for_configuration(locked, current_task, Clone::clone)
1879    }
1880
1881    fn wait_for_configuration_ready<L>(
1882        &mut self,
1883        locked: &mut Locked<L>,
1884        current_task: &CurrentTask,
1885    ) -> Result<(), Errno>
1886    where
1887        L: LockEqualOrBefore<FileOpsCore>,
1888    {
1889        self.wait_for_configuration(locked, current_task, |_| ())
1890    }
1891
1892    /// Execute the given operation on the `node`. If the operation is not asynchronous, this
1893    /// method will wait on the userspace process for a response. If the operation is interrupted,
1894    /// an interrupt will be sent to the userspace process and the operation will then block until
1895    /// the initial operation has a response. This block can only be interrupted by the filesystem
1896    /// being unmounted.
1897    fn execute_operation<L>(
1898        &mut self,
1899        locked: &mut Locked<L>,
1900        current_task: &CurrentTask,
1901        node: &FuseNode,
1902        operation: FuseOperation,
1903    ) -> Result<FuseResponse, Errno>
1904    where
1905        L: LockEqualOrBefore<FileOpsCore>,
1906    {
1907        // Block until we have a valid configuration to make sure that the FUSE
1908        // implementation has initialized, indicated by its response to the
1909        // `FUSE_INIT` request. Obviously, we skip this check for the `FUSE_INIT`
1910        // request itself.
1911        if !matches!(operation, FuseOperation::Init { .. }) {
1912            self.wait_for_configuration_ready(locked, current_task)?;
1913        }
1914
1915        if let Some(result) = self.operations_state.get(&operation.opcode()) {
1916            return result.clone();
1917        }
1918        if !operation.has_response() {
1919            self.queue_operation(current_task, node.nodeid, operation, None)?;
1920            return Ok(FuseResponse::None);
1921        }
1922        let waiter = Waiter::with_options(WaiterOptions::UNSAFE_CALLSTACK);
1923        let is_async = operation.is_async();
1924        let unique_id =
1925            self.queue_operation(current_task, node.nodeid, operation, Some(&waiter))?;
1926        if is_async {
1927            return Ok(FuseResponse::None);
1928        }
1929        let mut first_loop = true;
1930        loop {
1931            if !self.is_connected() {
1932                return error!(ECONNABORTED);
1933            }
1934            if let Some(response) = self.get_response(unique_id) {
1935                return response;
1936            }
1937            match Guard::<'a, FuseConnection, MutexGuard<'a, FuseMutableState>>::unlocked(
1938                self,
1939                || waiter.wait(locked, current_task),
1940            ) {
1941                Ok(()) => {}
1942                Err(e) if e == EINTR => {
1943                    // If interrupted by another process, send an interrupt command to the server
1944                    // the first time, then wait unconditionally.
1945                    if first_loop {
1946                        self.interrupt(current_task, node.nodeid, unique_id)?;
1947                        first_loop = false;
1948                    }
1949                }
1950                Err(e) => {
1951                    log_error!("Unexpected error: {e:?}");
1952                    return Err(e);
1953                }
1954            }
1955        }
1956    }
1957}
1958
1959impl FuseMutableState {
1960    fn wait_async(
1961        &self,
1962        waiter: &Waiter,
1963        events: FdEvents,
1964        handler: EventHandler,
1965    ) -> Option<WaitCanceler> {
1966        Some(self.waiters.wait_async_fd_events(waiter, events, handler))
1967    }
1968
1969    fn is_connected(&self) -> bool {
1970        matches!(self.state, FuseConnectionState::Connected)
1971    }
1972
1973    fn set_configuration(&mut self, configuration: FuseConfiguration) {
1974        debug_assert!(self.configuration.is_none());
1975        log_trace!("Fuse configuration: {configuration:?}");
1976        self.configuration = Some(configuration);
1977        self.waiters.notify_value(CONFIGURATION_AVAILABLE_EVENT);
1978    }
1979
1980    fn connect(&mut self) {
1981        debug_assert!(matches!(self.state, FuseConnectionState::Waiting));
1982        self.state = FuseConnectionState::Connected;
1983    }
1984
1985    /// Disconnect the mount. Happens on unmount. Every filesystem operation will fail with
1986    /// ECONNABORTED, and every read/write on the /dev/fuse fd will fail with ENODEV.
1987    fn disconnect(&mut self) {
1988        if matches!(self.state, FuseConnectionState::Disconnected) {
1989            return;
1990        }
1991        self.state = FuseConnectionState::Disconnected;
1992        self.message_queue.clear();
1993        self.operations.clear();
1994        self.waiters.notify_all();
1995    }
1996
1997    /// Queue the given operation on the internal queue for the userspace daemon to read. If
1998    /// `waiter` is not None, register `waiter` to be notified when userspace responds to the
1999    /// operation. This should only be used if the operation expects a response.
2000    fn queue_operation(
2001        &mut self,
2002        current_task: &CurrentTask,
2003        nodeid: u64,
2004        operation: FuseOperation,
2005        waiter: Option<&Waiter>,
2006    ) -> Result<u64, Errno> {
2007        debug_assert!(waiter.is_some() == operation.has_response(), "{operation:?}");
2008        if !self.is_connected() {
2009            return error!(ECONNABORTED);
2010        }
2011        self.last_unique_id += 1;
2012        let message = FuseKernelMessage::new(self.last_unique_id, current_task, nodeid, operation)?;
2013        if let Some(waiter) = waiter {
2014            self.waiters.wait_async_value(waiter, self.last_unique_id);
2015        }
2016        if message.operation.has_response() {
2017            self.operations.insert(self.last_unique_id, message.operation.as_running().into());
2018        }
2019        self.message_queue.push_back(message);
2020        self.waiters.notify_fd_events(FdEvents::POLLIN);
2021        Ok(self.last_unique_id)
2022    }
2023
2024    /// Interrupt the operation with the given unique_id.
2025    ///
2026    /// If the operation is still enqueued, this will immediately dequeue the operation and return
2027    /// with an EINTR error.
2028    ///
2029    /// If not, it will send an interrupt operation.
2030    fn interrupt(
2031        &mut self,
2032        current_task: &CurrentTask,
2033        nodeid: u64,
2034        unique_id: u64,
2035    ) -> Result<(), Errno> {
2036        debug_assert!(self.operations.contains_key(&unique_id));
2037
2038        let mut in_queue = false;
2039        self.message_queue.retain(|m| {
2040            if m.header.unique == unique_id {
2041                self.operations.remove(&unique_id);
2042                in_queue = true;
2043                false
2044            } else {
2045                true
2046            }
2047        });
2048        if in_queue {
2049            // Nothing to do, the operation has been cancelled before being sent.
2050            return error!(EINTR);
2051        }
2052        self.queue_operation(current_task, nodeid, FuseOperation::Interrupt { unique_id }, None)
2053            .map(|_| ())
2054    }
2055
2056    /// Returns the response for the operation with the given identifier. Returns None if the
2057    /// operation is still in flight.
2058    fn get_response(&mut self, unique_id: u64) -> Option<Result<FuseResponse, Errno>> {
2059        match self.operations.entry(unique_id) {
2060            Entry::Vacant(_) => Some(error!(EINVAL)),
2061            Entry::Occupied(mut entry) => {
2062                let result = entry.get_mut().response.take();
2063                if result.is_some() {
2064                    entry.remove();
2065                }
2066                result
2067            }
2068        }
2069    }
2070
2071    fn query_events(&self) -> FdEvents {
2072        let mut events = FdEvents::POLLOUT;
2073        if !self.is_connected() || !self.message_queue.is_empty() {
2074            events |= FdEvents::POLLIN
2075        };
2076        if !self.is_connected() {
2077            events |= FdEvents::POLLERR;
2078        }
2079        events
2080    }
2081
2082    fn read(&mut self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
2083        match self.state {
2084            FuseConnectionState::Waiting => return error!(EPERM),
2085            FuseConnectionState::Disconnected => return error!(ENODEV),
2086            _ => {}
2087        }
2088        if let Some(message) = self.message_queue.pop_front() {
2089            message.serialize(data)
2090        } else {
2091            error!(EAGAIN)
2092        }
2093    }
2094
2095    fn write(&mut self, data: &mut dyn InputBuffer) -> Result<usize, Errno> {
2096        match self.state {
2097            FuseConnectionState::Waiting => return error!(EPERM),
2098            FuseConnectionState::Disconnected => return error!(ENODEV),
2099            _ => {}
2100        }
2101        let header: uapi::fuse_out_header = data.read_to_object()?;
2102        let payload_size = (header.len as usize)
2103            .checked_sub(std::mem::size_of::<uapi::fuse_out_header>())
2104            .ok_or_else(|| errno!(EINVAL))?;
2105        if payload_size > data.available() {
2106            return error!(EINVAL);
2107        }
2108        if header.unique == 0 {
2109            track_stub!(TODO("https://fxbug.dev/322873416"), "Fuse notification from userspace");
2110            return error!(ENOTSUP);
2111        }
2112        self.waiters.notify_value(header.unique);
2113        let mut running_operation = match self.operations.entry(header.unique) {
2114            Entry::Occupied(e) => e,
2115            Entry::Vacant(_) => return error!(EINVAL),
2116        };
2117        let operation = &running_operation.get().operation;
2118        let is_async = operation.is_async();
2119        if header.error < 0 {
2120            log_trace!("Fuse: {operation:?} -> {header:?}");
2121            let code = i16::try_from(-header.error).unwrap_or_else(|_| EINVAL.error_code() as i16);
2122            let errno = errno_from_code!(code);
2123            let response = operation.handle_error(&mut self.operations_state, errno);
2124            if is_async {
2125                running_operation.remove();
2126            } else {
2127                running_operation.get_mut().response = Some(response);
2128            }
2129        } else {
2130            let buffer = data.read_to_vec_limited(payload_size)?;
2131            if buffer.len() != payload_size {
2132                return error!(EINVAL);
2133            }
2134            let response = operation.parse_response(buffer)?;
2135            log_trace!("Fuse: {operation:?} -> {response:?}");
2136            if is_async {
2137                let operation = running_operation.remove();
2138                self.handle_async(operation, response)?;
2139            } else {
2140                running_operation.get_mut().response = Some(Ok(response));
2141            }
2142        }
2143        Ok(data.bytes_read())
2144    }
2145
2146    fn handle_async(
2147        &mut self,
2148        operation: RunningOperation,
2149        response: FuseResponse,
2150    ) -> Result<(), Errno> {
2151        match (operation.operation, response) {
2152            (RunningOperationKind::Init { fs }, FuseResponse::Init(init_out)) => {
2153                let configuration = FuseConfiguration::try_from(init_out)?;
2154                if configuration.flags.contains(FuseInitFlags::POSIX_ACL) {
2155                    // Per libfuse's documentation on `FUSE_CAP_POSIX_ACL`,
2156                    // the POSIX_ACL flag implicitly enables the
2157                    // `default_permissions` mount option.
2158                    if let Some(fs) = fs.upgrade() {
2159                        FuseFs::from_fs(&fs)
2160                            .default_permissions
2161                            .store(true, DEFAULT_PERMISSIONS_ATOMIC_ORDERING)
2162                    } else {
2163                        log_warn!("failed to upgrade FuseFs when handling FUSE_INIT response");
2164                        return error!(ENOTCONN);
2165                    }
2166                }
2167                self.set_configuration(configuration);
2168                Ok(())
2169            }
2170            operation => {
2171                // Init is the only async operation.
2172                panic!("Incompatible operation={operation:?}");
2173            }
2174        }
2175    }
2176
2177    fn clear_released_passthrough_fds(&mut self) {
2178        self.registered_passthrough.retain(|_, s| s.strong_count() > 0);
2179    }
2180}
2181
2182/// An operation that is either queued to be send to userspace, or already sent to userspace and
2183/// waiting for a response.
2184#[derive(Debug)]
2185struct RunningOperation {
2186    operation: RunningOperationKind,
2187    response: Option<Result<FuseResponse, Errno>>,
2188}
2189
2190impl From<RunningOperationKind> for RunningOperation {
2191    fn from(operation: RunningOperationKind) -> Self {
2192        Self { operation, response: None }
2193    }
2194}
2195
2196#[derive(Debug)]
2197struct FuseKernelMessage {
2198    header: uapi::fuse_in_header,
2199    operation: FuseOperation,
2200}
2201
2202impl FuseKernelMessage {
2203    fn new(
2204        unique: u64,
2205        current_task: &CurrentTask,
2206        nodeid: u64,
2207        operation: FuseOperation,
2208    ) -> Result<Self, Errno> {
2209        let current_creds = current_task.current_creds();
2210        Ok(Self {
2211            header: uapi::fuse_in_header {
2212                len: u32::try_from(std::mem::size_of::<uapi::fuse_in_header>() + operation.len())
2213                    .map_err(|_| errno!(EINVAL))?,
2214                opcode: operation.opcode(),
2215                unique,
2216                nodeid,
2217                uid: current_creds.uid,
2218                gid: current_creds.gid,
2219                pid: current_task.get_tid() as u32,
2220                __bindgen_anon_1: Default::default(),
2221            },
2222            operation,
2223        })
2224    }
2225
2226    fn serialize(&self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
2227        let size = data.write(self.header.as_bytes())?;
2228        Ok(size + self.operation.serialize(data)?)
2229    }
2230}
2231
2232bitflags::bitflags! {
2233    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2234    pub struct FuseInitFlags : u64 {
2235        const BIG_WRITES = uapi::FUSE_BIG_WRITES as u64;
2236        const DONT_MASK = uapi::FUSE_DONT_MASK as u64;
2237        const SPLICE_WRITE = uapi::FUSE_SPLICE_WRITE as u64;
2238        const SPLICE_MOVE = uapi::FUSE_SPLICE_MOVE as u64;
2239        const SPLICE_READ = uapi::FUSE_SPLICE_READ as u64;
2240        const DO_READDIRPLUS = uapi::FUSE_DO_READDIRPLUS as u64;
2241        const READDIRPLUS_AUTO = uapi::FUSE_READDIRPLUS_AUTO as u64;
2242        const SETXATTR_EXT = uapi::FUSE_SETXATTR_EXT as u64;
2243        const POSIX_ACL = uapi::FUSE_POSIX_ACL as u64;
2244        const PASSTHROUGH = uapi::FUSE_PASSTHROUGH as u64;
2245        const INIT_EXT = uapi::FUSE_INIT_EXT as u64;
2246    }
2247}
2248
2249impl TryFrom<uapi::fuse_init_out> for FuseInitFlags {
2250    type Error = Errno;
2251    fn try_from(init_out: uapi::fuse_init_out) -> Result<Self, Errno> {
2252        let flags = (init_out.flags as u64) | ((init_out.flags2 as u64) << 32);
2253        let unknown_flags = flags & !Self::all().bits();
2254        if unknown_flags != 0 {
2255            track_stub!(
2256                TODO("https://fxbug.dev/322875725"),
2257                "FUSE unknown init flags",
2258                unknown_flags
2259            );
2260            log_warn!("FUSE daemon requested unknown flags in init: {unknown_flags}");
2261        }
2262        Ok(Self::from_bits_truncate(flags))
2263    }
2264}
2265
2266impl FuseInitFlags {
2267    /// Returns the 2 u32 components for these flags. The lowest part is returned first.
2268    fn get_u32_components(&self) -> (u32, u32) {
2269        let flags = (self.bits() & (u32::max_value() as u64)) as u32;
2270        let flags2 = (self.bits() >> 32) as u32;
2271        (flags, flags2)
2272    }
2273}
2274
2275#[derive(Clone, Debug)]
2276enum RunningOperationKind {
2277    Access,
2278    Create,
2279    Flush,
2280    Forget,
2281    GetAttr,
2282    Init {
2283        /// The FUSE fs that triggered this operation.
2284        ///
2285        /// `Weak` because the `FuseFs` holds an `Arc<FuseConnection>` which
2286        /// may hold this operation.
2287        fs: Weak<FileSystem>,
2288    },
2289    Interrupt,
2290    GetXAttr {
2291        size: u32,
2292    },
2293    ListXAttr {
2294        size: u32,
2295    },
2296    Lookup,
2297    Mkdir,
2298    Mknod,
2299    Link,
2300    Open {
2301        dir: bool,
2302    },
2303    Poll,
2304    Read,
2305    Readdir {
2306        use_readdirplus: bool,
2307    },
2308    Readlink,
2309    Release {
2310        dir: bool,
2311    },
2312    RemoveXAttr,
2313    Rename,
2314    Rmdir,
2315    Seek,
2316    SetAttr,
2317    SetXAttr,
2318    Statfs,
2319    Symlink,
2320    Unlink,
2321    Write,
2322}
2323
2324impl RunningOperationKind {
2325    fn is_async(&self) -> bool {
2326        matches!(self, Self::Init { .. })
2327    }
2328
2329    fn opcode(&self) -> u32 {
2330        match self {
2331            Self::Access => uapi::fuse_opcode_FUSE_ACCESS,
2332            Self::Create => uapi::fuse_opcode_FUSE_CREATE,
2333            Self::Flush => uapi::fuse_opcode_FUSE_FLUSH,
2334            Self::Forget => uapi::fuse_opcode_FUSE_FORGET,
2335            Self::GetAttr => uapi::fuse_opcode_FUSE_GETATTR,
2336            Self::GetXAttr { .. } => uapi::fuse_opcode_FUSE_GETXATTR,
2337            Self::Init { .. } => uapi::fuse_opcode_FUSE_INIT,
2338            Self::Interrupt => uapi::fuse_opcode_FUSE_INTERRUPT,
2339            Self::ListXAttr { .. } => uapi::fuse_opcode_FUSE_LISTXATTR,
2340            Self::Lookup => uapi::fuse_opcode_FUSE_LOOKUP,
2341            Self::Mkdir => uapi::fuse_opcode_FUSE_MKDIR,
2342            Self::Mknod => uapi::fuse_opcode_FUSE_MKNOD,
2343            Self::Link => uapi::fuse_opcode_FUSE_LINK,
2344            Self::Open { dir } => {
2345                if *dir {
2346                    uapi::fuse_opcode_FUSE_OPENDIR
2347                } else {
2348                    uapi::fuse_opcode_FUSE_OPEN
2349                }
2350            }
2351            Self::Poll => uapi::fuse_opcode_FUSE_POLL,
2352            Self::Read => uapi::fuse_opcode_FUSE_READ,
2353            Self::Readdir { use_readdirplus } => {
2354                if *use_readdirplus {
2355                    uapi::fuse_opcode_FUSE_READDIRPLUS
2356                } else {
2357                    uapi::fuse_opcode_FUSE_READDIR
2358                }
2359            }
2360            Self::Readlink => uapi::fuse_opcode_FUSE_READLINK,
2361            Self::Release { dir } => {
2362                if *dir {
2363                    uapi::fuse_opcode_FUSE_RELEASEDIR
2364                } else {
2365                    uapi::fuse_opcode_FUSE_RELEASE
2366                }
2367            }
2368            Self::RemoveXAttr => uapi::fuse_opcode_FUSE_REMOVEXATTR,
2369            Self::Rename => uapi::fuse_opcode_FUSE_RENAME2,
2370            Self::Rmdir => uapi::fuse_opcode_FUSE_RMDIR,
2371            Self::Seek => uapi::fuse_opcode_FUSE_LSEEK,
2372            Self::SetAttr => uapi::fuse_opcode_FUSE_SETATTR,
2373            Self::SetXAttr => uapi::fuse_opcode_FUSE_SETXATTR,
2374            Self::Statfs => uapi::fuse_opcode_FUSE_STATFS,
2375            Self::Symlink => uapi::fuse_opcode_FUSE_SYMLINK,
2376            Self::Unlink => uapi::fuse_opcode_FUSE_UNLINK,
2377            Self::Write => uapi::fuse_opcode_FUSE_WRITE,
2378        }
2379    }
2380
2381    fn to_response<T: FromBytes + IntoBytes + Immutable>(buffer: &[u8]) -> T {
2382        let mut result = T::new_zeroed();
2383        let length_to_copy = std::cmp::min(buffer.len(), std::mem::size_of::<T>());
2384        result.as_mut_bytes()[..length_to_copy].copy_from_slice(&buffer[..length_to_copy]);
2385        result
2386    }
2387
2388    fn parse_response(&self, buffer: Vec<u8>) -> Result<FuseResponse, Errno> {
2389        match self {
2390            Self::Access => Ok(FuseResponse::Access(Ok(()))),
2391            Self::Create { .. } => {
2392                Ok(FuseResponse::Create(Self::to_response::<CreateResponse>(&buffer)))
2393            }
2394            Self::GetAttr | Self::SetAttr => {
2395                Ok(FuseResponse::Attr(Self::to_response::<uapi::fuse_attr_out>(&buffer)))
2396            }
2397            Self::GetXAttr { size } | Self::ListXAttr { size } => {
2398                if *size == 0 {
2399                    if buffer.len() < std::mem::size_of::<uapi::fuse_getxattr_out>() {
2400                        return error!(EINVAL);
2401                    }
2402                    let getxattr_out = Self::to_response::<uapi::fuse_getxattr_out>(&buffer);
2403                    Ok(FuseResponse::GetXAttr(ValueOrSize::Size(getxattr_out.size as usize)))
2404                } else {
2405                    Ok(FuseResponse::GetXAttr(FsString::new(buffer).into()))
2406                }
2407            }
2408            Self::Init { .. } => {
2409                Ok(FuseResponse::Init(Self::to_response::<uapi::fuse_init_out>(&buffer)))
2410            }
2411            Self::Lookup | Self::Mkdir | Self::Mknod | Self::Link | Self::Symlink => {
2412                Ok(FuseResponse::Entry(Self::to_response::<FuseEntryOutExtended>(&buffer)))
2413            }
2414            Self::Open { .. } => {
2415                Ok(FuseResponse::Open(Self::to_response::<uapi::fuse_open_out>(&buffer)))
2416            }
2417            Self::Poll => Ok(FuseResponse::Poll(Self::to_response::<uapi::fuse_poll_out>(&buffer))),
2418            Self::Read | Self::Readlink => Ok(FuseResponse::Read(buffer)),
2419            Self::Readdir { use_readdirplus, .. } => {
2420                let mut result = vec![];
2421                let mut slice = &buffer[..];
2422                while !slice.is_empty() {
2423                    // If using READDIRPLUS, the data starts with the entry.
2424                    let entry = if *use_readdirplus {
2425                        if slice.len() < std::mem::size_of::<uapi::fuse_entry_out>() {
2426                            return error!(EINVAL);
2427                        }
2428                        let entry = Self::to_response::<uapi::fuse_entry_out>(slice);
2429                        slice = &slice[std::mem::size_of::<uapi::fuse_entry_out>()..];
2430                        Some(entry)
2431                    } else {
2432                        None
2433                    };
2434                    // The next item is the dirent.
2435                    if slice.len() < std::mem::size_of::<uapi::fuse_dirent>() {
2436                        return error!(EINVAL);
2437                    }
2438                    let dirent = Self::to_response::<uapi::fuse_dirent>(slice);
2439                    // And it ends with the name.
2440                    slice = &slice[std::mem::size_of::<uapi::fuse_dirent>()..];
2441                    let namelen = dirent.namelen as usize;
2442                    if slice.len() < namelen {
2443                        return error!(EINVAL);
2444                    }
2445                    let name = FsString::from(&slice[..namelen]);
2446                    result.push((dirent, name, entry));
2447                    let skipped = round_up_to_increment(namelen, 8)?;
2448                    if slice.len() < skipped {
2449                        return error!(EINVAL);
2450                    }
2451                    slice = &slice[skipped..];
2452                }
2453                Ok(FuseResponse::Readdir(result))
2454            }
2455            Self::Flush
2456            | Self::Release { .. }
2457            | Self::RemoveXAttr
2458            | Self::Rename
2459            | Self::Rmdir
2460            | Self::SetXAttr
2461            | Self::Unlink => Ok(FuseResponse::None),
2462            Self::Statfs => {
2463                Ok(FuseResponse::Statfs(Self::to_response::<uapi::fuse_statfs_out>(&buffer)))
2464            }
2465            Self::Seek => {
2466                Ok(FuseResponse::Seek(Self::to_response::<uapi::fuse_lseek_out>(&buffer)))
2467            }
2468            Self::Write => {
2469                Ok(FuseResponse::Write(Self::to_response::<uapi::fuse_write_out>(&buffer)))
2470            }
2471            Self::Interrupt | Self::Forget => {
2472                panic!("Response for operation without one");
2473            }
2474        }
2475    }
2476
2477    /// Handles an error from the userspace daemon.
2478    ///
2479    /// Given the `errno` returned by the userspace daemon, returns the response the caller should
2480    /// see. This can also update the `OperationState` to allow shortcircuit on future requests.
2481    fn handle_error(
2482        &self,
2483        state: &mut OperationsState,
2484        errno: Errno,
2485    ) -> Result<FuseResponse, Errno> {
2486        match self {
2487            Self::Access if errno == ENOSYS => {
2488                // Per libfuse, ENOSYS is interpreted as a "permanent success"
2489                // so we don't need to do anything further, including performing
2490                // the default/standard file permission checks like we do
2491                // when the `default_permissions` mount option is set.
2492                const UNIMPLEMENTED_ACCESS_RESPONSE: Result<FuseResponse, Errno> =
2493                    Ok(FuseResponse::Access(Ok(())));
2494                state.insert(self.opcode(), UNIMPLEMENTED_ACCESS_RESPONSE);
2495                UNIMPLEMENTED_ACCESS_RESPONSE
2496            }
2497            Self::Flush if errno == ENOSYS => {
2498                state.insert(self.opcode(), Ok(FuseResponse::None));
2499                Ok(FuseResponse::None)
2500            }
2501            Self::Seek if errno == ENOSYS => {
2502                state.insert(self.opcode(), Err(errno.clone()));
2503                Err(errno)
2504            }
2505            Self::Poll if errno == ENOSYS => {
2506                let response = FuseResponse::Poll(uapi::fuse_poll_out {
2507                    revents: (FdEvents::POLLIN | FdEvents::POLLOUT).bits(),
2508                    padding: 0,
2509                });
2510                state.insert(self.opcode(), Ok(response.clone()));
2511                Ok(response)
2512            }
2513            _ => Err(errno),
2514        }
2515    }
2516}
2517
2518#[derive(Debug)]
2519enum FuseOperation {
2520    Access {
2521        mask: u32,
2522    },
2523    Create(uapi::fuse_create_in, FsString),
2524    Flush(uapi::fuse_open_out),
2525    Forget(uapi::fuse_forget_in),
2526    GetAttr,
2527    Init {
2528        /// The FUSE fs that triggered this operation.
2529        ///
2530        /// `Weak` because the `FuseFs` holds an `Arc<FuseConnection>` which
2531        /// may hold this operation.
2532        fs: Weak<FileSystem>,
2533    },
2534    Interrupt {
2535        /// Identifier of the operation to interrupt
2536        unique_id: u64,
2537    },
2538    GetXAttr {
2539        getxattr_in: uapi::fuse_getxattr_in,
2540        /// Name of the attribute
2541        name: FsString,
2542    },
2543    ListXAttr(uapi::fuse_getxattr_in),
2544    Lookup {
2545        /// Name of the entry to lookup
2546        name: FsString,
2547    },
2548    Mkdir {
2549        mkdir_in: uapi::fuse_mkdir_in,
2550        /// Name of the entry to create
2551        name: FsString,
2552    },
2553    Mknod {
2554        mknod_in: uapi::fuse_mknod_in,
2555        /// Name of the node to create
2556        name: FsString,
2557    },
2558    Link {
2559        link_in: uapi::fuse_link_in,
2560        /// Name of the link to create
2561        name: FsString,
2562    },
2563    Open {
2564        flags: OpenFlags,
2565        mode: FileMode,
2566    },
2567    Poll(uapi::fuse_poll_in),
2568    Read(uapi::fuse_read_in),
2569    Readdir {
2570        read_in: uapi::fuse_read_in,
2571        /// Whether to use the READDIRPLUS api
2572        use_readdirplus: bool,
2573    },
2574    Readlink,
2575    Release(uapi::fuse_open_out),
2576    ReleaseDir(uapi::fuse_open_out),
2577    RemoveXAttr {
2578        /// Name of the attribute
2579        name: FsString,
2580    },
2581    Rename {
2582        old_name: FsString,
2583        new_dir: u64,
2584        new_name: FsString,
2585    },
2586    Rmdir {
2587        name: FsString,
2588    },
2589    Seek(uapi::fuse_lseek_in),
2590    SetAttr(uapi::fuse_setattr_in),
2591    SetXAttr {
2592        setxattr_in: uapi::fuse_setxattr_in,
2593        /// Indicates if userspace supports the, most-recent/extended variant of
2594        /// `fuse_setxattr_in`.
2595        is_ext: bool,
2596        /// Name of the attribute
2597        name: FsString,
2598        /// Value of the attribute
2599        value: FsString,
2600    },
2601    Statfs,
2602    Symlink {
2603        /// Target of the link
2604        target: FsString,
2605        /// Name of the link
2606        name: FsString,
2607    },
2608    Unlink {
2609        /// Name of the file to unlink
2610        name: FsString,
2611    },
2612    Write {
2613        write_in: uapi::fuse_write_in,
2614        // Content to write
2615        content: Vec<u8>,
2616    },
2617}
2618
2619#[derive(Clone, Debug)]
2620enum FuseResponse {
2621    Access(Result<(), Errno>),
2622    Attr(uapi::fuse_attr_out),
2623    Create(CreateResponse),
2624    Entry(FuseEntryOutExtended),
2625    GetXAttr(ValueOrSize<FsString>),
2626    Init(uapi::fuse_init_out),
2627    Open(uapi::fuse_open_out),
2628    Poll(uapi::fuse_poll_out),
2629    Read(
2630        // Content read
2631        Vec<u8>,
2632    ),
2633    Seek(uapi::fuse_lseek_out),
2634    Readdir(Vec<(uapi::fuse_dirent, FsString, Option<uapi::fuse_entry_out>)>),
2635    Statfs(uapi::fuse_statfs_out),
2636    Write(uapi::fuse_write_out),
2637    None,
2638}
2639
2640impl FuseResponse {
2641    fn entry(&self) -> Option<&uapi::fuse_entry_out> {
2642        if let Self::Entry(entry) = self { Some(&entry.arg) } else { None }
2643    }
2644}
2645
2646#[repr(C)]
2647#[derive(Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable)]
2648struct CreateResponse {
2649    entry: uapi::fuse_entry_out,
2650    open: uapi::fuse_open_out,
2651}
2652
2653static_assertions::const_assert_eq!(
2654    std::mem::offset_of!(CreateResponse, open),
2655    std::mem::size_of::<uapi::fuse_entry_out>()
2656);
2657
2658#[repr(C)]
2659#[derive(Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable)]
2660struct FuseEntryOutExtended {
2661    arg: uapi::fuse_entry_out,
2662    bpf_arg: uapi::fuse_entry_bpf_out,
2663}
2664
2665static_assertions::const_assert_eq!(
2666    std::mem::offset_of!(FuseEntryOutExtended, bpf_arg),
2667    std::mem::size_of::<uapi::fuse_entry_out>()
2668);
2669
2670impl FuseOperation {
2671    fn serialize(&self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
2672        match self {
2673            Self::Access { mask } => {
2674                let message = uapi::fuse_access_in { mask: *mask, padding: 0 };
2675                data.write_all(message.as_bytes())
2676            }
2677            Self::Create(create_in, name) => {
2678                Ok(data.write_all(create_in.as_bytes())? + Self::write_null_terminated(data, name)?)
2679            }
2680            Self::Flush(open_in) => {
2681                let message =
2682                    uapi::fuse_flush_in { fh: open_in.fh, unused: 0, padding: 0, lock_owner: 0 };
2683                data.write_all(message.as_bytes())
2684            }
2685            Self::Forget(forget_in) => data.write_all(forget_in.as_bytes()),
2686            Self::GetAttr | Self::Readlink | Self::Statfs => Ok(0),
2687            Self::GetXAttr { getxattr_in, name } => {
2688                let mut len = data.write_all(getxattr_in.as_bytes())?;
2689                len += Self::write_null_terminated(data, name)?;
2690                Ok(len)
2691            }
2692            Self::Init { .. } => {
2693                let (flags, flags2) = FuseInitFlags::all().get_u32_components();
2694                let message = uapi::fuse_init_in {
2695                    major: uapi::FUSE_KERNEL_VERSION,
2696                    minor: uapi::FUSE_KERNEL_MINOR_VERSION,
2697                    flags,
2698                    flags2,
2699                    ..Default::default()
2700                };
2701                data.write_all(message.as_bytes())
2702            }
2703            Self::Interrupt { unique_id } => {
2704                let message = uapi::fuse_interrupt_in { unique: *unique_id };
2705                data.write_all(message.as_bytes())
2706            }
2707            Self::ListXAttr(getxattr_in) => data.write_all(getxattr_in.as_bytes()),
2708            Self::Lookup { name } => Self::write_null_terminated(data, name),
2709            Self::Open { flags, .. } => {
2710                let message = uapi::fuse_open_in { flags: flags.bits(), open_flags: 0 };
2711                data.write_all(message.as_bytes())
2712            }
2713            Self::Poll(poll_in) => data.write_all(poll_in.as_bytes()),
2714            Self::Mkdir { mkdir_in, name } => {
2715                let mut len = data.write_all(mkdir_in.as_bytes())?;
2716                len += Self::write_null_terminated(data, name)?;
2717                Ok(len)
2718            }
2719            Self::Mknod { mknod_in, name } => {
2720                let mut len = data.write_all(mknod_in.as_bytes())?;
2721                len += Self::write_null_terminated(data, name)?;
2722                Ok(len)
2723            }
2724            Self::Link { link_in, name } => {
2725                let mut len = data.write_all(link_in.as_bytes())?;
2726                len += Self::write_null_terminated(data, name)?;
2727                Ok(len)
2728            }
2729            Self::Read(read_in) | Self::Readdir { read_in, .. } => {
2730                data.write_all(read_in.as_bytes())
2731            }
2732            Self::Release(open_out) | Self::ReleaseDir(open_out) => {
2733                let message = uapi::fuse_release_in {
2734                    fh: open_out.fh,
2735                    flags: 0,
2736                    release_flags: 0,
2737                    lock_owner: 0,
2738                };
2739                data.write_all(message.as_bytes())
2740            }
2741            Self::RemoveXAttr { name } => Self::write_null_terminated(data, name),
2742            Self::Rename { old_name, new_dir, new_name } => {
2743                Ok(data.write_all(
2744                    uapi::fuse_rename2_in { newdir: *new_dir, flags: 0, padding: 0 }.as_bytes(),
2745                )? + Self::write_null_terminated(data, old_name)?
2746                    + Self::write_null_terminated(data, new_name)?)
2747            }
2748            Self::Seek(seek_in) => data.write_all(seek_in.as_bytes()),
2749            Self::SetAttr(setattr_in) => data.write_all(setattr_in.as_bytes()),
2750            Self::SetXAttr { setxattr_in, is_ext, name, value } => {
2751                let header =
2752                    if *is_ext { setxattr_in.as_bytes() } else { &setxattr_in.as_bytes()[..8] };
2753                let mut len = data.write_all(header)?;
2754                len += Self::write_null_terminated(data, name)?;
2755                len += data.write_all(value.as_bytes())?;
2756                Ok(len)
2757            }
2758            Self::Symlink { target, name } => {
2759                let mut len = Self::write_null_terminated(data, name)?;
2760                len += Self::write_null_terminated(data, target)?;
2761                Ok(len)
2762            }
2763            Self::Rmdir { name } | Self::Unlink { name } => Self::write_null_terminated(data, name),
2764            &Self::Write { mut write_in, ref content } => {
2765                let mut write_in_size = write_in.size as usize;
2766                assert!(write_in_size == content.len());
2767                if write_in_size + write_in.as_bytes().len() > data.available() {
2768                    write_in_size = data.available() - write_in.as_bytes().len();
2769                    write_in.size = write_in_size as u32;
2770                }
2771                let mut len = data.write_all(write_in.as_bytes())?;
2772                len += data.write_all(&content[..write_in_size])?;
2773                Ok(len)
2774            }
2775        }
2776    }
2777
2778    fn write_null_terminated(
2779        data: &mut dyn OutputBuffer,
2780        content: &Vec<u8>,
2781    ) -> Result<usize, Errno> {
2782        let mut len = data.write_all(content.as_bytes())?;
2783        len += data.write_all(&[0])?;
2784        Ok(len)
2785    }
2786
2787    fn opcode(&self) -> u32 {
2788        match self {
2789            Self::Access { .. } => uapi::fuse_opcode_FUSE_ACCESS,
2790            Self::Create { .. } => uapi::fuse_opcode_FUSE_CREATE,
2791            Self::Flush(_) => uapi::fuse_opcode_FUSE_FLUSH,
2792            Self::Forget(_) => uapi::fuse_opcode_FUSE_FORGET,
2793            Self::GetAttr => uapi::fuse_opcode_FUSE_GETATTR,
2794            Self::GetXAttr { .. } => uapi::fuse_opcode_FUSE_GETXATTR,
2795            Self::Init { .. } => uapi::fuse_opcode_FUSE_INIT,
2796            Self::Interrupt { .. } => uapi::fuse_opcode_FUSE_INTERRUPT,
2797            Self::ListXAttr(_) => uapi::fuse_opcode_FUSE_LISTXATTR,
2798            Self::Lookup { .. } => uapi::fuse_opcode_FUSE_LOOKUP,
2799            Self::Mkdir { .. } => uapi::fuse_opcode_FUSE_MKDIR,
2800            Self::Mknod { .. } => uapi::fuse_opcode_FUSE_MKNOD,
2801            Self::Link { .. } => uapi::fuse_opcode_FUSE_LINK,
2802            Self::Open { flags, mode } => {
2803                if mode.is_dir() || flags.contains(OpenFlags::DIRECTORY) {
2804                    uapi::fuse_opcode_FUSE_OPENDIR
2805                } else {
2806                    uapi::fuse_opcode_FUSE_OPEN
2807                }
2808            }
2809            Self::Poll(_) => uapi::fuse_opcode_FUSE_POLL,
2810            Self::Read(_) => uapi::fuse_opcode_FUSE_READ,
2811            Self::Readdir { use_readdirplus, .. } => {
2812                if *use_readdirplus {
2813                    uapi::fuse_opcode_FUSE_READDIRPLUS
2814                } else {
2815                    uapi::fuse_opcode_FUSE_READDIR
2816                }
2817            }
2818            Self::Readlink => uapi::fuse_opcode_FUSE_READLINK,
2819            Self::Release(_) => uapi::fuse_opcode_FUSE_RELEASE,
2820            Self::ReleaseDir(_) => uapi::fuse_opcode_FUSE_RELEASEDIR,
2821            Self::RemoveXAttr { .. } => uapi::fuse_opcode_FUSE_REMOVEXATTR,
2822            Self::Rename { .. } => uapi::fuse_opcode_FUSE_RENAME2,
2823            Self::Rmdir { .. } => uapi::fuse_opcode_FUSE_RMDIR,
2824            Self::Seek(_) => uapi::fuse_opcode_FUSE_LSEEK,
2825            Self::SetAttr(_) => uapi::fuse_opcode_FUSE_SETATTR,
2826            Self::SetXAttr { .. } => uapi::fuse_opcode_FUSE_SETXATTR,
2827            Self::Statfs => uapi::fuse_opcode_FUSE_STATFS,
2828            Self::Symlink { .. } => uapi::fuse_opcode_FUSE_SYMLINK,
2829            Self::Unlink { .. } => uapi::fuse_opcode_FUSE_UNLINK,
2830            Self::Write { .. } => uapi::fuse_opcode_FUSE_WRITE,
2831        }
2832    }
2833
2834    fn as_running(&self) -> RunningOperationKind {
2835        match self {
2836            Self::Access { .. } => RunningOperationKind::Access,
2837            Self::Create { .. } => RunningOperationKind::Create,
2838            Self::Flush(_) => RunningOperationKind::Flush,
2839            Self::Forget(_) => RunningOperationKind::Forget,
2840            Self::GetAttr => RunningOperationKind::GetAttr,
2841            Self::GetXAttr { getxattr_in, .. } => {
2842                RunningOperationKind::GetXAttr { size: getxattr_in.size }
2843            }
2844            Self::Init { fs } => RunningOperationKind::Init { fs: fs.clone() },
2845            Self::Interrupt { .. } => RunningOperationKind::Interrupt,
2846            Self::ListXAttr(getxattr_in) => {
2847                RunningOperationKind::ListXAttr { size: getxattr_in.size }
2848            }
2849            Self::Lookup { .. } => RunningOperationKind::Lookup,
2850            Self::Mkdir { .. } => RunningOperationKind::Mkdir,
2851            Self::Mknod { .. } => RunningOperationKind::Mknod,
2852            Self::Link { .. } => RunningOperationKind::Link,
2853            Self::Open { flags, mode } => RunningOperationKind::Open {
2854                dir: mode.is_dir() || flags.contains(OpenFlags::DIRECTORY),
2855            },
2856            Self::Poll(_) => RunningOperationKind::Poll,
2857            Self::Read(_) => RunningOperationKind::Read,
2858            Self::Readdir { use_readdirplus, .. } => {
2859                RunningOperationKind::Readdir { use_readdirplus: *use_readdirplus }
2860            }
2861            Self::Readlink => RunningOperationKind::Readlink,
2862            Self::Release(_) => RunningOperationKind::Release { dir: false },
2863            Self::ReleaseDir(_) => RunningOperationKind::Release { dir: true },
2864            Self::RemoveXAttr { .. } => RunningOperationKind::RemoveXAttr,
2865            Self::Rename { .. } => RunningOperationKind::Rename,
2866            Self::Rmdir { .. } => RunningOperationKind::Rmdir,
2867            Self::Seek(_) => RunningOperationKind::Seek,
2868            Self::SetAttr(_) => RunningOperationKind::SetAttr,
2869            Self::SetXAttr { .. } => RunningOperationKind::SetXAttr,
2870            Self::Statfs => RunningOperationKind::Statfs,
2871            Self::Symlink { .. } => RunningOperationKind::Symlink,
2872            Self::Unlink { .. } => RunningOperationKind::Unlink,
2873            Self::Write { .. } => RunningOperationKind::Write,
2874        }
2875    }
2876
2877    fn len(&self) -> usize {
2878        #[derive(Debug, Default)]
2879        struct CountingOutputBuffer {
2880            written: usize,
2881        }
2882
2883        impl Buffer for CountingOutputBuffer {
2884            fn segments_count(&self) -> Result<usize, Errno> {
2885                panic!("Should not be called");
2886            }
2887
2888            fn peek_each_segment(
2889                &mut self,
2890                _callback: &mut PeekBufferSegmentsCallback<'_>,
2891            ) -> Result<(), Errno> {
2892                panic!("Should not be called");
2893            }
2894        }
2895
2896        impl OutputBuffer for CountingOutputBuffer {
2897            fn available(&self) -> usize {
2898                usize::MAX
2899            }
2900
2901            fn bytes_written(&self) -> usize {
2902                self.written
2903            }
2904
2905            fn zero(&mut self) -> Result<usize, Errno> {
2906                panic!("Should not be called");
2907            }
2908
2909            fn write_each(
2910                &mut self,
2911                _callback: &mut OutputBufferCallback<'_>,
2912            ) -> Result<usize, Errno> {
2913                panic!("Should not be called.");
2914            }
2915
2916            fn write_all(&mut self, buffer: &[u8]) -> Result<usize, Errno> {
2917                self.written += buffer.len();
2918                Ok(buffer.len())
2919            }
2920
2921            unsafe fn advance(&mut self, _length: usize) -> Result<(), Errno> {
2922                panic!("Should not be called.");
2923            }
2924        }
2925
2926        let mut counting_output_buffer = CountingOutputBuffer::default();
2927        self.serialize(&mut counting_output_buffer).expect("Serialization should not fail");
2928        counting_output_buffer.written
2929    }
2930
2931    fn has_response(&self) -> bool {
2932        !matches!(self, Self::Interrupt { .. } | Self::Forget(_))
2933    }
2934
2935    fn is_async(&self) -> bool {
2936        matches!(self, Self::Init { .. })
2937    }
2938}