1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

chmod: change permissions for files present even when there is a missing file

This commit is contained in:
David Matos 2023-02-14 00:18:17 +01:00
parent d3fc0e8706
commit 946c8d2d4a
2 changed files with 77 additions and 6 deletions

View file

@ -12,12 +12,12 @@ use std::fs;
use std::os::unix::fs::{MetadataExt, PermissionsExt}; use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::path::Path; use std::path::Path;
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::error::{ExitCode, UResult, USimpleError, UUsageError}; use uucore::error::{set_exit_code, ExitCode, UResult, USimpleError, UUsageError};
use uucore::fs::display_permissions_unix; use uucore::fs::display_permissions_unix;
use uucore::libc::mode_t; use uucore::libc::mode_t;
#[cfg(not(windows))] #[cfg(not(windows))]
use uucore::mode; use uucore::mode;
use uucore::{format_usage, show_error}; use uucore::{format_usage, show, show_error};
const ABOUT: &str = "Change the mode of each FILE to MODE.\n\ const ABOUT: &str = "Change the mode of each FILE to MODE.\n\
With --reference, change the mode of each FILE to that of RFILE."; With --reference, change the mode of each FILE to that of RFILE.";
@ -195,21 +195,24 @@ impl Chmoder {
filename.quote() filename.quote()
); );
if !self.quiet { if !self.quiet {
return Err(USimpleError::new( show!(USimpleError::new(
1, 1,
format!("cannot operate on dangling symlink {}", filename.quote()), format!("cannot operate on dangling symlink {}", filename.quote()),
)); ));
} }
} else if !self.quiet { } else if !self.quiet {
return Err(USimpleError::new( show!(USimpleError::new(
1, 1,
format!( format!(
"cannot access {}: No such file or directory", "cannot access {}: No such file or directory",
filename.quote() filename.quote()
), )
)); ));
} }
return Err(ExitCode::new(1)); // GNU exits with exit code 1 even if -q or --quiet are passed
// So we set the exit code, because it hasn't been set yet if `self.quiet` is true.
set_exit_code(1);
continue;
} }
if self.recursive && self.preserve_root && filename == "/" { if self.recursive && self.preserve_root && filename == "/" {
return Err(USimpleError::new( return Err(USimpleError::new(

View file

@ -574,3 +574,71 @@ fn test_mode_after_dash_dash() {
ucmd, ucmd,
); );
} }
#[test]
fn test_chmod_file_after_non_existing_file() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch(TEST_FILE);
at.touch("file2");
set_permissions(at.plus(TEST_FILE), Permissions::from_mode(0o664)).unwrap();
set_permissions(at.plus("file2"), Permissions::from_mode(0o664)).unwrap();
scene
.ucmd()
.arg("u+x")
.arg("does-not-exist")
.arg(TEST_FILE)
.fails()
.stderr_contains("chmod: cannot access 'does-not-exist': No such file or directory")
.code_is(1);
assert_eq!(at.metadata(TEST_FILE).permissions().mode(), 0o100764);
scene
.ucmd()
.arg("u+x")
.arg("--q")
.arg("does-not-exist")
.arg("file2")
.fails()
.no_stderr()
.code_is(1);
assert_eq!(at.metadata("file2").permissions().mode(), 0o100764);
}
#[test]
fn test_chmod_file_symlink_after_non_existing_file() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let existing = "file";
let test_existing_symlink = "file_symlink";
let non_existing = "test_chmod_symlink_non_existing_file";
let test_dangling_symlink = "test_chmod_symlink_non_existing_file_symlink";
let expected_stdout = &format!(
"failed to change mode of '{test_dangling_symlink}' from 0000 (---------) to 0000 (---------)"
);
let expected_stderr = &format!("cannot operate on dangling symlink '{test_dangling_symlink}'");
at.touch(existing);
set_permissions(at.plus(existing), Permissions::from_mode(0o664)).unwrap();
at.symlink_file(non_existing, test_dangling_symlink);
at.symlink_file(existing, test_existing_symlink);
// this cannot succeed since the symbolic link dangles
// but the metadata for the existing target should change
scene
.ucmd()
.arg("u+x")
.arg("-v")
.arg(test_dangling_symlink)
.arg(test_existing_symlink)
.fails()
.code_is(1)
.stdout_contains(expected_stdout)
.stderr_contains(expected_stderr);
assert_eq!(
at.metadata(test_existing_symlink).permissions().mode(),
0o100764
);
}