From 0d0a08203f37c152243502756b256cd5e3554f2b Mon Sep 17 00:00:00 2001 From: localcc Date: Wed, 17 Dec 2025 20:55:36 +0100 Subject: [PATCH] Fix windows path canonicalization (#45145) Closes #44962 Release Notes: - N/A --- crates/fs/src/fs.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/crates/fs/src/fs.rs b/crates/fs/src/fs.rs index e6f69a14593a0246ae8ccb4aa4673f4e1f5a1e8e..2cbbf61a21e145464e9dbec01ace3b5510709d0d 100644 --- a/crates/fs/src/fs.rs +++ b/crates/fs/src/fs.rs @@ -434,7 +434,18 @@ impl RealFs { for component in path.components() { match component { std::path::Component::Prefix(_) => { - let canonicalized = std::fs::canonicalize(component)?; + let component = component.as_os_str(); + let canonicalized = if component + .to_str() + .map(|e| e.ends_with("\\")) + .unwrap_or(false) + { + std::fs::canonicalize(component) + } else { + let mut component = component.to_os_string(); + component.push("\\"); + std::fs::canonicalize(component) + }?; let mut strip = PathBuf::new(); for component in canonicalized.components() { @@ -3394,6 +3405,26 @@ mod tests { assert_eq!(content, "Hello"); } + #[gpui::test] + #[cfg(target_os = "windows")] + async fn test_realfs_canonicalize(executor: BackgroundExecutor) { + use util::paths::SanitizedPath; + + let fs = RealFs { + bundled_git_binary_path: None, + executor, + next_job_id: Arc::new(AtomicUsize::new(0)), + job_event_subscribers: Arc::new(Mutex::new(Vec::new())), + }; + let temp_dir = TempDir::new().unwrap(); + let file = temp_dir.path().join("test (1).txt"); + let file = SanitizedPath::new(&file); + std::fs::write(&file, "test").unwrap(); + + let canonicalized = fs.canonicalize(file.as_path()).await; + assert!(canonicalized.is_ok()); + } + #[gpui::test] async fn test_rename(executor: BackgroundExecutor) { let fs = FakeFs::new(executor.clone());