io/fs: do not replace files with unchanged contents

Do not update file timestamps when contents have not actually changed.
This commit is contained in:
Matthias Schiffer 2023-07-30 20:31:40 +02:00
parent cb791f48e9
commit e18d4cea82
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C

View file

@ -1,6 +1,6 @@
use std::{
fs::{self, File},
io::{BufWriter, Write},
io::{BufReader, BufWriter, Read, Write},
path::{Path, PathBuf},
};
@ -41,19 +41,44 @@ where
.with_context(|| format!("Failed to write file {}", path.display()))
}
pub fn equal(path1: &Path, path2: &Path) -> Result<bool> {
let mut file1 = BufReader::new(
fs::File::open(path1)
.with_context(|| format!("Failed to open file {}", path1.display()))?,
)
.bytes();
let mut file2 = BufReader::new(
fs::File::open(path2)
.with_context(|| format!("Failed to open file {}", path2.display()))?,
)
.bytes();
Ok(loop {
match (file1.next().transpose()?, file2.next().transpose()?) {
(Some(b1), Some(b2)) if b1 == b2 => continue,
(None, None) => break true,
_ => break false,
};
})
}
pub fn create_with_tmpfile<T, F>(path: &Path, f: F) -> Result<T>
where
F: FnOnce(&mut BufWriter<File>) -> Result<T>,
{
let tmp_path = tmpfile_name(path);
let mut cleanup = true;
let ret = (|| {
let ret = create(&tmp_path, f)?;
rename(&tmp_path, path)?;
if !matches!(equal(path, &tmp_path), Result::Ok(true)) {
rename(&tmp_path, path)?;
cleanup = false;
}
Ok(ret)
})();
if ret.is_err() {
if cleanup {
let _ = fs::remove_file(&tmp_path);
}