mirror of
https://github.com/rust-lang/cargo
synced 2024-10-30 03:28:38 +00:00
fix: preserve file permissions on unix during write_atomic
Preseves u/g/o r/w/x permissions on unix platforms.
This commit is contained in:
parent
038ccd29c0
commit
36a63b4039
1 changed files with 26 additions and 2 deletions
|
@ -4,7 +4,7 @@ use anyhow::{Context, Result};
|
|||
use filetime::FileTime;
|
||||
use std::env;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs::{self, File, Metadata, OpenOptions};
|
||||
use std::fs::{self, File, Metadata, OpenOptions, Permissions};
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::iter;
|
||||
|
@ -185,10 +185,34 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()>
|
|||
/// write_atomic uses tempfile::persist to accomplish atomic writes.
|
||||
pub fn write_atomic<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
|
||||
// On unix platforms, get the permissions of the original file. Copy only the user/group/other
|
||||
// read/write/execute permission bits. The tempfile lib defaults to an initial mode of 0o600,
|
||||
// and we'll set the proper permissions after creating the file.
|
||||
#[cfg(unix)]
|
||||
let perms = path.metadata().ok().map(|meta| {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
// these constants are u16 on macOS
|
||||
let mask = u32::from(libc::S_IRWXU | libc::S_IRWXG | libc::S_IRWXO);
|
||||
let mode = meta.permissions().mode() & mask;
|
||||
|
||||
Permissions::from_mode(mode)
|
||||
});
|
||||
|
||||
let mut tmp = TempFileBuilder::new()
|
||||
.prefix(path.file_name().unwrap())
|
||||
.tempfile_in(path.parent().unwrap())?;
|
||||
tmp.write_all(contents.as_ref())?;
|
||||
|
||||
// On unix platforms, set the permissions on the newly created file. We can use fchmod (called
|
||||
// by the std lib; subject to change) which ignores the umask so that the new file has the same
|
||||
// permissions as the old file.
|
||||
#[cfg(unix)]
|
||||
if let Some(perms) = perms {
|
||||
tmp.as_file().set_permissions(perms)?;
|
||||
}
|
||||
|
||||
tmp.persist(path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -846,7 +870,7 @@ mod tests {
|
|||
let new_perms = std::fs::metadata(tmp.path()).unwrap().permissions();
|
||||
|
||||
let mask = u32::from(libc::S_IRWXU | libc::S_IRWXG | libc::S_IRWXO);
|
||||
assert_eq!(0o600, new_perms.mode() & mask);
|
||||
assert_eq!(original_perms.mode(), new_perms.mode() & mask);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in a new issue