diff options
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | src/chmod.c | 11 | ||||
-rwxr-xr-x | tests/chmod/c-option.sh | 11 |
3 files changed, 21 insertions, 4 deletions
@@ -4,6 +4,9 @@ GNU coreutils NEWS -*- outline -*- ** Bug fixes + chmod -Rc no longer issues erroneous warnings for files with special bits set. + [bug introduced in coreutils-6.0] + cp -a, mv, and install --preserve-context, once again set the correct SELinux context for existing directories in the destination. Previously they set the context of an existing directory to that of its last copied descendent. diff --git a/src/chmod.c b/src/chmod.c index 81bf4b227..756ec5a46 100644 --- a/src/chmod.c +++ b/src/chmod.c @@ -111,7 +111,8 @@ static struct option const long_options[] = The old mode was OLD_MODE, but it was changed to NEW_MODE. */ static bool -mode_changed (char const *file, mode_t old_mode, mode_t new_mode) +mode_changed (int dir_fd, char const *file, char const *file_full_name, + mode_t old_mode, mode_t new_mode) { if (new_mode & (S_ISUID | S_ISGID | S_ISVTX)) { @@ -120,10 +121,11 @@ mode_changed (char const *file, mode_t old_mode, mode_t new_mode) struct stat new_stats; - if (stat (file, &new_stats) != 0) + if (fstatat (dir_fd, file, &new_stats, 0) != 0) { if (! force_silent) - error (0, errno, _("getting new attributes of %s"), quote (file)); + error (0, errno, _("getting new attributes of %s"), + quote (file_full_name)); return false; } @@ -283,7 +285,8 @@ process_file (FTS *fts, FTSENT *ent) if (verbosity != V_off) { bool changed = (chmod_succeeded - && mode_changed (file, old_mode, new_mode)); + && mode_changed (fts->fts_cwd_fd, file, file_full_name, + old_mode, new_mode)); if (changed || verbosity == V_high) { diff --git a/tests/chmod/c-option.sh b/tests/chmod/c-option.sh index 1dd9b9ea7..a1782c3d8 100755 --- a/tests/chmod/c-option.sh +++ b/tests/chmod/c-option.sh @@ -37,4 +37,15 @@ case "$(cat out)" in *) cat out; fail=1 ;; esac +# From V5.1.0 to 8.22 this would stat the wrong file and +# give an erroneous ENOENT diagnostic +mkdir -p a/b || framework_failure_ +# chmod g+s might fail as detailed in setgid.sh +# but we don't care about those edge cases here +chmod g+s a/b +# This should never warn, but it did when special +# bits are set on b (the common case under test) +chmod -c -R g+w a 2>err +compare /dev/null err || fail=1 + Exit $fail |