1 use crate::io::{self, ErrorKind, Read, Write};
2 use crate::mem::MaybeUninit;
4 /// Copies the entire contents of a reader into a writer.
6 /// This function will continuously read data from `reader` and then
7 /// write it into `writer` in a streaming fashion until `reader`
10 /// On success, the total number of bytes that were copied from
11 /// `reader` to `writer` is returned.
13 /// If you’re wanting to copy the contents of one file to another and you’re
14 /// working with filesystem paths, see the [`fs::copy`] function.
16 /// [`fs::copy`]: crate::fs::copy
20 /// This function will return an error immediately if any call to [`read`] or
21 /// [`write`] returns an error. All instances of [`ErrorKind::Interrupted`] are
22 /// handled by this function and the underlying operation is retried.
24 /// [`read`]: Read::read
25 /// [`write`]: Write::write
32 /// fn main() -> io::Result<()> {
33 /// let mut reader: &[u8] = b"hello";
34 /// let mut writer: Vec<u8> = vec![];
36 /// io::copy(&mut reader, &mut writer)?;
38 /// assert_eq!(&b"hello"[..], &writer[..]);
42 #[stable(feature = "rust1", since = "1.0.0")]
43 pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
48 #[cfg(any(target_os = "linux", target_os = "android"))]
50 kernel_copy::copy_spec(reader, writer)
53 #[cfg(not(any(target_os = "linux", target_os = "android")))]
54 generic_copy(reader, writer)
57 pub(crate) fn generic_copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
62 let mut buf = MaybeUninit::<[u8; super::DEFAULT_BUF_SIZE]>::uninit();
65 // - This creates a (mut) reference to a slice of
66 // _uninitialized_ integers, which is **undefined behavior**
68 // - Only the standard library gets to soundly "ignore" this,
69 // based on its privileged knowledge of unstable rustc
72 reader.initializer().initialize(buf.assume_init_mut());
77 let len = match reader.read(unsafe { buf.assume_init_mut() }) {
78 Ok(0) => return Ok(written),
80 Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
81 Err(e) => return Err(e),
83 writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?;
84 written += len as u64;
88 #[cfg(any(target_os = "linux", target_os = "android"))]
92 use crate::convert::TryInto;
93 use crate::fs::{File, Metadata};
95 BufRead, BufReader, BufWriter, Read, Result, StderrLock, StdinLock, StdoutLock, Take, Write,
97 use crate::mem::ManuallyDrop;
98 use crate::net::TcpStream;
99 use crate::os::unix::fs::FileTypeExt;
100 use crate::os::unix::io::{AsRawFd, FromRawFd, RawFd};
101 use crate::process::{ChildStderr, ChildStdin, ChildStdout};
103 pub(super) fn copy_spec<R: Read + ?Sized, W: Write + ?Sized>(
107 let copier = Copier { read, write };
108 SpecCopy::copy(copier)
119 fn is_fifo(&self) -> bool {
121 FdMeta::Metadata(meta) => meta.file_type().is_fifo(),
122 FdMeta::Socket => false,
123 FdMeta::Pipe => true,
124 FdMeta::None => false,
129 struct CopyParams(FdMeta, Option<RawFd>);
131 struct Copier<'a, 'b, R: Read + ?Sized, W: Write + ?Sized> {
133 pub write: &'b mut W,
137 fn copy(self) -> Result<u64>;
140 impl<R: Read + ?Sized, W: Write + ?Sized> SpecCopy for Copier<'_, '_, R, W> {
141 default fn copy(self) -> Result<u64> {
142 super::generic_copy(self.read, self.write)
146 impl<R: CopyRead, W: CopyWrite> SpecCopy for Copier<'_, '_, R, W> {
147 fn copy(self) -> Result<u64> {
148 let (reader, writer) = (self.read, self.write);
149 let r_cfg = reader.properties();
150 let w_cfg = writer.properties();
152 // before direct operations on file descriptors ensure that all source and sink buffers are emtpy
153 let mut flush = || -> crate::io::Result<u64> {
154 let bytes = reader.drain_to(writer, u64::MAX)?;
159 match (r_cfg, w_cfg) {
161 CopyParams(FdMeta::Metadata(reader_meta), Some(readfd)),
162 CopyParams(FdMeta::Metadata(writer_meta), Some(writefd)),
163 ) if reader_meta.is_file() && writer_meta.is_file() => {
164 let bytes_flushed = flush()?;
165 let max_write = reader.min_limit();
166 let (mut reader, mut writer) =
167 unsafe { (fd_as_file(readfd), fd_as_file(writefd)) };
168 let len = reader_meta.len();
169 crate::sys::fs::copy_regular_files(
174 .map(|bytes_copied| bytes_copied + bytes_flushed)
176 (CopyParams(reader_meta, Some(readfd)), CopyParams(writer_meta, Some(writefd)))
177 if reader_meta.is_fifo() || writer_meta.is_fifo() =>
180 let bytes_flushed = flush()?;
181 let max_write = reader.min_limit();
182 let (mut reader, mut writer) =
183 unsafe { (fd_as_file(readfd), fd_as_file(writefd)) };
184 crate::sys::fs::sendfile_splice(
185 crate::sys::fs::SpliceMode::Splice,
190 .map(|bytes_sent| bytes_sent + bytes_flushed)
193 CopyParams(FdMeta::Metadata(reader_meta), Some(readfd)),
194 CopyParams(_, Some(writefd)),
195 ) if reader_meta.is_file() => {
196 // try sendfile, most modern systems it should work with any target as long as the source is a mmapable file.
197 // in the rare cases where it's no supported the wrapper function will fall back to a normal copy loop
198 let bytes_flushed = flush()?;
199 let (mut reader, mut writer) =
200 unsafe { (fd_as_file(readfd), fd_as_file(writefd)) };
201 let len = reader_meta.len();
202 let max_write = reader.min_limit();
203 crate::sys::fs::sendfile_splice(
204 crate::sys::fs::SpliceMode::Sendfile,
209 .map(|bytes_sent| bytes_sent + bytes_flushed)
211 _ => super::generic_copy(reader, writer),
216 #[rustc_specialization_trait]
217 trait CopyRead: Read {
218 fn drain_to<W: Write>(&mut self, _writer: &mut W, _limit: u64) -> Result<u64> {
222 /// The minimum of the limit of all `Take<_>` wrappers, `u64::MAX` otherwise.
223 /// This method does not account for data `BufReader` buffers and would underreport
224 /// the limit of a `Take<BufReader<Take<_>>>` type. Thus its result is only valid
225 /// after draining the buffers.
226 fn min_limit(&self) -> u64 {
230 fn properties(&self) -> CopyParams;
233 #[rustc_specialization_trait]
234 trait CopyWrite: Write {
235 fn properties(&self) -> CopyParams;
238 impl CopyRead for File {
239 fn properties(&self) -> CopyParams {
240 CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
244 impl CopyRead for &File {
245 fn properties(&self) -> CopyParams {
246 CopyParams(fd_to_meta(*self), Some(self.as_raw_fd()))
250 impl CopyWrite for File {
251 fn properties(&self) -> CopyParams {
252 CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
256 impl CopyWrite for &File {
257 fn properties(&self) -> CopyParams {
258 CopyParams(fd_to_meta(*self), Some(self.as_raw_fd()))
262 impl CopyRead for TcpStream {
263 fn properties(&self) -> CopyParams {
264 // avoid the stat syscall since we can be fairly sure it's a socket
265 CopyParams(FdMeta::Socket, Some(self.as_raw_fd()))
269 impl CopyRead for &TcpStream {
270 fn properties(&self) -> CopyParams {
271 // avoid the stat syscall since we can be fairly sure it's a socket
272 CopyParams(FdMeta::Socket, Some(self.as_raw_fd()))
276 impl CopyWrite for TcpStream {
277 fn properties(&self) -> CopyParams {
278 // avoid the stat syscall since we can be fairly sure it's a socket
279 CopyParams(FdMeta::Socket, Some(self.as_raw_fd()))
283 impl CopyWrite for &TcpStream {
284 fn properties(&self) -> CopyParams {
285 // avoid the stat syscall since we can be fairly sure it's a socket
286 CopyParams(FdMeta::Socket, Some(self.as_raw_fd()))
290 impl CopyWrite for ChildStdin {
291 fn properties(&self) -> CopyParams {
292 CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
296 impl CopyRead for ChildStdout {
297 fn properties(&self) -> CopyParams {
298 CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
302 impl CopyRead for ChildStderr {
303 fn properties(&self) -> CopyParams {
304 CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
308 impl CopyRead for StdinLock<'_> {
309 fn drain_to<W: Write>(&mut self, writer: &mut W, outer_limit: u64) -> Result<u64> {
310 let buf_reader = self.as_mut_buf();
311 let buf = buf_reader.buffer();
312 let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))];
313 let bytes_drained = buf.len();
314 writer.write_all(buf)?;
315 buf_reader.consume(bytes_drained);
317 Ok(bytes_drained as u64)
320 fn properties(&self) -> CopyParams {
321 CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
325 impl CopyWrite for StdoutLock<'_> {
326 fn properties(&self) -> CopyParams {
327 CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
331 impl CopyWrite for StderrLock<'_> {
332 fn properties(&self) -> CopyParams {
333 CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
337 impl<T: CopyRead> CopyRead for Take<T> {
338 fn drain_to<W: Write>(&mut self, writer: &mut W, outer_limit: u64) -> Result<u64> {
339 let local_limit = self.limit();
340 let combined_limit = min(outer_limit, local_limit);
341 let bytes_drained = self.get_mut().drain_to(writer, combined_limit)?;
342 // update limit since read() was bypassed
343 self.set_limit(local_limit - bytes_drained);
348 fn min_limit(&self) -> u64 {
349 min(Take::limit(self), self.get_ref().min_limit())
352 fn properties(&self) -> CopyParams {
353 self.get_ref().properties()
357 impl<T: CopyRead> CopyRead for BufReader<T> {
358 fn drain_to<W: Write>(&mut self, writer: &mut W, outer_limit: u64) -> Result<u64> {
359 let buf = self.buffer();
360 let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))];
361 let bytes = buf.len();
362 writer.write_all(buf)?;
365 let remaining = outer_limit - bytes as u64;
367 // in case of nested bufreaders we also need to drain the ones closer to the source
368 let inner_bytes = self.get_mut().drain_to(writer, remaining)?;
370 Ok(bytes as u64 + inner_bytes)
373 fn min_limit(&self) -> u64 {
374 self.get_ref().min_limit()
377 fn properties(&self) -> CopyParams {
378 self.get_ref().properties()
382 impl<T: CopyWrite> CopyWrite for BufWriter<T> {
383 fn properties(&self) -> CopyParams {
384 self.get_ref().properties()
388 fn fd_to_meta<T: AsRawFd>(fd: &T) -> FdMeta {
389 let fd = fd.as_raw_fd();
390 let file: ManuallyDrop<File> = ManuallyDrop::new(unsafe { File::from_raw_fd(fd) });
391 match file.metadata() {
392 Ok(meta) => FdMeta::Metadata(meta),
393 Err(_) => FdMeta::None,
397 unsafe fn fd_as_file(fd: RawFd) -> ManuallyDrop<File> {
398 ManuallyDrop::new(File::from_raw_fd(fd))