#include <string.h>
#include <unistd.h>
#include <zlib.h>
+#include <errno.h>
#include "pool.h"
#include "repo.h"
memset(&strm, 0, sizeof(strm));
strm.next_in = in;
strm.avail_in = inl;
- out = sat_malloc(4096);
+ out = solv_malloc(4096);
strm.next_out = out;
strm.avail_out = 4096;
outl = 0;
if (strm.avail_out == 0)
{
outl += 4096;
- out = sat_realloc(out, outl + 4096);
+ out = solv_realloc(out, outl + 4096);
strm.next_out = out + outl;
strm.avail_out = 4096;
}
return out;
}
-static unsigned int
-makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
+static Id
+parseonedep(Pool *pool, char *p)
{
- Pool *pool = repo->pool;
- char *p, *n, *ne, *e, *ee;
- Id id, name, evr;
+ char *n, *ne, *e, *ee;
+ Id name, evr;
int flags;
- while ((p = strchr(deps, ',')) != 0)
- {
- *p++ = 0;
- olddeps = makedeps(repo, deps, olddeps, marker);
- deps = p;
- }
- id = 0;
- p = deps;
- for (;;)
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ p++;
+ if (!*p || *p == '(')
+ return 0;
+ n = p;
+ /* find end of name */
+ while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '(' && *p != '|')
+ p++;
+ ne = p;
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ p++;
+ evr = 0;
+ flags = 0;
+ e = ee = 0;
+ if (*p == '(')
{
+ p++;
while (*p == ' ' || *p == '\t' || *p == '\n')
p++;
- if (!*p || *p == '(')
- break;
- n = p;
- while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '(' && *p != '|')
- p++;
- ne = p;
- while (*p == ' ' || *p == '\t' || *p == '\n')
- p++;
- evr = 0;
- flags = 0;
- e = ee = 0;
- if (*p == '(')
+ if (*p == '>')
+ flags |= REL_GT;
+ else if (*p == '=')
+ flags |= REL_EQ;
+ else if (*p == '<')
+ flags |= REL_LT;
+ if (flags)
{
p++;
- while (*p == ' ' || *p == '\t' || *p == '\n')
- p++;
if (*p == '>')
flags |= REL_GT;
else if (*p == '=')
flags |= REL_EQ;
else if (*p == '<')
flags |= REL_LT;
- if (flags)
- {
- p++;
- if (*p == '>')
- flags |= REL_GT;
- else if (*p == '=')
- flags |= REL_EQ;
- else if (*p == '<')
- flags |= REL_LT;
- else
- p--;
- p++;
- }
- while (*p == ' ' || *p == '\t' || *p == '\n')
- p++;
- e = p;
- while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != ')')
- p++;
- ee = p;
- while (*p && *p != ')')
- p++;
- if (*p)
- p++;
- while (*p == ' ' || *p == '\t' || *p == '\n')
- p++;
- }
- name = strn2id(pool, n, ne - n, 1);
- if (e)
- {
- evr = strn2id(pool, e, ee - e, 1);
- name = rel2id(pool, name, evr, flags, 1);
+ else
+ p--;
+ p++;
}
- if (!id)
- id = name;
- else
- id = rel2id(pool, id, name, REL_OR, 1);
- if (*p != '|')
- break;
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ p++;
+ e = p;
+ while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != ')')
+ p++;
+ ee = p;
+ while (*p && *p != ')')
+ p++;
+ if (*p)
+ p++;
+ while (*p == ' ' || *p == '\t' || *p == '\n')
+ p++;
+ }
+ if (ne - n > 4 && ne[-4] == ':' && !strncmp(ne - 4, ":any", 4))
+ {
+ /* multiarch annotation */
+ name = pool_strn2id(pool, n, ne - n - 4, 1);
+ name = pool_rel2id(pool, name, ARCH_ANY, REL_MULTIARCH, 1);
+ }
+ else
+ name = pool_strn2id(pool, n, ne - n, 1);
+ if (e)
+ {
+ evr = pool_strn2id(pool, e, ee - e, 1);
+ name = pool_rel2id(pool, name, evr, flags, 1);
+ }
+ if (*p == '|')
+ {
+ Id id = parseonedep(pool, p + 1);
+ if (id)
+ name = pool_rel2id(pool, name, id, REL_OR, 1);
}
+ return name;
+}
+
+static unsigned int
+makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
+{
+ Pool *pool = repo->pool;
+ char *p;
+ Id id;
+
+ while ((p = strchr(deps, ',')) != 0)
+ {
+ *p = 0;
+ olddeps = makedeps(repo, deps, olddeps, marker);
+ *p = ',';
+ deps = p + 1;
+ }
+ id = parseonedep(pool, deps);
if (!id)
return olddeps;
return repo_addid_dep(repo, olddeps, id, marker);
Pool *pool = repo->pool;
char *p, *q, *end, *tag;
int x, l;
+ int havesource = 0;
+ char checksum[32 * 2 + 1];
+ Id checksumtype = 0;
+ Id newtype;
p = control;
while (*p)
{
case 'A' << 8 | 'R':
if (!strcasecmp(tag, "architecture"))
- s->arch = str2id(pool, q, 1);
+ s->arch = pool_str2id(pool, q, 1);
break;
case 'B' << 8 | 'R':
if (!strcasecmp(tag, "breaks"))
if (!strcasecmp(tag, "enhances"))
s->enhances = makedeps(repo, q, s->enhances, 0);
break;
+ case 'F' << 8 | 'I':
+ if (!strcasecmp(tag, "filename"))
+ repodata_set_location(data, s - pool->solvables, 0, 0, q);
+ break;
+ case 'H' << 8 | 'O':
+ if (!strcasecmp(tag, "homepage"))
+ repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, q);
+ break;
case 'I' << 8 | 'N':
if (!strcasecmp(tag, "installed-size"))
- repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, atoi(q));
+ repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(q, 0, 10) << 10);
+ break;
+ case 'M' << 8 | 'D':
+ if (!strcasecmp(tag, "md5sum") && !checksumtype && strlen(q) == 16 * 2)
+ {
+ strcpy(checksum, q);
+ checksumtype = REPOKEY_TYPE_MD5;
+ }
break;
case 'P' << 8 | 'A':
if (!strcasecmp(tag, "package"))
- s->name = str2id(pool, q, 1);
+ s->name = pool_str2id(pool, q, 1);
break;
case 'P' << 8 | 'R':
if (!strcasecmp(tag, "pre-depends"))
break;
case 'R' << 8 | 'E':
if (!strcasecmp(tag, "replaces"))
- s->obsoletes = makedeps(repo, q, s->conflicts, 0);
+ s->obsoletes = makedeps(repo, q, s->obsoletes, 0);
else if (!strcasecmp(tag, "recommends"))
s->recommends = makedeps(repo, q, s->recommends, 0);
break;
+ case 'S' << 8 | 'H':
+ newtype = solv_chksum_str2type(tag);
+ if (!newtype || solv_chksum_len(newtype) * 2 != strlen(q))
+ break;
+ if (!checksumtype || (newtype == REPOKEY_TYPE_SHA1 && checksumtype != REPOKEY_TYPE_SHA256) || newtype == REPOKEY_TYPE_SHA256)
+ {
+ strcpy(checksum, q);
+ checksumtype = newtype;
+ }
+ break;
+ case 'S' << 8 | 'O':
+ if (!strcasecmp(tag, "source"))
+ {
+ char *q2;
+ /* ignore version for now */
+ for (q2 = q; *q2; q2++)
+ if (*q2 == ' ' || *q2 == '\t')
+ {
+ *q2 = 0;
+ break;
+ }
+ if (s->name && !strcmp(q, pool_id2str(pool, s->name)))
+ repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
+ else
+ repodata_set_id(data, s - pool->solvables, SOLVABLE_SOURCENAME, pool_str2id(pool, q, 1));
+ havesource = 1;
+ }
+ break;
case 'S' << 8 | 'U':
if (!strcasecmp(tag, "suggests"))
s->suggests = makedeps(repo, q, s->suggests, 0);
break;
case 'V' << 8 | 'E':
if (!strcasecmp(tag, "version"))
- s->evr = str2id(pool, q, 1);
+ s->evr = pool_str2id(pool, q, 1);
break;
}
}
+ if (checksumtype)
+ repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, checksumtype, checksum);
+ if (!s->arch)
+ s->arch = ARCH_ALL;
+ if (!s->evr)
+ s->evr = ID_EMPTY;
+ if (s->name)
+ s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+ if (s->name && !havesource)
+ repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
+ if (s->obsoletes)
+ {
+ /* obsoletes only count when the packages also conflict */
+ /* XXX: should not transcode here */
+ int i, j, k;
+ Id d, cid;
+ for (i = j = s->obsoletes; (d = repo->idarraydata[i]) != 0; i++)
+ {
+ if (!s->conflicts)
+ continue;
+ for (k = s->conflicts; (cid = repo->idarraydata[k]) != 0; k++)
+ {
+ if (repo->idarraydata[k] == cid)
+ break;
+ if (ISRELDEP(cid))
+ {
+ Reldep *rd = GETRELDEP(pool, cid);
+ if (rd->flags < 8 && rd->name == d)
+ break; /* specialize obsoletes */
+ }
+ }
+ if (cid)
+ repo->idarraydata[j++] = cid;
+ }
+ repo->idarraydata[j] = 0;
+ if (j == s->obsoletes)
+ s->obsoletes = 0;
+ }
+}
+
+int
+repo_add_debpackages(Repo *repo, FILE *fp, int flags)
+{
+ Pool *pool = repo->pool;
+ Repodata *data;
+ char *buf, *p;
+ int bufl, l, ll;
+ Solvable *s;
+
+ data = repo_add_repodata(repo, flags);
+ buf = solv_malloc(4096);
+ bufl = 4096;
+ l = 0;
+ buf[l] = 0;
+ p = buf;
+ for (;;)
+ {
+ if (!(p = strchr(p, '\n')))
+ {
+ int l3;
+ if (l + 1024 >= bufl)
+ {
+ buf = solv_realloc(buf, bufl + 4096);
+ bufl += 4096;
+ p = buf + l;
+ continue;
+ }
+ p = buf + l;
+ ll = fread(p, 1, bufl - l - 1, fp);
+ if (ll <= 0)
+ break;
+ p[ll] = 0;
+ while ((l3 = strlen(p)) < ll)
+ p[l3] = '\n';
+ l += ll;
+ continue;
+ }
+ p++;
+ if (*p != '\n')
+ continue;
+ *p = 0;
+ ll = p - buf + 1;
+ s = pool_id2solvable(pool, repo_add_solvable(repo));
+ control2solvable(s, data, buf);
+ if (!s->name)
+ repo_free_solvable(repo, s - pool->solvables, 1);
+ if (l > ll)
+ memmove(buf, p + 1, l - ll);
+ l -= ll;
+ p = buf;
+ buf[l] = 0;
+ }
+ if (l)
+ {
+ s = pool_id2solvable(pool, repo_add_solvable(repo));
+ control2solvable(s, data, buf);
+ if (!s->name)
+ repo_free_solvable(repo, s - pool->solvables, 1);
+ }
+ solv_free(buf);
+ if (!(flags & REPO_NO_INTERNALIZE))
+ repodata_internalize(data);
+ return 0;
+}
+
+int
+repo_add_debdb(Repo *repo, int flags)
+{
+ FILE *fp;
+ const char *path = "/var/lib/dpkg/status";
+ if (flags & REPO_USE_ROOTDIR)
+ path = pool_prepend_rootdir_tmp(repo->pool, path);
+ if ((fp = fopen(path, "r")) == 0)
+ return pool_error(repo->pool, -1, "%s: %s", path, strerror(errno));
+ repo_add_debpackages(repo, fp, flags);
+ fclose(fp);
+ return 0;
}
-void
-repo_add_debs(Repo *repo, const char **debs, int ndebs, int flags)
+Id
+repo_add_deb(Repo *repo, const char *deb, int flags)
{
Pool *pool = repo->pool;
Repodata *data;
unsigned char buf[4096], *bp;
- int i, l, l2, vlen, clen, ctarlen;
+ int l, l2, vlen, clen, ctarlen;
unsigned char *ctgz;
unsigned char pkgid[16];
unsigned char *ctar;
Solvable *s;
struct stat stb;
- if (!(flags & REPO_REUSE_REPODATA))
- data = repo_add_repodata(repo, 0);
- else
- data = repo_last_repodata(repo);
- for (i = 0; i < ndebs; i++)
+ data = repo_add_repodata(repo, flags);
+ if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, deb) : deb, "r")) == 0)
{
- if ((fp = fopen(debs[i], "r")) == 0)
- {
- perror(debs[i]);
- continue;
- }
- if (fstat(fileno(fp), &stb))
- {
- perror("stat");
- continue;
- }
- l = fread(buf, 1, sizeof(buf), fp);
- if (l < 8 + 60 || strncmp((char *)buf, "!<arch>\ndebian-binary ", 8 + 16) != 0)
- {
- fprintf(stderr, "%s: not a deb package\n", debs[i]);
- fclose(fp);
- continue;
- }
- vlen = atoi((char *)buf + 8 + 48);
- if (vlen < 0 || vlen > l)
- {
- fprintf(stderr, "%s: not a deb package\n", debs[i]);
- fclose(fp);
- continue;
- }
- vlen += vlen & 1;
- if (l < 8 + 60 + vlen + 60)
- {
- fprintf(stderr, "%s: unhandled deb package\n", debs[i]);
- fclose(fp);
- continue;
- }
- if (strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz ", 16) != 0)
- {
- fprintf(stderr, "%s: control.tar.gz is not second entry\n", debs[i]);
- fclose(fp);
- continue;
- }
- clen = atoi((char *)buf + 8 + 60 + vlen + 48);
- if (clen <= 0)
- {
- fprintf(stderr, "%s: control.tar.gz has illegal size\n", debs[i]);
- fclose(fp);
- continue;
- }
- ctgz = sat_calloc(1, clen + 4);
- bp = buf + 8 + 60 + vlen + 60;
- l -= 8 + 60 + vlen + 60;
- if (l > clen)
- l = clen;
- if (l)
- memcpy(ctgz, bp, l);
- if (l < clen)
- {
- if (fread(ctgz + l, clen - l, 1, fp) != 1)
- {
- fprintf(stderr, "%s: unexpected EOF\n", debs[i]);
- sat_free(ctgz);
- fclose(fp);
- continue;
- }
- }
+ pool_error(pool, -1, "%s: %s", deb, strerror(errno));
+ return 0;
+ }
+ if (fstat(fileno(fp), &stb))
+ {
+ pool_error(pool, -1, "fstat: %s", strerror(errno));
fclose(fp);
- gotpkgid = 0;
- if (flags & DEBS_ADD_WITH_PKGID)
- {
- void *handle = sat_chksum_create(REPOKEY_TYPE_MD5);
- sat_chksum_add(handle, ctgz, clen);
- sat_chksum_free(handle, pkgid);
- gotpkgid = 1;
- }
- if (ctgz[0] != 0x1f || ctgz[1] != 0x8b)
- {
- fprintf(stderr, "%s: control.tar.gz is not gzipped\n", debs[i]);
- sat_free(ctgz);
- continue;
- }
- if (ctgz[2] != 8 || (ctgz[3] & 0xe0) != 0)
- {
- fprintf(stderr, "%s: control.tar.gz is compressed in a strange way\n", debs[i]);
- sat_free(ctgz);
- continue;
- }
- bp = ctgz + 4;
- bp += 6; /* skip time, xflags and OS code */
- if (ctgz[3] & 0x04)
+ return 0;
+ }
+ l = fread(buf, 1, sizeof(buf), fp);
+ if (l < 8 + 60 || strncmp((char *)buf, "!<arch>\ndebian-binary ", 8 + 16) != 0)
+ {
+ pool_error(pool, -1, "%s: not a deb package", deb);
+ fclose(fp);
+ return 0;
+ }
+ vlen = atoi((char *)buf + 8 + 48);
+ if (vlen < 0 || vlen > l)
+ {
+ pool_error(pool, -1, "%s: not a deb package", deb);
+ fclose(fp);
+ return 0;
+ }
+ vlen += vlen & 1;
+ if (l < 8 + 60 + vlen + 60)
+ {
+ pool_error(pool, -1, "%s: unhandled deb package", deb);
+ fclose(fp);
+ return 0;
+ }
+ if (strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz ", 16) != 0)
+ {
+ pool_error(pool, -1, "%s: control.tar.gz is not second entry", deb);
+ fclose(fp);
+ return 0;
+ }
+ clen = atoi((char *)buf + 8 + 60 + vlen + 48);
+ if (clen <= 0 || clen >= 0x100000)
+ {
+ pool_error(pool, -1, "%s: control.tar.gz has illegal size", deb);
+ fclose(fp);
+ return 0;
+ }
+ ctgz = solv_calloc(1, clen + 4);
+ bp = buf + 8 + 60 + vlen + 60;
+ l -= 8 + 60 + vlen + 60;
+ if (l > clen)
+ l = clen;
+ if (l)
+ memcpy(ctgz, bp, l);
+ if (l < clen)
+ {
+ if (fread(ctgz + l, clen - l, 1, fp) != 1)
{
- /* skip extra field */
- l = bp[0] | bp[1] << 8;
- bp += l + 2;
- if (bp >= ctgz + clen)
- {
- fprintf(stderr, "%s: corrupt gzip\n", debs[i]);
- sat_free(ctgz);
- continue;
- }
+ pool_error(pool, -1, "%s: unexpected EOF", deb);
+ solv_free(ctgz);
+ fclose(fp);
+ return 0;
}
- if (ctgz[3] & 0x08) /* orig filename */
- while (*bp)
- bp++;
- if (ctgz[3] & 0x10) /* file comment */
- while (*bp)
- bp++;
- if (ctgz[3] & 0x02) /* header crc */
- bp += 2;
+ }
+ fclose(fp);
+ gotpkgid = 0;
+ if (flags & DEBS_ADD_WITH_PKGID)
+ {
+ Chksum *chk = solv_chksum_create(REPOKEY_TYPE_MD5);
+ solv_chksum_add(chk, ctgz, clen);
+ solv_chksum_free(chk, pkgid);
+ gotpkgid = 1;
+ }
+ if (ctgz[0] != 0x1f || ctgz[1] != 0x8b)
+ {
+ pool_error(pool, -1, "%s: control.tar.gz is not gzipped", deb);
+ solv_free(ctgz);
+ return 0;
+ }
+ if (ctgz[2] != 8 || (ctgz[3] & 0xe0) != 0)
+ {
+ pool_error(pool, -1, "%s: control.tar.gz is compressed in a strange way", deb);
+ solv_free(ctgz);
+ return 0;
+ }
+ bp = ctgz + 4;
+ bp += 6; /* skip time, xflags and OS code */
+ if (ctgz[3] & 0x04)
+ {
+ /* skip extra field */
+ l = bp[0] | bp[1] << 8;
+ bp += l + 2;
if (bp >= ctgz + clen)
{
- fprintf(stderr, "%s: corrupt control.tar.gz\n", debs[i]);
- sat_free(ctgz);
- continue;
- }
- ctar = decompress(bp, ctgz + clen - bp, &ctarlen);
- sat_free(ctgz);
- if (!ctar)
- {
- fprintf(stderr, "%s: corrupt control.tar.gz\n", debs[i]);
- continue;
- }
- bp = ctar;
- l = ctarlen;
- while (l > 512)
- {
- int j;
- l2 = 0;
- for (j = 124; j < 124 + 12; j++)
- if (bp[j] >= '0' && bp[j] <= '7')
- l2 = l2 * 8 + (bp[j] - '0');
- if (!strcmp((char *)bp, "./control"))
- break;
- l2 = 512 + ((l2 + 511) & ~511);
- l -= l2;
- bp += l2;
- }
- if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0)
- {
- fprintf(stderr, "%s: control.tar.gz contains no ./control file\n", debs[i]);
- free(ctar);
- continue;
+ pool_error(pool, -1, "%s: control.tar.gz is corrupt", deb);
+ solv_free(ctgz);
+ return 0;
}
- memmove(ctar, bp + 512, l2);
- ctar = sat_realloc(ctar, l2 + 1);
- ctar[l2] = 0;
- s = pool_id2solvable(pool, repo_add_solvable(repo));
- control2solvable(s, data, (char *)ctar);
- repodata_set_location(data, s - pool->solvables, 0, 0, debs[i]);
- if (S_ISREG(stb.st_mode))
- repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned int)((stb.st_size + 1023) / 1024));
- if (gotpkgid)
- repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
- sat_free(ctar);
}
+ if (ctgz[3] & 0x08) /* orig filename */
+ while (*bp)
+ bp++;
+ if (ctgz[3] & 0x10) /* file comment */
+ while (*bp)
+ bp++;
+ if (ctgz[3] & 0x02) /* header crc */
+ bp += 2;
+ if (bp >= ctgz + clen)
+ {
+ pool_error(pool, -1, "%s: control.tar.gz is corrupt", deb);
+ solv_free(ctgz);
+ return 0;
+ }
+ ctar = decompress(bp, ctgz + clen - bp, &ctarlen);
+ solv_free(ctgz);
+ if (!ctar)
+ {
+ pool_error(pool, -1, "%s: control.tar.gz is corrupt", deb);
+ return 0;
+ }
+ bp = ctar;
+ l = ctarlen;
+ while (l > 512)
+ {
+ int j;
+ l2 = 0;
+ for (j = 124; j < 124 + 12; j++)
+ if (bp[j] >= '0' && bp[j] <= '7')
+ l2 = l2 * 8 + (bp[j] - '0');
+ if (!strcmp((char *)bp, "./control") || !strcmp((char *)bp, "control"))
+ break;
+ l2 = 512 + ((l2 + 511) & ~511);
+ l -= l2;
+ bp += l2;
+ }
+ if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0)
+ {
+ pool_error(pool, -1, "%s: control.tar.gz contains no control file", deb);
+ free(ctar);
+ return 0;
+ }
+ memmove(ctar, bp + 512, l2);
+ ctar = solv_realloc(ctar, l2 + 1);
+ ctar[l2] = 0;
+ s = pool_id2solvable(pool, repo_add_solvable(repo));
+ control2solvable(s, data, (char *)ctar);
+ if (!(flags & REPO_NO_LOCATION))
+ repodata_set_location(data, s - pool->solvables, 0, 0, deb);
+ if (S_ISREG(stb.st_mode))
+ repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
+ if (gotpkgid)
+ repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
+ solv_free(ctar);
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
+ return s - pool->solvables;
}