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