about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-03-28 08:56:34 +0000
committerbors <bors@rust-lang.org>2019-03-28 08:56:34 +0000
commit237bf3244fffef501cf37d4bda00e1fce3fcfb46 (patch)
treeca483d5330b97887970dca2110c007a1084e4aa1 /src/libstd
parent6bfe4b7b51f47ca014d535506cbc5682f00d8d2a (diff)
parentd403cd787c98610cf5287301820ad3353b35481d (diff)
downloadrust-237bf3244fffef501cf37d4bda00e1fce3fcfb46.tar.gz
rust-237bf3244fffef501cf37d4bda00e1fce3fcfb46.zip
Auto merge of #59478 - Centril:rollup, r=Centril
Rollup of 12 pull requests

Successful merges:

 - #57987 (Fix some AArch64 typos)
 - #58581 (Refactor generic parameter encoder functions)
 - #58803 (fs::copy() unix: set file mode early)
 - #58848 (Prevent cache issues on version updates)
 - #59198 (Do not complain about unmentioned fields in recovered patterns)
 - #59351 (Include llvm-ar with llvm-tools component)
 - #59413 (HirIdify hir::ItemId)
 - #59441 (Remove the block on natvis for lld-link.)
 - #59448 (Use consistent phrasing for all macro summaries)
 - #59456 (Add documentation about `for` used as higher ranked trait bounds)
 - #59472 (Document that `std::io::BufReader` discards contents on drop)
 - #59474 (Fix link capitalization in documentation of std::io::BufWriter.)

Failed merges:

r? @ghost
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/io/buffered.rs8
-rw-r--r--src/libstd/keyword_docs.rs17
-rw-r--r--src/libstd/macros.rs46
-rw-r--r--src/libstd/sys/unix/fs.rs129
4 files changed, 116 insertions, 84 deletions
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 4668e3ec7ea..441f6b95d0b 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -21,6 +21,10 @@ use crate::memchr;
 /// times. It also provides no advantage when reading from a source that is
 /// already in memory, like a `Vec<u8>`.
 ///
+/// When the `BufReader` is dropped, the contents of its buffer will be
+/// discarded. Creating multiple instances of a `BufReader` on the same
+/// stream can cause data loss.
+///
 /// [`Read`]: ../../std/io/trait.Read.html
 /// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read
 /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
@@ -350,7 +354,7 @@ impl<R: Seek> Seek for BufReader<R> {
 ///
 /// It can be excessively inefficient to work directly with something that
 /// implements [`Write`]. For example, every call to
-/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A
+/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A
 /// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
 /// writer in large, infrequent batches.
 ///
@@ -401,7 +405,7 @@ impl<R: Seek> Seek for BufReader<R> {
 /// the `stream` is dropped.
 ///
 /// [`Write`]: ../../std/io/trait.Write.html
-/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write
+/// [`TcpStream::write`]: ../../std/net/struct.TcpStream.html#method.write
 /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
 /// [`flush`]: #method.flush
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index bef6bc92661..7b0d1549e06 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -286,11 +286,16 @@ mod fn_keyword { }
 //
 /// The `for` keyword.
 ///
-/// `for` is primarily used in for-in-loops, but it has a few other pieces of syntactic uses such as
-/// `impl Trait for Type` (see [`impl`] for more info on that). for-in-loops, or to be more
-/// precise, iterator loops, are a simple syntactic sugar over an exceedingly common practice
-/// within Rust, which is to loop over an iterator until that iterator returns `None` (or `break`
-/// is called).
+/// The `for` keyword is used in many syntactic locations:
+///
+/// * `for` is used in for-in-loops (see below).
+/// * `for` is used when implementing traits as in `impl Trait for Type` (see [`impl`] for more info
+///   on that).
+/// * `for` is also used for [higher-ranked trait bounds] as in `for<'a> &'a T: PartialEq<i32>`.
+///
+/// for-in-loops, or to be more precise, iterator loops, are a simple syntactic sugar over a common
+/// practice within Rust, which is to loop over an iterator until that iterator returns `None` (or
+/// `break` is called).
 ///
 /// ```rust
 /// for i in 0..5 {
@@ -347,6 +352,8 @@ mod fn_keyword { }
 /// For more information on for-loops, see the [Rust book] or the [Reference].
 ///
 /// [`impl`]: keyword.impl.html
+/// [higher-ranked trait bounds]:
+/// https://doc.rust-lang.org/nightly/reference/trait-bounds.html#higher-ranked-trait-bounds
 /// [`IntoIterator`]: iter/trait.IntoIterator.html
 /// [Rust book]:
 /// https://doc.rust-lang.org/book/2018-edition/ch03-05-control-flow.html#looping-through-a-collection-with-for
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index d5dc5f7c4f0..d5afd069d7f 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -4,7 +4,7 @@
 //! library. Each macro is available for use when linking against the standard
 //! library.
 
-/// The entry point for panic of Rust threads.
+/// Panics the current thread.
 ///
 /// This allows a program to terminate immediately and provide feedback
 /// to the caller of the program. `panic!` should be used when a program reaches
@@ -70,7 +70,7 @@ macro_rules! panic {
     });
 }
 
-/// Macro for printing to the standard output.
+/// Prints to the standard output.
 ///
 /// Equivalent to the [`println!`] macro except that a newline is not printed at
 /// the end of the message.
@@ -116,7 +116,7 @@ macro_rules! print {
     ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
 }
 
-/// Macro for printing to the standard output, with a newline.
+/// Prints to the standard output, with a newline.
 ///
 /// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
 /// (no additional CARRIAGE RETURN (`\r`/`U+000D`).
@@ -151,7 +151,7 @@ macro_rules! println {
     })
 }
 
-/// Macro for printing to the standard error.
+/// Prints to the standard error.
 ///
 /// Equivalent to the [`print!`] macro, except that output goes to
 /// [`io::stderr`] instead of `io::stdout`. See [`print!`] for
@@ -179,7 +179,7 @@ macro_rules! eprint {
     ($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*)));
 }
 
-/// Macro for printing to the standard error, with a newline.
+/// Prints to the standard error, with a newline.
 ///
 /// Equivalent to the [`println!`] macro, except that output goes to
 /// [`io::stderr`] instead of `io::stdout`. See [`println!`] for
@@ -210,8 +210,10 @@ macro_rules! eprintln {
     })
 }
 
-/// A macro for quick and dirty debugging with which you can inspect
-/// the value of a given expression. An example:
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
 ///
 /// ```rust
 /// let a = 2;
@@ -328,7 +330,7 @@ macro_rules! dbg {
     }
 }
 
-/// A macro to await on an async call.
+/// Awaits the completion of an async call.
 #[macro_export]
 #[unstable(feature = "await_macro", issue = "50547")]
 #[allow_internal_unstable(gen_future, generators)]
@@ -351,7 +353,7 @@ macro_rules! r#await {
     } }
 }
 
-/// A macro to select an event from a number of receivers.
+/// Selects the first successful receive event from a number of receivers.
 ///
 /// This macro is used to wait for the first event to occur on a number of
 /// receivers. It places no restrictions on the types of receivers given to
@@ -423,7 +425,7 @@ macro_rules! assert_approx_eq {
 #[cfg(rustdoc)]
 mod builtin {
 
-    /// Unconditionally causes compilation to fail with the given error message when encountered.
+    /// Causes compilation to fail with the given error message when encountered.
     ///
     /// This macro should be used when a crate uses a conditional compilation strategy to provide
     /// better error messages for erroneous conditions. It's the compiler-level form of [`panic!`],
@@ -465,7 +467,7 @@ mod builtin {
         ($msg:expr,) => ({ /* compiler built-in */ });
     }
 
-    /// The core macro for formatted string creation & output.
+    /// Constructs parameters for the other string-formatting macros.
     ///
     /// This macro functions by taking a formatting string literal containing
     /// `{}` for each additional argument passed. `format_args!` prepares the
@@ -517,7 +519,7 @@ mod builtin {
         ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ });
     }
 
-    /// Inspect an environment variable at compile time.
+    /// Inspects an environment variable at compile time.
     ///
     /// This macro will expand to the value of the named environment variable at
     /// compile time, yielding an expression of type `&'static str`.
@@ -555,7 +557,7 @@ mod builtin {
         ($name:expr,) => ({ /* compiler built-in */ });
     }
 
-    /// Optionally inspect an environment variable at compile time.
+    /// Optionally inspects an environment variable at compile time.
     ///
     /// If the named environment variable is present at compile time, this will
     /// expand into an expression of type `Option<&'static str>` whose value is
@@ -581,7 +583,7 @@ mod builtin {
         ($name:expr,) => ({ /* compiler built-in */ });
     }
 
-    /// Concatenate identifiers into one identifier.
+    /// Concatenates identifiers into one identifier.
     ///
     /// This macro takes any number of comma-separated identifiers, and
     /// concatenates them all into one, yielding an expression which is a new
@@ -634,7 +636,7 @@ mod builtin {
         ($($e:expr,)*) => ({ /* compiler built-in */ });
     }
 
-    /// A macro which expands to the line number on which it was invoked.
+    /// Expands to the line number on which it was invoked.
     ///
     /// With [`column!`] and [`file!`], these macros provide debugging information for
     /// developers about the location within the source.
@@ -659,7 +661,7 @@ mod builtin {
     #[rustc_doc_only_macro]
     macro_rules! line { () => ({ /* compiler built-in */ }) }
 
-    /// A macro which expands to the column number on which it was invoked.
+    /// Expands to the column number at which it was invoked.
     ///
     /// With [`line!`] and [`file!`], these macros provide debugging information for
     /// developers about the location within the source.
@@ -684,7 +686,7 @@ mod builtin {
     #[rustc_doc_only_macro]
     macro_rules! column { () => ({ /* compiler built-in */ }) }
 
-    /// A macro which expands to the file name from which it was invoked.
+    /// Expands to the file name in which it was invoked.
     ///
     /// With [`line!`] and [`column!`], these macros provide debugging information for
     /// developers about the location within the source.
@@ -708,7 +710,7 @@ mod builtin {
     #[rustc_doc_only_macro]
     macro_rules! file { () => ({ /* compiler built-in */ }) }
 
-    /// A macro which stringifies its arguments.
+    /// Stringifies its arguments.
     ///
     /// This macro will yield an expression of type `&'static str` which is the
     /// stringification of all the tokens passed to the macro. No restrictions
@@ -822,7 +824,7 @@ mod builtin {
     #[rustc_doc_only_macro]
     macro_rules! module_path { () => ({ /* compiler built-in */ }) }
 
-    /// Boolean evaluation of configuration flags, at compile-time.
+    /// Evaluates boolean combinations of configuration flags at compile-time.
     ///
     /// In addition to the `#[cfg]` attribute, this macro is provided to allow
     /// boolean expression evaluation of configuration flags. This frequently
@@ -844,7 +846,7 @@ mod builtin {
     #[rustc_doc_only_macro]
     macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) }
 
-    /// Parse a file as an expression or an item according to the context.
+    /// Parses a file as an expression or an item according to the context.
     ///
     /// The file is located relative to the current file (similarly to how
     /// modules are found).
@@ -890,7 +892,7 @@ mod builtin {
         ($file:expr,) => ({ /* compiler built-in */ });
     }
 
-    /// Ensure that a boolean expression is `true` at runtime.
+    /// Asserts that a boolean expression is `true` at runtime.
     ///
     /// This will invoke the [`panic!`] macro if the provided expression cannot be
     /// evaluated to `true` at runtime.
@@ -944,7 +946,7 @@ mod builtin {
     }
 }
 
-/// A macro for defining `#[cfg]` if-else statements.
+/// Defines `#[cfg]` if-else statements.
 ///
 /// This is similar to the `if/elif` C preprocessor macro by allowing definition
 /// of a cascade of `#[cfg]` cases, emitting the implementation which matches
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index 7ff098bc9e1..c73f7983146 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -827,30 +827,54 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
     Ok(PathBuf::from(OsString::from_vec(buf)))
 }
 
+fn open_and_set_permissions(
+    from: &Path,
+    to: &Path,
+) -> io::Result<(crate::fs::File, crate::fs::File, u64, crate::fs::Metadata)> {
+    use crate::fs::{File, OpenOptions};
+    use crate::os::unix::fs::{OpenOptionsExt, PermissionsExt};
+
+    let reader = File::open(from)?;
+    let (perm, len) = {
+        let metadata = reader.metadata()?;
+        if !metadata.is_file() {
+            return Err(Error::new(
+                ErrorKind::InvalidInput,
+                "the source path is not an existing regular file",
+            ));
+        }
+        (metadata.permissions(), metadata.len())
+    };
+    let writer = OpenOptions::new()
+        // create the file with the correct mode right away
+        .mode(perm.mode())
+        .write(true)
+        .create(true)
+        .truncate(true)
+        .open(to)?;
+    let writer_metadata = writer.metadata()?;
+    if writer_metadata.is_file() {
+        // Set the correct file permissions, in case the file already existed.
+        // Don't set the permissions on already existing non-files like
+        // pipes/FIFOs or device nodes.
+        writer.set_permissions(perm)?;
+    }
+    Ok((reader, writer, len, writer_metadata))
+}
+
 #[cfg(not(any(target_os = "linux",
               target_os = "android",
               target_os = "macos",
               target_os = "ios")))]
 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
-    use crate::fs::File;
-    if !from.is_file() {
-        return Err(Error::new(ErrorKind::InvalidInput,
-                              "the source path is not an existing regular file"))
-    }
+    let (mut reader, mut writer, _, _) = open_and_set_permissions(from, to)?;
 
-    let mut reader = File::open(from)?;
-    let mut writer = File::create(to)?;
-    let perm = reader.metadata()?.permissions();
-
-    let ret = io::copy(&mut reader, &mut writer)?;
-    writer.set_permissions(perm)?;
-    Ok(ret)
+    io::copy(&mut reader, &mut writer)
 }
 
 #[cfg(any(target_os = "linux", target_os = "android"))]
 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     use crate::cmp;
-    use crate::fs::File;
     use crate::sync::atomic::{AtomicBool, Ordering};
 
     // Kernel prior to 4.5 don't have copy_file_range
@@ -876,17 +900,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
         )
     }
 
-    if !from.is_file() {
-        return Err(Error::new(ErrorKind::InvalidInput,
-                              "the source path is not an existing regular file"))
-    }
-
-    let mut reader = File::open(from)?;
-    let mut writer = File::create(to)?;
-    let (perm, len) = {
-        let metadata = reader.metadata()?;
-        (metadata.permissions(), metadata.size())
-    };
+    let (mut reader, mut writer, len, _) = open_and_set_permissions(from, to)?;
 
     let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed);
     let mut written = 0u64;
@@ -896,13 +910,14 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
             let copy_result = unsafe {
                 // We actually don't have to adjust the offsets,
                 // because copy_file_range adjusts the file offset automatically
-                cvt(copy_file_range(reader.as_raw_fd(),
-                                    ptr::null_mut(),
-                                    writer.as_raw_fd(),
-                                    ptr::null_mut(),
-                                    bytes_to_copy,
-                                    0)
-                    )
+                cvt(copy_file_range(
+                    reader.as_raw_fd(),
+                    ptr::null_mut(),
+                    writer.as_raw_fd(),
+                    ptr::null_mut(),
+                    bytes_to_copy,
+                    0,
+                ))
             };
             if let Err(ref copy_err) = copy_result {
                 match copy_err.raw_os_error() {
@@ -920,24 +935,25 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
             Ok(ret) => written += ret as u64,
             Err(err) => {
                 match err.raw_os_error() {
-                    Some(os_err) if os_err == libc::ENOSYS
-                                 || os_err == libc::EXDEV
-                                 || os_err == libc::EPERM => {
-                        // Try fallback io::copy if either:
-                        // - Kernel version is < 4.5 (ENOSYS)
-                        // - Files are mounted on different fs (EXDEV)
-                        // - copy_file_range is disallowed, for example by seccomp (EPERM)
-                        assert_eq!(written, 0);
-                        let ret = io::copy(&mut reader, &mut writer)?;
-                        writer.set_permissions(perm)?;
-                        return Ok(ret)
-                    },
+                    Some(os_err)
+                    if os_err == libc::ENOSYS
+                        || os_err == libc::EXDEV
+                        || os_err == libc::EINVAL
+                        || os_err == libc::EPERM =>
+                        {
+                            // Try fallback io::copy if either:
+                            // - Kernel version is < 4.5 (ENOSYS)
+                            // - Files are mounted on different fs (EXDEV)
+                            // - copy_file_range is disallowed, for example by seccomp (EPERM)
+                            // - copy_file_range cannot be used with pipes or device nodes (EINVAL)
+                            assert_eq!(written, 0);
+                            return io::copy(&mut reader, &mut writer);
+                        }
                     _ => return Err(err),
                 }
             }
         }
     }
-    writer.set_permissions(perm)?;
     Ok(written)
 }
 
@@ -960,9 +976,9 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     type copyfile_flags_t = u32;
 
     extern "C" {
-        fn copyfile(
-            from: *const libc::c_char,
-            to: *const libc::c_char,
+        fn fcopyfile(
+            from: libc::c_int,
+            to: libc::c_int,
             state: copyfile_state_t,
             flags: copyfile_flags_t,
         ) -> libc::c_int;
@@ -988,10 +1004,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
         }
     }
 
-    if !from.is_file() {
-        return Err(Error::new(ErrorKind::InvalidInput,
-                              "the source path is not an existing regular file"))
-    }
+    let (reader, writer, _, writer_metadata) = open_and_set_permissions(from, to)?;
 
     // We ensure that `FreeOnDrop` never contains a null pointer so it is
     // always safe to call `copyfile_state_free`
@@ -1003,12 +1016,18 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
         FreeOnDrop(state)
     };
 
+    let flags = if writer_metadata.is_file() {
+        COPYFILE_ALL
+    } else {
+        COPYFILE_DATA
+    };
+
     cvt(unsafe {
-        copyfile(
-            cstr(from)?.as_ptr(),
-            cstr(to)?.as_ptr(),
+        fcopyfile(
+            reader.as_raw_fd(),
+            writer.as_raw_fd(),
             state.0,
-            COPYFILE_ALL,
+            flags,
         )
     })?;