Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS: Use libc definitions for copyfile #123485

Merged
merged 1 commit into from
Apr 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading