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