]> git.lizzy.rs Git - rust.git/commitdiff
path: Implement windows::make_non_verbatim()
authorKevin Ballard <kevin@sb.org>
Thu, 27 Feb 2014 08:25:43 +0000 (00:25 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 28 Feb 2014 05:04:04 +0000 (21:04 -0800)
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

index bf437875b844985f4023238f08cbe571ba31324e..864cdebe1a0909f093f8cf19f612291c426d2047 100644 (file)
@@ -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<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
 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);
+    }
 }