From 573d39c0b5b4fde1e9e2c10ba2e1d85f38dce272 Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Mon, 28 Jul 2025 17:38:08 +0400 Subject: [PATCH] refactor: create lockfile to avoid concurrency issues --- src/template/crg.toml | 1 + src/template/src/main.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/template/crg.toml b/src/template/crg.toml index 0ba0b93..c3cdd57 100644 --- a/src/template/crg.toml +++ b/src/template/crg.toml @@ -8,6 +8,7 @@ anyhow = "1.0" directories = "6" zip = "4" serde_json = "1.0" +fs2 = "0.4" [build-dependencies] # No build dependencies needed - data is embedded at compile time diff --git a/src/template/src/main.rs b/src/template/src/main.rs index 8c37339..0dbe1e9 100644 --- a/src/template/src/main.rs +++ b/src/template/src/main.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use zip::ZipArchive; use directories::BaseDirs; +use fs2::FileExt; // These will be replaced during the build process with actual embedded data // The build script will generate a data.rs file with the actual data @@ -24,12 +25,33 @@ fn main() -> Result<()> { return run_app(&app_dir, &args[1..]); } + // Use file locking to prevent concurrent extraction + let lock_file_path = cache_dir.join(format!("{}.lock", BUILD_ID)); + let lock_file = fs::OpenOptions::new() + .create(true) + .write(true) + .open(&lock_file_path) + .context("Failed to create lock file")?; + + // Acquire exclusive lock + lock_file.lock_exclusive().context("Failed to acquire extraction lock")?; + + // Double-check if extraction completed while waiting for lock + if ready_file.exists() && is_extraction_valid(&app_dir)? { + // Release lock and run + lock_file.unlock().ok(); + return run_app(&app_dir, &args[1..]); + } + // Extract application if needed extract_application(&app_dir)?; // Mark as ready fs::write(&ready_file, "ready")?; + // Release lock + lock_file.unlock().context("Failed to release extraction lock")?; + // Run the application run_app(&app_dir, &args[1..]) } @@ -52,6 +74,11 @@ fn is_extraction_valid(app_dir: &Path) -> Result { } fn extract_application(app_dir: &Path) -> Result<()> { + // Remove existing directory if it exists to ensure clean extraction + if app_dir.exists() { + fs::remove_dir_all(app_dir).context("Failed to remove existing app directory")?; + } + // Create app directory fs::create_dir_all(app_dir).context("Failed to create app directory")?; @@ -75,6 +102,10 @@ fn extract_application(app_dir: &Path) -> Result<()> { let mut outfile = fs::File::create(&outpath).context("Failed to create output file")?; std::io::copy(&mut file, &mut outfile).context("Failed to extract file")?; + // Ensure file is fully written before setting permissions + outfile.sync_all().context("Failed to sync file to disk")?; + drop(outfile); // Explicitly close the file + // Set executable permissions on Unix systems #[cfg(unix)] {