File tree Expand file tree Collapse file tree 2 files changed +25
-2
lines changed
Expand file tree Collapse file tree 2 files changed +25
-2
lines changed Original file line number Diff line number Diff line change @@ -63,8 +63,15 @@ pub(crate) fn copy_on_write(
6363 {
6464 // clonefile(2) fails if the destination exists. Remove it and try again. Do not
6565 // bother to check if removal worked because we're going to try to clone again.
66- let _ = fs:: remove_file ( dest) ;
67- error = pfn ( src. as_ptr ( ) , dst. as_ptr ( ) , 0 ) ;
66+ // first lets make sure the dest file is not read only
67+ if fs:: metadata ( dest) . map_or ( false , |md| !md. permissions ( ) . readonly ( ) ) {
68+ // remove and copy again
69+ // TODO: rewrite this to better match linux behavior
70+ // linux first opens the source file and destination file then uses the file
71+ // descriptors to do the clone.
72+ let _ = fs:: remove_file ( dest) ;
73+ error = pfn ( src. as_ptr ( ) , dst. as_ptr ( ) , 0 ) ;
74+ }
6875 }
6976 }
7077 }
Original file line number Diff line number Diff line change @@ -3440,3 +3440,19 @@ fn test_cp_only_source_no_target() {
34403440 panic ! ( "Failure: stderr was \n {stderr_str}" ) ;
34413441 }
34423442}
3443+
3444+ #[ test]
3445+ fn test_cp_dest_no_permissions ( ) {
3446+ let ts = TestScenario :: new ( util_name ! ( ) ) ;
3447+ let at = & ts. fixtures ;
3448+
3449+ at. touch ( "valid.txt" ) ;
3450+ at. touch ( "invalid_perms.txt" ) ;
3451+ at. set_readonly ( "invalid_perms.txt" ) ;
3452+
3453+ ts. ucmd ( )
3454+ . args ( & [ "valid.txt" , "invalid_perms.txt" ] )
3455+ . fails ( )
3456+ . stderr_contains ( "invalid_perms.txt" )
3457+ . stderr_contains ( "denied" ) ;
3458+ }
You can’t perform that action at this time.
0 commit comments