@@ -827,7 +827,10 @@ 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" ) ) ) ]
830
+ #[ cfg( not( any( target_os = "linux" ,
831
+ target_os = "android" ,
832
+ target_os = "macos" ,
833
+ target_os = "ios" ) ) ) ]
831
834
pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
832
835
use crate :: fs:: File ;
833
836
if !from. is_file ( ) {
@@ -954,3 +957,85 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
954
957
}
955
958
Ok ( written)
956
959
}
960
+
961
+ #[ cfg( any( target_os = "macos" , target_os = "ios" ) ) ]
962
+ pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
963
+ const COPYFILE_ACL : u32 = 1 << 0 ;
964
+ const COPYFILE_STAT : u32 = 1 << 1 ;
965
+ const COPYFILE_XATTR : u32 = 1 << 2 ;
966
+ const COPYFILE_DATA : u32 = 1 << 3 ;
967
+
968
+ const COPYFILE_SECURITY : u32 = COPYFILE_STAT | COPYFILE_ACL ;
969
+ const COPYFILE_METADATA : u32 = COPYFILE_SECURITY | COPYFILE_XATTR ;
970
+ const COPYFILE_ALL : u32 = COPYFILE_METADATA | COPYFILE_DATA ;
971
+
972
+ const COPYFILE_STATE_COPIED : u32 = 8 ;
973
+
974
+ #[ allow( non_camel_case_types) ]
975
+ type copyfile_state_t = * mut libc:: c_void ;
976
+ #[ allow( non_camel_case_types) ]
977
+ type copyfile_flags_t = u32 ;
978
+
979
+ extern "C" {
980
+ fn copyfile (
981
+ from : * const libc:: c_char ,
982
+ to : * const libc:: c_char ,
983
+ state : copyfile_state_t ,
984
+ flags : copyfile_flags_t ,
985
+ ) -> libc:: c_int ;
986
+ fn copyfile_state_alloc ( ) -> copyfile_state_t ;
987
+ fn copyfile_state_free ( state : copyfile_state_t ) -> libc:: c_int ;
988
+ fn copyfile_state_get (
989
+ state : copyfile_state_t ,
990
+ flag : u32 ,
991
+ dst : * mut libc:: c_void ,
992
+ ) -> libc:: c_int ;
993
+ }
994
+
995
+ struct FreeOnDrop ( copyfile_state_t ) ;
996
+ impl Drop for FreeOnDrop {
997
+ fn drop ( & mut self ) {
998
+ // The code below ensures that `FreeOnDrop` is never a null pointer
999
+ unsafe {
1000
+ // `copyfile_state_free` returns -1 if the `to` or `from` files
1001
+ // cannot be closed. However, this is not considerd this an
1002
+ // error.
1003
+ copyfile_state_free ( self . 0 ) ;
1004
+ }
1005
+ }
1006
+ }
1007
+
1008
+ if !from. is_file ( ) {
1009
+ return Err ( Error :: new ( ErrorKind :: InvalidInput ,
1010
+ "the source path is not an existing regular file" ) )
1011
+ }
1012
+
1013
+ // We ensure that `FreeOnDrop` never contains a null pointer so it is
1014
+ // always safe to call `copyfile_state_free`
1015
+ let state = unsafe {
1016
+ let state = copyfile_state_alloc ( ) ;
1017
+ if state. is_null ( ) {
1018
+ return Err ( crate :: io:: Error :: last_os_error ( ) ) ;
1019
+ }
1020
+ FreeOnDrop ( state)
1021
+ } ;
1022
+
1023
+ cvt ( unsafe {
1024
+ copyfile (
1025
+ cstr ( from) ?. as_ptr ( ) ,
1026
+ cstr ( to) ?. as_ptr ( ) ,
1027
+ state. 0 ,
1028
+ COPYFILE_ALL ,
1029
+ )
1030
+ } ) ?;
1031
+
1032
+ let mut bytes_copied: libc:: off_t = 0 ;
1033
+ cvt ( unsafe {
1034
+ copyfile_state_get (
1035
+ state. 0 ,
1036
+ COPYFILE_STATE_COPIED ,
1037
+ & mut bytes_copied as * mut libc:: off_t as * mut libc:: c_void ,
1038
+ )
1039
+ } ) ?;
1040
+ Ok ( bytes_copied as u64 )
1041
+ }
0 commit comments