@@ -827,7 +827,10 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
827827 Ok ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
828828}
829829
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" ) ) ) ]
831834pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
832835 use crate :: fs:: File ;
833836 if !from. is_file ( ) {
@@ -937,3 +940,85 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
937940 writer. set_permissions ( perm) ?;
938941 Ok ( written)
939942}
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