summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS5
-rw-r--r--src/mkdir.c25
-rw-r--r--src/mkfifo.c11
-rw-r--r--src/mknod.c9
-rw-r--r--tests/local.mk1
-rwxr-xr-xtests/mkdir/p-acl.sh35
6 files changed, 77 insertions, 9 deletions
diff --git a/NEWS b/NEWS
index ae6251de2..eec93dfd0 100644
--- a/NEWS
+++ b/NEWS
@@ -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