about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-02-26 14:03:52 -0800
committerbors <bors@rust-lang.org>2013-02-26 14:03:52 -0800
commit0ded562e8364244c9c0da1d5f4dc97cd900b4fe4 (patch)
treedf36457cac6b8b3b91ad1ef51fd8811f8a98e7cc /src
parent44acefd1017ae61d71a468961ba8f6131701dee5 (diff)
parentc77c5c4674c92b342132a56bd1b59f86af3d5a63 (diff)
downloadrust-0ded562e8364244c9c0da1d5f4dc97cd900b4fe4.tar.gz
rust-0ded562e8364244c9c0da1d5f4dc97cd900b4fe4.zip
auto merge of #5023 : mitsuhiko/rust/make-absolute-refactor, r=catamorphism
This pull request moves the logic from os::make_absolute() into the path module and fixes path joining for Windows.  It does this by adding an ``unsafe_join()`` function that implements the operating system's path joining semantics.

Additionally it also adds an ``is_restricted()`` method to the trait which will return true if the path points to a windows device file.
Diffstat (limited to 'src')
-rw-r--r--src/libcore/os.rs8
-rw-r--r--src/libcore/path.rs148
2 files changed, 145 insertions, 11 deletions
diff --git a/src/libcore/os.rs b/src/libcore/os.rs
index 8a512da7dc0..9cd5e8f4965 100644
--- a/src/libcore/os.rs
+++ b/src/libcore/os.rs
@@ -566,17 +566,13 @@ pub fn path_exists(p: &Path) -> bool {
  *
  * If the given path is relative, return it prepended with the current working
  * directory. If the given path is already an absolute path, return it
- * as is.
+ * as is.  This is a shortcut for calling os::getcwd().unsafe_join(p)
  */
 // NB: this is here rather than in path because it is a form of environment
 // querying; what it does depends on the process working directory, not just
 // the input paths.
 pub fn make_absolute(p: &Path) -> Path {
-    if p.is_absolute {
-        copy *p
-    } else {
-        getcwd().push_many(p.components)
-    }
+    getcwd().unsafe_join(p)
 }
 
 
diff --git a/src/libcore/path.rs b/src/libcore/path.rs
index 531ce95d067..1753862649f 100644
--- a/src/libcore/path.rs
+++ b/src/libcore/path.rs
@@ -64,6 +64,9 @@ pub trait GenericPath {
     pure fn push_many((&[~str])) -> Self;
     pure fn pop() -> Self;
 
+    pure fn unsafe_join((&Self)) -> Self;
+    pure fn is_restricted() -> bool;
+
     pure fn normalize() -> Self;
 }
 
@@ -485,6 +488,19 @@ impl GenericPath for PosixPath {
         self.push_many(other.components)
     }
 
+    pure fn unsafe_join(other: &PosixPath) -> PosixPath {
+        if other.is_absolute {
+            PosixPath { is_absolute: true,
+                        components: copy other.components }
+        } else {
+            self.push_rel(other)
+        }
+    }
+
+    pure fn is_restricted() -> bool {
+        false
+    }
+
     pure fn push_many(cs: &[~str]) -> PosixPath {
         let mut v = copy self.components;
         for cs.each |e| {
@@ -685,6 +701,61 @@ impl GenericPath for WindowsPath {
         self.push_many(other.components)
     }
 
+    pure fn unsafe_join(other: &WindowsPath) -> WindowsPath {
+        /* rhs not absolute is simple push */
+        if !other.is_absolute {
+            return self.push_many(other.components);
+        }
+
+        /* if rhs has a host set, then the whole thing wins */
+        match other.host {
+            Some(copy host) => {
+                return WindowsPath {
+                    host: Some(host),
+                    device: copy other.device,
+                    is_absolute: true,
+                    components: copy other.components
+                };
+            }
+            _ => {}
+        }
+
+        /* if rhs has a device set, then a part wins */
+        match other.device {
+            Some(copy device) => {
+                return WindowsPath {
+                    host: None,
+                    device: Some(device),
+                    is_absolute: true,
+                    components: copy other.components
+                };
+            }
+            _ => {}
+        }
+
+        /* fallback: host and device of lhs win, but the
+           whole path of the right */
+        WindowsPath {
+            host: copy self.host,
+            device: copy self.device,
+            is_absolute: self.is_absolute || other.is_absolute,
+            components: copy other.components
+        }
+    }
+
+    pure fn is_restricted() -> bool {
+        match self.filestem() {
+            Some(stem) => {
+                match stem.to_lower() {
+                    ~"con" | ~"aux" | ~"com1" | ~"com2" | ~"com3" | ~"com4" |
+                    ~"lpt1" | ~"lpt2" | ~"lpt3" | ~"prn" | ~"nul" => true,
+                    _ => false
+                }
+            },
+            None => false
+        }
+    }
+
     pure fn push_many(cs: &[~str]) -> WindowsPath {
         let mut v = copy self.components;
         for cs.each |e| {
@@ -725,7 +796,10 @@ impl GenericPath for WindowsPath {
     pure fn normalize() -> WindowsPath {
         return WindowsPath {
             host: copy self.host,
-            device: copy self.device,
+            device: match self.device {
+                None => None,
+                Some(ref device) => Some(device.to_upper())
+            },
             is_absolute: self.is_absolute,
             components: normalize(self.components)
         }
@@ -764,13 +838,13 @@ pub mod windows {
 
     pub pure fn extract_unc_prefix(s: &str) -> Option<(~str,~str)> {
         if (s.len() > 1 &&
-            s[0] == '\\' as u8 &&
-            s[1] == '\\' as u8) {
+            (s[0] == '\\' as u8 || s[0] == '/' as u8) &&
+            s[0] == s[1]) {
             let mut i = 2;
             while i < s.len() {
-                if s[i] == '\\' as u8 {
+                if is_sep(s[i]) {
                     let pre = s.slice(2, i);
-                    let rest = s.slice(i, s.len());
+                    let mut rest = s.slice(i, s.len());
                     return Some((pre, rest));
                 }
                 i += 1;
@@ -916,13 +990,21 @@ mod tests {
     #[test]
     fn test_extract_unc_prefixes() {
         assert windows::extract_unc_prefix("\\\\").is_none();
+        assert windows::extract_unc_prefix("//").is_none();
         assert windows::extract_unc_prefix("\\\\hi").is_none();
+        assert windows::extract_unc_prefix("//hi").is_none();
         assert windows::extract_unc_prefix("\\\\hi\\") ==
             Some((~"hi", ~"\\"));
+        assert windows::extract_unc_prefix("//hi\\") ==
+            Some((~"hi", ~"\\"));
         assert windows::extract_unc_prefix("\\\\hi\\there") ==
             Some((~"hi", ~"\\there"));
+        assert windows::extract_unc_prefix("//hi/there") ==
+            Some((~"hi", ~"/there"));
         assert windows::extract_unc_prefix("\\\\hi\\there\\friends.txt") ==
             Some((~"hi", ~"\\there\\friends.txt"));
+        assert windows::extract_unc_prefix("//hi\\there\\friends.txt") ==
+            Some((~"hi", ~"\\there\\friends.txt"));
     }
 
     #[test]
@@ -981,5 +1063,61 @@ mod tests {
             .push_many([~"lib", ~"thingy.dll"])
             .with_filename("librustc.dll")),
           "c:\\program files (x86)\\rust\\lib\\librustc.dll");
+
+        t(&(WindowsPath("\\\\computer\\share")
+            .unsafe_join(&WindowsPath("\\a"))),
+          "\\\\computer\\a");
+
+        t(&(WindowsPath("//computer/share")
+            .unsafe_join(&WindowsPath("\\a"))),
+          "\\\\computer\\a");
+
+        t(&(WindowsPath("//computer/share")
+            .unsafe_join(&WindowsPath("\\\\computer\\share"))),
+          "\\\\computer\\share");
+
+        t(&(WindowsPath("C:/whatever")
+            .unsafe_join(&WindowsPath("//computer/share/a/b"))),
+          "\\\\computer\\share\\a\\b");
+
+        t(&(WindowsPath("C:")
+            .unsafe_join(&WindowsPath("D:/foo"))),
+          "D:\\foo");
+
+        t(&(WindowsPath("C:")
+            .unsafe_join(&WindowsPath("B"))),
+          "C:B");
+
+        t(&(WindowsPath("C:")
+            .unsafe_join(&WindowsPath("/foo"))),
+          "C:\\foo");
+
+        t(&(WindowsPath("C:\\")
+            .unsafe_join(&WindowsPath("\\bar"))),
+          "C:\\bar");
+
+        t(&(WindowsPath("")
+            .unsafe_join(&WindowsPath(""))),
+          "");
+
+        t(&(WindowsPath("")
+            .unsafe_join(&WindowsPath("a"))),
+          "a");
+
+        t(&(WindowsPath("")
+            .unsafe_join(&WindowsPath("C:\\a"))),
+          "C:\\a");
+
+        t(&(WindowsPath("c:\\foo")
+            .normalize()),
+          "C:\\foo");
+    }
+
+    #[test]
+    fn test_windows_path_restrictions() {
+        assert WindowsPath("hi").is_restricted() == false;
+        assert WindowsPath("C:\\NUL").is_restricted() == true;
+        assert WindowsPath("C:\\COM1.TXT").is_restricted() == true;
+        assert WindowsPath("c:\\prn.exe").is_restricted() == true;
     }
 }