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)
177 CopyParams(FdMeta::Metadata(reader_meta), Some(readfd)),
178 CopyParams(_, Some(writefd)),
179 ) if reader_meta.is_file() => {
180 // try sendfile, most modern systems it should work with any target as long as the source is a mmapable file.
181 // in the rare cases where it's no supported the wrapper function will fall back to a normal copy loop
182 let bytes_flushed = flush()?;
183 let (mut reader, mut writer) =
184 unsafe { (fd_as_file(readfd), fd_as_file(writefd)) };
185 let len = reader_meta.len();
186 let max_write = reader.min_limit();
187 crate::sys::fs::sendfile_splice(
188 crate::sys::fs::SpliceMode::Sendfile,
193 .map(|bytes_sent| bytes_sent + bytes_flushed)
195 (CopyParams(reader_meta, Some(readfd)), CopyParams(writer_meta, Some(writefd)))
196 if reader_meta.is_fifo() || writer_meta.is_fifo() =>
199 let bytes_flushed = flush()?;
200 let max_write = reader.min_limit();
201 let (mut reader, mut writer) =
202 unsafe { (fd_as_file(readfd), fd_as_file(writefd)) };
203 crate::sys::fs::sendfile_splice(
204 crate::sys::fs::SpliceMode::Splice,
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<T> CopyRead for &mut T where T: CopyRead {
239 fn drain_to<W: Write>(&mut self, writer: &mut W, limit: u64) -> Result<u64> {
240 (**self).drain_to(writer, limit)
243 fn min_limit(&self) -> u64 {
247 fn properties(&self) -> CopyParams {
248 (**self).properties()
252 impl<T> CopyWrite for &mut T where T: CopyWrite {
253 fn properties(&self) -> CopyParams {
254 (**self).properties()
259 impl CopyRead for File {
260 fn properties(&self) -> CopyParams {
261 CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
265 impl CopyRead for &File {
266 fn properties(&self) -> CopyParams {
267 CopyParams(fd_to_meta(*self), Some(self.as_raw_fd()))
271 impl CopyWrite for File {
272 fn properties(&self) -> CopyParams {
273 CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
277 impl CopyWrite for &File {
278 fn properties(&self) -> CopyParams {
279 CopyParams(fd_to_meta(*self), Some(self.as_raw_fd()))
283 impl CopyRead 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 CopyRead for &TcpStream {
291 fn properties(&self) -> CopyParams {
292 // avoid the stat syscall since we can be fairly sure it's a socket
293 CopyParams(FdMeta::Socket, Some(self.as_raw_fd()))
297 impl CopyWrite for TcpStream {
298 fn properties(&self) -> CopyParams {
299 // avoid the stat syscall since we can be fairly sure it's a socket
300 CopyParams(FdMeta::Socket, Some(self.as_raw_fd()))
304 impl CopyWrite for &TcpStream {
305 fn properties(&self) -> CopyParams {
306 // avoid the stat syscall since we can be fairly sure it's a socket
307 CopyParams(FdMeta::Socket, Some(self.as_raw_fd()))
311 impl CopyWrite for ChildStdin {
312 fn properties(&self) -> CopyParams {
313 CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
317 impl CopyRead for ChildStdout {
318 fn properties(&self) -> CopyParams {
319 CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
323 impl CopyRead for ChildStderr {
324 fn properties(&self) -> CopyParams {
325 CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
329 impl CopyRead for StdinLock<'_> {
330 fn drain_to<W: Write>(&mut self, writer: &mut W, outer_limit: u64) -> Result<u64> {
331 let buf_reader = self.as_mut_buf();
332 let buf = buf_reader.buffer();
333 let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))];
334 let bytes_drained = buf.len();
335 writer.write_all(buf)?;
336 buf_reader.consume(bytes_drained);
338 Ok(bytes_drained as u64)
341 fn properties(&self) -> CopyParams {
342 CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
346 impl CopyWrite for StdoutLock<'_> {
347 fn properties(&self) -> CopyParams {
348 CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
352 impl CopyWrite for StderrLock<'_> {
353 fn properties(&self) -> CopyParams {
354 CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
358 impl<T: CopyRead> CopyRead for Take<T> {
359 fn drain_to<W: Write>(&mut self, writer: &mut W, outer_limit: u64) -> Result<u64> {
360 let local_limit = self.limit();
361 let combined_limit = min(outer_limit, local_limit);
362 let bytes_drained = self.get_mut().drain_to(writer, combined_limit)?;
363 // update limit since read() was bypassed
364 self.set_limit(local_limit - bytes_drained);
369 fn min_limit(&self) -> u64 {
370 min(Take::limit(self), self.get_ref().min_limit())
373 fn properties(&self) -> CopyParams {
374 self.get_ref().properties()
378 impl<T: CopyRead> CopyRead for BufReader<T> {
379 fn drain_to<W: Write>(&mut self, writer: &mut W, outer_limit: u64) -> Result<u64> {
380 let buf = self.buffer();
381 let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))];
382 let bytes = buf.len();
383 writer.write_all(buf)?;
386 let remaining = outer_limit - bytes as u64;
388 // in case of nested bufreaders we also need to drain the ones closer to the source
389 let inner_bytes = self.get_mut().drain_to(writer, remaining)?;
391 Ok(bytes as u64 + inner_bytes)
394 fn min_limit(&self) -> u64 {
395 self.get_ref().min_limit()
398 fn properties(&self) -> CopyParams {
399 self.get_ref().properties()
403 impl<T: CopyWrite> CopyWrite for BufWriter<T> {
404 fn properties(&self) -> CopyParams {
405 self.get_ref().properties()
409 fn fd_to_meta<T: AsRawFd>(fd: &T) -> FdMeta {
410 let fd = fd.as_raw_fd();
411 let file: ManuallyDrop<File> = ManuallyDrop::new(unsafe { File::from_raw_fd(fd) });
412 match file.metadata() {
413 Ok(meta) => FdMeta::Metadata(meta),
414 Err(_) => FdMeta::None,
418 unsafe fn fd_as_file(fd: RawFd) -> ManuallyDrop<File> {
419 ManuallyDrop::new(File::from_raw_fd(fd))