implement tools::file_set_contents
This commit is contained in:
		@ -4,6 +4,7 @@ use std::fs::{OpenOptions};
 | 
			
		||||
use std::io::{Read, Write};
 | 
			
		||||
 | 
			
		||||
//use std::sync::Arc;
 | 
			
		||||
use crate::tools;
 | 
			
		||||
use crate::api::schema::*;
 | 
			
		||||
 | 
			
		||||
use crate::section_config::*;
 | 
			
		||||
@ -71,9 +72,7 @@ pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
 | 
			
		||||
 | 
			
		||||
    //fixme: compute and compare digest
 | 
			
		||||
 | 
			
		||||
    //fixme: impl file_set_contents() (atomic write)
 | 
			
		||||
    file.set_len(0)?;
 | 
			
		||||
    file.write_all(raw.as_bytes())?;
 | 
			
		||||
    tools::file_set_contents(DATASTORE_CFG_FILENAME, raw.as_bytes(), None)?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,8 @@ pub mod static_map;
 | 
			
		||||
/// hierarchy of API entries, and provides ways to find an API
 | 
			
		||||
/// definition by path.
 | 
			
		||||
 | 
			
		||||
pub mod tools;
 | 
			
		||||
 | 
			
		||||
#[macro_use]
 | 
			
		||||
pub mod api {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										50
									
								
								src/tools.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/tools.rs
									
									
									
									
									
										Normal 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(())
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user