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