From d63babff0aa113684de505e3af6bb9c11418c46b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 11 Oct 2024 21:42:55 +0200 Subject: [PATCH] Assure that `Project::path` can be compared reasonably with other paths (#5096) When testing paths for prefix-matches it's important they are all normalized in the same fashion. `canonicalize()` is very particular about canonicalizing Windows paths, which makes it easy for these paths to not be compatible to other absolute-looking paths. The difficulty here is to get the right trade-off between performance and safety, e.g. we wouldn't want these canonicalized Windows paths to be used anywhere as they are very uncommon (and don't even work everywhere). --- crates/gitbutler-project/src/controller.rs | 2 +- crates/gitbutler-repo/src/commands.rs | 33 +++++++++++----------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/crates/gitbutler-project/src/controller.rs b/crates/gitbutler-project/src/controller.rs index 3a0350192c..755d7f63a1 100644 --- a/crates/gitbutler-project/src/controller.rs +++ b/crates/gitbutler-project/src/controller.rs @@ -72,7 +72,7 @@ impl Controller { let project = Project { id: ProjectId::generate(), title, - path: path.to_path_buf(), + path: gix::path::realpath(path)?, api: None, ..Default::default() }; diff --git a/crates/gitbutler-repo/src/commands.rs b/crates/gitbutler-repo/src/commands.rs index a1d6134489..25741ef75e 100644 --- a/crates/gitbutler-repo/src/commands.rs +++ b/crates/gitbutler-repo/src/commands.rs @@ -49,25 +49,24 @@ impl RepoCommands for Project { fn read_file_from_workspace(&self, relative_path: &Path) -> Result { let ctx = CommandContext::open(self)?; - if self - .path - .join(relative_path) - .canonicalize()? - .as_path() - .starts_with(self.path.clone()) - { - let tree = ctx.repository().head()?.peel_to_tree()?; - let entry = tree.get_path(relative_path)?; - let blob = ctx.repository().find_blob(entry.id())?; + let path_in_worktree = gix::path::realpath(self.path.join(relative_path))?; + if !path_in_worktree.starts_with(self.path.clone()) { + anyhow::bail!( + "Path to read from at '{}' isn't in the worktree directory '{}'", + relative_path.display(), + self.path.display() + ); + } + + let tree = ctx.repository().head()?.peel_to_tree()?; + let entry = tree.get_path(relative_path)?; + let blob = ctx.repository().find_blob(entry.id())?; - if !blob.is_binary() { - let content = std::str::from_utf8(blob.content())?; - Ok(content.to_string()) - } else { - anyhow::bail!("File is binary"); - } + if !blob.is_binary() { + let content = std::str::from_utf8(blob.content())?; + Ok(content.to_string()) } else { - anyhow::bail!("Invalid workspace file"); + anyhow::bail!("File is binary"); } } }