diff options
author | Elliott Hughes <enh@google.com> | 2020-06-09 10:09:03 -0700 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2020-06-09 15:51:17 -0500 |
commit | a01cee764f620c154fcccb688d7b1a742f7f687e (patch) | |
tree | 79da293c0967092d0b92e5e880d03a9b6f2b6aaf | |
parent | 53b2ceac9af6c4bfd120a170617e3bded526b427 (diff) | |
download | toybox-a01cee764f620c154fcccb688d7b1a742f7f687e.tar.gz |
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
-rwxr-xr-x | tests/chmod.test | 7 | ||||
-rw-r--r-- | 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; } |