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