diff options
| author | bors <bors@rust-lang.org> | 2019-03-28 08:56:34 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-03-28 08:56:34 +0000 |
| commit | 237bf3244fffef501cf37d4bda00e1fce3fcfb46 (patch) | |
| tree | ca483d5330b97887970dca2110c007a1084e4aa1 /src/libstd | |
| parent | 6bfe4b7b51f47ca014d535506cbc5682f00d8d2a (diff) | |
| parent | d403cd787c98610cf5287301820ad3353b35481d (diff) | |
| download | rust-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.rs | 8 | ||||
| -rw-r--r-- | src/libstd/keyword_docs.rs | 17 | ||||
| -rw-r--r-- | src/libstd/macros.rs | 46 | ||||
| -rw-r--r-- | src/libstd/sys/unix/fs.rs | 129 |
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, ) })?; |
