Found trying to run the libc++ tests.

For coreutils, `info chmod` says:

  'chmod' ignores symbolic links encountered during recursive directory
  traversals.

Bug: http://b/155809792
---
 tests/chmod.test   |  7 +++++++
 toys/posix/chmod.c | 20 +++++++++++++-------
 2 files changed, 20 insertions(+), 7 deletions(-)
From 50b6712be54dd9b1e6e3e2691ee0f6f85ae78fff Mon Sep 17 00:00:00 2001
From: Elliott Hughes <e...@google.com>
Date: Tue, 9 Jun 2020 10:09:03 -0700
Subject: [PATCH] chmod: fix -R and dangling symlinks.

Found trying to run the libc++ tests.

For coreutils, `info chmod` says:

  'chmod' ignores symbolic links encountered during recursive directory
  traversals.

Bug: http://b/155809792
---
 tests/chmod.test   |  7 +++++++
 toys/posix/chmod.c | 20 +++++++++++++-------
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/tests/chmod.test b/tests/chmod.test
index b2b5a488..cbc32805 100755
--- a/tests/chmod.test
+++ b/tests/chmod.test
@@ -112,5 +112,12 @@ chtest u+s "drwsr-xr-x\n-rwSr--r--\n"
 chtest o+s "drwxr-xr-x\n-rw-r--r--\n"
 chtest +t  "drwxr-xr-t\n-rw-r--r-T\n"
 
+mkdir foo
+ln -s bar foo/baz
+# If you explicitly ask us, we'll try (and fail) to chmod a symlink.
+testing "-R symlink arg" 'chmod -R 750 foo/baz 2>/dev/null; echo $?' "1\n" "" ""
+# If you only imply that you might want us to do that, we'll skip it.
+testing "-R symlink recurse" 'chmod -R 750 foo; echo $?' "0\n" "" ""
+
 # Removing test files for cleanup purpose
 rm -rf dir file
diff --git a/toys/posix/chmod.c b/toys/posix/chmod.c
index ac53957c..3645ebc8 100644
--- a/toys/posix/chmod.c
+++ b/toys/posix/chmod.c
@@ -45,14 +45,20 @@ static int do_chmod(struct dirtree *try)
 
   if (!dirtree_notdotdot(try)) return 0;
 
-  mode = string_to_mode(TT.mode, try->st.st_mode);
-  if (FLAG(v)) {
-    char *s = dirtree_path(try, 0);
-
-    printf("chmod '%s' to %s\n", s, TT.mode);
-    free(s);
+  if (FLAG(R) && try->parent && S_ISLNK(try->st.st_mode)) {
+    // Ignore symlinks found during recursion. We'll only try to modify
+    // symlinks mentioned directly as arguments. We'll fail, of course,
+    // but that's what you asked for in that case.
+  } else {
+    mode = string_to_mode(TT.mode, try->st.st_mode);
+    if (FLAG(v)) {
+      char *s = dirtree_path(try, 0);
+
+      printf("chmod '%s' to %s\n", s, TT.mode);
+      free(s);
+    }
+    wfchmodat(dirtree_parentfd(try), try->name, mode);
   }
-  wfchmodat(dirtree_parentfd(try), try->name, mode);
 
   return FLAG(R)*DIRTREE_RECURSE;
 }
-- 
2.27.0.278.ge193c7cf3a9-goog

_______________________________________________
Toybox mailing list
Toybox@lists.landley.net
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to