hash-set, linkedhash-set: Reduce code duplication.
[gnulib.git] / lib / file-has-acl.c
blob97fb08aaa5d8a80615929b1b86d95ce5d85722e7
1 /* Test whether a file has a nontrivial ACL. -*- coding: utf-8 -*-
3 Copyright (C) 2002-2003, 2005-2018 Free Software Foundation, Inc.
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
20 /* Without this pragma, gcc 4.7.0 20120126 may suggest that the
21 file_has_acl function might be candidate for attribute 'const' */
22 #if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
23 # pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
24 #endif
26 #include <config.h>
28 #include "acl.h"
30 #include "acl-internal.h"
32 #if GETXATTR_WITH_POSIX_ACLS
33 # include <sys/xattr.h>
34 # include <linux/xattr.h>
35 #endif
37 /* Return 1 if NAME has a nontrivial access control list,
38 0 if ACLs are not supported, or if NAME has no or only a base ACL,
39 and -1 (setting errno) on error. Note callers can determine
40 if ACLs are not supported as errno is set in that case also.
41 SB must be set to the stat buffer of NAME,
42 obtained through stat() or lstat(). */
44 int
45 file_has_acl (char const *name, struct stat const *sb)
47 #if USE_ACL
48 if (! S_ISLNK (sb->st_mode))
51 # if GETXATTR_WITH_POSIX_ACLS
53 ssize_t ret;
55 ret = getxattr (name, XATTR_NAME_POSIX_ACL_ACCESS, NULL, 0);
56 if (ret < 0 && errno == ENODATA)
57 ret = 0;
58 else if (ret > 0)
59 return 1;
61 if (ret == 0 && S_ISDIR (sb->st_mode))
63 ret = getxattr (name, XATTR_NAME_POSIX_ACL_DEFAULT, NULL, 0);
64 if (ret < 0 && errno == ENODATA)
65 ret = 0;
66 else if (ret > 0)
67 return 1;
70 if (ret < 0)
71 return - acl_errno_valid (errno);
72 return ret;
74 # elif HAVE_ACL_GET_FILE
76 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
77 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
78 int ret;
80 if (HAVE_ACL_EXTENDED_FILE) /* Linux */
82 /* On Linux, acl_extended_file is an optimized function: It only
83 makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
84 ACL_TYPE_DEFAULT. */
85 ret = acl_extended_file (name);
87 else /* FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
89 # if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
90 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
91 and acl_get_file (name, ACL_TYPE_DEFAULT)
92 always return NULL / EINVAL. There is no point in making
93 these two useless calls. The real ACL is retrieved through
94 acl_get_file (name, ACL_TYPE_EXTENDED). */
95 acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
96 if (acl)
98 ret = acl_extended_nontrivial (acl);
99 acl_free (acl);
101 else
102 ret = -1;
103 # else /* FreeBSD, IRIX, Tru64, Cygwin >= 2.5 */
104 acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
105 if (acl)
107 int saved_errno;
109 ret = acl_access_nontrivial (acl);
110 saved_errno = errno;
111 acl_free (acl);
112 errno = saved_errno;
113 # if HAVE_ACL_FREE_TEXT /* Tru64 */
114 /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
115 returns NULL with errno not set. There is no point in
116 making this call. */
117 # else /* FreeBSD, IRIX, Cygwin >= 2.5 */
118 /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
119 and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
120 either both succeed or both fail; it depends on the
121 file system. Therefore there is no point in making the second
122 call if the first one already failed. */
123 if (ret == 0 && S_ISDIR (sb->st_mode))
125 acl = acl_get_file (name, ACL_TYPE_DEFAULT);
126 if (acl)
128 # ifdef __CYGWIN__ /* Cygwin >= 2.5 */
129 ret = acl_access_nontrivial (acl);
130 saved_errno = errno;
131 acl_free (acl);
132 errno = saved_errno;
133 # else
134 ret = (0 < acl_entries (acl));
135 acl_free (acl);
136 # endif
138 else
139 ret = -1;
141 # endif
143 else
144 ret = -1;
145 # endif
147 if (ret < 0)
148 return - acl_errno_valid (errno);
149 return ret;
151 # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
153 # if defined ACL_NO_TRIVIAL
155 /* Solaris 10 (newer version), which has additional API declared in
156 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
157 acl_fromtext, ...). */
158 return acl_trivial (name);
160 # else /* Solaris, Cygwin, general case */
162 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
163 of Unixware. The acl() call returns the access and default ACL both
164 at once. */
166 /* Initially, try to read the entries into a stack-allocated buffer.
167 Use malloc if it does not fit. */
168 enum
170 alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */
171 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))
173 aclent_t buf[alloc_init];
174 size_t alloc = alloc_init;
175 aclent_t *entries = buf;
176 aclent_t *malloced = NULL;
177 int count;
179 for (;;)
181 count = acl (name, GETACL, alloc, entries);
182 if (count < 0 && errno == ENOSPC)
184 /* Increase the size of the buffer. */
185 free (malloced);
186 if (alloc > alloc_max / 2)
188 errno = ENOMEM;
189 return -1;
191 alloc = 2 * alloc; /* <= alloc_max */
192 entries = malloced =
193 (aclent_t *) malloc (alloc * sizeof (aclent_t));
194 if (entries == NULL)
196 errno = ENOMEM;
197 return -1;
199 continue;
201 break;
203 if (count < 0)
205 if (errno == ENOSYS || errno == ENOTSUP)
207 else
209 int saved_errno = errno;
210 free (malloced);
211 errno = saved_errno;
212 return -1;
215 else if (count == 0)
217 else
219 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin
220 returns only 3 entries for files with no ACL. But this is safe:
221 If there are more than 4 entries, there cannot be only the
222 "user::", "group::", "other:", and "mask:" entries. */
223 if (count > 4)
225 free (malloced);
226 return 1;
229 if (acl_nontrivial (count, entries))
231 free (malloced);
232 return 1;
235 free (malloced);
238 # ifdef ACE_GETACL
239 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
240 file systems (whereas the other ones are used in UFS file systems). */
242 /* Initially, try to read the entries into a stack-allocated buffer.
243 Use malloc if it does not fit. */
244 enum
246 alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
247 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
249 ace_t buf[alloc_init];
250 size_t alloc = alloc_init;
251 ace_t *entries = buf;
252 ace_t *malloced = NULL;
253 int count;
255 for (;;)
257 count = acl (name, ACE_GETACL, alloc, entries);
258 if (count < 0 && errno == ENOSPC)
260 /* Increase the size of the buffer. */
261 free (malloced);
262 if (alloc > alloc_max / 2)
264 errno = ENOMEM;
265 return -1;
267 alloc = 2 * alloc; /* <= alloc_max */
268 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
269 if (entries == NULL)
271 errno = ENOMEM;
272 return -1;
274 continue;
276 break;
278 if (count < 0)
280 if (errno == ENOSYS || errno == EINVAL)
282 else
284 int saved_errno = errno;
285 free (malloced);
286 errno = saved_errno;
287 return -1;
290 else if (count == 0)
292 else
294 /* In the old (original Solaris 10) convention:
295 If there are more than 3 entries, there cannot be only the
296 ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
297 In the newer Solaris 10 and Solaris 11 convention:
298 If there are more than 6 entries, there cannot be only the
299 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
300 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
301 NEW_ACE_ACCESS_DENIED_ACE_TYPE. */
302 if (count > 6)
304 free (malloced);
305 return 1;
308 if (acl_ace_nontrivial (count, entries))
310 free (malloced);
311 return 1;
314 free (malloced);
316 # endif
318 return 0;
319 # endif
321 # elif HAVE_GETACL /* HP-UX */
324 struct acl_entry entries[NACLENTRIES];
325 int count;
327 count = getacl (name, NACLENTRIES, entries);
329 if (count < 0)
331 /* ENOSYS is seen on newer HP-UX versions.
332 EOPNOTSUPP is typically seen on NFS mounts.
333 ENOTSUP was seen on Quantum StorNext file systems (cvfs). */
334 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
336 else
337 return -1;
339 else if (count == 0)
340 return 0;
341 else /* count > 0 */
343 if (count > NACLENTRIES)
344 /* If NACLENTRIES cannot be trusted, use dynamic memory
345 allocation. */
346 abort ();
348 /* If there are more than 3 entries, there cannot be only the
349 (uid,%), (%,gid), (%,%) entries. */
350 if (count > 3)
351 return 1;
354 struct stat statbuf;
356 if (stat (name, &statbuf) < 0)
357 return -1;
359 return acl_nontrivial (count, entries);
364 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
367 struct acl entries[NACLVENTRIES];
368 int count;
370 count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
372 if (count < 0)
374 /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
375 EINVAL is seen on NFS in HP-UX 11.31. */
376 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
378 else
379 return -1;
381 else if (count == 0)
382 return 0;
383 else /* count > 0 */
385 if (count > NACLVENTRIES)
386 /* If NACLVENTRIES cannot be trusted, use dynamic memory
387 allocation. */
388 abort ();
390 /* If there are more than 4 entries, there cannot be only the
391 four base ACL entries. */
392 if (count > 4)
393 return 1;
395 return aclv_nontrivial (count, entries);
399 # endif
401 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
403 acl_type_t type;
404 char aclbuf[1024];
405 void *acl = aclbuf;
406 size_t aclsize = sizeof (aclbuf);
407 mode_t mode;
409 for (;;)
411 /* The docs say that type being 0 is equivalent to ACL_ANY, but it
412 is not true, in AIX 5.3. */
413 type.u64 = ACL_ANY;
414 if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
415 break;
416 if (errno == ENOSYS)
417 return 0;
418 if (errno != ENOSPC)
420 if (acl != aclbuf)
422 int saved_errno = errno;
423 free (acl);
424 errno = saved_errno;
426 return -1;
428 aclsize = 2 * aclsize;
429 if (acl != aclbuf)
430 free (acl);
431 acl = malloc (aclsize);
432 if (acl == NULL)
434 errno = ENOMEM;
435 return -1;
439 if (type.u64 == ACL_AIXC)
441 int result = acl_nontrivial ((struct acl *) acl);
442 if (acl != aclbuf)
443 free (acl);
444 return result;
446 else if (type.u64 == ACL_NFS4)
448 int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
449 if (acl != aclbuf)
450 free (acl);
451 return result;
453 else
455 /* A newer type of ACL has been introduced in the system.
456 We should better support it. */
457 if (acl != aclbuf)
458 free (acl);
459 errno = EINVAL;
460 return -1;
463 # elif HAVE_STATACL /* older AIX */
465 union { struct acl a; char room[4096]; } u;
467 if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0)
468 return -1;
470 return acl_nontrivial (&u.a);
472 # elif HAVE_ACLSORT /* NonStop Kernel */
475 struct acl entries[NACLENTRIES];
476 int count;
478 count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
480 if (count < 0)
482 if (errno == ENOSYS || errno == ENOTSUP)
484 else
485 return -1;
487 else if (count == 0)
488 return 0;
489 else /* count > 0 */
491 if (count > NACLENTRIES)
492 /* If NACLENTRIES cannot be trusted, use dynamic memory
493 allocation. */
494 abort ();
496 /* If there are more than 4 entries, there cannot be only the
497 four base ACL entries. */
498 if (count > 4)
499 return 1;
501 return acl_nontrivial (count, entries);
505 # endif
507 #endif
509 return 0;