hermit/fs/
fuse.rs

1use alloc::borrow::ToOwned;
2use alloc::boxed::Box;
3use alloc::ffi::CString;
4use alloc::string::String;
5use alloc::sync::Arc;
6use alloc::vec::Vec;
7use core::marker::PhantomData;
8use core::mem::{MaybeUninit, align_of, offset_of, size_of};
9use core::sync::atomic::{AtomicU64, Ordering};
10use core::task::Poll;
11use core::{future, mem};
12
13use align_address::Align;
14use async_lock::Mutex;
15use async_trait::async_trait;
16use embedded_io::{ErrorType, Read, Write};
17use fuse_abi::linux::*;
18
19use crate::alloc::string::ToString;
20#[cfg(not(feature = "pci"))]
21use crate::arch::kernel::mmio::get_filesystem_driver;
22#[cfg(feature = "pci")]
23use crate::drivers::pci::get_filesystem_driver;
24use crate::drivers::virtio::virtqueue::error::VirtqError;
25use crate::errno::Errno;
26use crate::executor::block_on;
27use crate::fd::PollEvent;
28use crate::fs::fuse::ops::SetAttrValidFields;
29use crate::fs::{
30	self, AccessPermission, DirectoryEntry, FileAttr, NodeKind, ObjectInterface, OpenOption,
31	SeekWhence, VfsNode,
32};
33use crate::mm::device_alloc::DeviceAlloc;
34use crate::syscalls::Dirent64;
35use crate::time::{time_t, timespec};
36use crate::{arch, io};
37
38// response out layout eg @ https://github.com/zargony/fuse-rs/blob/bf6d1cf03f3277e35b580f3c7b9999255d72ecf3/src/ll/request.rs#L44
39// op in/out sizes/layout: https://github.com/hanwen/go-fuse/blob/204b45dba899dfa147235c255908236d5fde2d32/fuse/opcode.go#L439
40// possible responses for command: qemu/tools/virtiofsd/fuse_lowlevel.h
41
42const MAX_READ_LEN: usize = 1024 * 64;
43const MAX_WRITE_LEN: usize = 1024 * 64;
44
45const U64_SIZE: usize = mem::size_of::<u64>();
46
47const S_IFLNK: u32 = 0o120_000;
48const S_IFMT: u32 = 0o170_000;
49
50pub(crate) trait FuseInterface {
51	fn send_command<O: ops::Op + 'static>(
52		&mut self,
53		cmd: Cmd<O>,
54		rsp_payload_len: u32,
55	) -> Result<Rsp<O>, FuseError>
56	where
57		<O as ops::Op>::InStruct: Send,
58		<O as ops::Op>::OutStruct: Send;
59
60	fn get_mount_point(&self) -> String;
61}
62
63pub(crate) mod ops {
64	#![allow(clippy::type_complexity)]
65	use alloc::boxed::Box;
66	use alloc::ffi::CString;
67
68	use fuse_abi::linux;
69	use fuse_abi::linux::*;
70
71	use super::Cmd;
72	use crate::fd::PollEvent;
73	use crate::fs::{FileAttr, SeekWhence};
74
75	#[repr(C)]
76	#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)]
77	pub(crate) struct CreateOut {
78		pub entry: fuse_entry_out,
79		pub open: fuse_open_out,
80	}
81
82	pub(crate) trait Op {
83		const OP_CODE: fuse_opcode;
84
85		type InStruct: core::fmt::Debug;
86		type InPayload: ?Sized;
87		type OutStruct: core::fmt::Debug;
88		type OutPayload: ?Sized;
89	}
90
91	#[derive(Debug)]
92	pub(crate) struct Init;
93
94	impl Op for Init {
95		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_INIT;
96		type InStruct = fuse_init_in;
97		type InPayload = ();
98		type OutStruct = fuse_init_out;
99		type OutPayload = ();
100	}
101
102	impl Init {
103		pub(crate) fn create() -> (Cmd<Self>, u32) {
104			let cmd = Cmd::new(
105				FUSE_ROOT_ID,
106				fuse_init_in {
107					major: 7,
108					minor: 31,
109					..Default::default()
110				},
111			);
112			(cmd, 0)
113		}
114	}
115
116	#[derive(Debug)]
117	pub(crate) struct Create;
118
119	impl Op for Create {
120		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_CREATE;
121		type InStruct = fuse_create_in;
122		type InPayload = CString;
123		type OutStruct = CreateOut;
124		type OutPayload = ();
125	}
126
127	impl Create {
128		#[allow(clippy::self_named_constructors)]
129		pub(crate) fn create(path: CString, flags: u32, mode: u32) -> (Cmd<Self>, u32) {
130			let cmd = Cmd::with_cstring(
131				FUSE_ROOT_ID,
132				fuse_create_in {
133					flags,
134					mode,
135					..Default::default()
136				},
137				path,
138			);
139			(cmd, 0)
140		}
141	}
142
143	#[derive(Debug)]
144	pub(crate) struct Open;
145
146	impl Op for Open {
147		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_OPEN;
148		type InStruct = fuse_open_in;
149		type InPayload = ();
150		type OutStruct = fuse_open_out;
151		type OutPayload = ();
152	}
153
154	impl Open {
155		pub(crate) fn create(nid: u64, flags: u32) -> (Cmd<Self>, u32) {
156			let cmd = Cmd::new(
157				nid,
158				fuse_open_in {
159					flags,
160					..Default::default()
161				},
162			);
163			(cmd, 0)
164		}
165	}
166
167	#[derive(Debug)]
168	pub(crate) struct Write;
169
170	impl Op for Write {
171		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_WRITE;
172		type InStruct = fuse_write_in;
173		type InPayload = [u8];
174		type OutStruct = fuse_write_out;
175		type OutPayload = ();
176	}
177
178	impl Write {
179		pub(crate) fn create(nid: u64, fh: u64, buf: Box<[u8]>, offset: u64) -> (Cmd<Self>, u32) {
180			let cmd = Cmd::with_boxed_slice(
181				nid,
182				fuse_write_in {
183					fh,
184					offset,
185					size: buf.len().try_into().unwrap(),
186					..Default::default()
187				},
188				buf,
189			);
190			(cmd, 0)
191		}
192	}
193
194	#[derive(Debug)]
195	pub(crate) struct Read;
196
197	impl Op for Read {
198		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_READ;
199		type InStruct = fuse_read_in;
200		type InPayload = ();
201		type OutStruct = ();
202		type OutPayload = [u8];
203	}
204
205	impl Read {
206		pub(crate) fn create(nid: u64, fh: u64, size: u32, offset: u64) -> (Cmd<Self>, u32) {
207			let cmd = Cmd::new(
208				nid,
209				fuse_read_in {
210					fh,
211					offset,
212					size,
213					..Default::default()
214				},
215			);
216			(cmd, size)
217		}
218	}
219
220	#[derive(Debug)]
221	pub(crate) struct Lseek;
222
223	impl Op for Lseek {
224		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_LSEEK;
225		type InStruct = fuse_lseek_in;
226		type InPayload = ();
227		type OutStruct = fuse_lseek_out;
228		type OutPayload = ();
229	}
230
231	impl Lseek {
232		pub(crate) fn create(
233			nid: u64,
234			fh: u64,
235			offset: isize,
236			whence: SeekWhence,
237		) -> (Cmd<Self>, u32) {
238			let cmd = Cmd::new(
239				nid,
240				fuse_lseek_in {
241					fh,
242					offset: i64::try_from(offset).unwrap() as u64,
243					whence: u8::from(whence).into(),
244					..Default::default()
245				},
246			);
247			(cmd, 0)
248		}
249	}
250
251	#[derive(Debug)]
252	pub(crate) struct Getattr;
253
254	impl Op for Getattr {
255		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_GETATTR;
256		type InStruct = fuse_getattr_in;
257		type InPayload = ();
258		type OutStruct = fuse_attr_out;
259		type OutPayload = ();
260	}
261
262	impl Getattr {
263		pub(crate) fn create(nid: u64, fh: u64, getattr_flags: u32) -> (Cmd<Self>, u32) {
264			let cmd = Cmd::new(
265				nid,
266				fuse_getattr_in {
267					getattr_flags,
268					fh,
269					..Default::default()
270				},
271			);
272			(cmd, 0)
273		}
274	}
275
276	#[derive(Debug)]
277	pub(crate) struct Setattr;
278
279	impl Op for Setattr {
280		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_SETATTR;
281		type InStruct = fuse_setattr_in;
282		type InPayload = ();
283		type OutStruct = fuse_attr_out;
284		type OutPayload = ();
285	}
286
287	bitflags! {
288		#[derive(Debug, Copy, Clone, Default)]
289		pub struct SetAttrValidFields: u32 {
290			const FATTR_MODE = linux::FATTR_MODE;
291			const FATTR_UID = linux::FATTR_UID;
292			const FATTR_GID = linux::FATTR_GID;
293			const FATTR_SIZE = linux::FATTR_SIZE;
294			const FATTR_ATIME = linux::FATTR_ATIME;
295			const FATTR_MTIME = linux::FATTR_MTIME;
296			const FATTR_FH = linux::FATTR_FH;
297			const FATTR_ATIME_NOW = linux::FATTR_ATIME_NOW;
298			const FATTR_MTIME_NOW = linux::FATTR_MTIME_NOW;
299			const FATTR_LOCKOWNER = linux::FATTR_LOCKOWNER;
300			const FATTR_CTIME = linux::FATTR_CTIME;
301			const FATTR_KILL_SUIDGID = linux::FATTR_KILL_SUIDGID;
302		}
303	}
304
305	impl Setattr {
306		pub(crate) fn create(
307			nid: u64,
308			fh: u64,
309			attr: FileAttr,
310			valid_attr: SetAttrValidFields,
311		) -> (Cmd<Self>, u32) {
312			let cmd = Cmd::new(
313				nid,
314				fuse_setattr_in {
315					valid: valid_attr
316						.difference(
317							// Remove unsupported attributes
318							SetAttrValidFields::FATTR_LOCKOWNER,
319						)
320						.bits(),
321					padding: 0,
322					fh,
323
324					// Fuse attributes mapping: https://github.com/libfuse/libfuse/blob/fc1c8da0cf8a18d222cb1feed0057ba44ea4d18f/lib/fuse_lowlevel.c#L105
325					size: attr.st_size as u64,
326					atime: attr.st_atim.tv_sec as u64,
327					atimensec: attr.st_atim.tv_nsec as u32,
328					mtime: attr.st_ctim.tv_sec as u64,
329					mtimensec: attr.st_ctim.tv_nsec as u32,
330					ctime: attr.st_ctim.tv_sec as u64,
331					ctimensec: attr.st_ctim.tv_nsec as u32,
332					mode: attr.st_mode.bits(),
333					unused4: 0,
334					uid: attr.st_uid,
335					gid: attr.st_gid,
336					unused5: 0,
337
338					lock_owner: 0, // unsupported
339				},
340			);
341
342			(cmd, 0)
343		}
344	}
345
346	#[derive(Debug)]
347	pub(crate) struct Readlink;
348
349	impl Op for Readlink {
350		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_READLINK;
351		type InStruct = ();
352		type InPayload = ();
353		type OutStruct = ();
354		type OutPayload = [u8];
355	}
356
357	impl Readlink {
358		pub(crate) fn create(nid: u64, size: u32) -> (Cmd<Self>, u32) {
359			let cmd = Cmd::new(nid, ());
360			(cmd, size)
361		}
362	}
363
364	#[derive(Debug)]
365	pub(crate) struct Release;
366
367	impl Op for Release {
368		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_RELEASE;
369		type InStruct = fuse_release_in;
370		type InPayload = ();
371		type OutStruct = ();
372		type OutPayload = ();
373	}
374
375	impl Release {
376		pub(crate) fn create(nid: u64, fh: u64) -> (Cmd<Self>, u32) {
377			let cmd = Cmd::new(
378				nid,
379				fuse_release_in {
380					fh,
381					..Default::default()
382				},
383			);
384			(cmd, 0)
385		}
386	}
387
388	#[derive(Debug)]
389	pub(crate) struct Poll;
390
391	impl Op for Poll {
392		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_POLL;
393		type InStruct = fuse_poll_in;
394		type InPayload = ();
395		type OutStruct = fuse_poll_out;
396		type OutPayload = ();
397	}
398
399	impl Poll {
400		pub(crate) fn create(nid: u64, fh: u64, kh: u64, event: PollEvent) -> (Cmd<Self>, u32) {
401			let cmd = Cmd::new(
402				nid,
403				fuse_poll_in {
404					fh,
405					kh,
406					events: event.bits() as u32,
407					..Default::default()
408				},
409			);
410			(cmd, 0)
411		}
412	}
413
414	#[derive(Debug)]
415	pub(crate) struct Mkdir;
416
417	impl Op for Mkdir {
418		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_MKDIR;
419		type InStruct = fuse_mkdir_in;
420		type InPayload = CString;
421		type OutStruct = fuse_entry_out;
422		type OutPayload = ();
423	}
424
425	impl Mkdir {
426		pub(crate) fn create(path: CString, mode: u32) -> (Cmd<Self>, u32) {
427			let cmd = Cmd::with_cstring(
428				FUSE_ROOT_ID,
429				fuse_mkdir_in {
430					mode,
431					..Default::default()
432				},
433				path,
434			);
435			(cmd, 0)
436		}
437	}
438
439	#[derive(Debug)]
440	pub(crate) struct Unlink;
441
442	impl Op for Unlink {
443		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_UNLINK;
444		type InStruct = ();
445		type InPayload = CString;
446		type OutStruct = ();
447		type OutPayload = ();
448	}
449
450	impl Unlink {
451		pub(crate) fn create(name: CString) -> (Cmd<Self>, u32) {
452			let cmd = Cmd::with_cstring(FUSE_ROOT_ID, (), name);
453			(cmd, 0)
454		}
455	}
456
457	#[derive(Debug)]
458	pub(crate) struct Rmdir;
459
460	impl Op for Rmdir {
461		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_RMDIR;
462		type InStruct = ();
463		type InPayload = CString;
464		type OutStruct = ();
465		type OutPayload = ();
466	}
467
468	impl Rmdir {
469		pub(crate) fn create(name: CString) -> (Cmd<Self>, u32) {
470			let cmd = Cmd::with_cstring(FUSE_ROOT_ID, (), name);
471			(cmd, 0)
472		}
473	}
474
475	#[derive(Debug)]
476	pub(crate) struct Lookup;
477
478	impl Op for Lookup {
479		const OP_CODE: fuse_opcode = fuse_opcode::FUSE_LOOKUP;
480		type InStruct = ();
481		type InPayload = CString;
482		type OutStruct = fuse_entry_out;
483		type OutPayload = ();
484	}
485
486	impl Lookup {
487		pub(crate) fn create(name: CString) -> (Cmd<Self>, u32) {
488			let cmd = Cmd::with_cstring(FUSE_ROOT_ID, (), name);
489			(cmd, 0)
490		}
491	}
492}
493
494impl From<fuse_attr> for FileAttr {
495	fn from(attr: fuse_attr) -> FileAttr {
496		FileAttr {
497			st_ino: attr.ino,
498			st_nlink: attr.nlink.into(),
499			st_mode: AccessPermission::from_bits_retain(attr.mode),
500			st_uid: attr.uid,
501			st_gid: attr.gid,
502			st_rdev: attr.rdev.into(),
503			st_size: attr.size.try_into().unwrap(),
504			st_blksize: attr.blksize.into(),
505			st_blocks: attr.blocks.try_into().unwrap(),
506			st_atim: timespec {
507				tv_sec: attr.atime as time_t,
508				tv_nsec: attr.atimensec as i32,
509			},
510			st_mtim: timespec {
511				tv_sec: attr.mtime as time_t,
512				tv_nsec: attr.mtimensec as i32,
513			},
514			st_ctim: timespec {
515				tv_sec: attr.ctime as time_t,
516				tv_nsec: attr.ctimensec as i32,
517			},
518			..Default::default()
519		}
520	}
521}
522
523#[repr(C)]
524#[derive(Debug)]
525pub(crate) struct CmdHeader<O: ops::Op> {
526	pub in_header: fuse_in_header,
527	op_header: O::InStruct,
528}
529
530impl<O: ops::Op> CmdHeader<O>
531where
532	O: ops::Op<InPayload = ()>,
533{
534	fn new(nodeid: u64, op_header: O::InStruct) -> Self {
535		Self::with_payload_size(nodeid, op_header, 0)
536	}
537}
538
539impl<O: ops::Op> CmdHeader<O> {
540	fn with_payload_size(nodeid: u64, op_header: O::InStruct, len: usize) -> CmdHeader<O> {
541		CmdHeader {
542			in_header: fuse_in_header {
543				// The length we need the provide in the header is not the same as the size of the struct because of padding, so we need to calculate it manually.
544				len: (core::mem::size_of::<fuse_in_header>()
545					+ core::mem::size_of::<O::InStruct>()
546					+ len)
547					.try_into()
548					.expect("The command is too large"),
549				opcode: O::OP_CODE.into(),
550				nodeid,
551				unique: 1,
552				..Default::default()
553			},
554			op_header,
555		}
556	}
557}
558
559pub(crate) struct Cmd<O: ops::Op> {
560	pub headers: Box<CmdHeader<O>, DeviceAlloc>,
561	pub payload: Option<Vec<u8, DeviceAlloc>>,
562}
563
564impl<O: ops::Op> Cmd<O>
565where
566	O: ops::Op<InPayload = ()>,
567{
568	fn new(nodeid: u64, op_header: O::InStruct) -> Self {
569		Self {
570			headers: Box::new_in(CmdHeader::new(nodeid, op_header), DeviceAlloc),
571			payload: None,
572		}
573	}
574}
575
576impl<O: ops::Op> Cmd<O>
577where
578	O: ops::Op<InPayload = CString>,
579{
580	fn with_cstring(nodeid: u64, op_header: O::InStruct, cstring: CString) -> Self {
581		let cstring_bytes = cstring.into_bytes_with_nul().to_vec_in(DeviceAlloc);
582		Self {
583			headers: Box::new_in(
584				CmdHeader::with_payload_size(nodeid, op_header, cstring_bytes.len()),
585				DeviceAlloc,
586			),
587			payload: Some(cstring_bytes),
588		}
589	}
590}
591
592impl<O: ops::Op> Cmd<O>
593where
594	O: ops::Op<InPayload = [u8]>,
595{
596	fn with_boxed_slice(nodeid: u64, op_header: O::InStruct, slice: Box<[u8]>) -> Self {
597		let mut device_slice = Vec::with_capacity_in(slice.len(), DeviceAlloc);
598		device_slice.extend_from_slice(&slice);
599		Self {
600			headers: Box::new_in(
601				CmdHeader::with_payload_size(nodeid, op_header, slice.len()),
602				DeviceAlloc,
603			),
604			payload: Some(device_slice),
605		}
606	}
607}
608
609#[repr(C)]
610#[derive(Debug)]
611// The generic H parameter allows us to handle RspHeaders with their op_header
612// potenitally uninitialized. After checking for the error code in the out_header,
613// the object can be transmuted to one with an initialized op_header.
614pub(crate) struct RspHeader<O: ops::Op, H = <O as ops::Op>::OutStruct> {
615	pub out_header: fuse_out_header,
616	op_header: H,
617	_phantom: PhantomData<O::OutStruct>,
618}
619
620#[derive(Debug)]
621pub(crate) struct Rsp<O: ops::Op> {
622	pub headers: Box<RspHeader<O>, DeviceAlloc>,
623	pub payload: Option<Vec<u8, DeviceAlloc>>,
624}
625
626#[derive(Debug)]
627pub(crate) enum FuseError {
628	VirtqError(VirtqError),
629	IOError(Errno),
630}
631
632impl From<VirtqError> for FuseError {
633	fn from(value: VirtqError) -> Self {
634		Self::VirtqError(value)
635	}
636}
637
638impl From<FuseError> for Errno {
639	fn from(value: FuseError) -> Self {
640		match value {
641			FuseError::VirtqError(virtq_error) => virtq_error.into(),
642			FuseError::IOError(io_error) => io_error,
643		}
644	}
645}
646
647fn lookup(name: CString) -> Option<u64> {
648	let (cmd, rsp_payload_len) = ops::Lookup::create(name);
649	let rsp = get_filesystem_driver()
650		.unwrap()
651		.lock()
652		.send_command(cmd, rsp_payload_len)
653		.ok()?;
654	Some(rsp.headers.op_header.nodeid)
655}
656
657fn readlink(nid: u64) -> io::Result<String> {
658	let len = MAX_READ_LEN as u32;
659	let (cmd, rsp_payload_len) = ops::Readlink::create(nid, len);
660	let rsp = get_filesystem_driver()
661		.unwrap()
662		.lock()
663		.send_command(cmd, rsp_payload_len)?;
664	let len: usize = if rsp.headers.out_header.len as usize - mem::size_of::<fuse_out_header>()
665		>= usize::try_from(len).unwrap()
666	{
667		len.try_into().unwrap()
668	} else {
669		(rsp.headers.out_header.len as usize) - mem::size_of::<fuse_out_header>()
670	};
671
672	Ok(String::from_utf8(rsp.payload.unwrap()[..len].to_vec()).unwrap())
673}
674
675#[derive(Debug)]
676struct FuseFileHandleInner {
677	fuse_nid: Option<u64>,
678	fuse_fh: Option<u64>,
679	offset: usize,
680}
681
682impl FuseFileHandleInner {
683	pub fn new() -> Self {
684		Self {
685			fuse_nid: None,
686			fuse_fh: None,
687			offset: 0,
688		}
689	}
690
691	async fn poll(&self, events: PollEvent) -> io::Result<PollEvent> {
692		static KH: AtomicU64 = AtomicU64::new(0);
693		let kh = KH.fetch_add(1, Ordering::SeqCst);
694
695		future::poll_fn(|cx| {
696			if let (Some(nid), Some(fh)) = (self.fuse_nid, self.fuse_fh) {
697				let (cmd, rsp_payload_len) = ops::Poll::create(nid, fh, kh, events);
698				let rsp = get_filesystem_driver()
699					.ok_or(Errno::Nosys)?
700					.lock()
701					.send_command(cmd, rsp_payload_len)?;
702
703				if rsp.headers.out_header.error < 0 {
704					Poll::Ready(Err(Errno::Io))
705				} else {
706					let revents =
707						PollEvent::from_bits(i16::try_from(rsp.headers.op_header.revents).unwrap())
708							.unwrap();
709					if !revents.intersects(events)
710						&& !revents.intersects(
711							PollEvent::POLLERR | PollEvent::POLLNVAL | PollEvent::POLLHUP,
712						) {
713						// the current implementation use polling to wait for an event
714						// consequently, we have to wakeup the waker, if the the event doesn't arrive
715						cx.waker().wake_by_ref();
716					}
717					Poll::Ready(Ok(revents))
718				}
719			} else {
720				Poll::Ready(Ok(PollEvent::POLLERR))
721			}
722		})
723		.await
724	}
725
726	fn lseek(&mut self, offset: isize, whence: SeekWhence) -> io::Result<isize> {
727		debug!("FUSE lseek: offset: {offset}, whence: {whence:?}");
728
729		// Seek on fuse file systems seems to be a little odd: All reads are referenced from the
730		// beginning of the file, thus we have to track the offset ourself. Also, a read doesn't
731		// move the read pointer on the remote side, so we can't get the current position using
732		// remote lseek when referencing from `Cur` and we have to use the internally tracked
733		// position instead.
734		match whence {
735			SeekWhence::End | SeekWhence::Data | SeekWhence::Hole => {
736				if let (Some(nid), Some(fh)) = (self.fuse_nid, self.fuse_fh) {
737					let (cmd, rsp_payload_len) = ops::Lseek::create(nid, fh, offset, whence);
738					let rsp = get_filesystem_driver()
739						.ok_or(Errno::Nosys)?
740						.lock()
741						.send_command(cmd, rsp_payload_len)?;
742
743					if rsp.headers.out_header.error < 0 {
744						return Err(Errno::Io);
745					}
746
747					let rsp_offset = rsp.headers.op_header.offset;
748					self.offset = rsp.headers.op_header.offset.try_into().unwrap();
749
750					Ok(rsp_offset.try_into().unwrap())
751				} else {
752					Err(Errno::Io)
753				}
754			}
755			SeekWhence::Set => {
756				self.offset = offset.try_into().map_err(|_e| Errno::Inval)?;
757				Ok(self.offset as isize)
758			}
759			SeekWhence::Cur => {
760				self.offset = (self.offset as isize + offset)
761					.try_into()
762					.map_err(|_e| Errno::Inval)?;
763				Ok(self.offset as isize)
764			}
765		}
766	}
767
768	fn fstat(&mut self) -> io::Result<FileAttr> {
769		debug!("FUSE getattr");
770		if let (Some(nid), Some(fh)) = (self.fuse_nid, self.fuse_fh) {
771			let (cmd, rsp_payload_len) = ops::Getattr::create(nid, fh, FUSE_GETATTR_FH);
772			let rsp = get_filesystem_driver()
773				.ok_or(Errno::Nosys)?
774				.lock()
775				.send_command(cmd, rsp_payload_len)?;
776			if rsp.headers.out_header.error < 0 {
777				return Err(Errno::Io);
778			}
779			Ok(rsp.headers.op_header.attr.into())
780		} else {
781			Err(Errno::Io)
782		}
783	}
784
785	fn set_attr(&mut self, attr: FileAttr, valid: SetAttrValidFields) -> io::Result<FileAttr> {
786		debug!("FUSE setattr");
787		if let (Some(nid), Some(fh)) = (self.fuse_nid, self.fuse_fh) {
788			let (cmd, rsp_payload_len) = ops::Setattr::create(nid, fh, attr, valid);
789			let rsp = get_filesystem_driver()
790				.ok_or(Errno::Nosys)?
791				.lock()
792				.send_command(cmd, rsp_payload_len)?;
793			if rsp.headers.out_header.error < 0 {
794				return Err(Errno::Io);
795			}
796			Ok(rsp.headers.op_header.attr.into())
797		} else {
798			Err(Errno::Io)
799		}
800	}
801}
802
803impl ErrorType for FuseFileHandleInner {
804	type Error = Errno;
805}
806
807impl Read for FuseFileHandleInner {
808	fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
809		let mut len = buf.len();
810		if len > MAX_READ_LEN {
811			debug!("Reading longer than max_read_len: {len}");
812			len = MAX_READ_LEN;
813		}
814		if let (Some(nid), Some(fh)) = (self.fuse_nid, self.fuse_fh) {
815			let (cmd, rsp_payload_len) =
816				ops::Read::create(nid, fh, len.try_into().unwrap(), self.offset as u64);
817			let rsp = get_filesystem_driver()
818				.ok_or(Errno::Nosys)?
819				.lock()
820				.send_command(cmd, rsp_payload_len)?;
821			let len: usize =
822				if (rsp.headers.out_header.len as usize) - mem::size_of::<fuse_out_header>() >= len
823				{
824					len
825				} else {
826					(rsp.headers.out_header.len as usize) - mem::size_of::<fuse_out_header>()
827				};
828			self.offset += len;
829
830			buf[..len].copy_from_slice(&rsp.payload.unwrap()[..len]);
831
832			Ok(len)
833		} else {
834			debug!("File not open, cannot read!");
835			Err(Errno::Noent)
836		}
837	}
838}
839
840impl Write for FuseFileHandleInner {
841	fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
842		debug!("FUSE write!");
843		let mut truncated_len = buf.len();
844		if truncated_len > MAX_WRITE_LEN {
845			debug!(
846				"Writing longer than max_write_len: {} > {}",
847				buf.len(),
848				MAX_WRITE_LEN
849			);
850			truncated_len = MAX_WRITE_LEN;
851		}
852		if let (Some(nid), Some(fh)) = (self.fuse_nid, self.fuse_fh) {
853			let truncated_buf = Box::<[u8]>::from(&buf[..truncated_len]);
854			let (cmd, rsp_payload_len) =
855				ops::Write::create(nid, fh, truncated_buf, self.offset as u64);
856			let rsp = get_filesystem_driver()
857				.ok_or(Errno::Nosys)?
858				.lock()
859				.send_command(cmd, rsp_payload_len)?;
860
861			if rsp.headers.out_header.error < 0 {
862				return Err(Errno::Io);
863			}
864
865			let rsp_size = rsp.headers.op_header.size;
866			let rsp_len: usize = if rsp_size > u32::try_from(truncated_len).unwrap() {
867				truncated_len
868			} else {
869				rsp_size.try_into().unwrap()
870			};
871			self.offset += rsp_len;
872			Ok(rsp_len)
873		} else {
874			warn!("File not open, cannot read!");
875			Err(Errno::Noent)
876		}
877	}
878
879	fn flush(&mut self) -> Result<(), Self::Error> {
880		Ok(())
881	}
882}
883
884impl Drop for FuseFileHandleInner {
885	fn drop(&mut self) {
886		if let Some(fuse_nid) = self.fuse_nid
887			&& let Some(fuse_fh) = self.fuse_fh
888		{
889			let (cmd, rsp_payload_len) = ops::Release::create(fuse_nid, fuse_fh);
890			get_filesystem_driver()
891				.unwrap()
892				.lock()
893				.send_command(cmd, rsp_payload_len)
894				.unwrap();
895		}
896	}
897}
898
899#[derive(Debug)]
900struct FuseFileHandle(pub Arc<Mutex<FuseFileHandleInner>>);
901
902impl FuseFileHandle {
903	pub fn new() -> Self {
904		Self(Arc::new(Mutex::new(FuseFileHandleInner::new())))
905	}
906}
907
908#[async_trait]
909impl ObjectInterface for FuseFileHandle {
910	async fn poll(&self, event: PollEvent) -> io::Result<PollEvent> {
911		self.0.lock().await.poll(event).await
912	}
913
914	async fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
915		self.0.lock().await.read(buf)
916	}
917
918	async fn write(&self, buf: &[u8]) -> io::Result<usize> {
919		self.0.lock().await.write(buf)
920	}
921
922	async fn lseek(&self, offset: isize, whence: SeekWhence) -> io::Result<isize> {
923		self.0.lock().await.lseek(offset, whence)
924	}
925
926	async fn fstat(&self) -> io::Result<FileAttr> {
927		self.0.lock().await.fstat()
928	}
929
930	async fn truncate(&self, size: usize) -> io::Result<()> {
931		let attr = FileAttr {
932			st_size: size.try_into().unwrap(),
933			..FileAttr::default()
934		};
935
936		self.0
937			.lock()
938			.await
939			.set_attr(attr, SetAttrValidFields::FATTR_SIZE)
940			.map(|_| ())
941	}
942
943	async fn chmod(&self, access_permission: AccessPermission) -> io::Result<()> {
944		let attr = FileAttr {
945			st_mode: access_permission,
946			..FileAttr::default()
947		};
948
949		self.0
950			.lock()
951			.await
952			.set_attr(attr, SetAttrValidFields::FATTR_MODE)
953			.map(|_| ())
954	}
955}
956
957impl Clone for FuseFileHandle {
958	fn clone(&self) -> Self {
959		warn!("FuseFileHandle: clone not tested");
960		Self(self.0.clone())
961	}
962}
963
964#[derive(Debug)]
965pub struct FuseDirectoryHandle {
966	name: Option<String>,
967	read_position: Mutex<usize>,
968}
969
970impl FuseDirectoryHandle {
971	pub fn new(name: Option<String>) -> Self {
972		Self {
973			name,
974			read_position: Mutex::new(0),
975		}
976	}
977}
978
979#[async_trait]
980impl ObjectInterface for FuseDirectoryHandle {
981	async fn getdents(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
982		let path: CString = if let Some(name) = &self.name {
983			CString::new("/".to_string() + name).unwrap()
984		} else {
985			CString::new("/".to_string()).unwrap()
986		};
987
988		debug!("FUSE opendir: {path:#?}");
989
990		let fuse_nid = lookup(path.clone()).ok_or(Errno::Noent)?;
991
992		// Opendir
993		// Flag 0x10000 for O_DIRECTORY might not be necessary
994		let (mut cmd, rsp_payload_len) = ops::Open::create(fuse_nid, 0x10000);
995		cmd.headers.in_header.opcode = fuse_opcode::FUSE_OPENDIR as u32;
996		let rsp = get_filesystem_driver()
997			.ok_or(Errno::Nosys)?
998			.lock()
999			.send_command(cmd, rsp_payload_len)?;
1000		let fuse_fh = rsp.headers.op_header.fh;
1001
1002		debug!("FUSE readdir: {path:#?}");
1003
1004		// Linux seems to allocate a single page to store the dirfile
1005		let len = MAX_READ_LEN as u32;
1006		let rsp_offset: &mut usize = &mut *self.read_position.lock().await;
1007		let mut buf_offset: usize = 0;
1008
1009		// read content of the directory
1010		let (mut cmd, rsp_payload_len) = ops::Read::create(fuse_nid, fuse_fh, len, 0);
1011		cmd.headers.in_header.opcode = fuse_opcode::FUSE_READDIR as u32;
1012		let rsp = get_filesystem_driver()
1013			.ok_or(Errno::Nosys)?
1014			.lock()
1015			.send_command(cmd, rsp_payload_len)?;
1016
1017		let len = usize::min(
1018			MAX_READ_LEN,
1019			rsp.headers.out_header.len as usize - mem::size_of::<fuse_out_header>(),
1020		);
1021
1022		if len <= core::mem::size_of::<fuse_dirent>() {
1023			debug!("FUSE no new dirs");
1024			return Err(Errno::Noent);
1025		}
1026
1027		let mut ret = 0;
1028
1029		while (rsp.headers.out_header.len as usize) - *rsp_offset > size_of::<fuse_dirent>() {
1030			let dirent = unsafe {
1031				&*rsp
1032					.payload
1033					.as_ref()
1034					.unwrap()
1035					.as_ptr()
1036					.byte_add(*rsp_offset)
1037					.cast::<fuse_dirent>()
1038			};
1039
1040			let dirent_len = offset_of!(Dirent64, d_name) + dirent.namelen as usize + 1;
1041			let next_dirent = (buf_offset + dirent_len).align_up(align_of::<Dirent64>());
1042
1043			if next_dirent > buf.len() {
1044				// target buffer full -> we return the nr. of bytes written (like linux does)
1045				break;
1046			}
1047
1048			// could be replaced with slice_as_ptr once maybe_uninit_slice is stabilized.
1049			let target_dirent = buf[buf_offset].as_mut_ptr().cast::<Dirent64>();
1050			unsafe {
1051				target_dirent.write(Dirent64 {
1052					d_ino: dirent.ino,
1053					d_off: 0,
1054					d_reclen: (dirent_len.align_up(align_of::<Dirent64>()))
1055						.try_into()
1056						.unwrap(),
1057					d_type: (dirent.type_ as u8).try_into().unwrap(),
1058					d_name: PhantomData {},
1059				});
1060				let nameptr = core::ptr::from_mut(&mut (*(target_dirent)).d_name).cast::<u8>();
1061				core::ptr::copy_nonoverlapping(
1062					dirent.name.as_ptr().cast::<u8>(),
1063					nameptr,
1064					dirent.namelen as usize,
1065				);
1066				nameptr.add(dirent.namelen as usize).write(0); // zero termination
1067			}
1068
1069			*rsp_offset += core::mem::size_of::<fuse_dirent>() + dirent.namelen as usize;
1070			// Align to dirent struct
1071			*rsp_offset = ((*rsp_offset) + U64_SIZE - 1) & (!(U64_SIZE - 1));
1072			buf_offset = next_dirent;
1073			ret = buf_offset;
1074		}
1075
1076		let (cmd, rsp_payload_len) = ops::Release::create(fuse_nid, fuse_fh);
1077		get_filesystem_driver()
1078			.unwrap()
1079			.lock()
1080			.send_command(cmd, rsp_payload_len)?;
1081
1082		Ok(ret)
1083	}
1084
1085	/// lseek for a directory entry is the equivalent for seekdir on linux. But on Hermit this is
1086	/// logically the same operation, so we can just use the same fn in the backend.
1087	/// Any other offset than 0 is not supported. (Mostly because it doesn't make any sense, as
1088	/// userspace applications have no way of knowing valid offsets)
1089	async fn lseek(&self, offset: isize, whence: SeekWhence) -> io::Result<isize> {
1090		if whence != SeekWhence::Set && offset != 0 {
1091			error!("Invalid offset for directory lseek ({offset})");
1092			return Err(Errno::Inval);
1093		}
1094		*self.read_position.lock().await = offset as usize;
1095		Ok(offset)
1096	}
1097}
1098
1099#[derive(Debug)]
1100pub(crate) struct FuseDirectory {
1101	prefix: Option<String>,
1102	attr: FileAttr,
1103}
1104
1105impl FuseDirectory {
1106	pub fn new(prefix: Option<String>) -> Self {
1107		let microseconds = arch::kernel::systemtime::now_micros();
1108		let t = timespec::from_usec(microseconds as i64);
1109
1110		FuseDirectory {
1111			prefix,
1112			attr: FileAttr {
1113				st_mode: AccessPermission::from_bits(0o777).unwrap() | AccessPermission::S_IFDIR,
1114				st_atim: t,
1115				st_mtim: t,
1116				st_ctim: t,
1117				..Default::default()
1118			},
1119		}
1120	}
1121
1122	fn traversal_path(&self, components: &[&str]) -> CString {
1123		let prefix_deref = self.prefix.as_deref();
1124		let components_with_prefix = prefix_deref.iter().chain(components.iter().rev());
1125		let path: String = components_with_prefix
1126			.flat_map(|component| ["/", component])
1127			.collect();
1128		if path.is_empty() {
1129			CString::new("/").unwrap()
1130		} else {
1131			CString::new(path).unwrap()
1132		}
1133	}
1134}
1135
1136impl VfsNode for FuseDirectory {
1137	/// Returns the node type
1138	fn get_kind(&self) -> NodeKind {
1139		NodeKind::Directory
1140	}
1141
1142	fn get_file_attributes(&self) -> io::Result<FileAttr> {
1143		Ok(self.attr)
1144	}
1145
1146	fn get_object(&self) -> io::Result<Arc<async_lock::RwLock<dyn ObjectInterface>>> {
1147		Ok(Arc::new(async_lock::RwLock::new(FuseDirectoryHandle::new(
1148			self.prefix.clone(),
1149		))))
1150	}
1151
1152	fn traverse_readdir(&self, components: &mut Vec<&str>) -> io::Result<Vec<DirectoryEntry>> {
1153		let path = self.traversal_path(components);
1154
1155		debug!("FUSE opendir: {path:#?}");
1156
1157		let fuse_nid = lookup(path.clone()).ok_or(Errno::Noent)?;
1158
1159		// Opendir
1160		// Flag 0x10000 for O_DIRECTORY might not be necessary
1161		let (mut cmd, rsp_payload_len) = ops::Open::create(fuse_nid, 0x10000);
1162		cmd.headers.in_header.opcode = fuse_opcode::FUSE_OPENDIR as u32;
1163		let rsp = get_filesystem_driver()
1164			.ok_or(Errno::Nosys)?
1165			.lock()
1166			.send_command(cmd, rsp_payload_len)?;
1167		let fuse_fh = rsp.headers.op_header.fh;
1168
1169		debug!("FUSE readdir: {path:#?}");
1170
1171		// Linux seems to allocate a single page to store the dirfile
1172		let len = MAX_READ_LEN as u32;
1173		let mut offset: usize = 0;
1174
1175		// read content of the directory
1176		let (mut cmd, rsp_payload_len) = ops::Read::create(fuse_nid, fuse_fh, len, 0);
1177		cmd.headers.in_header.opcode = fuse_opcode::FUSE_READDIR as u32;
1178		let rsp = get_filesystem_driver()
1179			.ok_or(Errno::Nosys)?
1180			.lock()
1181			.send_command(cmd, rsp_payload_len)?;
1182
1183		let len: usize = if rsp.headers.out_header.len as usize - mem::size_of::<fuse_out_header>()
1184			>= usize::try_from(len).unwrap()
1185		{
1186			len.try_into().unwrap()
1187		} else {
1188			(rsp.headers.out_header.len as usize) - mem::size_of::<fuse_out_header>()
1189		};
1190
1191		if len <= core::mem::size_of::<fuse_dirent>() {
1192			debug!("FUSE no new dirs");
1193			return Err(Errno::Noent);
1194		}
1195
1196		let mut entries: Vec<DirectoryEntry> = Vec::new();
1197		while (rsp.headers.out_header.len as usize) - offset > core::mem::size_of::<fuse_dirent>() {
1198			let dirent = unsafe {
1199				&*rsp
1200					.payload
1201					.as_ref()
1202					.unwrap()
1203					.as_ptr()
1204					.byte_add(offset)
1205					.cast::<fuse_dirent>()
1206			};
1207
1208			offset += core::mem::size_of::<fuse_dirent>() + dirent.namelen as usize;
1209			// Align to dirent struct
1210			offset = ((offset) + U64_SIZE - 1) & (!(U64_SIZE - 1));
1211
1212			let name: &'static [u8] = unsafe {
1213				core::slice::from_raw_parts(
1214					dirent.name.as_ptr().cast(),
1215					dirent.namelen.try_into().unwrap(),
1216				)
1217			};
1218			entries.push(DirectoryEntry::new(unsafe {
1219				core::str::from_utf8_unchecked(name).to_string()
1220			}));
1221		}
1222
1223		let (cmd, rsp_payload_len) = ops::Release::create(fuse_nid, fuse_fh);
1224		get_filesystem_driver()
1225			.unwrap()
1226			.lock()
1227			.send_command(cmd, rsp_payload_len)?;
1228
1229		Ok(entries)
1230	}
1231
1232	fn traverse_stat(&self, components: &mut Vec<&str>) -> io::Result<FileAttr> {
1233		let path = self.traversal_path(components);
1234
1235		debug!("FUSE stat: {path:#?}");
1236
1237		// Is there a better way to implement this?
1238		let (cmd, rsp_payload_len) = ops::Lookup::create(path);
1239		let rsp = get_filesystem_driver()
1240			.unwrap()
1241			.lock()
1242			.send_command(cmd, rsp_payload_len)?;
1243
1244		if rsp.headers.out_header.error != 0 {
1245			return Err(Errno::try_from(-rsp.headers.out_header.error).unwrap());
1246		}
1247
1248		let entry_out = rsp.headers.op_header;
1249		let attr = entry_out.attr;
1250
1251		if attr.mode & S_IFMT != S_IFLNK {
1252			return Ok(FileAttr::from(attr));
1253		}
1254
1255		let path = readlink(entry_out.nodeid)?;
1256		let mut components: Vec<&str> = path.split('/').collect();
1257		self.traverse_stat(&mut components)
1258	}
1259
1260	fn traverse_lstat(&self, components: &mut Vec<&str>) -> io::Result<FileAttr> {
1261		let path = self.traversal_path(components);
1262
1263		debug!("FUSE lstat: {path:#?}");
1264
1265		let (cmd, rsp_payload_len) = ops::Lookup::create(path);
1266		let rsp = get_filesystem_driver()
1267			.unwrap()
1268			.lock()
1269			.send_command(cmd, rsp_payload_len)?;
1270		Ok(FileAttr::from(rsp.headers.op_header.attr))
1271	}
1272
1273	fn traverse_open(
1274		&self,
1275		components: &mut Vec<&str>,
1276		opt: OpenOption,
1277		mode: AccessPermission,
1278	) -> io::Result<Arc<async_lock::RwLock<dyn ObjectInterface>>> {
1279		let path = self.traversal_path(components);
1280
1281		debug!("FUSE open: {path:#?}, {opt:?} {mode:?}");
1282
1283		if opt.contains(OpenOption::O_DIRECTORY) {
1284			if opt.contains(OpenOption::O_CREAT) {
1285				// See https://lwn.net/Articles/926782/
1286				warn!("O_DIRECTORY and O_CREAT are together invalid as open options.");
1287				return Err(Errno::Inval);
1288			}
1289
1290			let (cmd, rsp_payload_len) = ops::Lookup::create(path.clone());
1291			let rsp = get_filesystem_driver()
1292				.unwrap()
1293				.lock()
1294				.send_command(cmd, rsp_payload_len)?;
1295
1296			let attr = FileAttr::from(rsp.headers.op_header.attr);
1297			if attr.st_mode.contains(AccessPermission::S_IFDIR) {
1298				let mut path = path.into_string().unwrap();
1299				path.remove(0);
1300				Ok(Arc::new(async_lock::RwLock::new(FuseDirectoryHandle::new(
1301					Some(path),
1302				))))
1303			} else {
1304				Err(Errno::Notdir)
1305			}
1306		} else {
1307			let file = FuseFileHandle::new();
1308
1309			// 1.FUSE_INIT to create session
1310			// Already done
1311			let mut file_guard = block_on(async { Ok(file.0.lock().await) }, None)?;
1312
1313			// Differentiate between opening and creating new file, since fuse does not support O_CREAT on open.
1314			if opt.contains(OpenOption::O_CREAT) {
1315				// Create file (opens implicitly, returns results from both lookup and open calls)
1316				let (cmd, rsp_payload_len) =
1317					ops::Create::create(path, opt.bits().try_into().unwrap(), mode.bits());
1318				let rsp = get_filesystem_driver()
1319					.ok_or(Errno::Nosys)?
1320					.lock()
1321					.send_command(cmd, rsp_payload_len)?;
1322
1323				let inner = rsp.headers.op_header;
1324				file_guard.fuse_nid = Some(inner.entry.nodeid);
1325				file_guard.fuse_fh = Some(inner.open.fh);
1326			} else {
1327				// 2.FUSE_LOOKUP(FUSE_ROOT_ID, “foo”) -> nodeid
1328				file_guard.fuse_nid = lookup(path);
1329
1330				if file_guard.fuse_nid.is_none() {
1331					warn!("Fuse lookup seems to have failed!");
1332					return Err(Errno::Noent);
1333				}
1334
1335				// 3.FUSE_OPEN(nodeid, O_RDONLY) -> fh
1336				let (cmd, rsp_payload_len) =
1337					ops::Open::create(file_guard.fuse_nid.unwrap(), opt.bits().try_into().unwrap());
1338				let rsp = get_filesystem_driver()
1339					.ok_or(Errno::Nosys)?
1340					.lock()
1341					.send_command(cmd, rsp_payload_len)?;
1342				file_guard.fuse_fh = Some(rsp.headers.op_header.fh);
1343			}
1344
1345			drop(file_guard);
1346
1347			Ok(Arc::new(async_lock::RwLock::new(file)))
1348		}
1349	}
1350
1351	fn traverse_unlink(&self, components: &mut Vec<&str>) -> io::Result<()> {
1352		let path = self.traversal_path(components);
1353
1354		let (cmd, rsp_payload_len) = ops::Unlink::create(path);
1355		let rsp = get_filesystem_driver()
1356			.ok_or(Errno::Nosys)?
1357			.lock()
1358			.send_command(cmd, rsp_payload_len)?;
1359		trace!("unlink answer {rsp:?}");
1360
1361		Ok(())
1362	}
1363
1364	fn traverse_rmdir(&self, components: &mut Vec<&str>) -> io::Result<()> {
1365		let path = self.traversal_path(components);
1366
1367		let (cmd, rsp_payload_len) = ops::Rmdir::create(path);
1368		let rsp = get_filesystem_driver()
1369			.ok_or(Errno::Nosys)?
1370			.lock()
1371			.send_command(cmd, rsp_payload_len)?;
1372		trace!("rmdir answer {rsp:?}");
1373
1374		Ok(())
1375	}
1376
1377	fn traverse_mkdir(&self, components: &mut Vec<&str>, mode: AccessPermission) -> io::Result<()> {
1378		let path = self.traversal_path(components);
1379		let (cmd, rsp_payload_len) = ops::Mkdir::create(path, mode.bits());
1380
1381		let rsp = get_filesystem_driver()
1382			.ok_or(Errno::Nosys)?
1383			.lock()
1384			.send_command(cmd, rsp_payload_len)?;
1385		if rsp.headers.out_header.error == 0 {
1386			Ok(())
1387		} else {
1388			Err(Errno::try_from(-rsp.headers.out_header.error).unwrap())
1389		}
1390	}
1391}
1392
1393pub(crate) fn init() {
1394	debug!("Try to initialize fuse filesystem");
1395
1396	if let Some(driver) = get_filesystem_driver() {
1397		let (cmd, rsp_payload_len) = ops::Init::create();
1398		let rsp = driver.lock().send_command(cmd, rsp_payload_len).unwrap();
1399		trace!("fuse init answer: {rsp:?}");
1400
1401		let mount_point = driver.lock().get_mount_point();
1402		if mount_point == "/" {
1403			let fuse_nid = lookup(c"/".to_owned()).unwrap();
1404			// Opendir
1405			// Flag 0x10000 for O_DIRECTORY might not be necessary
1406			let (mut cmd, rsp_payload_len) = ops::Open::create(fuse_nid, 0x10000);
1407			cmd.headers.in_header.opcode = fuse_opcode::FUSE_OPENDIR as u32;
1408			let rsp = get_filesystem_driver()
1409				.unwrap()
1410				.lock()
1411				.send_command(cmd, rsp_payload_len)
1412				.unwrap();
1413			let fuse_fh = rsp.headers.op_header.fh;
1414
1415			// Linux seems to allocate a single page to store the dirfile
1416			let len = MAX_READ_LEN as u32;
1417			let mut offset: usize = 0;
1418
1419			// read content of the directory
1420			let (mut cmd, rsp_payload_len) = ops::Read::create(fuse_nid, fuse_fh, len, 0);
1421			cmd.headers.in_header.opcode = fuse_opcode::FUSE_READDIR as u32;
1422			let rsp = get_filesystem_driver()
1423				.unwrap()
1424				.lock()
1425				.send_command(cmd, rsp_payload_len)
1426				.unwrap();
1427
1428			let len: usize = if rsp.headers.out_header.len as usize
1429				- mem::size_of::<fuse_out_header>()
1430				>= usize::try_from(len).unwrap()
1431			{
1432				len.try_into().unwrap()
1433			} else {
1434				(rsp.headers.out_header.len as usize) - mem::size_of::<fuse_out_header>()
1435			};
1436
1437			assert!(
1438				len > core::mem::size_of::<fuse_dirent>(),
1439				"FUSE no new dirs"
1440			);
1441
1442			let mut entries: Vec<String> = Vec::new();
1443			while (rsp.headers.out_header.len as usize) - offset
1444				> core::mem::size_of::<fuse_dirent>()
1445			{
1446				let dirent = unsafe {
1447					&*rsp
1448						.payload
1449						.as_ref()
1450						.unwrap()
1451						.as_ptr()
1452						.byte_add(offset)
1453						.cast::<fuse_dirent>()
1454				};
1455
1456				offset += core::mem::size_of::<fuse_dirent>() + dirent.namelen as usize;
1457				// Align to dirent struct
1458				offset = ((offset) + U64_SIZE - 1) & (!(U64_SIZE - 1));
1459
1460				let name: &'static [u8] = unsafe {
1461					core::slice::from_raw_parts(
1462						dirent.name.as_ptr().cast(),
1463						dirent.namelen.try_into().unwrap(),
1464					)
1465				};
1466				entries.push(unsafe { core::str::from_utf8_unchecked(name).to_string() });
1467			}
1468
1469			let (cmd, rsp_payload_len) = ops::Release::create(fuse_nid, fuse_fh);
1470			get_filesystem_driver()
1471				.unwrap()
1472				.lock()
1473				.send_command(cmd, rsp_payload_len)
1474				.unwrap();
1475
1476			// remove predefined directories
1477			entries.retain(|x| x != ".");
1478			entries.retain(|x| x != "..");
1479			entries.retain(|x| x != "tmp");
1480			entries.retain(|x| x != "proc");
1481			warn!(
1482				"Fuse don't mount the host directories 'tmp' and 'proc' into the guest file system!"
1483			);
1484
1485			for i in entries {
1486				let i_cstr = CString::new(i.clone()).unwrap();
1487				let (cmd, rsp_payload_len) = ops::Lookup::create(i_cstr);
1488				let rsp = get_filesystem_driver()
1489					.unwrap()
1490					.lock()
1491					.send_command(cmd, rsp_payload_len)
1492					.unwrap();
1493
1494				let attr = FileAttr::from(rsp.headers.op_header.attr);
1495				if attr.st_mode.contains(AccessPermission::S_IFDIR) {
1496					info!("Fuse mount {i} to /{i}");
1497					fs::FILESYSTEM
1498						.get()
1499						.unwrap()
1500						.mount(
1501							&("/".to_owned() + i.as_str()),
1502							Box::new(FuseDirectory::new(Some(i))),
1503						)
1504						.expect("Mount failed. Invalid mount_point?");
1505				} else {
1506					warn!("Fuse don't mount {i}. It isn't a directory!");
1507				}
1508			}
1509		} else {
1510			let mount_point = if mount_point.starts_with('/') {
1511				mount_point
1512			} else {
1513				"/".to_owned() + &mount_point
1514			};
1515
1516			info!("Mounting virtio-fs at {mount_point}");
1517			fs::FILESYSTEM
1518				.get()
1519				.unwrap()
1520				.mount(mount_point.as_str(), Box::new(FuseDirectory::new(None)))
1521				.expect("Mount failed. Invalid mount_point?");
1522		}
1523	}
1524}