1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-02 22:17:45 +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"] #![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. * This file is part of the uutils coreutils package.
@ -13,7 +13,10 @@
extern crate getopts; extern crate getopts;
extern crate libc; 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; #[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"), 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, Ok(m) => m,
Err(f) => { Err(f) => {
show_error!("{}", f); show_error!("{}", f);
show_usage(program.as_slice(), &options); show_usage(program, &options);
return 1 return 1
} }
}; };
if opts.opt_present("V") { version(); return 0 } 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 { if opts.free.len() == 0 {
show_error!("Missing operand: FILENAME, at least one is required"); 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 return 1
} }
@ -53,7 +56,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
let quiet = opts.opt_present("q"); let quiet = opts.opt_present("q");
let mut retcode = 0; let mut retcode = 0;
for path in opts.free.iter() { for path in opts.free.iter() {
if !resolve_path(path.as_slice(), strip, zero, quiet) { if !resolve_path(path, strip, zero, quiet) {
retcode = 1 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 { fn resolve_path(path: &str, strip: bool, zero: bool, quiet: bool) -> bool {
let p = Path::new(path); let p = Path::new(path).to_path_buf();
let abs = std::os::make_absolute(&p).unwrap(); let abs = p.canonicalize().unwrap();
if strip { if strip {
if zero { if zero {
@ -73,29 +76,25 @@ fn resolve_path(path: &str, strip: bool, zero: bool, quiet: bool) -> bool {
return true return true
} }
let mut result = match abs.root_path() { let mut result = PathBuf::new();
None => crash!(2, "Broken path parse! Report to developers: {}", path), let mut links_left = 256;
Some(x) => x,
};
let mut links_left = 256isize;
for part in abs.components() { for part in abs.components() {
result.push(part); result.push(part.as_ref());
loop { loop {
if links_left == 0 { if links_left == 0 {
if !quiet { show_error!("Too many symbolic links: {}", path) }; if !quiet { show_error!("Too many symbolic links: {}", path) };
return false return false
} }
match std::old_io::fs::lstat(&result) { match result.as_path().metadata() {
Err(_) => break, 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(_) => { Ok(_) => {
links_left -= 1; links_left -= 1;
match std::old_io::fs::readlink(&result) { match result.as_path().read_link() {
Ok(x) => { Ok(x) => {
result.pop(); result.pop();
result.push(x); result.push(x.as_path());
}, },
_ => { _ => {
if !quiet { if !quiet {

View file

@ -1,5 +1,5 @@
#![crate_name = "relpath"] #![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. * This file is part of the uutils coreutils package.
@ -13,7 +13,11 @@
extern crate getopts; extern crate getopts;
extern crate libc; 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; #[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"), 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, Ok(m) => m,
Err(f) => { Err(f) => {
show_error!("{}", f); show_error!("{}", f);
show_usage(program.as_slice(), &options); show_usage(program, &options);
return 1 return 1
} }
}; };
if opts.opt_present("V") { version(); return 0 } 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 { if opts.free.len() == 0 {
show_error!("Missing operand: TO"); show_error!("Missing operand: TO");
println!("Try `{} --help` for more information.", program.as_slice()); println!("Try `{} --help` for more information.", program);
return 1 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 { let from = if opts.free.len() > 1 {
Path::new(opts.free[1].as_slice()) Path::new(&opts.free[1]).to_path_buf()
} else { } else {
std::os::getcwd().unwrap() env::current_dir().unwrap()
}; };
let absto = std::os::make_absolute(&to).unwrap(); let absto = to.canonicalize().unwrap();
let absfrom = std::os::make_absolute(&from).unwrap(); let absfrom = from.canonicalize().unwrap();
if opts.opt_present("d") { if opts.opt_present("d") {
let base = Path::new(opts.opt_str("d").unwrap()); let base = Path::new(&opts.opt_str("d").unwrap()).to_path_buf();
let absbase = std::os::make_absolute(&base).unwrap(); let absbase = base.canonicalize().unwrap();
if !absbase.is_ancestor_of(&absto) || !absbase.is_ancestor_of(&absfrom) { if !absto.as_path().starts_with(absbase.as_path()) || !absfrom.as_path().starts_with(absbase.as_path()) {
println!("{}", absto.display()); println!("{}", absto.display());
return 0 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(); 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()); println!("{}", result.display());
0 0