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