File tree Expand file tree Collapse file tree 3 files changed +45
-1
lines changed
Expand file tree Collapse file tree 3 files changed +45
-1
lines changed Original file line number Diff line number Diff line change @@ -1664,6 +1664,13 @@ pub(crate) fn copy_attributes(
16641664 let source_metadata =
16651665 fs:: symlink_metadata ( source) . map_err ( |e| CpError :: IoErrContext ( e, context. to_owned ( ) ) ) ?;
16661666
1667+ // if --no-preserve wasn't explicitely passed and we're copying a directory by default we should preserve mode
1668+ let mode = if dest. is_dir ( ) && attributes. mode == ( Preserve :: No { explicit : false } ) {
1669+ Preserve :: Yes { required : false }
1670+ } else {
1671+ attributes. mode
1672+ } ;
1673+
16671674 // Ownership must be changed first to avoid interfering with mode change.
16681675 #[ cfg( unix) ]
16691676 handle_preserve ( & attributes. ownership , || -> CopyResult < ( ) > {
@@ -1701,7 +1708,7 @@ pub(crate) fn copy_attributes(
17011708 Ok ( ( ) )
17021709 } ) ?;
17031710
1704- handle_preserve ( & attributes . mode , || -> CopyResult < ( ) > {
1711+ handle_preserve ( & mode, || -> CopyResult < ( ) > {
17051712 // The `chmod()` system call that underlies the
17061713 // `fs::set_permissions()` call is unable to change the
17071714 // permissions of a symbolic link. In that case, we just
Original file line number Diff line number Diff line change @@ -7400,3 +7400,34 @@ fn test_cp_recurse_verbose_output_with_symlink_already_exists() {
74007400 . no_stderr ( )
74017401 . stdout_is ( output) ;
74027402}
7403+
7404+ #[ test]
7405+ #[ cfg( not( target_os = "windows" ) ) ]
7406+ fn test_cp_preserve_directory_permissions_by_default ( ) {
7407+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
7408+ let at = & scene. fixtures ;
7409+
7410+ let dir = "a/b/c/d" ;
7411+ let file = "foo.txt" ;
7412+
7413+ at. mkdir_all ( dir) ;
7414+
7415+ let file_path = format ! ( "{dir}/{file}" ) ;
7416+
7417+ at. touch ( file_path) ;
7418+
7419+ scene. cmd ( "chmod" ) . arg ( "-R" ) . arg ( "555" ) . arg ( "a" ) . succeeds ( ) ;
7420+ scene. cmd ( "cp" ) . arg ( "-r" ) . arg ( "a" ) . arg ( "b" ) . succeeds ( ) ;
7421+
7422+ scene. ucmd ( ) . arg ( "-r" ) . arg ( "a" ) . arg ( "c" ) . succeeds ( ) ;
7423+
7424+ assert_eq ! ( at. get_mode( "b" ) , 0o40555 ) ;
7425+ assert_eq ! ( at. get_mode( "b/b" ) , 0o40555 ) ;
7426+ assert_eq ! ( at. get_mode( "b/b/c" ) , 0o40555 ) ;
7427+ assert_eq ! ( at. get_mode( "b/b/c/d" ) , 0o40555 ) ;
7428+
7429+ assert_eq ! ( at. get_mode( "c" ) , 0o40555 ) ;
7430+ assert_eq ! ( at. get_mode( "c/b" ) , 0o40555 ) ;
7431+ assert_eq ! ( at. get_mode( "c/b/c" ) , 0o40555 ) ;
7432+ assert_eq ! ( at. get_mode( "c/b/c/d" ) , 0o40555 ) ;
7433+ }
Original file line number Diff line number Diff line change @@ -1324,6 +1324,12 @@ impl AtPath {
13241324 perms. set_mode ( mode) ;
13251325 std:: fs:: set_permissions ( & path, perms) . unwrap ( ) ;
13261326 }
1327+
1328+ pub fn get_mode ( & self , filename : & str ) -> u32 {
1329+ let path = self . plus ( filename) ;
1330+ let perms = std:: fs:: metadata ( & path) . unwrap ( ) . permissions ( ) ;
1331+ perms. mode ( )
1332+ }
13271333}
13281334
13291335/// An environment for running a single uutils test case, serves three functions:
You can’t perform that action at this time.
0 commit comments