From c7a48e0d3db24b05b7f20ce0000d0fddd03188b7 Mon Sep 17 00:00:00 2001 From: DarkBreakpoint <243206744+DarkBreakpoint@users.noreply.github.com> Date: Fri, 14 Nov 2025 08:38:38 -0600 Subject: [PATCH] =?UTF-8?q?=20FileLockManager=20previously=20keyed=20locks?= =?UTF-8?q?=20by=20the=20raw=20PathBuf=20supplied=20by=20callers,=20so=20t?= =?UTF-8?q?he=20same=20file=20accessed=20via=20different=20relative=20path?= =?UTF-8?q?s=20or=20symlinks=20acquired=20distinct=20locks=E2=80=94allowin?= =?UTF-8?q?g=20concurrent=20writers=20and=20risking=20corruption.=20By=20c?= =?UTF-8?q?anonicalizing/cleaning=20the=20path=20before=20indexing,=20all?= =?UTF-8?q?=20callers=20now=20share=20the=20same=20mutex=20and=20mutual=20?= =?UTF-8?q?exclusion=20is=20preserved.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/utils/file/file_lock_manager.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/backend/src/utils/file/file_lock_manager.rs b/backend/src/utils/file/file_lock_manager.rs index f604641f5..30e23d567 100644 --- a/backend/src/utils/file/file_lock_manager.rs +++ b/backend/src/utils/file/file_lock_manager.rs @@ -1,10 +1,12 @@ use std::collections::HashMap; +use std::env; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{fmt, io}; use tokio::sync::{Mutex, RwLock}; use tokio::sync::{OwnedRwLockReadGuard, OwnedRwLockWriteGuard}; use shared::error::str_to_io_error; +use path_clean::PathClean; #[derive(Clone)] pub struct FileLockManager { @@ -44,14 +46,15 @@ impl FileLockManager { // Helper function: retrieves or creates a lock for a file. async fn get_or_create_lock(&self, path: &Path) -> Arc> { + let normalized_path = normalize_path(path); let mut locks = self.locks.lock().await; - if let Some(lock) = locks.get(path) { + if let Some(lock) = locks.get(&normalized_path) { return lock.clone(); } let file_lock = Arc::new(RwLock::new(())); - locks.insert(path.to_path_buf(), file_lock.clone()); + locks.insert(normalized_path, file_lock.clone()); drop(locks); file_lock } @@ -94,3 +97,17 @@ impl FileWriteGuard { Self { _guard: guard } } } + +fn normalize_path(path: &Path) -> PathBuf { + if let Ok(canonical) = path.canonicalize() { + return canonical; + } + + let base = if path.is_absolute() { + path.to_path_buf() + } else { + env::current_dir().unwrap_or_else(|_| PathBuf::from("./")).join(path) + }; + + base.clean() +}