@@ -827,13 +827,14 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
827
827
Ok ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
828
828
}
829
829
830
- #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
831
- pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
830
+ fn open_and_set_permissions (
831
+ from : & Path ,
832
+ to : & Path ,
833
+ ) -> io:: Result < ( crate :: fs:: File , crate :: fs:: File , u64 ) > {
832
834
use crate :: fs:: { File , OpenOptions } ;
833
835
use crate :: os:: unix:: fs:: { OpenOptionsExt , PermissionsExt } ;
834
836
835
- let mut reader = File :: open ( from) ?;
836
-
837
+ let reader = File :: open ( from) ?;
837
838
let ( perm, len) = {
838
839
let metadata = reader. metadata ( ) ?;
839
840
if !metadata. is_file ( ) {
@@ -844,30 +845,33 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
844
845
}
845
846
( metadata. permissions ( ) , metadata. len ( ) )
846
847
} ;
847
-
848
- let mut writer = OpenOptions :: new ( )
848
+ let writer = OpenOptions :: new ( )
849
849
// create the file with the correct mode right away
850
850
. mode ( perm. mode ( ) )
851
851
. write ( true )
852
852
. create ( true )
853
853
. truncate ( true )
854
854
. open ( to) ?;
855
-
856
855
let writer_metadata = writer. metadata ( ) ?;
857
856
if writer_metadata. is_file ( ) {
858
857
// Set the correct file permissions, in case the file already existed.
859
858
// Don't set the permissions on already existing non-files like
860
859
// pipes/FIFOs or device nodes.
861
860
writer. set_permissions ( perm) ?;
862
861
}
862
+ Ok ( ( reader, writer, len) )
863
+ }
864
+
865
+ #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
866
+ pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
867
+ let ( mut reader, mut writer, _) = open_and_set_permissions ( from, to) ?;
863
868
864
869
io:: copy ( & mut reader, & mut writer)
865
870
}
866
871
867
872
#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
868
873
pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
869
874
use crate :: cmp;
870
- use crate :: fs:: File ;
871
875
use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
872
876
873
877
// Kernel prior to 4.5 don't have copy_file_range
@@ -893,17 +897,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
893
897
)
894
898
}
895
899
896
- if !from. is_file ( ) {
897
- return Err ( Error :: new ( ErrorKind :: InvalidInput ,
898
- "the source path is not an existing regular file" ) )
899
- }
900
-
901
- let mut reader = File :: open ( from) ?;
902
- let mut writer = File :: create ( to) ?;
903
- let ( perm, len) = {
904
- let metadata = reader. metadata ( ) ?;
905
- ( metadata. permissions ( ) , metadata. size ( ) )
906
- } ;
900
+ let ( mut reader, mut writer, len) = open_and_set_permissions ( from, to) ?;
907
901
908
902
let has_copy_file_range = HAS_COPY_FILE_RANGE . load ( Ordering :: Relaxed ) ;
909
903
let mut written = 0u64 ;
@@ -913,13 +907,14 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
913
907
let copy_result = unsafe {
914
908
// We actually don't have to adjust the offsets,
915
909
// because copy_file_range adjusts the file offset automatically
916
- cvt ( copy_file_range ( reader. as_raw_fd ( ) ,
917
- ptr:: null_mut ( ) ,
918
- writer. as_raw_fd ( ) ,
919
- ptr:: null_mut ( ) ,
920
- bytes_to_copy,
921
- 0 )
922
- )
910
+ cvt ( copy_file_range (
911
+ reader. as_raw_fd ( ) ,
912
+ ptr:: null_mut ( ) ,
913
+ writer. as_raw_fd ( ) ,
914
+ ptr:: null_mut ( ) ,
915
+ bytes_to_copy,
916
+ 0 ,
917
+ ) )
923
918
} ;
924
919
if let Err ( ref copy_err) = copy_result {
925
920
match copy_err. raw_os_error ( ) {
@@ -937,23 +932,24 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
937
932
Ok ( ret) => written += ret as u64 ,
938
933
Err ( err) => {
939
934
match err. raw_os_error ( ) {
940
- Some ( os_err) if os_err == libc:: ENOSYS
941
- || os_err == libc:: EXDEV
942
- || os_err == libc:: EPERM => {
943
- // Try fallback io::copy if either:
944
- // - Kernel version is < 4.5 (ENOSYS)
945
- // - Files are mounted on different fs (EXDEV)
946
- // - copy_file_range is disallowed, for example by seccomp (EPERM)
947
- assert_eq ! ( written, 0 ) ;
948
- let ret = io:: copy ( & mut reader, & mut writer) ?;
949
- writer. set_permissions ( perm) ?;
950
- return Ok ( ret)
951
- } ,
935
+ Some ( os_err)
936
+ if os_err == libc:: ENOSYS
937
+ || os_err == libc:: EXDEV
938
+ || os_err == libc:: EINVAL
939
+ || os_err == libc:: EPERM =>
940
+ {
941
+ // Try fallback io::copy if either:
942
+ // - Kernel version is < 4.5 (ENOSYS)
943
+ // - Files are mounted on different fs (EXDEV)
944
+ // - copy_file_range is disallowed, for example by seccomp (EPERM)
945
+ // - copy_file_range cannot be used with pipes or device nodes (EINVAL)
946
+ assert_eq ! ( written, 0 ) ;
947
+ return io:: copy ( & mut reader, & mut writer) ;
948
+ }
952
949
_ => return Err ( err) ,
953
950
}
954
951
}
955
952
}
956
953
}
957
- writer. set_permissions ( perm) ?;
958
954
Ok ( written)
959
955
}
0 commit comments