@@ -226,6 +226,24 @@ pub trait CapStdExtDirExt {
226
226
/// to determine, and `None` will be returned in those cases.
227
227
fn is_mountpoint ( & self , path : impl AsRef < Path > ) -> Result < Option < bool > > ;
228
228
229
+ #[ cfg( not( windows) ) ]
230
+ /// Get the value of an extended attribute. If the attribute is not present,
231
+ /// this function will return `Ok(None)`.
232
+ fn getxattr ( & self , path : impl AsRef < Path > , key : impl AsRef < OsStr > ) -> Result < Option < Vec < u8 > > > ;
233
+
234
+ #[ cfg( not( windows) ) ]
235
+ /// List all extended attribute keys for this path.
236
+ fn listxattrs ( & self , path : impl AsRef < Path > ) -> Result < crate :: XattrList > ;
237
+
238
+ #[ cfg( not( windows) ) ]
239
+ /// Set the value of an extended attribute.
240
+ fn setxattr (
241
+ & self ,
242
+ path : impl AsRef < Path > ,
243
+ key : impl AsRef < OsStr > ,
244
+ value : impl AsRef < [ u8 ] > ,
245
+ ) -> Result < ( ) > ;
246
+
229
247
/// Recursively walk a directory. If the function returns [`std::ops::ControlFlow::Break`]
230
248
/// while inspecting a directory, traversal of that directory is skipped. If
231
249
/// [`std::ops::ControlFlow::Break`] is returned when inspecting a non-directory,
@@ -562,6 +580,20 @@ where
562
580
Ok ( ( ) )
563
581
}
564
582
583
+ // Ensure that the target path isn't absolute, and doesn't
584
+ // have any parent references.
585
+ pub ( crate ) fn validate_relpath_no_uplinks ( path : & Path ) -> Result < & Path > {
586
+ let is_absolute = path. is_absolute ( ) ;
587
+ let contains_uplinks = path
588
+ . components ( )
589
+ . any ( |e| e == std:: path:: Component :: ParentDir ) ;
590
+ if is_absolute || contains_uplinks {
591
+ Err ( crate :: escape_attempt ( ) )
592
+ } else {
593
+ Ok ( path)
594
+ }
595
+ }
596
+
565
597
impl CapStdExtDirExt for Dir {
566
598
fn open_optional ( & self , path : impl AsRef < Path > ) -> Result < Option < File > > {
567
599
map_optional ( self . open ( path. as_ref ( ) ) )
@@ -738,6 +770,26 @@ impl CapStdExtDirExt for Dir {
738
770
is_mountpoint_impl_statx ( self , path. as_ref ( ) ) . map_err ( Into :: into)
739
771
}
740
772
773
+ #[ cfg( not( windows) ) ]
774
+ fn getxattr ( & self , path : impl AsRef < Path > , key : impl AsRef < OsStr > ) -> Result < Option < Vec < u8 > > > {
775
+ crate :: xattrs:: impl_getxattr ( self , path. as_ref ( ) , key. as_ref ( ) )
776
+ }
777
+
778
+ #[ cfg( not( windows) ) ]
779
+ fn listxattrs ( & self , path : impl AsRef < Path > ) -> Result < crate :: XattrList > {
780
+ crate :: xattrs:: impl_listxattrs ( self , path. as_ref ( ) )
781
+ }
782
+
783
+ #[ cfg( not( windows) ) ]
784
+ fn setxattr (
785
+ & self ,
786
+ path : impl AsRef < Path > ,
787
+ key : impl AsRef < OsStr > ,
788
+ value : impl AsRef < [ u8 ] > ,
789
+ ) -> Result < ( ) > {
790
+ crate :: xattrs:: impl_setxattr ( self , path. as_ref ( ) , key. as_ref ( ) , value. as_ref ( ) )
791
+ }
792
+
741
793
fn walk < C , E > ( & self , config : & WalkConfiguration , mut callback : C ) -> std:: result:: Result < ( ) , E >
742
794
where
743
795
C : FnMut ( & WalkComponent ) -> WalkResult < E > ,
@@ -851,3 +903,23 @@ impl CapStdExtDirExtUtf8 for cap_std::fs_utf8::Dir {
851
903
Ok ( r)
852
904
}
853
905
}
906
+
907
+ #[ cfg( test) ]
908
+ mod tests {
909
+ use std:: path:: Path ;
910
+
911
+ use super :: * ;
912
+
913
+ #[ test]
914
+ fn test_validate_relpath_no_uplinks ( ) {
915
+ let ok_cases = [ "foo" , "foo/bar" , "foo/bar/" ] ;
916
+ let err_cases = [ "/foo" , "/" , "../foo" , "foo/../bar" ] ;
917
+
918
+ for case in ok_cases {
919
+ assert ! ( validate_relpath_no_uplinks( Path :: new( case) ) . is_ok( ) ) ;
920
+ }
921
+ for case in err_cases {
922
+ assert ! ( validate_relpath_no_uplinks( Path :: new( case) ) . is_err( ) ) ;
923
+ }
924
+ }
925
+ }
0 commit comments