]> git.lizzy.rs Git - rust.git/blob - library/std/src/io/copy.rs
add forwarding specializations for &mut variants
[rust.git] / library / std / src / io / copy.rs
1 use crate::io::{self, ErrorKind, Read, Write};
2 use crate::mem::MaybeUninit;
3
4 /// Copies the entire contents of a reader into a writer.
5 ///
6 /// This function will continuously read data from `reader` and then
7 /// write it into `writer` in a streaming fashion until `reader`
8 /// returns EOF.
9 ///
10 /// On success, the total number of bytes that were copied from
11 /// `reader` to `writer` is returned.
12 ///
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.
15 ///
16 /// [`fs::copy`]: crate::fs::copy
17 ///
18 /// # Errors
19 ///
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.
23 ///
24 /// [`read`]: Read::read
25 /// [`write`]: Write::write
26 ///
27 /// # Examples
28 ///
29 /// ```
30 /// use std::io;
31 ///
32 /// fn main() -> io::Result<()> {
33 ///     let mut reader: &[u8] = b"hello";
34 ///     let mut writer: Vec<u8> = vec![];
35 ///
36 ///     io::copy(&mut reader, &mut writer)?;
37 ///
38 ///     assert_eq!(&b"hello"[..], &writer[..]);
39 ///     Ok(())
40 /// }
41 /// ```
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>
44 where
45     R: Read,
46     W: Write,
47 {
48     #[cfg(any(target_os = "linux", target_os = "android"))]
49     {
50         kernel_copy::copy_spec(reader, writer)
51     }
52
53     #[cfg(not(any(target_os = "linux", target_os = "android")))]
54     generic_copy(reader, writer)
55 }
56
57 pub(crate) fn generic_copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
58 where
59     R: Read,
60     W: Write,
61 {
62     let mut buf = MaybeUninit::<[u8; super::DEFAULT_BUF_SIZE]>::uninit();
63     // FIXME: #42788
64     //
65     //   - This creates a (mut) reference to a slice of
66     //     _uninitialized_ integers, which is **undefined behavior**
67     //
68     //   - Only the standard library gets to soundly "ignore" this,
69     //     based on its privileged knowledge of unstable rustc
70     //     internals;
71     unsafe {
72         reader.initializer().initialize(buf.assume_init_mut());
73     }
74
75     let mut written = 0;
76     loop {
77         let len = match reader.read(unsafe { buf.assume_init_mut() }) {
78             Ok(0) => return Ok(written),
79             Ok(len) => len,
80             Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
81             Err(e) => return Err(e),
82         };
83         writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?;
84         written += len as u64;
85     }
86 }
87
88 #[cfg(any(target_os = "linux", target_os = "android"))]
89 mod kernel_copy {
90
91     use crate::cmp::min;
92     use crate::convert::TryInto;
93     use crate::fs::{File, Metadata};
94     use crate::io::{
95         BufRead, BufReader, BufWriter, Read, Result, StderrLock, StdinLock, StdoutLock, Take, Write,
96     };
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};
102
103     pub(super) fn copy_spec<R: Read + ?Sized, W: Write + ?Sized>(
104         read: &mut R,
105         write: &mut W,
106     ) -> Result<u64> {
107         let copier = Copier { read, write };
108         SpecCopy::copy(copier)
109     }
110
111     enum FdMeta {
112         Metadata(Metadata),
113         Socket,
114         Pipe,
115         None,
116     }
117
118     impl FdMeta {
119         fn is_fifo(&self) -> bool {
120             match self {
121                 FdMeta::Metadata(meta) => meta.file_type().is_fifo(),
122                 FdMeta::Socket => false,
123                 FdMeta::Pipe => true,
124                 FdMeta::None => false,
125             }
126         }
127     }
128
129     struct CopyParams(FdMeta, Option<RawFd>);
130
131     struct Copier<'a, 'b, R: Read + ?Sized, W: Write + ?Sized> {
132         pub read: &'a mut R,
133         pub write: &'b mut W,
134     }
135
136     trait SpecCopy {
137         fn copy(self) -> Result<u64>;
138     }
139
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)
143         }
144     }
145
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();
151
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)?;
155                 writer.flush()?;
156                 Ok(bytes)
157             };
158
159             match (r_cfg, w_cfg) {
160                 (
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(
170                         &mut reader,
171                         &mut writer,
172                         min(len, max_write),
173                     )
174                     .map(|bytes_copied| bytes_copied + bytes_flushed)
175                 }
176                 (
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,
189                         &mut reader,
190                         &mut writer,
191                         min(len, max_write),
192                     )
193                         .map(|bytes_sent| bytes_sent + bytes_flushed)
194                 }
195                 (CopyParams(reader_meta, Some(readfd)), CopyParams(writer_meta, Some(writefd)))
196                     if reader_meta.is_fifo() || writer_meta.is_fifo() =>
197                 {
198                     // splice
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,
205                         &mut reader,
206                         &mut writer,
207                         max_write,
208                     )
209                     .map(|bytes_sent| bytes_sent + bytes_flushed)
210                 }
211                 _ => super::generic_copy(reader, writer),
212             }
213         }
214     }
215
216     #[rustc_specialization_trait]
217     trait CopyRead: Read {
218         fn drain_to<W: Write>(&mut self, _writer: &mut W, _limit: u64) -> Result<u64> {
219             Ok(0)
220         }
221
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 {
227             u64::MAX
228         }
229
230         fn properties(&self) -> CopyParams;
231     }
232
233     #[rustc_specialization_trait]
234     trait CopyWrite: Write {
235         fn properties(&self) -> CopyParams;
236     }
237
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)
241         }
242
243         fn min_limit(&self) -> u64 {
244             (**self).min_limit()
245         }
246
247         fn properties(&self) -> CopyParams {
248             (**self).properties()
249         }
250     }
251
252     impl<T> CopyWrite for &mut T where T: CopyWrite {
253         fn properties(&self) -> CopyParams {
254             (**self).properties()
255         }
256     }
257
258
259     impl CopyRead for File {
260         fn properties(&self) -> CopyParams {
261             CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
262         }
263     }
264
265     impl CopyRead for &File {
266         fn properties(&self) -> CopyParams {
267             CopyParams(fd_to_meta(*self), Some(self.as_raw_fd()))
268         }
269     }
270
271     impl CopyWrite for File {
272         fn properties(&self) -> CopyParams {
273             CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
274         }
275     }
276
277     impl CopyWrite for &File {
278         fn properties(&self) -> CopyParams {
279             CopyParams(fd_to_meta(*self), Some(self.as_raw_fd()))
280         }
281     }
282
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()))
287         }
288     }
289
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()))
294         }
295     }
296
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()))
301         }
302     }
303
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()))
308         }
309     }
310
311     impl CopyWrite for ChildStdin {
312         fn properties(&self) -> CopyParams {
313             CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
314         }
315     }
316
317     impl CopyRead for ChildStdout {
318         fn properties(&self) -> CopyParams {
319             CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
320         }
321     }
322
323     impl CopyRead for ChildStderr {
324         fn properties(&self) -> CopyParams {
325             CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
326         }
327     }
328
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);
337
338             Ok(bytes_drained as u64)
339         }
340
341         fn properties(&self) -> CopyParams {
342             CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
343         }
344     }
345
346     impl CopyWrite for StdoutLock<'_> {
347         fn properties(&self) -> CopyParams {
348             CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
349         }
350     }
351
352     impl CopyWrite for StderrLock<'_> {
353         fn properties(&self) -> CopyParams {
354             CopyParams(fd_to_meta(self), Some(self.as_raw_fd()))
355         }
356     }
357
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);
365
366             Ok(bytes_drained)
367         }
368
369         fn min_limit(&self) -> u64 {
370             min(Take::limit(self), self.get_ref().min_limit())
371         }
372
373         fn properties(&self) -> CopyParams {
374             self.get_ref().properties()
375         }
376     }
377
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)?;
384             self.consume(bytes);
385
386             let remaining = outer_limit - bytes as u64;
387
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)?;
390
391             Ok(bytes as u64 + inner_bytes)
392         }
393
394         fn min_limit(&self) -> u64 {
395             self.get_ref().min_limit()
396         }
397
398         fn properties(&self) -> CopyParams {
399             self.get_ref().properties()
400         }
401     }
402
403     impl<T: CopyWrite> CopyWrite for BufWriter<T> {
404         fn properties(&self) -> CopyParams {
405             self.get_ref().properties()
406         }
407     }
408
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,
415         }
416     }
417
418     unsafe fn fd_as_file(fd: RawFd) -> ManuallyDrop<File> {
419         ManuallyDrop::new(File::from_raw_fd(fd))
420     }
421 }