@@ -29,10 +29,10 @@ use crate::fs::{
2929 self , AccessPermission , DirectoryEntry , FileAttr , NodeKind , ObjectInterface , OpenOption ,
3030 SeekWhence , VfsNode ,
3131} ;
32+ use crate :: io;
3233use crate :: mm:: device_alloc:: DeviceAlloc ;
3334use crate :: syscalls:: Dirent64 ;
3435use crate :: time:: { time_t, timespec} ;
35- use crate :: { arch, io} ;
3636
3737// response out layout eg @ https://github.com/zargony/fuse-rs/blob/bf6d1cf03f3277e35b580f3c7b9999255d72ecf3/src/ll/request.rs#L44
3838// op in/out sizes/layout: https://github.com/hanwen/go-fuse/blob/204b45dba899dfa147235c255908236d5fde2d32/fuse/opcode.go#L439
@@ -1093,61 +1093,78 @@ impl ObjectInterface for FuseDirectoryHandle {
10931093 }
10941094}
10951095
1096- #[ derive( Debug ) ]
1096+ #[ derive( Clone , Debug ) ]
1097+ // The `original_prefix` is the one the directory was originally initialized with,
1098+ // `prefix` is the current prefix (normally, `prefix` has `original_prefix` as its prefix).
1099+ // This distinction is used for symlink resolution and directory traversal.
10971100pub ( crate ) struct FuseDirectory {
1098- prefix : Option < String > ,
1099- attr : FileAttr ,
1101+ original_prefix : Arc < str > ,
1102+ prefix : String ,
11001103}
11011104
11021105impl FuseDirectory {
11031106 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-
11071107 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- } ,
1108+ original_prefix : Arc :: from ( prefix. as_deref ( ) . unwrap_or_default ( ) ) ,
1109+ prefix : prefix. unwrap_or_default ( ) ,
11161110 }
11171111 }
11181112
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 ( )
1113+ fn traversal_this ( & self ) -> CString {
1114+ let mut path = String :: new ( ) ;
1115+ path. push ( '/' ) ;
1116+ path. push_str ( & self . prefix ) ;
1117+ CString :: new ( path) . unwrap ( )
1118+ }
1119+
1120+ fn traversal_path ( & self , component : & str ) -> CString {
1121+ let mut path = String :: new ( ) ;
1122+ if !self . prefix . is_empty ( ) {
1123+ path. push ( '/' ) ;
1124+ path. push_str ( & self . prefix ) ;
11291125 }
1126+ path. push ( '/' ) ;
1127+ path. push_str ( component) ;
1128+ CString :: new ( path) . unwrap ( )
11301129 }
11311130}
11321131
1132+ #[ async_trait]
11331133impl VfsNode for FuseDirectory {
11341134 /// Returns the node type
11351135 fn get_kind ( & self ) -> NodeKind {
11361136 NodeKind :: Directory
11371137 }
11381138
1139- fn get_file_attributes ( & self ) -> io:: Result < FileAttr > {
1140- Ok ( self . attr )
1141- }
1142-
11431139 fn get_object ( & self ) -> io:: Result < Arc < async_lock:: RwLock < dyn ObjectInterface > > > {
11441140 Ok ( Arc :: new ( async_lock:: RwLock :: new ( FuseDirectoryHandle :: new (
1145- self . prefix . clone ( ) ,
1141+ if self . prefix . is_empty ( ) {
1142+ None
1143+ } else {
1144+ Some ( self . prefix . clone ( ) )
1145+ } ,
11461146 ) ) ) )
11471147 }
11481148
1149- fn traverse_readdir ( & self , components : & mut Vec < & str > ) -> io:: Result < Vec < DirectoryEntry > > {
1150- let path = self . traversal_path ( components) ;
1149+ fn dup ( & self ) -> Box < dyn VfsNode > {
1150+ Box :: new ( self . clone ( ) )
1151+ }
1152+
1153+ async fn traverse_once ( & self , component : & str ) -> io:: Result < Box < dyn VfsNode > > {
1154+ let mut prefix = self . prefix . clone ( ) ;
1155+ if !prefix. is_empty ( ) {
1156+ prefix. push ( '/' ) ;
1157+ }
1158+ prefix. push_str ( component) ;
1159+
1160+ Ok ( Box :: new ( Self {
1161+ original_prefix : Arc :: clone ( & self . original_prefix ) ,
1162+ prefix,
1163+ } ) )
1164+ }
1165+
1166+ async fn readdir ( & self ) -> io:: Result < Vec < DirectoryEntry > > {
1167+ let path = self . traversal_this ( ) ;
11511168
11521169 debug ! ( "FUSE opendir: {path:#?}" ) ;
11531170
@@ -1226,36 +1243,54 @@ impl VfsNode for FuseDirectory {
12261243 Ok ( entries)
12271244 }
12281245
1229- fn traverse_stat ( & self , components : & mut Vec < & str > ) -> io:: Result < FileAttr > {
1230- let path = self . traversal_path ( components ) ;
1246+ async fn stat ( & self ) -> io:: Result < FileAttr > {
1247+ let mut prefix = alloc :: borrow :: Cow :: Borrowed ( & self . prefix ) ;
12311248
1232- debug ! ( "FUSE stat: {path:#?}" ) ;
1249+ loop {
1250+ let mut path = String :: new ( ) ;
1251+ path. push ( '/' ) ;
1252+ path. push_str ( & * prefix) ;
1253+ let path = CString :: new ( path) . unwrap ( ) ;
12331254
1234- // Is there a better way to implement this?
1235- let ( cmd, rsp_payload_len) = ops:: Lookup :: create ( path) ;
1236- let rsp = get_filesystem_driver ( )
1237- . unwrap ( )
1238- . lock ( )
1239- . send_command ( cmd, rsp_payload_len) ?;
1255+ debug ! ( "FUSE stat: {path:#?}" ) ;
12401256
1241- if rsp. headers . out_header . error != 0 {
1242- return Err ( Errno :: try_from ( -rsp. headers . out_header . error ) . unwrap ( ) ) ;
1243- }
1257+ // Is there a better way to implement this?
1258+ let ( cmd, rsp_payload_len) = ops:: Lookup :: create ( path) ;
1259+ let rsp = get_filesystem_driver ( )
1260+ . unwrap ( )
1261+ . lock ( )
1262+ . send_command ( cmd, rsp_payload_len) ?;
12441263
1245- let entry_out = rsp. headers . op_header ;
1246- let attr = entry_out. attr ;
1264+ if rsp. headers . out_header . error != 0 {
1265+ break Err ( Errno :: try_from ( -rsp. headers . out_header . error ) . unwrap ( ) ) ;
1266+ }
12471267
1248- if attr. mode & S_IFMT != S_IFLNK {
1249- return Ok ( FileAttr :: from ( attr) ) ;
1250- }
1268+ let entry_out = rsp. headers . op_header ;
1269+ let attr = entry_out. attr ;
1270+
1271+ if attr. mode & S_IFMT != S_IFLNK {
1272+ break Ok ( FileAttr :: from ( attr) ) ;
1273+ }
12511274
1252- let path = readlink ( entry_out. nodeid ) ?;
1253- let mut components: Vec < & str > = path. split ( '/' ) . collect ( ) ;
1254- self . traverse_stat ( & mut components)
1275+ let path = readlink ( entry_out. nodeid ) ?;
1276+
1277+ // rewind and re-traverse
1278+ let mut new_prefix: String = ( * self . original_prefix ) . to_owned ( ) ;
1279+ if !path. starts_with ( '/' ) {
1280+ new_prefix. push ( '/' ) ;
1281+ }
1282+
1283+ // handle infinite recursion
1284+ new_prefix. push_str ( & path) ;
1285+ if & new_prefix == & * prefix {
1286+ break Err ( Errno :: Loop ) ;
1287+ }
1288+ prefix = alloc:: borrow:: Cow :: Owned ( new_prefix) ;
1289+ }
12551290 }
12561291
1257- fn traverse_lstat ( & self , components : & mut Vec < & str > ) -> io:: Result < FileAttr > {
1258- let path = self . traversal_path ( components ) ;
1292+ async fn lstat ( & self ) -> io:: Result < FileAttr > {
1293+ let path = self . traversal_this ( ) ;
12591294
12601295 debug ! ( "FUSE lstat: {path:#?}" ) ;
12611296
@@ -1267,13 +1302,13 @@ impl VfsNode for FuseDirectory {
12671302 Ok ( FileAttr :: from ( rsp. headers . op_header . attr ) )
12681303 }
12691304
1270- fn traverse_open (
1305+ async fn open (
12711306 & self ,
1272- components : & mut Vec < & str > ,
1307+ component : & str ,
12731308 opt : OpenOption ,
12741309 mode : AccessPermission ,
12751310 ) -> io:: Result < Arc < async_lock:: RwLock < dyn ObjectInterface > > > {
1276- let path = self . traversal_path ( components ) ;
1311+ let path = self . traversal_path ( component ) ;
12771312
12781313 debug ! ( "FUSE open: {path:#?}, {opt:?} {mode:?}" ) ;
12791314
@@ -1345,8 +1380,8 @@ impl VfsNode for FuseDirectory {
13451380 }
13461381 }
13471382
1348- fn traverse_unlink ( & self , components : & mut Vec < & str > ) -> io:: Result < ( ) > {
1349- let path = self . traversal_path ( components ) ;
1383+ async fn unlink ( & self , component : & str ) -> io:: Result < ( ) > {
1384+ let path = self . traversal_path ( component ) ;
13501385
13511386 let ( cmd, rsp_payload_len) = ops:: Unlink :: create ( path) ;
13521387 let rsp = get_filesystem_driver ( )
@@ -1358,8 +1393,8 @@ impl VfsNode for FuseDirectory {
13581393 Ok ( ( ) )
13591394 }
13601395
1361- fn traverse_rmdir ( & self , components : & mut Vec < & str > ) -> io:: Result < ( ) > {
1362- let path = self . traversal_path ( components ) ;
1396+ async fn rmdir ( & self , component : & str ) -> io:: Result < ( ) > {
1397+ let path = self . traversal_path ( component ) ;
13631398
13641399 let ( cmd, rsp_payload_len) = ops:: Rmdir :: create ( path) ;
13651400 let rsp = get_filesystem_driver ( )
@@ -1371,8 +1406,8 @@ impl VfsNode for FuseDirectory {
13711406 Ok ( ( ) )
13721407 }
13731408
1374- fn traverse_mkdir ( & self , components : & mut Vec < & str > , mode : AccessPermission ) -> io:: Result < ( ) > {
1375- let path = self . traversal_path ( components ) ;
1409+ async fn mkdir ( & self , component : & str , mode : AccessPermission ) -> io:: Result < ( ) > {
1410+ let path = self . traversal_path ( component ) ;
13761411 let ( cmd, rsp_payload_len) = ops:: Mkdir :: create ( path, mode. bits ( ) ) ;
13771412
13781413 let rsp = get_filesystem_driver ( )
0 commit comments