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
38const 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 SetAttrValidFields::FATTR_LOCKOWNER,
319 )
320 .bits(),
321 padding: 0,
322 fh,
323
324 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, },
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 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)]
611pub(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 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 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 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 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 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 break;
1046 }
1047
1048 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); }
1068
1069 *rsp_offset += core::mem::size_of::<fuse_dirent>() + dirent.namelen as usize;
1070 *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 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 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 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 let len = MAX_READ_LEN as u32;
1173 let mut offset: usize = 0;
1174
1175 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 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 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 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 let mut file_guard = block_on(async { Ok(file.0.lock().await) }, None)?;
1312
1313 if opt.contains(OpenOption::O_CREAT) {
1315 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 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 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 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 let len = MAX_READ_LEN as u32;
1417 let mut offset: usize = 0;
1418
1419 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 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 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}