@@ -37,7 +37,7 @@ impl FsPermissions {
37
37
/// Caution: This should be called with normalized paths if the `allowed_paths` are also
38
38
/// normalized.
39
39
pub fn is_path_allowed ( & self , path : & Path , kind : FsAccessKind ) -> bool {
40
- self . find_permission ( path) . map ( |perm| perm. is_granted ( kind) ) . unwrap_or_default ( )
40
+ self . find_all_permissions ( path) . iter ( ) . any ( |perm| perm. is_granted ( kind) )
41
41
}
42
42
43
43
/// Returns the permission for the matching path.
@@ -66,6 +66,39 @@ impl FsPermissions {
66
66
permission. map ( |perm| perm. access )
67
67
}
68
68
69
+ /// Returns all permissions for the matching path.
70
+ ///
71
+ /// This finds the longest matching paths with resolved sym links, e.g. if we have the following
72
+ /// permissions:
73
+ ///
74
+ /// `./out` = `read`
75
+ /// `./out/contracts` = `read`
76
+ /// `./out/contracts` = `write`
77
+ ///
78
+ /// And we check for `./out/contracts/MyContract.sol`, we will get both `read` and
79
+ /// `write` permissions.
80
+ pub fn find_all_permissions ( & self , path : & Path ) -> Vec < FsAccessPermission > {
81
+ let mut matching_permissions = Vec :: new ( ) ;
82
+ let mut max_path_len = 0 ;
83
+
84
+ // First pass: find all matching permissions and determine the maximum path length
85
+ for perm in & self . permissions {
86
+ let permission_path = dunce:: canonicalize ( & perm. path ) . unwrap_or ( perm. path . clone ( ) ) ;
87
+ if path. starts_with ( & permission_path) {
88
+ let path_len = permission_path. components ( ) . count ( ) ;
89
+ if path_len > max_path_len {
90
+ max_path_len = path_len;
91
+ matching_permissions. clear ( ) ;
92
+ matching_permissions. push ( perm. access ) ;
93
+ } else if path_len == max_path_len {
94
+ matching_permissions. push ( perm. access ) ;
95
+ }
96
+ }
97
+ }
98
+
99
+ matching_permissions
100
+ }
101
+
69
102
/// Updates all `allowed_paths` and joins ([`Path::join`]) the `root` with all entries
70
103
pub fn join_all ( & mut self , root : & Path ) {
71
104
self . permissions . iter_mut ( ) . for_each ( |perm| {
@@ -270,4 +303,19 @@ mod tests {
270
303
let permission = permissions. find_permission ( Path :: new ( "./out/MyContract.sol" ) ) . unwrap ( ) ;
271
304
assert_eq ! ( FsAccessPermission :: Write , permission) ;
272
305
}
306
+
307
+ #[ test]
308
+ fn find_all_permissions ( ) {
309
+ let permissions = FsPermissions :: new ( vec ! [
310
+ PathPermission :: read( "./out" ) ,
311
+ PathPermission :: read( "./out/contracts" ) ,
312
+ PathPermission :: write( "./out/contracts" ) ,
313
+ ] ) ;
314
+
315
+ let found_permissions =
316
+ permissions. find_all_permissions ( Path :: new ( "./out/contracts/MyContract.sol" ) ) ;
317
+ assert_eq ! ( found_permissions. len( ) , 2 ) ;
318
+ assert ! ( found_permissions. contains( & FsAccessPermission :: Write ) ) ;
319
+ assert ! ( found_permissions. contains( & FsAccessPermission :: Read ) ) ;
320
+ }
273
321
}
0 commit comments