-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Please find the attached test case comparing the output of chmod between GNU and uutils chmod (and chown, chgrp, but they are good).
Update 1:
-- more cases
It creates a scenario like this:
diris a directorydir/link-fileis a symlink totarget-filedir/link-diris a symlink totarget-dirtarget-fileandtarget-dir/fileare files
chmod can hence change the permissions of all files in the scenario by running it on dir. We also test passing dir/target-dir to see how it fares when passing a symlink to a dir.
The output shows that the -H, -L, and --no-dereference options are not correctly implemented (- is GNU, + is uutils):
============================= chmod -R go-rwx dir ============================
--- /dev/fd/63 2025-07-31 18:41:55.044252233 +0200
+++ /dev/fd/62 2025-07-31 18:41:55.045252250 +0200
@@ -5 +5 @@
-drwxrwxr-x 2 jak jak 18 Jul 31 18:41 ./target-dir
+drwx------ 2 jak jak 18 Jul 31 18:41 ./target-dir
@@ -7 +7 @@
--rw-rw-r-- 1 jak jak 0 Jul 31 18:41 ./target-file
+-rw------- 1 jak jak 0 Jul 31 18:41 ./target-file
============================= chmod -R go-rwx dir/link-dir ============================
============================= chmod -R go-rwx dir/link-file ============================
============================= chmod -H -R go-rwx dir ============================
--- /dev/fd/63 2025-07-31 18:41:55.134253752 +0200
+++ /dev/fd/62 2025-07-31 18:41:55.134253752 +0200
@@ -5 +5 @@
-drwxrwxr-x 2 jak jak 18 Jul 31 18:41 ./target-dir
+drwx------ 2 jak jak 18 Jul 31 18:41 ./target-dir
@@ -7 +7 @@
--rw-rw-r-- 1 jak jak 0 Jul 31 18:41 ./target-file
+-rw------- 1 jak jak 0 Jul 31 18:41 ./target-file
============================= chmod -H -R go-rwx dir/link-dir ============================
============================= chmod -H -R go-rwx dir/link-file ============================
============================= chmod -L -R go-rwx dir ============================
--- /dev/fd/63 2025-07-31 18:41:55.220255202 +0200
+++ /dev/fd/62 2025-07-31 18:41:55.220255202 +0200
@@ -6 +6 @@
--rw------- 1 jak jak 0 Jul 31 18:41 ./target-dir/file
+-rw-rw-r-- 1 jak jak 0 Jul 31 18:41 ./target-dir/file
============================= chmod -L -R go-rwx dir/link-dir ============================
============================= chmod -L -R go-rwx dir/link-file ============================
============================= chmod -P -R go-rwx dir ============================
============================= chmod -P -R go-rwx dir/link-dir ============================
============================= chmod -P -R go-rwx dir/link-file ============================
============================= chmod --dereference -R go-rwx dir ============================
============================= chmod --dereference -R go-rwx dir/link-dir ============================
============================= chmod --dereference -R go-rwx dir/link-file ============================
============================= chmod --no-dereference -R go-rwx dir ============================
============================= chmod --no-dereference -R go-rwx dir/link-dir ============================
--- /dev/fd/63 2025-07-31 18:41:55.507260044 +0200
+++ /dev/fd/62 2025-07-31 18:41:55.507260044 +0200
@@ -6 +6 @@
--rw------- 1 jak jak 0 Jul 31 18:41 ./target-dir/file
+-rw-rw-r-- 1 jak jak 0 Jul 31 18:41 ./target-dir/file
============================= chmod --no-dereference -R go-rwx dir/link-file ============================In particular, this gets worse if you pass an absolute path: All symlinks are derferenced, as the check for TraverseSymlinks::First is considerably wrong:
fn walk_dir(&self, file_path: &Path) -> UResult<()> {
let mut r = self.chmod_file(file_path);
// Determine whether to traverse symlinks based on `self.traverse_symlinks`
let should_follow_symlink = match self.traverse_symlinks {
TraverseSymlinks::All => true,
TraverseSymlinks::First => {
file_path == file_path.canonicalize().unwrap_or(file_path.to_path_buf())
}
TraverseSymlinks::None => false,
};It's not clear how this happened, first should deference symlinks that are specified directly as command-line arguments (see dir/link-dir) test cases above. So it stands to reason that selection needs to change to
fn walk_dir(&self, file_path: &Path, bool is_argument) -> UResult<()> {
let mut r = self.chmod_file(file_path);
// Determine whether to traverse symlinks based on `self.traverse_symlinks`
let should_follow_symlink = match self.traverse_symlinks {
TraverseSymlinks::All => true,
TraverseSymlinks::First => is_argument,
TraverseSymlinks::None => false,
};or similar, but this doesn't resolve all issues above and causes failures in the test_chmod suite.