1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-01 21:47:46 +00:00

Fix realpath and relpath.

I used the new Path/PathBuf/PathExt libraries.
This commit is contained in:
Joseph Crail 2015-05-06 00:14:13 -04:00
parent 5bdd303d68
commit b854a3161a
2 changed files with 39 additions and 36 deletions

View file

@ -1,5 +1,5 @@
#![crate_name= "realpath"]
#![feature(collections, core, old_io, os, old_path, rustc_private)]
#![feature(file_type, path_ext, rustc_private)]
/*
* This file is part of the uutils coreutils package.
@ -13,7 +13,10 @@
extern crate getopts;
extern crate libc;
use getopts::{optflag, getopts, usage};
use getopts::{getopts, optflag, usage};
use std::fs::PathExt;
use std::io::Write;
use std::path::{Path, PathBuf};
#[path = "../common/util.rs"] #[macro_use] mod util;
@ -30,21 +33,21 @@ pub fn uumain(args: Vec<String>) -> i32 {
optflag("q", "quiet", "Do not print warnings for invalid paths"),
];
let opts = match getopts(args.tail(), &options) {
let opts = match getopts(&args[1..], &options) {
Ok(m) => m,
Err(f) => {
show_error!("{}", f);
show_usage(program.as_slice(), &options);
show_usage(program, &options);
return 1
}
};
if opts.opt_present("V") { version(); return 0 }
if opts.opt_present("h") { show_usage(program.as_slice(), &options); return 0 }
if opts.opt_present("h") { show_usage(program, &options); return 0 }
if opts.free.len() == 0 {
show_error!("Missing operand: FILENAME, at least one is required");
println!("Try `{} --help` for more information.", program.as_slice());
println!("Try `{} --help` for more information.", program);
return 1
}
@ -53,7 +56,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
let quiet = opts.opt_present("q");
let mut retcode = 0;
for path in opts.free.iter() {
if !resolve_path(path.as_slice(), strip, zero, quiet) {
if !resolve_path(path, strip, zero, quiet) {
retcode = 1
};
}
@ -61,8 +64,8 @@ pub fn uumain(args: Vec<String>) -> i32 {
}
fn resolve_path(path: &str, strip: bool, zero: bool, quiet: bool) -> bool {
let p = Path::new(path);
let abs = std::os::make_absolute(&p).unwrap();
let p = Path::new(path).to_path_buf();
let abs = p.canonicalize().unwrap();
if strip {
if zero {
@ -73,29 +76,25 @@ fn resolve_path(path: &str, strip: bool, zero: bool, quiet: bool) -> bool {
return true
}
let mut result = match abs.root_path() {
None => crash!(2, "Broken path parse! Report to developers: {}", path),
Some(x) => x,
};
let mut links_left = 256isize;
let mut result = PathBuf::new();
let mut links_left = 256;
for part in abs.components() {
result.push(part);
result.push(part.as_ref());
loop {
if links_left == 0 {
if !quiet { show_error!("Too many symbolic links: {}", path) };
return false
}
match std::old_io::fs::lstat(&result) {
match result.as_path().metadata() {
Err(_) => break,
Ok(ref s) if s.kind != std::old_io::FileType::Symlink => break,
Ok(ref m) if !m.file_type().is_symlink() => break,
Ok(_) => {
links_left -= 1;
match std::old_io::fs::readlink(&result) {
match result.as_path().read_link() {
Ok(x) => {
result.pop();
result.push(x);
result.push(x.as_path());
},
_ => {
if !quiet {

View file

@ -1,5 +1,5 @@
#![crate_name = "relpath"]
#![feature(collections, core, os, old_path, rustc_private)]
#![feature(path_ext, rustc_private)]
/*
* This file is part of the uutils coreutils package.
@ -13,7 +13,11 @@
extern crate getopts;
extern crate libc;
use getopts::{optflag, optopt, getopts, usage};
use getopts::{getopts, optflag, optopt, usage};
use std::env;
use std::fs::PathExt;
use std::io::Write;
use std::path::{Path, PathBuf};
#[path = "../common/util.rs"] #[macro_use] mod util;
@ -28,37 +32,37 @@ pub fn uumain(args: Vec<String>) -> i32 {
optopt("d", "", "If any of FROM and TO is not subpath of DIR, output absolute path instead of relative", "DIR"),
];
let opts = match getopts(args.tail(), &options) {
let opts = match getopts(&args[1..], &options) {
Ok(m) => m,
Err(f) => {
show_error!("{}", f);
show_usage(program.as_slice(), &options);
show_usage(program, &options);
return 1
}
};
if opts.opt_present("V") { version(); return 0 }
if opts.opt_present("h") { show_usage(program.as_slice(), &options); return 0 }
if opts.opt_present("h") { show_usage(program, &options); return 0 }
if opts.free.len() == 0 {
show_error!("Missing operand: TO");
println!("Try `{} --help` for more information.", program.as_slice());
println!("Try `{} --help` for more information.", program);
return 1
}
let to = Path::new(opts.free[0].as_slice());
let to = Path::new(&opts.free[0]);
let from = if opts.free.len() > 1 {
Path::new(opts.free[1].as_slice())
Path::new(&opts.free[1]).to_path_buf()
} else {
std::os::getcwd().unwrap()
env::current_dir().unwrap()
};
let absto = std::os::make_absolute(&to).unwrap();
let absfrom = std::os::make_absolute(&from).unwrap();
let absto = to.canonicalize().unwrap();
let absfrom = from.canonicalize().unwrap();
if opts.opt_present("d") {
let base = Path::new(opts.opt_str("d").unwrap());
let absbase = std::os::make_absolute(&base).unwrap();
if !absbase.is_ancestor_of(&absto) || !absbase.is_ancestor_of(&absfrom) {
let base = Path::new(&opts.opt_str("d").unwrap()).to_path_buf();
let absbase = base.canonicalize().unwrap();
if !absto.as_path().starts_with(absbase.as_path()) || !absfrom.as_path().starts_with(absbase.as_path()) {
println!("{}", absto.display());
return 0
}
@ -73,9 +77,9 @@ pub fn uumain(args: Vec<String>) -> i32 {
}
}
let mut result = Path::new("");
let mut result = PathBuf::new();
absfrom.components().skip(suffix_pos).map(|_| result.push("..")).last();
absto.components().skip(suffix_pos).map(|x| result.push(x)).last();
absto.components().skip(suffix_pos).map(|x| result.push(x.as_ref())).last();
println!("{}", result.display());
0