summaryrefslogtreecommitdiff
path: root/gl/lib/mgetgroups.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/lib/mgetgroups.c')
-rw-r--r--gl/lib/mgetgroups.c46
1 files changed, 17 insertions, 29 deletions
diff --git a/gl/lib/mgetgroups.c b/gl/lib/mgetgroups.c
index ad1fd4f3b..e697013ef 100644
--- a/gl/lib/mgetgroups.c
+++ b/gl/lib/mgetgroups.c
@@ -1,6 +1,6 @@
/* mgetgroups.c -- return a list of the groups a user is in
- Copyright (C) 2007-2008 Free Software Foundation, Inc.
+ Copyright (C) 2007-2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,16 +33,16 @@
#include "xalloc.h"
-static void *
-allocate_groupbuf (int size)
+static GETGROUPS_T *
+realloc_groupbuf (GETGROUPS_T *g, size_t num)
{
- if (xalloc_oversized (size, sizeof (GETGROUPS_T)))
+ if (xalloc_oversized (num, sizeof (*g)))
{
errno = ENOMEM;
return NULL;
}
- return malloc (size * sizeof (GETGROUPS_T));
+ return realloc (g, num * sizeof (*g));
}
/* Like getugroups, but store the result in malloc'd storage.
@@ -65,45 +65,27 @@ mgetgroups (char const *username, gid_t gid, GETGROUPS_T **groups)
performance characteristics.
In glibc 2.3.2, getgrouplist is buggy. If you pass a zero as the
- size of the output buffer, getgrouplist will still write to the
+ length of the output buffer, getgrouplist will still write to the
buffer. Contrary to what some versions of the getgrouplist
manpage say, this doesn't happen with nonzero buffer sizes.
Therefore our usage here just avoids a zero sized buffer. */
if (username)
{
enum { N_GROUPS_INIT = 10 };
- GETGROUPS_T smallbuf[N_GROUPS_INIT];
-
max_n_groups = N_GROUPS_INIT;
- ng = getgrouplist (username, gid, smallbuf, &max_n_groups);
- g = allocate_groupbuf (max_n_groups);
+ g = realloc_groupbuf (NULL, max_n_groups);
if (g == NULL)
return -1;
- if (max_n_groups <= N_GROUPS_INIT)
- {
- /* smallbuf was big enough, so we already have our data */
- memcpy (g, smallbuf, max_n_groups * sizeof *g);
- *groups = g;
- return max_n_groups;
- }
-
while (1)
{
GETGROUPS_T *h;
- ng = getgrouplist (username, gid, g, &max_n_groups);
- if (0 <= ng)
- {
- *groups = g;
- return ng;
- }
- /* When getgrouplist fails, it guarantees that
- max_n_groups reflects the new number of groups. */
+ /* getgrouplist updates max_n_groups to num required. */
+ ng = getgrouplist (username, gid, g, &max_n_groups);
- if (xalloc_oversized (max_n_groups, sizeof *h)
- || (h = realloc (g, max_n_groups * sizeof *h)) == NULL)
+ if ((h = realloc_groupbuf (g, max_n_groups)) == NULL)
{
int saved_errno = errno;
free (g);
@@ -111,6 +93,12 @@ mgetgroups (char const *username, gid_t gid, GETGROUPS_T **groups)
return -1;
}
g = h;
+
+ if (0 <= ng)
+ {
+ *groups = g;
+ return ng;
+ }
}
}
/* else no username, so fall through and use getgroups. */
@@ -125,7 +113,7 @@ mgetgroups (char const *username, gid_t gid, GETGROUPS_T **groups)
if (max_n_groups < 0)
max_n_groups = 5;
- g = allocate_groupbuf (max_n_groups);
+ g = realloc_groupbuf (NULL, max_n_groups);
if (g == NULL)
return -1;