      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156

    use super::{BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
    use crate::mem::MaybeUninit;

    /// Copies the entire contents of a reader into a writer.
    ///
    /// This function will continuously read data from `reader` and then
    /// write it into `writer` in a streaming fashion until `reader`
    /// returns EOF.
    ///
    /// On success, the total number of bytes that were copied from
    /// `reader` to `writer` is returned.
    ///
    /// If you’re wanting to copy the contents of one file to another and you’re
    /// working with filesystem paths, see the [`fs::copy`] function.
    ///
    /// [`fs::copy`]: crate::fs::copy
    ///
    /// # Errors
    ///
    /// This function will return an error immediately if any call to [`read`] or
    /// [`write`] returns an error. All instances of [`ErrorKind::Interrupted`] are
    /// handled by this function and the underlying operation is retried.
    ///
    /// [`read`]: Read::read
    /// [`write`]: Write::write
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io;
    ///
    /// fn main() -> io::Result<()> {
    ///     let mut reader: &[u8] = b"hello";
    ///     let mut writer: Vec<u8> = vec![];
    ///
    ///     io::copy(&mut reader, &mut writer)?;
    ///
    ///     assert_eq!(&b"hello"[..], &writer[..]);
    ///     Ok(())
    /// }
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64>
    where
        R: Read,
        W: Write,
    {
        cfg_if::cfg_if! {
            if #[cfg(any(target_os = "linux", target_os = "android"))] {
                crate::sys::kernel_copy::copy_spec(reader, writer)
            } else {
                generic_copy(reader, writer)
            }
        }
    }

    /// 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<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64>
    where
        R: Read,
        W: Write,
    {
        BufferedCopySpec::copy_to(reader, writer)
    }

    /// Specialization of the read-write loop that either uses a stack buffer
    /// or reuses the internal buffer of a BufWriter
    trait BufferedCopySpec: Write {
        fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64>;
    }

    impl<W: Write + ?Sized> BufferedCopySpec for W {
        default fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> {
            stack_buffer_copy(reader, writer)
        }
    }

    impl<I: Write> BufferedCopySpec for BufWriter<I> {
        fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> {
            if writer.capacity() < DEFAULT_BUF_SIZE {
                return stack_buffer_copy(reader, writer);
            }

            // FIXME: #42788
            //
            //   - This creates a (mut) reference to a slice of
            //     _uninitialized_ integers, which is **undefined behavior**
            //
            //   - Only the standard library gets to soundly "ignore" this,
            //     based on its privileged knowledge of unstable rustc
            //     internals;
            unsafe {
                let spare_cap = writer.buffer_mut().spare_capacity_mut();
                reader.initializer().initialize(MaybeUninit::slice_assume_init_mut(spare_cap));
            }

            let mut len = 0;

            loop {
                let buf = writer.buffer_mut();
                let spare_cap = buf.spare_capacity_mut();

                if spare_cap.len() >= DEFAULT_BUF_SIZE {
                    match reader.read(unsafe { MaybeUninit::slice_assume_init_mut(spare_cap) }) {
                        Ok(0) => return Ok(len), // EOF reached
                        Ok(bytes_read) => {
                            assert!(bytes_read <= spare_cap.len());
                            // SAFETY: The initializer contract guarantees that either it or `read`
                            // will have initialized these bytes. And we just checked that the number
                            // of bytes is within the buffer capacity.
                            unsafe { buf.set_len(buf.len() + bytes_read) };
                            len += bytes_read as u64;
                            // Read again if the buffer still has enough capacity, as BufWriter itself would do
                            // This will occur if the reader returns short reads
                            continue;
                        }
                        Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                        Err(e) => return Err(e),
                    }
                }

                writer.flush_buf()?;
            }
        }
    }

    fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
        reader: &mut R,
        writer: &mut W,
    ) -> Result<u64> {
        let mut buf = MaybeUninit::<[u8; DEFAULT_BUF_SIZE]>::uninit();
        // FIXME: #42788
        //
        //   - This creates a (mut) reference to a slice of
        //     _uninitialized_ integers, which is **undefined behavior**
        //
        //   - Only the standard library gets to soundly "ignore" this,
        //     based on its privileged knowledge of unstable rustc
        //     internals;
        unsafe {
            reader.initializer().initialize(buf.assume_init_mut());
        }

        let mut written = 0;
        loop {
            let len = match reader.read(unsafe { buf.assume_init_mut() }) {
                Ok(0) => return Ok(written),
                Ok(len) => len,
                Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                Err(e) => return Err(e),
            };
            writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?;
            written += len as u64;
        }
    }