Better absolute path handling (#19727)
Closes #19866 This PR supersedes #19228, as #19228 encountered too many merge conflicts. After some exploration, I found that for paths with the `\\?\` prefix, we can safely remove it and consistently use the clean paths in all cases. Previously, in #19228, I thought we would still need the `\\?\` prefix for IO operations to handle long paths better. However, this turns out to be unnecessary because Rust automatically manages this for us when calling IO-related APIs. For details, refer to Rust's internal function [`get_long_path`](017ae1b21f/library/std/src/sys/path/windows.rs (L225-L233)
). Therefore, we can always store and use paths without the `\\?\` prefix. This PR introduces a `SanitizedPath` structure, which represents a path stripped of the `\\?\` prefix. To prevent untrimmed paths from being mistakenly passed into `Worktree`, the type of `Worktree`’s `abs_path` member variable has been changed to `SanitizedPath`. Additionally, this PR reverts the changes of #15856 and #18726. After testing, it appears that the issues those PRs addressed can be resolved by this PR. ### Existing Issue To keep the scope of modifications manageable, `Worktree::abs_path` has retained its current signature as `fn abs_path(&self) -> Arc<Path>`, rather than returning a `SanitizedPath`. Updating the method to return `SanitizedPath`—which may better resolve path inconsistencies—would likely introduce extensive changes similar to those in #19228. Currently, the limitation is as follows: ```rust let abs_path: &Arc<Path> = snapshot.abs_path(); let some_non_trimmed_path = Path::new("\\\\?\\C:\\Users\\user\\Desktop\\project"); // The caller performs some actions here: some_non_trimmed_path.strip_prefix(abs_path); // This fails some_non_trimmed_path.starts_with(abs_path); // This fails too ``` The final two lines will fail because `snapshot.abs_path()` returns a clean path without the `\\?\` prefix. I have identified two relevant instances that may face this issue: - [lsp_store.rs#L3578](0173479d18/crates/project/src/lsp_store.rs (L3578)
) - [worktree.rs#L4338](0173479d18/crates/worktree/src/worktree.rs (L4338)
) Switching `Worktree::abs_path` to return `SanitizedPath` would resolve these issues but would also lead to many code changes. Any suggestions or feedback on this approach are very welcome. cc @SomeoneToIgnore Release Notes: - N/A
This commit is contained in:
parent
d0bafce86b
commit
cff9ae0bbc
12 changed files with 189 additions and 113 deletions
|
@ -452,18 +452,16 @@ impl Fs for RealFs {
|
|||
|
||||
#[cfg(target_os = "windows")]
|
||||
async fn trash_file(&self, path: &Path, _options: RemoveOptions) -> Result<()> {
|
||||
use util::paths::SanitizedPath;
|
||||
use windows::{
|
||||
core::HSTRING,
|
||||
Storage::{StorageDeleteOption, StorageFile},
|
||||
};
|
||||
// todo(windows)
|
||||
// When new version of `windows-rs` release, make this operation `async`
|
||||
let path = path.canonicalize()?.to_string_lossy().to_string();
|
||||
let path_str = path.trim_start_matches("\\\\?\\");
|
||||
if path_str.is_empty() {
|
||||
anyhow::bail!("File path is empty!");
|
||||
}
|
||||
let file = StorageFile::GetFileFromPathAsync(&HSTRING::from(path_str))?.get()?;
|
||||
let path = SanitizedPath::from(path.canonicalize()?);
|
||||
let path_string = path.to_string();
|
||||
let file = StorageFile::GetFileFromPathAsync(&HSTRING::from(path_string))?.get()?;
|
||||
file.DeleteAsync(StorageDeleteOption::Default)?.get()?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -480,19 +478,17 @@ impl Fs for RealFs {
|
|||
|
||||
#[cfg(target_os = "windows")]
|
||||
async fn trash_dir(&self, path: &Path, _options: RemoveOptions) -> Result<()> {
|
||||
use util::paths::SanitizedPath;
|
||||
use windows::{
|
||||
core::HSTRING,
|
||||
Storage::{StorageDeleteOption, StorageFolder},
|
||||
};
|
||||
|
||||
let path = path.canonicalize()?.to_string_lossy().to_string();
|
||||
let path_str = path.trim_start_matches("\\\\?\\");
|
||||
if path_str.is_empty() {
|
||||
anyhow::bail!("Folder path is empty!");
|
||||
}
|
||||
// todo(windows)
|
||||
// When new version of `windows-rs` release, make this operation `async`
|
||||
let folder = StorageFolder::GetFolderFromPathAsync(&HSTRING::from(path_str))?.get()?;
|
||||
let path = SanitizedPath::from(path.canonicalize()?);
|
||||
let path_string = path.to_string();
|
||||
let folder = StorageFolder::GetFolderFromPathAsync(&HSTRING::from(path_string))?.get()?;
|
||||
folder.DeleteAsync(StorageDeleteOption::Default)?.get()?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue