use std::io;
use std::path::Path;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn reflink(from: &Path, to: &Path) -> io::Result<()> {
use std::fs;
use std::os::unix::io::AsRawFd;
const IOCTL_FICLONE: u64 = 0x40049409;
let src = fs::File::open(&from)?;
let dest = fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(&to)?;
let ret = unsafe {
libc::ioctl(dest.as_raw_fd(), IOCTL_FICLONE, src.as_raw_fd())
};
if ret == -1 {
let err = io::Error::last_os_error();
let _ = fs::remove_file(to);
Err(err)
} else {
Ok(())
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn reflink(from: &Path, to: &Path) -> io::Result<()> {
use std::ffi::CString;
use std::os::unix::ffi::OsStrExt;
fn cstr(path: &Path) -> io::Result<CString> {
Ok(CString::new(path.as_os_str().as_bytes())?)
}
const CLONE_NOOWNERCOPY: libc::c_int = 0x0002;
extern "C" {
fn clonefile(
src: *const libc::c_char,
dest: *const libc::c_char,
flags: libc::c_int,
) -> libc::c_int;
}
let src = cstr(from.as_ref())?;
let dest = cstr(to.as_ref())?;
let ret = unsafe { clonefile(src.as_ptr(), dest.as_ptr(), CLONE_NOOWNERCOPY) };
if ret == -1 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
}
#[cfg(not(any(
target_os = "linux",
target_os = "android",
target_os = "macos",
target_os = "ios"
)))]
pub fn reflink(_from: &Path, _to: &Path) -> io::Result<()> {
super::_reflink_not_supported()
}