Skip to content

Commit ea0bd40

Browse files
lilyballalexcrichton
authored andcommitted
path: Implement windows::make_non_verbatim()
make_non_verbatim() takes a WindowsPath and returns a new one that does not use the \\?\ verbatim prefix, if possible.
1 parent af38726 commit ea0bd40

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

src/libstd/path/windows.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,38 @@ pub fn is_verbatim(path: &Path) -> bool {
871871
prefix_is_verbatim(path.prefix)
872872
}
873873

874+
/// Returns the non-verbatim equivalent of the input path, if possible.
875+
/// If the input path is a device namespace path, None is returned.
876+
/// If the input path is not verbatim, it is returned as-is.
877+
/// If the input path is verbatim, but the same path can be expressed as
878+
/// non-verbatim, the non-verbatim version is returned.
879+
/// Otherwise, None is returned.
880+
pub fn make_non_verbatim(path: &Path) -> Option<Path> {
881+
let new_path = match path.prefix {
882+
Some(VerbatimPrefix(_)) | Some(DeviceNSPrefix(_)) => return None,
883+
Some(UNCPrefix(_,_)) | Some(DiskPrefix) | None => return Some(path.clone()),
884+
Some(VerbatimDiskPrefix) => {
885+
// \\?\D:\
886+
Path::new(path.repr.slice_from(4))
887+
}
888+
Some(VerbatimUNCPrefix(_,_)) => {
889+
// \\?\UNC\server\share
890+
Path::new(format!(r"\\{}", path.repr.slice_from(7)))
891+
}
892+
};
893+
if new_path.prefix.is_none() {
894+
// \\?\UNC\server is a VerbatimUNCPrefix
895+
// but \\server is nothing
896+
return None;
897+
}
898+
// now ensure normalization didn't change anything
899+
if path.repr.slice_from(path.prefix_len()) == new_path.repr.slice_from(new_path.prefix_len()) {
900+
Some(new_path)
901+
} else {
902+
None
903+
}
904+
}
905+
874906
/// The standard path separator character
875907
pub static SEP: char = '\\';
876908
/// The standard path separator byte
@@ -2284,4 +2316,38 @@ mod tests {
22842316
t!(s: ".", [b!(".")]);
22852317
// since this is really a wrapper around str_components, those tests suffice
22862318
}
2319+
2320+
#[test]
2321+
fn test_make_non_verbatim() {
2322+
macro_rules! t(
2323+
($path:expr, $exp:expr) => (
2324+
{
2325+
let path = Path::new($path);
2326+
let exp: Option<&str> = $exp;
2327+
let exp = exp.map(|s| Path::new(s));
2328+
assert_eq!(make_non_verbatim(&path), exp);
2329+
}
2330+
)
2331+
)
2332+
2333+
t!(r"\a\b\c", Some(r"\a\b\c"));
2334+
t!(r"a\b\c", Some(r"a\b\c"));
2335+
t!(r"C:\a\b\c", Some(r"C:\a\b\c"));
2336+
t!(r"C:a\b\c", Some(r"C:a\b\c"));
2337+
t!(r"\\server\share\foo", Some(r"\\server\share\foo"));
2338+
t!(r"\\.\foo", None);
2339+
t!(r"\\?\foo", None);
2340+
t!(r"\\?\C:", None);
2341+
t!(r"\\?\C:foo", None);
2342+
t!(r"\\?\C:\", Some(r"C:\"));
2343+
t!(r"\\?\C:\foo", Some(r"C:\foo"));
2344+
t!(r"\\?\C:\foo\bar\baz", Some(r"C:\foo\bar\baz"));
2345+
t!(r"\\?\C:\foo\.\bar\baz", None);
2346+
t!(r"\\?\C:\foo\bar\..\baz", None);
2347+
t!(r"\\?\C:\foo\bar\..", None);
2348+
t!(r"\\?\UNC\server\share\foo", Some(r"\\server\share\foo"));
2349+
t!(r"\\?\UNC\server\share", Some(r"\\server\share"));
2350+
t!(r"\\?\UNC\server", None);
2351+
t!(r"\\?\UNC\server\", None);
2352+
}
22872353
}

0 commit comments

Comments
 (0)