Add -e/-m to realpath

This commit is contained in:
James Robson 2021-08-29 15:08:45 +01:00 committed by Michael Debertol
parent 68e89c7ea3
commit 625c3f2330
2 changed files with 79 additions and 3 deletions

View file

@ -21,6 +21,8 @@ static OPT_STRIP: &str = "strip";
static OPT_ZERO: &str = "zero"; static OPT_ZERO: &str = "zero";
static OPT_PHYSICAL: &str = "physical"; static OPT_PHYSICAL: &str = "physical";
static OPT_LOGICAL: &str = "logical"; static OPT_LOGICAL: &str = "logical";
const OPT_CANONICALIZE_MISSING: &str = "canonicalize-missing";
const OPT_CANONICALIZE_EXISTING: &str = "canonicalize-existing";
static ARG_FILES: &str = "files"; static ARG_FILES: &str = "files";
@ -45,9 +47,16 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let zero = matches.is_present(OPT_ZERO); let zero = matches.is_present(OPT_ZERO);
let quiet = matches.is_present(OPT_QUIET); let quiet = matches.is_present(OPT_QUIET);
let logical = matches.is_present(OPT_LOGICAL); let logical = matches.is_present(OPT_LOGICAL);
let can_mode = if matches.is_present(OPT_CANONICALIZE_EXISTING) {
MissingHandling::Existing
} else if matches.is_present(OPT_CANONICALIZE_MISSING) {
MissingHandling::Missing
} else {
MissingHandling::Normal
};
let mut retcode = 0; let mut retcode = 0;
for path in &paths { for path in &paths {
if let Err(e) = resolve_path(path, strip, zero, logical) { if let Err(e) = resolve_path(path, strip, zero, logical, can_mode) {
if !quiet { if !quiet {
show_error!("{}: {}", e, path.display()); show_error!("{}: {}", e, path.display());
} }
@ -92,6 +101,24 @@ pub fn uu_app() -> App<'static, 'static> {
.overrides_with_all(&[OPT_STRIP, OPT_LOGICAL]) .overrides_with_all(&[OPT_STRIP, OPT_LOGICAL])
.help("resolve symlinks as encountered (default)"), .help("resolve symlinks as encountered (default)"),
) )
.arg(
Arg::with_name(OPT_CANONICALIZE_EXISTING)
.short("e")
.long(OPT_CANONICALIZE_EXISTING)
.help(
"canonicalize by following every symlink in every component of the \
given name recursively, all components must exist",
),
)
.arg(
Arg::with_name(OPT_CANONICALIZE_MISSING)
.short("m")
.long(OPT_CANONICALIZE_MISSING)
.help(
"canonicalize by following every symlink in every component of the \
given name recursively, without requirements on components existence",
),
)
.arg( .arg(
Arg::with_name(ARG_FILES) Arg::with_name(ARG_FILES)
.multiple(true) .multiple(true)
@ -112,7 +139,13 @@ pub fn uu_app() -> App<'static, 'static> {
/// ///
/// This function returns an error if there is a problem resolving /// This function returns an error if there is a problem resolving
/// symbolic links. /// symbolic links.
fn resolve_path(p: &Path, strip: bool, zero: bool, logical: bool) -> std::io::Result<()> { fn resolve_path(
p: &Path,
strip: bool,
zero: bool,
logical: bool,
can_mode: MissingHandling,
) -> std::io::Result<()> {
let resolve = if strip { let resolve = if strip {
ResolveMode::None ResolveMode::None
} else if logical { } else if logical {
@ -120,7 +153,7 @@ fn resolve_path(p: &Path, strip: bool, zero: bool, logical: bool) -> std::io::Re
} else { } else {
ResolveMode::Physical ResolveMode::Physical
}; };
let abs = canonicalize(p, MissingHandling::Normal, resolve)?; let abs = canonicalize(p, can_mode, resolve)?;
let line_ending = if zero { '\0' } else { '\n' }; let line_ending = if zero { '\0' } else { '\n' };
print!("{}{}", abs.display(), line_ending); print!("{}{}", abs.display(), line_ending);

View file

@ -1,5 +1,9 @@
use crate::common::util::*; use crate::common::util::*;
use std::path::Path;
static GIBBERISH: &str = "supercalifragilisticexpialidocious";
#[test] #[test]
fn test_realpath_current_directory() { fn test_realpath_current_directory() {
let (at, mut ucmd) = at_and_ucmd!(); let (at, mut ucmd) = at_and_ucmd!();
@ -159,3 +163,42 @@ fn test_realpath_loop() {
.succeeds() .succeeds()
.stdout_only(at.plus_as_string("2\n")); .stdout_only(at.plus_as_string("2\n"));
} }
#[test]
fn test_realpath_default_allows_final_non_existent() {
let p = Path::new("").join(GIBBERISH);
let (at, mut ucmd) = at_and_ucmd!();
let expect = path_concat!(at.root_dir_resolved(), p.to_str().unwrap()) + "\n";
ucmd.arg(p.as_os_str()).succeeds().stdout_only(expect);
}
#[test]
fn test_realpath_default_forbids_non_final_non_existent() {
let p = Path::new("").join(GIBBERISH).join(GIBBERISH);
new_ucmd!().arg(p.to_str().unwrap()).fails();
}
#[test]
fn test_realpath_existing() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.arg("-e")
.arg(".")
.succeeds()
.stdout_only(at.plus_as_string(&format!("{}\n", at.root_dir_resolved())));
}
#[test]
fn test_realpath_existing_error() {
new_ucmd!().arg("-e").arg(GIBBERISH).fails();
}
#[test]
fn test_realpath_missing() {
let p = Path::new("").join(GIBBERISH).join(GIBBERISH);
let (at, mut ucmd) = at_and_ucmd!();
let expect = path_concat!(at.root_dir_resolved(), p.to_str().unwrap()) + "\n";
ucmd.arg("-m")
.arg(p.as_os_str())
.succeeds()
.stdout_only(expect);
}