1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

uucore/perms: take traverse_symlinks into account

This commit is contained in:
Michael Debertol 2021-09-02 22:31:49 +02:00
parent a4fca2d4fc
commit a7f6b4420a
2 changed files with 78 additions and 2 deletions

View file

@ -265,10 +265,21 @@ impl ChownExecutor {
} }
fn dive_into<P: AsRef<Path>>(&self, root: P) -> i32 { fn dive_into<P: AsRef<Path>>(&self, root: P) -> i32 {
let mut ret = 0;
let root = root.as_ref(); let root = root.as_ref();
// walkdir always dereferences the root directory, so we have to check it ourselves
// TODO: replace with `root.is_symlink()` once it is stable
if self.traverse_symlinks == TraverseSymlinks::None
&& std::fs::symlink_metadata(root)
.map(|m| m.file_type().is_symlink())
.unwrap_or(false)
{
return 0;
}
let mut ret = 0;
let mut iterator = WalkDir::new(root) let mut iterator = WalkDir::new(root)
.follow_links(self.dereference) .follow_links(self.traverse_symlinks == TraverseSymlinks::All)
.min_depth(1) .min_depth(1)
.into_iter(); .into_iter();
// We can't use a for loop because we need to manipulate the iterator inside the loop. // We can't use a for loop because we need to manipulate the iterator inside the loop.

View file

@ -288,3 +288,68 @@ fn test_subdir_permission_denied() {
.stderr_only("chgrp: cannot access 'dir/subdir': Permission denied"); .stderr_only("chgrp: cannot access 'dir/subdir': Permission denied");
} }
} }
#[test]
#[cfg(not(target_vendor = "apple"))]
fn test_traverse_symlinks() {
use std::os::unix::prelude::MetadataExt;
let groups = nix::unistd::getgroups().unwrap();
if groups.len() < 2 {
return;
}
let (first_group, second_group) = (groups[0], groups[1]);
for &(args, traverse_first, traverse_second) in &[
(&[][..] as &[&str], false, false),
(&["-H"][..], true, false),
(&["-P"][..], false, false),
(&["-L"][..], true, true),
] {
let scenario = TestScenario::new("chgrp");
let (at, mut ucmd) = (scenario.fixtures.clone(), scenario.ucmd());
at.mkdir("dir");
at.mkdir("dir2");
at.touch("dir2/file");
at.mkdir("dir3");
at.touch("dir3/file");
at.symlink_dir("dir2", "dir/dir2_ln");
at.symlink_dir("dir3", "dir3_ln");
scenario
.ccmd("chgrp")
.arg(first_group.to_string())
.arg("dir2/file")
.arg("dir3/file")
.succeeds();
assert!(at.plus("dir2/file").metadata().unwrap().gid() == first_group.as_raw());
assert!(at.plus("dir3/file").metadata().unwrap().gid() == first_group.as_raw());
ucmd.arg("-R")
.args(args)
.arg(second_group.to_string())
.arg("dir")
.arg("dir3_ln")
.succeeds()
.no_stderr();
assert_eq!(
at.plus("dir2/file").metadata().unwrap().gid(),
if traverse_second {
second_group.as_raw()
} else {
first_group.as_raw()
}
);
assert_eq!(
at.plus("dir3/file").metadata().unwrap().gid(),
if traverse_first {
second_group.as_raw()
} else {
first_group.as_raw()
}
);
}
}