summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/rpmfi.c74
-rw-r--r--lib/rpmfi_internal.h10
2 files changed, 74 insertions, 10 deletions
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
index 2bfedbfa2..ba88870e1 100644
--- a/lib/rpmfi.c
+++ b/lib/rpmfi.c
@@ -19,7 +19,50 @@
#include "debug.h"
+/*
+ * Simple and stupid user + groupname "cache."
+ * Store each unique user and group name string just once, retrieve
+ * by index value. As the number of unique names is typically very low,
+ * the dumb linear lookup appears to be fast enough and hash table seems
+ * like an overkill.
+ */
+struct ugcache_s {
+ char **uniq;
+ ugidx_t num;
+} ugcache = { NULL, 0 };
+
+static ugidx_t ugcachePut(const char *str)
+{
+ int found = 0;
+ ugidx_t ret;
+
+ for (ugidx_t i = 0; i < ugcache.num; i++) {
+ if (strcmp(str, ugcache.uniq[i]) == 0) {
+ ret = i;
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ /* blow up on index wraparound */
+ assert((ugidx_t)(ugcache.num + 1) > ugcache.num);
+ ugcache.uniq = xrealloc(ugcache.uniq,
+ sizeof(ugcache.uniq) * (ugcache.num+1));
+ ugcache.uniq[ugcache.num] = xstrdup(str);
+ ret = ugcache.num;
+ ugcache.num++;
+ }
+ return ret;
+}
+static const char *ugcacheGet(ugidx_t idx)
+{
+ const char *name = NULL;
+ if (idx >= 0 && idx < ugcache.num && ugcache.uniq != NULL)
+ name = ugcache.uniq[idx];
+ return name;
+}
+
int _rpmfi_debug = 0;
rpmfi rpmfiUnlink(rpmfi fi, const char * msg)
@@ -353,10 +396,9 @@ const char * rpmfiFUser(rpmfi fi)
{
const char * fuser = NULL;
- /* XXX add support for ancient RPMTAG_FILEUIDS? */
if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
if (fi->fuser != NULL)
- fuser = fi->fuser[fi->i];
+ fuser = ugcacheGet(fi->fuser[fi->i]);
}
return fuser;
}
@@ -365,10 +407,9 @@ const char * rpmfiFGroup(rpmfi fi)
{
const char * fgroup = NULL;
- /* XXX add support for ancient RPMTAG_FILEGIDS? */
if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
if (fi->fgroup != NULL)
- fgroup = fi->fgroup[fi->i];
+ fgroup = ugcacheGet(fi->fgroup[fi->i]);
}
return fgroup;
}
@@ -1192,6 +1233,23 @@ fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, fi->Type, fi->fc);
return NULL;
}
+/* Helper to convert user+group names into indexes to name cache */
+static ugidx_t *cacheNames(Header h, rpmTag tag)
+{
+ ugidx_t *idx = NULL;
+ struct rpmtd_s td;
+ if (headerGet(h, tag, &td, HEADERGET_MINMEM)) {
+ idx = xmalloc(sizeof(*idx) * rpmtdCount(&td));
+ int i = 0;
+ const char *str;
+ while ((str = rpmtdNextString(&td))) {
+ idx[i++] = ugcachePut(str);
+ }
+ rpmtdFreeData(&td);
+ }
+ return idx;
+}
+
#define _hgfi(_h, _tag, _td, _flags, _data) \
if (headerGet((_h), (_tag), (_td), (_flags))) \
_data = (td.data)
@@ -1353,10 +1411,10 @@ rpmfi rpmfiNew(const rpmts ts, Header h, rpmTag tagN, rpmfiFlags flags)
if (!(flags & RPMFI_NOFILEINODES))
_hgfi(h, RPMTAG_FILEINODES, &td, scareFlags, fi->finodes);
- if (!(flags & RPMFI_NOFILEUSER))
- _hgfi(h, RPMTAG_FILEUSERNAME, &td, defFlags, fi->fuser);
- if (!(flags & RPMFI_NOFILEGROUP))
- _hgfi(h, RPMTAG_FILEGROUPNAME, &td, defFlags, fi->fgroup);
+ if (!(flags & RPMFI_NOFILEUSER))
+ fi->fuser = cacheNames(h, RPMTAG_FILEUSERNAME);
+ if (!(flags & RPMFI_NOFILEGROUP))
+ fi->fgroup = cacheNames(h, RPMTAG_FILEGROUPNAME);
if (ts != NULL)
if (fi != NULL)
diff --git a/lib/rpmfi_internal.h b/lib/rpmfi_internal.h
index 60d3458e1..291f78454 100644
--- a/lib/rpmfi_internal.h
+++ b/lib/rpmfi_internal.h
@@ -18,6 +18,12 @@ struct sharedFileInfo_s {
int isRemoved;
};
+/*
+ * This limits maximum unique user + group names from packages to 65535,
+ * should be plenty but easy to bump if ever needed.
+ */
+typedef uint16_t ugidx_t;
+
/**
* A package filename set.
*/
@@ -52,8 +58,8 @@ struct rpmfi_s {
/*?null?*/
const rpm_ino_t * finodes; /*!< File inodes(s) (from header) */
- const char ** fuser; /*!< File owner(s) (from header) */
- const char ** fgroup; /*!< File group(s) (from header) */
+ ugidx_t *fuser; /*!< Index to file owner(s) cache */
+ ugidx_t *fgroup; /*!< Index to file group(s) cache */
char * fstates; /*!< File state(s) (from header) */