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