Notify on opening WSL paths outside of wsl (#40195)
Closes #27340 Release Notes: - N/A --------- Co-authored-by: John Tur <john-tur@outlook.com>
This commit is contained in:
@@ -1087,6 +1087,68 @@ pub fn compare_paths(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct WslPath {
|
||||
pub distro: String,
|
||||
|
||||
// the reason this is an OsString and not any of the path types is that it needs to
|
||||
// represent a unix path (with '/' separators) on windows. `from_path` does this by
|
||||
// manually constructing it from the path components of a given windows path.
|
||||
pub path: std::ffi::OsString,
|
||||
}
|
||||
|
||||
impl WslPath {
|
||||
pub fn from_path<P: AsRef<Path>>(path: P) -> Option<WslPath> {
|
||||
if cfg!(not(target_os = "windows")) {
|
||||
return None;
|
||||
}
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
path::{Component, Prefix},
|
||||
};
|
||||
|
||||
let mut components = path.as_ref().components();
|
||||
let Some(Component::Prefix(prefix)) = components.next() else {
|
||||
return None;
|
||||
};
|
||||
let (server, distro) = match prefix.kind() {
|
||||
Prefix::UNC(server, distro) => (server, distro),
|
||||
Prefix::VerbatimUNC(server, distro) => (server, distro),
|
||||
_ => return None,
|
||||
};
|
||||
let Some(Component::RootDir) = components.next() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let server_str = server.to_string_lossy();
|
||||
if server_str == "wsl.localhost" || server_str == "wsl$" {
|
||||
let mut result = OsString::from("");
|
||||
for c in components {
|
||||
use Component::*;
|
||||
match c {
|
||||
Prefix(p) => unreachable!("got {p:?}, but already stripped prefix"),
|
||||
RootDir => unreachable!("got root dir, but already stripped root"),
|
||||
CurDir => continue,
|
||||
ParentDir => result.push("/.."),
|
||||
Normal(s) => {
|
||||
result.push("/");
|
||||
result.push(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
if result.is_empty() {
|
||||
result.push("/");
|
||||
}
|
||||
Some(WslPath {
|
||||
distro: distro.to_string_lossy().to_string(),
|
||||
path: result,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -1921,4 +1983,45 @@ mod tests {
|
||||
let suffix = Path::new("app.tar.gz");
|
||||
assert_eq!(strip_path_suffix(base, suffix), None);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn test_wsl_path() {
|
||||
use super::WslPath;
|
||||
let path = "/a/b/c";
|
||||
assert_eq!(WslPath::from_path(&path), None);
|
||||
|
||||
let path = r"\\wsl.localhost";
|
||||
assert_eq!(WslPath::from_path(&path), None);
|
||||
|
||||
let path = r"\\wsl.localhost\Distro";
|
||||
assert_eq!(
|
||||
WslPath::from_path(&path),
|
||||
Some(WslPath {
|
||||
distro: "Distro".to_owned(),
|
||||
path: "/".into(),
|
||||
})
|
||||
);
|
||||
|
||||
let path = r"\\wsl.localhost\Distro\blue";
|
||||
assert_eq!(
|
||||
WslPath::from_path(&path),
|
||||
Some(WslPath {
|
||||
distro: "Distro".to_owned(),
|
||||
path: "/blue".into()
|
||||
})
|
||||
);
|
||||
|
||||
let path = r"\\wsl$\archlinux\tomato\.\paprika\..\aubergine.txt";
|
||||
assert_eq!(
|
||||
WslPath::from_path(&path),
|
||||
Some(WslPath {
|
||||
distro: "archlinux".to_owned(),
|
||||
path: "/tomato/paprika/../aubergine.txt".into()
|
||||
})
|
||||
);
|
||||
|
||||
let path = r"\\windows.localhost\Distro\foo";
|
||||
assert_eq!(WslPath::from_path(&path), None);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user