diff --git a/Cargo.lock b/Cargo.lock index 024486977..be63e690f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,12 +156,8 @@ dependencies = [ name = "chmod" version = "0.0.1" 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)", "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", "walker 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/src/chmod/Cargo.toml b/src/chmod/Cargo.toml index a85059a93..40914154f 100644 --- a/src/chmod/Cargo.toml +++ b/src/chmod/Cargo.toml @@ -10,10 +10,6 @@ path = "chmod.rs" [dependencies] getopts = "*" libc = "*" -aho-corasick = "*" -memchr = "*" -regex = "*" -regex-syntax = "*" uucore = { path="../uucore" } walker = "*" diff --git a/src/chmod/chmod.rs b/src/chmod/chmod.rs index 105021fea..341cc8255 100644 --- a/src/chmod/chmod.rs +++ b/src/chmod/chmod.rs @@ -9,10 +9,8 @@ * file that was distributed with this source code. */ -extern crate aho_corasick; extern crate getopts; extern crate libc; -extern crate memchr; extern crate walker; #[macro_use] @@ -29,7 +27,7 @@ use walker::Walker; const NAME: &'static str = "chmod"; const VERSION: &'static str = env!("CARGO_PKG_VERSION"); -pub fn uumain(args: Vec) -> i32 { +pub fn uumain(mut args: Vec) -> i32 { let mut opts = Options::new(); 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 @@ -40,7 +38,27 @@ pub fn uumain(args: Vec) -> i32 { opts.optflag("R", "recursive", "change files and directories recursively"); opts.optflag("h", "help", "display this help 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..]) { Ok(m) => m, Err(f) => { crash!(1, "{}", f) } @@ -86,7 +104,13 @@ Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.", }); let cmode = if fmode.is_none() { - Some(matches.free.remove(0)) + // 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)) + } } else { None }; diff --git a/tests/chmod.rs b/tests/chmod.rs index ac476a573..a00cb5417 100644 --- a/tests/chmod.rs +++ b/tests/chmod.rs @@ -24,18 +24,14 @@ fn mkfile(file: &str, mode: mode_t) { std::fs::set_permissions(file, perms).unwrap(); } -fn run_tests(tests: Vec) { - for test in tests { - let (at, mut ucmd) = testing(UTIL_NAME); - +fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) { 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(); if perms != test.before{ 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); } let r = ucmd.run(); @@ -48,6 +44,12 @@ fn run_tests(tests: Vec) { if perms != test.after { panic!(format!("{:?}: expected: {:o} got: {:o}", ucmd.raw, test.after, perms)); } +} + +fn run_tests(tests: Vec) { + 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!{"0070", TEST_FILE}, before: 0o000, after: 0o070}, 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!{"-0070", TEST_FILE}, before: 0o060, after: 0o000}, - // TestCase{args: vec!{"-0007", TEST_FILE}, before: 0o001, 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!{"-0007", TEST_FILE}, before: 0o001, after: 0o000}, TestCase{args: vec!{"+0100", TEST_FILE}, before: 0o600, after: 0o700}, TestCase{args: vec!{"+0020", TEST_FILE}, before: 0o050, after: 0o070}, 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!{"o=rwx", TEST_FILE}, before: 0o000, after: 0o007}, 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); } @@ -92,9 +96,20 @@ fn test_chmod_ugo_copy() { } #[test] -fn test_chmod_reference_file() { +fn test_chmod_many_options() { 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); } + +#[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); +}