Dynamically size the buffer we pass to getgrgid_r() and getpwuid_r().

Keep the buffer in the cache object so we don't have to keep doing this.
This commit is contained in:
Tim Kientzle 2009-04-17 01:01:15 +00:00
parent 82ea3751d6
commit a5e75fbb6c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=191178

View file

@ -61,6 +61,8 @@ static const char * const NO_NAME = "(noname)";
struct name_cache {
struct archive *archive;
char *buff;
size_t buff_size;
int probes;
int hits;
size_t size;
@ -73,8 +75,8 @@ struct name_cache {
static const char * lookup_gname(void *, gid_t);
static const char * lookup_uname(void *, uid_t);
static void cleanup(void *);
static const char * lookup_gname_helper(struct archive *, id_t gid);
static const char * lookup_uname_helper(struct archive *, id_t uid);
static const char * lookup_gname_helper(struct name_cache *, id_t gid);
static const char * lookup_uname_helper(struct name_cache *, id_t uid);
/*
* Installs functions that use getpwuid()/getgrgid()---along with
@ -128,6 +130,7 @@ cleanup(void *data)
cache->cache[i].name != NO_NAME)
free((void *)(uintptr_t)cache->cache[i].name);
}
free(cache->buff);
free(cache);
}
}
@ -137,7 +140,7 @@ cleanup(void *data)
*/
static const char *
lookup_name(struct name_cache *cache,
const char * (*lookup_fn)(struct archive *, id_t), id_t id)
const char * (*lookup_fn)(struct name_cache *, id_t), id_t id)
{
const char *name;
int slot;
@ -158,7 +161,7 @@ lookup_name(struct name_cache *cache,
cache->cache[slot].name = NULL;
}
name = (lookup_fn)(cache->archive, id);
name = (lookup_fn)(cache, id);
if (name == NULL) {
/* Cache and return the negative response. */
cache->cache[slot].name = NO_NAME;
@ -180,23 +183,43 @@ lookup_uname(void *data, uid_t uid)
}
static const char *
lookup_uname_helper(struct archive *a, id_t id)
lookup_uname_helper(struct name_cache *cache, id_t id)
{
char buffer[512];
struct passwd pwent, *result;
int r;
errno = 0;
r = getpwuid_r((uid_t)id, &pwent, buffer, sizeof(buffer), &result);
if (cache->buff_size == 0) {
cache->buff_size = 256;
cache->buff = malloc(cache->buff_size);
}
if (cache->buff == NULL)
return (NULL);
for (;;) {
r = getpwuid_r((uid_t)id, &pwent,
cache->buff, cache->buff_size, &result);
if (r == 0)
break;
if (r != ERANGE)
break;
/* ERANGE means our buffer was too small, but POSIX
* doesn't tell us how big the buffer should be, so
* we just double it and try again. Because the buffer
* is kept around in the cache object, we shouldn't
* have to do this very often. */
cache->buff_size *= 2;
cache->buff = realloc(cache->buff, cache->buff_size);
if (cache->buff == NULL)
break;
}
if (r != 0) {
archive_set_error(a, errno,
archive_set_error(cache->archive, errno,
"Can't lookup user for id %d", (int)id);
return (NULL);
}
if (result == NULL)
return (NULL);
return strdup(pwent.pw_name);
return strdup(result->pw_name);
}
static const char *
@ -208,22 +231,40 @@ lookup_gname(void *data, gid_t gid)
}
static const char *
lookup_gname_helper(struct archive *a, id_t id)
lookup_gname_helper(struct name_cache *cache, id_t id)
{
char buffer[512];
struct group grent, *result;
int r;
errno = 0;
r = getgrgid_r((gid_t)id, &grent, buffer, sizeof(buffer), &result);
if (cache->buff_size == 0) {
cache->buff_size = 256;
cache->buff = malloc(cache->buff_size);
}
if (cache->buff == NULL)
return (NULL);
for (;;) {
r = getgrgid_r((gid_t)id, &grent,
cache->buff, cache->buff_size, &result);
if (r == 0)
break;
if (r != ERANGE)
break;
/* ERANGE means our buffer was too small, but POSIX
* doesn't tell us how big the buffer should be, so
* we just double it and try again. */
cache->buff_size *= 2;
cache->buff = realloc(cache->buff, cache->buff_size);
if (cache->buff == NULL)
break;
}
if (r != 0) {
archive_set_error(a, errno,
archive_set_error(cache->archive, errno,
"Can't lookup group for id %d", (int)id);
return (NULL);
}
if (result == NULL)
return (NULL);
return strdup(grent.gr_name);
return strdup(result->gr_name);
}
#endif /* ! (_WIN32 && !__CYGWIN__) */