implement tools::file_set_contents

This commit is contained in:
Dietmar Maurer 2018-12-09 16:37:48 +01:00
parent 652c11900d
commit f12f8ff1a6
3 changed files with 54 additions and 3 deletions

View File

@ -4,6 +4,7 @@ use std::fs::{OpenOptions};
use std::io::{Read, Write}; use std::io::{Read, Write};
//use std::sync::Arc; //use std::sync::Arc;
use crate::tools;
use crate::api::schema::*; use crate::api::schema::*;
use crate::section_config::*; use crate::section_config::*;
@ -71,9 +72,7 @@ pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
//fixme: compute and compare digest //fixme: compute and compare digest
//fixme: impl file_set_contents() (atomic write) tools::file_set_contents(DATASTORE_CFG_FILENAME, raw.as_bytes(), None)?;
file.set_len(0)?;
file.write_all(raw.as_bytes())?;
Ok(()) Ok(())
} }

View File

@ -10,6 +10,8 @@ pub mod static_map;
/// hierarchy of API entries, and provides ways to find an API /// hierarchy of API entries, and provides ways to find an API
/// definition by path. /// definition by path.
pub mod tools;
#[macro_use] #[macro_use]
pub mod api { pub mod api {

50
src/tools.rs Normal file
View File

@ -0,0 +1,50 @@
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();
let mode : stat::Mode = stat::Mode::from(
stat::Mode::S_IRUSR | stat::Mode::S_IWUSR |
stat::Mode::S_IRGRP | stat::Mode::S_IROTH
);
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(())
}