1use super::Fuse;
5use super::Mapper;
6use super::protocol::*;
7use super::reply::ReplySender;
8use super::request::FuseOperation;
9use super::request::Request;
10use super::request::RequestReader;
11use parking_lot::RwLock;
12use std::io;
13use std::sync::atomic;
14use thiserror::Error;
15use zerocopy::FromZeros;
16use zerocopy::Immutable;
17use zerocopy::KnownLayout;
18
19const DEFAULT_FLAGS: u32 = FUSE_ASYNC_READ
21 | FUSE_PARALLEL_DIROPS
22 | FUSE_AUTO_INVAL_DATA
23 | FUSE_HANDLE_KILLPRIV
24 | FUSE_ASYNC_DIO
25 | FUSE_ATOMIC_O_TRUNC
26 | FUSE_BIG_WRITES
27 | FUSE_MAX_PAGES
28 | FUSE_INIT_EXT;
29
30const DEFAULT_FLAGS2: u32 = 0;
34
35const DEFAULT_MAX_PAGES: u32 = 256;
36
37const PAGE_SIZE: u32 = 4096;
41
42pub struct Session {
46 fs: Box<dyn Fuse + Send + Sync>,
47 initialized: atomic::AtomicBool,
50 info: RwLock<SessionInfo>,
51}
52
53impl Session {
54 pub fn new<T>(fs: T) -> Self
56 where
57 T: 'static + Fuse + Send + Sync,
58 {
59 Self {
60 fs: Box::new(fs),
61 initialized: atomic::AtomicBool::new(false),
62 info: RwLock::new(SessionInfo::default()),
63 }
64 }
65
66 pub fn is_initialized(&self) -> bool {
70 self.initialized.load(atomic::Ordering::Acquire)
71 }
72
73 pub fn dispatch(
75 &self,
76 request: Request,
77 sender: &mut impl ReplySender,
78 mapper: Option<&dyn Mapper>,
79 ) {
80 let unique = request.unique();
81 let result = if self.is_initialized() {
82 self.dispatch_helper(request, sender, mapper)
83 } else {
84 self.dispatch_init(request, sender)
85 };
86
87 match result {
88 Err(OperationError::FsError(e)) => {
89 if let Err(e) = sender.send_error(unique, e.value()) {
90 tracing::error!(
91 unique,
92 error = &e as &dyn std::error::Error,
93 "Failed to send reply",
94 );
95 }
96 }
97 Err(OperationError::SendError(e)) => {
98 if e.kind() == io::ErrorKind::NotFound {
99 tracing::trace!(unique, "Request was interrupted.");
100 } else {
101 tracing::error!(
102 unique,
103 error = &e as &dyn std::error::Error,
104 "Failed to send reply",
105 );
106 }
107 }
108 Ok(_) => (),
109 }
110 }
111
112 pub fn destroy(&self) {
119 if self.initialized.swap(false, atomic::Ordering::AcqRel) {
120 self.fs.destroy();
121 }
122 }
123
124 fn dispatch_helper(
127 &self,
128 request: Request,
129 sender: &mut impl ReplySender,
130 mapper: Option<&dyn Mapper>,
131 ) -> Result<(), OperationError> {
132 request.log();
133
134 match request.operation() {
135 FuseOperation::Invalid => {
136 return Err(lx::Error::EIO.into());
139 }
140 FuseOperation::Error(e) => {
141 return Err((*e).into());
144 }
145 FuseOperation::Lookup { name } => {
146 let out = self.fs.lookup(&request, name)?;
147 sender.send_arg(request.unique(), out)?;
148 }
149 FuseOperation::Forget { arg } => {
150 self.fs.forget(request.node_id(), arg.nlookup);
151 }
152 FuseOperation::GetAttr { arg } => {
153 let out = self.fs.get_attr(&request, arg.getattr_flags, arg.fh)?;
154 sender.send_arg(request.unique(), out)?;
155 }
156 FuseOperation::SetAttr { arg } => {
157 let out = self.fs.set_attr(&request, arg)?;
158 sender.send_arg(request.unique(), out)?;
159 }
160 FuseOperation::ReadLink {} => {
161 let out = self.fs.read_link(&request)?;
162 sender.send_string(request.unique(), out)?;
163 }
164 FuseOperation::Symlink { name, target } => {
165 let out = self.fs.symlink(&request, name, target)?;
166 sender.send_arg(request.unique(), out)?;
167 }
168 FuseOperation::MkNod { arg, name } => {
169 let out = self.fs.mknod(&request, name, arg)?;
170 sender.send_arg(request.unique(), out)?;
171 }
172 FuseOperation::MkDir { arg, name } => {
173 let out = self.fs.mkdir(&request, name, arg)?;
174 sender.send_arg(request.unique(), out)?;
175 }
176 FuseOperation::Unlink { name } => {
177 self.fs.unlink(&request, name)?;
178 sender.send_empty(request.unique())?;
179 }
180 FuseOperation::RmDir { name } => {
181 self.fs.rmdir(&request, name)?;
182 sender.send_empty(request.unique())?;
183 }
184 FuseOperation::Rename {
185 arg,
186 name,
187 new_name,
188 } => {
189 self.fs.rename(&request, name, arg.newdir, new_name, 0)?;
190
191 sender.send_empty(request.unique())?;
192 }
193 FuseOperation::Link { arg, name } => {
194 let out = self.fs.link(&request, name, arg.oldnodeid)?;
195 sender.send_arg(request.unique(), out)?;
196 }
197 FuseOperation::Open { arg } => {
198 let out = self.fs.open(&request, arg.flags)?;
199 self.send_release_if_interrupted(&request, sender, out.fh, arg.flags, out, false)?;
200 }
201 FuseOperation::Read { arg } => {
202 let out = self.fs.read(&request, arg)?;
203 Self::send_max_size(sender, request.unique(), &out, arg.size)?;
204 }
205 FuseOperation::Write { arg, data } => {
206 let out = self.fs.write(&request, arg, data)?;
207 sender.send_arg(
208 request.unique(),
209 fuse_write_out {
210 size: out.try_into().unwrap(),
211 padding: 0,
212 },
213 )?;
214 }
215 FuseOperation::StatFs {} => {
216 let out = self.fs.statfs(&request)?;
217 sender.send_arg(request.unique(), fuse_statfs_out { st: out })?;
218 }
219 FuseOperation::Release { arg } => {
220 self.fs.release(&request, arg)?;
221 sender.send_empty(request.unique())?;
222 }
223 FuseOperation::FSync { arg } => {
224 self.fs.fsync(&request, arg.fh, arg.fsync_flags)?;
225 sender.send_empty(request.unique())?;
226 }
227 FuseOperation::SetXAttr { arg, name, value } => {
228 self.fs.set_xattr(&request, name, value, arg.flags)?;
229 sender.send_empty(request.unique())?;
230 }
231 FuseOperation::GetXAttr { arg, name } => {
232 if arg.size == 0 {
233 let out = self.fs.get_xattr_size(&request, name)?;
234 sender.send_arg(
235 request.unique(),
236 fuse_getxattr_out {
237 size: out,
238 padding: 0,
239 },
240 )?;
241 } else {
242 let out = self.fs.get_xattr(&request, name, arg.size)?;
243 Self::send_max_size(sender, request.unique(), &out, arg.size)?;
244 }
245 }
246 FuseOperation::ListXAttr { arg } => {
247 if arg.size == 0 {
248 let out = self.fs.list_xattr_size(&request)?;
249 sender.send_arg(
250 request.unique(),
251 fuse_getxattr_out {
252 size: out,
253 padding: 0,
254 },
255 )?;
256 } else {
257 let out = self.fs.list_xattr(&request, arg.size)?;
258 Self::send_max_size(sender, request.unique(), &out, arg.size)?;
259 }
260 }
261 FuseOperation::RemoveXAttr { name } => {
262 self.fs.remove_xattr(&request, name)?;
263 sender.send_empty(request.unique())?;
264 }
265 FuseOperation::Flush { arg } => {
266 self.fs.flush(&request, arg)?;
267 sender.send_empty(request.unique())?;
268 }
269 FuseOperation::Init { arg: _ } => {
270 tracing::warn!("Duplicate init message.");
271 return Err(lx::Error::EIO.into());
272 }
273 FuseOperation::OpenDir { arg } => {
274 let out = self.fs.open_dir(&request, arg.flags)?;
275 self.send_release_if_interrupted(&request, sender, out.fh, arg.flags, out, true)?;
276 }
277 FuseOperation::ReadDir { arg } => {
278 let out = self.fs.read_dir(&request, arg)?;
279 Self::send_max_size(sender, request.unique(), &out, arg.size)?;
280 }
281 FuseOperation::ReleaseDir { arg } => {
282 self.fs.release_dir(&request, arg)?;
283 sender.send_empty(request.unique())?;
284 }
285 FuseOperation::FSyncDir { arg } => {
286 self.fs.fsync_dir(&request, arg.fh, arg.fsync_flags)?;
287 sender.send_empty(request.unique())?;
288 }
289 FuseOperation::GetLock { arg } => {
290 let out = self.fs.get_lock(&request, arg)?;
291 sender.send_arg(request.unique(), out)?;
292 }
293 FuseOperation::SetLock { arg } => {
294 self.fs.set_lock(&request, arg, false)?;
295 sender.send_empty(request.unique())?;
296 }
297 FuseOperation::SetLockSleep { arg } => {
298 self.fs.set_lock(&request, arg, true)?;
299 sender.send_empty(request.unique())?;
300 }
301 FuseOperation::Access { arg } => {
302 self.fs.access(&request, arg.mask)?;
303 sender.send_empty(request.unique())?;
304 }
305 FuseOperation::Create { arg, name } => {
306 let out = self.fs.create(&request, name, arg)?;
307 self.send_release_if_interrupted(
308 &request,
309 sender,
310 out.open.fh,
311 arg.flags,
312 out,
313 false,
314 )?;
315 }
316 FuseOperation::Interrupt { arg: _ } => {
317 tracing::warn!("FUSE_INTERRUPT not supported.");
320 return Err(lx::Error::ENOSYS.into());
321 }
322 FuseOperation::BMap { arg } => {
323 let out = self.fs.block_map(&request, arg.block, arg.blocksize)?;
324 sender.send_arg(request.unique(), fuse_bmap_out { block: out })?;
325 }
326 FuseOperation::Destroy {} => {
327 if let Some(mapper) = mapper {
328 mapper.clear();
329 }
330 self.destroy();
331 sender.send_empty(request.unique())?;
332 }
333 FuseOperation::Ioctl { arg, data } => {
334 let out = self.fs.ioctl(&request, arg, data)?;
335 if out.1.len() > arg.out_size as usize {
336 return Err(lx::Error::EINVAL.into());
337 }
338
339 sender.send_arg_data(
341 request.unique(),
342 fuse_ioctl_out {
343 result: out.0,
344 flags: 0,
345 in_iovs: 0,
346 out_iovs: 0,
347 },
348 data,
349 )?;
350 }
351 FuseOperation::Poll { arg: _ } => {
352 tracing::warn!("FUSE_POLL not supported.");
356 return Err(lx::Error::ENOSYS.into());
357 }
358 FuseOperation::NotifyReply { arg: _, data: _ } => {
359 tracing::warn!("FUSE_NOTIFY_REPLY not supported.");
361 return Err(lx::Error::ENOSYS.into());
362 }
363 FuseOperation::BatchForget { arg, nodes } => {
364 self.batch_forget(arg.count, nodes);
365 }
366 FuseOperation::FAllocate { arg } => {
367 self.fs.fallocate(&request, arg)?;
368 sender.send_empty(request.unique())?;
369 }
370 FuseOperation::ReadDirPlus { arg } => {
371 let out = self.fs.read_dir_plus(&request, arg)?;
372 Self::send_max_size(sender, request.unique(), &out, arg.size)?;
373 }
374 FuseOperation::Rename2 {
375 arg,
376 name,
377 new_name,
378 } => {
379 self.fs
380 .rename(&request, name, arg.newdir, new_name, arg.flags)?;
381
382 sender.send_empty(request.unique())?;
383 }
384 FuseOperation::LSeek { arg } => {
385 let out = self.fs.lseek(&request, arg.fh, arg.offset, arg.whence)?;
386 sender.send_arg(request.unique(), fuse_lseek_out { offset: out })?;
387 }
388 FuseOperation::CopyFileRange { arg } => {
389 let out = self.fs.copy_file_range(&request, arg)?;
390 sender.send_arg(
391 request.unique(),
392 fuse_write_out {
393 size: out.try_into().unwrap(),
394 padding: 0,
395 },
396 )?;
397 }
398 FuseOperation::SetupMapping { arg } => {
399 if let Some(mapper) = mapper {
400 self.fs.setup_mapping(&request, mapper, arg)?;
401 sender.send_empty(request.unique())?;
402 } else {
403 return Err(lx::Error::ENOSYS.into());
404 }
405 }
406 FuseOperation::RemoveMapping { arg, mappings } => {
407 if let Some(mapper) = mapper {
408 self.remove_mapping(&request, mapper, arg.count, mappings)?;
409 sender.send_empty(request.unique())?;
410 } else {
411 return Err(lx::Error::ENOSYS.into());
412 }
413 }
414 FuseOperation::SyncFs { _arg } => {
415 sender.send_empty(request.unique())?;
417 }
418 FuseOperation::StatX { arg } => {
419 let out = self.fs.get_statx(
420 &request,
421 arg.fh,
422 arg.getattr_flags,
423 arg.flags,
424 arg.mask.into(),
425 )?;
426 sender.send_arg(request.unique(), out)?;
427 }
428 FuseOperation::CanonicalPath {} => {
429 tracing::trace!("Unsupported opcode FUSE_CANONICAL_PATH");
433 sender.send_error(request.unique(), lx::Error::ENOSYS.value())?;
434 }
435 }
436
437 Ok(())
438 }
439
440 fn dispatch_init(
442 &self,
443 request: Request,
444 sender: &mut impl ReplySender,
445 ) -> Result<(), OperationError> {
446 request.log();
447 let init: &fuse_init_in = if let FuseOperation::Init { arg } = request.operation() {
448 arg
449 } else {
450 tracing::error!(opcode = request.opcode(), "Expected FUSE_INIT");
451 return Err(lx::Error::EIO.into());
452 };
453
454 let mut info = self.info.write();
455 if self.is_initialized() {
456 tracing::error!("Racy FUSE_INIT requests.");
457 return Err(lx::Error::EIO.into());
458 }
459
460 let mut out = fuse_init_out::new_zeroed();
461 out.major = FUSE_KERNEL_VERSION;
462 out.minor = FUSE_KERNEL_MINOR_VERSION;
463
464 if init.major > FUSE_KERNEL_VERSION {
467 sender.send_arg(request.unique(), out)?;
468 return Ok(());
469 }
470
471 if init.major < FUSE_KERNEL_VERSION || init.minor < 27 {
474 tracing::error!(
475 major = init.major,
476 minor = init.minor,
477 "Got unsupported kernel version",
478 );
479 return Err(lx::Error::EIO.into());
480 }
481
482 info.major = init.major;
484 info.minor = init.minor;
485 info.max_readahead = init.max_readahead;
486 info.capable = init.flags;
487 info.want = DEFAULT_FLAGS & init.flags;
488 info.want2 = 0;
489 info.capable2 = 0;
490 if init.flags & FUSE_INIT_EXT != 0 {
492 info.capable2 = init.flags2;
493 info.want2 = DEFAULT_FLAGS2 & init.flags2;
494 }
495 info.time_gran = 1;
496 info.max_write = DEFAULT_MAX_PAGES * PAGE_SIZE;
497 self.fs.init(&mut info);
498
499 assert!(info.want & !info.capable == 0);
500 if info.want & FUSE_INIT_EXT == 0 {
503 info.want2 = 0;
504 }
505 assert!(info.want2 & !info.capable2 == 0);
506
507 out.max_readahead = info.max_readahead;
510 out.flags = info.want;
511 out.max_background = info.max_background;
512 out.congestion_threshold = info.congestion_threshold;
513 out.max_write = info.max_write;
514 out.time_gran = info.time_gran;
515 out.max_pages = info.max_write.div_ceil(PAGE_SIZE).min(u16::MAX as u32) as u16;
516 if info.want & FUSE_INIT_EXT != 0 {
518 out.flags2 = info.want2;
519 }
520
521 sender.send_arg(request.unique(), out)?;
522
523 self.initialized.store(true, atomic::Ordering::Release);
525 Ok(())
526 }
527
528 fn send_release_if_interrupted<
530 TArg: zerocopy::IntoBytes + std::fmt::Debug + Immutable + KnownLayout,
531 >(
532 &self,
533 request: &Request,
534 sender: &mut impl ReplySender,
535 fh: u64,
536 flags: u32,
537 arg: TArg,
538 dir: bool,
539 ) -> lx::Result<()> {
540 if let Err(e) = sender.send_arg(request.unique(), arg) {
541 if e.kind() == io::ErrorKind::NotFound {
544 let arg = fuse_release_in {
545 fh,
546 flags,
547 release_flags: 0,
548 lock_owner: 0,
549 };
550
551 if dir {
552 self.fs.release_dir(request, &arg)?;
553 } else {
554 self.fs.release(request, &arg)?;
555 }
556 } else {
557 return Err(e.into());
558 }
559 }
560
561 Ok(())
562 }
563
564 fn send_max_size(
568 sender: &mut impl ReplySender,
569 unique: u64,
570 data: &[u8],
571 max_size: u32,
572 ) -> Result<(), OperationError> {
573 assert!(data.len() <= max_size as usize);
574 sender.send_data(unique, data)?;
575 Ok(())
576 }
577
578 fn batch_forget(&self, count: u32, mut nodes: &[u8]) {
580 for _ in 0..count {
581 let forget: fuse_forget_one = match nodes.read_type() {
582 Ok(f) => f,
583 Err(_) => break,
584 };
585
586 self.fs.forget(forget.nodeid, forget.nlookup);
587 }
588 }
589
590 fn remove_mapping(
592 &self,
593 request: &Request,
594 mapper: &dyn Mapper,
595 count: u32,
596 mut mappings: &[u8],
597 ) -> lx::Result<()> {
598 for _ in 0..count {
599 let mapping: fuse_removemapping_one = mappings.read_type()?;
600 self.fs
601 .remove_mapping(request, mapper, mapping.moffset, mapping.len)?;
602 }
603
604 Ok(())
605 }
606}
607
608#[derive(Default)]
610pub struct SessionInfo {
611 major: u32,
612 minor: u32,
613 pub max_readahead: u32,
614 capable: u32,
615 capable2: u32,
616 pub want: u32,
617 pub want2: u32,
619 pub max_background: u16,
620 pub congestion_threshold: u16,
621 pub max_write: u32,
622 pub time_gran: u32,
623}
624
625impl SessionInfo {
626 pub fn major(&self) -> u32 {
627 self.major
628 }
629
630 pub fn minor(&self) -> u32 {
631 self.minor
632 }
633
634 pub fn capable(&self) -> u32 {
635 self.capable
636 }
637
638 pub fn capable2(&self) -> u32 {
639 self.capable2
640 }
641}
642
643#[derive(Debug, Error)]
644enum OperationError {
645 #[error("File system error")]
646 FsError(#[from] lx::Error),
647 #[error("Send error")]
648 SendError(#[from] io::Error),
649}
650
651#[cfg(test)]
652mod tests {
653 use super::*;
654 use crate::request::tests::*;
655 use parking_lot::Mutex;
656 use std::sync::Arc;
657 use zerocopy::FromBytes;
658 use zerocopy::IntoBytes;
659
660 #[test]
661 fn dispatch_error_name_too_long() {
662 let fs = TestFs::default();
663 let session = Session::new(fs);
664
665 let mut init_sender = MockSender::default();
667 session.dispatch(
668 Request::new(FUSE_INIT_REQUEST).unwrap(),
669 &mut init_sender,
670 None,
671 );
672 assert!(session.is_initialized());
673
674 let mut error_sender = ErrorCheckingSender::default();
676 let lookup_data = make_lookup_name_too_long();
677 let request = Request::new(lookup_data.as_slice()).unwrap();
678
679 assert!(
681 matches!(request.operation(), FuseOperation::Error(e) if *e == lx::Error::ENAMETOOLONG)
682 );
683
684 session.dispatch(request, &mut error_sender, None);
685
686 assert_eq!(
688 error_sender.last_error,
689 Some(lx::Error::ENAMETOOLONG.value())
690 );
691 }
692
693 #[test]
694 fn dispatch() {
695 let mut sender = MockSender::default();
696 let fs = TestFs::default();
697 let state = fs.state.clone();
698 let session = Session::new(fs);
699 assert!(!session.is_initialized());
700 let request = Request::new(FUSE_INIT_REQUEST).unwrap();
701 session.dispatch(request, &mut sender, None);
702 assert_eq!(state.lock().called, INIT_CALLED);
703 assert!(session.is_initialized());
704 session.dispatch(
705 Request::new(FUSE_GETATTR_REQUEST).unwrap(),
706 &mut sender,
707 None,
708 );
709 assert_eq!(state.lock().called, INIT_CALLED | GETATTR_CALLED);
710
711 session.dispatch(
712 Request::new(FUSE_LOOKUP_REQUEST).unwrap(),
713 &mut sender,
714 None,
715 );
716 assert_eq!(
717 state.lock().called,
718 INIT_CALLED | GETATTR_CALLED | LOOKUP_CALLED
719 );
720 }
721
722 #[derive(Default)]
723 struct State {
724 called: u32,
725 }
726
727 #[derive(Default)]
728 struct TestFs {
729 state: Arc<Mutex<State>>,
730 }
731
732 impl Fuse for TestFs {
733 fn init(&self, info: &mut SessionInfo) {
734 assert_eq!(self.state.lock().called & INIT_CALLED, 0);
735 assert_eq!(info.major(), 7);
736 assert_eq!(info.minor(), 27);
737 assert_eq!(info.capable(), 0x3FFFFB);
738 assert_eq!(info.want, 0xC9029);
739 assert_eq!(info.max_readahead, 131072);
740 assert_eq!(info.max_background, 0);
741 assert_eq!(info.max_write, 1048576);
742 assert_eq!(info.congestion_threshold, 0);
743 assert_eq!(info.time_gran, 1);
744 self.state.lock().called |= INIT_CALLED;
745 }
746
747 fn get_attr(&self, request: &Request, flags: u32, fh: u64) -> lx::Result<fuse_attr_out> {
748 assert_eq!(self.state.lock().called & GETATTR_CALLED, 0);
749 assert_eq!(request.node_id(), 1);
750 assert_eq!(flags, 0);
751 assert_eq!(fh, 0);
752 let mut attr = fuse_attr_out::new_zeroed();
753 attr.attr.ino = 1;
754 attr.attr.mode = lx::S_IFDIR | 0o755;
755 attr.attr.nlink = 2;
756 attr.attr_valid = 1;
757 self.state.lock().called |= GETATTR_CALLED;
758 Ok(attr)
759 }
760
761 fn lookup(&self, request: &Request, name: &lx::LxStr) -> lx::Result<fuse_entry_out> {
762 assert_eq!(self.state.lock().called & LOOKUP_CALLED, 0);
763 assert_eq!(request.node_id(), 1);
764 assert_eq!(name, "hello");
765 self.state.lock().called |= LOOKUP_CALLED;
766 let mut attr = fuse_attr::new_zeroed();
767 attr.ino = 2;
768 attr.mode = lx::S_IFREG | 0o644;
769 attr.nlink = 1;
770 attr.size = 13;
771 Ok(fuse_entry_out {
772 nodeid: 2,
773 generation: 0,
774 entry_valid: 1,
775 entry_valid_nsec: 0,
776 attr_valid: 1,
777 attr_valid_nsec: 0,
778 attr,
779 })
780 }
781 }
782
783 #[derive(Default)]
784 struct MockSender {
785 state: u32,
786 }
787
788 impl ReplySender for MockSender {
789 fn send(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<()> {
790 let flat: Vec<u8> = bufs.iter().flat_map(|s| s.iter()).copied().collect();
791 match self.state {
792 0 => assert_eq!(flat, INIT_REPLY),
793 1 => assert_eq!(flat, GETATTR_REPLY),
794 2 => assert_eq!(flat, LOOKUP_REPLY),
795 _ => panic!("Unexpected send."),
796 }
797
798 self.state += 1;
799 Ok(())
800 }
801 }
802
803 const INIT_CALLED: u32 = 0x1;
804 const GETATTR_CALLED: u32 = 0x2;
805 const LOOKUP_CALLED: u32 = 0x4;
806
807 const INIT_REPLY: &[u8] = &[
808 80, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 39, 0, 0, 0, 0, 0, 2, 0, 41,
809 144, 12, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
810 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
811 ];
812
813 const GETATTR_REPLY: &[u8] = &[
814 120, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
815 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
816 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
817 0, 0, 237, 65, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
818 0,
819 ];
820
821 const LOOKUP_REPLY: &[u8] = &[
822 144, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
823 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
824 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
825 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 129, 0,
826 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
827 ];
828
829 #[derive(Default)]
831 struct ErrorCheckingSender {
832 last_error: Option<i32>,
833 }
834
835 impl ReplySender for ErrorCheckingSender {
836 fn send(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<()> {
837 let flat: Vec<u8> = bufs.iter().flat_map(|s| s.iter()).copied().collect();
839 if flat.len() >= 16 {
840 let error = i32::from_ne_bytes([flat[4], flat[5], flat[6], flat[7]]);
842 if error != 0 {
843 self.last_error = Some(-error); }
845 }
846 Ok(())
847 }
848 }
849
850 #[derive(Default)]
852 struct CapturingSender {
853 data: Vec<u8>,
854 }
855
856 impl ReplySender for CapturingSender {
857 fn send(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<()> {
858 self.data = bufs.iter().flat_map(|s| s.iter()).copied().collect();
859 Ok(())
860 }
861 }
862
863 impl CapturingSender {
864 fn parse_init_reply(&self) -> (fuse_out_header, fuse_init_out) {
866 let hdr = fuse_out_header::read_from_prefix(&self.data).unwrap().0;
867 let body = fuse_init_out::read_from_prefix(&self.data[size_of::<fuse_out_header>()..])
868 .unwrap()
869 .0;
870 (hdr, body)
871 }
872 }
873
874 fn make_init_request(
876 major: u32,
877 minor: u32,
878 max_readahead: u32,
879 flags: u32,
880 flags2: u32,
881 ) -> Vec<u8> {
882 let header = fuse_in_header {
883 len: (size_of::<fuse_in_header>() + size_of::<fuse_init_in>()) as u32,
884 opcode: FUSE_INIT,
885 unique: 1,
886 nodeid: 0,
887 uid: 0,
888 gid: 0,
889 pid: 0,
890 padding: 0,
891 };
892 let init = fuse_init_in {
893 major,
894 minor,
895 max_readahead,
896 flags,
897 flags2,
898 unused: [0; 11],
899 };
900 let mut data = Vec::new();
901 data.extend_from_slice(header.as_bytes());
902 data.extend_from_slice(init.as_bytes());
903 data
904 }
905
906 #[derive(Default)]
909 struct InitCapturingFs {
910 info: Arc<Mutex<Option<(u32, u32, u32)>>>, request_direct_io_mmap: bool,
912 max_write_override: Option<u32>,
913 }
914
915 impl Fuse for InitCapturingFs {
916 fn init(&self, info: &mut SessionInfo) {
917 if self.request_direct_io_mmap && info.capable2() & FUSE_DIRECT_IO_ALLOW_MMAP_FLAG2 != 0
918 {
919 info.want2 |= FUSE_DIRECT_IO_ALLOW_MMAP_FLAG2;
920 }
921 if let Some(max_write) = self.max_write_override {
922 info.max_write = max_write;
923 }
924 *self.info.lock() = Some((info.want, info.want2, info.capable()));
925 }
926 }
927
928 #[test]
929 fn init_with_ext_negotiates_flags2_and_direct_io_allow_mmap() {
930 let flags = 0x003FFFFB | FUSE_INIT_EXT;
932 let request_data = make_init_request(7, 39, 131072, flags, FUSE_DIRECT_IO_ALLOW_MMAP_FLAG2);
933
934 let fs = InitCapturingFs {
935 request_direct_io_mmap: true,
936 ..Default::default()
937 };
938 let info_ref = fs.info.clone();
939 let session = Session::new(fs);
940
941 let mut sender = CapturingSender::default();
942 session.dispatch(
943 Request::new(request_data.as_slice()).unwrap(),
944 &mut sender,
945 None,
946 );
947
948 assert!(session.is_initialized());
949
950 let info = info_ref.lock();
953 let &(want, want2, _capable) = info
954 .as_ref()
955 .expect("filesystem init info should be captured after initialization");
956 assert_ne!(
957 want & FUSE_INIT_EXT,
958 0,
959 "FUSE_INIT_EXT should be negotiated"
960 );
961 assert_ne!(
962 want2 & FUSE_DIRECT_IO_ALLOW_MMAP_FLAG2,
963 0,
964 "FUSE_DIRECT_IO_ALLOW_MMAP_FLAG2 should be in want2"
965 );
966
967 let (_hdr, init_out) = sender.parse_init_reply();
969 assert_ne!(
970 init_out.flags & FUSE_INIT_EXT,
971 0,
972 "Reply flags must include FUSE_INIT_EXT"
973 );
974 assert_ne!(
975 init_out.flags2 & FUSE_DIRECT_IO_ALLOW_MMAP_FLAG2,
976 0,
977 "Reply flags2 must include FUSE_DIRECT_IO_ALLOW_MMAP_FLAG2"
978 );
979 }
980
981 #[test]
982 fn init_without_ext_does_not_negotiate_flags2() {
983 let flags = 0x003FFFFB; let request_data = make_init_request(7, 27, 131072, flags, 0);
986
987 let fs = InitCapturingFs::default();
988 let info_ref = fs.info.clone();
989 let session = Session::new(fs);
990
991 let mut sender = CapturingSender::default();
992 session.dispatch(
993 Request::new(request_data.as_slice()).unwrap(),
994 &mut sender,
995 None,
996 );
997
998 assert!(session.is_initialized());
999
1000 let info = info_ref.lock();
1002 let &(_want, want2, _capable) = info
1003 .as_ref()
1004 .expect("filesystem init info should be captured after initialization");
1005 assert_eq!(want2, 0, "want2 must be zero without FUSE_INIT_EXT");
1006
1007 let (_hdr, init_out) = sender.parse_init_reply();
1008 assert_eq!(
1009 init_out.flags & FUSE_INIT_EXT,
1010 0,
1011 "Reply flags must NOT include FUSE_INIT_EXT"
1012 );
1013 assert_eq!(init_out.flags2, 0, "Reply flags2 must be zero");
1014 }
1015
1016 #[test]
1017 fn init_ext_without_direct_io_mmap_results_in_zero_flags2() {
1018 let flags = 0x003FFFFB | FUSE_INIT_EXT;
1021 let request_data = make_init_request(7, 39, 131072, flags, 0);
1022
1023 let fs = InitCapturingFs::default();
1024 let info_ref = fs.info.clone();
1025 let session = Session::new(fs);
1026
1027 let mut sender = CapturingSender::default();
1028 session.dispatch(
1029 Request::new(request_data.as_slice()).unwrap(),
1030 &mut sender,
1031 None,
1032 );
1033
1034 assert!(session.is_initialized());
1035
1036 let info = info_ref.lock();
1037 let &(_want, want2, _capable) = info
1038 .as_ref()
1039 .expect("filesystem init info should be captured after initialization");
1040 assert_eq!(
1041 want2, 0,
1042 "want2 must be zero when kernel flags2 lacks FUSE_DIRECT_IO_ALLOW_MMAP_FLAG2"
1043 );
1044
1045 let (_hdr, init_out) = sender.parse_init_reply();
1046 assert_eq!(init_out.flags2, 0, "Reply flags2 must be zero");
1047 }
1048
1049 #[test]
1050 fn init_higher_major_version_replies_with_supported_version() {
1051 let request_data = make_init_request(8, 0, 131072, 0, 0);
1053
1054 let fs = InitCapturingFs::default();
1055 let info_ref = fs.info.clone();
1056 let session = Session::new(fs);
1057
1058 let mut sender = CapturingSender::default();
1059 session.dispatch(
1060 Request::new(request_data.as_slice()).unwrap(),
1061 &mut sender,
1062 None,
1063 );
1064
1065 assert!(!session.is_initialized());
1067
1068 assert!(info_ref.lock().is_none());
1070
1071 let (hdr, init_out) = sender.parse_init_reply();
1073 assert_eq!(hdr.error, 0);
1074 assert_eq!(init_out.major, FUSE_KERNEL_VERSION);
1075 assert_eq!(init_out.minor, FUSE_KERNEL_MINOR_VERSION);
1076 }
1077
1078 #[test]
1079 fn init_old_unsupported_version_returns_error() {
1080 let request_data = make_init_request(7, 26, 131072, 0, 0);
1082
1083 let fs = InitCapturingFs::default();
1084 let session = Session::new(fs);
1085
1086 let mut sender = ErrorCheckingSender::default();
1087 session.dispatch(
1088 Request::new(request_data.as_slice()).unwrap(),
1089 &mut sender,
1090 None,
1091 );
1092
1093 assert!(!session.is_initialized());
1095
1096 assert!(sender.last_error.is_some());
1098 }
1099
1100 #[test]
1101 fn init_negotiates_fuse_max_pages_when_kernel_supports_it() {
1102 let flags = 0x003FFFFB | FUSE_MAX_PAGES;
1104 let request_data = make_init_request(7, 39, 131072, flags, 0);
1105
1106 let fs = InitCapturingFs::default();
1107 let info_ref = fs.info.clone();
1108 let session = Session::new(fs);
1109
1110 let mut sender = CapturingSender::default();
1111 session.dispatch(
1112 Request::new(request_data.as_slice()).unwrap(),
1113 &mut sender,
1114 None,
1115 );
1116
1117 assert!(session.is_initialized());
1118
1119 let info = info_ref.lock();
1121 let &(want, _want2, _capable) = info
1122 .as_ref()
1123 .expect("filesystem init info should be captured after initialization");
1124 assert_ne!(
1125 want & FUSE_MAX_PAGES,
1126 0,
1127 "FUSE_MAX_PAGES should be negotiated"
1128 );
1129
1130 let (_hdr, init_out) = sender.parse_init_reply();
1133 assert_ne!(
1134 init_out.flags & FUSE_MAX_PAGES,
1135 0,
1136 "Reply flags must include FUSE_MAX_PAGES"
1137 );
1138 assert_eq!(init_out.max_write, 256 * 4096);
1139 assert_eq!(init_out.max_pages, 256);
1140 }
1141
1142 #[test]
1143 fn init_without_max_pages_does_not_advertise_it() {
1144 let flags = 0x003FFFFB; let request_data = make_init_request(7, 27, 131072, flags, 0);
1147
1148 let fs = InitCapturingFs::default();
1149 let session = Session::new(fs);
1150
1151 let mut sender = CapturingSender::default();
1152 session.dispatch(
1153 Request::new(request_data.as_slice()).unwrap(),
1154 &mut sender,
1155 None,
1156 );
1157
1158 assert!(session.is_initialized());
1159
1160 let (_hdr, init_out) = sender.parse_init_reply();
1161 assert_eq!(
1162 init_out.flags & FUSE_MAX_PAGES,
1163 0,
1164 "Reply flags must NOT include FUSE_MAX_PAGES when kernel lacks it"
1165 );
1166 }
1167
1168 #[test]
1169 fn init_max_pages_uses_ceiling_division() {
1170 let flags = 0x003FFFFB | FUSE_MAX_PAGES;
1176 let request_data = make_init_request(7, 39, 131072, flags, 0);
1177
1178 let fs = InitCapturingFs {
1179 max_write_override: Some(4097),
1180 ..Default::default()
1181 };
1182 let session = Session::new(fs);
1183
1184 let mut sender = CapturingSender::default();
1185 session.dispatch(
1186 Request::new(request_data.as_slice()).unwrap(),
1187 &mut sender,
1188 None,
1189 );
1190
1191 assert!(session.is_initialized());
1192
1193 let (_hdr, init_out) = sender.parse_init_reply();
1194 assert_eq!(init_out.max_write, 4097);
1195 assert_eq!(
1196 init_out.max_pages, 2,
1197 "max_pages must round up to cover max_write"
1198 );
1199 }
1200
1201 fn make_lookup_name_too_long() -> Vec<u8> {
1203 let mut data = vec![0u8; 297]; data[0] = 0x29;
1208 data[1] = 0x01;
1209 data[2] = 0x00;
1210 data[3] = 0x00;
1211
1212 data[4] = 0x01;
1214 data[5] = 0x00;
1215 data[6] = 0x00;
1216 data[7] = 0x00;
1217
1218 data[8] = 99;
1220 data[9] = 0x00;
1221 data[10] = 0x00;
1222 data[11] = 0x00;
1223 data[12] = 0x00;
1224 data[13] = 0x00;
1225 data[14] = 0x00;
1226 data[15] = 0x00;
1227
1228 data[16] = 0x01;
1230 data[17] = 0x00;
1231 data[18] = 0x00;
1232 data[19] = 0x00;
1233 data[20] = 0x00;
1234 data[21] = 0x00;
1235 data[22] = 0x00;
1236 data[23] = 0x00;
1237
1238 data[32] = 0xCB;
1242 data[33] = 0x03;
1243 data[34] = 0x00;
1244 data[35] = 0x00;
1245
1246 for item in data.iter_mut().take(296).skip(40) {
1250 *item = 0x61; }
1252 data[296] = 0x00;
1254
1255 data
1256 }
1257}