return r;
}
+static inline Hashval
+strhash_cont(const char *str, Hashval r)
+{
+ unsigned int c;
+ while ((c = *(const unsigned char *)str++) != 0)
+ r += (r << 3) + c;
+ return r;
+}
+
+
/* hash for rel
* rel -> hash
*/
ADD_EXECUTABLE( mergesolv mergesolv.c )
TARGET_LINK_LIBRARIES( mergesolv satsolver toolstuff)
+SET(findfileconflicts_SOURCES findfileconflicts.c pool_fileconflicts.c repo_rpmdb.c )
+ADD_EXECUTABLE( findfileconflicts ${findfileconflicts_SOURCES} )
+TARGET_LINK_LIBRARIES( findfileconflicts satsolver ${RPMDB_LIBRARY} ${EXPAT_LIBRARY} )
+
install(TARGETS
mergesolv
dumpsolv
--- /dev/null
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "hash.h"
+#include "repo_rpmdb.h"
+
+struct cbdata {
+ Pool *pool;
+ Queue lookat;
+ Queue lookat_dir;
+
+ Hashval *cflmap;
+ Hashmask cflmapn;
+ unsigned int cflmapused;
+
+ Hashval *dirmap;
+ Hashmask dirmapn;
+ unsigned int dirmapused;
+
+ Hashval idx;
+ unsigned int hx;
+
+ Queue files;
+ unsigned char *filesspace;
+ unsigned int filesspacen;
+};
+
+#define FILESSPACE_BLOCK 255
+
+static Hashval *
+doublehash(Hashval *map, Hashmask *mapnp)
+{
+ Hashmask mapn = *mapnp;
+ Hashmask i, hx, qx, h, hh;
+ Hashmask nn = (mapn + 1) * 2 - 1;
+ Hashmask *m;
+
+ m = sat_calloc(nn + 1, 2 * sizeof(Id));
+ for (i = 0; i <= mapn; i++)
+ {
+ hx = map[2 * i];
+ if (!hx)
+ continue;
+ h = hx & nn;
+ hh = HASHCHAIN_START;
+ for (;;)
+ {
+ qx = m[2 * h];
+ if (!qx)
+ break;
+ h = HASHCHAIN_NEXT(h, hh, nn);
+ }
+ m[2 * h] = hx;
+ m[2 * h + 1] = map[2 * i + 1];
+ }
+ sat_free(map);
+ *mapnp = nn;
+ return m;
+}
+
+static void
+finddirs_cb(void *cbdatav, char *fn, int fmode, char *md5)
+{
+ struct cbdata *cbdata = cbdatav;
+ Hashmask h, hh, hx, qx;
+ Hashval idx = cbdata->idx;
+
+ hx = strhash(fn);
+ if (!hx)
+ hx = strlen(fn) + 1;
+ h = hx & cbdata->dirmapn;
+ hh = HASHCHAIN_START;
+ for (;;)
+ {
+ qx = cbdata->dirmap[2 * h];
+ if (!qx)
+ break;
+ if (qx == hx)
+ break;
+ h = HASHCHAIN_NEXT(h, hh, cbdata->dirmapn);
+ }
+ if (!qx)
+ {
+ /* a miss */
+ cbdata->dirmap[2 * h] = hx;
+ cbdata->dirmap[2 * h + 1] = idx;
+ cbdata->dirmapused++;
+ if (cbdata->dirmapused * 2 > cbdata->dirmapn)
+ cbdata->dirmap = doublehash(cbdata->dirmap, &cbdata->dirmapn);
+ return;
+ }
+ if (cbdata->dirmap[2 * h + 1] == idx)
+ return;
+ /* found a conflict, this dir is used in multiple packages */
+ cbdata->dirmap[2 * h + 1] = -1;
+}
+
+static inline int
+isindirmap(struct cbdata *cbdata, Hashmask hx)
+{
+ Hashmask h, hh, qx;
+
+ h = hx & cbdata->dirmapn;
+ hh = HASHCHAIN_START;
+ for (;;)
+ {
+ qx = cbdata->dirmap[2 * h];
+ if (!qx)
+ return 0;
+ if (qx == hx)
+ return cbdata->dirmap[2 * h + 1] == -1 ? 1 : 0;
+ h = HASHCHAIN_NEXT(h, hh, cbdata->dirmapn);
+ }
+}
+
+static void
+findfileconflicts_cb(void *cbdatav, char *fn, int fmode, char *md5)
+{
+ struct cbdata *cbdata = cbdatav;
+ int isdir = S_ISDIR(fmode);
+ char *dp;
+ Hashval idx, qidx;
+ Hashmask qx, h, hx, hh, dhx;
+
+ idx = cbdata->idx;
+
+ dp = strrchr(fn, '/');
+ if (!dp)
+ return;
+ dhx = strnhash(fn, dp + 1 - fn);
+ if (!dhx)
+ dhx = 1 + dp + 1 - fn;
+#if 1
+ if (!isindirmap(cbdata, dhx))
+ return;
+#endif
+
+ hx = strhash_cont(dp + 1, dhx);
+ if (!hx)
+ hx = strlen(fn) + 1;
+
+ h = hx & cbdata->cflmapn;
+ hh = HASHCHAIN_START;
+ for (;;)
+ {
+ qx = cbdata->cflmap[2 * h];
+ if (!qx)
+ break;
+ if (qx == hx)
+ break;
+ h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn);
+ }
+ if (!qx)
+ {
+ cbdata->cflmap[2 * h] = hx;
+ cbdata->cflmap[2 * h + 1] = (isdir ? ~idx : idx);
+ cbdata->cflmapused++;
+ if (cbdata->cflmapused * 2 > cbdata->cflmapn)
+ cbdata->cflmap = doublehash(cbdata->cflmap, &cbdata->cflmapn);
+ return;
+ }
+ qidx = cbdata->cflmap[2 * h + 1];
+ if ((int)qidx < 0)
+ {
+ int i;
+ qidx = ~qidx;
+ if (isdir)
+ {
+ /* delay the conflict */
+ queue_push2(&cbdata->lookat_dir, hx, qidx);
+ queue_push2(&cbdata->lookat_dir, hx, idx);
+ return;
+ }
+ cbdata->cflmap[2 * h + 1] = qidx;
+ for (i = 0; i < cbdata->lookat_dir.count; i += 2)
+ if (cbdata->lookat_dir.elements[i] == hx)
+ queue_push2(&cbdata->lookat, hx, cbdata->lookat_dir.elements[i + 1]);
+ }
+ if (qidx == idx)
+ return; /* no conflicts with ourself, please */
+ queue_push2(&cbdata->lookat, hx, qidx);
+ queue_push2(&cbdata->lookat, hx, idx);
+}
+
+static inline void
+addfilesspace(struct cbdata *cbdata, unsigned char *data, int len)
+{
+ cbdata->filesspace = sat_extend(cbdata->filesspace, cbdata->filesspacen, len, 1, FILESSPACE_BLOCK);
+ memcpy(cbdata->filesspace + cbdata->filesspacen, data, len);
+ cbdata->filesspacen += len;
+}
+
+static void
+findfileconflicts2_cb(void *cbdatav, char *fn, int fmode, char *md5)
+{
+ struct cbdata *cbdata = cbdatav;
+ unsigned int hx = strhash(fn);
+ char md5padded[33];
+
+ if (!hx)
+ hx = strlen(fn) + 1;
+ if (hx != cbdata->hx)
+ return;
+ strncpy(md5padded, md5, 32);
+ md5padded[32] = 0;
+ // printf("%d, hx %x -> %s %d %s\n", cbdata->idx, hx, fn, fmode, md5);
+ queue_push(&cbdata->files, cbdata->filesspacen);
+ addfilesspace(cbdata, (unsigned char *)md5padded, 33);
+ addfilesspace(cbdata, (unsigned char *)fn, strlen(fn) + 1);
+}
+
+static int cand_sort(const void *ap, const void *bp, void *dp)
+{
+ const Id *a = ap;
+ const Id *b = bp;
+
+ unsigned int ax = (unsigned int)a[0];
+ unsigned int bx = (unsigned int)b[0];
+ if (ax < bx)
+ return -1;
+ if (ax > bx)
+ return 1;
+ return (a[1] < 0 ? -a[1] : a[1]) - (b[1] < 0 ? -b[1] : b[1]);
+}
+
+static int conflicts_cmp(const void *ap, const void *bp, void *dp)
+{
+ Pool *pool = dp;
+ const Id *a = ap;
+ const Id *b = bp;
+ if (a[0] != b[0])
+ return strcmp(id2str(pool, a[0]), id2str(pool, b[0]));
+ if (a[1] != b[1])
+ return a[1] - b[1];
+ if (a[3] != b[3])
+ return a[3] - b[3];
+ return 0;
+}
+
+int
+pool_findfileconflicts(Pool *pool, Queue *pkgs, Queue *conflicts, void *(*handle_cb)(Pool *, Id, void *) , void *handle_cbdata)
+{
+ int i, j, cflmapn;
+ unsigned int hx;
+ struct cbdata cbdata;
+ unsigned int now, start;
+ void *handle;
+
+ queue_empty(conflicts);
+ if (!pkgs->count)
+ return 0;
+
+ now = start = sat_timems(0);
+ printf("packages: %d\n", pkgs->count);
+
+ memset(&cbdata, 0, sizeof(cbdata));
+ cbdata.pool = pool;
+ queue_init(&cbdata.lookat);
+ queue_init(&cbdata.lookat_dir);
+ queue_init(&cbdata.files);
+
+ /* avarage file list size: 200 files per package */
+ /* avarage dir count: 20 dirs per package */
+
+ /* first pass: scan dirs */
+ cflmapn = pkgs->count * 64;
+ while ((cflmapn & (cflmapn - 1)) != 0)
+ cflmapn = cflmapn & (cflmapn - 1);
+ cbdata.dirmap = sat_calloc(cflmapn, 2 * sizeof(Id));
+ cbdata.dirmapn = cflmapn - 1; /* make it a mask */
+ for (i = 0; i < pkgs->count; i++)
+ {
+ Id p = pkgs->elements[i];
+ cbdata.idx = p;
+ handle = (*handle_cb)(pool, p, handle_cbdata);
+ if (handle)
+ rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_ONLYDIRS, finddirs_cb, &cbdata);
+ }
+
+ printf("dirmap size: %d used %d\n", cbdata.dirmapn + 1, cbdata.dirmapused);
+ printf("dirmap memory usage: %d K\n", (cbdata.dirmapn + 1) * 2 * (int)sizeof(Id) / 1024);
+ printf("dirmap creation took %d ms\n", sat_timems(now));
+
+ /* second pass: scan files */
+ now = sat_timems(0);
+ cflmapn = pkgs->count * 128;
+ while ((cflmapn & (cflmapn - 1)) != 0)
+ cflmapn = cflmapn & (cflmapn - 1);
+ cbdata.cflmap = sat_calloc(cflmapn, 2 * sizeof(Id));
+ cbdata.cflmapn = cflmapn - 1; /* make it a mask */
+ for (i = 0; i < pkgs->count; i++)
+ {
+ Id p = pkgs->elements[i];
+ cbdata.idx = p;
+ handle = (*handle_cb)(pool, p, handle_cbdata);
+ if (handle)
+ rpm_iterate_filelist(handle, 0, findfileconflicts_cb, &cbdata);
+ }
+
+ printf("filemap size: %d used %d\n", cbdata.cflmapn + 1, cbdata.cflmapused);
+ printf("filemap memory usage: %d K\n", (cbdata.cflmapn + 1) * 2 * (int)sizeof(Id) / 1024);
+ printf("filemap creation took %d ms\n", sat_timems(now));
+
+ cbdata.dirmap = sat_free(cbdata.dirmap);
+ cbdata.dirmapn = 0;
+ cbdata.dirmapused = 0;
+ cbdata.cflmap = sat_free(cbdata.cflmap);
+ cbdata.cflmapn = 0;
+ cbdata.cflmapused = 0;
+
+ now = sat_timems(0);
+ printf("lookat_dir size: %d\n", cbdata.lookat_dir.count);
+ queue_free(&cbdata.lookat_dir);
+ sat_sort(cbdata.lookat.elements, cbdata.lookat.count / 2, sizeof(Id) * 2, &cand_sort, pool);
+ /* unify */
+ for (i = j = 0; i < cbdata.lookat.count; i += 2)
+ {
+ hx = cbdata.lookat.elements[i];
+ Id p = cbdata.lookat.elements[i + 1];
+ if (j && hx == cbdata.lookat.elements[j - 2] && p == cbdata.lookat.elements[j - 1])
+ continue;
+ cbdata.lookat.elements[j++] = hx;
+ cbdata.lookat.elements[j++] = p;
+ }
+ printf("candidates: %d\n", cbdata.lookat.count / 2);
+
+ /* third pass: scan candidates */
+ for (i = 0; i < cbdata.lookat.count - 2; i += 2)
+ {
+ int pend, ii, jj;
+ Id p = cbdata.lookat.elements[i + 1];
+
+ hx = cbdata.lookat.elements[i];
+ if (cbdata.lookat.elements[i + 2] != hx)
+ continue; /* no package left */
+ queue_empty(&cbdata.files);
+ cbdata.filesspace = sat_free(cbdata.filesspace);
+ cbdata.filesspacen = 0;
+
+ cbdata.idx = p;
+ cbdata.hx = cbdata.lookat.elements[i];
+ handle = (*handle_cb)(pool, p, handle_cbdata);
+ if (!handle)
+ continue;
+ rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_WITHMD5, findfileconflicts2_cb, &cbdata);
+
+ pend = cbdata.files.count;
+ for (j = i + 2; j < cbdata.lookat.count && cbdata.lookat.elements[j] == hx; j++)
+ {
+ Id q = cbdata.lookat.elements[j + 1];
+ cbdata.idx = q;
+ handle = (*handle_cb)(pool, q, handle_cbdata);
+ if (!handle)
+ continue;
+ rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_WITHMD5, findfileconflicts2_cb, &cbdata);
+ for (ii = 0; ii < pend; ii++)
+ for (jj = pend; jj < cbdata.files.count; jj++)
+ {
+ if (strcmp((char *)cbdata.filesspace + cbdata.files.elements[ii] + 33, (char *)cbdata.filesspace + cbdata.files.elements[jj] + 33))
+ continue;
+ if (!strcmp((char *)cbdata.filesspace + cbdata.files.elements[ii], (char *)cbdata.filesspace + cbdata.files.elements[jj]))
+ continue;
+ queue_push(conflicts, str2id(pool, (char *)cbdata.filesspace + cbdata.files.elements[ii] + 33, 1));
+ queue_push(conflicts, p);
+ queue_push(conflicts, str2id(pool, (char *)cbdata.filesspace + cbdata.files.elements[ii], 1));
+ queue_push(conflicts, q);
+ queue_push(conflicts, str2id(pool, (char *)cbdata.filesspace + cbdata.files.elements[jj], 1));
+ }
+ }
+ }
+ cbdata.filesspace = sat_free(cbdata.filesspace);
+ cbdata.filesspacen = 0;
+ printf("candidate check took %d ms\n", sat_timems(now));
+ if (conflicts->count > 5)
+ sat_sort(conflicts->elements, conflicts->count / 5, 5 * sizeof(Id), conflicts_cmp, pool);
+ (*handle_cb)(pool, 0, handle_cbdata);
+ printf("conflict detection took %d ms\n", sat_timems(start));
+ return conflicts->count;
+}
+
--- /dev/null
+#ifndef POOL_FILECONFLICTS_H
+#define POOL_FILECONFLICTS_H
+
+#include "pool.h"
+
+extern int pool_findfileconflicts(Pool *pool, Queue *pkgs, Queue *conflicts, void *(*handle_cb)(Pool *, Id, void *) , void *handle_cbdata);
+
+#endif
#define TAG_ARCH 1022
#define TAG_FILESIZES 1028
#define TAG_FILEMODES 1030
+#define TAG_FILEMD5S 1035
+#define TAG_FILELINKTOS 1036
#define TAG_SOURCERPM 1044
#define TAG_PROVIDENAME 1047
#define TAG_REQUIREFLAGS 1048
exit(1);
}
if (dbdata.size > rpmheadsize)
- rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + dbdata.size);
+ {
+ rpmheadsize = dbdata.size + 128;
+ rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
+ }
memcpy(buf, dbdata.data, 8);
rpmhead->cnt = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
rpmhead->dcnt = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7];
exit(1);
}
if (dbdata.size > rpmheadsize)
- rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + dbdata.size);
+ {
+ rpmheadsize = dbdata.size + 128;
+ rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
+ }
memcpy(buf, dbdata.data, 8);
rpmhead->cnt = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
rpmhead->dcnt = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7];
l = sigdsize + sigcnt * 16;
headerend = headerstart + 16 + l;
if (l > rpmheadsize)
- rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + l);
+ {
+ rpmheadsize = l + 128;
+ rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
+ }
if (fread(rpmhead->data, l, 1, fp) != 1)
{
fprintf(stderr, "%s: unexpected EOF\n", rpms[i]);
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
}
+
+static inline void
+linkhash(const char *lt, char *hash)
+{
+ unsigned int r = 0;
+ const unsigned char *str = (const unsigned char *)lt;
+ int l, c;
+
+ l = strlen(lt);
+ while ((c = *str++) != 0)
+ r += (r << 3) + c;
+ sprintf(hash, "%08x", r);
+ sprintf(hash + 8, "%08x", l);
+ sprintf(hash + 16, "%08x", 0);
+ sprintf(hash + 24, "%08x", 0);
+}
+
+void
+rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, char *, int, char *), void *cbdata)
+{
+ RpmHead *rpmhead = rpmhandle;
+ char **bn;
+ char **dn;
+ char **md = 0;
+ char **lt = 0;
+ unsigned int *di;
+ unsigned int *fm;
+ int cnt, dcnt, cnt2;
+ int i, l1, l;
+ char *space = 0;
+ int spacen = 0;
+ char md5[33], *md5p = 0;
+
+ dn = headstringarray(rpmhead, TAG_DIRNAMES, &dcnt);
+ if (!dn)
+ return;
+ if ((flags & RPM_ITERATE_FILELIST_ONLYDIRS) != 0)
+ {
+ for (i = 0; i < dcnt; i++)
+ (*cb)(cbdata, dn[i], 0, (char *)0);
+ sat_free(dn);
+ return;
+ }
+ bn = headstringarray(rpmhead, TAG_BASENAMES, &cnt);
+ if (!bn)
+ {
+ sat_free(dn);
+ return;
+ }
+ di = headint32array(rpmhead, TAG_DIRINDEXES, &cnt2);
+ if (!di || cnt != cnt2)
+ {
+ sat_free(di);
+ sat_free(bn);
+ sat_free(dn);
+ return;
+ }
+ fm = headint16array(rpmhead, TAG_FILEMODES, &cnt2);
+ if (!fm || cnt != cnt2)
+ {
+ sat_free(fm);
+ sat_free(di);
+ sat_free(bn);
+ sat_free(dn);
+ return;
+ }
+ if ((flags & RPM_ITERATE_FILELIST_WITHMD5) != 0)
+ {
+ md = headstringarray(rpmhead, TAG_FILEMD5S, &cnt2);
+ if (!md || cnt != cnt2)
+ {
+ sat_free(md);
+ sat_free(fm);
+ sat_free(di);
+ sat_free(bn);
+ sat_free(dn);
+ return;
+ }
+ }
+ for (i = 0; i < cnt; i++)
+ {
+ if (di[i] >= dcnt)
+ continue;
+ l1 = strlen(dn[di[i]]);
+ if (l1 == 0)
+ continue;
+ l = l1 + strlen(bn[i]) + 1;
+ if (l > spacen)
+ {
+ spacen = l + 16;
+ space = sat_realloc(space, spacen);
+ }
+ strcpy(space, dn[di[i]]);
+ strcpy(space + l1, bn[i]);
+ if (md)
+ {
+ md5p = md[i];
+ if (S_ISLNK(fm[i]))
+ {
+ md5p = 0;
+ if (!lt)
+ {
+ lt = headstringarray(rpmhead, TAG_FILELINKTOS, &cnt2);
+ if (cnt != cnt2)
+ lt = sat_free(lt);
+ }
+ if (lt)
+ {
+ linkhash(lt[i], md5);
+ md5p = md5;
+ }
+ }
+ if (!md5p)
+ md5p = "";
+ }
+ (*cb)(cbdata, space, fm[i], md5p);
+ }
+ sat_free(lt);
+ sat_free(md);
+ sat_free(fm);
+ sat_free(di);
+ sat_free(bn);
+ sat_free(dn);
+}
+
+
+struct rpm_by_state {
+ RpmHead *rpmhead;
+ int rpmheadsize;
+
+ int dbopened;
+ DB_ENV *dbenv;
+ DB *db;
+ int byteswapped;
+};
+
+void *
+rpm_byrpmdbid(Id rpmdbid, const char *rootdir, void **statep)
+{
+ struct rpm_by_state *state = *statep;
+ unsigned char buf[16];
+ DBT dbkey;
+ DBT dbdata;
+ RpmHead *rpmhead;
+
+ if (!rpmdbid)
+ {
+ /* close down */
+ if (!state)
+ return 0;
+ if (state->db)
+ state->db->close(state->db, 0);
+ if (state->dbenv)
+ state->dbenv->close(state->dbenv, 0);
+ sat_free(state->rpmhead);
+ sat_free(state);
+ *statep = (void *)0;
+ return 0;
+ }
+
+ if (!state)
+ {
+ state = sat_calloc(1, sizeof(*state));
+ *statep = state;
+ }
+ if (!state->dbopened)
+ {
+ char dbpath[PATH_MAX];
+ state->dbopened = 1;
+ if (db_env_create(&state->dbenv, 0))
+ {
+ perror("db_env_create");
+ state->dbenv = 0;
+ return 0;
+ }
+ if (!rootdir)
+ rootdir = "";
+ snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm", rootdir);
+#ifdef FEDORA
+ if (state->dbenv->open(state->dbenv, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL, 0))
+#else
+ if (state->dbenv->open(state->dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0))
+#endif
+ {
+ perror("dbenv open");
+ state->dbenv->close(state->dbenv, 0);
+ state->dbenv = 0;
+ return 0;
+ }
+ if (db_create(&state->db, state->dbenv, 0))
+ {
+ perror("db_create");
+ state->db = 0;
+ state->dbenv->close(state->dbenv, 0);
+ state->dbenv = 0;
+ return 0;
+ }
+ if (state->db->open(state->db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664))
+ {
+ perror("db->open var/lib/rpm/Packages");
+ state->db->close(state->db, 0);
+ state->db = 0;
+ state->dbenv->close(state->dbenv, 0);
+ state->dbenv = 0;
+ return 0;
+ }
+ if (state->db->get_byteswapped(state->db, &state->byteswapped))
+ {
+ perror("db->get_byteswapped");
+ state->db->close(state->db, 0);
+ state->db = 0;
+ state->dbenv->close(state->dbenv, 0);
+ state->dbenv = 0;
+ return 0;
+ }
+ }
+ memcpy(buf, &rpmdbid, 4);
+ if (state->byteswapped)
+ {
+ unsigned char bx;
+ bx = buf[0]; buf[0] = buf[3]; buf[3] = bx;
+ bx = buf[1]; buf[1] = buf[2]; buf[2] = bx;
+ }
+ memset(&dbkey, 0, sizeof(dbkey));
+ memset(&dbdata, 0, sizeof(dbdata));
+ dbkey.data = buf;
+ dbkey.size = 4;
+ dbdata.data = 0;
+ dbdata.size = 0;
+ if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0))
+ {
+ perror("db->get");
+ return 0;
+ }
+ if (dbdata.size < 8)
+ {
+ fprintf(stderr, "corrupt rpm database (size)\n");
+ return 0;
+ }
+ if (dbdata.size > state->rpmheadsize)
+ {
+ state->rpmheadsize = dbdata.size + 128;
+ state->rpmhead = sat_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize);
+ }
+ rpmhead = state->rpmhead;
+ memcpy(buf, dbdata.data, 8);
+ rpmhead->cnt = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+ rpmhead->dcnt = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7];
+ if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size)
+ {
+ fprintf(stderr, "corrupt rpm database (data size)\n");
+ return 0;
+ }
+ memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
+ rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
+ return rpmhead;
+}
+
+void *
+rpm_byfp(FILE *fp, const char *name, void **statep)
+{
+ struct rpm_by_state *state = *statep;
+ int headerstart, headerend;
+ RpmHead *rpmhead;
+ int sigdsize, sigcnt, l;
+ unsigned char lead[4096];
+
+ if (!fp)
+ return rpm_byrpmdbid(0, 0, statep);
+ if (!state)
+ {
+ state = sat_calloc(1, sizeof(*state));
+ *statep = state;
+ }
+ if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
+ {
+ fprintf(stderr, "%s: not a rpm\n", name);
+ return 0;
+ }
+ if (lead[78] != 0 || lead[79] != 5)
+ {
+ fprintf(stderr, "%s: not a V5 header\n", name);
+ return 0;
+ }
+ if (getu32(lead + 96) != 0x8eade801)
+ {
+ fprintf(stderr, "%s: bad signature header\n", name);
+ return 0;
+ }
+ sigcnt = getu32(lead + 96 + 8);
+ sigdsize = getu32(lead + 96 + 12);
+ if (sigcnt >= 0x4000000 || sigdsize >= 0x40000000)
+ {
+ fprintf(stderr, "%s: bad signature header\n", name);
+ return 0;
+ }
+ sigdsize += sigcnt * 16;
+ sigdsize = (sigdsize + 7) & ~7;
+ headerstart = 96 + 16 + sigdsize;
+ while (sigdsize)
+ {
+ l = sigdsize > 4096 ? 4096 : sigdsize;
+ if (fread(lead, l, 1, fp) != 1)
+ {
+ fprintf(stderr, "%s: unexpected EOF\n", name);
+ return 0;
+ }
+ sigdsize -= l;
+ }
+ if (fread(lead, 16, 1, fp) != 1)
+ {
+ fprintf(stderr, "%s: unexpected EOF\n", name);
+ return 0;
+ }
+ if (getu32(lead) != 0x8eade801)
+ {
+ fprintf(stderr, "%s: bad header\n", name);
+ fclose(fp);
+ return 0;
+ }
+ sigcnt = getu32(lead + 8);
+ sigdsize = getu32(lead + 12);
+ if (sigcnt >= 0x4000000 || sigdsize >= 0x40000000)
+ {
+ fprintf(stderr, "%s: bad header\n", name);
+ fclose(fp);
+ return 0;
+ }
+ l = sigdsize + sigcnt * 16;
+ headerend = headerstart + 16 + l;
+ if (l > state->rpmheadsize)
+ {
+ state->rpmheadsize = l + 128;
+ state->rpmhead = sat_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
+ }
+ rpmhead = state->rpmhead;
+ if (fread(rpmhead->data, l, 1, fp) != 1)
+ {
+ fprintf(stderr, "%s: unexpected EOF\n", name);
+ fclose(fp);
+ return 0;
+ }
+ rpmhead->cnt = sigcnt;
+ rpmhead->dcnt = sigdsize;
+ rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
+ return rpmhead;
+}
+
extern void repo_add_rpms(Repo *repo, const char **rpms, int nrpms, int flags);
#define RPMDB_REPORT_PROGRESS (1 << 8)
+
+#define RPM_ITERATE_FILELIST_ONLYDIRS (1 << 0)
+#define RPM_ITERATE_FILELIST_WITHMD5 (1 << 1)
+
+void *rpm_byrpmdbid(Id rpmdbid, const char *rootdir, void **statep);
+void *rpm_byfp(FILE *fp, const char *name, void **statep);
+void rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, char *, int, char *), void *cbdata);