diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2021-01-15 02:57:59 -0800 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2021-01-15 02:59:24 -0800 |
commit | e9789a1cf2d9a1fd5bc4177b8f27f0a93ff2ed78 (patch) | |
tree | 1b4555b97fdafcff54ce48d452d783c3589b8eb3 | |
parent | 06f70d9ee69163fb2b18647963d6d6e81b6bd35d (diff) |
mkdir: fix bug when -m's more generous than umask
Problem reported by David McCall (Bug#45886).
I introduced this problem when fixing Bug#14371.
* NEWS: Mention the fix.
* src/mkdir.c (struct mkdir_options): New members umask_ancestor,
umask_self, replacing umask_value.
(make_ancestor): Use them when temporarily adjusting umask.
(main): Set them, and set the umask to umask_self instead
of leaving it alone.
* tests/mkdir/perm.sh (tests): Add test case for bug.
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | src/mkdir.c | 30 | ||||
-rwxr-xr-x | tests/mkdir/perm.sh | 1 |
3 files changed, 22 insertions, 12 deletions
@@ -20,6 +20,9 @@ GNU coreutils NEWS -*- outline -*- ls no longer crashes when printing the SELinux context for unstatable files. [bug introduced in coreutils-6.9.91] + mkdir -m no longer mishandles modes more generous than the umask. + [bug introduced in coreutils-8.22] + nl now handles single character --section-delimiter arguments, by assuming a second ':' character has been specified, as specified by POSIX. [This bug was present in "the beginning".] diff --git a/src/mkdir.c b/src/mkdir.c index eccc9d382..b266cee8c 100644 --- a/src/mkdir.c +++ b/src/mkdir.c @@ -89,8 +89,11 @@ struct mkdir_options made. */ int (*make_ancestor_function) (char const *, char const *, void *); - /* Umask value in effect. */ - mode_t umask_value; + /* Umask value for when making an ancestor. */ + mode_t umask_ancestor; + + /* Umask value for when making the directory itself. */ + mode_t umask_self; /* Mode for directory itself. */ mode_t mode; @@ -130,20 +133,18 @@ make_ancestor (char const *dir, char const *component, void *options) error (0, errno, _("failed to set default creation context for %s"), quoteaf (dir)); - mode_t user_wx = S_IWUSR | S_IXUSR; - bool self_denying_umask = (o->umask_value & user_wx) != 0; - if (self_denying_umask) - umask (o->umask_value & ~user_wx); + if (o->umask_ancestor != o->umask_self) + umask (o->umask_ancestor); int r = mkdir (component, S_IRWXUGO); - if (self_denying_umask) + if (o->umask_ancestor != o->umask_self) { int mkdir_errno = errno; - umask (o->umask_value); + umask (o->umask_self); errno = mkdir_errno; } if (r == 0) { - r = (o->umask_value & S_IRUSR) != 0; + r = (o->umask_ancestor & S_IRUSR) != 0; announce_mkdir (dir, options); } return r; @@ -282,8 +283,7 @@ main (int argc, char **argv) if (options.make_ancestor_function || specified_mode) { mode_t umask_value = umask (0); - umask (umask_value); - options.umask_value = umask_value; + options.umask_ancestor = umask_value & ~(S_IWUSR | S_IXUSR); if (specified_mode) { @@ -293,10 +293,16 @@ main (int argc, char **argv) quote (specified_mode)); options.mode = mode_adjust (S_IRWXUGO, true, umask_value, change, &options.mode_bits); + options.umask_self = umask_value & ~options.mode; free (change); } else - options.mode = S_IRWXUGO; + { + options.mode = S_IRWXUGO; + options.umask_self = umask_value; + } + + umask (options.umask_self); } return savewd_process_files (argc - optind, argv + optind, diff --git a/tests/mkdir/perm.sh b/tests/mkdir/perm.sh index 4d36f19b5..083a47733 100755 --- a/tests/mkdir/perm.sh +++ b/tests/mkdir/perm.sh @@ -35,6 +35,7 @@ tests=' 050 : -m 312 : drwx-w-rwx : d-wx--x-w- : 160 : empty : drwx--xrwx : drw---xrwx : 160 : -m 743 : drwx--xrwx : drwxr---wx : + 022 : -m o-w : drwxr-xr-x : drwxrwxr-x : 027 : -m =+x : drwxr-x--- : d--x--x--- : 027 : -m =+X : drwxr-x--- : d--x--x--- : - : - : last : last : |