From 4a331897cbe259fce32cf35a7ea68bdd1229cb06 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Fri, 31 Jul 2015 17:05:22 -0400 Subject: [PATCH 1/2] Replace unstable VecMap w/ external crate. --- deps/Cargo.toml | 1 + src/tr/deps.mk | 2 +- src/tr/tr.rs | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/deps/Cargo.toml b/deps/Cargo.toml index 2851d83a3..9607091c3 100644 --- a/deps/Cargo.toml +++ b/deps/Cargo.toml @@ -10,6 +10,7 @@ libc = "0.1.8" getopts = "0.2.11" bit-vec = "0.4.0" bit-set = "0.2.0" +vec_map = "0.3.0" num_cpus = "*" rand = "0.3.8" regex = "0.1.38" diff --git a/src/tr/deps.mk b/src/tr/deps.mk index 556049c9b..5e9f37b70 100644 --- a/src/tr/deps.mk +++ b/src/tr/deps.mk @@ -1 +1 @@ -DEPLIBS += bit-vec bit-set +DEPLIBS += bit-vec bit-set vec_map diff --git a/src/tr/tr.rs b/src/tr/tr.rs index 557ae1058..a95fc9460 100644 --- a/src/tr/tr.rs +++ b/src/tr/tr.rs @@ -1,5 +1,5 @@ #![crate_name = "tr"] -#![feature(io, vecmap)] +#![feature(io)] /* * This file is part of the uutils coreutils package. @@ -14,11 +14,12 @@ extern crate bit_set; extern crate getopts; +extern crate vec_map; use bit_set::BitSet; use getopts::Options; -use std::collections::VecMap; use std::io::{stdin, stdout, BufReader, Read, Write}; +use vec_map::VecMap; use expand::ExpandSet; From b089831ea0931816a11865304c535a25fb411d1b Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Fri, 31 Jul 2015 18:37:50 -0400 Subject: [PATCH 2/2] Switch over to internal canonicalize(). The method, fs::canonicalize(), is unstable and can't be used for stable builds. We already have our own implementation of canonicalize(), which supports more options than the Rust library implementation. --- src/common/filesystem.rs | 113 ++++++++++++++++++++++++++++++++-- src/cp/cp.rs | 7 +-- src/readlink/readlink.rs | 128 +++++---------------------------------- src/realpath/realpath.rs | 12 +++- src/relpath/relpath.rs | 17 ++++-- src/stdbuf/stdbuf.rs | 7 +-- 6 files changed, 150 insertions(+), 134 deletions(-) diff --git a/src/common/filesystem.rs b/src/common/filesystem.rs index 44f192222..e00aa34b8 100644 --- a/src/common/filesystem.rs +++ b/src/common/filesystem.rs @@ -12,15 +12,16 @@ // be backported to stable (<= 1.1). This will likely be dropped // when the path trait stabilizes. +use std::env; use std::fs; -use std::io; -use std::path::Path; +use std::io::{Error, ErrorKind, Result}; +use std::path::{Component, Path, PathBuf}; pub trait UUPathExt { fn uu_exists(&self) -> bool; fn uu_is_file(&self) -> bool; fn uu_is_dir(&self) -> bool; - fn uu_metadata(&self) -> io::Result; + fn uu_metadata(&self) -> Result; } impl UUPathExt for Path { @@ -36,7 +37,111 @@ impl UUPathExt for Path { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } - fn uu_metadata(&self) -> io::Result { + fn uu_metadata(&self) -> Result { fs::metadata(self) } } + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[allow(dead_code)] +pub enum CanonicalizeMode { + None, + Normal, + Existing, + Missing, +} + +#[allow(dead_code)] +fn resolve>(original: P) -> Result { + const MAX_LINKS_FOLLOWED: u32 = 255; + let mut followed = 0; + let mut result = original.as_ref().to_path_buf(); + loop { + if followed == MAX_LINKS_FOLLOWED { + return Err(Error::new(ErrorKind::InvalidInput, "maximum links followed")); + } + + match fs::metadata(&result) { + Err(e) => return Err(e), + Ok(ref m) if !m.file_type().is_symlink() => break, + Ok(..) => { + followed += 1; + match fs::read_link(&result) { + Ok(path) => { + result.pop(); + result.push(path); + }, + Err(e) => { + return Err(e); + } + } + } + } + } + Ok(result) +} + +#[allow(dead_code)] +pub fn canonicalize>(original: P, can_mode: CanonicalizeMode) -> Result { + // Create an absolute path + let original = original.as_ref(); + let original = if original.is_absolute() { + original.to_path_buf() + } else { + env::current_dir().unwrap().join(original) + }; + + let mut result = PathBuf::new(); + let mut parts = vec!(); + + // Split path by directory separator; add prefix (Windows-only) and root + // directory to final path buffer; add remaining parts to temporary + // vector for canonicalization. + for part in original.components() { + match part { + Component::Prefix(_) | Component::RootDir => { + result.push(part.as_os_str()); + }, + Component::CurDir => {}, + Component::ParentDir => { + parts.pop(); + }, + Component::Normal(_) => { + parts.push(part.as_os_str()); + } + } + } + + // Resolve the symlinks where possible + if parts.len() > 0 { + for part in parts[..parts.len()-1].iter() { + result.push(part); + + if can_mode == CanonicalizeMode::None { + continue; + } + + match resolve(&result) { + Err(e) => match can_mode { + CanonicalizeMode::Missing => continue, + _ => return Err(e) + }, + Ok(path) => { + result.pop(); + result.push(path); + } + } + } + + result.push(parts.last().unwrap()); + + match resolve(&result) { + Err(e) => { if can_mode == CanonicalizeMode::Existing { return Err(e); } }, + Ok(path) => { + result.pop(); + result.push(path); + } + } + } + Ok(result) +} diff --git a/src/cp/cp.rs b/src/cp/cp.rs index d6d216579..3c0fa2944 100644 --- a/src/cp/cp.rs +++ b/src/cp/cp.rs @@ -1,5 +1,4 @@ #![crate_name = "cp"] -#![feature(fs_canonicalize)] /* * This file is part of the uutils coreutils package. @@ -24,7 +23,7 @@ mod util; #[path = "../common/filesystem.rs"] mod filesystem; -use filesystem::UUPathExt; +use filesystem::{canonicalize, CanonicalizeMode, UUPathExt}; #[derive(Clone, Eq, PartialEq)] pub enum Mode { @@ -155,8 +154,8 @@ fn copy(matches: getopts::Matches) { pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> Result { // We have to take symlinks and relative paths into account. - let pathbuf1 = try!(fs::canonicalize(p1)); - let pathbuf2 = try!(fs::canonicalize(p2)); + let pathbuf1 = try!(canonicalize(p1, CanonicalizeMode::Normal)); + let pathbuf2 = try!(canonicalize(p2, CanonicalizeMode::Normal)); Ok(pathbuf1 == pathbuf2) } diff --git a/src/readlink/readlink.rs b/src/readlink/readlink.rs index 352800eb4..58640b97d 100644 --- a/src/readlink/readlink.rs +++ b/src/readlink/readlink.rs @@ -11,120 +11,22 @@ extern crate getopts; -use std::env; -use std::fs::{metadata, read_link}; -use std::io::{Error, ErrorKind, Result, Write}; -use std::path::{Component, PathBuf}; - -use CanonicalizeMode::{None, Normal, Existing, Missing}; +use std::fs; +use std::io::Write; +use std::path::PathBuf; #[path = "../common/util.rs"] #[macro_use] mod util; +#[path = "../common/filesystem.rs"] +mod filesystem; + +use filesystem::{canonicalize, CanonicalizeMode}; + const NAME: &'static str = "readlink"; const VERSION: &'static str = "0.0.1"; -#[derive(PartialEq)] -enum CanonicalizeMode { - None, - Normal, - Existing, - Missing, -} - -fn resolve(original: &PathBuf) -> Result { - const MAX_LINKS_FOLLOWED: u32 = 255; - let mut followed = 0; - let mut result = original.clone(); - loop { - if followed == MAX_LINKS_FOLLOWED { - return Err(Error::new(ErrorKind::InvalidInput, "maximum links followed")); - } - - match metadata(&result) { - Err(e) => return Err(e), - Ok(ref m) if !m.file_type().is_symlink() => break, - Ok(..) => { - followed += 1; - match read_link(&result) { - Ok(path) => { - result.pop(); - result.push(path); - }, - Err(e) => { - return Err(e); - } - } - } - } - } - Ok(result) -} - -fn canonicalize(original: &PathBuf, can_mode: &CanonicalizeMode) -> Result { - // Create an absolute path - let original = if original.as_path().is_absolute() { - original.clone() - } else { - env::current_dir().unwrap().join(original) - }; - - let mut result = PathBuf::new(); - let mut parts = vec!(); - - // Split path by directory separator; add prefix (Windows-only) and root - // directory to final path buffer; add remaining parts to temporary - // vector for canonicalization. - for part in original.components() { - match part { - Component::Prefix(_) | Component::RootDir => { - result.push(part.as_os_str()); - }, - Component::CurDir => {}, - Component::ParentDir => { - parts.pop(); - }, - Component::Normal(_) => { - parts.push(part.as_os_str()); - } - } - } - - // Resolve the symlinks where possible - if parts.len() > 0 { - for part in parts[..parts.len()-1].iter() { - result.push(part); - - if *can_mode == None { - continue; - } - - match resolve(&result) { - Err(e) => match *can_mode { - Missing => continue, - _ => return Err(e) - }, - Ok(path) => { - result.pop(); - result.push(path); - } - } - } - - result.push(parts.last().unwrap()); - - match resolve(&result) { - Err(e) => { if *can_mode == Existing { return Err(e); } }, - Ok(path) => { - result.pop(); - result.push(path); - } - } - } - Ok(result) -} - pub fn uumain(args: Vec) -> i32 { let mut opts = getopts::Options::new(); @@ -164,17 +66,17 @@ pub fn uumain(args: Vec) -> i32 { let silent = matches.opt_present("silent") || matches.opt_present("quiet"); let verbose = matches.opt_present("verbose"); - let mut can_mode = None; + let mut can_mode = CanonicalizeMode::None; if matches.opt_present("canonicalize") { - can_mode = Normal; + can_mode = CanonicalizeMode::Normal; } if matches.opt_present("canonicalize-existing") { - can_mode = Existing; + can_mode = CanonicalizeMode::Existing; } if matches.opt_present("canonicalize-missing") { - can_mode = Missing; + can_mode = CanonicalizeMode::Missing; } let files = matches.free; @@ -191,8 +93,8 @@ pub fn uumain(args: Vec) -> i32 { for f in files.iter() { let p = PathBuf::from(f); - if can_mode == None { - match read_link(&p) { + if can_mode == CanonicalizeMode::None { + match fs::read_link(&p) { Ok(path) => show(&path, no_newline, use_zero), Err(err) => { if verbose { @@ -202,7 +104,7 @@ pub fn uumain(args: Vec) -> i32 { } } } else { - match canonicalize(&p, &can_mode) { + match canonicalize(&p, can_mode) { Ok(path) => show(&path, no_newline, use_zero), Err(err) => { if verbose { diff --git a/src/realpath/realpath.rs b/src/realpath/realpath.rs index 19e41456c..62b1f951b 100644 --- a/src/realpath/realpath.rs +++ b/src/realpath/realpath.rs @@ -1,5 +1,4 @@ #![crate_name= "realpath"] -#![feature(fs_canonicalize)] /* * This file is part of the uutils coreutils package. @@ -17,7 +16,14 @@ use std::fs; 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; + +#[path = "../common/filesystem.rs"] +mod filesystem; + +use filesystem::{canonicalize, CanonicalizeMode}; static NAME: &'static str = "realpath"; static VERSION: &'static str = "1.0.0"; @@ -63,7 +69,7 @@ pub fn uumain(args: Vec) -> i32 { fn resolve_path(path: &str, strip: bool, zero: bool, quiet: bool) -> bool { let p = Path::new(path).to_path_buf(); - let abs = fs::canonicalize(p).unwrap(); + let abs = canonicalize(p, CanonicalizeMode::Normal).unwrap(); if strip { if zero { diff --git a/src/relpath/relpath.rs b/src/relpath/relpath.rs index e02f16e56..1f4cebcbc 100644 --- a/src/relpath/relpath.rs +++ b/src/relpath/relpath.rs @@ -1,5 +1,4 @@ #![crate_name = "relpath"] -#![feature(fs_canonicalize)] /* * This file is part of the uutils coreutils package. @@ -14,11 +13,17 @@ extern crate getopts; extern crate libc; use std::env; -use std::fs; 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; + +#[path = "../common/filesystem.rs"] +mod filesystem; + +use filesystem::{canonicalize, CanonicalizeMode}; static NAME: &'static str = "relpath"; static VERSION: &'static str = "1.0.0"; @@ -54,12 +59,12 @@ pub fn uumain(args: Vec) -> i32 { } else { env::current_dir().unwrap() }; - let absto = fs::canonicalize(to).unwrap(); - let absfrom = fs::canonicalize(from).unwrap(); + let absto = canonicalize(to, CanonicalizeMode::Normal).unwrap(); + let absfrom = canonicalize(from, CanonicalizeMode::Normal).unwrap(); if matches.opt_present("d") { let base = Path::new(&matches.opt_str("d").unwrap()).to_path_buf(); - let absbase = fs::canonicalize(base).unwrap(); + let absbase = canonicalize(base, CanonicalizeMode::Normal).unwrap(); if !absto.as_path().starts_with(absbase.as_path()) || !absfrom.as_path().starts_with(absbase.as_path()) { println!("{}", absto.display()); return 0 diff --git a/src/stdbuf/stdbuf.rs b/src/stdbuf/stdbuf.rs index f8a1dff9d..988d89085 100644 --- a/src/stdbuf/stdbuf.rs +++ b/src/stdbuf/stdbuf.rs @@ -1,5 +1,5 @@ #![crate_name = "stdbuf"] -#![feature(fs_canonicalize, negate_unsigned)] +#![feature(negate_unsigned)] /* * This file is part of the uutils coreutils package. @@ -15,7 +15,6 @@ extern crate libc; use getopts::{Matches, Options}; use std::env; -use std::fs; use std::io::{self, Write}; use std::os::unix::process::ExitStatusExt; use std::path::PathBuf; @@ -28,7 +27,7 @@ mod util; #[path = "../common/filesystem.rs"] mod filesystem; -use filesystem::UUPathExt; +use filesystem::{canonicalize, CanonicalizeMode, UUPathExt}; static NAME: &'static str = "stdbuf"; static VERSION: &'static str = "1.0.0"; @@ -195,7 +194,7 @@ fn set_command_env(command: &mut Command, buffer_name: &str, buffer_type: Buffer fn exe_path() -> io::Result { let exe_path = try!(env::current_exe()); - let absolute_path = try!(fs::canonicalize(exe_path.as_path())); + let absolute_path = try!(canonicalize(exe_path, CanonicalizeMode::Normal)); Ok(match absolute_path.parent() { Some(p) => p.to_path_buf(), None => absolute_path.clone()