(root)/
tar-1.35/
gnu/
file-has-acl.c
       1  /* Test whether a file has a nontrivial ACL.  -*- coding: utf-8 -*-
       2  
       3     Copyright (C) 2002-2003, 2005-2023 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 <https://www.gnu.org/licenses/>.
      17  
      18     Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible.  */
      19  
      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
      25  
      26  #include <config.h>
      27  
      28  #include "acl.h"
      29  
      30  #include "acl-internal.h"
      31  #include "attribute.h"
      32  #include "minmax.h"
      33  
      34  #if USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR
      35  # include <stdckdint.h>
      36  # include <string.h>
      37  # include <arpa/inet.h>
      38  # include <sys/xattr.h>
      39  # include <linux/xattr.h>
      40  # ifndef XATTR_NAME_NFSV4_ACL
      41  #  define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
      42  # endif
      43  # ifndef XATTR_NAME_POSIX_ACL_ACCESS
      44  #  define XATTR_NAME_POSIX_ACL_ACCESS "system.posix_acl_access"
      45  # endif
      46  # ifndef XATTR_NAME_POSIX_ACL_DEFAULT
      47  #  define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
      48  # endif
      49  
      50  enum {
      51    /* ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000, */
      52    ACE4_ACCESS_DENIED_ACE_TYPE  = 0x00000001,
      53    ACE4_IDENTIFIER_GROUP        = 0x00000040
      54  };
      55  
      56  /* Return true if ATTR is in the set represented by the NUL-terminated
      57     strings in LISTBUF, which is of size LISTSIZE.  */
      58  
      59  ATTRIBUTE_PURE static bool
      60  have_xattr (char const *attr, char const *listbuf, ssize_t listsize)
      61  {
      62    char const *blim = listbuf + listsize;
      63    for (char const *b = listbuf; b < blim; b += strlen (b) + 1)
      64      for (char const *a = attr; *a == *b; a++, b++)
      65        if (!*a)
      66          return true;
      67    return false;
      68  }
      69  
      70  /* Return 1 if given ACL in XDR format is non-trivial, 0 if it is trivial.
      71     -1 upon failure to determine it.  Possibly change errno.  Assume that
      72     the ACL is valid, except avoid undefined behavior even if invalid.
      73  
      74     See <https://linux.die.net/man/5/nfs4_acl>.  The NFSv4 acls are
      75     defined in Internet RFC 7530 and as such, every NFSv4 server
      76     supporting ACLs should support NFSv4 ACLs (they differ from from
      77     POSIX draft ACLs).  The ACLs can be obtained via the
      78     nfsv4-acl-tools, e.g., the nfs4_getfacl command.  Gnulib provides
      79     only basic support of NFSv4 ACLs, i.e., recognize trivial vs
      80     nontrivial ACLs.  */
      81  
      82  static int
      83  acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes)
      84  {
      85    enum { BYTES_PER_NETWORK_UINT = 4};
      86  
      87    /* Grab the number of aces in the acl.  */
      88    nbytes -= BYTES_PER_NETWORK_UINT;
      89    if (nbytes < 0)
      90      return -1;
      91    uint32_t num_aces = ntohl (*xattr++);
      92    if (6 < num_aces)
      93      return 1;
      94    int ace_found = 0;
      95  
      96    for (int ace_n = 0; ace_n < num_aces; ace_n++)
      97      {
      98        /* Get the acl type and flag.  Skip the mask; it's too risky to
      99           test it and it does not seem to be needed.  Get the wholen.  */
     100        nbytes -= 4 * BYTES_PER_NETWORK_UINT;
     101        if (nbytes < 0)
     102          return -1;
     103        uint32_t type = ntohl (xattr[0]);
     104        uint32_t flag = ntohl (xattr[1]);
     105        uint32_t wholen = ntohl (xattr[3]);
     106        xattr += 4;
     107        int whowords = (wholen / BYTES_PER_NETWORK_UINT
     108                        + (wholen % BYTES_PER_NETWORK_UINT != 0));
     109        int64_t wholen4 = whowords;
     110        wholen4 *= BYTES_PER_NETWORK_UINT;
     111  
     112        /* Trivial ACLs have only ACE4_ACCESS_ALLOWED_ACE_TYPE or
     113           ACE4_ACCESS_DENIED_ACE_TYPE.  */
     114        if (ACE4_ACCESS_DENIED_ACE_TYPE < type)
     115          return 1;
     116  
     117        /* RFC 7530 says FLAG should be 0, but be generous to NetApp and
     118           also accept the group flag.  */
     119        if (flag & ~ACE4_IDENTIFIER_GROUP)
     120          return 1;
     121  
     122        /* Get the who string.  Check NBYTES - WHOLEN4 before storing
     123           into NBYTES, to avoid truncation on conversion.  */
     124        if (nbytes - wholen4 < 0)
     125          return -1;
     126        nbytes -= wholen4;
     127  
     128        /* For a trivial ACL, max 6 (typically 3) ACEs, 3 allow, 3 deny.
     129           Check that there is at most one ACE of each TYPE and WHO.  */
     130        int who2
     131          = (wholen == 6 && memcmp (xattr, "OWNER@", 6) == 0 ? 0
     132             : wholen == 6 && memcmp (xattr, "GROUP@", 6) == 0 ? 2
     133             : wholen == 9 && memcmp (xattr, "EVERYONE@", 9) == 0 ? 4
     134             : -1);
     135        if (who2 < 0)
     136          return 1;
     137        int ace_found_bit = 1 << (who2 | type);
     138        if (ace_found & ace_found_bit)
     139          return 1;
     140        ace_found |= ace_found_bit;
     141  
     142        xattr += whowords;
     143      }
     144  
     145    return 0;
     146  }
     147  #endif
     148  
     149  /* Return 1 if NAME has a nontrivial access control list,
     150     0 if ACLs are not supported, or if NAME has no or only a base ACL,
     151     and -1 (setting errno) on error.  Note callers can determine
     152     if ACLs are not supported as errno is set in that case also.
     153     SB must be set to the stat buffer of NAME,
     154     obtained through stat() or lstat().  */
     155  
     156  int
     157  file_has_acl (char const *name, struct stat const *sb)
     158  {
     159  #if USE_ACL
     160    if (! S_ISLNK (sb->st_mode))
     161      {
     162  
     163  # if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR
     164        int initial_errno = errno;
     165  
     166        /* The max length of a trivial NFSv4 ACL is 6 words for owner,
     167           6 for group, 7 for everyone, all times 2 because there are
     168           both allow and deny ACEs.  There are 6 words for owner
     169           because of type, flag, mask, wholen, "OWNER@"+pad and
     170           similarly for group; everyone is another word to hold
     171           "EVERYONE@".  */
     172        typedef uint32_t trivial_NFSv4_xattr_buf[2 * (6 + 6 + 7)];
     173  
     174        /* A buffer large enough to hold any trivial NFSv4 ACL,
     175           and also useful as a small array of char.  */
     176        union {
     177          trivial_NFSv4_xattr_buf xattr;
     178          char ch[sizeof (trivial_NFSv4_xattr_buf)];
     179        } stackbuf;
     180  
     181        char *listbuf = stackbuf.ch;
     182        ssize_t listbufsize = sizeof stackbuf.ch;
     183        char *heapbuf = NULL;
     184        ssize_t listsize;
     185  
     186        /* Use listxattr first, as this means just one syscall in the
     187           typical case where the file lacks an ACL.  Try stackbuf
     188           first, falling back on malloc if stackbuf is too small.  */
     189        while ((listsize = listxattr (name, listbuf, listbufsize)) < 0
     190               && errno == ERANGE)
     191          {
     192            free (heapbuf);
     193            ssize_t newsize = listxattr (name, NULL, 0);
     194            if (newsize <= 0)
     195              return newsize;
     196  
     197            /* Grow LISTBUFSIZE to at least NEWSIZE.  Grow it by a
     198               nontrivial amount too, to defend against denial of
     199               service by an adversary that fiddles with ACLs.  */
     200            bool overflow = ckd_add (&listbufsize, listbufsize, listbufsize >> 1);
     201            listbufsize = MAX (listbufsize, newsize);
     202            if (overflow || SIZE_MAX < listbufsize)
     203              {
     204                errno = ENOMEM;
     205                return -1;
     206              }
     207  
     208            listbuf = heapbuf = malloc (listbufsize);
     209            if (!listbuf)
     210              return -1;
     211          }
     212  
     213        /* In Fedora 39, a file can have both NFSv4 and POSIX ACLs,
     214           but if it has an NFSv4 ACL that's the one that matters.
     215           In earlier Fedora the two types of ACLs were mutually exclusive.
     216           Attempt to work correctly on both kinds of systems.  */
     217        bool nfsv4_acl
     218          = 0 < listsize && have_xattr (XATTR_NAME_NFSV4_ACL, listbuf, listsize);
     219        int ret
     220          = (listsize <= 0 ? listsize
     221             : (nfsv4_acl
     222                || have_xattr (XATTR_NAME_POSIX_ACL_ACCESS, listbuf, listsize)
     223                || (S_ISDIR (sb->st_mode)
     224                    && have_xattr (XATTR_NAME_POSIX_ACL_DEFAULT,
     225                                   listbuf, listsize))));
     226        free (heapbuf);
     227  
     228        /* If there is an NFSv4 ACL, follow up with a getxattr syscall
     229           to see whether the NFSv4 ACL is nontrivial.  */
     230        if (nfsv4_acl)
     231          {
     232            ret = getxattr (name, XATTR_NAME_NFSV4_ACL,
     233                            stackbuf.xattr, sizeof stackbuf.xattr);
     234            if (ret < 0)
     235              switch (errno)
     236                {
     237                case ENODATA: return 0;
     238                case ERANGE : return 1; /* ACL must be nontrivial.  */
     239                }
     240            else
     241              {
     242                /* It looks like a trivial ACL, but investigate further.  */
     243                ret = acl_nfs4_nontrivial (stackbuf.xattr, ret);
     244                if (ret < 0)
     245                  {
     246                    errno = EINVAL;
     247                    return ret;
     248                  }
     249                errno = initial_errno;
     250              }
     251          }
     252        if (ret < 0)
     253          return - acl_errno_valid (errno);
     254        return ret;
     255  
     256  # elif HAVE_ACL_GET_FILE
     257  
     258        /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
     259        /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
     260        int ret;
     261  
     262        if (HAVE_ACL_EXTENDED_FILE) /* Linux */
     263          {
     264            /* On Linux, acl_extended_file is an optimized function: It only
     265               makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
     266               ACL_TYPE_DEFAULT.  */
     267            ret = acl_extended_file (name);
     268          }
     269        else /* FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
     270          {
     271  #  if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
     272            /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
     273               and acl_get_file (name, ACL_TYPE_DEFAULT)
     274               always return NULL / EINVAL.  There is no point in making
     275               these two useless calls.  The real ACL is retrieved through
     276               acl_get_file (name, ACL_TYPE_EXTENDED).  */
     277            acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
     278            if (acl)
     279              {
     280                ret = acl_extended_nontrivial (acl);
     281                acl_free (acl);
     282              }
     283            else
     284              ret = -1;
     285  #  else /* FreeBSD, IRIX, Tru64, Cygwin >= 2.5 */
     286            acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
     287            if (acl)
     288              {
     289                int saved_errno;
     290  
     291                ret = acl_access_nontrivial (acl);
     292                saved_errno = errno;
     293                acl_free (acl);
     294                errno = saved_errno;
     295  #   if HAVE_ACL_FREE_TEXT /* Tru64 */
     296                /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
     297                   returns NULL with errno not set.  There is no point in
     298                   making this call.  */
     299  #   else /* FreeBSD, IRIX, Cygwin >= 2.5 */
     300                /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
     301                   and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
     302                   either both succeed or both fail; it depends on the
     303                   file system.  Therefore there is no point in making the second
     304                   call if the first one already failed.  */
     305                if (ret == 0 && S_ISDIR (sb->st_mode))
     306                  {
     307                    acl = acl_get_file (name, ACL_TYPE_DEFAULT);
     308                    if (acl)
     309                      {
     310  #    ifdef __CYGWIN__ /* Cygwin >= 2.5 */
     311                        ret = acl_access_nontrivial (acl);
     312                        saved_errno = errno;
     313                        acl_free (acl);
     314                        errno = saved_errno;
     315  #    else
     316                        ret = (0 < acl_entries (acl));
     317                        acl_free (acl);
     318  #    endif
     319                      }
     320                    else
     321                      ret = -1;
     322                  }
     323  #   endif
     324              }
     325            else
     326              ret = -1;
     327  #  endif
     328          }
     329        if (ret < 0)
     330          return - acl_errno_valid (errno);
     331        return ret;
     332  
     333  # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
     334  
     335  #  if defined ACL_NO_TRIVIAL
     336  
     337        /* Solaris 10 (newer version), which has additional API declared in
     338           <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
     339           acl_fromtext, ...).  */
     340        return acl_trivial (name);
     341  
     342  #  else /* Solaris, Cygwin, general case */
     343  
     344        /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
     345           of Unixware.  The acl() call returns the access and default ACL both
     346           at once.  */
     347        {
     348          /* Initially, try to read the entries into a stack-allocated buffer.
     349             Use malloc if it does not fit.  */
     350          enum
     351            {
     352              alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */
     353              alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))
     354            };
     355          aclent_t buf[alloc_init];
     356          size_t alloc = alloc_init;
     357          aclent_t *entries = buf;
     358          aclent_t *malloced = NULL;
     359          int count;
     360  
     361          for (;;)
     362            {
     363              count = acl (name, GETACL, alloc, entries);
     364              if (count < 0 && errno == ENOSPC)
     365                {
     366                  /* Increase the size of the buffer.  */
     367                  free (malloced);
     368                  if (alloc > alloc_max / 2)
     369                    {
     370                      errno = ENOMEM;
     371                      return -1;
     372                    }
     373                  alloc = 2 * alloc; /* <= alloc_max */
     374                  entries = malloced =
     375                    (aclent_t *) malloc (alloc * sizeof (aclent_t));
     376                  if (entries == NULL)
     377                    {
     378                      errno = ENOMEM;
     379                      return -1;
     380                    }
     381                  continue;
     382                }
     383              break;
     384            }
     385          if (count < 0)
     386            {
     387              if (errno == ENOSYS || errno == ENOTSUP)
     388                ;
     389              else
     390                {
     391                  free (malloced);
     392                  return -1;
     393                }
     394            }
     395          else if (count == 0)
     396            ;
     397          else
     398            {
     399              /* Don't use MIN_ACL_ENTRIES:  It's set to 4 on Cygwin, but Cygwin
     400                 returns only 3 entries for files with no ACL.  But this is safe:
     401                 If there are more than 4 entries, there cannot be only the
     402                 "user::", "group::", "other:", and "mask:" entries.  */
     403              if (count > 4)
     404                {
     405                  free (malloced);
     406                  return 1;
     407                }
     408  
     409              if (acl_nontrivial (count, entries))
     410                {
     411                  free (malloced);
     412                  return 1;
     413                }
     414            }
     415          free (malloced);
     416        }
     417  
     418  #   ifdef ACE_GETACL
     419        /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
     420           file systems (whereas the other ones are used in UFS file systems).  */
     421        {
     422          /* Initially, try to read the entries into a stack-allocated buffer.
     423             Use malloc if it does not fit.  */
     424          enum
     425            {
     426              alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
     427              alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
     428            };
     429          ace_t buf[alloc_init];
     430          size_t alloc = alloc_init;
     431          ace_t *entries = buf;
     432          ace_t *malloced = NULL;
     433          int count;
     434  
     435          for (;;)
     436            {
     437              count = acl (name, ACE_GETACL, alloc, entries);
     438              if (count < 0 && errno == ENOSPC)
     439                {
     440                  /* Increase the size of the buffer.  */
     441                  free (malloced);
     442                  if (alloc > alloc_max / 2)
     443                    {
     444                      errno = ENOMEM;
     445                      return -1;
     446                    }
     447                  alloc = 2 * alloc; /* <= alloc_max */
     448                  entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
     449                  if (entries == NULL)
     450                    {
     451                      errno = ENOMEM;
     452                      return -1;
     453                    }
     454                  continue;
     455                }
     456              break;
     457            }
     458          if (count < 0)
     459            {
     460              if (errno == ENOSYS || errno == EINVAL)
     461                ;
     462              else
     463                {
     464                  free (malloced);
     465                  return -1;
     466                }
     467            }
     468          else if (count == 0)
     469            ;
     470          else
     471            {
     472              /* In the old (original Solaris 10) convention:
     473                 If there are more than 3 entries, there cannot be only the
     474                 ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
     475                 In the newer Solaris 10 and Solaris 11 convention:
     476                 If there are more than 6 entries, there cannot be only the
     477                 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
     478                 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
     479                 NEW_ACE_ACCESS_DENIED_ACE_TYPE.  */
     480              if (count > 6)
     481                {
     482                  free (malloced);
     483                  return 1;
     484                }
     485  
     486              if (acl_ace_nontrivial (count, entries))
     487                {
     488                  free (malloced);
     489                  return 1;
     490                }
     491            }
     492          free (malloced);
     493        }
     494  #   endif
     495  
     496        return 0;
     497  #  endif
     498  
     499  # elif HAVE_GETACL /* HP-UX */
     500  
     501        {
     502          struct acl_entry entries[NACLENTRIES];
     503          int count;
     504  
     505          count = getacl (name, NACLENTRIES, entries);
     506  
     507          if (count < 0)
     508            {
     509              /* ENOSYS is seen on newer HP-UX versions.
     510                 EOPNOTSUPP is typically seen on NFS mounts.
     511                 ENOTSUP was seen on Quantum StorNext file systems (cvfs).  */
     512              if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
     513                ;
     514              else
     515                return -1;
     516            }
     517          else if (count == 0)
     518            return 0;
     519          else /* count > 0 */
     520            {
     521              if (count > NACLENTRIES)
     522                /* If NACLENTRIES cannot be trusted, use dynamic memory
     523                   allocation.  */
     524                abort ();
     525  
     526              /* If there are more than 3 entries, there cannot be only the
     527                 (uid,%), (%,gid), (%,%) entries.  */
     528              if (count > 3)
     529                return 1;
     530  
     531              {
     532                struct stat statbuf;
     533  
     534                if (stat (name, &statbuf) == -1 && errno != EOVERFLOW)
     535                  return -1;
     536  
     537                return acl_nontrivial (count, entries);
     538              }
     539            }
     540        }
     541  
     542  #  if HAVE_ACLV_H /* HP-UX >= 11.11 */
     543  
     544        {
     545          struct acl entries[NACLVENTRIES];
     546          int count;
     547  
     548          count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
     549  
     550          if (count < 0)
     551            {
     552              /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
     553                 EINVAL is seen on NFS in HP-UX 11.31.  */
     554              if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
     555                ;
     556              else
     557                return -1;
     558            }
     559          else if (count == 0)
     560            return 0;
     561          else /* count > 0 */
     562            {
     563              if (count > NACLVENTRIES)
     564                /* If NACLVENTRIES cannot be trusted, use dynamic memory
     565                   allocation.  */
     566                abort ();
     567  
     568              /* If there are more than 4 entries, there cannot be only the
     569                 four base ACL entries.  */
     570              if (count > 4)
     571                return 1;
     572  
     573              return aclv_nontrivial (count, entries);
     574            }
     575        }
     576  
     577  #  endif
     578  
     579  # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
     580  
     581        acl_type_t type;
     582        char aclbuf[1024];
     583        void *acl = aclbuf;
     584        size_t aclsize = sizeof (aclbuf);
     585        mode_t mode;
     586  
     587        for (;;)
     588          {
     589            /* The docs say that type being 0 is equivalent to ACL_ANY, but it
     590               is not true, in AIX 5.3.  */
     591            type.u64 = ACL_ANY;
     592            if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
     593              break;
     594            if (errno == ENOSYS)
     595              return 0;
     596            if (errno != ENOSPC)
     597              {
     598                if (acl != aclbuf)
     599                  free (acl);
     600                return -1;
     601              }
     602            aclsize = 2 * aclsize;
     603            if (acl != aclbuf)
     604              free (acl);
     605            acl = malloc (aclsize);
     606            if (acl == NULL)
     607              {
     608                errno = ENOMEM;
     609                return -1;
     610              }
     611          }
     612  
     613        if (type.u64 == ACL_AIXC)
     614          {
     615            int result = acl_nontrivial ((struct acl *) acl);
     616            if (acl != aclbuf)
     617              free (acl);
     618            return result;
     619          }
     620        else if (type.u64 == ACL_NFS4)
     621          {
     622            int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
     623            if (acl != aclbuf)
     624              free (acl);
     625            return result;
     626          }
     627        else
     628          {
     629            /* A newer type of ACL has been introduced in the system.
     630               We should better support it.  */
     631            if (acl != aclbuf)
     632              free (acl);
     633            errno = EINVAL;
     634            return -1;
     635          }
     636  
     637  # elif HAVE_STATACL /* older AIX */
     638  
     639        union { struct acl a; char room[4096]; } u;
     640  
     641        if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0)
     642          return -1;
     643  
     644        return acl_nontrivial (&u.a);
     645  
     646  # elif HAVE_ACLSORT /* NonStop Kernel */
     647  
     648        {
     649          struct acl entries[NACLENTRIES];
     650          int count;
     651  
     652          count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
     653  
     654          if (count < 0)
     655            {
     656              if (errno == ENOSYS || errno == ENOTSUP)
     657                ;
     658              else
     659                return -1;
     660            }
     661          else if (count == 0)
     662            return 0;
     663          else /* count > 0 */
     664            {
     665              if (count > NACLENTRIES)
     666                /* If NACLENTRIES cannot be trusted, use dynamic memory
     667                   allocation.  */
     668                abort ();
     669  
     670              /* If there are more than 4 entries, there cannot be only the
     671                 four base ACL entries.  */
     672              if (count > 4)
     673                return 1;
     674  
     675              return acl_nontrivial (count, entries);
     676            }
     677        }
     678  
     679  # endif
     680      }
     681  #endif
     682  
     683    return 0;
     684  }