mirror of
https://github.com/uutils/coreutils
synced 2024-10-15 04:14:44 +00:00
Merge pull request #2252 from jfinkels/realpath-simplify
realpath: use uucore::fs::canonicalize() to reduce code duplication
This commit is contained in:
commit
73fb426b2b
|
@ -11,7 +11,6 @@
|
|||
extern crate uucore;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use uucore::fs::{canonicalize, CanonicalizeMode};
|
||||
|
||||
|
@ -75,64 +74,35 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
let quiet = matches.is_present(OPT_QUIET);
|
||||
let mut retcode = 0;
|
||||
for path in &paths {
|
||||
if !resolve_path(path, strip, zero, quiet) {
|
||||
if let Err(e) = resolve_path(path, strip, zero) {
|
||||
if !quiet {
|
||||
show_error!("{}: {}", e, path.display());
|
||||
}
|
||||
retcode = 1
|
||||
};
|
||||
}
|
||||
retcode
|
||||
}
|
||||
|
||||
fn resolve_path(p: &Path, strip: bool, zero: bool, quiet: bool) -> bool {
|
||||
let abs = canonicalize(p, CanonicalizeMode::Normal).unwrap();
|
||||
|
||||
if strip {
|
||||
if zero {
|
||||
print!("{}\0", p.display());
|
||||
} else {
|
||||
println!("{}", p.display())
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let mut result = PathBuf::new();
|
||||
let mut links_left = 256;
|
||||
|
||||
for part in abs.components() {
|
||||
result.push(part.as_os_str());
|
||||
loop {
|
||||
if links_left == 0 {
|
||||
if !quiet {
|
||||
show_error!("Too many symbolic links: {}", p.display())
|
||||
};
|
||||
return false;
|
||||
}
|
||||
match fs::metadata(result.as_path()) {
|
||||
Err(_) => break,
|
||||
Ok(ref m) if !m.file_type().is_symlink() => break,
|
||||
Ok(_) => {
|
||||
links_left -= 1;
|
||||
match fs::read_link(result.as_path()) {
|
||||
Ok(x) => {
|
||||
result.pop();
|
||||
result.push(x.as_path());
|
||||
}
|
||||
_ => {
|
||||
if !quiet {
|
||||
show_error!("Invalid path: {}", p.display())
|
||||
};
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if zero {
|
||||
print!("{}\0", result.display());
|
||||
/// Resolve a path to an absolute form and print it.
|
||||
///
|
||||
/// If `strip` is `true`, then this function does not attempt to resolve
|
||||
/// symbolic links in the path. If `zero` is `true`, then this function
|
||||
/// prints the path followed by the null byte (`'\0'`) instead of a
|
||||
/// newline character (`'\n'`).
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function returns an error if there is a problem resolving
|
||||
/// symbolic links.
|
||||
fn resolve_path(p: &Path, strip: bool, zero: bool) -> std::io::Result<()> {
|
||||
let mode = if strip {
|
||||
CanonicalizeMode::None
|
||||
} else {
|
||||
println!("{}", result.display());
|
||||
}
|
||||
|
||||
true
|
||||
CanonicalizeMode::Normal
|
||||
};
|
||||
let abs = canonicalize(p, mode)?;
|
||||
let line_ending = if zero { '\0' } else { '\n' };
|
||||
print!("{}{}", abs.display(), line_ending);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -54,11 +54,19 @@ pub fn resolve_relative_path(path: &Path) -> Cow<Path> {
|
|||
result.into()
|
||||
}
|
||||
|
||||
/// Controls how symbolic links should be handled when canonicalizing a path.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum CanonicalizeMode {
|
||||
/// Do not resolve any symbolic links.
|
||||
None,
|
||||
|
||||
/// Resolve all symbolic links.
|
||||
Normal,
|
||||
|
||||
/// Resolve symbolic links, ignoring errors on the final component.
|
||||
Existing,
|
||||
|
||||
/// Resolve symbolic links, ignoring errors on the non-final components.
|
||||
Missing,
|
||||
}
|
||||
|
||||
|
@ -125,6 +133,24 @@ fn resolve<P: AsRef<Path>>(original: P) -> IOResult<PathBuf> {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
/// Return the canonical, absolute form of a path.
|
||||
///
|
||||
/// This function is a generalization of [`std::fs::canonicalize`] that
|
||||
/// allows controlling how symbolic links are resolved and how to deal
|
||||
/// with missing components. It returns the canonical, absolute form of
|
||||
/// a path. The `can_mode` parameter controls how symbolic links are
|
||||
/// resolved:
|
||||
///
|
||||
/// * [`CanonicalizeMode::Normal`] makes this function behave like
|
||||
/// [`std::fs::canonicalize`], resolving symbolic links and returning
|
||||
/// an error if the path does not exist.
|
||||
/// * [`CanonicalizeMode::Missing`] makes this function ignore non-final
|
||||
/// components of the path that could not be resolved.
|
||||
/// * [`CanonicalizeMode::Existing`] makes this function return an error
|
||||
/// if the final component of the path does not exist.
|
||||
/// * [`CanonicalizeMode::None`] makes this function not try to resolve
|
||||
/// any symbolic links.
|
||||
///
|
||||
pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> IOResult<PathBuf> {
|
||||
// Create an absolute path
|
||||
let original = original.as_ref();
|
||||
|
@ -180,6 +206,10 @@ pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) ->
|
|||
|
||||
result.push(parts.last().unwrap());
|
||||
|
||||
if can_mode == CanonicalizeMode::None {
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
match resolve(&result) {
|
||||
Err(e) => {
|
||||
if can_mode == CanonicalizeMode::Existing {
|
||||
|
|
Loading…
Reference in a new issue