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