(root)/
tar-1.35/
gnu/
getgroups.c
       1  /* provide consistent interface to getgroups for systems that don't allow N==0
       2  
       3     Copyright (C) 1996, 1999, 2003, 2006-2023 Free Software Foundation, Inc.
       4  
       5     This file is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU Lesser General Public License as
       7     published by the Free Software Foundation; either version 2.1 of the
       8     License, or (at your option) any later version.
       9  
      10     This file 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 Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  /* written by Jim Meyering */
      19  
      20  #include <config.h>
      21  
      22  #include <unistd.h>
      23  
      24  #include <errno.h>
      25  #include <stdlib.h>
      26  #include <stdint.h>
      27  
      28  #if !HAVE_GETGROUPS
      29  
      30  /* Provide a stub that fails with ENOSYS, since there is no group
      31     information available on mingw.  */
      32  int
      33  getgroups (_GL_UNUSED int n, _GL_UNUSED GETGROUPS_T *groups)
      34  {
      35    errno = ENOSYS;
      36    return -1;
      37  }
      38  
      39  #else /* HAVE_GETGROUPS */
      40  
      41  # undef getgroups
      42  # ifndef GETGROUPS_ZERO_BUG
      43  #  define GETGROUPS_ZERO_BUG 0
      44  # endif
      45  
      46  /* On OS X 10.6 and later, use the usual getgroups, not the one
      47     supplied when _DARWIN_C_SOURCE is defined.  _DARWIN_C_SOURCE is
      48     normally defined, since it means "conform to POSIX, but add
      49     non-POSIX extensions even if that violates the POSIX namespace
      50     rules", which is what we normally want.  But with getgroups there
      51     is an inconsistency, and _DARWIN_C_SOURCE means "change getgroups()
      52     so that it no longer works right".  The BUGS section of compat(5)
      53     says that the behavior is dubious if you compile different sections
      54     of a program with different _DARWIN_C_SOURCE settings, so fix only
      55     the offending symbol.  */
      56  # ifdef __APPLE__
      57  int posix_getgroups (int, gid_t []) __asm ("_getgroups");
      58  #  define getgroups posix_getgroups
      59  # endif
      60  
      61  /* On at least NeXTstep 3.2, getgroups (0, NULL) always fails.
      62     On other systems, it returns the number of supplemental
      63     groups for the process.  This function handles that special case
      64     and lets the system-provided function handle all others.  However,
      65     it can fail with ENOMEM if memory is tight.  It is unspecified
      66     whether the effective group id is included in the list.  */
      67  
      68  int
      69  rpl_getgroups (int n, gid_t *group)
      70  {
      71    int n_groups;
      72    GETGROUPS_T *gbuf;
      73  
      74    if (n < 0)
      75      {
      76        errno = EINVAL;
      77        return -1;
      78      }
      79  
      80    if (n != 0 || !GETGROUPS_ZERO_BUG)
      81      {
      82        int result;
      83        if (sizeof *group == sizeof *gbuf)
      84          return getgroups (n, (GETGROUPS_T *) group);
      85  
      86        if (SIZE_MAX / sizeof *gbuf <= n)
      87          {
      88            errno = ENOMEM;
      89            return -1;
      90          }
      91        gbuf = malloc (n * sizeof *gbuf);
      92        if (!gbuf)
      93          return -1;
      94        result = getgroups (n, gbuf);
      95        if (0 <= result)
      96          {
      97            n = result;
      98            while (n--)
      99              group[n] = gbuf[n];
     100          }
     101        free (gbuf);
     102        return result;
     103      }
     104  
     105    n = 20;
     106    while (1)
     107      {
     108        /* No need to worry about address arithmetic overflow here,
     109           since the ancient systems that we're running on have low
     110           limits on the number of secondary groups.  */
     111        gbuf = malloc (n * sizeof *gbuf);
     112        if (!gbuf)
     113          return -1;
     114        n_groups = getgroups (n, gbuf);
     115        if (n_groups == -1 ? errno != EINVAL : n_groups < n)
     116          break;
     117        free (gbuf);
     118        n *= 2;
     119      }
     120  
     121    free (gbuf);
     122    return n_groups;
     123  }
     124  
     125  #endif /* HAVE_GETGROUPS */