root/maint/gnulib/lib/get-permissions.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_permissions

   1 /* Get permissions of a file.  -*- coding: utf-8 -*-
   2 
   3    Copyright (C) 2002-2003, 2005-2021 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 #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 
  32 int
  33 get_permissions (const char *name, int desc, mode_t mode,
     /* [previous][next][first][last][top][bottom][index][help] */
  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, Cygwin >= 2.5 */
  42 # if !HAVE_ACL_TYPE_EXTENDED
  43   /* Linux, FreeBSD, IRIX, Tru64, Cygwin >= 2.5 */
  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 #  if HAVE_ACL_TYPE_NFS4  /* FreeBSD */
  64 
  65   /* TODO (see set_permissions). */
  66 
  67 #  endif
  68 
  69 # else /* HAVE_ACL_TYPE_EXTENDED */
  70   /* Mac OS X */
  71 
  72   /* On Mac OS X,  acl_get_file (name, ACL_TYPE_ACCESS)
  73      and           acl_get_file (name, ACL_TYPE_DEFAULT)
  74      always return NULL / EINVAL.  You have to use
  75                    acl_get_file (name, ACL_TYPE_EXTENDED)
  76      or            acl_get_fd (open (name, ...))
  77      to retrieve an ACL.
  78      On the other hand,
  79                    acl_set_file (name, ACL_TYPE_ACCESS, acl)
  80      and           acl_set_file (name, ACL_TYPE_DEFAULT, acl)
  81      have the same effect as
  82                    acl_set_file (name, ACL_TYPE_EXTENDED, acl):
  83      Each of these calls sets the file's ACL.  */
  84 
  85   if (HAVE_ACL_GET_FD && desc != -1)
  86     ctx->acl = acl_get_fd (desc);
  87   else
  88     ctx->acl = acl_get_file (name, ACL_TYPE_EXTENDED);
  89   if (ctx->acl == NULL)
  90     return acl_errno_valid (errno) ? -1 : 0;
  91 
  92 # endif
  93 
  94 #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
  95 
  96   /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
  97      of Unixware.  The acl() call returns the access and default ACL both
  98      at once.  */
  99 # ifdef ACE_GETACL
 100   /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
 101      file systems (whereas the other ones are used in UFS file systems).
 102      There is an API
 103        pathconf (name, _PC_ACL_ENABLED)
 104        fpathconf (desc, _PC_ACL_ENABLED)
 105      that allows us to determine which of the two kinds of ACLs is supported
 106      for the given file.  But some file systems may implement this call
 107      incorrectly, so better not use it.
 108      When fetching the source ACL, we simply fetch both ACL types.
 109      When setting the destination ACL, we try either ACL types, assuming
 110      that the kernel will translate the ACL from one form to the other.
 111      (See in <https://docs.oracle.com/cd/E86824_01/html/E54765/acl-2.html>
 112      the description of ENOTSUP.)  */
 113   for (;;)
 114     {
 115       int ret;
 116 
 117       if (desc != -1)
 118         ret = facl (desc, ACE_GETACLCNT, 0, NULL);
 119       else
 120         ret = acl (name, ACE_GETACLCNT, 0, NULL);
 121       if (ret < 0)
 122         {
 123           if (errno == ENOSYS || errno == EINVAL)
 124             ret = 0;
 125           else
 126             return -1;
 127         }
 128       ctx->ace_count = ret;
 129 
 130       if (ctx->ace_count == 0)
 131         break;
 132 
 133       ctx->ace_entries = (ace_t *) malloc (ctx->ace_count * sizeof (ace_t));
 134       if (ctx->ace_entries == NULL)
 135         {
 136           errno = ENOMEM;
 137           return -1;
 138         }
 139 
 140       if (desc != -1)
 141         ret = facl (desc, ACE_GETACL, ctx->ace_count, ctx->ace_entries);
 142       else
 143         ret = acl (name, ACE_GETACL, ctx->ace_count, ctx->ace_entries);
 144       if (ret < 0)
 145         {
 146           if (errno == ENOSYS || errno == EINVAL)
 147             {
 148               free (ctx->ace_entries);
 149               ctx->ace_entries = NULL;
 150               ctx->ace_count = 0;
 151               break;
 152             }
 153           else
 154             return -1;
 155         }
 156       if (ret <= ctx->ace_count)
 157         {
 158           ctx->ace_count = ret;
 159           break;
 160         }
 161       /* Huh? The number of ACL entries has increased since the last call.
 162          Repeat.  */
 163       free (ctx->ace_entries);
 164       ctx->ace_entries = NULL;
 165     }
 166 # endif
 167 
 168   for (;;)
 169     {
 170       int ret;
 171 
 172       if (desc != -1)
 173         ret = facl (desc, GETACLCNT, 0, NULL);
 174       else
 175         ret = acl (name, GETACLCNT, 0, NULL);
 176       if (ret < 0)
 177         {
 178           if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
 179             ret = 0;
 180           else
 181             return -1;
 182         }
 183       ctx->count = ret;
 184 
 185       if (ctx->count == 0)
 186         break;
 187 
 188       ctx->entries = (aclent_t *) malloc (ctx->count * sizeof (aclent_t));
 189       if (ctx->entries == NULL)
 190         {
 191           errno = ENOMEM;
 192           return -1;
 193         }
 194 
 195       if (desc != -1)
 196         ret = facl (desc, GETACL, ctx->count, ctx->entries);
 197       else
 198         ret = acl (name, GETACL, ctx->count, ctx->entries);
 199       if (ret < 0)
 200         {
 201           if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
 202             {
 203               free (ctx->entries);
 204               ctx->entries = NULL;
 205               ctx->count = 0;
 206               break;
 207             }
 208           else
 209             return -1;
 210         }
 211       if (ret <= ctx->count)
 212         {
 213           ctx->count = ret;
 214           break;
 215         }
 216       /* Huh? The number of ACL entries has increased since the last call.
 217          Repeat.  */
 218       free (ctx->entries);
 219       ctx->entries = NULL;
 220     }
 221 
 222 #elif USE_ACL && HAVE_GETACL /* HP-UX */
 223 
 224   {
 225     int ret;
 226 
 227     if (desc != -1)
 228       ret = fgetacl (desc, NACLENTRIES, ctx->entries);
 229     else
 230       ret = getacl (name, NACLENTRIES, ctx->entries);
 231     if (ret < 0)
 232       {
 233         if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
 234           ret = 0;
 235         else
 236           return -1;
 237       }
 238     else if (ret > NACLENTRIES)
 239       /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
 240       abort ();
 241     ctx->count = ret;
 242 
 243 # if HAVE_ACLV_H
 244     ret = acl ((char *) name, ACL_GET, NACLVENTRIES, ctx->aclv_entries);
 245     if (ret < 0)
 246       {
 247         if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
 248           ret = 0;
 249         else
 250           return -2;
 251       }
 252     else if (ret > NACLVENTRIES)
 253       /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation.  */
 254       abort ();
 255     ctx->aclv_count = ret;
 256 # endif
 257   }
 258 
 259 #elif USE_ACL && HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
 260 
 261   /* TODO (see set_permissions). */
 262 
 263 #elif USE_ACL && HAVE_STATACL /* older AIX */
 264 
 265   {
 266     int ret;
 267     if (desc != -1)
 268       ret = fstatacl (desc, STX_NORMAL, &ctx->u.a, sizeof ctx->u);
 269     else
 270       ret = statacl ((char *) name, STX_NORMAL, &ctx->u.a, sizeof ctx->u);
 271     if (ret == 0)
 272       ctx->have_u = true;
 273   }
 274 
 275 #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
 276 
 277   {
 278     int ret = acl ((char *) name, ACL_GET, NACLENTRIES, ctx->entries);
 279     if (ret < 0)
 280       return -1;
 281     else if (ret > NACLENTRIES)
 282       /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
 283       abort ();
 284     ctx->count = ret;
 285   }
 286 
 287 #endif
 288 
 289   return 0;
 290 
 291 }

/* [previous][next][first][last][top][bottom][index][help] */