about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorKevin Ballard <kevin@sb.org>2014-02-27 00:25:43 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-02-27 21:04:04 -0800
commitea0bd40d9b03542d5b9b5bb8f84fecc274a10b82 (patch)
tree9536eff10ae6ea3606d9e2df76a97c2e5eb2984f /src/libstd
parentaf38726d8e5f9d0cdd6167d0d918bf86138833ce (diff)
downloadrust-ea0bd40d9b03542d5b9b5bb8f84fecc274a10b82.tar.gz
rust-ea0bd40d9b03542d5b9b5bb8f84fecc274a10b82.zip
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.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/path/windows.rs66
1 files changed, 66 insertions, 0 deletions
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<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 @@ mod tests {
         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);
+    }
 }