mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-31 04:57:45 +00:00
Merge pull request #2597 from miDeb/resolve-dangling
uucore/fs: use the latest resolution that did not fail
This commit is contained in:
commit
33055f7152
2 changed files with 52 additions and 18 deletions
|
@ -17,6 +17,7 @@ use libc::{
|
|||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::Error as IOError;
|
||||
use std::io::Result as IOResult;
|
||||
use std::io::{Error, ErrorKind};
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
|
@ -111,26 +112,42 @@ pub fn normalize_path(path: &Path) -> PathBuf {
|
|||
ret
|
||||
}
|
||||
|
||||
fn resolve<P: AsRef<Path>>(original: P) -> IOResult<PathBuf> {
|
||||
fn resolve<P: AsRef<Path>>(original: P) -> Result<PathBuf, (PathBuf, IOError)> {
|
||||
const MAX_LINKS_FOLLOWED: u32 = 255;
|
||||
let mut followed = 0;
|
||||
let mut result = original.as_ref().to_path_buf();
|
||||
|
||||
let mut first_resolution = None;
|
||||
loop {
|
||||
if followed == MAX_LINKS_FOLLOWED {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"maximum links followed",
|
||||
return Err((
|
||||
// When we hit MAX_LINKS_FOLLOWED we should return the first resolution (that's what GNU does - for whatever reason)
|
||||
first_resolution.unwrap(),
|
||||
Error::new(ErrorKind::InvalidInput, "maximum links followed"),
|
||||
));
|
||||
}
|
||||
|
||||
if !fs::symlink_metadata(&result)?.file_type().is_symlink() {
|
||||
break;
|
||||
match fs::symlink_metadata(&result) {
|
||||
Ok(meta) => {
|
||||
if !meta.file_type().is_symlink() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => return Err((result, e)),
|
||||
}
|
||||
|
||||
followed += 1;
|
||||
let path = fs::read_link(&result)?;
|
||||
result.pop();
|
||||
result.push(path);
|
||||
match fs::read_link(&result) {
|
||||
Ok(path) => {
|
||||
result.pop();
|
||||
result.push(path);
|
||||
}
|
||||
Err(e) => return Err((result, e)),
|
||||
}
|
||||
|
||||
if first_resolution.is_none() {
|
||||
first_resolution = Some(result.clone());
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -216,11 +233,10 @@ pub fn canonicalize<P: AsRef<Path>>(
|
|||
}
|
||||
|
||||
match resolve(&result) {
|
||||
Err(_) if miss_mode == MissingHandling::Missing => continue,
|
||||
Err(e) => return Err(e),
|
||||
Err((path, _)) if miss_mode == MissingHandling::Missing => result = path,
|
||||
Err((_, e)) => return Err(e),
|
||||
Ok(path) => {
|
||||
result.pop();
|
||||
result.push(path);
|
||||
result = path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -232,14 +248,12 @@ pub fn canonicalize<P: AsRef<Path>>(
|
|||
}
|
||||
|
||||
match resolve(&result) {
|
||||
Err(e) if miss_mode == MissingHandling::Existing => {
|
||||
Err((_, e)) if miss_mode == MissingHandling::Existing => {
|
||||
return Err(e);
|
||||
}
|
||||
Ok(path) => {
|
||||
result.pop();
|
||||
result.push(path);
|
||||
Ok(path) | Err((path, _)) => {
|
||||
result = path;
|
||||
}
|
||||
Err(_) => (),
|
||||
}
|
||||
if res_mode == ResolveMode::Physical {
|
||||
result = normalize_path(&result);
|
||||
|
|
|
@ -139,3 +139,23 @@ fn test_realpath_logical_mode() {
|
|||
.succeeds()
|
||||
.stdout_contains("dir1\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_realpath_dangling() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.symlink_file("nonexistent-file", "link");
|
||||
ucmd.arg("link")
|
||||
.succeeds()
|
||||
.stdout_only(at.plus_as_string("nonexistent-file\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_realpath_loop() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.symlink_file("2", "1");
|
||||
at.symlink_file("3", "2");
|
||||
at.symlink_file("1", "3");
|
||||
ucmd.arg("1")
|
||||
.succeeds()
|
||||
.stdout_only(at.plus_as_string("2\n"));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue