/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
* repo_rpmdb
*
* convert rpm db to repo
*/
#include <sys/types.h>
+#include <sys/stat.h>
#include <limits.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
-#include <db43/db.h>
+#include <rpm/db.h>
#include "pool.h"
+#include "repo.h"
#include "hash.h"
+#include "util.h"
#include "repo_rpmdb.h"
+
#define TAG_NAME 1000
#define TAG_VERSION 1001
#define TAG_RELEASE 1002
#define TAG_SUMMARY 1004
#define TAG_DESCRIPTION 1005
#define TAG_BUILDTIME 1006
+#define TAG_SIZE 1009
#define TAG_VENDOR 1011
+#define TAG_GROUP 1016
#define TAG_ARCH 1022
+#define TAG_FILESIZES 1028
+#define TAG_FILEMODES 1030
+#define TAG_SOURCERPM 1044
#define TAG_PROVIDENAME 1047
#define TAG_REQUIREFLAGS 1048
#define TAG_REQUIRENAME 1049
#define TAG_REQUIREVERSION 1050
+#define TAG_NOSOURCE 1051
+#define TAG_NOPATCH 1052
#define TAG_CONFLICTFLAGS 1053
#define TAG_CONFLICTNAME 1054
#define TAG_CONFLICTVERSION 1055
unsigned char data[1];
} RpmHead;
+static int
+headexists(RpmHead *h, int tag)
+{
+ unsigned int i;
+ unsigned char *d, taga[4];
+
+ d = h->dp - 16;
+ taga[0] = tag >> 24;
+ taga[1] = tag >> 16;
+ taga[2] = tag >> 8;
+ taga[3] = tag;
+ for (i = 0; i < h->cnt; i++, d -= 16)
+ if (d[3] == taga[3] && d[2] == taga[2] && d[1] == taga[1] && d[0] == taga[0])
+ return 1;
+ return 0;
+}
+
static unsigned int *
-headint32(RpmHead *h, int tag, int *cnt)
+headint32array(RpmHead *h, int tag, int *cnt)
{
unsigned int i, o, *r;
unsigned char *d, taga[4];
if (o + 4 * i > h->dcnt)
return 0;
d = h->dp + o;
- r = calloc(i ? i : 1, sizeof(unsigned int));
+ r = sat_calloc(i ? i : 1, sizeof(unsigned int));
if (cnt)
*cnt = i;
for (o = 0; o < i; o++, d += 4)
return r;
}
+static unsigned int
+headint32(RpmHead *h, int tag)
+{
+ unsigned int i, o;
+ unsigned char *d, taga[4];
+
+ d = h->dp - 16;
+ taga[0] = tag >> 24;
+ taga[1] = tag >> 16;
+ taga[2] = tag >> 8;
+ taga[3] = tag;
+ for (i = 0; i < h->cnt; i++, d -= 16)
+ if (d[3] == taga[3] && d[2] == taga[2] && d[1] == taga[1] && d[0] == taga[0])
+ break;
+ if (i >= h->cnt)
+ return 0;
+ if (d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4)
+ return 0;
+ o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+ i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+ if (i == 0 || o + 4 * i > h->dcnt)
+ return 0;
+ d = h->dp + o;
+ return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+}
+
+static unsigned int *
+headint16array(RpmHead *h, int tag, int *cnt)
+{
+ unsigned int i, o, *r;
+ unsigned char *d, taga[4];
+
+ d = h->dp - 16;
+ taga[0] = tag >> 24;
+ taga[1] = tag >> 16;
+ taga[2] = tag >> 8;
+ taga[3] = tag;
+ for (i = 0; i < h->cnt; i++, d -= 16)
+ if (d[3] == taga[3] && d[2] == taga[2] && d[1] == taga[1] && d[0] == taga[0])
+ break;
+ if (i >= h->cnt)
+ return 0;
+ if (d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 3)
+ return 0;
+ o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+ i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+ if (o + 4 * i > h->dcnt)
+ return 0;
+ d = h->dp + o;
+ r = sat_calloc(i ? i : 1, sizeof(unsigned int));
+ if (cnt)
+ *cnt = i;
+ for (o = 0; o < i; o++, d += 2)
+ r[o] = d[0] << 8 | d[1];
+ return r;
+}
+
static char *
headstring(RpmHead *h, int tag)
{
break;
if (i >= h->cnt)
return 0;
- if (d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 6)
+ /* 6: STRING, 9: I18NSTRING */
+ if (d[4] != 0 || d[5] != 0 || d[6] != 0 || (d[7] != 6 && d[7] != 9))
return 0;
o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
return (char *)h->dp + o;
return 0;
o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
- r = calloc(i ? i : 1, sizeof(char *));
+ r = sat_calloc(i ? i : 1, sizeof(char *));
if (cnt)
*cnt = i;
d = h->dp + o;
d += strlen((char *)d) + 1;
if (d >= h->dp + h->dcnt)
{
- free(r);
+ sat_free(r);
return 0;
}
}
static char *headtoevr(RpmHead *h)
{
- unsigned int epoch, *epochp;
+ unsigned int epoch;
char *version, *v;
char *release;
char *evr;
- int epochcnt = 0;
version = headstring(h, TAG_VERSION);
release = headstring(h, TAG_RELEASE);
- epochp = headint32(h, TAG_EPOCH, &epochcnt);
+ epoch = headint32(h, TAG_EPOCH);
if (!version || !release)
{
fprintf(stderr, "headtoevr: bad rpm header\n");
}
for (v = version; *v >= 0 && *v <= '9'; v++)
;
- epoch = epochp && epochcnt ? *epochp : 0;
if (epoch || (v != version && *v == ':'))
{
char epochbuf[11]; /* 32bit decimal will fit in */
sprintf(epochbuf, "%u", epoch);
- evr = malloc(strlen(epochbuf) + 1 + strlen(version) + 1 + strlen(release) + 1);
+ evr = sat_malloc(strlen(epochbuf) + 1 + strlen(version) + 1 + strlen(release) + 1);
sprintf(evr, "%s:%s-%s", epochbuf, version, release);
}
else
{
- evr = malloc(strlen(version) + 1 + strlen(release) + 1);
+ evr = sat_malloc(strlen(version) + 1 + strlen(release) + 1);
sprintf(evr, "%s-%s", version, release);
}
- if (epochp)
- free(epochp);
return evr;
}
v = headstringarray(rpmhead, tagv, &vc);
if (!v)
{
- free(n);
+ sat_free(n);
return 0;
}
- f = headint32(rpmhead, tagf, &fc);
+ f = headint32array(rpmhead, tagf, &fc);
if (!f)
{
- free(n);
+ sat_free(n);
free(v);
return 0;
}
haspre = 0;
if (cc == 0)
{
- free(n);
- free(v);
- free(f);
+ sat_free(n);
+ sat_free(v);
+ sat_free(f);
return 0;
}
cc += haspre;
}
*ida++ = 0;
repo->idarraysize += cc + 1;
- free(n);
- free(v);
- free(f);
+ sat_free(n);
+ sat_free(v);
+ sat_free(f);
return olddeps;
}
{ FILEFILTER_STARTS, "/opt/gnome/games/", 0},
};
+static void
+adddudata(Pool *pool, Repo *repo, Repodata *repodata, Solvable *s, RpmHead *rpmhead, char **dn, unsigned int *di, int fc, int dic)
+{
+ Id entry, did;
+ int i, fszc;
+ unsigned int *fkb, *fn, *fsz, *fm;
+
+ fsz = headint32array(rpmhead, TAG_FILESIZES, &fszc);
+ if (!fsz || fc != fszc)
+ {
+ sat_free(fsz);
+ return;
+ }
+ /* stupid rpm recodrs sizes of directories, so we have to check the mode */
+ fm = headint16array(rpmhead, TAG_FILEMODES, &fszc);
+ if (!fm || fc != fszc)
+ {
+ sat_free(fsz);
+ sat_free(fm);
+ return;
+ }
+ fn = sat_calloc(dic, sizeof(unsigned int));
+ fkb = sat_calloc(dic, sizeof(unsigned int));
+ for (i = 0; i < fc; i++)
+ {
+ if (fsz[i] == 0 || !S_ISREG(fm[i]))
+ continue;
+ if (di[i] >= dic)
+ continue;
+ fn[di[i]]++;
+ /* does not consider hard links. tough luck. */
+ fkb[di[i]] += fsz[i] / 1024 + 1;
+ }
+ sat_free(fsz);
+ sat_free(fm);
+ /* commit */
+ repodata_extend(repodata, s - pool->solvables);
+ entry = (s - pool->solvables) - repodata->start;
+ for (i = 0; i < fc; i++)
+ {
+ if (!fn[i])
+ continue;
+ if (!*dn[i] && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
+ did = repodata_str2dir(repodata, "/usr/src", 1);
+ else
+ did = repodata_str2dir(repodata, dn[i], 1);
+ repodata_add_dirnumnum(repodata, entry, SOLVABLE_DISKUSAGE, did, fkb[i], fn[i]);
+ }
+ sat_free(fn);
+ sat_free(fkb);
+}
+
/* assumes last processed array is provides! */
static unsigned int
-addfileprovides(Pool *pool, Repo *repo, RpmHead *rpmhead, unsigned int olddeps)
+addfileprovides(Pool *pool, Repo *repo, Repodata *repodata, Solvable *s, RpmHead *rpmhead, unsigned int olddeps)
{
char **bn;
char **dn;
char *fn = 0;
int fna = 0;
+ if (!repodata)
+ return olddeps;
bn = headstringarray(rpmhead, TAG_BASENAMES, &bnc);
if (!bn)
return olddeps;
dn = headstringarray(rpmhead, TAG_DIRNAMES, &dnc);
if (!dn)
{
- free(bn);
+ sat_free(bn);
return olddeps;
}
- di = headint32(rpmhead, TAG_DIRINDEXES, &dic);
+ di = headint32array(rpmhead, TAG_DIRINDEXES, &dic);
if (!di)
{
- free(bn);
- free(dn);
+ sat_free(bn);
+ sat_free(dn);
return olddeps;
}
if (bnc != dic)
fprintf(stderr, "bad filelist\n");
exit(1);
}
+
+ if (repodata)
+ adddudata(pool, repo, repodata, s, rpmhead, dn, di, bnc, dic);
+
for (i = 0; i < bnc; i++)
{
ff = filefilters;
j = strlen(bn[i]) + strlen(dn[di[i]]) + 1;
if (j > fna)
{
- if (fn)
- fn = realloc(fn, j + 256);
- else
- fn = malloc(j + 256);
fna = j + 256;
+ fn = sat_realloc(fn, fna);
}
strcpy(fn, dn[di[i]]);
strcat(fn, bn[i]);
- olddeps = repo_addid(repo, olddeps, str2id(pool, fn, 1));
+#if 0
+ olddeps = repo_addid_dep(repo, olddeps, str2id(pool, fn, 1), SOLVABLE_FILEMARKER);
+#endif
+ if (repodata)
+ {
+ Id entry, did;
+ repodata_extend(repodata, s - pool->solvables);
+ entry = (s - pool->solvables) - repodata->start;
+ did = repodata_str2dir(repodata, dn[di[i]], 1);
+ repodata_add_dirstr(repodata, entry, SOLVABLE_FILELIST, did, bn[i]);
+ }
}
if (fn)
- free(fn);
- free(bn);
- free(dn);
- free(di);
+ sat_free(fn);
+ sat_free(bn);
+ sat_free(dn);
+ sat_free(di);
return olddeps;
}
static int
-rpm2solv(Pool *pool, Repo *repo, Solvable *s, RpmHead *rpmhead)
+rpm2solv(Pool *pool, Repo *repo, Repodata *repodata, Solvable *s, RpmHead *rpmhead)
{
char *name;
char *evr;
fprintf(stderr, "package has no name\n");
exit(1);
}
- s->arch = str2id(pool, headstring(rpmhead, TAG_ARCH), 1);
- if (!s->arch)
+ if (headstring(rpmhead, TAG_SOURCERPM))
+ s->arch = str2id(pool, headstring(rpmhead, TAG_ARCH), 1);
+ else
{
- fprintf(stderr, "package %s has no arch\n", id2str(pool, s->name));
- exit(1);
+ if (headexists(rpmhead, TAG_NOSOURCE) || headexists(rpmhead, TAG_NOPATCH))
+ s->arch = ARCH_NOSRC;
+ else
+ s->arch = ARCH_SRC;
}
+ if (!s->arch)
+ s->arch = ARCH_NOARCH;
evr = headtoevr(rpmhead);
s->evr = str2id(pool, evr, 1);
- free(evr);
+ sat_free(evr);
+ s->vendor = str2id(pool, headstring(rpmhead, TAG_VENDOR), 1);
s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0);
- s->provides = addfileprovides(pool, repo, rpmhead, s->provides);
+ s->provides = addfileprovides(pool, repo, repodata, s, rpmhead, s->provides);
s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, 0);
s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0);
s->enhances = makedeps(pool, repo, rpmhead, TAG_ENHANCESNAME, TAG_ENHANCESVERSION, TAG_ENHANCESFLAGS, 1);
s->freshens = 0;
s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
+
+ if (repodata)
+ {
+ Id entry;
+ char *str;
+ unsigned int u32;
+
+ repodata_extend(repodata, s - pool->solvables);
+ entry = (s - pool->solvables) - repodata->start;
+ str = headstring(rpmhead, TAG_SUMMARY);
+ if (str)
+ repodata_set_str(repodata, entry, SOLVABLE_SUMMARY, str);
+ str = headstring(rpmhead, TAG_DESCRIPTION);
+ if (str)
+ {
+ char *aut, *p;
+ for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++)
+ if (!strncmp(aut, "\nAuthors:\n--------\n", 19))
+ break;
+ if (aut)
+ {
+ /* oh my, found SUSE special author section */
+ int l = aut - str;
+ str = strdup(str);
+ aut = str + l;
+ str[l] = 0;
+ while (l > 0 && str[l - 1] == '\n')
+ str[--l] = 0;
+ if (l)
+ repodata_set_str(repodata, entry, SOLVABLE_DESCRIPTION, str);
+ p = aut + 19;
+ aut = str; /* copy over */
+ while (*p == ' ' || *p == '\n')
+ p++;
+ while (*p)
+ {
+ if (*p == '\n')
+ {
+ *aut++ = *p++;
+ while (*p == ' ')
+ p++;
+ continue;
+ }
+ *aut++ = *p++;
+ }
+ while (aut != str && aut[-1] == '\n')
+ aut--;
+ *aut = 0;
+ if (*str)
+ repodata_set_str(repodata, entry, SOLVABLE_AUTHORS, str);
+ free(str);
+ }
+ else if (*str)
+ repodata_set_str(repodata, entry, SOLVABLE_DESCRIPTION, str);
+ }
+ str = headstring(rpmhead, TAG_GROUP);
+ if (str)
+ repodata_set_poolstr(repodata, entry, SOLVABLE_GROUP, str);
+ u32 = headint32(rpmhead, TAG_BUILDTIME);
+ if (u32)
+ repodata_set_num(repodata, entry, SOLVABLE_BUILDTIME, u32);
+ u32 = headint32(rpmhead, TAG_SIZE);
+ if (u32)
+ repodata_set_num(repodata, entry, SOLVABLE_INSTALLSIZE, (u32 + 1023) / 1024);
+ }
return 1;
}
*
*/
-Repo *
-pool_addrepo_rpmdb(Pool *pool, Repo *ref)
+void
+repo_add_rpmdb(Repo *repo, Repo *ref, const char *rootdir)
{
+ Pool *pool = repo->pool;
unsigned char buf[16];
DB *db = 0;
DBC *dbc = 0;
int i;
int rpmheadsize;
RpmHead *rpmhead;
- Repo *repo;
Solvable *s;
Id id, *refhash;
unsigned int refmask, h;
int asolv;
+ Repodata *repodata;
+ char dbpath[PATH_MAX];
+
+ if (repo->start != repo->end)
+ abort(); /* FIXME: rpmdbid */
- repo = pool_addrepo_empty(pool);
+ repodata = repo_add_repodata(repo);
if (ref && !(ref->nsolvables && ref->rpmdbid))
ref = 0;
if (!ref)
{
- if (db->open(db, 0, "/var/lib/rpm/Packages", 0, DB_HASH, DB_RDONLY, 0664))
+ snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm/Packages", rootdir);
+ if (db->open(db, 0, dbpath, 0, DB_HASH, DB_RDONLY, 0664))
{
- perror("db->open /var/lib/rpm/Packages");
+ perror("db->open var/lib/rpm/Packages");
exit(1);
}
if (db->get_byteswapped(db, &byteswapped))
exit(1);
}
dbidp = (unsigned char *)&dbid;
- pool->solvables = realloc(pool->solvables, (pool->nsolvables + 256) * sizeof(Solvable));
- memset(pool->solvables + repo->start, 0, 256 * sizeof(Solvable));
- repo->rpmdbid = calloc(256, sizeof(unsigned int));
+ repo->rpmdbid = sat_calloc(256, sizeof(unsigned int));
asolv = 256;
rpmheadsize = 0;
rpmhead = 0;
i = 0;
+ s = 0;
while (dbc->c_get(dbc, &key, &data, DB_NEXT) == 0)
{
+ if (!s)
+ s = pool_id2solvable(pool, repo_add_solvable(repo));
if (i >= asolv)
{
- pool->solvables = realloc(pool->solvables, (pool->nsolvables + asolv + 256) * sizeof(Solvable));
- memset(pool->solvables + repo->start + asolv, 0, 256 * sizeof(Solvable));
- repo->rpmdbid = realloc(repo->rpmdbid, (asolv + 256) * sizeof(unsigned int));
+ repo->rpmdbid = sat_realloc(repo->rpmdbid, (asolv + 256) * sizeof(unsigned int));
memset(repo->rpmdbid + asolv, 0, 256 * sizeof(unsigned int));
asolv += 256;
}
- pool->solvables[repo->start + i].repo = repo;
if (key.size != 4)
{
fprintf(stderr, "corrupt Packages database (key size)\n");
fprintf(stderr, "corrupt rpm database (size %u)\n", data.size);
exit(1);
}
- if (!rpmhead)
- rpmhead = malloc(sizeof(*rpmhead) + data.size);
- else if (data.size > rpmheadsize)
- rpmhead = realloc(rpmhead, sizeof(*rpmhead) + data.size);
+ if (data.size > rpmheadsize)
+ rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + data.size);
memcpy(buf, data.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];
memcpy(rpmhead->data, (unsigned char *)data.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
repo->rpmdbid[i] = dbid;
- if (rpm2solv(pool, repo, pool->solvables + repo->start + i, rpmhead))
- i++;
+ if (rpm2solv(pool, repo, repodata, s, rpmhead))
+ {
+ i++;
+ s = 0;
+ }
+ else
+ {
+ /* We can reuse this solvable, but make sure it's still
+ associated with this repo. */
+ memset(s, 0, sizeof(*s));
+ s->repo = repo;
+ }
+ }
+ if (s)
+ {
+ /* oops, could not reuse. free it instead */
+ repo_free_solvable_block(repo, s - pool->solvables, 1, 1);
+ s = 0;
}
- nrpmids = i;
dbc->c_close(dbc);
db->close(db, 0);
db = 0;
}
else
{
- if (db->open(db, 0, "/var/lib/rpm/Name", 0, DB_HASH, DB_RDONLY, 0664))
+ snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm/Name", rootdir);
+ if (db->open(db, 0, dbpath, 0, DB_HASH, DB_RDONLY, 0664))
{
- perror("db->open /var/lib/rpm/Name");
+ perror("db->open var/lib/rpm/Name");
exit(1);
}
if (db->get_byteswapped(db, &byteswapped))
else
memcpy(dbidp, dp, 4);
if ((nrpmids & 255) == 0)
- {
- if (rpmids)
- rpmids = realloc(rpmids, sizeof(*rpmids) * (nrpmids + 256));
- else
- rpmids = malloc(sizeof(*rpmids) * 256);
- }
+ rpmids = sat_realloc(rpmids, sizeof(*rpmids) * (nrpmids + 256));
rpmids[nrpmids].dbid = dbid;
- rpmids[nrpmids].name = malloc((int)key.size + 1);
+ rpmids[nrpmids].name = sat_malloc((int)key.size + 1);
memcpy(rpmids[nrpmids].name, key.data, (int)key.size);
rpmids[nrpmids].name[(int)key.size] = 0;
nrpmids++;
dp += 8;
dl -= 8;
}
-
}
dbc->c_close(dbc);
db->close(db, 0);
rpmheadsize = 0;
rpmhead = 0;
- pool->solvables = realloc(pool->solvables, (pool->nsolvables + nrpmids) * sizeof(Solvable));
- memset(pool->solvables + repo->start, 0, nrpmids * sizeof(Solvable));
- repo->rpmdbid = calloc(nrpmids, sizeof(unsigned int));
-
refhash = 0;
refmask = 0;
if (ref)
{
refmask = mkmask(ref->nsolvables);
- refhash = calloc(refmask + 1, sizeof(Id));
+ refhash = sat_calloc(refmask + 1, sizeof(Id));
for (i = 0; i < ref->nsolvables; i++)
{
h = ref->rpmdbid[i] & refmask;
refhash[h] = i + 1; /* make it non-zero */
}
}
- s = pool->solvables + repo->start;
+
+ repo->rpmdbid = sat_calloc(nrpmids, sizeof(unsigned int));
+
+ s = pool_id2solvable(pool, repo_add_solvable_block(repo, nrpmids));
+
for (i = 0; i < nrpmids; i++, rp++, s++)
{
- s->repo = repo;
dbid = rp->dbid;
repo->rpmdbid[i] = dbid;
if (refhash)
s->name = r->name;
s->evr = r->evr;
s->arch = r->arch;
+ s->vendor = r->vendor;
}
else
{
s->evr = str2id(pool, id2str(ref->pool, r->evr), 1);
if (r->arch)
s->arch = str2id(pool, id2str(ref->pool, r->arch), 1);
+ if (r->vendor)
+ s->vendor = str2id(pool, id2str(ref->pool, r->vendor), 1);
}
s->provides = copydeps(pool, repo, r->provides, ref);
s->requires = copydeps(pool, repo, r->requires, ref);
perror("db_create");
exit(1);
}
- if (db->open(db, 0, "/var/lib/rpm/Packages", 0, DB_HASH, DB_RDONLY, 0664))
+ snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm/Packages", rootdir);
+ if (db->open(db, 0, dbpath, 0, DB_HASH, DB_RDONLY, 0664))
{
- perror("db->open /var/lib/rpm/Packages");
+ perror("db->open var/lib/rpm/Packages");
exit(1);
}
if (db->get_byteswapped(db, &byteswapped))
fprintf(stderr, "corrupt rpm database (size)\n");
exit(1);
}
- if (!rpmhead)
- rpmhead = malloc(sizeof(*rpmhead) + data.size);
- else if (data.size > rpmheadsize)
- rpmhead = realloc(rpmhead, sizeof(*rpmhead) + data.size);
+ if (data.size > rpmheadsize)
+ rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + data.size);
memcpy(buf, data.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];
memcpy(rpmhead->data, (unsigned char *)data.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
- rpm2solv(pool, repo, s, rpmhead);
+ rpm2solv(pool, repo, repodata, s, rpmhead);
}
if (refhash)
- free(refhash);
+ sat_free(refhash);
if (rpmids)
{
for (i = 0; i < nrpmids; i++)
- free(rpmids[i].name);
- free(rpmids);
+ sat_free(rpmids[i].name);
+ sat_free(rpmids);
}
}
if (rpmhead)
- free(rpmhead);
- pool->nsolvables += nrpmids;
- repo->nsolvables = nrpmids;
-
+ sat_free(rpmhead);
if (db)
db->close(db, 0);
- return repo;
+ if (repodata)
+ repodata_internalize(repodata);
+}
+
+static inline unsigned int
+getu32(unsigned char *dp)
+{
+ return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3];
+}
+
+static void
+add_location(Repodata *data, Solvable *s, const char *location)
+{
+ Pool *pool = s->repo->pool;
+ const char *name, *n1, *n2;
+ int l;
+ Id entry;
+
+ repodata_extend(data, s - pool->solvables);
+ entry = (s - pool->solvables) - data->start;
+
+ /* skip ./ prefix */
+ if (location[0] == '.' && location[1] == '/' && location[2] != '/')
+ location += 2;
+
+ name = strrchr(location, '/');
+ if (!name)
+ name = location;
+ else
+ {
+ name++;
+ n2 = id2str(pool, s->arch);
+ l = strlen(n2);
+ if (strncmp(location, n2, l) != 0 || location + l + 1 != name)
+ {
+ /* too bad, need to store directory */
+ char *dir = strdup(location);
+ dir[name - location - 1] = 0;
+ repodata_set_str(data, entry, SOLVABLE_MEDIADIR, dir);
+ free(dir);
+ }
+ else
+ repodata_set_void(data, entry, SOLVABLE_MEDIADIR);
+ }
+ n1 = name;
+ for (n2 = id2str(pool, s->name); *n2; n1++, n2++)
+ if (*n1 != *n2)
+ break;
+ if (*n2 || *n1 != '-')
+ goto nontrivial;
+ n1++;
+ for (n2 = id2str (pool, s->evr); *n2; n1++, n2++)
+ if (*n1 != *n2)
+ break;
+ if (*n2 || *n1 != '.')
+ goto nontrivial;
+ n1++;
+ for (n2 = id2str (pool, s->arch); *n2; n1++, n2++)
+ if (*n1 != *n2)
+ break;
+ if (*n2 || strcmp (n1, ".rpm"))
+ goto nontrivial;
+ repodata_set_void(data, entry, SOLVABLE_MEDIAFILE);
+ return;
+
+nontrivial:
+ repodata_set_str(data, entry, SOLVABLE_MEDIAFILE, name);
+ return;
+}
+
+
+void
+repo_add_rpms(Repo *repo, const char **rpms, int nrpms)
+{
+ int i, sigdsize, sigcnt, l;
+ Pool *pool = repo->pool;
+ Solvable *s;
+ Repodata *repodata;
+ RpmHead *rpmhead = 0;
+ int rpmheadsize = 0;
+ FILE *fp;
+ unsigned char lead[4096];
+
+ if (nrpms <= 0)
+ return;
+ repodata = repo_add_repodata(repo);
+ for (i = 0; i < nrpms; i++)
+ {
+ if ((fp = fopen(rpms[i], "r")) == 0)
+ {
+ perror(rpms[i]);
+ continue;
+ }
+ if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
+ {
+ fprintf(stderr, "%s: not a rpm\n", rpms[i]);
+ fclose(fp);
+ continue;
+ }
+ if (lead[78] != 0 || lead[79] != 5)
+ {
+ fprintf(stderr, "%s: not a V5 header\n", rpms[i]);
+ fclose(fp);
+ continue;
+ }
+ if (getu32(lead + 96) != 0x8eade801)
+ {
+ fprintf(stderr, "%s: bad signature header\n", rpms[i]);
+ fclose(fp);
+ continue;
+ }
+ sigcnt = getu32(lead + 96 + 8);
+ sigdsize = getu32(lead + 96 + 12);
+ if (sigcnt >= 0x4000000 || sigdsize >= 0x40000000)
+ {
+ fprintf(stderr, "%s: bad signature header\n", rpms[i]);
+ fclose(fp);
+ continue;
+ }
+ sigdsize += sigcnt * 16;
+ sigdsize = (sigdsize + 7) & ~7;
+ while (sigdsize)
+ {
+ l = sigdsize > 4096 ? 4096 : sigdsize;
+ if (fread(lead, l, 1, fp) != 1)
+ {
+ fprintf(stderr, "%s: unexpected EOF\n", rpms[i]);
+ fclose(fp);
+ continue;
+ }
+ sigdsize -= l;
+ }
+ if (fread(lead, 16, 1, fp) != 1)
+ {
+ fprintf(stderr, "%s: unexpected EOF\n", rpms[i]);
+ fclose(fp);
+ continue;
+ }
+ if (getu32(lead) != 0x8eade801)
+ {
+ fprintf(stderr, "%s: bad header\n", rpms[i]);
+ fclose(fp);
+ continue;
+ }
+ sigcnt = getu32(lead + 8);
+ sigdsize = getu32(lead + 12);
+ if (sigcnt >= 0x4000000 || sigdsize >= 0x40000000)
+ {
+ fprintf(stderr, "%s: bad header\n", rpms[i]);
+ fclose(fp);
+ continue;
+ }
+ l = sigdsize + sigcnt * 16;
+ if (l > rpmheadsize)
+ rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + l);
+ if (fread(rpmhead->data, l, 1, fp) != 1)
+ {
+ fprintf(stderr, "%s: unexpected EOF\n", rpms[i]);
+ fclose(fp);
+ continue;
+ }
+ rpmhead->cnt = sigcnt;
+ rpmhead->dcnt = sigdsize;
+ rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
+ fclose(fp);
+ s = pool_id2solvable(pool, repo_add_solvable(repo));
+ rpm2solv(pool, repo, repodata, s, rpmhead);
+ add_location(repodata, s, rpms[i]);
+ }
+ if (rpmhead)
+ sat_free(rpmhead);
+ if (repodata)
+ repodata_internalize(repodata);
}