svn commit: r191178 - head/lib/libarchive

Tim Kientzle kientzle at FreeBSD.org
Fri Apr 17 01:01:17 UTC 2009


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__) */


More information about the svn-src-head mailing list