1 /* Test whether a file has a nontrivial ACL. -*- coding: utf-8 -*-
3 Copyright (C) 2002-2003, 2005-2025 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. */
22 /* Without this pragma, gcc 4.7.0 20120126 may suggest that the
23 file_has_acl function might be candidate for attribute 'const' */
24 #if _GL_GNUC_PREREQ (4, 6)
25 # pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
33 #include "acl-internal.h"
34 #include "attribute.h"
37 /* Check the assumption that UCHAR_MAX < INT_MAX. */
38 static_assert (ACL_SYMLINK_FOLLOW
& ~ (unsigned char) -1);
40 static char const UNKNOWN_SECURITY_CONTEXT
[] = "?";
42 #if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR
43 # define USE_LINUX_XATTR true
45 # define USE_LINUX_XATTR false
49 # if USE_SELINUX_SELINUX_H
50 # include <selinux/selinux.h>
52 # include <stdckdint.h>
55 # include <arpa/inet.h>
56 # include <sys/xattr.h>
57 # include <linux/xattr.h>
58 # ifndef XATTR_NAME_SMACK
59 # define XATTR_NAME_SMACK "security.SMACK64"
61 # ifndef XATTR_NAME_SELINUX
62 # define XATTR_NAME_SELINUX "security.selinux"
64 # ifndef XATTR_NAME_NFSV4_ACL
65 # define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
67 # ifndef XATTR_NAME_POSIX_ACL_ACCESS
68 # define XATTR_NAME_POSIX_ACL_ACCESS "system.posix_acl_access"
70 # ifndef XATTR_NAME_POSIX_ACL_DEFAULT
71 # define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
75 # include <sys/smack.h>
78 smack_smackfs_path (void)
83 smack_new_label_from_path (MAYBE_UNUSED
const char *path
,
84 MAYBE_UNUSED
const char *xattr
,
85 MAYBE_UNUSED
int follow
, MAYBE_UNUSED
char **label
)
91 is_smack_enabled (void)
93 return !!smack_smackfs_path ();
97 /* ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000, */
98 ACE4_ACCESS_DENIED_ACE_TYPE
= 0x00000001,
99 ACE4_IDENTIFIER_GROUP
= 0x00000040
102 /* AI indicates XATTR may be present but wasn't accessible.
103 This is the case when [l]listxattr failed with E2BIG,
104 or is not supported (!acl_errno_valid()), or failed with EACCES
105 which in Linux kernel 6.12 NFS can mean merely that we lack read access.
109 aclinfo_may_indicate_xattr (struct aclinfo
const *ai
)
111 return ai
->size
< 0 && (!acl_errno_valid (ai
->u
.err
)
112 || ai
->u
.err
== EACCES
|| ai
->u
.err
== E2BIG
);
115 /* Does NAME have XATTR? */
118 has_xattr (char const *xattr
, struct aclinfo
const *ai
,
119 MAYBE_UNUSED
char const *restrict name
, MAYBE_UNUSED
int flags
)
121 if (ai
&& aclinfo_has_xattr (ai
, xattr
))
123 else if (!ai
|| aclinfo_may_indicate_xattr (ai
))
125 int ret
= ((flags
& ACL_SYMLINK_FOLLOW
? getxattr
: lgetxattr
)
126 (name
, xattr
, NULL
, 0));
127 if (0 <= ret
|| (errno
== ERANGE
|| errno
== E2BIG
))
133 /* Does AI's xattr set contain XATTR? */
136 aclinfo_has_xattr (struct aclinfo
const *ai
, char const *xattr
)
140 char const *blim
= ai
->buf
+ ai
->size
;
141 for (char const *b
= ai
->buf
; b
< blim
; b
+= strlen (b
) + 1)
142 for (char const *a
= xattr
; *a
== *b
; a
++, b
++)
149 /* Get attributes of the file NAME into AI, if USE_ACL.
150 If FLAGS & ACL_GET_SCONTEXT, also get security context.
151 If FLAGS & ACL_SYMLINK_FOLLOW, follow symbolic links. */
153 get_aclinfo (char const *name
, struct aclinfo
*ai
, int flags
)
155 int scontext_err
= ENOTSUP
;
156 ai
->buf
= ai
->u
.__gl_acl_ch
;
157 ssize_t acl_alloc
= sizeof ai
->u
.__gl_acl_ch
;
159 if (! (USE_ACL
|| flags
& ACL_GET_SCONTEXT
))
163 ssize_t (*lsxattr
) (char const *, char *, size_t)
164 = (flags
& ACL_SYMLINK_FOLLOW
? listxattr
: llistxattr
);
167 ai
->size
= lsxattr (name
, ai
->buf
, acl_alloc
);
170 ai
->u
.err
= ai
->size
< 0 ? errno
: 0;
171 if (! (ai
->size
< 0 && ai
->u
.err
== ERANGE
&& acl_alloc
< SSIZE_MAX
))
174 /* The buffer was too small. Find how large it should have been. */
175 ssize_t size
= lsxattr (name
, NULL
, 0);
179 ai
->u
.err
= size
< 0 ? errno
: 0;
183 /* Grow allocation to at least 'size'. Grow it by a nontrivial
184 amount, to defend against denial of service by an adversary
185 that fiddles with ACLs. */
186 if (ai
->buf
!= ai
->u
.__gl_acl_ch
)
189 ai
->buf
= ai
->u
.__gl_acl_ch
;
191 if (ckd_add (&acl_alloc
, acl_alloc
, acl_alloc
>> 1))
192 acl_alloc
= SSIZE_MAX
;
193 if (acl_alloc
< size
)
195 if (SIZE_MAX
< acl_alloc
)
200 char *newbuf
= malloc (acl_alloc
);
210 /* A security context can exist only if extended attributes do. */
211 if (flags
& ACL_GET_SCONTEXT
212 && (0 < ai
->size
|| aclinfo_may_indicate_xattr (ai
)))
214 if (is_smack_enabled ())
216 if (ai
->size
< 0 || aclinfo_has_xattr (ai
, XATTR_NAME_SMACK
))
218 ssize_t r
= smack_new_label_from_path (name
, "security.SMACK64",
219 flags
& ACL_SYMLINK_FOLLOW
,
221 scontext_err
= r
< 0 ? errno
: 0;
226 # if USE_SELINUX_SELINUX_H
227 if (ai
->size
< 0 || aclinfo_has_xattr (ai
, XATTR_NAME_SELINUX
))
230 ((flags
& ACL_SYMLINK_FOLLOW
? getfilecon
: lgetfilecon
)
231 (name
, &ai
->scontext
));
232 scontext_err
= r
< 0 ? errno
: 0;
233 # ifndef SE_SELINUX_INLINE
234 /* Gnulib's selinux-h module is not in use, so getfilecon and
235 lgetfilecon can misbehave, be it via an old version of
236 libselinux where these would return 0 and set the result
237 context to NULL, or via a modern kernel+lib operating on a
238 file from a disk whose attributes were set by a kernel from
239 around 2006. In that latter case, the functions return a
240 length of 10 for the "unlabeled" context. Map both failures
241 to a return value of -1, and set errno to ENOTSUP in the
242 first case, and ENODATA in the latter. */
244 scontext_err
= ENOTSUP
;
245 if (r
== 10 && memcmp (ai
->scontext
, "unlabeled", 10) == 0)
247 freecon (ai
->scontext
);
248 scontext_err
= ENODATA
;
255 ai
->scontext_err
= scontext_err
;
257 ai
->scontext
= (char *) UNKNOWN_SECURITY_CONTEXT
;
260 # ifndef aclinfo_scontext_free
261 /* Free the pointer that file_has_aclinfo put into scontext.
262 However, do nothing if the argument is a null pointer;
263 This lets the caller replace the scontext member with a null pointer if it
264 is willing to own the member and call this function later. */
266 aclinfo_scontext_free (char *scontext
)
268 if (scontext
!= UNKNOWN_SECURITY_CONTEXT
)
270 if (is_smack_enabled ())
278 /* Free AI's heap storage. */
280 aclinfo_free (struct aclinfo
*ai
)
282 if (ai
->buf
!= ai
->u
.__gl_acl_ch
)
284 aclinfo_scontext_free (ai
->scontext
);
287 /* Return 1 if given ACL in XDR format is non-trivial, 0 if it is trivial.
288 -1 upon failure to determine it. Possibly change errno. Assume that
289 the ACL is valid, except avoid undefined behavior even if invalid.
291 See <https://linux.die.net/man/5/nfs4_acl>. The NFSv4 acls are
292 defined in Internet RFC 7530 and as such, every NFSv4 server
293 supporting ACLs should support NFSv4 ACLs (they differ from from
294 POSIX draft ACLs). The ACLs can be obtained via the
295 nfsv4-acl-tools, e.g., the nfs4_getfacl command. Gnulib provides
296 only basic support of NFSv4 ACLs, i.e., recognize trivial vs
300 acl_nfs4_nontrivial (uint32_t *xattr
, ssize_t nbytes
)
302 enum { BYTES_PER_NETWORK_UINT
= 4};
304 /* Grab the number of aces in the acl. */
305 nbytes
-= BYTES_PER_NETWORK_UINT
;
308 uint32_t num_aces
= ntohl (*xattr
++);
313 for (int ace_n
= 0; ace_n
< num_aces
; ace_n
++)
315 /* Get the acl type and flag. Skip the mask; it's too risky to
316 test it and it does not seem to be needed. Get the wholen. */
317 nbytes
-= 4 * BYTES_PER_NETWORK_UINT
;
320 uint32_t type
= ntohl (xattr
[0]);
321 uint32_t flag
= ntohl (xattr
[1]);
322 uint32_t wholen
= ntohl (xattr
[3]);
324 int whowords
= (wholen
/ BYTES_PER_NETWORK_UINT
325 + (wholen
% BYTES_PER_NETWORK_UINT
!= 0));
326 int64_t wholen4
= whowords
;
327 wholen4
*= BYTES_PER_NETWORK_UINT
;
329 /* Trivial ACLs have only ACE4_ACCESS_ALLOWED_ACE_TYPE or
330 ACE4_ACCESS_DENIED_ACE_TYPE. */
331 if (ACE4_ACCESS_DENIED_ACE_TYPE
< type
)
334 /* RFC 7530 says FLAG should be 0, but be generous to NetApp and
335 also accept the group flag. */
336 if (flag
& ~ACE4_IDENTIFIER_GROUP
)
339 /* Get the who string. Check NBYTES - WHOLEN4 before storing
340 into NBYTES, to avoid truncation on conversion. */
341 if (nbytes
- wholen4
< 0)
345 /* For a trivial ACL, max 6 (typically 3) ACEs, 3 allow, 3 deny.
346 Check that there is at most one ACE of each TYPE and WHO. */
348 = (wholen
== 6 && memcmp (xattr
, "OWNER@", 6) == 0 ? 0
349 : wholen
== 6 && memcmp (xattr
, "GROUP@", 6) == 0 ? 2
350 : wholen
== 9 && memcmp (xattr
, "EVERYONE@", 9) == 0 ? 4
354 int ace_found_bit
= 1 << (who2
| type
);
355 if (ace_found
& ace_found_bit
)
357 ace_found
|= ace_found_bit
;
366 /* Return 1 if NAME has a nontrivial access control list,
367 0 if ACLs are not supported, or if NAME has no or only a base ACL,
368 and -1 (setting errno) on error. Note callers can determine
369 if ACLs are not supported as errno is set in that case also.
370 Set *AI to ACL info regardless of return value.
371 FLAGS should be a <dirent.h> d_type value, optionally ORed with
372 - _GL_DT_NOTDIR if it is known that NAME is not a directory,
373 - ACL_GET_SCONTEXT to retrieve security context and return 1 if present,
374 - ACL_SYMLINK_FOLLOW to follow the link if NAME is a symbolic link;
375 otherwise do not follow them if possible.
376 If the d_type value is not known, use DT_UNKNOWN though this may be less
379 file_has_aclinfo (MAYBE_UNUSED
char const *restrict name
,
380 struct aclinfo
*restrict ai
, int flags
)
382 MAYBE_UNUSED
unsigned char d_type
= flags
& UCHAR_MAX
;
385 int initial_errno
= errno
;
386 get_aclinfo (name
, ai
, flags
);
388 if (!aclinfo_may_indicate_xattr (ai
) && ai
->size
<= 0)
390 errno
= ai
->size
< 0 ? ai
->u
.err
: initial_errno
;
394 /* In Fedora 39, a file can have both NFSv4 and POSIX ACLs,
395 but if it has an NFSv4 ACL that's the one that matters.
396 In earlier Fedora the two types of ACLs were mutually exclusive.
397 Attempt to work correctly on both kinds of systems. */
399 if (!has_xattr (XATTR_NAME_NFSV4_ACL
, ai
, name
, flags
))
401 (has_xattr (XATTR_NAME_POSIX_ACL_ACCESS
, ai
, name
, flags
)
402 || ((d_type
== DT_DIR
|| d_type
== DT_UNKNOWN
)
403 && has_xattr (XATTR_NAME_POSIX_ACL_DEFAULT
, ai
, name
, flags
)));
405 /* A buffer large enough to hold any trivial NFSv4 ACL.
406 The max length of a trivial NFSv4 ACL is 6 words for owner,
407 6 for group, 7 for everyone, all times 2 because there are both
408 allow and deny ACEs. There are 6 words for owner because of
409 type, flag, mask, wholen, "OWNER@"+pad and similarly for group;
410 everyone is another word to hold "EVERYONE@". */
411 uint32_t buf
[2 * (6 + 6 + 7)];
413 int ret
= ((flags
& ACL_SYMLINK_FOLLOW
? getxattr
: lgetxattr
)
414 (name
, XATTR_NAME_NFSV4_ACL
, buf
, sizeof buf
));
418 case ENODATA
: return 0;
419 case ERANGE
: return 1; /* ACL must be nontrivial. */
420 default: return - acl_errno_valid (errno
);
423 /* It looks like a trivial ACL, but investigate further. */
424 ret
= acl_nfs4_nontrivial (buf
, ret
);
425 errno
= ret
< 0 ? EINVAL
: initial_errno
;
428 #else /* !USE_LINUX_XATTR */
430 ai
->buf
= ai
->u
.__gl_acl_ch
;
433 ai
->scontext
= (char *) UNKNOWN_SECURITY_CONTEXT
;
434 ai
->scontext_err
= ENOTSUP
;
437 # if HAVE_ACL_GET_FILE
440 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
441 /* Linux, FreeBSD, NetBSD >= 10, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
444 # if HAVE_ACL_EXTENDED_FILE /* Linux */
445 /* On Linux, acl_extended_file is an optimized function: It only
446 makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
448 ret
= ((flags
& ACL_SYMLINK_FOLLOW
450 : acl_extended_file_nofollow
)
452 # elif HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
453 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
454 and acl_get_file (name, ACL_TYPE_DEFAULT)
455 always return NULL / EINVAL. There is no point in making
456 these two useless calls. The real ACL is retrieved through
457 acl_get_file (name, ACL_TYPE_EXTENDED). */
458 acl_t acl
= ((flags
& ACL_SYMLINK_FOLLOW
461 (name
, ACL_TYPE_EXTENDED
));
464 ret
= acl_extended_nontrivial (acl
);
469 # else /* FreeBSD, NetBSD >= 10, IRIX, Tru64, Cygwin >= 2.5 */
470 acl_t (*acl_get_file_or_link
) (char const *, acl_type_t
) = acl_get_file
;
471 # if HAVE_ACL_GET_LINK_NP /* FreeBSD, NetBSD >= 10 */
472 if (! (flags
& ACL_SYMLINK_FOLLOW
))
473 acl_get_file_or_link
= acl_get_link_np
;
476 acl_t acl
= acl_get_file_or_link (name
, ACL_TYPE_ACCESS
);
479 ret
= acl_access_nontrivial (acl
);
480 int saved_errno
= errno
;
483 # if HAVE_ACL_FREE_TEXT /* Tru64 */
484 /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
485 returns NULL with errno not set. There is no point in
487 # else /* FreeBSD, NetBSD >= 10, IRIX, Cygwin >= 2.5 */
488 /* On Linux, FreeBSD, NetBSD, IRIX,
489 acl_get_file (name, ACL_TYPE_ACCESS)
490 and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
491 either both succeed or both fail; it depends on the
492 file system. Therefore there is no point in making the second
493 call if the first one already failed. */
496 || (d_type
== DT_UNKNOWN
&& !(flags
& _GL_DT_NOTDIR
))))
498 acl
= acl_get_file_or_link (name
, ACL_TYPE_DEFAULT
);
501 # ifdef __CYGWIN__ /* Cygwin >= 2.5 */
502 ret
= acl_access_nontrivial (acl
);
507 ret
= (0 < acl_entries (acl
));
514 # ifdef __CYGWIN__ /* Cygwin >= 2.5 */
515 if (d_type
== DT_UNKNOWN
)
526 return ret
< 0 ? - acl_errno_valid (errno
) : ret
;
529 # else /* !HAVE_ACL_GET_FILE */
531 /* The remaining APIs always follow symlinks and operate on
532 platforms where symlinks do not have ACLs, so skip the APIs if
533 NAME is known to be a symlink. */
534 if (d_type
!= DT_LNK
)
537 # if HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
539 # ifdef ACL_NO_TRIVIAL
541 /* Solaris 10 (newer version), which has additional API declared in
542 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
543 acl_fromtext, ...). */
544 return acl_trivial (name
);
546 # else /* Solaris, Cygwin, general case */
548 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
549 of Unixware. The acl() call returns the access and default ACL both
552 /* Initially, try to read the entries into a stack-allocated buffer.
553 Use malloc if it does not fit. */
556 alloc_init
= 4000 / sizeof (aclent_t
), /* >= 3 */
557 alloc_max
= MIN (INT_MAX
, SIZE_MAX
/ sizeof (aclent_t
))
559 aclent_t buf
[alloc_init
];
560 size_t alloc
= alloc_init
;
561 aclent_t
*entries
= buf
;
562 aclent_t
*malloced
= NULL
;
567 count
= acl (name
, GETACL
, alloc
, entries
);
568 if (count
< 0 && errno
== ENOSPC
)
570 /* Increase the size of the buffer. */
572 if (alloc
> alloc_max
/ 2)
577 alloc
= 2 * alloc
; /* <= alloc_max */
579 (aclent_t
*) malloc (alloc
* sizeof (aclent_t
));
588 if (errno
== ENOSYS
|| errno
== ENOTSUP
)
600 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin
601 returns only 3 entries for files with no ACL. But this is safe:
602 If there are more than 4 entries, there cannot be only the
603 "user::", "group::", "other:", and "mask:" entries. */
610 if (acl_nontrivial (count
, entries
))
620 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
621 file systems (whereas the other ones are used in UFS file systems). */
623 /* Initially, try to read the entries into a stack-allocated buffer.
624 Use malloc if it does not fit. */
627 alloc_init
= 4000 / sizeof (ace_t
), /* >= 3 */
628 alloc_max
= MIN (INT_MAX
, SIZE_MAX
/ sizeof (ace_t
))
630 ace_t buf
[alloc_init
];
631 size_t alloc
= alloc_init
;
632 ace_t
*entries
= buf
;
633 ace_t
*malloced
= NULL
;
638 count
= acl (name
, ACE_GETACL
, alloc
, entries
);
639 if (count
< 0 && errno
== ENOSPC
)
641 /* Increase the size of the buffer. */
643 if (alloc
> alloc_max
/ 2)
648 alloc
= 2 * alloc
; /* <= alloc_max */
649 entries
= malloced
= (ace_t
*) malloc (alloc
* sizeof (ace_t
));
658 if (errno
== ENOSYS
|| errno
== EINVAL
)
670 /* In the old (original Solaris 10) convention:
671 If there are more than 3 entries, there cannot be only the
672 ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
673 In the newer Solaris 10 and Solaris 11 convention:
674 If there are more than 6 entries, there cannot be only the
675 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
676 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
677 NEW_ACE_ACCESS_DENIED_ACE_TYPE. */
684 if (acl_ace_nontrivial (count
, entries
))
697 # elif HAVE_GETACL /* HP-UX */
700 struct acl_entry entries
[NACLENTRIES
];
703 count
= getacl (name
, NACLENTRIES
, entries
);
707 /* ENOSYS is seen on newer HP-UX versions.
708 EOPNOTSUPP is typically seen on NFS mounts.
709 ENOTSUP was seen on Quantum StorNext file systems (cvfs). */
710 if (errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== ENOTSUP
)
719 if (count
> NACLENTRIES
)
720 /* If NACLENTRIES cannot be trusted, use dynamic memory
724 /* If there are more than 3 entries, there cannot be only the
725 (uid,%), (%,gid), (%,%) entries. */
732 if (stat (name
, &statbuf
) == -1 && errno
!= EOVERFLOW
)
735 return acl_nontrivial (count
, entries
);
740 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
743 struct acl entries
[NACLVENTRIES
];
746 count
= acl ((char *) name
, ACL_GET
, NACLVENTRIES
, entries
);
750 /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
751 EINVAL is seen on NFS in HP-UX 11.31. */
752 if (errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== EINVAL
)
761 if (count
> NACLVENTRIES
)
762 /* If NACLVENTRIES cannot be trusted, use dynamic memory
766 /* If there are more than 4 entries, there cannot be only the
767 four base ACL entries. */
771 return aclv_nontrivial (count
, entries
);
777 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
782 size_t aclsize
= sizeof (aclbuf
);
787 /* The docs say that type being 0 is equivalent to ACL_ANY, but it
788 is not true, in AIX 5.3. */
790 if (aclx_get (name
, 0, &type
, aclbuf
, &aclsize
, &mode
) >= 0)
800 aclsize
= 2 * aclsize
;
803 acl
= malloc (aclsize
);
808 if (type
.u64
== ACL_AIXC
)
810 int result
= acl_nontrivial ((struct acl
*) acl
);
815 else if (type
.u64
== ACL_NFS4
)
817 int result
= acl_nfs4_nontrivial ((nfs4_acl_int_t
*) acl
);
824 /* A newer type of ACL has been introduced in the system.
825 We should better support it. */
832 # elif HAVE_STATACL /* older AIX */
834 union { struct acl a
; char room
[4096]; } u
;
836 if (statacl ((char *) name
, STX_NORMAL
, &u
.a
, sizeof (u
)) < 0)
839 return acl_nontrivial (&u
.a
);
841 # elif HAVE_ACLSORT /* NonStop Kernel */
844 struct acl entries
[NACLENTRIES
];
847 count
= acl ((char *) name
, ACL_GET
, NACLENTRIES
, entries
);
851 if (errno
== ENOSYS
|| errno
== ENOTSUP
)
860 if (count
> NACLENTRIES
)
861 /* If NACLENTRIES cannot be trusted, use dynamic memory
865 /* If there are more than 4 entries, there cannot be only the
866 four base ACL entries. */
870 return acl_nontrivial (count
, entries
);
882 /* Return 1 if NAME has a nontrivial access control list,
883 0 if ACLs are not supported, or if NAME has no or only a base ACL,
884 and -1 (setting errno) on error. Note callers can determine
885 if ACLs are not supported as errno is set in that case also.
886 SB must be set to the stat buffer of NAME,
887 obtained through stat() or lstat(). */
889 file_has_acl (char const *name
, struct stat
const *sb
)
891 int flags
= IFTODT (sb
->st_mode
);
892 if (!S_ISDIR (sb
->st_mode
))
893 flags
|= _GL_DT_NOTDIR
;
895 int r
= file_has_aclinfo (name
, &ai
, flags
);