aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xadmin/merge-gnulib2
-rw-r--r--doc/misc/texinfo.tex3
-rw-r--r--lib/acl-internal.c31
-rw-r--r--lib/acl-internal.h57
-rw-r--r--lib/get-permissions.c280
-rw-r--r--lib/gnulib.mk23
-rw-r--r--lib/inttypes.in.h4
-rw-r--r--lib/qcopy-acl.c531
-rw-r--r--lib/set-permissions.c (renamed from lib/qset-acl.c)805
-rw-r--r--lib/string.in.h21
-rw-r--r--m4/acl.m424
-rw-r--r--m4/gnulib-comp.m48
-rw-r--r--m4/stdio_h.m420
-rw-r--r--nt/gnulib.mk23
14 files changed, 924 insertions, 908 deletions
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index e63422b0d5e..e7910a642c7 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -34,7 +34,7 @@ GNULIB_MODULES='
34 getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog 34 getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog
35 intprops largefile lstat 35 intprops largefile lstat
36 manywarnings memrchr mkostemp mktime 36 manywarnings memrchr mkostemp mktime
37 pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat 37 pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat
38 sig2str socklen stat-time stdalign stddef stdio 38 sig2str socklen stat-time stdalign stddef stdio
39 stpcpy strftime strtoimax strtoumax symlink sys_stat 39 stpcpy strftime strtoimax strtoumax symlink sys_stat
40 sys_time time time_r timer-time timespec-add timespec-sub 40 sys_time time time_r timer-time timespec-add timespec-sub
diff --git a/doc/misc/texinfo.tex b/doc/misc/texinfo.tex
index 152e9853485..4b4856469a8 100644
--- a/doc/misc/texinfo.tex
+++ b/doc/misc/texinfo.tex
@@ -3,7 +3,7 @@
3% Load plain if necessary, i.e., if running under initex. 3% Load plain if necessary, i.e., if running under initex.
4\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi 4\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
5% 5%
6\def\texinfoversion{2015-05-06.11} 6\def\texinfoversion{2015-05-26.15}
7% 7%
8% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, 8% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
9% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 9% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
@@ -8954,7 +8954,6 @@ directory should work if nowhere else does.}
8954 \catcode\count255=#1\relax 8954 \catcode\count255=#1\relax
8955 \advance\count255 by 1 8955 \advance\count255 by 1
8956 \repeat 8956 \repeat
8957
8958} 8957}
8959 8958
8960% @documentencoding sets the definition of non-ASCII characters 8959% @documentencoding sets the definition of non-ASCII characters
diff --git a/lib/acl-internal.c b/lib/acl-internal.c
index d9bd4461ea6..1a2f8c44bf7 100644
--- a/lib/acl-internal.c
+++ b/lib/acl-internal.c
@@ -467,3 +467,34 @@ acl_nontrivial (int count, struct acl *entries)
467} 467}
468 468
469#endif 469#endif
470
471void
472free_permission_context (struct permission_context *ctx)
473{
474#ifdef USE_ACL
475# if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
476 if (ctx->acl)
477 acl_free (ctx->acl);
478# if !HAVE_ACL_TYPE_EXTENDED
479 if (ctx->default_acl)
480 acl_free (ctx->default_acl);
481# endif
482
483# elif defined GETACL /* Solaris, Cygwin */
484 free (ctx->entries);
485# ifdef ACE_GETACL
486 free (ctx->ace_entries);
487# endif
488
489# elif HAVE_GETACL /* HP-UX */
490
491# if HAVE_ACLV_H
492# endif
493
494# elif HAVE_STATACL /* older AIX */
495
496# elif HAVE_ACLSORT /* NonStop Kernel */
497
498# endif
499#endif
500}
diff --git a/lib/acl-internal.h b/lib/acl-internal.h
index 9b9fae2e9e0..11fdea14042 100644
--- a/lib/acl-internal.h
+++ b/lib/acl-internal.h
@@ -133,12 +133,9 @@ rpl_acl_set_fd (int fd, acl_t acl)
133# define acl_from_mode(mode) (NULL) 133# define acl_from_mode(mode) (NULL)
134# endif 134# endif
135 135
136/* Set to 1 if a file's mode is implicit by the ACL. 136/* Set to 0 if a file's mode is stored independently from the ACL. */
137 Set to 0 if a file's mode is stored independently from the ACL. */
138# if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */ 137# if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */
139# define MODE_INSIDE_ACL 0 138# define MODE_INSIDE_ACL 0
140# else
141# define MODE_INSIDE_ACL 1
142# endif 139# endif
143 140
144/* Return the number of entries in ACL. 141/* Return the number of entries in ACL.
@@ -164,12 +161,9 @@ extern int acl_access_nontrivial (acl_t);
164 161
165# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ 162# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
166 163
167/* Set to 1 if a file's mode is implicit by the ACL. 164/* Set to 0 if a file's mode is stored independently from the ACL. */
168 Set to 0 if a file's mode is stored independently from the ACL. */
169# if defined __CYGWIN__ /* Cygwin */ 165# if defined __CYGWIN__ /* Cygwin */
170# define MODE_INSIDE_ACL 0 166# define MODE_INSIDE_ACL 0
171# else /* Solaris */
172# define MODE_INSIDE_ACL 1
173# endif 167# endif
174 168
175/* Return 1 if the given ACL is non-trivial. 169/* Return 1 if the given ACL is non-trivial.
@@ -248,6 +242,53 @@ extern int acl_nontrivial (int count, struct acl *entries);
248 242
249# endif 243# endif
250 244
245/* Set to 1 if a file's mode is implicit by the ACL. */
246# ifndef MODE_INSIDE_ACL
247# define MODE_INSIDE_ACL 1
248# endif
249
251#endif 250#endif
252 251
252struct permission_context {
253 mode_t mode;
254#ifdef USE_ACL
255# if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
256 acl_t acl;
257# if !HAVE_ACL_TYPE_EXTENDED
258 acl_t default_acl;
259# endif
260 bool acls_not_supported;
261
262# elif defined GETACL /* Solaris, Cygwin */
263 int count;
264 aclent_t *entries;
265# ifdef ACE_GETACL
266 int ace_count;
267 ace_t *ace_entries;
268# endif
269
270# elif HAVE_GETACL /* HP-UX */
271 struct acl_entry entries[NACLENTRIES];
272 int count;
273# if HAVE_ACLV_H
274 struct acl aclv_entries[NACLVENTRIES];
275 int aclv_count;
276# endif
277
278# elif HAVE_STATACL /* older AIX */
279 union { struct acl a; char room[4096]; } u;
280 bool have_u;
281
282# elif HAVE_ACLSORT /* NonStop Kernel */
283 struct acl entries[NACLENTRIES];
284 int count;
285
286# endif
287#endif
288};
289
290int get_permissions (const char *, int, mode_t, struct permission_context *);
291int set_permissions (struct permission_context *, const char *, int);
292void free_permission_context (struct permission_context *);
293
253_GL_INLINE_HEADER_END 294_GL_INLINE_HEADER_END
diff --git a/lib/get-permissions.c b/lib/get-permissions.c
new file mode 100644
index 00000000000..ccee1f1410e
--- /dev/null
+++ b/lib/get-permissions.c
@@ -0,0 +1,280 @@
1/* get-permissions.c - get permissions of a file
2
3 Copyright (C) 2002-2003, 2005-2015 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
19
20#include <config.h>
21
22#include <string.h>
23#include "acl.h"
24
25#include "acl-internal.h"
26
27/* Read the permissions of a file into CTX. If DESC is a valid file descriptor,
28 use file descriptor operations, else use filename based operations on NAME.
29 MODE is the file mode obtained from a previous stat call.
30 Return 0 if successful. Return -1 and set errno upon failure. */
31
32int
33get_permissions (const char *name, int desc, mode_t mode,
34 struct permission_context *ctx)
35{
36 memset (ctx, 0, sizeof(*ctx));
37 ctx->mode = mode;
38
39#if USE_ACL && HAVE_ACL_GET_FILE
40 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
41 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
42# if !HAVE_ACL_TYPE_EXTENDED
43 /* Linux, FreeBSD, IRIX, Tru64 */
44
45 if (HAVE_ACL_GET_FD && desc != -1)
46 ctx->acl = acl_get_fd (desc);
47 else
48 ctx->acl = acl_get_file (name, ACL_TYPE_ACCESS);
49 if (ctx->acl == NULL)
50 return acl_errno_valid (errno) ? -1 : 0;
51
52 /* With POSIX ACLs, a file cannot have "no" acl; a file without
53 extended permissions has a "minimal" acl which is equivalent to the
54 file mode. */
55
56 if (S_ISDIR (mode))
57 {
58 ctx->default_acl = acl_get_file (name, ACL_TYPE_DEFAULT);
59 if (ctx->default_acl == NULL)
60 return -1;
61 }
62
63# else /* HAVE_ACL_TYPE_EXTENDED */
64 /* Mac OS X */
65
66 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
67 and acl_get_file (name, ACL_TYPE_DEFAULT)
68 always return NULL / EINVAL. You have to use
69 acl_get_file (name, ACL_TYPE_EXTENDED)
70 or acl_get_fd (open (name, ...))
71 to retrieve an ACL.
72 On the other hand,
73 acl_set_file (name, ACL_TYPE_ACCESS, acl)
74 and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
75 have the same effect as
76 acl_set_file (name, ACL_TYPE_EXTENDED, acl):
77 Each of these calls sets the file's ACL. */
78
79 if (HAVE_ACL_GET_FD && desc != -1)
80 ctx->acl = acl_get_fd (desc);
81 else
82 ctx->acl = acl_get_file (name, ACL_TYPE_EXTENDED);
83 if (ctx->acl == NULL)
84 return acl_errno_valid (errno) ? -1 : 0;
85
86# endif
87
88#elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
89
90 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
91 of Unixware. The acl() call returns the access and default ACL both
92 at once. */
93# ifdef ACE_GETACL
94 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
95 file systems (whereas the other ones are used in UFS file systems).
96 There is an API
97 pathconf (name, _PC_ACL_ENABLED)
98 fpathconf (desc, _PC_ACL_ENABLED)
99 that allows to determine which of the two kinds of ACLs is supported
100 for the given file. But some file systems may implement this call
101 incorrectly, so better not use it.
102 When fetching the source ACL, we simply fetch both ACL types.
103 When setting the destination ACL, we try either ACL types, assuming
104 that the kernel will translate the ACL from one form to the other.
105 (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
106 the description of ENOTSUP.) */
107 for (;;)
108 {
109 int ret;
110
111 if (desc != -1)
112 ret = facl (desc, ACE_GETACLCNT, 0, NULL);
113 else
114 ret = acl (name, ACE_GETACLCNT, 0, NULL);
115 if (ret < 0)
116 {
117 if (errno == ENOSYS || errno == EINVAL)
118 ret = 0;
119 else
120 return -1;
121 }
122 ctx->ace_count = ret;
123
124 if (ctx->ace_count == 0)
125 break;
126
127 ctx->ace_entries = (ace_t *) malloc (ctx->ace_count * sizeof (ace_t));
128 if (ctx->ace_entries == NULL)
129 {
130 errno = ENOMEM;
131 return -1;
132 }
133
134 if (desc != -1)
135 ret = facl (desc, ACE_GETACL, ctx->ace_count, ctx->ace_entries);
136 else
137 ret = acl (name, ACE_GETACL, ctx->ace_count, ctx->ace_entries);
138 if (ret < 0)
139 {
140 if (errno == ENOSYS || errno == EINVAL)
141 {
142 free (ctx->ace_entries);
143 ctx->ace_entries = NULL;
144 ctx->ace_count = 0;
145 break;
146 }
147 else
148 return -1;
149 }
150 if (ret <= ctx->ace_count)
151 {
152 ctx->ace_count = ret;
153 break;
154 }
155 /* Huh? The number of ACL entries has increased since the last call.
156 Repeat. */
157 free (ctx->ace_entries);
158 ctx->ace_entries = NULL;
159 }
160# endif
161
162 for (;;)
163 {
164 int ret;
165
166 if (desc != -1)
167 ret = facl (desc, GETACLCNT, 0, NULL);
168 else
169 ret = acl (name, GETACLCNT, 0, NULL);
170 if (ret < 0)
171 {
172 if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
173 ret = 0;
174 else
175 return -1;
176 }
177 ctx->count = ret;
178
179 if (ctx->count == 0)
180 break;
181
182 ctx->entries = (aclent_t *) malloc (ctx->count * sizeof (aclent_t));
183 if (ctx->entries == NULL)
184 {
185 errno = ENOMEM;
186 return -1;
187 }
188
189 if (desc != -1)
190 ret = facl (desc, GETACL, ctx->count, ctx->entries);
191 else
192 ret = acl (name, GETACL, ctx->count, ctx->entries);
193 if (ret < 0)
194 {
195 if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
196 {
197 free (ctx->entries);
198 ctx->entries = NULL;
199 ctx->count = 0;
200 break;
201 }
202 else
203 return -1;
204 }
205 if (ret <= ctx->count)
206 {
207 ctx->count = ret;
208 break;
209 }
210 /* Huh? The number of ACL entries has increased since the last call.
211 Repeat. */
212 free (ctx->entries);
213 ctx->entries = NULL;
214 }
215
216#elif USE_ACL && HAVE_GETACL /* HP-UX */
217
218 int ret;
219
220 if (desc != -1)
221 ret = fgetacl (desc, NACLENTRIES, ctx->entries);
222 else
223 ret = getacl (name, NACLENTRIES, ctx->entries);
224 if (ret < 0)
225 {
226 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
227 ret = 0;
228 else
229 return -1;
230 }
231 else if (ret > NACLENTRIES)
232 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
233 abort ();
234 ctx->count = ret;
235
236# if HAVE_ACLV_H
237 ret = acl ((char *) name, ACL_GET, NACLVENTRIES, ctx->aclv_entries);
238 if (ret < 0)
239 {
240 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
241 ret = 0;
242 else
243 return -2;
244 }
245 else if (ret > NACLVENTRIES)
246 /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
247 abort ();
248 ctx->aclv_count = ret;
249# endif
250
251#elif USE_ACL && HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
252
253 /* TODO (see set_permissions). */
254
255#elif USE_ACL && HAVE_STATACL /* older AIX */
256
257 if (desc != -1)
258 ret = fstatacl (desc, STX_NORMAL, &ctx->u.a, sizeof (ctx->u));
259 else
260 ret = statacl (name, STX_NORMAL, &ctx->u.a, sizeof (ctx->u));
261 if (ret == 0)
262 ctx->have_u = true;
263
264#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
265
266 int ret;
267
268 ret = acl ((char *) name, ACL_GET, NACLENTRIES, ctx->entries);
269 if (ret < 0)
270 return -1;
271 else if (ret > NACLENTRIES)
272 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
273 abort ();
274 ctx->count = ret;
275
276#endif
277
278 return 0;
279
280}
diff --git a/lib/gnulib.mk b/lib/gnulib.mk
index bec0d3bb19b..95f2f8b48a6 100644
--- a/lib/gnulib.mk
+++ b/lib/gnulib.mk
@@ -21,7 +21,7 @@
21# the same distribution terms as the rest of that program. 21# the same distribution terms as the rest of that program.
22# 22#
23# Generated by gnulib-tool. 23# Generated by gnulib-tool.
24# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings 24# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings
25 25
26 26
27MOSTLYCLEANFILES += core *.stackdump 27MOSTLYCLEANFILES += core *.stackdump
@@ -42,6 +42,17 @@ HAVE_INCLUDE_NEXT = (__GNUC__ || 60000000 <= __DECC_VER)
42 42
43## end gnulib module absolute-header 43## end gnulib module absolute-header
44 44
45## begin gnulib module acl-permissions
46
47libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c \
48 get-permissions.c set-permissions.c
49
50EXTRA_DIST += acl-internal.h acl.h acl_entries.c
51
52EXTRA_libgnu_a_SOURCES += acl_entries.c
53
54## end gnulib module acl-permissions
55
45## begin gnulib module alloca-opt 56## begin gnulib module alloca-opt
46 57
47BUILT_SOURCES += $(ALLOCA_H) 58BUILT_SOURCES += $(ALLOCA_H)
@@ -696,15 +707,11 @@ EXTRA_libgnu_a_SOURCES += putenv.c
696 707
697## end gnulib module putenv 708## end gnulib module putenv
698 709
699## begin gnulib module qacl 710## begin gnulib module qcopy-acl
700
701libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c qcopy-acl.c qset-acl.c
702 711
703EXTRA_DIST += acl-internal.h acl.h acl_entries.c 712libgnu_a_SOURCES += qcopy-acl.c
704
705EXTRA_libgnu_a_SOURCES += acl_entries.c
706 713
707## end gnulib module qacl 714## end gnulib module qcopy-acl
708 715
709## begin gnulib module readlink 716## begin gnulib module readlink
710 717
diff --git a/lib/inttypes.in.h b/lib/inttypes.in.h
index 13a72bee90c..78846f69683 100644
--- a/lib/inttypes.in.h
+++ b/lib/inttypes.in.h
@@ -51,6 +51,10 @@
51#endif 51#endif
52/* Get CHAR_BIT. */ 52/* Get CHAR_BIT. */
53#include <limits.h> 53#include <limits.h>
54/* On mingw, __USE_MINGW_ANSI_STDIO only works if <stdio.h> is also included */
55#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
56# include <stdio.h>
57#endif
54 58
55#if !(INT_MIN == INT32_MIN && INT_MAX == INT32_MAX) 59#if !(INT_MIN == INT32_MIN && INT_MAX == INT32_MAX)
56# error "This file assumes that 'int' has exactly 32 bits. Please report your platform and compiler to <bug-gnulib@gnu.org>." 60# error "This file assumes that 'int' has exactly 32 bits. Please report your platform and compiler to <bug-gnulib@gnu.org>."
diff --git a/lib/qcopy-acl.c b/lib/qcopy-acl.c
index bc258ba560b..c4507424719 100644
--- a/lib/qcopy-acl.c
+++ b/lib/qcopy-acl.c
@@ -39,534 +39,13 @@ int
39qcopy_acl (const char *src_name, int source_desc, const char *dst_name, 39qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
40 int dest_desc, mode_t mode) 40 int dest_desc, mode_t mode)
41{ 41{
42#if USE_ACL && HAVE_ACL_GET_FILE 42 struct permission_context ctx;
43 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
44 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
45# if !HAVE_ACL_TYPE_EXTENDED
46 /* Linux, FreeBSD, IRIX, Tru64 */
47
48 acl_t acl;
49 int ret;
50
51 if (HAVE_ACL_GET_FD && source_desc != -1)
52 acl = acl_get_fd (source_desc);
53 else
54 acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
55 if (acl == NULL)
56 {
57 if (! acl_errno_valid (errno))
58 return qset_acl (dst_name, dest_desc, mode);
59 else
60 return -2;
61 }
62
63 if (HAVE_ACL_SET_FD && dest_desc != -1)
64 ret = acl_set_fd (dest_desc, acl);
65 else
66 ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
67 if (ret != 0)
68 {
69 int saved_errno = errno;
70
71 if (! acl_errno_valid (errno) && !acl_access_nontrivial (acl))
72 {
73 acl_free (acl);
74 return chmod_or_fchmod (dst_name, dest_desc, mode);
75 }
76 else
77 {
78 acl_free (acl);
79 chmod_or_fchmod (dst_name, dest_desc, mode);
80 errno = saved_errno;
81 return -1;
82 }
83 }
84 else
85 acl_free (acl);
86
87 if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
88 {
89 /* We did not call chmod so far, and either the mode and the ACL are
90 separate or special bits are to be set which don't fit into ACLs. */
91
92 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
93 return -1;
94 }
95
96 if (S_ISDIR (mode))
97 {
98 acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
99 if (acl == NULL)
100 return -2;
101
102 if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
103 {
104 int saved_errno = errno;
105
106 acl_free (acl);
107 errno = saved_errno;
108 return -1;
109 }
110 else
111 acl_free (acl);
112 }
113 return 0;
114
115# else /* HAVE_ACL_TYPE_EXTENDED */
116 /* Mac OS X */
117
118 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
119 and acl_get_file (name, ACL_TYPE_DEFAULT)
120 always return NULL / EINVAL. You have to use
121 acl_get_file (name, ACL_TYPE_EXTENDED)
122 or acl_get_fd (open (name, ...))
123 to retrieve an ACL.
124 On the other hand,
125 acl_set_file (name, ACL_TYPE_ACCESS, acl)
126 and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
127 have the same effect as
128 acl_set_file (name, ACL_TYPE_EXTENDED, acl):
129 Each of these calls sets the file's ACL. */
130
131 acl_t acl;
132 int ret; 43 int ret;
133 44
134 if (HAVE_ACL_GET_FD && source_desc != -1) 45 ret = get_permissions (src_name, source_desc, mode, &ctx);
135 acl = acl_get_fd (source_desc);
136 else
137 acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
138 if (acl == NULL)
139 {
140 if (!acl_errno_valid (errno))
141 return qset_acl (dst_name, dest_desc, mode);
142 else
143 return -2;
144 }
145
146 if (HAVE_ACL_SET_FD && dest_desc != -1)
147 ret = acl_set_fd (dest_desc, acl);
148 else
149 ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
150 if (ret != 0) 46 if (ret != 0)
151 {
152 int saved_errno = errno;
153
154 if (!acl_errno_valid (saved_errno) && !acl_extended_nontrivial (acl))
155 {
156 acl_free (acl);
157 return chmod_or_fchmod (dst_name, dest_desc, mode);
158 }
159 else
160 {
161 acl_free (acl);
162 chmod_or_fchmod (dst_name, dest_desc, mode);
163 errno = saved_errno;
164 return -1;
165 }
166 }
167 else
168 acl_free (acl);
169
170 /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
171 return chmod_or_fchmod (dst_name, dest_desc, mode);
172
173# endif
174
175#elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
176
177 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
178 of Unixware. The acl() call returns the access and default ACL both
179 at once. */
180# ifdef ACE_GETACL
181 int ace_count;
182 ace_t *ace_entries;
183# endif
184 int count;
185 aclent_t *entries;
186 int did_chmod;
187 int saved_errno;
188 int ret;
189
190# ifdef ACE_GETACL
191 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
192 file systems (whereas the other ones are used in UFS file systems).
193 There is an API
194 pathconf (name, _PC_ACL_ENABLED)
195 fpathconf (desc, _PC_ACL_ENABLED)
196 that allows to determine which of the two kinds of ACLs is supported
197 for the given file. But some file systems may implement this call
198 incorrectly, so better not use it.
199 When fetching the source ACL, we simply fetch both ACL types.
200 When setting the destination ACL, we try either ACL types, assuming
201 that the kernel will translate the ACL from one form to the other.
202 (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
203 the description of ENOTSUP.) */
204 for (;;)
205 {
206 ace_count = (source_desc != -1
207 ? facl (source_desc, ACE_GETACLCNT, 0, NULL)
208 : acl (src_name, ACE_GETACLCNT, 0, NULL));
209
210 if (ace_count < 0)
211 {
212 if (errno == ENOSYS || errno == EINVAL)
213 {
214 ace_count = 0;
215 ace_entries = NULL;
216 break;
217 }
218 else
219 return -2;
220 }
221
222 if (ace_count == 0)
223 {
224 ace_entries = NULL;
225 break;
226 }
227
228 ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
229 if (ace_entries == NULL)
230 {
231 errno = ENOMEM;
232 return -2;
233 }
234
235 ret = (source_desc != -1
236 ? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
237 : acl (src_name, ACE_GETACL, ace_count, ace_entries));
238 if (ret < 0)
239 {
240 free (ace_entries);
241 if (errno == ENOSYS || errno == EINVAL)
242 {
243 ace_count = 0;
244 ace_entries = NULL;
245 break;
246 }
247 else
248 return -2;
249 }
250 if (ret == ace_count)
251 break;
252 /* Huh? The number of ACL entries changed since the last call.
253 Repeat. */
254 }
255# endif
256
257 for (;;)
258 {
259 count = (source_desc != -1
260 ? facl (source_desc, GETACLCNT, 0, NULL)
261 : acl (src_name, GETACLCNT, 0, NULL));
262
263 if (count < 0)
264 {
265 if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
266 {
267 count = 0;
268 entries = NULL;
269 break;
270 }
271 else
272 return -2;
273 }
274
275 if (count == 0)
276 {
277 entries = NULL;
278 break;
279 }
280
281 entries = (aclent_t *) malloc (count * sizeof (aclent_t));
282 if (entries == NULL)
283 {
284 errno = ENOMEM;
285 return -2;
286 }
287
288 if ((source_desc != -1
289 ? facl (source_desc, GETACL, count, entries)
290 : acl (src_name, GETACL, count, entries))
291 == count)
292 break;
293 /* Huh? The number of ACL entries changed since the last call.
294 Repeat. */
295 }
296
297 /* Is there an ACL of either kind? */
298# ifdef ACE_GETACL
299 if (ace_count == 0)
300# endif
301 if (count == 0)
302 return qset_acl (dst_name, dest_desc, mode);
303
304 did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
305 saved_errno = 0; /* the first non-ignorable error code */
306
307 if (!MODE_INSIDE_ACL)
308 {
309 /* On Cygwin, it is necessary to call chmod before acl, because
310 chmod can change the contents of the ACL (in ways that don't
311 change the allowed accesses, but still visible). */
312 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
313 saved_errno = errno;
314 did_chmod = 1;
315 }
316
317 /* If both ace_entries and entries are available, try SETACL before
318 ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
319 can. */
320
321 if (count > 0)
322 {
323 ret = (dest_desc != -1
324 ? facl (dest_desc, SETACL, count, entries)
325 : acl (dst_name, SETACL, count, entries));
326 if (ret < 0 && saved_errno == 0)
327 {
328 saved_errno = errno;
329 if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
330 && !acl_nontrivial (count, entries))
331 saved_errno = 0;
332 }
333 else
334 did_chmod = 1;
335 }
336 free (entries);
337
338# ifdef ACE_GETACL
339 if (ace_count > 0)
340 {
341 ret = (dest_desc != -1
342 ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
343 : acl (dst_name, ACE_SETACL, ace_count, ace_entries));
344 if (ret < 0 && saved_errno == 0)
345 {
346 saved_errno = errno;
347 if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
348 && !acl_ace_nontrivial (ace_count, ace_entries))
349 saved_errno = 0;
350 }
351 }
352 free (ace_entries);
353# endif
354
355 if (MODE_INSIDE_ACL
356 && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
357 {
358 /* We did not call chmod so far, and either the mode and the ACL are
359 separate or special bits are to be set which don't fit into ACLs. */
360
361 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
362 {
363 if (saved_errno == 0)
364 saved_errno = errno;
365 }
366 }
367
368 if (saved_errno)
369 {
370 errno = saved_errno;
371 return -1;
372 }
373 return 0;
374
375#elif USE_ACL && HAVE_GETACL /* HP-UX */
376
377 struct acl_entry entries[NACLENTRIES];
378 int count;
379# if HAVE_ACLV_H
380 struct acl aclv_entries[NACLVENTRIES];
381 int aclv_count;
382# endif
383 int did_chmod;
384 int saved_errno;
385 int ret;
386
387 count = (source_desc != -1
388 ? fgetacl (source_desc, NACLENTRIES, entries)
389 : getacl (src_name, NACLENTRIES, entries));
390
391 if (count < 0)
392 {
393 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
394 count = 0;
395 else
396 return -2;
397 }
398 else if (count > 0)
399 {
400 if (count > NACLENTRIES)
401 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
402 abort ();
403 }
404
405# if HAVE_ACLV_H
406 aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries);
407
408 if (aclv_count < 0)
409 {
410 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
411 count = 0;
412 else
413 return -2;
414 }
415 else if (aclv_count > 0)
416 {
417 if (aclv_count > NACLVENTRIES)
418 /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
419 abort ();
420 }
421# endif
422
423 if (count == 0)
424# if HAVE_ACLV_H
425 if (aclv_count == 0)
426# endif
427 return qset_acl (dst_name, dest_desc, mode);
428
429 did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
430 saved_errno = 0; /* the first non-ignorable error code */
431
432 if (count > 0)
433 {
434 ret = (dest_desc != -1
435 ? fsetacl (dest_desc, count, entries)
436 : setacl (dst_name, count, entries));
437 if (ret < 0 && saved_errno == 0)
438 {
439 saved_errno = errno;
440 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP
441 && !acl_nontrivial (count, entries))
442 saved_errno = 0;
443 }
444 else
445 did_chmod = 1;
446 }
447
448# if HAVE_ACLV_H
449 if (aclv_count > 0)
450 {
451 ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
452 if (ret < 0 && saved_errno == 0)
453 {
454 saved_errno = errno;
455 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
456 {
457 if (!aclv_nontrivial (aclv_count, aclv_entries))
458 saved_errno = 0;
459 }
460 }
461 else
462 did_chmod = 1;
463 }
464# endif
465
466 if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
467 {
468 /* We did not call chmod so far, and special bits are to be set which
469 don't fit into ACLs. */
470
471 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
472 {
473 if (saved_errno == 0)
474 saved_errno = errno;
475 }
476 }
477
478 if (saved_errno)
479 {
480 errno = saved_errno;
481 return -1;
482 }
483 return 0;
484
485#elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
486
487 /* TODO */
488
489#elif USE_ACL && HAVE_STATACL /* older AIX */
490
491 union { struct acl a; char room[4096]; } u;
492 int ret;
493
494 if ((source_desc != -1
495 ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
496 : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
497 < 0)
498 return -2; 47 return -2;
499 48 ret = set_permissions (&ctx, dst_name, dest_desc);
500 ret = (dest_desc != -1 49 free_permission_context (&ctx);
501 ? fchacl (dest_desc, &u.a, u.a.acl_len) 50 return ret;
502 : chacl (dst_name, &u.a, u.a.acl_len));
503 if (ret < 0)
504 {
505 int saved_errno = errno;
506
507 chmod_or_fchmod (dst_name, dest_desc, mode);
508 errno = saved_errno;
509 return -1;
510 }
511
512 /* No need to call chmod_or_fchmod at this point, since the mode bits
513 S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
514
515 return 0;
516
517#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
518
519 struct acl entries[NACLENTRIES];
520 int count;
521 int ret;
522
523 count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries);
524
525 if (count < 0)
526 {
527 if (0)
528 count = 0;
529 else
530 return -2;
531 }
532 else if (count > 0)
533 {
534 if (count > NACLENTRIES)
535 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
536 abort ();
537 }
538
539 if (count == 0)
540 return qset_acl (dst_name, dest_desc, mode);
541
542 ret = acl ((char *) dst_name, ACL_SET, count, entries);
543 if (ret < 0)
544 {
545 int saved_errno = errno;
546
547 if (0)
548 {
549 if (!acl_nontrivial (count, entries))
550 return chmod_or_fchmod (dst_name, dest_desc, mode);
551 }
552
553 chmod_or_fchmod (dst_name, dest_desc, mode);
554 errno = saved_errno;
555 return -1;
556 }
557
558 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
559 {
560 /* We did not call chmod so far, and either the mode and the ACL are
561 separate or special bits are to be set which don't fit into ACLs. */
562
563 return chmod_or_fchmod (dst_name, dest_desc, mode);
564 }
565 return 0;
566
567#else
568
569 return qset_acl (dst_name, dest_desc, mode);
570
571#endif
572} 51}
diff --git a/lib/qset-acl.c b/lib/set-permissions.c
index bb4b0b261a9..47cb91ca162 100644
--- a/lib/qset-acl.c
+++ b/lib/set-permissions.c
@@ -1,4 +1,4 @@
1/* qset-acl.c - set access control list equivalent to a mode 1/* set-permissions.c - set permissions of a file
2 2
3 Copyright (C) 2002-2003, 2005-2015 Free Software Foundation, Inc. 3 Copyright (C) 2002-2003, 2005-2015 Free Software Foundation, Inc.
4 4
@@ -15,182 +15,43 @@
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
18 Written by Paul Eggert and Andreas Gruenbacher, and Bruno Haible. */ 18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
19 19
20#include <config.h> 20#include <config.h>
21 21
22#define ACL_INTERNAL_INLINE _GL_EXTERN_INLINE
23
24#include "acl.h" 22#include "acl.h"
25 23
26#include "acl-internal.h" 24#include "acl-internal.h"
27 25
28
29/* If DESC is a valid file descriptor use fchmod to change the
30 file's mode to MODE on systems that have fchmod. On systems
31 that don't have fchmod and if DESC is invalid, use chmod on
32 NAME instead.
33 Return 0 if successful. Return -1 and set errno upon failure. */
34
35int
36chmod_or_fchmod (const char *name, int desc, mode_t mode)
37{
38 if (HAVE_FCHMOD && desc != -1)
39 return fchmod (desc, mode);
40 else
41 return chmod (name, mode);
42}
43
44/* Set the access control lists of a file. If DESC is a valid file
45 descriptor, use file descriptor operations where available, else use
46 filename based operations on NAME. If access control lists are not
47 available, fchmod the target file to MODE. Also sets the
48 non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
49 to those from MODE if any are set.
50 Return 0 if successful. Return -1 and set errno upon failure. */
51
52int
53qset_acl (char const *name, int desc, mode_t mode)
54{
55#if USE_ACL 26#if USE_ACL
56# if HAVE_ACL_GET_FILE 27# if ! defined HAVE_ACL_FROM_MODE && defined HAVE_ACL_FROM_TEXT /* FreeBSD, IRIX, Tru64 */
57 /* POSIX 1003.1e draft 17 (abandoned) specific version. */ 28static acl_t
58 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ 29acl_from_mode (mode_t mode)
59# if !HAVE_ACL_TYPE_EXTENDED 30{
60 /* Linux, FreeBSD, IRIX, Tru64 */ 31# if HAVE_ACL_FREE_TEXT /* Tru64 */
61 32 char acl_text[] = "u::---,g::---,o::---,";
62 /* We must also have acl_from_text and acl_delete_def_file. 33# else /* FreeBSD, IRIX */
63 (acl_delete_def_file could be emulated with acl_init followed 34 char acl_text[] = "u::---,g::---,o::---";
64 by acl_set_file, but acl_set_file with an empty acl is
65 unspecified.) */
66
67# ifndef HAVE_ACL_FROM_TEXT
68# error Must have acl_from_text (see POSIX 1003.1e draft 17).
69# endif
70# ifndef HAVE_ACL_DELETE_DEF_FILE
71# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
72# endif
73
74 acl_t acl;
75 int ret;
76
77 if (HAVE_ACL_FROM_MODE) /* Linux */
78 {
79 acl = acl_from_mode (mode);
80 if (!acl)
81 return -1;
82 }
83 else /* FreeBSD, IRIX, Tru64 */
84 {
85 /* If we were to create the ACL using the functions acl_init(),
86 acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(),
87 acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we
88 would need to create a qualifier. I don't know how to do this.
89 So create it using acl_from_text(). */
90
91# if HAVE_ACL_FREE_TEXT /* Tru64 */
92 char acl_text[] = "u::---,g::---,o::---,";
93# else /* FreeBSD, IRIX */
94 char acl_text[] = "u::---,g::---,o::---";
95# endif
96
97 if (mode & S_IRUSR) acl_text[ 3] = 'r';
98 if (mode & S_IWUSR) acl_text[ 4] = 'w';
99 if (mode & S_IXUSR) acl_text[ 5] = 'x';
100 if (mode & S_IRGRP) acl_text[10] = 'r';
101 if (mode & S_IWGRP) acl_text[11] = 'w';
102 if (mode & S_IXGRP) acl_text[12] = 'x';
103 if (mode & S_IROTH) acl_text[17] = 'r';
104 if (mode & S_IWOTH) acl_text[18] = 'w';
105 if (mode & S_IXOTH) acl_text[19] = 'x';
106
107 acl = acl_from_text (acl_text);
108 if (!acl)
109 return -1;
110 }
111 if (HAVE_ACL_SET_FD && desc != -1)
112 ret = acl_set_fd (desc, acl);
113 else
114 ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
115 if (ret != 0)
116 {
117 int saved_errno = errno;
118 acl_free (acl);
119 if (! acl_errno_valid (errno))
120 return chmod_or_fchmod (name, desc, mode);
121 errno = saved_errno;
122 return -1;
123 }
124 else
125 acl_free (acl);
126
127 if (S_ISDIR (mode) && acl_delete_def_file (name))
128 return -1;
129
130 if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
131 {
132 /* We did not call chmod so far, and either the mode and the ACL are
133 separate or special bits are to be set which don't fit into ACLs. */
134 return chmod_or_fchmod (name, desc, mode);
135 }
136 return 0;
137
138# else /* HAVE_ACL_TYPE_EXTENDED */
139 /* Mac OS X */
140
141 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
142 and acl_get_file (name, ACL_TYPE_DEFAULT)
143 always return NULL / EINVAL. You have to use
144 acl_get_file (name, ACL_TYPE_EXTENDED)
145 or acl_get_fd (open (name, ...))
146 to retrieve an ACL.
147 On the other hand,
148 acl_set_file (name, ACL_TYPE_ACCESS, acl)
149 and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
150 have the same effect as
151 acl_set_file (name, ACL_TYPE_EXTENDED, acl):
152 Each of these calls sets the file's ACL. */
153
154 acl_t acl;
155 int ret;
156
157 /* Remove the ACL if the file has ACLs. */
158 if (HAVE_ACL_GET_FD && desc != -1)
159 acl = acl_get_fd (desc);
160 else
161 acl = acl_get_file (name, ACL_TYPE_EXTENDED);
162 if (acl)
163 {
164 acl_free (acl);
165
166 acl = acl_init (0);
167 if (acl)
168 {
169 if (HAVE_ACL_SET_FD && desc != -1)
170 ret = acl_set_fd (desc, acl);
171 else
172 ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
173 if (ret != 0)
174 {
175 int saved_errno = errno;
176 acl_free (acl);
177 if (! acl_errno_valid (saved_errno))
178 return chmod_or_fchmod (name, desc, mode);
179 errno = saved_errno;
180 return -1;
181 }
182 acl_free (acl);
183 }
184 }
185
186 /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
187 return chmod_or_fchmod (name, desc, mode);
188# endif 35# endif
189 36
190# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ 37 if (mode & S_IRUSR) acl_text[ 3] = 'r';
191 38 if (mode & S_IWUSR) acl_text[ 4] = 'w';
192 int done_setacl = 0; 39 if (mode & S_IXUSR) acl_text[ 5] = 'x';
40 if (mode & S_IRGRP) acl_text[10] = 'r';
41 if (mode & S_IWGRP) acl_text[11] = 'w';
42 if (mode & S_IXGRP) acl_text[12] = 'x';
43 if (mode & S_IROTH) acl_text[17] = 'r';
44 if (mode & S_IWOTH) acl_text[18] = 'w';
45 if (mode & S_IXOTH) acl_text[19] = 'x';
46
47 return acl_from_text (acl_text);
48}
49# endif
193 50
51# if HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
52static int
53set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod)
54{
194# ifdef ACE_GETACL 55# ifdef ACE_GETACL
195 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 56 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
196 file systems (whereas the other ones are used in UFS file systems). */ 57 file systems (whereas the other ones are used in UFS file systems). */
@@ -365,53 +226,53 @@ qset_acl (char const *name, int desc, mode_t mode)
365 if (ret < 0 && errno != EINVAL && errno != ENOTSUP) 226 if (ret < 0 && errno != EINVAL && errno != ENOTSUP)
366 { 227 {
367 if (errno == ENOSYS) 228 if (errno == ENOSYS)
368 return chmod_or_fchmod (name, desc, mode); 229 {
230 *must_chmod = true;
231 return 0;
232 }
369 return -1; 233 return -1;
370 } 234 }
371 if (ret == 0) 235 if (ret == 0)
372 done_setacl = 1; 236 return 0;
373 } 237 }
374# endif 238# endif
375 239
376 if (!done_setacl) 240 {
377 { 241 aclent_t entries[3];
378 aclent_t entries[3]; 242 int ret;
379 int ret; 243
380 244 entries[0].a_type = USER_OBJ;
381 entries[0].a_type = USER_OBJ; 245 entries[0].a_id = 0; /* irrelevant */
382 entries[0].a_id = 0; /* irrelevant */ 246 entries[0].a_perm = (mode >> 6) & 7;
383 entries[0].a_perm = (mode >> 6) & 7; 247 entries[1].a_type = GROUP_OBJ;
384 entries[1].a_type = GROUP_OBJ; 248 entries[1].a_id = 0; /* irrelevant */
385 entries[1].a_id = 0; /* irrelevant */ 249 entries[1].a_perm = (mode >> 3) & 7;
386 entries[1].a_perm = (mode >> 3) & 7; 250 entries[2].a_type = OTHER_OBJ;
387 entries[2].a_type = OTHER_OBJ; 251 entries[2].a_id = 0;
388 entries[2].a_id = 0; 252 entries[2].a_perm = mode & 7;
389 entries[2].a_perm = mode & 7;
390
391 if (desc != -1)
392 ret = facl (desc, SETACL,
393 sizeof (entries) / sizeof (aclent_t), entries);
394 else
395 ret = acl (name, SETACL,
396 sizeof (entries) / sizeof (aclent_t), entries);
397 if (ret < 0)
398 {
399 if (errno == ENOSYS || errno == EOPNOTSUPP)
400 return chmod_or_fchmod (name, desc, mode);
401 return -1;
402 }
403 }
404
405 if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
406 {
407 /* We did not call chmod so far, so the special bits have not yet
408 been set. */
409 return chmod_or_fchmod (name, desc, mode);
410 }
411 return 0;
412 253
413# elif HAVE_GETACL /* HP-UX */ 254 if (desc != -1)
255 ret = facl (desc, SETACL,
256 sizeof (entries) / sizeof (aclent_t), entries);
257 else
258 ret = acl (name, SETACL,
259 sizeof (entries) / sizeof (aclent_t), entries);
260 if (ret < 0)
261 {
262 if (errno == ENOSYS || errno == EOPNOTSUPP)
263 {
264 *must_chmod = true;
265 return 0;
266 }
267 return -1;
268 }
269 }
270}
414 271
272#elif HAVE_GETACL /* HP-UX */
273static int
274context_acl_from_mode (struct permission_context *ctx, const char *name, int desc)
275{
415 struct stat statbuf; 276 struct stat statbuf;
416 int ret; 277 int ret;
417 278
@@ -422,87 +283,60 @@ qset_acl (char const *name, int desc, mode_t mode)
422 if (ret < 0) 283 if (ret < 0)
423 return -1; 284 return -1;
424 285
425 { 286 ctx->entries[0].uid = statbuf.st_uid;
426 struct acl_entry entries[3]; 287 ctx->entries[0].gid = ACL_NSGROUP;
427 288 ctx->entries[0].mode = (mode >> 6) & 7;
428 entries[0].uid = statbuf.st_uid; 289 ctx->entries[1].uid = ACL_NSUSER;
429 entries[0].gid = ACL_NSGROUP; 290 ctx->entries[1].gid = statbuf.st_gid;
430 entries[0].mode = (mode >> 6) & 7; 291 ctx->entries[1].mode = (mode >> 3) & 7;
431 entries[1].uid = ACL_NSUSER; 292 ctx->entries[2].uid = ACL_NSUSER;
432 entries[1].gid = statbuf.st_gid; 293 ctx->entries[2].gid = ACL_NSGROUP;
433 entries[1].mode = (mode >> 3) & 7; 294 ctx->entries[2].mode = mode & 7;
434 entries[2].uid = ACL_NSUSER; 295 ctx->count = 3;
435 entries[2].gid = ACL_NSGROUP; 296 return 0;
436 entries[2].mode = mode & 7; 297}
437
438 if (desc != -1)
439 ret = fsetacl (desc, sizeof (entries) / sizeof (struct acl_entry), entries);
440 else
441 ret = setacl (name, sizeof (entries) / sizeof (struct acl_entry), entries);
442 }
443 if (ret < 0)
444 {
445 if (!(errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
446 return -1;
447 298
448# if HAVE_ACLV_H /* HP-UX >= 11.11 */ 299# if HAVE_ACLV_H /* HP-UX >= 11.11 */
449 { 300static int
450 struct acl entries[4]; 301context_aclv_from_mode (struct permission_context *ctx)
451 302{
452 entries[0].a_type = USER_OBJ; 303 int ret;
453 entries[0].a_id = 0; /* irrelevant */
454 entries[0].a_perm = (mode >> 6) & 7;
455 entries[1].a_type = GROUP_OBJ;
456 entries[1].a_id = 0; /* irrelevant */
457 entries[1].a_perm = (mode >> 3) & 7;
458 entries[2].a_type = CLASS_OBJ;
459 entries[2].a_id = 0;
460 entries[2].a_perm = (mode >> 3) & 7;
461 entries[3].a_type = OTHER_OBJ;
462 entries[3].a_id = 0;
463 entries[3].a_perm = mode & 7;
464
465 ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
466 if (ret > 0)
467 abort ();
468 if (ret < 0)
469 {
470 if (0)
471 return chmod_or_fchmod (name, desc, mode);
472 return -1;
473 }
474 304
475 ret = acl ((char *) name, ACL_SET, 305 ctx->aclv_entries[0].a_type = USER_OBJ;
476 sizeof (entries) / sizeof (struct acl), entries); 306 ctx->aclv_entries[0].a_id = 0; /* irrelevant */
477 if (ret < 0) 307 ctx->aclv_entries[0].a_perm = (mode >> 6) & 7;
478 { 308 ctx->aclv_entries[1].a_type = GROUP_OBJ;
479 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) 309 ctx->aclv_entries[1].a_id = 0; /* irrelevant */
480 return chmod_or_fchmod (name, desc, mode); 310 ctx->aclv_entries[1].a_perm = (mode >> 3) & 7;
481 return -1; 311 ctx->aclv_entries[2].a_type = CLASS_OBJ;
482 } 312 ctx->aclv_entries[2].a_id = 0;
483 } 313 ctx->aclv_entries[2].a_perm = (mode >> 3) & 7;
484# else 314 ctx->aclv_entries[3].a_type = OTHER_OBJ;
485 return chmod_or_fchmod (name, desc, mode); 315 ctx->aclv_entries[3].a_id = 0;
486# endif 316 ctx->aclv_entries[3].a_perm = mode & 7;
487 } 317 ctx->aclv_count = 4;
488 318
489 if (mode & (S_ISUID | S_ISGID | S_ISVTX)) 319 ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
490 { 320 if (ret > 0)
491 /* We did not call chmod so far, so the special bits have not yet 321 abort ();
492 been set. */ 322 return ret;
493 return chmod_or_fchmod (name, desc, mode); 323}
494 } 324#endif
495 return 0;
496 325
497# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ 326# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
498 327static int
328set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod)
329{
499 acl_type_list_t types; 330 acl_type_list_t types;
500 size_t types_size = sizeof (types); 331 size_t types_size = sizeof (types);
501 acl_type_t type; 332 acl_type_t type;
502 333
503 if (aclx_gettypes (name, &types, &types_size) < 0 334 if (aclx_gettypes (name, &types, &types_size) < 0
504 || types.num_entries == 0) 335 || types.num_entries == 0)
505 return chmod_or_fchmod (name, desc, mode); 336 {
337 *must_chmod = true;
338 return 0;
339 }
506 340
507 /* XXX Do we need to clear all types of ACLs for the given file, or is it 341 /* XXX Do we need to clear all types of ACLs for the given file, or is it
508 sufficient to clear the first one? */ 342 sufficient to clear the first one? */
@@ -599,78 +433,401 @@ qset_acl (char const *name, int desc, mode_t mode)
599 return ret; 433 return ret;
600 } 434 }
601 435
602 return chmod_or_fchmod (name, desc, mode); 436 *must_chmod = true;
437 return 0;
438}
603 439
604# elif HAVE_STATACL /* older AIX */ 440# elif HAVE_STATACL /* older AIX */
441static int
442context_acl_from_mode (struct permission_context *ctx)
443{
444 ctx->u.a.acl_len = (char *) &ctx->u.a.acl_ext[0] - (char *) &ctx->u.a; /* no entries */
445 ctx->u.a.acl_mode = ctx->mode & ~(S_IXACL | 0777);
446 ctx->u.a.u_access = (ctx->mode >> 6) & 7;
447 ctx->u.a.g_access = (ctx->mode >> 3) & 7;
448 ctx->u.a.o_access = ctx->mode & 7;
449 ctx->have_u = true;
450 return 0;
451}
605 452
606 union { struct acl a; char room[128]; } u; 453# elif HAVE_ACLSORT /* NonStop Kernel */
454static int
455context_acl_from_mode (struct permission_context *ctx)
456{
607 int ret; 457 int ret;
608 458
609 u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */ 459 ctx->entries[0].a_type = USER_OBJ;
610 u.a.acl_mode = mode & ~(S_IXACL | 0777); 460 ctx->entries[0].a_id = 0; /* irrelevant */
611 u.a.u_access = (mode >> 6) & 7; 461 ctx->entries[0].a_perm = (mode >> 6) & 7;
612 u.a.g_access = (mode >> 3) & 7; 462 ctx->entries[1].a_type = GROUP_OBJ;
613 u.a.o_access = mode & 7; 463 ctx->entries[1].a_id = 0; /* irrelevant */
464 ctx->entries[1].a_perm = (mode >> 3) & 7;
465 ctx->entries[2].a_type = CLASS_OBJ;
466 ctx->entries[2].a_id = 0;
467 ctx->entries[2].a_perm = (mode >> 3) & 7;
468 ctx->entries[3].a_type = OTHER_OBJ;
469 ctx->entries[3].a_id = 0;
470 ctx->entries[3].a_perm = mode & 7;
471 ctx->count = 4;
614 472
615 if (desc != -1) 473 ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
616 ret = fchacl (desc, &u.a, u.a.acl_len); 474 if (ret > 0)
475 abort ();
476 return ret;
477}
478# endif
479
480static int
481set_acls (struct permission_context *ctx, const char *name, int desc,
482 int from_mode, bool *must_chmod, bool *acls_set)
483{
484 int ret = 0;
485
486#if HAVE_ACL_GET_FILE
487 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
488 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
489# if !HAVE_ACL_TYPE_EXTENDED
490 /* Linux, FreeBSD, IRIX, Tru64 */
491
492# ifndef HAVE_ACL_FROM_TEXT
493# error Must have acl_from_text (see POSIX 1003.1e draft 17).
494# endif
495# ifndef HAVE_ACL_DELETE_DEF_FILE
496# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
497# endif
498
499 if (! ctx->acls_not_supported)
500 {
501 if (ret == 0 && from_mode)
502 {
503 if (ctx->acl)
504 acl_free (ctx->acl);
505 ctx->acl = acl_from_mode (ctx->mode);
506 if (ctx->acl == NULL)
507 ret = -1;
508 }
509
510 if (ret == 0 && ctx->acl)
511 {
512 if (HAVE_ACL_SET_FD && desc != -1)
513 ret = acl_set_fd (desc, ctx->acl);
514 else
515 ret = acl_set_file (name, ACL_TYPE_ACCESS, ctx->acl);
516 if (ret != 0)
517 {
518 if (! acl_errno_valid (errno))
519 {
520 ctx->acls_not_supported = true;
521 if (from_mode || acl_access_nontrivial (ctx->acl) == 0)
522 ret = 0;
523 }
524 }
525 else
526 {
527 *acls_set = true;
528 if (S_ISDIR(ctx->mode))
529 {
530 if (! from_mode && ctx->default_acl)
531 ret = acl_set_file (name, ACL_TYPE_DEFAULT,
532 ctx->default_acl);
533 else
534 ret = acl_delete_def_file (name);
535 }
536 }
537 }
538 }
539
540# else /* HAVE_ACL_TYPE_EXTENDED */
541 /* Mac OS X */
542
543 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
544 and acl_get_file (name, ACL_TYPE_DEFAULT)
545 always return NULL / EINVAL. You have to use
546 acl_get_file (name, ACL_TYPE_EXTENDED)
547 or acl_get_fd (open (name, ...))
548 to retrieve an ACL.
549 On the other hand,
550 acl_set_file (name, ACL_TYPE_ACCESS, acl)
551 and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
552 have the same effect as
553 acl_set_file (name, ACL_TYPE_EXTENDED, acl):
554 Each of these calls sets the file's ACL. */
555
556 if (ctx->acl == NULL)
557 {
558 acl_t acl;
559
560 /* Remove ACLs if the file has ACLs. */
561 if (HAVE_ACL_GET_FD && desc != -1)
562 acl = acl_get_fd (desc);
563 else
564 acl = acl_get_file (name, ACL_TYPE_EXTENDED);
565 if (acl)
566 {
567 acl_free (acl);
568
569 acl = acl_init (acl);
570 if (acl)
571 {
572 if (HAVE_ACL_SET_FD && desc != -1)
573 ret = acl_set_fd (desc, acl);
574 else
575 ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
576 acl_free (acl);
577 }
578 else
579 ret = -1;
580 }
581 }
617 else 582 else
618 ret = chacl (name, &u.a, u.a.acl_len); 583 {
584 if (HAVE_ACL_SET_FD && desc != -1)
585 ret = acl_set_fd (desc, acl);
586 else
587 ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
588 if (ret != 0)
589 {
590 if (! acl_errno_valid (saved_errno) && ! acl_extended_nontrivial (acl))
591 ret = 0;
592 }
593 }
594 *acls_set = true;
619 595
620 if (ret < 0 && errno == ENOSYS) 596# endif
621 return chmod_or_fchmod (name, desc, mode);
622 597
623 return ret; 598# elif defined GETACL /* Solaris, Cygwin, not HP-UX */
624 599
625# elif HAVE_ACLSORT /* NonStop Kernel */ 600 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
601 of Unixware. The acl() call returns the access and default ACL both
602 at once. */
626 603
627 struct acl entries[4]; 604 /* If both ace_entries and entries are available, try SETACL before
628 int ret; 605 ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
606 can. */
629 607
630 entries[0].a_type = USER_OBJ; 608 if (from_mode)
631 entries[0].a_id = 0; /* irrelevant */ 609 return set_acls_from_mode (name, desc, ctx->mode, must_chmod);
632 entries[0].a_perm = (mode >> 6) & 7;
633 entries[1].a_type = GROUP_OBJ;
634 entries[1].a_id = 0; /* irrelevant */
635 entries[1].a_perm = (mode >> 3) & 7;
636 entries[2].a_type = CLASS_OBJ;
637 entries[2].a_id = 0;
638 entries[2].a_perm = (mode >> 3) & 7;
639 entries[3].a_type = OTHER_OBJ;
640 entries[3].a_id = 0;
641 entries[3].a_perm = mode & 7;
642 610
643 ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries); 611 if (ret == 0 && ctx->count)
644 if (ret > 0)
645 abort ();
646 if (ret < 0)
647 { 612 {
648 if (0) 613 if (desc != -1)
649 return chmod_or_fchmod (name, desc, mode); 614 ret = facl (desc, SETACL, count, entries);
650 return -1; 615 else
616 ret = acl (name, SETACL, count, entries);
617 if (ret < 0)
618 {
619 if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
620 && acl_nontrivial (count, entries) == 0)
621 ret = 0;
622 }
623 else
624 *acls_set = true;
651 } 625 }
652 626
653 ret = acl ((char *) name, ACL_SET, 627# ifdef ACE_GETACL
654 sizeof (entries) / sizeof (struct acl), entries); 628 if (ret == 0 && ctx->ace_count)
655 if (ret < 0)
656 { 629 {
657 if (0) 630 if (desc != -1)
658 return chmod_or_fchmod (name, desc, mode); 631 ret = facl (desc, ACE_SETACL, ace_count, ace_entries);
659 return -1; 632 else
633 ret = acl (name, ACE_SETACL, ace_count, ace_entries);
634 if (ret < 0)
635 {
636 if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
637 && acl_ace_nontrivial (ace_count, ace_entries) == 0)
638 ret = 0;
639 }
640 else
641 *acls_set = true;
660 } 642 }
643# endif
644
645#elif HAVE_GETACL /* HP-UX */
661 646
662 if (mode & (S_ISUID | S_ISGID | S_ISVTX)) 647 if (from_mode)
648 ret = context_acl_from_mode (ctx, name, desc);
649
650 if (ret == 0 && ctx->count > 0)
663 { 651 {
664 /* We did not call chmod so far, so the special bits have not yet 652 if (desc != -1)
665 been set. */ 653 ret = fsetacl (desc, ctx->count, ctx->entries);
666 return chmod_or_fchmod (name, desc, mode); 654 else
655 ret = setacl (name, ctx->count, ctx->entries);
656 if (ret < 0)
657 {
658 if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
659 && (from_mode || !acl_nontrivial (ctx->count, ctx->entries, &source_statbuf)))
660 ret = 0;
661 }
662 else
663 *acls_set = true;
667 } 664 }
668 return 0;
669 665
670# else /* Unknown flavor of ACLs */ 666# if HAVE_ACLV_H
671 return chmod_or_fchmod (name, desc, mode); 667 if (from_mode)
668 ret = context_aclv_from_mode (ctx);
669
670 if (ret == 0 && ctx->aclv_count > 0)
671 {
672 ret = acl ((char *) name, ACL_SET, ctx->aclv_count, ctx->aclv_entries);
673 if (ret < 0)
674 {
675 if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
676 && (from_mode || !aclv_nontrivial (ctx->aclv_count, ctx->aclv_entries)))
677 ret = 0;
678 }
679 else
680 *acls_set = true;
681 }
682# endif
683
684# elif HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
685
686 /* TODO: Implement setting ACLs once get_permissions() reads them. */
687
688 if (from_mode)
689 ret = set_acls_from_mode (name, desc, mode, must_chmod);
690
691# elif HAVE_STATACL /* older AIX */
692
693 if (from_mode)
694 ret = context_acl_from_mode (ctx);
695
696 if (ret == 0 && ctx->have_u)
697 {
698 if (desc != -1)
699 ret = fchacl (desc, &u.a, u.a.acl_len);
700 else
701 ret = chacl (name, &u.a, u.a.acl_len);
702 if (ret < 0)
703 {
704 if (errno == ENOSYS && from_mode)
705 ret = 0;
706 }
707 else
708 *acls_set = true;
709 }
710
711# elif HAVE_ACLSORT /* NonStop Kernel */
712
713 if (from_mode)
714 ret = context_acl_from_mode (ctx);
715
716 if (ret == 0 && ctx->count)
717 {
718 ret = acl ((char *) name, ACL_SET, ctx->count, ctx->entries);
719 if (ret != 0)
720 {
721 if (!acl_nontrivial (ctx->count, ctx->entries))
722 ret = 0;
723 }
724 else
725 *acls_set = true;
726 }
727
728# else /* No ACLs */
729
730 /* Nothing to do. */
731
732#endif
733
734 return ret;
735}
736#endif
737
738/* If DESC is a valid file descriptor use fchmod to change the
739 file's mode to MODE on systems that have fchmod. On systems
740 that don't have fchmod and if DESC is invalid, use chmod on
741 NAME instead.
742 Return 0 if successful. Return -1 and set errno upon failure. */
743
744int
745chmod_or_fchmod (const char *name, int desc, mode_t mode)
746{
747 if (HAVE_FCHMOD && desc != -1)
748 return fchmod (desc, mode);
749 else
750 return chmod (name, mode);
751}
752
753/* Set the permissions in CTX on a file. If DESC is a valid file descriptor,
754 use file descriptor operations, else use filename based operations on NAME.
755 If access control lists are not available, fchmod the target file to the
756 mode in CTX. Also sets the non-permission bits of the destination file
757 (S_ISUID, S_ISGID, S_ISVTX) to those from the mode in CTX if any are set.
758 Return 0 if successful. Return -1 and set errno upon failure. */
759
760int
761set_permissions (struct permission_context *ctx, const char *name, int desc)
762{
763 bool acls_set _GL_UNUSED = false;
764 bool early_chmod;
765 bool must_chmod = false;
766 int ret = 0;
767
768#if USE_ACL
769# if HAVE_STATACL
770 /* older AIX */
771 /* There is no need to call chmod_or_fchmod, since the mode
772 bits S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
773
774 early_chmod = false;
775# else
776 /* All other plaforms */
777 /* On Cygwin, it is necessary to call chmod before acl, because
778 chmod can change the contents of the ACL (in ways that don't
779 change the allowed accesses, but still visible). */
780
781 early_chmod = (! MODE_INSIDE_ACL || (ctx->mode & (S_ISUID | S_ISGID | S_ISVTX)));
672# endif 782# endif
673#else /* !USE_ACL */ 783#else
674 return chmod_or_fchmod (name, desc, mode); 784 /* No ACLs */
785
786 early_chmod = true;
675#endif 787#endif
788
789 if (early_chmod)
790 {
791 ret = chmod_or_fchmod (name, desc, ctx->mode);
792 if (ret != 0)
793 return -1;
794 }
795
796#if USE_ACL
797 ret = set_acls (ctx, name, desc, false, &must_chmod, &acls_set);
798 if (! acls_set)
799 {
800 int saved_errno = ret ? errno : 0;
801
802 /* If we can't set an acl which we expect to be able to set, try setting
803 the permissions to ctx->mode. Doe to possible inherited permissions,
804 we cannot simply chmod. */
805
806 acls_set = false;
807 ret = set_acls (ctx, name, desc, true, &must_chmod, &acls_set);
808 if (! acls_set)
809 must_chmod = true;
810
811 if (saved_errno)
812 {
813 errno = saved_errno;
814 ret = -1;
815 }
816 }
817#endif
818
819 if (must_chmod && ! early_chmod)
820 {
821 int saved_errno = ret ? errno : 0;
822
823 ret = chmod_or_fchmod (name, desc, ctx->mode);
824
825 if (saved_errno)
826 {
827 errno = saved_errno;
828 ret = -1;
829 }
830 }
831
832 return ret;
676} 833}
diff --git a/lib/string.in.h b/lib/string.in.h
index ebd727eda14..2abd6bc0e10 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -15,16 +15,32 @@
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */ 16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
17 17
18#ifndef _@GUARD_PREFIX@_STRING_H
19
20#if __GNUC__ >= 3 18#if __GNUC__ >= 3
21@PRAGMA_SYSTEM_HEADER@ 19@PRAGMA_SYSTEM_HEADER@
22#endif 20#endif
23@PRAGMA_COLUMNS@ 21@PRAGMA_COLUMNS@
24 22
23#if defined _GL_ALREADY_INCLUDING_STRING_H
24/* Special invocation convention:
25 - On OS X/NetBSD we have a sequence of nested includes
26 <string.h> -> <strings.h> -> "string.h"
27 In this situation system _chk variants due to -D_FORTIFY_SOURCE
28 might be used after any replacements defined here. */
29
30#@INCLUDE_NEXT@ @NEXT_STRING_H@
31
32#else
33/* Normal invocation convention. */
34
35#ifndef _@GUARD_PREFIX@_STRING_H
36
37#define _GL_ALREADY_INCLUDING_STRING_H
38
25/* The include_next requires a split double-inclusion guard. */ 39/* The include_next requires a split double-inclusion guard. */
26#@INCLUDE_NEXT@ @NEXT_STRING_H@ 40#@INCLUDE_NEXT@ @NEXT_STRING_H@
27 41
42#undef _GL_ALREADY_INCLUDING_STRING_H
43
28#ifndef _@GUARD_PREFIX@_STRING_H 44#ifndef _@GUARD_PREFIX@_STRING_H
29#define _@GUARD_PREFIX@_STRING_H 45#define _@GUARD_PREFIX@_STRING_H
30 46
@@ -1027,3 +1043,4 @@ _GL_WARN_ON_USE (strverscmp, "strverscmp is unportable - "
1027 1043
1028#endif /* _@GUARD_PREFIX@_STRING_H */ 1044#endif /* _@GUARD_PREFIX@_STRING_H */
1029#endif /* _@GUARD_PREFIX@_STRING_H */ 1045#endif /* _@GUARD_PREFIX@_STRING_H */
1046#endif
diff --git a/m4/acl.m4 b/m4/acl.m4
index b8f4660f7e3..5da6a43ab6a 100644
--- a/m4/acl.m4
+++ b/m4/acl.m4
@@ -1,5 +1,5 @@
1# acl.m4 - check for access control list (ACL) primitives 1# acl.m4 - check for access control list (ACL) primitives
2# serial 19 2# serial 20
3 3
4# Copyright (C) 2002, 2004-2015 Free Software Foundation, Inc. 4# Copyright (C) 2002, 2004-2015 Free Software Foundation, Inc.
5# This file is free software; the Free Software Foundation 5# This file is free software; the Free Software Foundation
@@ -181,26 +181,12 @@ AC_DEFUN([gl_FILE_HAS_ACL],
181[ 181[
182 AC_REQUIRE([gl_FUNC_ACL_ARG]) 182 AC_REQUIRE([gl_FUNC_ACL_ARG])
183 if test "$enable_acl" != no; then 183 if test "$enable_acl" != no; then
184 AC_CACHE_CHECK([for getxattr with XATTR_NAME_POSIX_ACL macros], 184 AC_CHECK_HEADERS([linux/xattr.h])
185 [gl_cv_getxattr_with_posix_acls], 185 AC_CHECK_HEADERS([sys/xattr.h],
186 [gl_cv_getxattr_with_posix_acls=no 186 [AC_CHECK_FUNCS([getxattr])])
187 AC_LINK_IFELSE(
188 [AC_LANG_PROGRAM(
189 [[#include <sys/types.h>
190 #include <sys/xattr.h>
191 #include <linux/xattr.h>
192 ]],
193 [[ssize_t a = getxattr (".", XATTR_NAME_POSIX_ACL_ACCESS, 0, 0);
194 ssize_t b = getxattr (".", XATTR_NAME_POSIX_ACL_DEFAULT, 0, 0);
195 return a < 0 || b < 0;
196 ]])],
197 [gl_cv_getxattr_with_posix_acls=yes])])
198 fi 187 fi
199 if test "$gl_cv_getxattr_with_posix_acls" = yes; then 188 if test "$ac_cv_header_sys_xattr_h,$ac_cv_func_getxattr" = yes,yes; then
200 LIB_HAS_ACL= 189 LIB_HAS_ACL=
201 AC_DEFINE([GETXATTR_WITH_POSIX_ACLS], 1,
202 [Define to 1 if getxattr works with XATTR_NAME_POSIX_ACL_ACCESS
203 and XATTR_NAME_POSIX_ACL_DEFAULT.])
204 else 190 else
205 dnl Set gl_need_lib_has_acl to a nonempty value, so that any 191 dnl Set gl_need_lib_has_acl to a nonempty value, so that any
206 dnl later gl_FUNC_ACL call will set LIB_HAS_ACL=$LIB_ACL. 192 dnl later gl_FUNC_ACL call will set LIB_HAS_ACL=$LIB_ACL.
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index 06636cfe76c..0425d02241a 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -39,6 +39,7 @@ AC_DEFUN([gl_EARLY],
39 m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable 39 m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable
40 AC_REQUIRE([gl_PROG_AR_RANLIB]) 40 AC_REQUIRE([gl_PROG_AR_RANLIB])
41 # Code from module absolute-header: 41 # Code from module absolute-header:
42 # Code from module acl-permissions:
42 # Code from module alloca-opt: 43 # Code from module alloca-opt:
43 # Code from module allocator: 44 # Code from module allocator:
44 # Code from module at-internal: 45 # Code from module at-internal:
@@ -105,7 +106,7 @@ AC_DEFUN([gl_EARLY],
105 # Code from module pselect: 106 # Code from module pselect:
106 # Code from module pthread_sigmask: 107 # Code from module pthread_sigmask:
107 # Code from module putenv: 108 # Code from module putenv:
108 # Code from module qacl: 109 # Code from module qcopy-acl:
109 # Code from module readlink: 110 # Code from module readlink:
110 # Code from module readlinkat: 111 # Code from module readlinkat:
111 # Code from module root-uid: 112 # Code from module root-uid:
@@ -172,6 +173,7 @@ AC_DEFUN([gl_INIT],
172 m4_pushdef([gl_LIBSOURCES_DIR], []) 173 m4_pushdef([gl_LIBSOURCES_DIR], [])
173 gl_COMMON 174 gl_COMMON
174 gl_source_base='lib' 175 gl_source_base='lib'
176 gl_FUNC_ACL
175 gl_FUNC_ALLOCA 177 gl_FUNC_ALLOCA
176 gl_BYTESWAP 178 gl_BYTESWAP
177 AC_CHECK_FUNCS_ONCE([readlinkat]) 179 AC_CHECK_FUNCS_ONCE([readlinkat])
@@ -317,7 +319,6 @@ AC_DEFUN([gl_INIT],
317 gl_PREREQ_PUTENV 319 gl_PREREQ_PUTENV
318 fi 320 fi
319 gl_STDLIB_MODULE_INDICATOR([putenv]) 321 gl_STDLIB_MODULE_INDICATOR([putenv])
320 gl_FUNC_ACL
321 gl_FUNC_READLINK 322 gl_FUNC_READLINK
322 if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then 323 if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then
323 AC_LIBOBJ([readlink]) 324 AC_LIBOBJ([readlink])
@@ -865,6 +866,7 @@ AC_DEFUN([gl_FILE_LIST], [
865 lib/fsync.c 866 lib/fsync.c
866 lib/ftoastr.c 867 lib/ftoastr.c
867 lib/ftoastr.h 868 lib/ftoastr.h
869 lib/get-permissions.c
868 lib/getdtablesize.c 870 lib/getdtablesize.c
869 lib/getgroups.c 871 lib/getgroups.c
870 lib/getloadavg.c 872 lib/getloadavg.c
@@ -895,11 +897,11 @@ AC_DEFUN([gl_FILE_LIST], [
895 lib/pthread_sigmask.c 897 lib/pthread_sigmask.c
896 lib/putenv.c 898 lib/putenv.c
897 lib/qcopy-acl.c 899 lib/qcopy-acl.c
898 lib/qset-acl.c
899 lib/readlink.c 900 lib/readlink.c
900 lib/readlinkat.c 901 lib/readlinkat.c
901 lib/root-uid.h 902 lib/root-uid.h
902 lib/secure_getenv.c 903 lib/secure_getenv.c
904 lib/set-permissions.c
903 lib/sha1.c 905 lib/sha1.c
904 lib/sha1.h 906 lib/sha1.h
905 lib/sha256.c 907 lib/sha256.c
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index e0c4bde1f8e..f60cc2156e0 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,4 +1,4 @@
1# stdio_h.m4 serial 44 1# stdio_h.m4 serial 46
2dnl Copyright (C) 2007-2015 Free Software Foundation, Inc. 2dnl Copyright (C) 2007-2015 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 3dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 4dnl gives unlimited permission to copy and/or distribute it,
@@ -15,15 +15,21 @@ AC_DEFUN([gl_STDIO_H],
15 dnl Determine whether __USE_MINGW_ANSI_STDIO makes printf and 15 dnl Determine whether __USE_MINGW_ANSI_STDIO makes printf and
16 dnl inttypes.h behave like gnu instead of system; we must give our 16 dnl inttypes.h behave like gnu instead of system; we must give our
17 dnl printf wrapper the right attribute to match. 17 dnl printf wrapper the right attribute to match.
18 AC_CACHE_CHECK([whether inttypes macros match system or gnu printf], 18 AC_CACHE_CHECK([which flavor of printf attribute matches inttypes macros],
19 [gl_cv_func_printf_attribute_flavor], 19 [gl_cv_func_printf_attribute_flavor],
20 [AC_EGREP_CPP([findme .(ll|j)d. findme], 20 [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
21 [#define __STDC_FORMAT_MACROS 1 21 #define __STDC_FORMAT_MACROS 1
22 #include <stdio.h> 22 #include <stdio.h>
23 #include <inttypes.h> 23 #include <inttypes.h>
24 findme PRIdMAX findme 24 /* For non-mingw systems, compilation will trivially succeed.
25 ], [gl_cv_func_printf_attribute_flavor=gnu], 25 For mingw, compilation will succeed for older mingw (system
26 [gl_cv_func_printf_attribute_flavor=system])]) 26 printf, "I64d") and fail for newer mingw (gnu printf, "lld"). */
27 #if ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__) && \
28 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))
29 extern char PRIdMAX_probe[sizeof PRIdMAX == sizeof "I64d" ? 1 : -1];
30 #endif
31 ]])], [gl_cv_func_printf_attribute_flavor=system],
32 [gl_cv_func_printf_attribute_flavor=gnu])])
27 if test "$gl_cv_func_printf_attribute_flavor" = gnu; then 33 if test "$gl_cv_func_printf_attribute_flavor" = gnu; then
28 AC_DEFINE([GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU], [1], 34 AC_DEFINE([GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU], [1],
29 [Define to 1 if printf and friends should be labeled with 35 [Define to 1 if printf and friends should be labeled with
diff --git a/nt/gnulib.mk b/nt/gnulib.mk
index 26a9ea9ad53..cab20d911b8 100644
--- a/nt/gnulib.mk
+++ b/nt/gnulib.mk
@@ -43,7 +43,7 @@
43# the same distribution terms as the rest of that program. 43# the same distribution terms as the rest of that program.
44# 44#
45# Generated by gnulib-tool. 45# Generated by gnulib-tool.
46# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings 46# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings
47 47
48 48
49MOSTLYCLEANFILES += core *.stackdump 49MOSTLYCLEANFILES += core *.stackdump
@@ -64,6 +64,17 @@ HAVE_INCLUDE_NEXT = (__GNUC__ || 60000000 <= __DECC_VER)
64 64
65## end gnulib module absolute-header 65## end gnulib module absolute-header
66 66
67## begin gnulib module acl-permissions
68
69libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c \
70 get-permissions.c set-permissions.c
71
72EXTRA_DIST += acl-internal.h acl.h acl_entries.c
73
74EXTRA_libgnu_a_SOURCES += acl_entries.c
75
76## end gnulib module acl-permissions
77
67## begin gnulib module alloca-opt 78## begin gnulib module alloca-opt
68 79
69BUILT_SOURCES += $(ALLOCA_H) 80BUILT_SOURCES += $(ALLOCA_H)
@@ -521,15 +532,11 @@ EXTRA_libgnu_a_SOURCES += putenv.c
521 532
522## end gnulib module putenv 533## end gnulib module putenv
523 534
524## begin gnulib module qacl 535## begin gnulib module qcopy-acl
525
526libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c qcopy-acl.c
527 536
528EXTRA_DIST += acl-internal.h acl.h acl_entries.c 537libgnu_a_SOURCES += qcopy-acl.c
529
530EXTRA_libgnu_a_SOURCES += acl_entries.c
531 538
532## end gnulib module qacl 539## end gnulib module qcopy-acl
533 540
534## begin gnulib module readlink 541## begin gnulib module readlink
535 542