summaryrefslogtreecommitdiffstats
path: root/src/parse.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2024-07-30 16:44:17 -0400
committerTavian Barnes <tavianator@tavianator.com>2024-08-02 17:18:26 -0400
commit6290ce41f3ec1f889abb881cf90ca91da869b5b2 (patch)
tree679b1717100bd9f4c693d9d8b9463d51b195fd6c /src/parse.c
parentb8a008dc9b84804d8b2c751daa9c04bd86d5e59c (diff)
downloadbfs-6290ce41f3ec1f889abb881cf90ca91da869b5b2.tar.xz
parse: Take umask into account in parse_mode()
POSIX 2024 clarified that find(1) is meant to work exactly like chmod(1) here, so for modes like +rw,-x with no "who" specified, apply the umask. Link: https://www.austingroupbugs.net/view.php?id=1392
Diffstat (limited to 'src/parse.c')
-rw-r--r--src/parse.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/src/parse.c b/src/parse.c
index c6030e7..6a1b34c 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1901,6 +1901,8 @@ static int parse_mode(const struct bfs_parser *parser, const char *mode, struct
return 0;
}
+ mode_t umask = parser->ctx->umask;
+
expr->file_mode = 0;
expr->dir_mode = 0;
@@ -1938,6 +1940,7 @@ static int parse_mode(const struct bfs_parser *parser, const char *mode, struct
} op uninit(MODE_EQUALS);
mode_t who uninit(0);
+ mode_t mask uninit(0);
mode_t file_change uninit(0);
mode_t dir_change uninit(0);
@@ -1946,6 +1949,7 @@ static int parse_mode(const struct bfs_parser *parser, const char *mode, struct
switch (state) {
case MODE_CLAUSE:
who = 0;
+ mask = 0777;
state = MODE_WHO;
fallthru;
@@ -1989,6 +1993,9 @@ static int parse_mode(const struct bfs_parser *parser, const char *mode, struct
case MODE_ACTION:
if (who == 0) {
who = 0777;
+ mask = who & ~umask;
+ } else {
+ mask = who;
}
switch (*i) {
@@ -2048,27 +2055,27 @@ static int parse_mode(const struct bfs_parser *parser, const char *mode, struct
}
file_change |= (file_change << 6) | (file_change << 3);
- file_change &= who;
+ file_change &= mask;
dir_change |= (dir_change << 6) | (dir_change << 3);
- dir_change &= who;
+ dir_change &= mask;
state = MODE_ACTION_APPLY;
break;
case MODE_PERM:
switch (*i) {
case 'r':
- file_change |= who & 0444;
- dir_change |= who & 0444;
+ file_change |= mask & 0444;
+ dir_change |= mask & 0444;
break;
case 'w':
- file_change |= who & 0222;
- dir_change |= who & 0222;
+ file_change |= mask & 0222;
+ dir_change |= mask & 0222;
break;
case 'x':
- file_change |= who & 0111;
+ file_change |= mask & 0111;
fallthru;
case 'X':
- dir_change |= who & 0111;
+ dir_change |= mask & 0111;
break;
case 's':
if (who & 0700) {