>From f845b1742ce2f06dd8b6a6fe94e3881f7cd0ff4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Va=C5=A1=C3=ADk?= Date: Mon, 5 Mar 2012 10:34:13 +0100 Subject: [PATCH] modechange: Allow cleaning of special bits on dirs when requested As discussed in coreutils bug #8391 and rhbz #691466, some users miss the functionality of cleaning set user id and set group id dir bits by exact octal mode. This functionality was removed by 4e3c4c0478e6e1e81f093b80d8272840a39ca2bd gnulib commit and this patch allows it for 5+ digits octal modes or octal modes preceeded by "@" character. * lib/modechange.c: Allow cleaning of special bits on dirs. (enum): Add new mode flag - MODE_EXACT_CHANGE. (mode_compile): Use MODE_EXACT_CHANGE for 5+ digits octals and octal mode preceeded by @. (mode_adjust): Don't mask the special bit change for MODE_EXACT_CHANGE. --- ChangeLog | 8 ++++++++ lib/modechange.c | 21 ++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4ec700f..54b9ffb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2012-03-04 Ondrej Vasik + modechange: Allow cleaning of special bits on dirs when requested + * lib/modechange.c: Allow cleaning of special bits on dirs. + (enum): Add new mode flag - MODE_EXACT_CHANGE. + (mode_compile): Use MODE_EXACT_CHANGE for 5+ digits octals and octal + mode preceeded by @. + (mode_adjust): Don't mask the special bit change for MODE_EXACT_CHANGE. + 2012-03-04 Bruno Haible sqrt* tests: More tests. diff --git a/lib/modechange.c b/lib/modechange.c index 4ae90ca..a4741ac 100644 --- a/lib/modechange.c +++ b/lib/modechange.c @@ -32,6 +32,7 @@ #include "stat-macros.h" #include "xalloc.h" #include +#include /* The traditional octal values corresponding to each mode bit. */ #define SUID 04000 @@ -91,7 +92,11 @@ enum /* Instead of the typical case, copy some existing permissions for u, g, or o onto the other two. Which of u, g, or o is copied is determined by which bits are set in the 'value' field. */ - MODE_COPY_EXISTING + MODE_COPY_EXISTING, + + /* Instead of the typical case, we want to enforce the exact + requested mode */ + MODE_EXACT_CHANGE }; /* Description of a mode change. */ @@ -136,6 +141,10 @@ mode_compile (char const *mode_string) /* The array of mode-change directives to be returned. */ struct mode_change *mc; size_t used = 0; + bool exact_change = (strlen(mode_string) > 4 || '@' == *mode_string); + + if ('@' == *mode_string) + mode_string++; if ('0' <= *mode_string && *mode_string < '8') { @@ -156,7 +165,11 @@ mode_compile (char const *mode_string) mode = octal_to_mode (octal_mode); mentioned = (mode & (S_ISUID | S_ISGID)) | S_ISVTX | S_IRWXUGO; - return make_node_op_equals (mode, mentioned); + + mc = make_node_op_equals (mode, mentioned); + if (exact_change) + mc->flag = MODE_EXACT_CHANGE; + return mc; } /* Allocate enough space to hold the result. */ @@ -320,11 +333,13 @@ mode_adjust (mode_t oldmode, bool dir, mode_t umask_value, { mode_t affected = changes->affected; mode_t omit_change = - (dir ? S_ISUID | S_ISGID : 0) & ~ changes->mentioned; + ((dir && changes->flag != MODE_EXACT_CHANGE) ? + S_ISUID | S_ISGID : 0) & ~ changes->mentioned; mode_t value = changes->value; switch (changes->flag) { + case MODE_EXACT_CHANGE: case MODE_ORDINARY_CHANGE: break; -- 1.7.1