1
Fork 0

rustc_back: Rewrite realpath to not use old_io

Just bind the relevant platform-specific functions we should probably be calling
anyway.
This commit is contained in:
Alex Crichton 2015-04-09 18:04:11 -07:00
parent bf4e77d4b5
commit 359ab0b56b
3 changed files with 63 additions and 66 deletions

View file

@ -8,70 +8,67 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use libc;
use std::io; use std::io;
use std::env;
#[allow(deprecated)] use std::old_path::{self, GenericPath};
#[allow(deprecated)] use std::old_io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
/// Returns an absolute path in the filesystem that `path` points to. The #[cfg(windows)]
/// returned path does not contain any symlinks in its hierarchy.
#[allow(deprecated)] // readlink is deprecated
pub fn realpath(original: &Path) -> io::Result<PathBuf> { pub fn realpath(original: &Path) -> io::Result<PathBuf> {
let old = old_path::Path::new(original.to_str().unwrap()); use std::fs::File;
match old_realpath(&old) { use std::ffi::OsString;
Ok(p) => Ok(PathBuf::from(p.as_str().unwrap())), use std::os::windows::prelude::*;
Err(e) => Err(io::Error::new(io::ErrorKind::Other, e))
extern "system" {
fn GetFinalPathNameByHandleW(hFile: libc::HANDLE,
lpszFilePath: libc::LPCWSTR,
cchFilePath: libc::DWORD,
dwFlags: libc::DWORD) -> libc::DWORD;
} }
let mut v = Vec::with_capacity(16 * 1024);
let f = try!(File::open(original));
unsafe {
let ret = GetFinalPathNameByHandleW(f.as_raw_handle(),
v.as_mut_ptr(),
v.capacity() as libc::DWORD,
libc::VOLUME_NAME_DOS);
if ret == 0 {
return Err(io::Error::last_os_error())
}
assert!(ret as usize < v.capacit());
v.set_len(ret);
}
Ok(PathBuf::from(OsString::from_wide(&v)))
} }
#[allow(deprecated)] #[cfg(unix)]
fn old_realpath(original: &old_path::Path) -> old_io::IoResult<old_path::Path> { pub fn realpath(original: &Path) -> io::Result<PathBuf> {
use std::old_io::fs; use std::os::unix::prelude::*;
const MAX_LINKS_FOLLOWED: usize = 256; use std::ffi::{OsString, CString};
let original = old_path::Path::new(env::current_dir().unwrap()
.to_str().unwrap()).join(original);
// Right now lstat on windows doesn't work quite well extern {
if cfg!(windows) { fn realpath(pathname: *const libc::c_char, resolved: *mut libc::c_char)
return Ok(original) -> *mut libc::c_char;
} }
let result = original.root_path(); let path = try!(CString::new(original.as_os_str().as_bytes()));
let mut result = result.expect("make_absolute has no root_path"); let mut buf = vec![0u8; 16 * 1024];
let mut followed = 0; unsafe {
let r = realpath(path.as_ptr(), buf.as_mut_ptr() as *mut _);
for part in original.components() { if r.is_null() {
result.push(part); return Err(io::Error::last_os_error())
loop {
if followed == MAX_LINKS_FOLLOWED {
return Err(old_io::standard_error(old_io::InvalidInput))
}
match fs::lstat(&result) {
Err(..) => break,
Ok(ref stat) if stat.kind != old_io::FileType::Symlink => break,
Ok(..) => {
followed += 1;
let path = try!(fs::readlink(&result));
result.pop();
result.push(path);
}
}
} }
} }
let p = buf.iter().position(|i| *i == 0).unwrap();
return Ok(result); buf.truncate(p);
Ok(PathBuf::from(OsString::from_vec(buf)))
} }
#[cfg(all(not(windows), test))] #[cfg(all(not(windows), test))]
mod test { mod test {
use std::old_io; use tempdir::TempDir;
use std::old_io::fs::{File, symlink, mkdir, mkdir_recursive}; use std::fs::{self, File};
use super::old_realpath as realpath; use std::path::{Path, PathBuf};
use std::old_io::TempDir;
use std::old_path::{Path, GenericPath};
#[test] #[test]
fn realpath_works() { fn realpath_works() {
@ -83,15 +80,15 @@ mod test {
let linkdir = tmpdir.join("test3"); let linkdir = tmpdir.join("test3");
File::create(&file).unwrap(); File::create(&file).unwrap();
mkdir(&dir, old_io::USER_RWX).unwrap(); fs::create_dir(&dir).unwrap();
symlink(&file, &link).unwrap(); fs::soft_link(&file, &link).unwrap();
symlink(&dir, &linkdir).unwrap(); fs::soft_link(&dir, &linkdir).unwrap();
assert!(realpath(&tmpdir).unwrap() == tmpdir); assert_eq!(realpath(&tmpdir).unwrap(), tmpdir);
assert!(realpath(&file).unwrap() == file); assert_eq!(realpath(&file).unwrap(), file);
assert!(realpath(&link).unwrap() == file); assert_eq!(realpath(&link).unwrap(), file);
assert!(realpath(&linkdir).unwrap() == dir); assert_eq!(realpath(&linkdir).unwrap(), dir);
assert!(realpath(&linkdir.join("link")).unwrap() == file); assert_eq!(realpath(&linkdir.join("link")).unwrap(), file);
} }
#[test] #[test]
@ -106,13 +103,13 @@ mod test {
let e = d.join("e"); let e = d.join("e");
let f = a.join("f"); let f = a.join("f");
mkdir_recursive(&b, old_io::USER_RWX).unwrap(); fs::create_dir_all(&b).unwrap();
mkdir_recursive(&d, old_io::USER_RWX).unwrap(); fs::create_dir_all(&d).unwrap();
File::create(&f).unwrap(); File::create(&f).unwrap();
symlink(&Path::new("../d/e"), &c).unwrap(); fs::soft_link("../d/e", &c).unwrap();
symlink(&Path::new("../f"), &e).unwrap(); fs::soft_link("../f", &e).unwrap();
assert!(realpath(&c).unwrap() == f); assert_eq!(realpath(&c).unwrap(), f);
assert!(realpath(&e).unwrap() == f); assert_eq!(realpath(&e).unwrap(), f);
} }
} }

View file

@ -35,17 +35,16 @@
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(collections)] #![feature(collections)]
#![feature(core)] #![feature(core)]
#![feature(old_fs)]
#![feature(old_io)]
#![feature(old_path)]
#![feature(rustc_private)] #![feature(rustc_private)]
#![feature(staged_api)] #![feature(staged_api)]
#![feature(rand)] #![feature(rand)]
#![feature(path_ext)] #![feature(path_ext)]
#![feature(step_by)] #![feature(step_by)]
#![feature(libc)]
#![cfg_attr(test, feature(test, rand))] #![cfg_attr(test, feature(test, rand))]
extern crate syntax; extern crate syntax;
extern crate libc;
extern crate serialize; extern crate serialize;
#[macro_use] extern crate log; #[macro_use] extern crate log;

View file

@ -97,8 +97,9 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String
let cwd = env::current_dir().unwrap(); let cwd = env::current_dir().unwrap();
let mut lib = (config.realpath)(&cwd.join(lib)).unwrap(); let mut lib = (config.realpath)(&cwd.join(lib)).unwrap();
lib.pop(); lib.pop();
let mut output = (config.realpath)(&cwd.join(&config.out_filename)).unwrap(); let mut output = cwd.join(&config.out_filename);
output.pop(); output.pop();
let output = (config.realpath)(&output).unwrap();
let relative = path_relative_from(&lib, &output) let relative = path_relative_from(&lib, &output)
.expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib)); .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib));
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths