@@ -72,6 +72,7 @@ struct LinuxDirent64 {
7272 d_reclen : libc:: c_ushort ,
7373 d_ty : libc:: c_uchar ,
7474}
75+
7576unsafe impl ByteValued for LinuxDirent64 { }
7677
7778fn ebadf ( ) -> io:: Error {
@@ -522,21 +523,143 @@ fn read_rosetta_data() -> io::Result<Vec<u8>> {
522523 Ok ( data)
523524}
524525
526+ fn insert_root_dir (
527+ root_dir : & str ,
528+ inodes : & mut MultikeyBTreeMap < Inode , InodeAltKey , Arc < InodeData > > ,
529+ path_cache : & mut BTreeMap < Inode , Vec < String > > ,
530+ ) -> io:: Result < ( ) > {
531+ let root_dir_cstr = CString :: new ( root_dir) . expect ( "CString::new failed" ) ;
532+
533+ // Safe because this doesn't modify any memory and we check the return value.
534+ let fd = unsafe {
535+ libc:: openat (
536+ libc:: AT_FDCWD ,
537+ root_dir_cstr. as_ptr ( ) ,
538+ libc:: O_NOFOLLOW | libc:: O_CLOEXEC ,
539+ )
540+ } ;
541+ if fd < 0 {
542+ return Err ( linux_error ( io:: Error :: last_os_error ( ) ) ) ;
543+ }
544+
545+ // Safe because we just opened this fd above.
546+ let f = unsafe { File :: from_raw_fd ( fd) } ;
547+
548+ let st = fstat ( & f) ?;
549+
550+ // Safe because this doesn't modify any memory and there is no need to check the return
551+ // value because this system call always succeeds. We need to clear the umask here because
552+ // we want the client to be able to set all the bits in the mode.
553+ unsafe { libc:: umask ( 0o000 ) } ;
554+
555+ // Not sure why the root inode gets a refcount of 2 but that's what libfuse does.
556+ inodes. insert (
557+ fuse:: ROOT_ID ,
558+ InodeAltKey {
559+ ino : st. st_ino ,
560+ dev : st. st_dev ,
561+ } ,
562+ Arc :: new ( InodeData {
563+ inode : fuse:: ROOT_ID ,
564+ linkdata : CString :: new ( "" ) . unwrap ( ) ,
565+ refcount : AtomicU64 :: new ( 2 ) ,
566+ } ) ,
567+ ) ;
568+ add_path ( path_cache, fuse:: ROOT_ID , root_dir. to_owned ( ) ) ;
569+ Ok ( ( ) )
570+ }
571+
572+ fn insert_mapped_volumes (
573+ mapped_volumes : & [ ( PathBuf , PathBuf ) ] ,
574+ inodes : & mut MultikeyBTreeMap < Inode , InodeAltKey , Arc < InodeData > > ,
575+ next_inode : & mut u64 ,
576+ path_cache : & mut BTreeMap < Inode , Vec < String > > ,
577+ host_volumes : & mut HashMap < String , u64 > ,
578+ ) -> io:: Result < ( ) > {
579+ for ( host_vol, guest_vol) in mapped_volumes {
580+ assert ! ( host_vol. is_absolute( ) ) ;
581+ assert ! ( guest_vol. is_absolute( ) ) ;
582+ assert_eq ! ( guest_vol. components( ) . count( ) , 2 ) ;
583+
584+ let guest_vol_str = guest_vol
585+ . file_name ( )
586+ . unwrap ( )
587+ . to_str ( )
588+ . expect ( "Couldn't parse guest volume as String" ) ;
589+ let host_vol_str = host_vol
590+ . to_str ( )
591+ . expect ( "Couldn't parse host volume as String" ) ;
592+ let path = CString :: new ( host_vol_str) . expect ( "Couldn't parse volume as CString" ) ;
593+ // Safe because this doesn't modify any memory and we check the return value.
594+ let fd = unsafe { libc:: open ( path. as_ptr ( ) , libc:: O_NOFOLLOW | libc:: O_CLOEXEC ) } ;
595+ if fd < 0 {
596+ error ! (
597+ "Error setting up mapped volume: {:?}:{:?}: {:?}" ,
598+ host_vol,
599+ guest_vol,
600+ io:: Error :: last_os_error( ) ,
601+ ) ;
602+ continue ;
603+ }
604+
605+ // Safe because we just opened this fd above.
606+ let f = unsafe { File :: from_raw_fd ( fd) } ;
607+
608+ let st = fstat ( & f) ?;
609+ let inode = * next_inode;
610+ * next_inode += 1 ;
611+
612+ inodes. insert (
613+ inode,
614+ InodeAltKey {
615+ ino : st. st_ino ,
616+ dev : st. st_dev ,
617+ } ,
618+ Arc :: new ( InodeData {
619+ inode,
620+ linkdata : CString :: new ( "" ) . unwrap ( ) ,
621+ refcount : AtomicU64 :: new ( 1 ) ,
622+ } ) ,
623+ ) ;
624+ add_path ( path_cache, inode, host_vol_str. to_string ( ) ) ;
625+ host_volumes. insert ( guest_vol_str. to_string ( ) , inode) ;
626+ }
627+
628+ Ok ( ( ) )
629+ }
630+
525631impl PassthroughFs {
526632 pub fn new ( cfg : Config ) -> io:: Result < PassthroughFs > {
633+ let mut inodes = MultikeyBTreeMap :: new ( ) ;
634+ let mut next_inode = fuse:: ROOT_ID + 2 ;
635+ let mut path_cache = BTreeMap :: new ( ) ;
636+ let mut host_volumes = HashMap :: new ( ) ;
637+
638+ insert_root_dir ( & cfg. root_dir , & mut inodes, & mut path_cache) ?;
639+
640+ if let Some ( mapped_volumes) = & cfg. mapped_volumes {
641+ insert_mapped_volumes (
642+ mapped_volumes,
643+ & mut inodes,
644+ & mut next_inode,
645+ & mut path_cache,
646+ & mut host_volumes,
647+ ) ?;
648+ }
649+
527650 Ok ( PassthroughFs {
528- inodes : RwLock :: new ( MultikeyBTreeMap :: new ( ) ) ,
529- next_inode : AtomicU64 :: new ( fuse :: ROOT_ID + 2 ) ,
651+ inodes : RwLock :: new ( inodes ) ,
652+ next_inode : AtomicU64 :: new ( next_inode ) ,
530653 init_inode : fuse:: ROOT_ID + 1 ,
531- path_cache : Mutex :: new ( BTreeMap :: new ( ) ) ,
654+ path_cache : Mutex :: new ( path_cache ) ,
532655 file_cache : Mutex :: new ( LruCache :: new ( NonZeroUsize :: new ( 256 ) . unwrap ( ) ) ) ,
533656 pinned_files : Mutex :: new ( BTreeMap :: new ( ) ) ,
534657
535658 handles : RwLock :: new ( BTreeMap :: new ( ) ) ,
536659 next_handle : AtomicU64 :: new ( 1 ) ,
537660 init_handle : 0 ,
538661
539- host_volumes : RwLock :: new ( HashMap :: new ( ) ) ,
662+ host_volumes : RwLock :: new ( host_volumes ) ,
540663 writeback : AtomicBool :: new ( false ) ,
541664
542665 rosetta_data : read_rosetta_data ( ) . ok ( ) ,
@@ -1021,102 +1144,6 @@ impl FileSystem for PassthroughFs {
10211144 type Handle = Handle ;
10221145
10231146 fn init ( & self , capable : FsOptions ) -> io:: Result < FsOptions > {
1024- let root = CString :: new ( self . cfg . root_dir . as_str ( ) ) . expect ( "CString::new failed" ) ;
1025-
1026- // Safe because this doesn't modify any memory and we check the return value.
1027- let fd = unsafe {
1028- libc:: openat (
1029- libc:: AT_FDCWD ,
1030- root. as_ptr ( ) ,
1031- libc:: O_NOFOLLOW | libc:: O_CLOEXEC ,
1032- )
1033- } ;
1034- if fd < 0 {
1035- return Err ( linux_error ( io:: Error :: last_os_error ( ) ) ) ;
1036- }
1037-
1038- // Safe because we just opened this fd above.
1039- let f = unsafe { File :: from_raw_fd ( fd) } ;
1040-
1041- let st = fstat ( & f) ?;
1042-
1043- // Safe because this doesn't modify any memory and there is no need to check the return
1044- // value because this system call always succeeds. We need to clear the umask here because
1045- // we want the client to be able to set all the bits in the mode.
1046- unsafe { libc:: umask ( 0o000 ) } ;
1047-
1048- let mut inodes = self . inodes . write ( ) . unwrap ( ) ;
1049-
1050- // Not sure why the root inode gets a refcount of 2 but that's what libfuse does.
1051- inodes. insert (
1052- fuse:: ROOT_ID ,
1053- InodeAltKey {
1054- ino : st. st_ino ,
1055- dev : st. st_dev ,
1056- } ,
1057- Arc :: new ( InodeData {
1058- inode : fuse:: ROOT_ID ,
1059- linkdata : CString :: new ( "" ) . unwrap ( ) ,
1060- refcount : AtomicU64 :: new ( 2 ) ,
1061- } ) ,
1062- ) ;
1063-
1064- let mut path_cache = self . path_cache . lock ( ) . unwrap ( ) ;
1065- add_path ( & mut path_cache, fuse:: ROOT_ID , self . cfg . root_dir . clone ( ) ) ;
1066-
1067- if let Some ( mapped_volumes) = & self . cfg . mapped_volumes {
1068- for ( host_vol, guest_vol) in mapped_volumes. iter ( ) {
1069- assert ! ( host_vol. is_absolute( ) ) ;
1070- assert ! ( guest_vol. is_absolute( ) ) ;
1071- assert_eq ! ( guest_vol. components( ) . count( ) , 2 ) ;
1072-
1073- let guest_vol_str = guest_vol
1074- . file_name ( )
1075- . unwrap ( )
1076- . to_str ( )
1077- . expect ( "Couldn't parse guest volume as String" ) ;
1078- let host_vol_str = host_vol
1079- . to_str ( )
1080- . expect ( "Couldn't parse host volume as String" ) ;
1081- let path = CString :: new ( host_vol_str) . expect ( "Couldn't parse volume as CString" ) ;
1082- // Safe because this doesn't modify any memory and we check the return value.
1083- let fd = unsafe { libc:: open ( path. as_ptr ( ) , libc:: O_NOFOLLOW | libc:: O_CLOEXEC ) } ;
1084- if fd < 0 {
1085- error ! (
1086- "Error setting up mapped volume: {:?}:{:?}: {:?}" ,
1087- host_vol,
1088- guest_vol,
1089- io:: Error :: last_os_error( ) ,
1090- ) ;
1091- continue ;
1092- }
1093-
1094- // Safe because we just opened this fd above.
1095- let f = unsafe { File :: from_raw_fd ( fd) } ;
1096-
1097- let st = fstat ( & f) ?;
1098- let inode = self . next_inode . fetch_add ( 1 , Ordering :: Relaxed ) ;
1099-
1100- inodes. insert (
1101- inode,
1102- InodeAltKey {
1103- ino : st. st_ino ,
1104- dev : st. st_dev ,
1105- } ,
1106- Arc :: new ( InodeData {
1107- inode,
1108- linkdata : CString :: new ( "" ) . unwrap ( ) ,
1109- refcount : AtomicU64 :: new ( 1 ) ,
1110- } ) ,
1111- ) ;
1112- add_path ( & mut path_cache, inode, host_vol_str. to_string ( ) ) ;
1113- self . host_volumes
1114- . write ( )
1115- . unwrap ( )
1116- . insert ( guest_vol_str. to_string ( ) , inode) ;
1117- }
1118- }
1119-
11201147 let mut opts = FsOptions :: empty ( ) ;
11211148 if self . cfg . writeback && capable. contains ( FsOptions :: WRITEBACK_CACHE ) {
11221149 opts |= FsOptions :: WRITEBACK_CACHE ;
0 commit comments