diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index d060ad528973f..2b558efb8885e 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -4,6 +4,7 @@ use crate::cmp; use crate::collections::VecDeque; use crate::io::IoSlice; use crate::mem::MaybeUninit; +use crate::sys::io::{CopyState, kernel_copy}; #[cfg(test)] mod tests; @@ -63,19 +64,17 @@ where R: Read, W: Write, { - cfg_select! { - any(target_os = "linux", target_os = "android") => { - crate::sys::kernel_copy::copy_spec(reader, writer) - } - _ => { - generic_copy(reader, writer) + match kernel_copy(reader, writer)? { + CopyState::Ended(copied) => Ok(copied), + CopyState::Fallback(copied) => { + generic_copy(reader, writer).map(|additional| copied + additional) } } } /// The userspace read-write-loop implementation of `io::copy` that is used when /// OS-specific specializations for copy offloading are not available or not applicable. -pub(crate) fn generic_copy(reader: &mut R, writer: &mut W) -> Result +fn generic_copy(reader: &mut R, writer: &mut W) -> Result where R: Read, W: Write, @@ -269,7 +268,7 @@ impl BufferedWriterSpec for Vec { } } -pub fn stack_buffer_copy( +fn stack_buffer_copy( reader: &mut R, writer: &mut W, ) -> Result { diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 64f5a6b36d3db..5e2fa5fd55563 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -14,7 +14,7 @@ cfg_select! { pub use unix::chroot; pub(crate) use unix::debug_assert_fd_is_open; #[cfg(any(target_os = "linux", target_os = "android"))] - pub(crate) use unix::CachedFileMetadata; + pub(super) use unix::CachedFileMetadata; use crate::sys::common::small_c_string::run_path_with_cstr as with_native_path; } target_os = "windows" => { diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 33a1e7ff5e40e..c0070f2dc7b8b 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -2166,7 +2166,7 @@ mod cfm { } } #[cfg(any(target_os = "linux", target_os = "android"))] -pub(crate) use cfm::CachedFileMetadata; +pub(in crate::sys) use cfm::CachedFileMetadata; #[cfg(not(target_vendor = "apple"))] pub fn copy(from: &Path, to: &Path) -> io::Result { diff --git a/library/std/src/sys/pal/unix/kernel_copy.rs b/library/std/src/sys/io/kernel_copy/linux.rs similarity index 97% rename from library/std/src/sys/pal/unix/kernel_copy.rs rename to library/std/src/sys/io/kernel_copy/linux.rs index b984afa149d06..1c00d317f2a52 100644 --- a/library/std/src/sys/pal/unix/kernel_copy.rs +++ b/library/std/src/sys/io/kernel_copy/linux.rs @@ -48,9 +48,9 @@ use libc::sendfile as sendfile64; use libc::sendfile64; use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV}; +use super::CopyState; use crate::cmp::min; use crate::fs::{File, Metadata}; -use crate::io::copy::generic_copy; use crate::io::{ BufRead, BufReader, BufWriter, Error, PipeReader, PipeWriter, Read, Result, StderrLock, StdinLock, StdoutLock, Take, Write, @@ -70,10 +70,10 @@ use crate::sys::weak::syscall; #[cfg(test)] mod tests; -pub(crate) fn copy_spec( +pub fn kernel_copy( read: &mut R, write: &mut W, -) -> Result { +) -> Result { let copier = Copier { read, write }; SpecCopy::copy(copier) } @@ -176,17 +176,17 @@ struct Copier<'a, 'b, R: Read + ?Sized, W: Write + ?Sized> { } trait SpecCopy { - fn copy(self) -> Result; + fn copy(self) -> Result; } impl SpecCopy for Copier<'_, '_, R, W> { - default fn copy(self) -> Result { - generic_copy(self.read, self.write) + default fn copy(self) -> Result { + Ok(CopyState::Fallback(0)) } } impl SpecCopy for Copier<'_, '_, R, W> { - fn copy(self) -> Result { + fn copy(self) -> Result { let (reader, writer) = (self.read, self.write); let r_cfg = reader.properties(); let w_cfg = writer.properties(); @@ -214,7 +214,9 @@ impl SpecCopy for Copier<'_, '_, R, W> { result.update_take(reader); match result { - CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written), + CopyResult::Ended(bytes_copied) => { + return Ok(CopyState::Ended(bytes_copied + written)); + } CopyResult::Error(e, _) => return Err(e), CopyResult::Fallback(bytes) => written += bytes, } @@ -231,7 +233,9 @@ impl SpecCopy for Copier<'_, '_, R, W> { result.update_take(reader); match result { - CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written), + CopyResult::Ended(bytes_copied) => { + return Ok(CopyState::Ended(bytes_copied + written)); + } CopyResult::Error(e, _) => return Err(e), CopyResult::Fallback(bytes) => written += bytes, } @@ -244,7 +248,9 @@ impl SpecCopy for Copier<'_, '_, R, W> { result.update_take(reader); match result { - CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written), + CopyResult::Ended(bytes_copied) => { + return Ok(CopyState::Ended(bytes_copied + written)); + } CopyResult::Error(e, _) => return Err(e), CopyResult::Fallback(0) => { /* use the fallback below */ } CopyResult::Fallback(_) => { @@ -255,10 +261,7 @@ impl SpecCopy for Copier<'_, '_, R, W> { } // fallback if none of the more specialized syscalls wants to work with these file descriptors - match generic_copy(reader, writer) { - Ok(bytes) => Ok(bytes + written), - err => err, - } + Ok(CopyState::Fallback(written)) } } @@ -558,7 +561,7 @@ fn fd_to_meta(fd: &T) -> FdMeta { } } -pub(super) enum CopyResult { +enum CopyResult { Ended(u64), Error(Error, u64), Fallback(u64), @@ -587,7 +590,7 @@ const INVALID_FD: RawFd = -1; /// Callers must handle fallback to a generic copy loop. /// `Fallback` may indicate non-zero number of bytes already written /// if one of the files' cursor +`max_len` would exceed u64::MAX (`EOVERFLOW`). -pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> CopyResult { +fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> CopyResult { use crate::cmp; const NOT_PROBED: u8 = 0; diff --git a/library/std/src/sys/pal/unix/kernel_copy/tests.rs b/library/std/src/sys/io/kernel_copy/linux/tests.rs similarity index 100% rename from library/std/src/sys/pal/unix/kernel_copy/tests.rs rename to library/std/src/sys/io/kernel_copy/linux/tests.rs diff --git a/library/std/src/sys/io/kernel_copy/mod.rs b/library/std/src/sys/io/kernel_copy/mod.rs new file mode 100644 index 0000000000000..a89279412cf7f --- /dev/null +++ b/library/std/src/sys/io/kernel_copy/mod.rs @@ -0,0 +1,23 @@ +pub enum CopyState { + #[cfg_attr(not(any(target_os = "linux", target_os = "android")), expect(dead_code))] + Ended(u64), + Fallback(u64), +} + +cfg_select! { + any(target_os = "linux", target_os = "android") => { + mod linux; + pub use linux::kernel_copy; + } + _ => { + use crate::io::{Result, Read, Write}; + + pub fn kernel_copy(_reader: &mut R, _writer: &mut W) -> Result + where + R: Read, + W: Write, + { + Ok(CopyState::Fallback(0)) + } + } +} diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs index fe8ec1dbb7325..acd8acb7be85d 100644 --- a/library/std/src/sys/io/mod.rs +++ b/library/std/src/sys/io/mod.rs @@ -46,8 +46,11 @@ mod is_terminal { } } +mod kernel_copy; + pub use io_slice::{IoSlice, IoSliceMut}; pub use is_terminal::is_terminal; +pub use kernel_copy::{CopyState, kernel_copy}; // Bare metal platforms usually have very small amounts of RAM // (in the order of hundreds of KB) diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index dd1059fe04a2d..22cac09f3d0dc 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -9,8 +9,6 @@ pub mod weak; #[cfg(target_os = "fuchsia")] pub mod fuchsia; pub mod futex; -#[cfg(any(target_os = "linux", target_os = "android"))] -pub mod kernel_copy; #[cfg(target_os = "linux")] pub mod linux; pub mod os; diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index cefad7d9596a6..145b97dc14976 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -59,12 +59,9 @@ const EXCEPTION_PATHS: &[&str] = &[ "library/std/src/os", // Platform-specific public interfaces // Temporary `std` exceptions // FIXME: platform-specific code should be moved to `sys` - "library/std/src/io/copy.rs", "library/std/src/io/stdio.rs", "library/std/src/lib.rs", // for miniz_oxide leaking docs, which itself workaround "library/std/src/path.rs", - "library/std/src/sys_common", // Should only contain abstractions over platforms - "library/std/src/net/test.rs", // Utility helpers for tests "library/std/src/io/error.rs", // Repr unpacked needed for UEFI ];