uucore::fs: don't canonicalize last component

Change the behavior of `uucore::fs::canonicalize()` when `can_mode` is
`CanonicalizeMode::None` so that it does not attempt to resolve the
final component if it is a symbolic link. This matches the behavior of
the function for the non-final components of a path when `can_mode` is
`None`.
This commit is contained in:
Jeffrey Finkelstein 2021-05-22 10:44:50 -04:00
parent 66cfdb8644
commit bee3b1237c

View file

@ -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 {