diff options
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | src/mkdir.c | 25 | ||||
-rw-r--r-- | src/mkfifo.c | 11 | ||||
-rw-r--r-- | src/mknod.c | 9 | ||||
-rw-r--r-- | tests/local.mk | 1 | ||||
-rwxr-xr-x | tests/mkdir/p-acl.sh | 35 |
6 files changed, 77 insertions, 9 deletions
@@ -13,6 +13,11 @@ GNU coreutils NEWS -*- outline -*- the relative link on the dereferenced path of an existing link. [This bug was introduced when --relative was added in coreutils-8.16.] + mkdir, mkfifo, and mknod now work better when creating a file in a directory + with a default ACL whose umask disagrees with the process's umask, on a + system such as GNU/Linux where directory ACL umasks override process umasks. + [bug introduced in coreutils-6.0] + tail --retry -f now waits for the files specified to appear. Before, tail would immediately exit when such a file is inaccessible during the initial open. diff --git a/src/mkdir.c b/src/mkdir.c index a94f96e14..b36237a33 100644 --- a/src/mkdir.c +++ b/src/mkdir.c @@ -81,8 +81,8 @@ struct mkdir_options made. */ int (*make_ancestor_function) (char const *, char const *, void *); - /* Mode for ancestor directory. */ - mode_t ancestor_mode; + /* Umask value in effect. */ + mode_t umask_value; /* Mode for directory itself. */ mode_t mode; @@ -112,10 +112,21 @@ static int make_ancestor (char const *dir, char const *component, void *options) { struct mkdir_options const *o = options; - int r = mkdir (component, o->ancestor_mode); + int r; + 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); + r = mkdir (component, S_IRWXUGO); + if (self_denying_umask) + { + int mkdir_errno = errno; + umask (o->umask_value); + errno = mkdir_errno; + } if (r == 0) { - r = ! (o->ancestor_mode & S_IRUSR); + r = (o->umask_value & S_IRUSR) != 0; announce_mkdir (dir, options); } return r; @@ -191,8 +202,8 @@ main (int argc, char **argv) if (options.make_ancestor_function || specified_mode) { mode_t umask_value = umask (0); - - options.ancestor_mode = (S_IRWXUGO & ~umask_value) | (S_IWUSR | S_IXUSR); + umask (umask_value); + options.umask_value = umask_value; if (specified_mode) { @@ -205,7 +216,7 @@ main (int argc, char **argv) free (change); } else - options.mode = S_IRWXUGO & ~umask_value; + options.mode = S_IRWXUGO; } exit (savewd_process_files (argc - optind, argv + optind, diff --git a/src/mkfifo.c b/src/mkfifo.c index 76291e5bc..78ff909cc 100644 --- a/src/mkfifo.c +++ b/src/mkfifo.c @@ -116,10 +116,13 @@ main (int argc, char **argv) newmode = MODE_RW_UGO; if (specified_mode) { + mode_t umask_value; struct mode_change *change = mode_compile (specified_mode); if (!change) error (EXIT_FAILURE, 0, _("invalid mode")); - newmode = mode_adjust (newmode, false, umask (0), change, NULL); + umask_value = umask (0); + umask (umask_value); + newmode = mode_adjust (newmode, false, umask_value, change, NULL); free (change); if (newmode & ~S_IRWXUGO) error (EXIT_FAILURE, 0, @@ -132,6 +135,12 @@ main (int argc, char **argv) error (0, errno, _("cannot create fifo %s"), quote (argv[optind])); exit_status = EXIT_FAILURE; } + else if (specified_mode && lchmod (argv[optind], newmode) != 0) + { + error (0, errno, _("cannot set permissions of `%s'"), + quote (argv[optind])); + exit_status = EXIT_FAILURE; + } exit (exit_status); } diff --git a/src/mknod.c b/src/mknod.c index 7cfc708d3..a384ad35c 100644 --- a/src/mknod.c +++ b/src/mknod.c @@ -122,10 +122,13 @@ main (int argc, char **argv) newmode = MODE_RW_UGO; if (specified_mode) { + mode_t umask_value; struct mode_change *change = mode_compile (specified_mode); if (!change) error (EXIT_FAILURE, 0, _("invalid mode")); - newmode = mode_adjust (newmode, false, umask (0), change, NULL); + umask_value = umask (0); + umask (umask_value); + newmode = mode_adjust (newmode, false, umask_value, change, NULL); free (change); if (newmode & ~S_IRWXUGO) error (EXIT_FAILURE, 0, @@ -226,5 +229,9 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } + if (specified_mode && lchmod (argv[optind], newmode) != 0) + error (EXIT_FAILURE, errno, _("cannot set permissions of `%s'"), + quote (argv[optind])); + exit (EXIT_SUCCESS); } diff --git a/tests/local.mk b/tests/local.mk index fb5cc63b6..5ec7d9859 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -555,6 +555,7 @@ all_tests = \ tests/mkdir/p-1.sh \ tests/mkdir/p-2.sh \ tests/mkdir/p-3.sh \ + tests/mkdir/p-acl.sh \ tests/mkdir/p-slashdot.sh \ tests/mkdir/p-thru-slink.sh \ tests/mkdir/p-v.sh \ diff --git a/tests/mkdir/p-acl.sh b/tests/mkdir/p-acl.sh new file mode 100755 index 000000000..f1be628a2 --- /dev/null +++ b/tests/mkdir/p-acl.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# Test "mkdir -p" with default ACLs. + +# Copyright (C) 1997-2013 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mkdir + +require_setfacl_ + +mkdir d || framework_failure_ +setfacl -d -m group::rwx d || framework_failure_ +umask 077 + +mkdir --parents d/e || fail=1 +ls_l=$(ls -ld d/e) || fail=1 +case $ls_l in + d???rw[sx]*) ;; + *) fail=1 ;; +esac + +Exit $fail |