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