feat: atomic writing (#1673)

* feat: atomic writing

* Apply suggestions from code review

* clean up temp files on error

Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
J M
2022-07-22 14:08:49 -06:00
committed by GitHub
parent 15af827cbc
commit c22c80d3b0
12 changed files with 357 additions and 122 deletions

View File

@@ -33,6 +33,7 @@ swc_eq_ignore_macros = "=0.1.0"
swc_macros_common = "=0.3.5"
swc_visit = "=0.3.0"
swc_visit_macros = "=0.3.1"
sha2 = "0.10.2"
models = { path = "../models" }
helpers = { path = "../helpers" }
serde = { version = "1.0", features = ["derive", "rc"] }

View File

@@ -347,8 +347,10 @@ mod fns {
use deno_core::anyhow::{anyhow, bail};
use deno_core::error::AnyError;
use deno_core::*;
use helpers::{to_tmp_path, AtomicFile};
use models::VolumeId;
use serde_json::Value;
use tokio::io::AsyncWriteExt;
use super::{AnswerState, JsContext};
use crate::{system_time_as_unix_ms, MetadataJs};
@@ -514,7 +516,7 @@ mod fns {
bail!("Volume {} is readonly", volume_id);
}
let new_file = volume_path.join(path_in);
let new_file = volume_path.join(&path_in);
let parent_new_file = new_file
.parent()
.ok_or_else(|| anyhow!("Expecting that file is not root"))?;
@@ -526,7 +528,22 @@ mod fns {
volume_path.to_string_lossy(),
);
}
tokio::fs::write(new_file, write).await?;
let new_volume_tmp = to_tmp_path(&volume_path).map_err(|e| anyhow!("{}", e))?;
let hashed_name = {
use sha2::{Digest, Sha256};
use std::os::unix::ffi::OsStrExt;
let mut hasher = Sha256::new();
hasher.update(path_in.as_os_str().as_bytes());
let result = hasher.finalize();
format!("{:X}", result)
};
let temp_file = new_volume_tmp.join(&hashed_name);
let mut file = AtomicFile::new(&new_file, Some(&temp_file))
.await
.map_err(|e| anyhow!("{}", e))?;
file.write_all(write.as_bytes()).await?;
file.save().await.map_err(|e| anyhow!("{}", e))?;
Ok(())
}
#[op]