Skip to content

Commit

Permalink
util: added umask manipulation (#6404)
Browse files Browse the repository at this point in the history

Co-authored-by: Terts Diepraam <[email protected]>
  • Loading branch information
matrixhead and tertsdiepraam authored May 19, 2024
1 parent f013d23 commit 3c096ee
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 94 deletions.
74 changes: 44 additions & 30 deletions tests/by-util/test_chmod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use crate::common::util::{AtPath, TestScenario, UCommand};
use once_cell::sync::Lazy;
use std::fs::{metadata, set_permissions, OpenOptions, Permissions};
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use std::sync::Mutex;

use libc::umask;

static TEST_FILE: &str = "file";
static REFERENCE_FILE: &str = "reference";
static REFERENCE_PERMS: u32 = 0o247;
static UMASK_MUTEX: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));

struct TestCase {
args: Vec<&'static str>,
before: u32,
after: u32,
umask: Option<libc::mode_t>,
}

fn make_file(file: &str, mode: u32) {
Expand All @@ -45,6 +41,9 @@ fn run_single_test(test: &TestCase, at: &AtPath, mut ucmd: UCommand) {

for arg in &test.args {
ucmd.arg(arg);
if let Some(umask) = test.umask {
ucmd.umask(umask);
}
}
let r = ucmd.run();
if !r.succeeded() {
Expand Down Expand Up @@ -73,46 +72,55 @@ fn test_chmod_octal() {
args: vec!["0700", TEST_FILE],
before: 0o100000,
after: 0o100700,
umask: None,
},
TestCase {
args: vec!["0070", TEST_FILE],
before: 0o100000,
after: 0o100070,
umask: None,
},
TestCase {
args: vec!["0007", TEST_FILE],
before: 0o100000,
after: 0o100007,
umask: None,
},
TestCase {
args: vec!["-0700", TEST_FILE],
before: 0o100700,
after: 0o100000,
umask: None,
},
TestCase {
args: vec!["-0070", TEST_FILE],
before: 0o100060,
after: 0o100000,
umask: None,
},
TestCase {
args: vec!["-0007", TEST_FILE],
before: 0o100001,
after: 0o100000,
umask: None,
},
TestCase {
args: vec!["+0100", TEST_FILE],
before: 0o100600,
after: 0o100700,
umask: None,
},
TestCase {
args: vec!["+0020", TEST_FILE],
before: 0o100050,
after: 0o100070,
umask: None,
},
TestCase {
args: vec!["+0004", TEST_FILE],
before: 0o100003,
after: 0o100007,
umask: None,
},
];
run_tests(tests);
Expand All @@ -122,86 +130,94 @@ fn test_chmod_octal() {
#[allow(clippy::unreadable_literal)]
// spell-checker:disable-next-line
fn test_chmod_ugoa() {
let _guard = UMASK_MUTEX.lock();

let last = unsafe { umask(0) };
let tests = vec![
TestCase {
args: vec!["u=rwx", TEST_FILE],
before: 0o100000,
after: 0o100700,
umask: Some(0),
},
TestCase {
args: vec!["g=rwx", TEST_FILE],
before: 0o100000,
after: 0o100070,
umask: Some(0),
},
TestCase {
args: vec!["o=rwx", TEST_FILE],
before: 0o100000,
after: 0o100007,
umask: Some(0),
},
TestCase {
args: vec!["a=rwx", TEST_FILE],
before: 0o100000,
after: 0o100777,
umask: Some(0),
},
TestCase {
args: vec!["-r", TEST_FILE],
before: 0o100777,
after: 0o100333,
umask: Some(0),
},
TestCase {
args: vec!["-w", TEST_FILE],
before: 0o100777,
after: 0o100555,
umask: Some(0),
},
TestCase {
args: vec!["-x", TEST_FILE],
before: 0o100777,
after: 0o100666,
umask: Some(0),
},
];
run_tests(tests);

unsafe {
umask(0o022);
}
let tests = vec![
TestCase {
args: vec!["u=rwx", TEST_FILE],
before: 0o100000,
after: 0o100700,
umask: Some(0o022),
},
TestCase {
args: vec!["g=rwx", TEST_FILE],
before: 0o100000,
after: 0o100070,
umask: Some(0o022),
},
TestCase {
args: vec!["o=rwx", TEST_FILE],
before: 0o100000,
after: 0o100007,
umask: Some(0o022),
},
TestCase {
args: vec!["a=rwx", TEST_FILE],
before: 0o100000,
after: 0o100777,
umask: Some(0o022),
},
TestCase {
args: vec!["+rw", TEST_FILE],
before: 0o100000,
after: 0o100644,
umask: Some(0o022),
},
TestCase {
args: vec!["=rwx", TEST_FILE],
before: 0o100000,
after: 0o100755,
umask: Some(0o022),
},
TestCase {
args: vec!["-x", TEST_FILE],
before: 0o100777,
after: 0o100666,
umask: Some(0o022),
},
];
run_tests(tests);
Expand All @@ -219,10 +235,6 @@ fn test_chmod_ugoa() {
metadata(at.plus("file")).unwrap().permissions().mode(),
0o100577
);

unsafe {
umask(last);
}
}

#[test]
Expand All @@ -233,26 +245,31 @@ fn test_chmod_ugo_copy() {
args: vec!["u=g", TEST_FILE],
before: 0o100070,
after: 0o100770,
umask: None,
},
TestCase {
args: vec!["g=o", TEST_FILE],
before: 0o100005,
after: 0o100055,
umask: None,
},
TestCase {
args: vec!["o=u", TEST_FILE],
before: 0o100200,
after: 0o100202,
umask: None,
},
TestCase {
args: vec!["u-g", TEST_FILE],
before: 0o100710,
after: 0o100610,
umask: None,
},
TestCase {
args: vec!["u+g", TEST_FILE],
before: 0o100250,
after: 0o100750,
umask: None,
},
];
run_tests(tests);
Expand All @@ -261,18 +278,13 @@ fn test_chmod_ugo_copy() {
#[test]
#[allow(clippy::unreadable_literal)]
fn test_chmod_many_options() {
let _guard = UMASK_MUTEX.lock();

let original_umask = unsafe { umask(0) };
let tests = vec![TestCase {
args: vec!["-r,a+w", TEST_FILE],
before: 0o100444,
after: 0o100222,
umask: Some(0),
}];
run_tests(tests);
unsafe {
umask(original_umask);
}
}

#[test]
Expand All @@ -283,11 +295,13 @@ fn test_chmod_reference_file() {
args: vec!["--reference", REFERENCE_FILE, TEST_FILE],
before: 0o100070,
after: 0o100247,
umask: None,
},
TestCase {
args: vec!["a-w", "--reference", REFERENCE_FILE, TEST_FILE],
before: 0o100070,
after: 0o100247,
umask: None,
},
];
let (at, ucmd) = at_and_ucmd!();
Expand Down Expand Up @@ -318,14 +332,16 @@ fn test_permission_denied() {
#[test]
#[allow(clippy::unreadable_literal)]
fn test_chmod_recursive() {
let _guard = UMASK_MUTEX.lock();

let original_umask = unsafe { umask(0) };
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("a");
at.mkdir("a/b");
at.mkdir("a/b/c");
at.mkdir("z");

// create expected permissions by removing read bits and write bits to the current perms
let a_perms_expected = (at.metadata("a").permissions().mode() & !0o444) | 0o222;
let z_perms_expected = (at.metadata("z").permissions().mode() & !0o444) | 0o222;

make_file(&at.plus_as_string("a/a"), 0o100444);
make_file(&at.plus_as_string("a/b/b"), 0o100444);
make_file(&at.plus_as_string("a/b/c/c"), 0o100444);
Expand All @@ -338,6 +354,7 @@ fn test_chmod_recursive() {
.arg("-r,a+w")
.arg("a")
.arg("z")
.umask(0)
.fails()
.stderr_is("chmod: Permission denied\n");

Expand All @@ -346,12 +363,8 @@ fn test_chmod_recursive() {
assert_eq!(at.metadata("a/b/b").permissions().mode(), 0o100444);
assert_eq!(at.metadata("a/b/c/c").permissions().mode(), 0o100444);
println!("mode {:o}", at.metadata("a").permissions().mode());
assert_eq!(at.metadata("a").permissions().mode(), 0o40333);
assert_eq!(at.metadata("z").permissions().mode(), 0o40333);

unsafe {
umask(original_umask);
}
assert_eq!(at.metadata("a").permissions().mode(), a_perms_expected);
assert_eq!(at.metadata("z").permissions().mode(), z_perms_expected);
}

#[test]
Expand Down Expand Up @@ -550,6 +563,7 @@ fn test_mode_after_dash_dash() {
args: vec!["--", "-r", TEST_FILE],
before: 0o100_777,
after: 0o100_333,
umask: None,
},
&at,
ucmd,
Expand Down
12 changes: 4 additions & 8 deletions tests/by-util/test_cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1718,27 +1718,24 @@ fn test_cp_preserve_links_case_7() {
#[test]
#[cfg(unix)]
fn test_cp_no_preserve_mode() {
use libc::umask;
use uucore::fs as uufs;
let (at, mut ucmd) = at_and_ucmd!();

at.touch("a");
at.set_mode("a", 0o731);
unsafe { umask(0o077) };

ucmd.arg("-a")
.arg("--no-preserve=mode")
.arg("a")
.arg("b")
.umask(0o077)
.succeeds();

assert!(at.file_exists("b"));

let metadata_b = std::fs::metadata(at.subdir.join("b")).unwrap();
let permission_b = uufs::display_permissions(&metadata_b, false);
assert_eq!(permission_b, "rw-------".to_string());

unsafe { umask(0o022) };
}

#[test]
Expand Down Expand Up @@ -2535,8 +2532,6 @@ fn test_copy_symlink_force() {
fn test_no_preserve_mode() {
use std::os::unix::prelude::MetadataExt;

use uucore::mode::get_umask;

const PERMS_ALL: u32 = if cfg!(target_os = "freebsd") {
// Only the superuser can set the sticky bit on a file.
0o6777
Expand All @@ -2547,14 +2542,15 @@ fn test_no_preserve_mode() {
let (at, mut ucmd) = at_and_ucmd!();
at.touch("file");
set_permissions(at.plus("file"), PermissionsExt::from_mode(PERMS_ALL)).unwrap();
let umask: u16 = 0o022;
ucmd.arg("file")
.arg("dest")
.umask(umask as libc::mode_t)
.succeeds()
.no_stderr()
.no_stdout();
let umask = get_umask();
// remove sticky bit, setuid and setgid bit; apply umask
let expected_perms = PERMS_ALL & !0o7000 & !umask;
let expected_perms = PERMS_ALL & !0o7000 & !umask as u32;
assert_eq!(
at.plus("dest").metadata().unwrap().mode() & 0o7777,
expected_perms
Expand Down
Loading

0 comments on commit 3c096ee

Please sign in to comment.