2018-12-09 15:37:48 +00:00
|
|
|
use failure::*;
|
|
|
|
use nix::unistd;
|
|
|
|
use nix::sys::stat;
|
|
|
|
|
|
|
|
use std::fs::File;
|
|
|
|
use std::io::Write;
|
|
|
|
use std::path::Path;
|
|
|
|
|
|
|
|
pub fn file_set_contents<P: AsRef<Path>>(
|
|
|
|
path: P,
|
|
|
|
data: &[u8],
|
|
|
|
perm: Option<stat::Mode>,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
|
|
|
|
let path = path.as_ref();
|
|
|
|
|
|
|
|
let mut template = path.to_owned();
|
|
|
|
template.set_extension("tmp_XXXXXX");
|
|
|
|
let (fd, tmp_path) = match unistd::mkstemp(&template) {
|
|
|
|
Ok((fd, path)) => (fd, path),
|
|
|
|
Err(err) => bail!("mkstemp {:?} failed: {}", template, err),
|
|
|
|
};
|
|
|
|
|
|
|
|
let tmp_path = tmp_path.as_path();
|
|
|
|
|
2018-12-09 15:41:54 +00:00
|
|
|
let mode : stat::Mode = perm.unwrap_or(stat::Mode::from(
|
2018-12-09 15:37:48 +00:00
|
|
|
stat::Mode::S_IRUSR | stat::Mode::S_IWUSR |
|
|
|
|
stat::Mode::S_IRGRP | stat::Mode::S_IROTH
|
2018-12-09 15:41:54 +00:00
|
|
|
));
|
2018-12-09 15:37:48 +00:00
|
|
|
|
|
|
|
if let Err(err) = stat::fchmod(fd, mode) {
|
|
|
|
let _ = unistd::unlink(tmp_path);
|
|
|
|
bail!("fchmod {:?} failed: {}", tmp_path, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
use std::os::unix::io::FromRawFd;
|
|
|
|
let mut file = unsafe { File::from_raw_fd(fd) };
|
|
|
|
|
|
|
|
if let Err(err) = file.write_all(data) {
|
|
|
|
let _ = unistd::unlink(tmp_path);
|
|
|
|
bail!("write failed: {}", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Err(err) = std::fs::rename(tmp_path, path) {
|
|
|
|
let _ = unistd::unlink(tmp_path);
|
|
|
|
bail!("Atomic rename failed for file {:?} - {}", path, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|