@@ -761,6 +761,7 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
761
761
Ok ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
762
762
}
763
763
764
+ #[ cfg( not( target_os = "linux" ) ) ]
764
765
pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
765
766
use fs:: { File , set_permissions} ;
766
767
if !from. is_file ( ) {
@@ -776,3 +777,69 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
776
777
set_permissions ( to, perm) ?;
777
778
Ok ( ret)
778
779
}
780
+
781
+ #[ cfg( target_os = "linux" ) ]
782
+ pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
783
+ use fs:: { File , set_permissions} ;
784
+
785
+ unsafe fn copy_file_range (
786
+ fd_in : libc:: c_int ,
787
+ off_in : * mut libc:: loff_t ,
788
+ fd_out : libc:: c_int ,
789
+ off_out : * mut libc:: loff_t ,
790
+ len : libc:: size_t ,
791
+ flags : libc:: c_uint ,
792
+ ) -> libc:: c_long {
793
+ libc:: syscall (
794
+ libc:: SYS_copy_file_range ,
795
+ fd_in,
796
+ off_in,
797
+ fd_out,
798
+ off_out,
799
+ len,
800
+ flags,
801
+ )
802
+ }
803
+
804
+ if !from. is_file ( ) {
805
+ return Err ( Error :: new ( ErrorKind :: InvalidInput ,
806
+ "the source path is not an existing regular file" ) )
807
+ }
808
+
809
+ let mut reader = File :: open ( from) ?;
810
+ let mut writer = File :: create ( to) ?;
811
+ let ( perm, len) = {
812
+ let metadata = reader. metadata ( ) ?;
813
+ ( metadata. permissions ( ) , metadata. size ( ) )
814
+ } ;
815
+
816
+ let mut written = 0u64 ;
817
+ while written < len {
818
+ let copy_result = unsafe {
819
+ cvt ( copy_file_range ( reader. as_raw_fd ( ) ,
820
+ ptr:: null_mut ( ) ,
821
+ writer. as_raw_fd ( ) ,
822
+ ptr:: null_mut ( ) ,
823
+ len as usize ,
824
+ 0 )
825
+ )
826
+ } ;
827
+ match copy_result {
828
+ Ok ( ret) => written += ret as u64 ,
829
+ Err ( err) => {
830
+ match err. raw_os_error ( ) {
831
+ Some ( os_err) if os_err == libc:: ENOSYS || os_err == libc:: EXDEV => {
832
+ // Either kernel is too old or the files are not mounted on the same fs.
833
+ // Try again with fallback method
834
+ let ret = io:: copy ( & mut reader, & mut writer) ?;
835
+ set_permissions ( to, perm) ?;
836
+ return Ok ( ret)
837
+ } ,
838
+ _ => return Err ( err) ,
839
+ }
840
+ }
841
+ }
842
+ }
843
+ set_permissions ( to, perm) ?;
844
+ Ok ( written)
845
+ }
0 commit comments