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