From 6f176aa623f8301685299598590bc9c89958d1eb Mon Sep 17 00:00:00 2001 From: Roland Sherwin Date: Thu, 5 Dec 2024 03:15:50 +0530 Subject: [PATCH] fix(bootstrap): use rename isntead of persist for atomic write --- Cargo.lock | 1 + ant-bootstrap/Cargo.toml | 3 ++- ant-bootstrap/src/cache_store.rs | 27 +++++++++++++++++++++------ ant-bootstrap/src/error.rs | 2 -- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f5eb4ca627..693d619523 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -734,6 +734,7 @@ dependencies = [ "fs2", "futures", "libp2p 0.54.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.8.5", "reqwest 0.12.9", "serde", "serde_json", diff --git a/ant-bootstrap/Cargo.toml b/ant-bootstrap/Cargo.toml index 51667787cf..5f3b31a06a 100644 --- a/ant-bootstrap/Cargo.toml +++ b/ant-bootstrap/Cargo.toml @@ -21,12 +21,12 @@ dirs-next = "~2.0.0" fs2 = "0.4.3" futures = "0.3.30" libp2p = { version = "0.54.1", features = ["serde"] } +rand = { version = "~0.8.5", features = ["small_rng"] } reqwest = { version = "0.12.2", default-features = false, features = [ "rustls-tls-manual-roots", ] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -tempfile = "3.8.1" thiserror = "1.0" tokio = { version = "1.0", features = ["time"] } tracing = "0.1" @@ -36,6 +36,7 @@ url = "2.4.0" wiremock = "0.5" tokio = { version = "1.0", features = ["full", "test-util"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tempfile = "3.8.1" [target.'cfg(target_arch = "wasm32")'.dependencies] wasmtimer = "0.2.0" \ No newline at end of file diff --git a/ant-bootstrap/src/cache_store.rs b/ant-bootstrap/src/cache_store.rs index cbab845a0a..a4c9a453a2 100644 --- a/ant-bootstrap/src/cache_store.rs +++ b/ant-bootstrap/src/cache_store.rs @@ -14,6 +14,8 @@ use crate::{ use fs2::FileExt; use libp2p::multiaddr::Protocol; use libp2p::{Multiaddr, PeerId}; +use rand::rngs::StdRng; +use rand::{Rng, SeedableRng}; use serde::{Deserialize, Serialize}; use std::collections::hash_map::Entry; use std::collections::HashMap; @@ -21,7 +23,6 @@ use std::fs::{self, File, OpenOptions}; use std::io::{self, Read}; use std::path::PathBuf; use std::time::{Duration, SystemTime}; -use tempfile::NamedTempFile; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CacheData { @@ -430,13 +431,27 @@ impl BootstrapCacheStore { fs::create_dir_all(parent)?; } - // Create a temporary file in the same directory as the cache file - let temp_dir = std::env::temp_dir(); - let temp_file = NamedTempFile::new_in(&temp_dir)?; + // create a random char string for the temp file name + + let mut rng = StdRng::from_entropy(); + let random_string: String = (0..7) + .map(|_| rng.sample(rand::distributions::Alphanumeric) as char) + .collect(); + let temp_file_path = self + .cache_path + .parent() + .ok_or(Error::CouldNotObtainDataDir)? + .join(format!(".cache-{random_string}.tmp")); + + let temp_file = File::create(&temp_file_path)?; // Write data to temporary file serde_json::to_writer_pretty(&temp_file, &self.data)?; + // Ensure the temporary file is closed before renaming + temp_file.sync_all()?; + drop(temp_file); // Explicitly close the file + // Open the target file with proper permissions let file = OpenOptions::new() .write(true) @@ -448,8 +463,8 @@ impl BootstrapCacheStore { Self::acquire_exclusive_lock(&file).await?; // Perform atomic rename - temp_file.persist(&self.cache_path).inspect_err(|err| { - error!("Failed to persist file with err: {err:?}"); + fs::rename(&temp_file_path, &self.cache_path).inspect_err(|err| { + error!("Failed to rename file with err: {err:?}"); })?; info!("Cache written to disk: {:?}", self.cache_path); diff --git a/ant-bootstrap/src/error.rs b/ant-bootstrap/src/error.rs index a8cb8e1cc8..77002702e5 100644 --- a/ant-bootstrap/src/error.rs +++ b/ant-bootstrap/src/error.rs @@ -26,8 +26,6 @@ pub enum Error { Json(#[from] serde_json::Error), #[error("HTTP error: {0}")] Http(#[from] reqwest::Error), - #[error("Persist error: {0}")] - Persist(#[from] tempfile::PersistError), #[error("Lock error")] LockError, }