Skip to content

Commit 0ded562

Browse files
committed
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.
2 parents 44acefd + c77c5c4 commit 0ded562

File tree

2 files changed

+145
-11
lines changed

2 files changed

+145
-11
lines changed

src/libcore/os.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -566,17 +566,13 @@ pub fn path_exists(p: &Path) -> bool {
566566
*
567567
* If the given path is relative, return it prepended with the current working
568568
* directory. If the given path is already an absolute path, return it
569-
* as is.
569+
* as is. This is a shortcut for calling os::getcwd().unsafe_join(p)
570570
*/
571571
// NB: this is here rather than in path because it is a form of environment
572572
// querying; what it does depends on the process working directory, not just
573573
// the input paths.
574574
pub fn make_absolute(p: &Path) -> Path {
575-
if p.is_absolute {
576-
copy *p
577-
} else {
578-
getcwd().push_many(p.components)
579-
}
575+
getcwd().unsafe_join(p)
580576
}
581577

582578

src/libcore/path.rs

+143-5
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ pub trait GenericPath {
6464
pure fn push_many((&[~str])) -> Self;
6565
pure fn pop() -> Self;
6666

67+
pure fn unsafe_join((&Self)) -> Self;
68+
pure fn is_restricted() -> bool;
69+
6770
pure fn normalize() -> Self;
6871
}
6972

@@ -485,6 +488,19 @@ impl GenericPath for PosixPath {
485488
self.push_many(other.components)
486489
}
487490

491+
pure fn unsafe_join(other: &PosixPath) -> PosixPath {
492+
if other.is_absolute {
493+
PosixPath { is_absolute: true,
494+
components: copy other.components }
495+
} else {
496+
self.push_rel(other)
497+
}
498+
}
499+
500+
pure fn is_restricted() -> bool {
501+
false
502+
}
503+
488504
pure fn push_many(cs: &[~str]) -> PosixPath {
489505
let mut v = copy self.components;
490506
for cs.each |e| {
@@ -685,6 +701,61 @@ impl GenericPath for WindowsPath {
685701
self.push_many(other.components)
686702
}
687703

704+
pure fn unsafe_join(other: &WindowsPath) -> WindowsPath {
705+
/* rhs not absolute is simple push */
706+
if !other.is_absolute {
707+
return self.push_many(other.components);
708+
}
709+
710+
/* if rhs has a host set, then the whole thing wins */
711+
match other.host {
712+
Some(copy host) => {
713+
return WindowsPath {
714+
host: Some(host),
715+
device: copy other.device,
716+
is_absolute: true,
717+
components: copy other.components
718+
};
719+
}
720+
_ => {}
721+
}
722+
723+
/* if rhs has a device set, then a part wins */
724+
match other.device {
725+
Some(copy device) => {
726+
return WindowsPath {
727+
host: None,
728+
device: Some(device),
729+
is_absolute: true,
730+
components: copy other.components
731+
};
732+
}
733+
_ => {}
734+
}
735+
736+
/* fallback: host and device of lhs win, but the
737+
whole path of the right */
738+
WindowsPath {
739+
host: copy self.host,
740+
device: copy self.device,
741+
is_absolute: self.is_absolute || other.is_absolute,
742+
components: copy other.components
743+
}
744+
}
745+
746+
pure fn is_restricted() -> bool {
747+
match self.filestem() {
748+
Some(stem) => {
749+
match stem.to_lower() {
750+
~"con" | ~"aux" | ~"com1" | ~"com2" | ~"com3" | ~"com4" |
751+
~"lpt1" | ~"lpt2" | ~"lpt3" | ~"prn" | ~"nul" => true,
752+
_ => false
753+
}
754+
},
755+
None => false
756+
}
757+
}
758+
688759
pure fn push_many(cs: &[~str]) -> WindowsPath {
689760
let mut v = copy self.components;
690761
for cs.each |e| {
@@ -725,7 +796,10 @@ impl GenericPath for WindowsPath {
725796
pure fn normalize() -> WindowsPath {
726797
return WindowsPath {
727798
host: copy self.host,
728-
device: copy self.device,
799+
device: match self.device {
800+
None => None,
801+
Some(ref device) => Some(device.to_upper())
802+
},
729803
is_absolute: self.is_absolute,
730804
components: normalize(self.components)
731805
}
@@ -764,13 +838,13 @@ pub mod windows {
764838
765839
pub pure fn extract_unc_prefix(s: &str) -> Option<(~str,~str)> {
766840
if (s.len() > 1 &&
767-
s[0] == '\\' as u8 &&
768-
s[1] == '\\' as u8) {
841+
(s[0] == '\\' as u8 || s[0] == '/' as u8) &&
842+
s[0] == s[1]) {
769843
let mut i = 2;
770844
while i < s.len() {
771-
if s[i] == '\\' as u8 {
845+
if is_sep(s[i]) {
772846
let pre = s.slice(2, i);
773-
let rest = s.slice(i, s.len());
847+
let mut rest = s.slice(i, s.len());
774848
return Some((pre, rest));
775849
}
776850
i += 1;
@@ -916,13 +990,21 @@ mod tests {
916990
#[test]
917991
fn test_extract_unc_prefixes() {
918992
assert windows::extract_unc_prefix("\\\\").is_none();
993+
assert windows::extract_unc_prefix("//").is_none();
919994
assert windows::extract_unc_prefix("\\\\hi").is_none();
995+
assert windows::extract_unc_prefix("//hi").is_none();
920996
assert windows::extract_unc_prefix("\\\\hi\\") ==
921997
Some((~"hi", ~"\\"));
998+
assert windows::extract_unc_prefix("//hi\\") ==
999+
Some((~"hi", ~"\\"));
9221000
assert windows::extract_unc_prefix("\\\\hi\\there") ==
9231001
Some((~"hi", ~"\\there"));
1002+
assert windows::extract_unc_prefix("//hi/there") ==
1003+
Some((~"hi", ~"/there"));
9241004
assert windows::extract_unc_prefix("\\\\hi\\there\\friends.txt") ==
9251005
Some((~"hi", ~"\\there\\friends.txt"));
1006+
assert windows::extract_unc_prefix("//hi\\there\\friends.txt") ==
1007+
Some((~"hi", ~"\\there\\friends.txt"));
9261008
}
9271009

9281010
#[test]
@@ -981,5 +1063,61 @@ mod tests {
9811063
.push_many([~"lib", ~"thingy.dll"])
9821064
.with_filename("librustc.dll")),
9831065
"c:\\program files (x86)\\rust\\lib\\librustc.dll");
1066+
1067+
t(&(WindowsPath("\\\\computer\\share")
1068+
.unsafe_join(&WindowsPath("\\a"))),
1069+
"\\\\computer\\a");
1070+
1071+
t(&(WindowsPath("//computer/share")
1072+
.unsafe_join(&WindowsPath("\\a"))),
1073+
"\\\\computer\\a");
1074+
1075+
t(&(WindowsPath("//computer/share")
1076+
.unsafe_join(&WindowsPath("\\\\computer\\share"))),
1077+
"\\\\computer\\share");
1078+
1079+
t(&(WindowsPath("C:/whatever")
1080+
.unsafe_join(&WindowsPath("//computer/share/a/b"))),
1081+
"\\\\computer\\share\\a\\b");
1082+
1083+
t(&(WindowsPath("C:")
1084+
.unsafe_join(&WindowsPath("D:/foo"))),
1085+
"D:\\foo");
1086+
1087+
t(&(WindowsPath("C:")
1088+
.unsafe_join(&WindowsPath("B"))),
1089+
"C:B");
1090+
1091+
t(&(WindowsPath("C:")
1092+
.unsafe_join(&WindowsPath("/foo"))),
1093+
"C:\\foo");
1094+
1095+
t(&(WindowsPath("C:\\")
1096+
.unsafe_join(&WindowsPath("\\bar"))),
1097+
"C:\\bar");
1098+
1099+
t(&(WindowsPath("")
1100+
.unsafe_join(&WindowsPath(""))),
1101+
"");
1102+
1103+
t(&(WindowsPath("")
1104+
.unsafe_join(&WindowsPath("a"))),
1105+
"a");
1106+
1107+
t(&(WindowsPath("")
1108+
.unsafe_join(&WindowsPath("C:\\a"))),
1109+
"C:\\a");
1110+
1111+
t(&(WindowsPath("c:\\foo")
1112+
.normalize()),
1113+
"C:\\foo");
1114+
}
1115+
1116+
#[test]
1117+
fn test_windows_path_restrictions() {
1118+
assert WindowsPath("hi").is_restricted() == false;
1119+
assert WindowsPath("C:\\NUL").is_restricted() == true;
1120+
assert WindowsPath("C:\\COM1.TXT").is_restricted() == true;
1121+
assert WindowsPath("c:\\prn.exe").is_restricted() == true;
9841122
}
9851123
}

0 commit comments

Comments
 (0)