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:
parent
82ea3751d6
commit
a5e75fbb6c
@ -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__) */
|
||||
|
Loading…
Reference in New Issue
Block a user