From c8d8f6cfec50cad6b35e3b5fc604abc01a26143e Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Mon, 18 Feb 2013 22:48:18 +0000 Subject: [PATCH 1/3] Refactored make_absolute into functionality on the Path --- src/libcore/os.rs | 8 ++------ src/libcore/path.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/libcore/os.rs b/src/libcore/os.rs index 98bac3a49d8a2..8667efb746806 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -565,17 +565,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 531ce95d067be..46f8743ff15fd 100644 --- a/src/libcore/path.rs +++ b/src/libcore/path.rs @@ -64,6 +64,8 @@ pub trait GenericPath { pure fn push_many((&[~str])) -> Self; pure fn pop() -> Self; + pure fn unsafe_join((&Self)) -> Self; + pure fn normalize() -> Self; } @@ -485,6 +487,15 @@ 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 push_many(cs: &[~str]) -> PosixPath { let mut v = copy self.components; for cs.each |e| { @@ -685,6 +696,25 @@ impl GenericPath for WindowsPath { self.push_many(other.components) } + pure fn unsafe_join(other: &WindowsPath) -> WindowsPath { + if !other.is_absolute { + self.push_rel(other) + } else { + WindowsPath { + host: match other.host { + None => copy self.host, + Some(copy x) => Some(x) + }, + device: match other.device { + None => copy self.device, + Some(copy x) => Some(x) + }, + is_absolute: true, + components: copy other.components + } + } + } + pure fn push_many(cs: &[~str]) -> WindowsPath { let mut v = copy self.components; for cs.each |e| { From b07eab5faab16a975df89eae8ea5d7276bc44507 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 19 Feb 2013 01:34:48 +0000 Subject: [PATCH 2/3] Improved windows path handling support --- src/libcore/path.rs | 118 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 100 insertions(+), 18 deletions(-) diff --git a/src/libcore/path.rs b/src/libcore/path.rs index 46f8743ff15fd..96a921cf20bfb 100644 --- a/src/libcore/path.rs +++ b/src/libcore/path.rs @@ -697,21 +697,44 @@ impl GenericPath for WindowsPath { } pure fn unsafe_join(other: &WindowsPath) -> WindowsPath { + /* rhs not absolute is simple push */ if !other.is_absolute { - self.push_rel(other) - } else { - WindowsPath { - host: match other.host { - None => copy self.host, - Some(copy x) => Some(x) - }, - device: match other.device { - None => copy self.device, - Some(copy x) => Some(x) - }, - is_absolute: true, - components: copy other.components + 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 } } @@ -755,7 +778,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) } @@ -794,13 +820,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; @@ -946,13 +972,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] @@ -1011,5 +1045,53 @@ 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"); } } From c77c5c4674c92b342132a56bd1b59f86af3d5a63 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 19 Feb 2013 01:54:05 +0000 Subject: [PATCH 3/3] Added is_restricted() to path --- src/libcore/path.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/libcore/path.rs b/src/libcore/path.rs index 96a921cf20bfb..1753862649f57 100644 --- a/src/libcore/path.rs +++ b/src/libcore/path.rs @@ -65,6 +65,7 @@ pub trait GenericPath { pure fn pop() -> Self; pure fn unsafe_join((&Self)) -> Self; + pure fn is_restricted() -> bool; pure fn normalize() -> Self; } @@ -496,6 +497,10 @@ impl GenericPath for PosixPath { } } + pure fn is_restricted() -> bool { + false + } + pure fn push_many(cs: &[~str]) -> PosixPath { let mut v = copy self.components; for cs.each |e| { @@ -738,6 +743,19 @@ impl GenericPath for WindowsPath { } } + 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| { @@ -1094,4 +1112,12 @@ mod tests { .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; + } }