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:
parent
d3fc0e8706
commit
946c8d2d4a
2 changed files with 77 additions and 6 deletions
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue