Author: kientzle
Date: Fri Apr 17 01:01:15 2009
New Revision: 191178
URL: http://svn.freebsd.org/changeset/base/191178

Log:
  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.

Modified:
  head/lib/libarchive/archive_read_disk_set_standard_lookup.c

Modified: head/lib/libarchive/archive_read_disk_set_standard_lookup.c
==============================================================================
--- head/lib/libarchive/archive_read_disk_set_standard_lookup.c Fri Apr 17 
01:00:11 2009        (r191177)
+++ head/lib/libarchive/archive_read_disk_set_standard_lookup.c Fri Apr 17 
01:01:15 2009        (r191178)
@@ -61,6 +61,8 @@ static const char * const NO_NAME = "(no
 
 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__) */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to