Skip to content

Commit 1a19c46

Browse files
committed
fs::copy() unix: set file mode early
same fix as commit fb98ca7 PR: rust-lang#58803 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.
1 parent 9261088 commit 1a19c46

File tree

1 file changed

+30
-10
lines changed

1 file changed

+30
-10
lines changed

src/libstd/sys/unix/fs.rs

+30-10
Original file line numberDiff line numberDiff line change
@@ -829,19 +829,39 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
829829

830830
#[cfg(not(any(target_os = "linux", target_os = "android")))]
831831
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
832-
use crate::fs::File;
833-
if !from.is_file() {
834-
return Err(Error::new(ErrorKind::InvalidInput,
835-
"the source path is not an existing regular file"))
836-
}
832+
use crate::fs::{File, OpenOptions};
833+
use crate::os::unix::fs::{OpenOptionsExt, PermissionsExt};
837834

838835
let mut reader = File::open(from)?;
839-
let mut writer = File::create(to)?;
840-
let perm = reader.metadata()?.permissions();
841836

842-
let ret = io::copy(&mut reader, &mut writer)?;
843-
writer.set_permissions(perm)?;
844-
Ok(ret)
837+
let (perm, len) = {
838+
let metadata = reader.metadata()?;
839+
if !metadata.is_file() {
840+
return Err(Error::new(
841+
ErrorKind::InvalidInput,
842+
"the source path is not an existing regular file",
843+
));
844+
}
845+
(metadata.permissions(), metadata.len())
846+
};
847+
848+
let mut writer = OpenOptions::new()
849+
// create the file with the correct mode right away
850+
.mode(perm.mode())
851+
.write(true)
852+
.create(true)
853+
.truncate(true)
854+
.open(to)?;
855+
856+
let writer_metadata = writer.metadata()?;
857+
if writer_metadata.is_file() {
858+
// Set the correct file permissions, in case the file already existed.
859+
// Don't set the permissions on already existing non-files like
860+
// pipes/FIFOs or device nodes.
861+
writer.set_permissions(perm)?;
862+
}
863+
864+
io::copy(&mut reader, &mut writer)
845865
}
846866

847867
#[cfg(any(target_os = "linux", target_os = "android"))]

0 commit comments

Comments
 (0)