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
37const 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 SetAttrValidFields::FATTR_LOCKOWNER,
318 )
319 .bits(),
320 padding: 0,
321 fh,
322
323 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, },
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 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)]
610pub(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 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 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 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 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 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 break;
1043 }
1044
1045 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); }
1065
1066 *rsp_offset += core::mem::size_of::<fuse_dirent>() + dirent.namelen as usize;
1067 *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 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 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 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 let len = MAX_READ_LEN as u32;
1170 let mut offset: usize = 0;
1171
1172 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 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 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 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 let mut file_guard = block_on(async { Ok(file.0.lock().await) }, None)?;
1309
1310 if opt.contains(OpenOption::O_CREAT) {
1312 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 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 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 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 let len = MAX_READ_LEN as u32;
1414 let mut offset: usize = 0;
1415
1416 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 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 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}