Skip to content

Commit

Permalink
auto merge of #5023 : mitsuhiko/rust/make-absolute-refactor, r=catamo…
Browse files Browse the repository at this point in the history
…rphism

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.
  • Loading branch information
bors committed Feb 26, 2013
2 parents 44acefd + c77c5c4 commit 0ded562
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 11 deletions.
8 changes: 2 additions & 6 deletions src/libcore/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}


Expand Down
148 changes: 143 additions & 5 deletions src/libcore/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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;
}
}

0 comments on commit 0ded562

Please sign in to comment.