From ea0bd40d9b03542d5b9b5bb8f84fecc274a10b82 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Thu, 27 Feb 2014 00:25:43 -0800 Subject: [PATCH] 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. --- src/libstd/path/windows.rs | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index bf437875b84..864cdebe1a0 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -871,6 +871,38 @@ pub fn is_verbatim(path: &Path) -> bool { 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 { + 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 pub static SEP: char = '\\'; /// The standard path separator byte @@ -2284,4 +2316,38 @@ macro_rules! t( t!(s: ".", [b!(".")]); // 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); + } }