From 6cd6759cfcb9794dba4cc2a5a1fae6ae63706d12 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 14 Mar 2019 18:28:24 -0700 Subject: Do not complain about unmentioned fields in recovered patterns When the parser has to recover from malformed code in a pattern, do not complain about missing fields. --- src/test/ui/parser/bind-struct-early-modifiers.rs | 1 - src/test/ui/parser/bind-struct-early-modifiers.stderr | 9 +-------- src/test/ui/parser/issue-10392.rs | 1 - src/test/ui/parser/issue-10392.stderr | 9 +-------- src/test/ui/resolve/issue-54379.rs | 2 +- src/test/ui/resolve/issue-54379.stderr | 9 +-------- 6 files changed, 4 insertions(+), 27 deletions(-) (limited to 'src/test') diff --git a/src/test/ui/parser/bind-struct-early-modifiers.rs b/src/test/ui/parser/bind-struct-early-modifiers.rs index c1de0df54e2..c4b1937de10 100644 --- a/src/test/ui/parser/bind-struct-early-modifiers.rs +++ b/src/test/ui/parser/bind-struct-early-modifiers.rs @@ -2,7 +2,6 @@ fn main() { struct Foo { x: isize } match (Foo { x: 10 }) { Foo { ref x: ref x } => {}, //~ ERROR expected `,` - //~| ERROR pattern does not mention field `x` _ => {} } } diff --git a/src/test/ui/parser/bind-struct-early-modifiers.stderr b/src/test/ui/parser/bind-struct-early-modifiers.stderr index 50c95b8cf40..03482a41f54 100644 --- a/src/test/ui/parser/bind-struct-early-modifiers.stderr +++ b/src/test/ui/parser/bind-struct-early-modifiers.stderr @@ -4,12 +4,5 @@ error: expected `,` LL | Foo { ref x: ref x } => {}, | ^ -error[E0027]: pattern does not mention field `x` - --> $DIR/bind-struct-early-modifiers.rs:4:9 - | -LL | Foo { ref x: ref x } => {}, - | ^^^^^^^^^^^^^^^^^^^^ missing field `x` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/parser/issue-10392.rs b/src/test/ui/parser/issue-10392.rs index dd84af39300..5b0c2fc2be4 100644 --- a/src/test/ui/parser/issue-10392.rs +++ b/src/test/ui/parser/issue-10392.rs @@ -4,5 +4,4 @@ fn a() -> A { panic!() } fn main() { let A { , } = a(); //~ ERROR expected ident - //~| ERROR pattern does not mention field `foo` } diff --git a/src/test/ui/parser/issue-10392.stderr b/src/test/ui/parser/issue-10392.stderr index 7bf5aa93f0a..34991151c1e 100644 --- a/src/test/ui/parser/issue-10392.stderr +++ b/src/test/ui/parser/issue-10392.stderr @@ -4,12 +4,5 @@ error: expected identifier, found `,` LL | let A { , } = a(); | ^ expected identifier -error[E0027]: pattern does not mention field `foo` - --> $DIR/issue-10392.rs:6:9 - | -LL | let A { , } = a(); - | ^^^^^^^ missing field `foo` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/resolve/issue-54379.rs b/src/test/ui/resolve/issue-54379.rs index a48f66bf0fd..807c54393f2 100644 --- a/src/test/ui/resolve/issue-54379.rs +++ b/src/test/ui/resolve/issue-54379.rs @@ -6,7 +6,7 @@ fn main() { let thing = MyStruct { s1: None }; match thing { - MyStruct { .., Some(_) } => {}, //~ ERROR pattern does not mention field `s1` + MyStruct { .., Some(_) } => {}, //~^ ERROR expected `,` //~| ERROR expected `}`, found `,` _ => {} diff --git a/src/test/ui/resolve/issue-54379.stderr b/src/test/ui/resolve/issue-54379.stderr index 60a6f904610..2a6b54572de 100644 --- a/src/test/ui/resolve/issue-54379.stderr +++ b/src/test/ui/resolve/issue-54379.stderr @@ -13,12 +13,5 @@ error: expected `,` LL | MyStruct { .., Some(_) } => {}, | ^^^^ -error[E0027]: pattern does not mention field `s1` - --> $DIR/issue-54379.rs:9:9 - | -LL | MyStruct { .., Some(_) } => {}, - | ^^^^^^^^^^^^^^^^^^^^^^^^ missing field `s1` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0027`. -- cgit 1.4.1-3-g733a5 From cf8347ba6bc82c41de2ad9bf561af593a89cbe45 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 28 Feb 2019 10:25:54 +0100 Subject: fs::copy() set file mode early A convenience method like fs::copy() should try to prevent pitfalls a normal user doesn't think about. In case of an empty umask, setting the file mode early prevents temporarily world readable or even writeable files, because the default mode is 0o666. In case the target is a named pipe or special device node, setting the file mode can lead to unwanted side effects, like setting permissons on `/dev/stdout` or for root setting permissions on `/dev/null`. copy_file_range() returns EINVAL, if the destination is a FIFO/pipe or a device like "/dev/null", so fallback to io::copy, too. Use `fcopyfile` on MacOS instead of `copyfile`. Fixes: https://github.com/rust-lang/rust/issues/26933 Fixed: https://github.com/rust-lang/rust/issues/37885 --- src/libstd/sys/unix/fs.rs | 129 +++++++++++++++++------------- src/test/run-pass/paths-containing-nul.rs | 13 ++- 2 files changed, 83 insertions(+), 59 deletions(-) (limited to 'src/test') 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 { 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 { - 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 { 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 { ) } - 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 { 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 { 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 { 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 { } } - 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 { 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, ) })?; diff --git a/src/test/run-pass/paths-containing-nul.rs b/src/test/run-pass/paths-containing-nul.rs index 8c800089d1c..dfcef59aa57 100644 --- a/src/test/run-pass/paths-containing-nul.rs +++ b/src/test/run-pass/paths-containing-nul.rs @@ -1,6 +1,7 @@ #![allow(deprecated)] // ignore-cloudabi no files or I/O // ignore-wasm32-bare no files or I/O +// ignore-emscripten no files use std::fs; use std::io; @@ -22,14 +23,18 @@ fn main() { assert_invalid_input("remove_file", fs::remove_file("\0")); assert_invalid_input("metadata", fs::metadata("\0")); assert_invalid_input("symlink_metadata", fs::symlink_metadata("\0")); + + // If `dummy_file` does not exist, then we might get another unrelated error + let dummy_file = std::env::current_exe().unwrap(); + assert_invalid_input("rename1", fs::rename("\0", "a")); - assert_invalid_input("rename2", fs::rename("a", "\0")); + assert_invalid_input("rename2", fs::rename(&dummy_file, "\0")); assert_invalid_input("copy1", fs::copy("\0", "a")); - assert_invalid_input("copy2", fs::copy("a", "\0")); + assert_invalid_input("copy2", fs::copy(&dummy_file, "\0")); assert_invalid_input("hard_link1", fs::hard_link("\0", "a")); - assert_invalid_input("hard_link2", fs::hard_link("a", "\0")); + assert_invalid_input("hard_link2", fs::hard_link(&dummy_file, "\0")); assert_invalid_input("soft_link1", fs::soft_link("\0", "a")); - assert_invalid_input("soft_link2", fs::soft_link("a", "\0")); + assert_invalid_input("soft_link2", fs::soft_link(&dummy_file, "\0")); assert_invalid_input("read_link", fs::read_link("\0")); assert_invalid_input("canonicalize", fs::canonicalize("\0")); assert_invalid_input("create_dir", fs::create_dir("\0")); -- cgit 1.4.1-3-g733a5