2 * Copyright (c) 2009, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
15 #ifdef ENABLE_ZLIB_COMPRESSION
18 #ifdef ENABLE_LZMA_COMPRESSION
21 #ifdef ENABLE_ZSTD_COMPRESSION
28 #include "solver.h" /* for GET_USERINSTALLED_ flags */
36 #if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
37 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
40 #define MAX_CONTROL_SIZE 0x1000000
42 #ifdef ENABLE_ZLIB_COMPRESSION
44 static unsigned char *
45 decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
49 unsigned char *bp, *out;
51 /* first skip the gz header */
52 if (inl <= 10 || in[0] != 0x1f || in[1] != 0x8b)
54 if (in[2] != 8 || (in[3] & 0xe0) != 0)
57 bp += 6; /* skip time, xflags and OS code */
60 /* skip extra field */
61 int l = bp + 2 >= in + inl ? 0 : (bp[0] | bp[1] << 8);
64 if (in[3] & 0x08) /* orig filename */
65 while (bp < in + inl && *bp++)
67 if (in[3] & 0x10) /* file comment */
68 while (bp < in + inl && *bp++)
70 if (in[3] & 0x02) /* header crc */
77 memset(&strm, 0, sizeof(strm));
80 out = solv_malloc(4096);
82 strm.avail_out = 4096;
84 ret = inflateInit2(&strm, -MAX_WBITS);
92 if (strm.avail_out == 0)
101 out = solv_realloc(out, outl + 4096);
102 strm.next_out = out + outl;
103 strm.avail_out = 4096;
105 ret = inflate(&strm, Z_NO_FLUSH);
106 if (ret == Z_STREAM_END)
115 outl += 4096 - strm.avail_out;
123 static unsigned char *
124 decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
129 #endif /* ENABLE_ZLIB_COMPRESSION */
131 #ifdef ENABLE_LZMA_COMPRESSION
133 static unsigned char *
134 decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
136 static lzma_stream stream_init = LZMA_STREAM_INIT;
144 out = solv_malloc(4096);
146 strm.avail_out = 4096;
148 ret = lzma_auto_decoder(&strm, 100 << 20, 0);
156 if (strm.avail_out == 0)
165 out = solv_realloc(out, outl + 4096);
166 strm.next_out = out + outl;
167 strm.avail_out = 4096;
169 ret = lzma_code(&strm, LZMA_RUN);
170 if (ret == LZMA_STREAM_END)
179 outl += 4096 - strm.avail_out;
187 static unsigned char *
188 decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
193 #endif /* ENABLE_LZMA_COMPRESSION */
195 #ifdef ENABLE_ZSTD_COMPRESSION
197 static unsigned char *
198 decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl)
200 ZSTD_DStream *dstream;
202 ZSTD_outBuffer outbuf;
205 dstream = ZSTD_createDStream();
208 if (ZSTD_isError(ZSTD_initDStream(dstream)))
210 ZSTD_freeDStream(dstream);
216 outbuf.dst = solv_malloc(4096);
221 if (outbuf.pos == outbuf.size)
224 if (outbuf.size >= maxoutl)
229 outbuf.dst = solv_realloc(outbuf.dst, outbuf.size + 4096);
231 ret = ZSTD_decompressStream(dstream, &outbuf, &inbuf);
232 if (ret == 0 && inbuf.pos == inbuf.size)
234 if (ZSTD_isError(ret) || (inbuf.pos == inbuf.size && outbuf.pos < outbuf.size))
240 ZSTD_freeDStream(dstream);
243 solv_free(outbuf.dst);
252 static unsigned char *
253 decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl)
258 #endif /* ENABLE_ZSTD_COMPRESSION */
261 parseonedep(Pool *pool, char *p)
263 char *n, *ne, *e, *ee;
267 while (*p == ' ' || *p == '\t' || *p == '\n')
269 if (!*p || *p == '(')
272 /* find end of name */
273 while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '(' && *p != '|')
276 while (*p == ' ' || *p == '\t' || *p == '\n')
284 while (*p == ' ' || *p == '\t' || *p == '\n')
305 while (*p == ' ' || *p == '\t' || *p == '\n')
308 while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != ')')
311 while (*p && *p != ')')
315 while (*p == ' ' || *p == '\t' || *p == '\n')
318 if (ne - n > 4 && ne[-4] == ':' && !strncmp(ne - 4, ":any", 4))
320 /* multiarch annotation */
321 name = pool_strn2id(pool, n, ne - n - 4, 1);
322 name = pool_rel2id(pool, name, ARCH_ANY, REL_MULTIARCH, 1);
325 name = pool_strn2id(pool, n, ne - n, 1);
328 evr = pool_strn2id(pool, e, ee - e, 1);
329 name = pool_rel2id(pool, name, evr, flags, 1);
333 Id id = parseonedep(pool, p + 1);
335 name = pool_rel2id(pool, name, id, REL_OR, 1);
341 makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
343 Pool *pool = repo->pool;
347 while ((p = strchr(deps, ',')) != 0)
350 olddeps = makedeps(repo, deps, olddeps, marker);
354 id = parseonedep(pool, deps);
357 return repo_addid_dep(repo, olddeps, id, marker);
361 /* put data from control file into the solvable */
362 /* warning: does inplace changes */
364 control2solvable(Solvable *s, Repodata *data, char *control)
366 Repo *repo = s->repo;
367 Pool *pool = repo->pool;
368 char *p, *q, *end, *tag;
371 char checksum[32 * 2 + 1];
381 if (p[1] == ' ' || p[1] == '\t')
384 /* continuation line */
386 while (q >= control && *q == ' ' && *q == '\t')
390 memmove(p + 1 - l, control, l);
399 /* strip trailing space */
400 while (end >= control && (*end == ' ' || *end == '\t'))
404 q = strchr(tag, ':');
405 if (!q || q - tag < 4)
408 while (*q == ' ' || *q == '\t')
410 x = '@' + (tag[0] & 0x1f);
411 x = (x << 8) + '@' + (tag[1] & 0x1f);
415 if (!strcasecmp(tag, "architecture"))
416 s->arch = pool_str2id(pool, q, 1);
419 if (!strcasecmp(tag, "breaks"))
420 s->conflicts = makedeps(repo, q, s->conflicts, 0);
423 if (!strcasecmp(tag, "conflicts"))
424 s->conflicts = makedeps(repo, q, s->conflicts, 0);
427 if (!strcasecmp(tag, "depends"))
428 s->requires = makedeps(repo, q, s->requires, -SOLVABLE_PREREQMARKER);
429 else if (!strcasecmp(tag, "description"))
431 char *ld = strchr(q, '\n');
435 repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, ld);
438 repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, q);
439 repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, q);
443 if (!strcasecmp(tag, "enhances"))
444 s->enhances = makedeps(repo, q, s->enhances, 0);
447 if (!strcasecmp(tag, "filename"))
448 repodata_set_location(data, s - pool->solvables, 0, 0, q);
451 if (!strcasecmp(tag, "homepage"))
452 repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, q);
455 if (!strcasecmp(tag, "installed-size"))
456 repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(q, 0, 10) << 10);
459 if (!strcasecmp(tag, "md5sum") && !checksumtype && strlen(q) == 16 * 2)
462 checksumtype = REPOKEY_TYPE_MD5;
466 if (!strcasecmp(tag, "multi-arch"))
467 repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_MULTIARCH, q);
470 if (!strcasecmp(tag, "package"))
471 s->name = pool_str2id(pool, q, 1);
474 if (!strcasecmp(tag, "pre-depends"))
475 s->requires = makedeps(repo, q, s->requires, SOLVABLE_PREREQMARKER);
476 else if (!strcasecmp(tag, "provides"))
477 s->provides = makedeps(repo, q, s->provides, 0);
480 if (!strcasecmp(tag, "replaces"))
481 s->obsoletes = makedeps(repo, q, s->obsoletes, 0);
482 else if (!strcasecmp(tag, "recommends"))
483 s->recommends = makedeps(repo, q, s->recommends, 0);
486 newtype = solv_chksum_str2type(tag);
487 if (!newtype || solv_chksum_len(newtype) * 2 != strlen(q))
489 if (!checksumtype || (newtype == REPOKEY_TYPE_SHA1 && checksumtype != REPOKEY_TYPE_SHA256) || newtype == REPOKEY_TYPE_SHA256)
492 checksumtype = newtype;
496 if (!strcasecmp(tag, "source"))
499 /* ignore version for now */
500 for (q2 = q; *q2; q2++)
501 if (*q2 == ' ' || *q2 == '\t')
506 if (s->name && !strcmp(q, pool_id2str(pool, s->name)))
507 repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
509 repodata_set_id(data, s - pool->solvables, SOLVABLE_SOURCENAME, pool_str2id(pool, q, 1));
514 if (!strcasecmp(tag, "status"))
515 repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_INSTALLSTATUS, q);
518 if (!strcasecmp(tag, "suggests"))
519 s->suggests = makedeps(repo, q, s->suggests, 0);
522 if (!strcasecmp(tag, "version"))
523 s->evr = pool_str2id(pool, q, 1);
528 repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, checksumtype, checksum);
534 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
535 if (s->name && !havesource)
536 repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
539 /* obsoletes only count when the packages also conflict */
540 /* XXX: should not transcode here */
543 for (i = j = s->obsoletes; (d = repo->idarraydata[i]) != 0; i++)
547 for (k = s->conflicts; (cid = repo->idarraydata[k]) != 0; k++)
549 if (repo->idarraydata[k] == cid)
553 Reldep *rd = GETRELDEP(pool, cid);
554 if (rd->flags < 8 && rd->name == d)
555 break; /* specialize obsoletes */
559 repo->idarraydata[j++] = cid;
561 repo->idarraydata[j] = 0;
562 if (j == s->obsoletes)
568 repo_add_debpackages(Repo *repo, FILE *fp, int flags)
570 Pool *pool = repo->pool;
576 data = repo_add_repodata(repo, flags);
577 buf = solv_malloc(4096);
584 if (!(p = strchr(p, '\n')))
587 while (l + 1024 >= bufl)
589 buf = solv_realloc(buf, bufl + 4096);
593 ll = fread(p, 1, bufl - l - 1, fp);
597 while ((l3 = strlen(p)) < ll)
609 s = pool_id2solvable(pool, repo_add_solvable(repo));
610 control2solvable(s, data, buf);
612 s = solvable_free(s, 1);
614 memmove(buf, p + 1, l - ll);
621 s = pool_id2solvable(pool, repo_add_solvable(repo));
622 control2solvable(s, data, buf);
624 s = solvable_free(s, 1);
627 if (!(flags & REPO_NO_INTERNALIZE))
628 repodata_internalize(data);
633 repo_add_debdb(Repo *repo, int flags)
636 const char *path = "/var/lib/dpkg/status";
637 if (flags & REPO_USE_ROOTDIR)
638 path = pool_prepend_rootdir_tmp(repo->pool, path);
639 if ((fp = fopen(path, "r")) == 0)
640 return pool_error(repo->pool, -1, "%s: %s", path, strerror(errno));
641 repo_add_debpackages(repo, fp, flags);
646 #define CONTROL_COMP_NONE 0
647 #define CONTROL_COMP_GZIP 1
648 #define CONTROL_COMP_XZ 2
649 #define CONTROL_COMP_ZSTD 3
652 repo_add_deb(Repo *repo, const char *deb, int flags)
654 Pool *pool = repo->pool;
656 unsigned char buf[4096], *bp;
657 int l, l2, vlen, clen, ctarlen;
660 unsigned char pkgid[16];
667 data = repo_add_repodata(repo, flags);
668 if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, deb) : deb, "r")) == 0)
670 pool_error(pool, -1, "%s: %s", deb, strerror(errno));
673 if (fstat(fileno(fp), &stb))
675 pool_error(pool, -1, "fstat: %s", strerror(errno));
679 l = fread(buf, 1, sizeof(buf), fp);
680 if (l < 8 + 60 || (strncmp((char *)buf, "!<arch>\ndebian-binary ", 8 + 16) != 0 && strncmp((char *)buf, "!<arch>\ndebian-binary/ ", 8 + 16) != 0))
682 pool_error(pool, -1, "%s: not a deb package", deb);
686 vlen = atoi((char *)buf + 8 + 48);
687 if (vlen < 0 || vlen > l)
689 pool_error(pool, -1, "%s: not a deb package", deb);
694 if (l < 8 + 60 + vlen + 60)
696 pool_error(pool, -1, "%s: unhandled deb package", deb);
701 if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz/ ", 16))
702 control_comp = CONTROL_COMP_GZIP;
703 else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz/ ", 16))
704 control_comp = CONTROL_COMP_XZ;
705 else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst/", 16))
706 control_comp = CONTROL_COMP_ZSTD;
707 else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar/ ", 16))
708 control_comp = CONTROL_COMP_NONE;
711 pool_error(pool, -1, "%s: control.tar is not second entry", deb);
715 /* dpkg has no actual maximum size for the control.tar member, so this
716 * just keeps from allocating arbitrarily large amounts of memory.
718 clen = atoi((char *)buf + 8 + 60 + vlen + 48);
719 if (clen <= 0 || clen >= MAX_CONTROL_SIZE)
721 pool_error(pool, -1, "%s: control.tar has illegal size", deb);
725 ctgz = solv_calloc(1, clen + 4);
726 bp = buf + 8 + 60 + vlen + 60;
727 l -= 8 + 60 + vlen + 60;
734 if (fread(ctgz + l, clen - l, 1, fp) != 1)
736 pool_error(pool, -1, "%s: unexpected EOF", deb);
744 if (flags & DEBS_ADD_WITH_PKGID)
746 Chksum *chk = solv_chksum_create(REPOKEY_TYPE_MD5);
747 solv_chksum_add(chk, ctgz, clen);
748 solv_chksum_free(chk, pkgid);
752 if (control_comp == CONTROL_COMP_GZIP)
753 ctar = decompress_gz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
754 else if (control_comp == CONTROL_COMP_XZ)
755 ctar = decompress_xz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
756 else if (control_comp == CONTROL_COMP_ZSTD)
757 ctar = decompress_zstd(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
761 ctar = solv_memdup(ctgz, clen);
766 pool_error(pool, -1, "%s: control.tar decompression error", deb);
776 for (j = 124; j < 124 + 12; j++)
777 if (bp[j] >= '0' && bp[j] <= '7')
778 l2 = l2 * 8 + (bp[j] - '0');
779 if (l2 < 0 || l2 > l)
785 if (!strcmp((char *)bp, "./control") || !strcmp((char *)bp, "control"))
787 l2 = 512 + ((l2 + 511) & ~511);
791 if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0)
793 pool_error(pool, -1, "%s: control.tar contains no control file", deb);
797 memmove(ctar, bp + 512, l2);
798 ctar = solv_realloc(ctar, l2 + 1);
800 s = pool_id2solvable(pool, repo_add_solvable(repo));
801 control2solvable(s, data, (char *)ctar);
802 if (!(flags & REPO_NO_LOCATION))
803 repodata_set_location(data, s - pool->solvables, 0, 0, deb);
804 if (S_ISREG(stb.st_mode))
805 repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
807 repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
809 if (!(flags & REPO_NO_INTERNALIZE))
810 repodata_internalize(data);
811 return s - pool->solvables;
815 pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags)
817 Id name = 0, arch = 0;
818 int autoinstalled = -1;
820 int x, l, bufl, eof = 0;
824 buf = solv_malloc(4096);
829 while (bufl - l < 1024)
832 if (bufl > 1024 * 64)
834 buf = solv_realloc(buf, bufl);
836 if (!fgets(buf + l, bufl - l, fp))
843 if (l && buf[l - 1] == '\n')
848 if (name && autoinstalled > 0)
850 if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
851 queue_push2(q, name, arch);
852 else if ((flags & GET_USERINSTALLED_NAMES) != 0)
856 FOR_PROVIDES(p, pp, name)
858 Solvable *s = pool->solvables + p;
861 if (arch && s->arch != arch)
871 /* strip trailing space */
872 while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t'))
876 bp = strchr(buf, ':');
877 if (!bp || bp - buf < 4)
880 while (*bp == ' ' || *bp == '\t')
882 x = '@' + (buf[0] & 0x1f);
883 x = (x << 8) + '@' + (buf[1] & 0x1f);
887 if (!strcasecmp(buf, "package"))
888 name = pool_str2id(pool, bp, 1);
891 if (!strcasecmp(buf, "architecture"))
892 arch = pool_str2id(pool, bp, 1);
895 if (!strcasecmp(buf, "auto-installed"))
896 autoinstalled = atoi(bp);