mirror of
https://github.com/uutils/coreutils
synced 2024-11-15 09:27:21 +00:00
chmod: fixed behavior for dangling symlinks (#1775)
This commit is contained in:
parent
5f17719a59
commit
2647a72e9e
2 changed files with 123 additions and 35 deletions
|
@ -206,7 +206,17 @@ impl Chmoder {
|
||||||
let filename = &filename[..];
|
let filename = &filename[..];
|
||||||
let file = Path::new(filename);
|
let file = Path::new(filename);
|
||||||
if !file.exists() {
|
if !file.exists() {
|
||||||
show_error!("no such file or directory '{}'", filename);
|
if is_symlink(file) {
|
||||||
|
println!(
|
||||||
|
"failed to change mode of '{}' from 0000 (---------) to 0000 (---------)",
|
||||||
|
filename
|
||||||
|
);
|
||||||
|
if !self.quiet {
|
||||||
|
show_error!("cannot operate on dangling symlink '{}'", filename);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
show_error!("cannot access '{}': No such file or directory", filename);
|
||||||
|
}
|
||||||
return Err(1);
|
return Err(1);
|
||||||
}
|
}
|
||||||
if self.recursive && self.preserve_root && filename == "/" {
|
if self.recursive && self.preserve_root && filename == "/" {
|
||||||
|
@ -240,18 +250,16 @@ impl Chmoder {
|
||||||
let mut fperm = match fs::metadata(file) {
|
let mut fperm = match fs::metadata(file) {
|
||||||
Ok(meta) => meta.mode() & 0o7777,
|
Ok(meta) => meta.mode() & 0o7777,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if !self.quiet {
|
if is_symlink(file) {
|
||||||
if is_symlink(file) {
|
if self.verbose {
|
||||||
if self.verbose {
|
println!(
|
||||||
show_info!(
|
"neither symbolic link '{}' nor referent has been changed",
|
||||||
"neither symbolic link '{}' nor referent has been changed",
|
file.display()
|
||||||
file.display()
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
} else {
|
|
||||||
show_error!("{}: '{}'", err, file.display());
|
|
||||||
}
|
}
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
show_error!("{}: '{}'", err, file.display());
|
||||||
}
|
}
|
||||||
return Err(1);
|
return Err(1);
|
||||||
}
|
}
|
||||||
|
@ -291,11 +299,11 @@ impl Chmoder {
|
||||||
fn change_file(&self, fperm: u32, mode: u32, file: &Path) -> Result<(), i32> {
|
fn change_file(&self, fperm: u32, mode: u32, file: &Path) -> Result<(), i32> {
|
||||||
if fperm == mode {
|
if fperm == mode {
|
||||||
if self.verbose && !self.changes {
|
if self.verbose && !self.changes {
|
||||||
show_info!(
|
println!(
|
||||||
"mode of '{}' retained as {:o} ({})",
|
"mode of '{}' retained as {:04o} ({})",
|
||||||
file.display(),
|
file.display(),
|
||||||
fperm,
|
fperm,
|
||||||
display_permissions_unix(fperm)
|
display_permissions_unix(fperm),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -329,10 +329,9 @@ fn test_chmod_non_existing_file() {
|
||||||
.arg("-r,a+w")
|
.arg("-r,a+w")
|
||||||
.arg("dont-exist")
|
.arg("dont-exist")
|
||||||
.fails();
|
.fails();
|
||||||
assert_eq!(
|
assert!(result
|
||||||
result.stderr,
|
.stderr
|
||||||
"chmod: error: no such file or directory 'dont-exist'\n"
|
.contains("cannot access 'dont-exist': No such file or directory"));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -351,30 +350,111 @@ fn test_chmod_preserve_root() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_chmod_symlink_non_existing_file() {
|
fn test_chmod_symlink_non_existing_file() {
|
||||||
let (at, mut ucmd) = at_and_ucmd!();
|
let scene = TestScenario::new(util_name!());
|
||||||
at.symlink_file("/non-existing", "test-long.link");
|
let at = &scene.fixtures;
|
||||||
|
|
||||||
let _result = ucmd
|
let non_existing = "test_chmod_symlink_non_existing_file";
|
||||||
.arg("-R")
|
let test_symlink = "test_chmod_symlink_non_existing_file_symlink";
|
||||||
|
let expected_stdout = &format!(
|
||||||
|
"failed to change mode of '{}' from 0000 (---------) to 0000 (---------)",
|
||||||
|
test_symlink
|
||||||
|
);
|
||||||
|
let expected_stderr = &format!("cannot operate on dangling symlink '{}'", test_symlink);
|
||||||
|
|
||||||
|
at.symlink_file(non_existing, test_symlink);
|
||||||
|
let mut result;
|
||||||
|
|
||||||
|
// this cannot succeed since the symbolic link dangles
|
||||||
|
result = scene.ucmd().arg("755").arg("-v").arg(test_symlink).fails();
|
||||||
|
|
||||||
|
println!("stdout = {:?}", result.stdout);
|
||||||
|
println!("stderr = {:?}", result.stderr);
|
||||||
|
|
||||||
|
assert!(result.stdout.contains(expected_stdout));
|
||||||
|
assert!(result.stderr.contains(expected_stderr));
|
||||||
|
assert_eq!(result.code, Some(1));
|
||||||
|
|
||||||
|
// this should be the same than with just '-v' but without stderr
|
||||||
|
result = scene
|
||||||
|
.ucmd()
|
||||||
.arg("755")
|
.arg("755")
|
||||||
.arg("-v")
|
.arg("-v")
|
||||||
.arg("test-long.link")
|
.arg("-f")
|
||||||
|
.arg(test_symlink)
|
||||||
.fails();
|
.fails();
|
||||||
|
|
||||||
|
println!("stdout = {:?}", result.stdout);
|
||||||
|
println!("stderr = {:?}", result.stderr);
|
||||||
|
|
||||||
|
assert!(result.stdout.contains(expected_stdout));
|
||||||
|
assert!(result.stderr.is_empty());
|
||||||
|
assert_eq!(result.code, Some(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_chmod_symlink_non_existing_recursive() {
|
fn test_chmod_symlink_non_existing_file_recursive() {
|
||||||
let (at, mut ucmd) = at_and_ucmd!();
|
let scene = TestScenario::new(util_name!());
|
||||||
at.mkdir("tmp");
|
let at = &scene.fixtures;
|
||||||
at.symlink_file("/non-existing", "tmp/test-long.link");
|
|
||||||
|
|
||||||
let result = ucmd.arg("-R").arg("755").arg("-v").arg("tmp").succeeds();
|
let non_existing = "test_chmod_symlink_non_existing_file_recursive";
|
||||||
// it should be a success
|
let test_symlink = "test_chmod_symlink_non_existing_file_recursive_symlink";
|
||||||
println!("stderr {}", result.stderr);
|
let test_directory = "test_chmod_symlink_non_existing_file_directory";
|
||||||
println!("stdout {}", result.stdout);
|
|
||||||
assert!(result
|
at.mkdir(test_directory);
|
||||||
.stderr
|
at.symlink_file(
|
||||||
.contains("neither symbolic link 'tmp/test-long.link' nor referent has been changed"));
|
non_existing,
|
||||||
|
&format!("{}/{}", test_directory, test_symlink),
|
||||||
|
);
|
||||||
|
let mut result;
|
||||||
|
|
||||||
|
// this should succeed
|
||||||
|
result = scene
|
||||||
|
.ucmd()
|
||||||
|
.arg("-R")
|
||||||
|
.arg("755")
|
||||||
|
.arg(test_directory)
|
||||||
|
.succeeds();
|
||||||
|
assert_eq!(result.code, Some(0));
|
||||||
|
assert!(result.stdout.is_empty());
|
||||||
|
assert!(result.stderr.is_empty());
|
||||||
|
|
||||||
|
let expected_stdout = &format!(
|
||||||
|
"mode of '{}' retained as 0755 (rwxr-xr-x)\nneither symbolic link '{}/{}' nor referent has been changed",
|
||||||
|
test_directory, test_directory, test_symlink
|
||||||
|
);
|
||||||
|
|
||||||
|
// '-v': this should succeed without stderr
|
||||||
|
result = scene
|
||||||
|
.ucmd()
|
||||||
|
.arg("-R")
|
||||||
|
.arg("-v")
|
||||||
|
.arg("755")
|
||||||
|
.arg(test_directory)
|
||||||
|
.succeeds();
|
||||||
|
|
||||||
|
println!("stdout = {:?}", result.stdout);
|
||||||
|
println!("stderr = {:?}", result.stderr);
|
||||||
|
|
||||||
|
assert!(result.stdout.contains(expected_stdout));
|
||||||
|
assert!(result.stderr.is_empty());
|
||||||
|
assert_eq!(result.code, Some(0));
|
||||||
|
|
||||||
|
// '-vf': this should be the same than with just '-v'
|
||||||
|
result = scene
|
||||||
|
.ucmd()
|
||||||
|
.arg("-R")
|
||||||
|
.arg("-v")
|
||||||
|
.arg("-f")
|
||||||
|
.arg("755")
|
||||||
|
.arg(test_directory)
|
||||||
|
.succeeds();
|
||||||
|
|
||||||
|
println!("stdout = {:?}", result.stdout);
|
||||||
|
println!("stderr = {:?}", result.stderr);
|
||||||
|
|
||||||
|
assert!(result.stdout.contains(expected_stdout));
|
||||||
|
assert!(result.stderr.is_empty());
|
||||||
|
assert_eq!(result.code, Some(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue