@@ -72,6 +72,7 @@ struct LinuxDirent64 {
72
72
d_reclen : libc:: c_ushort ,
73
73
d_ty : libc:: c_uchar ,
74
74
}
75
+
75
76
unsafe impl ByteValued for LinuxDirent64 { }
76
77
77
78
fn ebadf ( ) -> io:: Error {
@@ -522,21 +523,143 @@ fn read_rosetta_data() -> io::Result<Vec<u8>> {
522
523
Ok ( data)
523
524
}
524
525
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
+
525
631
impl PassthroughFs {
526
632
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
+
527
650
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 ) ,
530
653
init_inode : fuse:: ROOT_ID + 1 ,
531
- path_cache : Mutex :: new ( BTreeMap :: new ( ) ) ,
654
+ path_cache : Mutex :: new ( path_cache ) ,
532
655
file_cache : Mutex :: new ( LruCache :: new ( NonZeroUsize :: new ( 256 ) . unwrap ( ) ) ) ,
533
656
pinned_files : Mutex :: new ( BTreeMap :: new ( ) ) ,
534
657
535
658
handles : RwLock :: new ( BTreeMap :: new ( ) ) ,
536
659
next_handle : AtomicU64 :: new ( 1 ) ,
537
660
init_handle : 0 ,
538
661
539
- host_volumes : RwLock :: new ( HashMap :: new ( ) ) ,
662
+ host_volumes : RwLock :: new ( host_volumes ) ,
540
663
writeback : AtomicBool :: new ( false ) ,
541
664
542
665
rosetta_data : read_rosetta_data ( ) . ok ( ) ,
@@ -1021,102 +1144,6 @@ impl FileSystem for PassthroughFs {
1021
1144
type Handle = Handle ;
1022
1145
1023
1146
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
-
1120
1147
let mut opts = FsOptions :: empty ( ) ;
1121
1148
if self . cfg . writeback && capable. contains ( FsOptions :: WRITEBACK_CACHE ) {
1122
1149
opts |= FsOptions :: WRITEBACK_CACHE ;
0 commit comments