mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
commit
f47fafb28d
4 changed files with 56 additions and 25 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -156,12 +156,8 @@ dependencies = [
|
||||||
name = "chmod"
|
name = "chmod"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"regex 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"regex-syntax 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"uucore 0.0.1",
|
"uucore 0.0.1",
|
||||||
"walker 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"walker 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
|
@ -10,10 +10,6 @@ path = "chmod.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
getopts = "*"
|
getopts = "*"
|
||||||
libc = "*"
|
libc = "*"
|
||||||
aho-corasick = "*"
|
|
||||||
memchr = "*"
|
|
||||||
regex = "*"
|
|
||||||
regex-syntax = "*"
|
|
||||||
uucore = { path="../uucore" }
|
uucore = { path="../uucore" }
|
||||||
walker = "*"
|
walker = "*"
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,8 @@
|
||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern crate aho_corasick;
|
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate memchr;
|
|
||||||
extern crate walker;
|
extern crate walker;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -29,7 +27,7 @@ use walker::Walker;
|
||||||
const NAME: &'static str = "chmod";
|
const NAME: &'static str = "chmod";
|
||||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
pub fn uumain(args: Vec<String>) -> i32 {
|
pub fn uumain(mut args: Vec<String>) -> i32 {
|
||||||
let mut opts = Options::new();
|
let mut opts = Options::new();
|
||||||
opts.optflag("c", "changes", "like verbose but report only when a change is made (unimplemented)");
|
opts.optflag("c", "changes", "like verbose but report only when a change is made (unimplemented)");
|
||||||
opts.optflag("f", "quiet", "suppress most error messages (unimplemented)"); // TODO: support --silent
|
opts.optflag("f", "quiet", "suppress most error messages (unimplemented)"); // TODO: support --silent
|
||||||
|
@ -40,7 +38,27 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
opts.optflag("R", "recursive", "change files and directories recursively");
|
opts.optflag("R", "recursive", "change files and directories recursively");
|
||||||
opts.optflag("h", "help", "display this help and exit");
|
opts.optflag("h", "help", "display this help and exit");
|
||||||
opts.optflag("V", "version", "output version information and exit");
|
opts.optflag("V", "version", "output version information and exit");
|
||||||
// TODO: sanitize input for - at beginning (e.g. chmod -x testfile). Solution is to add a to -x, making a-x
|
// sanitize input for - at beginning (e.g. chmod -x testfile). Remove
|
||||||
|
// the option and save it for later, after parsing is finished.
|
||||||
|
let mut negative_option = None;
|
||||||
|
for i in 0..args.len() {
|
||||||
|
if let Some(first) = args[i].chars().nth(0) {
|
||||||
|
if first != '-' {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(second) = args[i].chars().nth(1) {
|
||||||
|
match second {
|
||||||
|
'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0' ... '7' => {
|
||||||
|
negative_option = Some(args.remove(i));
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut matches = match opts.parse(&args[1..]) {
|
let mut matches = match opts.parse(&args[1..]) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(f) => { crash!(1, "{}", f) }
|
Err(f) => { crash!(1, "{}", f) }
|
||||||
|
@ -86,7 +104,13 @@ Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.",
|
||||||
});
|
});
|
||||||
let cmode =
|
let cmode =
|
||||||
if fmode.is_none() {
|
if fmode.is_none() {
|
||||||
|
// If there was a negative option, now it's a good time to
|
||||||
|
// use it.
|
||||||
|
if negative_option.is_some() {
|
||||||
|
negative_option
|
||||||
|
} else {
|
||||||
Some(matches.free.remove(0))
|
Some(matches.free.remove(0))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,18 +24,14 @@ fn mkfile(file: &str, mode: mode_t) {
|
||||||
std::fs::set_permissions(file, perms).unwrap();
|
std::fs::set_permissions(file, perms).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_tests(tests: Vec<TestCase>) {
|
fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) {
|
||||||
for test in tests {
|
|
||||||
let (at, mut ucmd) = testing(UTIL_NAME);
|
|
||||||
|
|
||||||
mkfile(&at.plus_as_string(TEST_FILE), test.before);
|
mkfile(&at.plus_as_string(TEST_FILE), test.before);
|
||||||
mkfile(&at.plus_as_string(REFERENCE_FILE), REFERENCE_PERMS);
|
|
||||||
let perms = at.metadata(TEST_FILE).permissions().mode();
|
let perms = at.metadata(TEST_FILE).permissions().mode();
|
||||||
if perms != test.before{
|
if perms != test.before{
|
||||||
panic!(format!("{}: expected: {:o} got: {:o}", "setting permissions failed", test.after, perms));
|
panic!(format!("{}: expected: {:o} got: {:o}", "setting permissions failed", test.after, perms));
|
||||||
}
|
}
|
||||||
|
|
||||||
for arg in test.args {
|
for arg in &test.args {
|
||||||
ucmd.arg(arg);
|
ucmd.arg(arg);
|
||||||
}
|
}
|
||||||
let r = ucmd.run();
|
let r = ucmd.run();
|
||||||
|
@ -48,6 +44,12 @@ fn run_tests(tests: Vec<TestCase>) {
|
||||||
if perms != test.after {
|
if perms != test.after {
|
||||||
panic!(format!("{:?}: expected: {:o} got: {:o}", ucmd.raw, test.after, perms));
|
panic!(format!("{:?}: expected: {:o} got: {:o}", ucmd.raw, test.after, perms));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_tests(tests: Vec<TestCase>) {
|
||||||
|
for test in tests {
|
||||||
|
let (at, ucmd) = testing(UTIL_NAME);
|
||||||
|
run_single_test(&test, at, ucmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,10 +59,9 @@ fn test_chmod_octal() {
|
||||||
TestCase{args: vec!{"0700", TEST_FILE}, before: 0o000, after: 0o700},
|
TestCase{args: vec!{"0700", TEST_FILE}, before: 0o000, after: 0o700},
|
||||||
TestCase{args: vec!{"0070", TEST_FILE}, before: 0o000, after: 0o070},
|
TestCase{args: vec!{"0070", TEST_FILE}, before: 0o000, after: 0o070},
|
||||||
TestCase{args: vec!{"0007", TEST_FILE}, before: 0o000, after: 0o007},
|
TestCase{args: vec!{"0007", TEST_FILE}, before: 0o000, after: 0o007},
|
||||||
// Known failues: #788
|
TestCase{args: vec!{"-0700", TEST_FILE}, before: 0o700, after: 0o000},
|
||||||
// TestCase{args: vec!{"-0700", TEST_FILE}, before: 0o700, after: 0o000},
|
TestCase{args: vec!{"-0070", TEST_FILE}, before: 0o060, after: 0o000},
|
||||||
// TestCase{args: vec!{"-0070", TEST_FILE}, before: 0o060, after: 0o000},
|
TestCase{args: vec!{"-0007", TEST_FILE}, before: 0o001, after: 0o000},
|
||||||
// TestCase{args: vec!{"-0007", TEST_FILE}, before: 0o001, after: 0o000},
|
|
||||||
TestCase{args: vec!{"+0100", TEST_FILE}, before: 0o600, after: 0o700},
|
TestCase{args: vec!{"+0100", TEST_FILE}, before: 0o600, after: 0o700},
|
||||||
TestCase{args: vec!{"+0020", TEST_FILE}, before: 0o050, after: 0o070},
|
TestCase{args: vec!{"+0020", TEST_FILE}, before: 0o050, after: 0o070},
|
||||||
TestCase{args: vec!{"+0004", TEST_FILE}, before: 0o003, after: 0o007},
|
TestCase{args: vec!{"+0004", TEST_FILE}, before: 0o003, after: 0o007},
|
||||||
|
@ -75,6 +76,9 @@ fn test_chmod_ugoa() {
|
||||||
TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o000, after: 0o070},
|
TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o000, after: 0o070},
|
||||||
TestCase{args: vec!{"o=rwx", TEST_FILE}, before: 0o000, after: 0o007},
|
TestCase{args: vec!{"o=rwx", TEST_FILE}, before: 0o000, after: 0o007},
|
||||||
TestCase{args: vec!{"a=rwx", TEST_FILE}, before: 0o000, after: 0o777},
|
TestCase{args: vec!{"a=rwx", TEST_FILE}, before: 0o000, after: 0o777},
|
||||||
|
TestCase{args: vec!{"-r", TEST_FILE}, before: 0o777, after: 0o333},
|
||||||
|
TestCase{args: vec!{"-w", TEST_FILE}, before: 0o777, after: 0o555},
|
||||||
|
TestCase{args: vec!{"-x", TEST_FILE}, before: 0o777, after: 0o666},
|
||||||
};
|
};
|
||||||
run_tests(tests);
|
run_tests(tests);
|
||||||
}
|
}
|
||||||
|
@ -92,9 +96,20 @@ fn test_chmod_ugo_copy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_chmod_reference_file() {
|
fn test_chmod_many_options() {
|
||||||
let tests = vec!{
|
let tests = vec!{
|
||||||
TestCase{args: vec!{"--reference", REFERENCE_FILE, TEST_FILE}, before: 0o070, after: 0o247},
|
TestCase{args: vec!{"-r,a+w", TEST_FILE}, before: 0o444, after: 0o222},
|
||||||
};
|
};
|
||||||
run_tests(tests);
|
run_tests(tests);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_chmod_reference_file() {
|
||||||
|
let tests = vec!{
|
||||||
|
TestCase{args: vec!{"--reference", REFERENCE_FILE, TEST_FILE}, before: 0o070, after: 0o247},
|
||||||
|
TestCase{args: vec!{"a-w", "--reference", REFERENCE_FILE, TEST_FILE}, before: 0o070, after: 0o247},
|
||||||
|
};
|
||||||
|
let (at, ucmd) = testing(UTIL_NAME);
|
||||||
|
mkfile(&at.plus_as_string(REFERENCE_FILE), REFERENCE_PERMS);
|
||||||
|
run_single_test(&tests[0], at, ucmd);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue