Skip to content

Commit

Permalink
macOS: Use libc definitions for copyfile
Browse files Browse the repository at this point in the history
`COPYFILE_ALL` is not yet exposed in `libc`, but the rest of what we need is, so use those definitions instead of manually defining them.
  • Loading branch information
madsmtm committed Apr 5, 2024
1 parent 385fa9d commit 3fe5839
Showing 1 changed file with 10 additions and 39 deletions.
49 changes: 10 additions & 39 deletions library/std/src/sys/pal/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1817,47 +1817,17 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
use crate::sync::atomic::{AtomicBool, Ordering};

const COPYFILE_ACL: u32 = 1 << 0;
const COPYFILE_STAT: u32 = 1 << 1;
const COPYFILE_XATTR: u32 = 1 << 2;
const COPYFILE_DATA: u32 = 1 << 3;

const COPYFILE_SECURITY: u32 = COPYFILE_STAT | COPYFILE_ACL;
const COPYFILE_METADATA: u32 = COPYFILE_SECURITY | COPYFILE_XATTR;
const COPYFILE_ALL: u32 = COPYFILE_METADATA | COPYFILE_DATA;

const COPYFILE_STATE_COPIED: u32 = 8;

#[allow(non_camel_case_types)]
type copyfile_state_t = *mut libc::c_void;
#[allow(non_camel_case_types)]
type copyfile_flags_t = u32;

extern "C" {
fn fcopyfile(
from: libc::c_int,
to: libc::c_int,
state: copyfile_state_t,
flags: copyfile_flags_t,
) -> libc::c_int;
fn copyfile_state_alloc() -> copyfile_state_t;
fn copyfile_state_free(state: copyfile_state_t) -> libc::c_int;
fn copyfile_state_get(
state: copyfile_state_t,
flag: u32,
dst: *mut libc::c_void,
) -> libc::c_int;
}

struct FreeOnDrop(copyfile_state_t);
const COPYFILE_ALL: libc::copyfile_flags_t = libc::COPYFILE_METADATA | libc::COPYFILE_DATA;

struct FreeOnDrop(libc::copyfile_state_t);
impl Drop for FreeOnDrop {
fn drop(&mut self) {
// The code below ensures that `FreeOnDrop` is never a null pointer
unsafe {
// `copyfile_state_free` returns -1 if the `to` or `from` files
// cannot be closed. However, this is not considered this an
// error.
copyfile_state_free(self.0);
libc::copyfile_state_free(self.0);
}
}
}
Expand All @@ -1866,6 +1836,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
// We store the availability in a global to avoid unnecessary syscalls
static HAS_FCLONEFILEAT: AtomicBool = AtomicBool::new(true);
syscall! {
// Mirrors `libc::fclonefileat`
fn fclonefileat(
srcfd: libc::c_int,
dst_dirfd: libc::c_int,
Expand Down Expand Up @@ -1902,22 +1873,22 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
// We ensure that `FreeOnDrop` never contains a null pointer so it is
// always safe to call `copyfile_state_free`
let state = unsafe {
let state = copyfile_state_alloc();
let state = libc::copyfile_state_alloc();
if state.is_null() {
return Err(crate::io::Error::last_os_error());
}
FreeOnDrop(state)
};

let flags = if writer_metadata.is_file() { COPYFILE_ALL } else { COPYFILE_DATA };
let flags = if writer_metadata.is_file() { COPYFILE_ALL } else { libc::COPYFILE_DATA };

cvt(unsafe { fcopyfile(reader.as_raw_fd(), writer.as_raw_fd(), state.0, flags) })?;
cvt(unsafe { libc::fcopyfile(reader.as_raw_fd(), writer.as_raw_fd(), state.0, flags) })?;

let mut bytes_copied: libc::off_t = 0;
cvt(unsafe {
copyfile_state_get(
libc::copyfile_state_get(
state.0,
COPYFILE_STATE_COPIED,
libc::COPYFILE_STATE_COPIED as u32,
core::ptr::addr_of_mut!(bytes_copied) as *mut libc::c_void,
)
})?;
Expand Down

0 comments on commit 3fe5839

Please sign in to comment.