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.
This commit is contained in:
Kevin Ballard 2014-02-27 00:25:43 -08:00 committed by Alex Crichton
parent af38726d8e
commit ea0bd40d9b

View File

@ -871,6 +871,38 @@ pub fn is_verbatim(path: &Path) -> bool {
prefix_is_verbatim(path.prefix) prefix_is_verbatim(path.prefix)
} }
/// Returns the non-verbatim equivalent of the input path, if possible.
/// If the input path is a device namespace path, None is returned.
/// If the input path is not verbatim, it is returned as-is.
/// If the input path is verbatim, but the same path can be expressed as
/// non-verbatim, the non-verbatim version is returned.
/// Otherwise, None is returned.
pub fn make_non_verbatim(path: &Path) -> Option<Path> {
let new_path = match path.prefix {
Some(VerbatimPrefix(_)) | Some(DeviceNSPrefix(_)) => return None,
Some(UNCPrefix(_,_)) | Some(DiskPrefix) | None => return Some(path.clone()),
Some(VerbatimDiskPrefix) => {
// \\?\D:\
Path::new(path.repr.slice_from(4))
}
Some(VerbatimUNCPrefix(_,_)) => {
// \\?\UNC\server\share
Path::new(format!(r"\\{}", path.repr.slice_from(7)))
}
};
if new_path.prefix.is_none() {
// \\?\UNC\server is a VerbatimUNCPrefix
// but \\server is nothing
return None;
}
// now ensure normalization didn't change anything
if path.repr.slice_from(path.prefix_len()) == new_path.repr.slice_from(new_path.prefix_len()) {
Some(new_path)
} else {
None
}
}
/// The standard path separator character /// The standard path separator character
pub static SEP: char = '\\'; pub static SEP: char = '\\';
/// The standard path separator byte /// The standard path separator byte
@ -2284,4 +2316,38 @@ macro_rules! t(
t!(s: ".", [b!(".")]); t!(s: ".", [b!(".")]);
// since this is really a wrapper around str_components, those tests suffice // since this is really a wrapper around str_components, those tests suffice
} }
#[test]
fn test_make_non_verbatim() {
macro_rules! t(
($path:expr, $exp:expr) => (
{
let path = Path::new($path);
let exp: Option<&str> = $exp;
let exp = exp.map(|s| Path::new(s));
assert_eq!(make_non_verbatim(&path), exp);
}
)
)
t!(r"\a\b\c", Some(r"\a\b\c"));
t!(r"a\b\c", Some(r"a\b\c"));
t!(r"C:\a\b\c", Some(r"C:\a\b\c"));
t!(r"C:a\b\c", Some(r"C:a\b\c"));
t!(r"\\server\share\foo", Some(r"\\server\share\foo"));
t!(r"\\.\foo", None);
t!(r"\\?\foo", None);
t!(r"\\?\C:", None);
t!(r"\\?\C:foo", None);
t!(r"\\?\C:\", Some(r"C:\"));
t!(r"\\?\C:\foo", Some(r"C:\foo"));
t!(r"\\?\C:\foo\bar\baz", Some(r"C:\foo\bar\baz"));
t!(r"\\?\C:\foo\.\bar\baz", None);
t!(r"\\?\C:\foo\bar\..\baz", None);
t!(r"\\?\C:\foo\bar\..", None);
t!(r"\\?\UNC\server\share\foo", Some(r"\\server\share\foo"));
t!(r"\\?\UNC\server\share", Some(r"\\server\share"));
t!(r"\\?\UNC\server", None);
t!(r"\\?\UNC\server\", None);
}
} }