File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -667,7 +667,9 @@ fn build_dir(
667667 } ;
668668
669669 excluded_perms |= umask;
670- let mode = !excluded_perms & 0o777 ; //use only the last three octet bits
670+ // Always keep the owner write bit so we can copy files into the directory.
671+ // The correct final permissions are applied afterward by dirs_needing_permissions.
672+ let mode = ( !excluded_perms & 0o777 ) | 0o200 ; // mask to permission bits, always keep owner write
671673 std:: os:: unix:: fs:: DirBuilderExt :: mode ( & mut builder, mode) ;
672674 }
673675
Original file line number Diff line number Diff line change @@ -3795,6 +3795,27 @@ fn test_copy_dir_preserve_subdir_permissions() {
37953795 assert_metadata_eq ! ( at. metadata( "a1/a2" ) , at. metadata( "b1/a2" ) ) ;
37963796}
37973797
3798+ /// cp should successfully copy a read-only source directory containing files.
3799+ /// Regression test: build_dir previously created the destination with the source's
3800+ /// read-only mode, causing EPERM when copying files into it.
3801+ #[ cfg( all( not( windows) , not( target_os = "freebsd" ) , not( target_os = "openbsd" ) ) ) ]
3802+ #[ test]
3803+ fn test_copy_dir_preserve_readonly_source_with_files ( ) {
3804+ let ( at, mut ucmd) = at_and_ucmd ! ( ) ;
3805+ at. mkdir ( "src" ) ;
3806+ at. write ( "src/file.txt" , "hello" ) ;
3807+ at. set_mode ( "src" , 0o0555 ) ;
3808+
3809+ ucmd. args ( & [ "-p" , "-r" , "src" , "dest" ] )
3810+ . succeeds ( )
3811+ . no_stderr ( )
3812+ . no_stdout ( ) ;
3813+
3814+ assert ! ( at. dir_exists( "dest" ) ) ;
3815+ assert_eq ! ( at. read( "dest/file.txt" ) , "hello" ) ;
3816+ assert_metadata_eq ! ( at. metadata( "src" ) , at. metadata( "dest" ) ) ;
3817+ }
3818+
37983819/// Test for preserving permissions when copying a directory, even in
37993820/// the face of an inaccessible file in that directory.
38003821#[ cfg( all( not( windows) , not( target_os = "freebsd" ) , not( target_os = "openbsd" ) ) ) ]
You can’t perform that action at this time.
0 commit comments