Ok(PathBuf::from(OsString::from_vec(buf)))
}
+#[cfg(not(target_os = "linux"))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
use fs::{File, set_permissions};
if !from.is_file() {
set_permissions(to, perm)?;
Ok(ret)
}
+
+#[cfg(target_os = "linux")]
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+ use fs::{File, set_permissions};
+
+ unsafe fn copy_file_range(
+ fd_in: libc::c_int,
+ off_in: *mut libc::loff_t,
+ fd_out: libc::c_int,
+ off_out: *mut libc::loff_t,
+ len: libc::size_t,
+ flags: libc::c_uint,
+ ) -> libc::c_long {
+ libc::syscall(
+ libc::SYS_copy_file_range,
+ fd_in,
+ off_in,
+ fd_out,
+ off_out,
+ len,
+ flags,
+ )
+ }
+
+ if !from.is_file() {
+ return Err(Error::new(ErrorKind::InvalidInput,
+ "the source path is not an existing regular file"))
+ }
+
+ let mut reader = File::open(from)?;
+ let mut writer = File::create(to)?;
+ let (perm, len) = {
+ let metadata = reader.metadata()?;
+ (metadata.permissions(), metadata.size())
+ };
+
+ let mut written = 0u64;
+ while written < len {
+ let copy_result = unsafe {
+ cvt(copy_file_range(reader.as_raw_fd(),
+ ptr::null_mut(),
+ writer.as_raw_fd(),
+ ptr::null_mut(),
+ len as usize,
+ 0)
+ )
+ };
+ match copy_result {
+ Ok(ret) => written += ret as u64,
+ Err(err) => {
+ match err.raw_os_error() {
+ Some(os_err) if os_err == libc::ENOSYS || os_err == libc::EXDEV => {
+ // Either kernel is too old or the files are not mounted on the same fs.
+ // Try again with fallback method
+ let ret = io::copy(&mut reader, &mut writer)?;
+ set_permissions(to, perm)?;
+ return Ok(ret)
+ },
+ _ => return Err(err),
+ }
+ }
+ }
+ }
+ set_permissions(to, perm)?;
+ Ok(written)
+}