From 0f19012b1ce57301e6ede3de7bfb4f45d8125706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rni=20Dagur?= Date: Tue, 11 Jun 2019 22:44:11 +0000 Subject: Implement `copy_file_range()` --- src/fcntl.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 8 deletions(-) (limited to 'src/fcntl.rs') diff --git a/src/fcntl.rs b/src/fcntl.rs index 6da62d87..3d932a53 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -7,6 +7,8 @@ use std::os::unix::io::RawFd; use std::ffi::OsStr; use std::os::unix::ffi::OsStrExt; +#[cfg(any(target_os = "android", target_os = "linux"))] +use std::ptr; // For splice and copy_file_range #[cfg(any(target_os = "android", target_os = "linux"))] use sys::uio::IoVec; // For vmsplice @@ -325,15 +327,70 @@ libc_bitflags! { } } +/// Copy a range of data from one file to another +/// +/// The `copy_file_range` system call performs an in-kernel copy between +/// file descriptors `fd_in` and `fd_out` without the additional cost of +/// transferring data from the kernel to user space and then back into the +/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to +/// file descriptor `fd_out`, overwriting any data that exists within the +/// requested range of the target file. +/// +/// If the `off_in` and/or `off_out` arguments are used, the values +/// will be mutated to reflect the new position within the file after +/// copying. If they are not used, the relevant filedescriptors will be seeked +/// to the new position. +/// +/// On successful completion the number of bytes actually copied will be +/// returned. +#[cfg(any(target_os = "android", target_os = "linux"))] +pub fn copy_file_range( + fd_in: RawFd, + off_in: Option<&mut libc::loff_t>, + fd_out: RawFd, + off_out: Option<&mut libc::loff_t>, + len: usize, +) -> Result { + let off_in = off_in + .map(|offset| offset as *mut libc::loff_t) + .unwrap_or(ptr::null_mut()); + let off_out = off_out + .map(|offset| offset as *mut libc::loff_t) + .unwrap_or(ptr::null_mut()); + + let ret = unsafe { + libc::syscall( + libc::SYS_copy_file_range, + fd_in, + off_in, + fd_out, + off_out, + len, + 0, + ) + }; + Errno::result(ret).map(|r| r as usize) +} + #[cfg(any(target_os = "linux", target_os = "android"))] -pub fn splice(fd_in: RawFd, off_in: Option<&mut libc::loff_t>, - fd_out: RawFd, off_out: Option<&mut libc::loff_t>, - len: usize, flags: SpliceFFlags) -> Result { - use std::ptr; - let off_in = off_in.map(|offset| offset as *mut _).unwrap_or(ptr::null_mut()); - let off_out = off_out.map(|offset| offset as *mut _).unwrap_or(ptr::null_mut()); - - let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) }; +pub fn splice( + fd_in: RawFd, + off_in: Option<&mut libc::loff_t>, + fd_out: RawFd, + off_out: Option<&mut libc::loff_t>, + len: usize, + flags: SpliceFFlags, +) -> Result { + let off_in = off_in + .map(|offset| offset as *mut libc::loff_t) + .unwrap_or(ptr::null_mut()); + let off_out = off_out + .map(|offset| offset as *mut libc::loff_t) + .unwrap_or(ptr::null_mut()); + + let ret = unsafe { + libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) + }; Errno::result(ret).map(|r| r as usize) } -- cgit v1.2.3