summaryrefslogtreecommitdiffstats
path: root/sysif.c
diff options
context:
space:
mode:
authorKaz Kyheku <kaz@kylheku.com>2020-02-07 21:45:48 -0800
committerKaz Kylheku <kaz@kylheku.com>2020-02-07 21:45:48 -0800
commita5fd4b908bf6ad193c5d68dfa3c0eda81aa7802a (patch)
tree00faf6357dcef9adb6b70af0fa75ea0461518160 /sysif.c
parent92d77f69a4224c50ced57b32844c0f464b137e92 (diff)
downloadtxr-a5fd4b908bf6ad193c5d68dfa3c0eda81aa7802a.tar.gz
txr-a5fd4b908bf6ad193c5d68dfa3c0eda81aa7802a.tar.bz2
txr-a5fd4b908bf6ad193c5d68dfa3c0eda81aa7802a.zip
chmod: bugfix and new tests.
* sysif.c (chmod_wrap): When processing set (=), only punch a hole in the target permission area once per clause, so as not to clobber previously set modes. We do this by checking for the chm_perm state. Whenever '=' is processed, the state machine enters into that state; when any permission letter is then processed, it transitions out of that state. This gets the "u=rwsx" test to pass. * tests/018/chmod.tl: New tests.
Diffstat (limited to 'sysif.c')
-rw-r--r--sysif.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/sysif.c b/sysif.c
index 286dcca6..ee219ff3 100644
--- a/sysif.c
+++ b/sysif.c
@@ -671,11 +671,13 @@ static val chmod_wrap(val target, val mode)
case chm_add: cmode |= bits; break;
case chm_sub: cmode &= ~bits; break;
case chm_set:
- cmode &= ~mask;
- if (implicit_all || (who & CHM_O) != 0)
- cmode &= ~S_ISVTX; /* GNU Coreutils 8.28 chmod behavior */
- if (!S_ISDIR(cmode))
- cmode &= ~(S_ISUID | S_ISGID);
+ if (cs == chm_perm) {
+ cmode &= ~mask;
+ if (implicit_all || (who & CHM_O) != 0)
+ cmode &= ~S_ISVTX; /* GNU Coreutils 8.28 chmod behavior */
+ if (!S_ISDIR(cmode))
+ cmode &= ~(S_ISUID | S_ISGID);
+ }
cmode |= bits;
break;
}