diff --git a/src/chmod/chmod.rs b/src/chmod/chmod.rs index 341cc8255..70e3935cd 100644 --- a/src/chmod/chmod.rs +++ b/src/chmod/chmod.rs @@ -248,11 +248,18 @@ fn parse_symbolic(mut fperm: libc::mode_t, mut mode: &str, file: &Path) -> Resul if pos == mode.len() { return Err(format!("invalid mode ({})", mode)); } + let respect_umask = pos == 0; + let last_umask = unsafe { + libc::umask(0) + }; mode = &mode[pos..]; while mode.len() > 0 { let (op, pos) = try!(parse_op(mode, None)); mode = &mode[pos..]; - let (srwx, pos) = parse_change(mode, fperm, file); + let (mut srwx, pos) = parse_change(mode, fperm, file); + if respect_umask { + srwx &= !last_umask; + } mode = &mode[pos..]; match op { '+' => fperm |= srwx & mask, @@ -261,6 +268,9 @@ fn parse_symbolic(mut fperm: libc::mode_t, mut mode: &str, file: &Path) -> Resul _ => unreachable!() } } + unsafe { + libc::umask(last_umask); + } Ok(fperm) } diff --git a/tests/test_chmod.rs b/tests/test_chmod.rs index 4efb24d8f..8ee636a3b 100644 --- a/tests/test_chmod.rs +++ b/tests/test_chmod.rs @@ -2,6 +2,9 @@ use common::util::*; use std::fs::{metadata, OpenOptions, set_permissions}; use std::os::unix::fs::{OpenOptionsExt, PermissionsExt}; +extern crate libc; +use self::libc::umask; + static UTIL_NAME: &'static str = "chmod"; static TEST_FILE: &'static str = "file"; static REFERENCE_FILE: &'static str = "reference"; @@ -67,6 +70,9 @@ fn test_chmod_octal() { #[test] fn test_chmod_ugoa() { + let last = unsafe { + umask(0) + }; let tests = vec!{ TestCase{args: vec!{"u=rwx", TEST_FILE}, before: 0o000, after: 0o700}, TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o000, after: 0o070}, @@ -77,6 +83,24 @@ fn test_chmod_ugoa() { TestCase{args: vec!{"-x", TEST_FILE}, before: 0o777, after: 0o666}, }; run_tests(tests); + + unsafe { + umask(0o022); + } + let tests = vec!{ + TestCase{args: vec!{"u=rwx", TEST_FILE}, before: 0o000, after: 0o700}, + 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!{"+rw", TEST_FILE}, before: 0o000, after: 0o644}, + TestCase{args: vec!{"=rwx", TEST_FILE}, before: 0o000, after: 0o755}, + TestCase{args: vec!{"-w", TEST_FILE}, before: 0o777, after: 0o577}, + TestCase{args: vec!{"-x", TEST_FILE}, before: 0o777, after: 0o666}, + }; + run_tests(tests); + unsafe { + umask(last); + } } #[test]