Skip to content

Commit 3690dc0

Browse files
committed
rustc: Add a realpath utility function
This is required in rustc to resolve symlinks for utilities such as the sysroot and the rpath values which are encoded into binaries.
1 parent 83ae17d commit 3690dc0

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

src/librustc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ pub mod util {
127127
pub mod ppaux;
128128
pub mod sha2;
129129
pub mod nodemap;
130+
pub mod fs;
130131
}
131132

132133
pub mod lib {

src/librustc/util/fs.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::io;
12+
use std::io::fs;
13+
use std::os;
14+
15+
/// Returns an absolute path in the filesystem that `path` points to. The
16+
/// returned path does not contain any symlinks in its hierarchy.
17+
pub fn realpath(original: &Path) -> io::IoResult<Path> {
18+
static MAX_LINKS_FOLLOWED: uint = 256;
19+
let original = os::make_absolute(original);
20+
21+
// Right now lstat on windows doesn't work quite well
22+
if cfg!(windows) {
23+
return Ok(original)
24+
}
25+
26+
let result = original.root_path();
27+
let mut result = result.expect("make_absolute has no root_path");
28+
let mut followed = 0;
29+
30+
for part in original.components() {
31+
result.push(part);
32+
33+
loop {
34+
if followed == MAX_LINKS_FOLLOWED {
35+
return Err(io::standard_error(io::InvalidInput))
36+
}
37+
38+
match fs::lstat(&result) {
39+
Err(..) => break,
40+
Ok(ref stat) if stat.kind != io::TypeSymlink => break,
41+
Ok(..) => {
42+
followed += 1;
43+
let path = try!(fs::readlink(&result));
44+
result.pop();
45+
result.push(path);
46+
}
47+
}
48+
}
49+
}
50+
51+
return Ok(result);
52+
}
53+
54+
#[cfg(not(windows), test)]
55+
mod test {
56+
use std::io;
57+
use std::io::fs::{File, symlink, mkdir, mkdir_recursive};
58+
use super::realpath;
59+
use std::io::TempDir;
60+
61+
#[test]
62+
fn realpath_works() {
63+
let tmpdir = TempDir::new("rustc-fs").unwrap();
64+
let tmpdir = realpath(tmpdir.path()).unwrap();
65+
let file = tmpdir.join("test");
66+
let dir = tmpdir.join("test2");
67+
let link = dir.join("link");
68+
let linkdir = tmpdir.join("test3");
69+
70+
File::create(&file).unwrap();
71+
mkdir(&dir, io::UserRWX).unwrap();
72+
symlink(&file, &link).unwrap();
73+
symlink(&dir, &linkdir).unwrap();
74+
75+
assert!(realpath(&tmpdir).unwrap() == tmpdir);
76+
assert!(realpath(&file).unwrap() == file);
77+
assert!(realpath(&link).unwrap() == file);
78+
assert!(realpath(&linkdir).unwrap() == dir);
79+
assert!(realpath(&linkdir.join("link")).unwrap() == file);
80+
}
81+
82+
#[test]
83+
fn realpath_works_tricky() {
84+
let tmpdir = TempDir::new("rustc-fs").unwrap();
85+
let tmpdir = realpath(tmpdir.path()).unwrap();
86+
87+
let a = tmpdir.join("a");
88+
let b = a.join("b");
89+
let c = b.join("c");
90+
let d = a.join("d");
91+
let e = d.join("e");
92+
let f = a.join("f");
93+
94+
mkdir_recursive(&b, io::UserRWX).unwrap();
95+
mkdir_recursive(&d, io::UserRWX).unwrap();
96+
File::create(&f).unwrap();
97+
symlink(&Path::new("../d/e"), &c).unwrap();
98+
symlink(&Path::new("../f"), &e).unwrap();
99+
100+
assert!(realpath(&c).unwrap() == f);
101+
assert!(realpath(&e).unwrap() == f);
102+
}
103+
}

0 commit comments

Comments
 (0)