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/sys | |
| 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/sys')
| -rw-r--r-- | src/libstd/sys/unix/fs.rs | 129 |
1 files changed, 74 insertions, 55 deletions
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, ) })?; |
