9 #define MULTI_SEMANTICS
17 #include "repo_solv.h"
18 #include "repo_write.h"
19 #include "repo_rpmdb.h"
22 #include "repo_arch.h"
25 typedef struct _Expander {
51 typedef Pool *BSSolv__pool;
52 typedef Repo *BSSolv__repo;
53 typedef Expander *BSSolv__expander;
55 static Id buildservice_id;
56 static Id buildservice_repocookie;
57 static Id buildservice_external;
58 static Id buildservice_dodurl;
59 static Id expander_directdepsend;
60 static Id buildservice_dodcookie;
62 /* make sure bit n is usable */
63 #define MAPEXP(m, n) ((m)->size < (((n) + 8) >> 3) ? map_grow(m, n + 256) : 0)
65 #define REPOCOOKIE "buildservice repo 1.1"
68 myrepowritefilter(Repo *repo, Repokey *key, void *kfdata)
71 if (key->name == SOLVABLE_URL)
72 return KEY_STORAGE_DROPPED;
73 if (key->name == SOLVABLE_HEADEREND)
74 return KEY_STORAGE_DROPPED;
75 if (key->name == SOLVABLE_PACKAGER)
76 return KEY_STORAGE_DROPPED;
77 if (key->name == SOLVABLE_GROUP)
78 return KEY_STORAGE_DROPPED;
79 if (key->name == SOLVABLE_LICENSE)
80 return KEY_STORAGE_DROPPED;
81 if (key->name == SOLVABLE_PKGID)
82 return KEY_STORAGE_INCORE;
83 if (key->name == SOLVABLE_CHECKSUM)
84 return KEY_STORAGE_INCORE;
85 i = repo_write_stdkeyfilter(repo, key, kfdata);
86 if (i == KEY_STORAGE_VERTICAL_OFFSET)
87 return KEY_STORAGE_DROPPED;
92 hvlookupstr(HV *hv, const char *key, int keyl)
94 SV **svp = hv_fetch(hv, key, keyl, 0);
97 return SvPV_nolen(*svp);
101 hvlookupav(HV *hv, const char *key, int keyl)
103 SV *sv, **svp = hv_fetch(hv, key, keyl, 0);
107 if (!sv || !SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV)
109 return (AV *)SvRV(sv);
113 makeevr(Pool *pool, char *e, char *v, char *r)
119 if (e && !strcmp(e, "0"))
122 s = pool_tmpjoin(pool, e, ":", v);
126 s = pool_tmpjoin(pool, s, "-", r);
127 return pool_str2id(pool, s, 1);
131 avlookupstr(AV *av, int n)
133 SV **svp = av_fetch(av, n, 0);
136 return SvPV_nolen(*svp);
140 id2name(Pool *pool, Id id)
144 Reldep *rd = GETRELDEP(pool, id);
151 dep2id(Pool *pool, char *s)
157 if ((n = strchr(s, '|')) != 0)
159 id = dep2id(pool, n + 1);
161 id = pool_rel2id(pool, dep2id(pool, s), id, REL_OR, 1);
165 while (*s == ' ' || *s == '\t')
168 while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>')
171 if (s - n > 4 && s[-4] == ':' && !strncmp(s - 4, ":any", 4))
173 id = pool_strn2id(pool, n, s - n - 4, 1);
174 id = pool_rel2id(pool, id, ARCH_ANY, REL_MULTIARCH, 1);
178 id = pool_strn2id(pool, n, s - n, 1);
181 while (*s == ' ' || *s == '\t')
197 while (*s == ' ' || *s == '\t')
200 while (*s && *s != ' ' && *s != '\t')
202 return pool_rel2id(pool, id, pool_strn2id(pool, n, s - n, 1), flags, 1);
206 importdeps(HV *hv, const char *key, int keyl, Repo *repo)
208 Pool *pool = repo->pool;
210 AV *av = hvlookupav(hv, key, keyl);
214 for (i = 0; i <= av_len(av); i++)
216 char *str = avlookupstr(av, i);
218 off = repo_addid_dep(repo, off, dep2id(pool, str), 0);
225 exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey)
227 Pool *pool = repo->pool;
232 if (!off || !repo->idarraydata[off])
234 pp = repo->idarraydata + off;
238 if (id == SOLVABLE_FILEMARKER)
240 str = pool_dep2str(pool, id);
243 Reldep *rd = GETRELDEP(pool, id);
244 if (skey == SOLVABLE_CONFLICTS && rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
246 if (!strncmp(str, "namespace:", 10))
249 if (skey == SOLVABLE_SUPPLEMENTS)
251 if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_FILESYSTEM)
253 if (!strncmp(str, "namespace:", 10))
256 else if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_MODALIAS)
258 if (!strncmp(str, "namespace:", 10))
261 else if (rd->flags == REL_AND)
263 /* either packageand chain or modalias */
265 if (ISRELDEP(rd->evr))
267 Reldep *mrd = GETRELDEP(pool, rd->evr);
268 if (mrd->flags == REL_NAMESPACE && mrd->name == NAMESPACE_MODALIAS)
270 str = pool_tmpjoin(pool, "modalias(", pool_dep2str(pool, rd->name), ":");
271 str = pool_tmpappend(pool, str, pool_dep2str(pool, mrd->evr), ")");
273 else if (mrd->flags >= 8)
278 /* must be and chain */
279 str = pool_dep2str(pool, rd->evr);
285 rd = GETRELDEP(pool, id);
286 if (rd->flags != REL_AND)
288 str = pool_tmpjoin(pool, pool_dep2str(pool, rd->evr), ":", str);
290 str = pool_tmpjoin(pool, pool_dep2str(pool, id), ":", str);
291 str = pool_tmpjoin(pool, "packageand(", str, ")");
294 else if (rd->flags >= 8)
298 if (skey == SOLVABLE_REQUIRES)
300 if (id == SOLVABLE_PREREQMARKER)
302 if (*str == 'r' && !strncmp(str, "rpmlib(", 7))
307 av_push(av, newSVpv(str, 0));
310 (void)hv_store(hv, key, keyl, newRV_noinc((SV*)av), 0);
314 data2solvables(Repo *repo, Repodata *data, HV *rhv)
316 Pool *pool = repo->pool;
325 while ((sv = hv_iternextsv(rhv, &key, &keyl)) != 0)
327 if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV)
330 str = hvlookupstr(hv, "name", 4);
332 continue; /* need to have a name */
333 p = repo_add_solvable(repo);
334 s = pool_id2solvable(pool, p);
335 s->name = pool_str2id(pool, str, 1);
336 str = hvlookupstr(hv, "arch", 4);
338 str = ""; /* dummy, need to have arch */
339 s->arch = pool_str2id(pool, str, 1);
340 s->evr = makeevr(pool, hvlookupstr(hv, "epoch", 5), hvlookupstr(hv, "version", 7), hvlookupstr(hv, "release", 7));
341 str = hvlookupstr(hv, "path", 4);
344 char *ss = strrchr(str, '/');
348 repodata_set_str(data, p, SOLVABLE_MEDIADIR, str);
353 repodata_set_str(data, p, SOLVABLE_MEDIAFILE, ss);
355 str = hvlookupstr(hv, "id", 2);
357 repodata_set_str(data, p, buildservice_id, str);
358 str = hvlookupstr(hv, "source", 6);
360 repodata_set_poolstr(data, p, SOLVABLE_SOURCENAME, str);
361 str = hvlookupstr(hv, "hdrmd5", 6);
362 if (str && strlen(str) == 32)
363 repodata_set_checksum(data, p, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, str);
364 s->provides = importdeps(hv, "provides", 8, repo);
365 s->obsoletes = importdeps(hv, "obsoletes", 9, repo);
366 s->conflicts = importdeps(hv, "conflicts", 9, repo);
367 s->requires = importdeps(hv, "requires", 8, repo);
368 s->recommends = importdeps(hv, "recommends", 10, repo);
369 s->suggests = importdeps(hv, "suggests", 8, repo);
370 s->supplements = importdeps(hv, "supplements", 11, repo);
371 s->enhances = importdeps(hv, "enhances", 8, repo);
372 if (!s->evr && s->provides)
374 /* look for self provides */
375 Id pro, *prop = s->repo->idarraydata + s->provides;
376 while ((pro = *prop++) != 0)
381 rd = GETRELDEP(pool, pro);
382 if (rd->name == s->name && rd->flags == REL_EQ)
387 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
388 str = hvlookupstr(hv, "checksum", 8);
391 char *cp, typebuf[8];
393 if (*str != ':' && (cp = strchr(str, ':')) != 0 && cp - str < sizeof(typebuf))
395 strncpy(typebuf, str, cp - str);
396 typebuf[cp - str] = 0;
397 ctype = solv_chksum_str2type(typebuf);
399 repodata_set_checksum(data, p, SOLVABLE_CHECKSUM, ctype, cp + 1);
404 repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
405 str = hvlookupstr(rhv, "/url", 4);
407 repodata_set_str(data, SOLVID_META, buildservice_dodurl, str);
408 str = hvlookupstr(rhv, "/dodcookie", 10);
410 repodata_set_str(data, SOLVID_META, buildservice_dodcookie, str);
414 retrieve(unsigned char **srcp, STRLEN *srclp, int depth)
419 unsigned char *src = *srcp;
420 STRLEN srcl = *srclp;
435 size = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3];
440 sv = NEWSV(10002, size);
441 sv_setpvn(sv, (char *)src, size);
448 len = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3];
456 for (i = 0; i < len; i++)
458 sv = retrieve(&src, &srcl, depth + 1);
461 if (av_store(av, i, sv) == 0)
469 len = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3];
476 hv_ksplit(hv, len + 1);
477 for (i = 0; i < len; i++)
479 sv = retrieve(&src, &srcl, depth + 1);
484 size = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3];
489 if (hv_store(hv, (char *)src, (U32)size, sv, 0) == 0)
497 rv = NEWSV(10002, 0);
498 sv = retrieve(&src, &srcl, depth + 1);
501 sv_upgrade(rv, SVt_RV);
512 sv = NEWSV(10002, size);
513 sv_setpvn(sv, (char *)src, size);
518 /* fprintf(stderr, "unknown tag %d\n", type); */
527 expander_dbg(Expander *xp, const char *format, ...)
534 va_start(args, format);
535 vsnprintf(buf, sizeof(buf), format, args);
539 if (buf[0] != ' ' || (l && buf[l - 1] == '\n'))
541 if (l >= xp->debugstrf) /* >= because of trailing \0 */
543 xp->debugstr = solv_realloc(xp->debugstr, xp->debugstrl + l + 1024);
544 xp->debugstrf = l + 1024;
546 strcpy(xp->debugstr + xp->debugstrl, buf);
552 expander_solvid2name(Expander *xp, Id p)
554 const char *n = pool_id2str(xp->pool, xp->pool->solvables[p].name);
558 r = xp->pool->solvables[p].repo;
561 return pool_tmpjoin(xp->pool, n, "@", r->name);
565 expander_installed(Expander *xp, Id p, Map *installed, Map *conflicts, Queue *conflictsinfo, int *cidone, Queue *out, Queue *todo)
567 Pool *pool = xp->pool;
568 Solvable *s = pool->solvables + p;
569 Id req, id, *reqp, con, *conp;
572 MAPSET(installed, p);
574 if (MAPTST(&xp->conflicts, s->name))
577 for (i = 0; i < xp->conflictsq.count; i++)
580 Id id = xp->conflictsq.elements[i];
583 id = xp->conflictsq.elements[i ^ 1];
584 FOR_PROVIDES(p2, pp2, id)
586 if (pool->solvables[p2].name == id)
588 MAPEXP(conflicts, pool->nsolvables);
589 MAPSET(conflicts, p2);
596 reqp = s->repo->idarraydata + s->requires;
597 while ((req = *reqp++) != 0)
599 if (req == SOLVABLE_PREREQMARKER)
601 id = id2name(pool, req);
602 if (!xp->ignoreignore)
604 if (MAPTST(&xp->ignored, id))
606 if (MAPTST(&xp->ignoredx, id))
608 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, s->name), ":", pool_id2str(pool, id)), 0);
609 if (xid && MAPTST(&xp->ignored, xid))
613 n = pool_id2str(pool, id);
614 if (!strncmp(n, "rpmlib(", 7))
616 MAPEXP(&xp->ignored, id);
617 MAPSET(&xp->ignored, id);
622 if (!xp->havefileprovides || pool->whatprovides[id] <= 1)
624 MAPEXP(&xp->ignored, id);
625 MAPSET(&xp->ignored, id);
629 queue_push2(todo, req, p);
632 if (!xp->ignoreconflicts)
636 conp = s->repo->idarraydata + s->conflicts;
637 while ((con = *conp++) != 0)
640 FOR_PROVIDES(p2, pp2, con)
644 MAPEXP(conflicts, pool->nsolvables);
645 MAPSET(conflicts, p2);
647 queue_push2(conflictsinfo, p2, p);
653 conp = s->repo->idarraydata + s->obsoletes;
654 while ((con = *conp++) != 0)
657 FOR_PROVIDES(p2, pp2, con)
659 if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con))
661 MAPEXP(conflicts, pool->nsolvables);
662 MAPSET(conflicts, p2);
664 queue_push2(conflictsinfo, p2, -p);
669 *cidone = out->count;
674 expander_checkconflicts(Expander *xp, Id p, Map *installed, Id *conflicts, int isobsoletes)
676 Pool *pool = xp->pool;
679 if (xp->ignoreconflicts)
681 while ((con = *conflicts++) != 0)
683 FOR_PROVIDES(p2, pp2, con)
687 if (isobsoletes && !pool_match_nevr(pool, pool->solvables + p2, con))
689 if (MAPTST(installed, p2))
697 expander_updateconflictsinfo(Expander *xp, Queue *conflictsinfo, int *cidone, Queue *out)
699 Pool *pool = xp->pool;
701 if (xp->ignoreconflicts)
703 for (i = *cidone; i < out->count; i++)
708 p = out->elements[i];
709 s = pool->solvables + p;
710 /* keep in sync with expander_installed! */
713 conp = s->repo->idarraydata + s->conflicts;
714 while ((con = *conp++) != 0)
716 FOR_PROVIDES(p2, pp2, con)
720 queue_push2(conflictsinfo, p2, p);
726 conp = s->repo->idarraydata + s->obsoletes;
727 while ((con = *conp++) != 0)
729 FOR_PROVIDES(p2, pp2, con)
731 if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con))
733 queue_push2(conflictsinfo, p2, -p);
738 *cidone = out->count;
742 findconflictsinfo(Queue *conflictsinfo, Id p)
746 for (i = 0; i < conflictsinfo->count; i++)
747 if (conflictsinfo->elements[i] == p)
748 return conflictsinfo->elements[i + 1];
752 #define ERROR_NOPROVIDER 1
753 #define ERROR_CHOICE 2
754 #define ERROR_CONFLICTINGPROVIDER 3
755 #define ERROR_CONFLICTINGPROVIDERS 4
756 #define ERROR_PROVIDERINFO 5
757 #define ERROR_PROVIDERINFO2 6
761 expander_expand(Expander *xp, Queue *in, Queue *out, Queue *inconfl)
763 Pool *pool = xp->pool;
764 Queue todo, errors, cerrors, qq, posfoundq;
771 int i, j, nerrors, doamb, ambcnt;
772 Id id, who, whon, pn;
773 Id conflprov, conflprovpc;
775 map_init(&installed, pool->nsolvables);
776 map_init(&conflicts, 0);
777 queue_init(&conflictsinfo);
781 queue_init(&cerrors);
782 queue_init(&posfoundq);
789 for (i = 0; i < inconfl->count; i += 2)
791 Id con = inconfl->elements[i];
792 FOR_PROVIDES(p, pp, con)
794 if (inconfl->elements[i + 1] && !pool_match_nevr(pool, pool->solvables + p, con))
796 MAPEXP(&conflicts, pool->nsolvables);
797 MAPSET(&conflicts, p);
801 /* do direct expands */
802 for (i = 0; i < in->count; i++)
804 id = in->elements[i];
805 if (id == expander_directdepsend)
807 for (i = i + 1; i < in->count; i++)
808 if (in->elements[i] != expander_directdepsend)
809 queue_push2(&todo, in->elements[i], 0);
813 FOR_PROVIDES(p, pp, id)
815 s = pool->solvables + p;
816 if (!pool_match_nevr(pool, s, id))
827 /* unclear, resolve later */
828 queue_push2(&todo, id, 0);
831 if (MAPTST(&installed, q))
833 if (conflicts.size && MAPTST(&conflicts, q))
835 queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
836 queue_push2(&errors, id, 0);
837 if (cidone < out->count)
838 expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
839 queue_push(&errors, ERROR_PROVIDERINFO2);
840 queue_push2(&errors, q, findconflictsinfo(&conflictsinfo, q));
843 if (pool->solvables[q].conflicts && (pp = expander_checkconflicts(xp, q, &installed, pool->solvables[q].repo->idarraydata + pool->solvables[q].conflicts, 0)) != 0)
845 queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
846 queue_push2(&errors, id, 0);
847 queue_push(&errors, ERROR_PROVIDERINFO);
848 queue_push2(&errors, q, pp);
851 if (pool->solvables[q].obsoletes && (pp = expander_checkconflicts(xp, q, &installed, pool->solvables[q].repo->idarraydata + pool->solvables[q].obsoletes, 1)) != 0)
853 queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
854 queue_push2(&errors, id, 0);
855 queue_push(&errors, ERROR_PROVIDERINFO);
856 queue_push2(&errors, q, -pp);
860 expander_dbg(xp, "added %s because of %s (direct dep)\n", expander_solvid2name(xp, q), pool_dep2str(pool, id));
861 expander_installed(xp, q, &installed, &conflicts, &conflictsinfo, &cidone, out, &todo); /* unique match! */
868 id = queue_shift(&todo);
869 who = queue_shift(&todo);
873 break; /* amb pass had no progress, stop */
875 expander_dbg(xp, "now doing undecided dependencies\n");
876 doamb = 1; /* start amb pass */
881 // printf("todo %s %s ambcnt %d\n", pool_id2str(pool, pool->solvables[who].name), pool_dep2str(pool, id), ambcnt);
883 whon = who ? pool->solvables[who].name : 0;
887 FOR_PROVIDES(p, pp, id)
890 if (MAPTST(&installed, p))
892 if (who && !xp->ignoreignore)
894 Id pn = pool->solvables[p].name;
895 if (MAPTST(&xp->ignored, pn))
897 if (MAPTST(&xp->ignoredx, pn))
899 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
900 if (xid && MAPTST(&xp->ignored, xid))
904 if (conflicts.size && MAPTST(&conflicts, p))
908 Id pc = findconflictsinfo(&conflictsinfo, p);
910 expander_dbg(xp, "ignoring provider %s of %s because installed %s %s it\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc > 0 ? pc : -pc), pc > 0 ? "conflicts with" : "obsoletes");
912 expander_dbg(xp, "ignoring conflicted provider %s of %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id));
914 conflprov = conflprov ? 1 : p;
918 if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0)) != 0)
920 expander_dbg(xp, "ignoring provider %s of %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc));
921 conflprov = conflprov ? 1 : p;
925 if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1)) != 0)
927 expander_dbg(xp, "ignoring provider %s of %s because it obsoletes installed %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc));
928 conflprov = conflprov ? 1 : p;
940 queue_push(&errors, ERROR_NOPROVIDER);
941 queue_push2(&errors, id, who);
944 /* more work for conflicts */
947 /* nice, just one provider */
948 queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
949 queue_push2(&errors, id, who);
952 if (cidone < out->count)
953 expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
954 conflprovpc = findconflictsinfo(&conflictsinfo, conflprov);
955 queue_push(&errors, ERROR_PROVIDERINFO2);
956 queue_push2(&errors, conflprov, conflprovpc);
960 queue_push(&errors, ERROR_PROVIDERINFO);
961 queue_push2(&errors, conflprov, conflprovpc);
965 /* even more work if all providers conflict */
966 queue_push(&errors, ERROR_CONFLICTINGPROVIDERS);
967 queue_push2(&errors, id, who);
968 if (cidone < out->count)
969 expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
970 FOR_PROVIDES(p, pp, id)
973 if (conflicts.size && MAPTST(&conflicts, p))
975 pc = findconflictsinfo(&conflictsinfo, p);
976 queue_push(&errors, ERROR_PROVIDERINFO2);
977 queue_push2(&errors, p, pc);
980 if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0)) != 0)
982 queue_push(&errors, ERROR_PROVIDERINFO);
983 queue_push2(&errors, p, pc);
986 if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1)) != 0)
988 queue_push(&errors, ERROR_PROVIDERINFO);
989 queue_push2(&errors, p, -pc);
995 if (qq.count > 1 && !doamb)
997 /* try again later */
998 queue_push2(&todo, id, who);
1001 expander_dbg(xp, "undecided about %s:%s:", whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
1002 for (i = 0; i < qq.count; i++)
1003 expander_dbg(xp, " %s", expander_solvid2name(xp, qq.elements[i]));
1004 expander_dbg(xp, "\n");
1009 /* prune neg prefers */
1012 for (i = j = 0; i < qq.count; i++)
1015 pn = pool->solvables[p].name;
1016 if (MAPTST(&xp->preferneg, pn))
1018 if (who && MAPTST(&xp->prefernegx, pn))
1020 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
1021 if (xid && MAPTST(&xp->preferneg, xid))
1024 qq.elements[j++] = p;
1027 queue_truncate(&qq, j);
1030 /* prune pos prefers */
1033 queue_empty(&posfoundq);
1034 for (i = j = 0; i < qq.count; i++)
1037 pn = pool->solvables[p].name;
1038 if (MAPTST(&xp->preferpos, pn))
1040 queue_push2(&posfoundq, pn, p);
1041 qq.elements[j++] = p;
1044 if (who && MAPTST(&xp->preferposx, pn))
1046 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
1047 if (xid && MAPTST(&xp->preferpos, xid))
1049 queue_push2(&posfoundq, xid, p);
1050 qq.elements[j++] = p;
1055 if (posfoundq.count == 2)
1058 queue_push(&qq, posfoundq.elements[1]);
1060 else if (posfoundq.count)
1062 /* found a pos prefer, now find first hit */
1063 /* (prefers are ordered) */
1064 for (i = 0; i < xp->preferposq.count; i++)
1066 Id xid = xp->preferposq.elements[i];
1067 for (j = 0; j < posfoundq.count; j += 2)
1068 if (posfoundq.elements[j] == xid)
1070 if (j < posfoundq.count)
1073 queue_push(&qq, posfoundq.elements[j + 1]);
1081 if (qq.count > 1 && ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_OR)
1089 rd = GETRELDEP(pool, rid);
1090 if (rd->flags != REL_OR)
1096 FOR_PROVIDES(p, pp, rid)
1108 queue_push(&cerrors, ERROR_CHOICE);
1109 queue_push2(&cerrors, id, who);
1110 for (i = 0; i < qq.count; i++)
1111 queue_push(&cerrors, qq.elements[i]);
1112 queue_push(&cerrors, 0);
1113 /* try again later */
1114 queue_push2(&todo, id, who);
1118 expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, qq.elements[0]), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
1119 expander_installed(xp, qq.elements[0], &installed, &conflicts, &conflictsinfo, &cidone, out, &todo);
1121 ambcnt = todo.count;
1122 queue_empty(&cerrors);
1124 map_free(&installed);
1125 map_free(&conflicts);
1126 queue_free(&conflictsinfo);
1128 if (errors.count || cerrors.count)
1131 for (i = 0; i < errors.count; i += 3)
1133 queue_push(out, errors.elements[i]);
1134 queue_push(out, errors.elements[i + 1]);
1135 queue_push(out, errors.elements[i + 2]);
1138 for (i = 0; i < cerrors.count; )
1140 queue_push(out, cerrors.elements[i]);
1141 queue_push(out, cerrors.elements[i + 1]);
1142 queue_push(out, cerrors.elements[i + 2]);
1144 while (cerrors.elements[i])
1146 queue_push(out, cerrors.elements[i]);
1158 fprintf(stderr, "Internal expansion error!\n");
1160 queue_push(out, ERROR_NOPROVIDER);
1167 queue_free(&errors);
1168 queue_free(&cerrors);
1169 queue_free(&posfoundq);
1174 set_disttype(Pool *pool, int disttype)
1176 pool_setdisttype(pool, disttype);
1177 #ifdef POOL_FLAG_HAVEDISTEPOCH
1178 /* make newer mandriva work, hopefully there are no ill effects... */
1179 pool_set_flag(pool, POOL_FLAG_HAVEDISTEPOCH, disttype == DISTTYPE_RPM ? 1 : 0);
1184 set_disttype_from_location(Pool *pool, Solvable *so)
1186 unsigned int medianr;
1187 const char *s = solvable_get_location(so, &medianr);
1193 if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".rpm"))
1194 disttype = DISTTYPE_RPM;
1196 if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".deb"))
1197 disttype = DISTTYPE_DEB;
1199 #ifdef DISTTYPE_ARCH
1200 if (disttype < 0 && sl >= 11 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz")))
1201 disttype = DISTTYPE_ARCH;
1203 if (disttype >= 0 && pool->disttype != disttype)
1204 set_disttype(pool, disttype);
1208 create_considered(Pool *pool, Repo *repoonly, Map *considered)
1214 int olddisttype = -1;
1217 map_init(considered, pool->nsolvables);
1218 best = solv_calloc(sizeof(Id), pool->ss.nstrings);
1220 FOR_REPOS(ridx, repo)
1222 if (repoonly && repo != repoonly)
1224 dodrepo = repo_lookup_str(repo, SOLVID_META, buildservice_dodurl) != 0;
1225 FOR_REPO_SOLVABLES(repo, p, s)
1227 if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
1232 sb = pool->solvables + pb;
1233 if (s->repo != sb->repo)
1234 continue; /* first repo wins */
1235 if (s->arch != sb->arch)
1238 if (s->arch == ARCH_NOARCH || s->arch == ARCH_ALL || s->arch == ARCH_ANY)
1240 if (sb->arch != ARCH_NOARCH && sb->arch != ARCH_ALL && sb->arch != ARCH_ANY)
1242 /* the strcmp is kind of silly, but works for most archs */
1243 r = strcmp(pool_id2str(pool, sb->arch), pool_id2str(pool, s->arch));
1248 else if (s->evr != sb->evr)
1250 /* same repo, check versions */
1252 if (olddisttype < 0)
1254 olddisttype = pool->disttype;
1255 set_disttype_from_location(pool, s);
1257 r = pool_evrcmp(pool, sb->evr, s->evr, EVRCMP_COMPARE);
1262 r = strcmp(pool_id2str(pool, sb->evr), pool_id2str(pool, s->evr));
1270 /* we only consider dod packages */
1271 const char *bsid = solvable_lookup_str(s, buildservice_id);
1272 if (!bsid || strcmp(bsid, "dod") != 0)
1276 MAPCLR(considered, pb);
1278 MAPSET(considered, p);
1280 /* dodrepos have a second pass: replace dod entries with downloaded ones */
1284 FOR_REPO_SOLVABLES(repo, p, s)
1286 if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
1291 sb = pool->solvables + pb;
1292 if (sb->repo != s->repo || sb->name != s->name || sb->arch != s->arch || sb->evr != s->evr)
1294 bsid = solvable_lookup_str(s, buildservice_id);
1295 if (bsid && strcmp(bsid, "dod") == 0)
1296 continue; /* not downloaded */
1297 MAPCLR(considered, pb);
1299 MAPSET(considered, p);
1304 if (olddisttype >= 0 && pool->disttype != olddisttype)
1305 set_disttype(pool, olddisttype);
1315 static int metacmp(const void *ap, const void *bp)
1317 const struct metaline *a, *b;
1322 r = a->nslash - b->nslash;
1325 r = strcmp(a->l + 34, b->l + 34);
1328 r = strcmp(a->l, b->l);
1334 #ifndef REPO_NO_LOCATION
1335 # define REPO_NO_LOCATION 0
1339 repodata_addbin(Repodata *data, char *prefix, char *s, int sl, char *sid)
1343 #if REPO_NO_LOCATION == 0
1347 path = solv_dupjoin(prefix, "/", s);
1348 if (sl >= 4 && !strcmp(s + sl - 4, ".rpm"))
1349 p = repo_add_rpm(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|RPM_ADD_WITH_PKGID|RPM_ADD_NO_FILELIST|RPM_ADD_NO_RPMLIBREQS);
1350 else if (sl >= 4 && !strcmp(s + sl - 4, ".deb"))
1351 p = repo_add_deb(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|DEBS_ADD_WITH_PKGID);
1352 #ifdef ARCH_ADD_WITH_PKGID
1353 else if (sl >= 11 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz")))
1354 p = repo_add_arch_pkg(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|ARCH_ADD_WITH_PKGID);
1359 #if REPO_NO_LOCATION != 0
1360 repodata_set_location(data, p, 0, 0, s);
1362 if ((sp = strrchr(s, '/')) != 0)
1365 repodata_set_str(data, p, SOLVABLE_MEDIADIR, s);
1369 repodata_delete_uninternalized(data, p, SOLVABLE_MEDIADIR);
1371 repodata_set_str(data, p, buildservice_id, sid);
1376 subpack_sort_cmp(const void *ap, const void *bp, void *dp)
1378 Pool *pool = (Pool *)dp;
1381 int r = a[1] - b[1];
1384 r = strcmp(pool_id2str(pool, a[0]), pool_id2str(pool, b[0]));
1385 return r ? r : a[0] - b[0];
1388 /* This is an OpenSSL-compatible implementation of the RSA Data Security,
1389 * Inc. MD5 Message-Digest Algorithm.
1391 * Written by Solar Designer <solar@openwall.com> in 2001, and placed in
1392 * the public domain. */
1394 #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
1395 #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
1396 #define H(x, y, z) ((x) ^ (y) ^ (z))
1397 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
1399 #define STEP(f, a, b, c, d, x, t, s) \
1400 (a) += f((b), (c), (d)) + (x) + (t); \
1401 (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
1404 #if defined(__i386__) || defined(__vax__)
1406 (*(MD5_u32plus *)&ptr[(n) * 4])
1411 (ctx->block[(n)] = \
1412 (MD5_u32plus)ptr[(n) * 4] | \
1413 ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
1414 ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
1415 ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
1420 typedef unsigned long MD5_u32plus;
1424 MD5_u32plus a, b, c, d;
1425 unsigned char buffer[64];
1426 MD5_u32plus block[16];
1430 * This processes one or more 64-byte data blocks, but does NOT update
1431 * the bit counters. There're no alignment requirements.
1433 static void *md5_body(MD5_CTX *ctx, void *data, unsigned long size)
1436 MD5_u32plus a, b, c, d;
1437 MD5_u32plus saved_a, saved_b, saved_c, saved_d;
1453 STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
1454 STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
1455 STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
1456 STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
1457 STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
1458 STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
1459 STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
1460 STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
1461 STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
1462 STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
1463 STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
1464 STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
1465 STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
1466 STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
1467 STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
1468 STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
1471 STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
1472 STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
1473 STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
1474 STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
1475 STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
1476 STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
1477 STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
1478 STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
1479 STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
1480 STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
1481 STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
1482 STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
1483 STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
1484 STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
1485 STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
1486 STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
1489 STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
1490 STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
1491 STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
1492 STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
1493 STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
1494 STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
1495 STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
1496 STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
1497 STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
1498 STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
1499 STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
1500 STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
1501 STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
1502 STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
1503 STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
1504 STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
1507 STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
1508 STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
1509 STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
1510 STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
1511 STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
1512 STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
1513 STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
1514 STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
1515 STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
1516 STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
1517 STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
1518 STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
1519 STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
1520 STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
1521 STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
1522 STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
1530 } while (size -= 64);
1540 static void md5_init(MD5_CTX *ctx)
1542 ctx->a = 0x67452301;
1543 ctx->b = 0xefcdab89;
1544 ctx->c = 0x98badcfe;
1545 ctx->d = 0x10325476;
1550 static void md5_update(MD5_CTX *ctx, void *data, unsigned long size)
1552 MD5_u32plus saved_lo;
1553 unsigned long used, free;
1556 if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
1558 ctx->hi += size >> 29;
1560 used = saved_lo & 0x3f;
1566 memcpy(&ctx->buffer[used], data, size);
1570 memcpy(&ctx->buffer[used], data, free);
1571 data = (unsigned char *)data + free;
1573 md5_body(ctx, ctx->buffer, 64);
1577 data = md5_body(ctx, data, size & ~(unsigned long)0x3f);
1581 memcpy(ctx->buffer, data, size);
1584 static void md5_final(MD5_CTX *ctx, unsigned char *result)
1586 unsigned long used, free;
1587 used = ctx->lo & 0x3f;
1588 ctx->buffer[used++] = 0x80;
1591 memset(&ctx->buffer[used], 0, free);
1592 md5_body(ctx, ctx->buffer, 64);
1596 memset(&ctx->buffer[used], 0, free - 8);
1598 ctx->buffer[56] = ctx->lo;
1599 ctx->buffer[57] = ctx->lo >> 8;
1600 ctx->buffer[58] = ctx->lo >> 16;
1601 ctx->buffer[59] = ctx->lo >> 24;
1602 ctx->buffer[60] = ctx->hi;
1603 ctx->buffer[61] = ctx->hi >> 8;
1604 ctx->buffer[62] = ctx->hi >> 16;
1605 ctx->buffer[63] = ctx->hi >> 24;
1606 md5_body(ctx, ctx->buffer, 64);
1608 result[1] = ctx->a >> 8;
1609 result[2] = ctx->a >> 16;
1610 result[3] = ctx->a >> 24;
1612 result[5] = ctx->b >> 8;
1613 result[6] = ctx->b >> 16;
1614 result[7] = ctx->b >> 24;
1616 result[9] = ctx->c >> 8;
1617 result[10] = ctx->c >> 16;
1618 result[11] = ctx->c >> 24;
1619 result[12] = ctx->d;
1620 result[13] = ctx->d >> 8;
1621 result[14] = ctx->d >> 16;
1622 result[15] = ctx->d >> 24;
1623 memset(ctx, 0, sizeof(*ctx));
1626 static unsigned int buz_noise[256] =
1628 0x9be502a4U, 0xba7180eaU, 0x324e474fU, 0x0aab8451U, 0x0ced3810U,
1629 0x2158a968U, 0x6bbd3771U, 0x75a02529U, 0x41f05c14U, 0xc2264b87U,
1630 0x1f67b359U, 0xcd2d031dU, 0x49dc0c04U, 0xa04ae45cU, 0x6ade28a7U,
1631 0x2d0254ffU, 0xdec60c7cU, 0xdef5c084U, 0x0f77ffc8U, 0x112021f6U,
1632 0x5f6d581eU, 0xe35ea3dfU, 0x3216bfb4U, 0xd5a3083dU, 0x7e63e9cdU,
1633 0xaa9208f6U, 0xda3f3978U, 0xfe0e2547U, 0x09dfb020U, 0xd97472c5U,
1634 0xbbce2edeU, 0x121aebd2U, 0x0e9fdbebU, 0x7b6f5d9cU, 0x84938e43U,
1635 0x30694f2dU, 0x86b7a7f8U, 0xefaf5876U, 0x263812e6U, 0xb6e48ddfU,
1636 0xce8ed980U, 0x4df591e1U, 0x75257b35U, 0x2f88dcffU, 0xa461fe44U,
1637 0xca613b4dU, 0xd9803f73U, 0xea056205U, 0xccca7a89U, 0x0f2dbb07U,
1638 0xc53e359eU, 0xe80d0137U, 0x2b2d2a5dU, 0xcfc1391aU, 0x2bb3b6c5U,
1639 0xb66aea3cU, 0x00ea419eU, 0xce5ada84U, 0xae1d6712U, 0x12f576baU,
1640 0x117fcbc4U, 0xa9d4c775U, 0x25b3d616U, 0xefda65a8U, 0xaff3ef5bU,
1641 0x00627e68U, 0x668d1e99U, 0x088d0eefU, 0xf8fac24dU, 0xe77457c7U,
1642 0x68d3beb4U, 0x921d2acbU, 0x9410eac9U, 0xd7f24399U, 0xcbdec497U,
1643 0x98c99ae1U, 0x65802b2cU, 0x81e1c3c4U, 0xa130bb09U, 0x17a87badU,
1644 0xa70367d6U, 0x148658d4U, 0x02f33377U, 0x8620d8b6U, 0xbdac25bdU,
1645 0xb0a6de51U, 0xd64c4571U, 0xa4185ba0U, 0xa342d70fU, 0x3f1dc4c1U,
1646 0x042dc3ceU, 0x0de89f43U, 0xa69b1867U, 0x3c064e11U, 0xad1e2c3eU,
1647 0x9660e8cdU, 0xd36b09caU, 0x4888f228U, 0x61a9ac3cU, 0xd9561118U,
1648 0x3532797eU, 0x71a35c22U, 0xecc1376cU, 0xab31e656U, 0x88bd0d35U,
1649 0x423b20ddU, 0x38e4651cU, 0x3c6397a4U, 0x4a7b12d9U, 0x08b1cf33U,
1650 0xd0604137U, 0xb035fdb8U, 0x4916da23U, 0xa9349493U, 0xd83daa9bU,
1651 0x145f7d95U, 0x868531d6U, 0xacb18f17U, 0x9cd33b6fU, 0x193e42b9U,
1652 0x26dfdc42U, 0x5069d8faU, 0x5bee24eeU, 0x5475d4c6U, 0x315b2c0cU,
1653 0xf764ef45U, 0x01b6f4ebU, 0x60ba3225U, 0x8a16777cU, 0x4c05cd28U,
1654 0x53e8c1d2U, 0xc8a76ce5U, 0x8045c1e6U, 0x61328752U, 0x2ebad322U,
1655 0x3444f3e2U, 0x91b8af11U, 0xb0cee675U, 0x55dbff5aU, 0xf7061ee0U,
1656 0x27d7d639U, 0xa4aef8c9U, 0x42ff0e4fU, 0x62755468U, 0x1c6ca3f3U,
1657 0xe4f522d1U, 0x2765fcb3U, 0xe20c8a95U, 0x3a69aea7U, 0x56ab2c4fU,
1658 0x8551e688U, 0xe0bc14c2U, 0x278676bfU, 0x893b6102U, 0xb4f0ab3bU,
1659 0xb55ddda9U, 0xa04c521fU, 0xc980088eU, 0x912aeac1U, 0x08519badU,
1660 0x991302d3U, 0x5b91a25bU, 0x696d9854U, 0x9ad8b4bfU, 0x41cb7e21U,
1661 0xa65d1e03U, 0x85791d29U, 0x89478aa7U, 0x4581e337U, 0x59bae0b1U,
1662 0xe0fc9df3U, 0x45d9002cU, 0x7837464fU, 0xda22de3aU, 0x1dc544bdU,
1663 0x601d8badU, 0x668b0abcU, 0x7a5ebfb1U, 0x3ac0b624U, 0x5ee16d7dU,
1664 0x9bfac387U, 0xbe8ef20cU, 0x8d2ae384U, 0x819dc7d5U, 0x7c4951e7U,
1665 0xe60da716U, 0x0c5b0073U, 0xb43b3d97U, 0xce9974edU, 0x0f691da9U,
1666 0x4b616d60U, 0x8fa9e819U, 0x3f390333U, 0x6f62fad6U, 0x5a32b67cU,
1667 0x3be6f1c3U, 0x05851103U, 0xff28828dU, 0xaa43a56aU, 0x075d7dd5U,
1668 0x248c4b7eU, 0x52fde3ebU, 0xf72e2edaU, 0x5da6f75fU, 0x2f5148d9U,
1669 0xcae2aeaeU, 0xfda6f3e5U, 0xff60d8ffU, 0x2adc02d2U, 0x1dbdbd4cU,
1670 0xd410ad7cU, 0x8c284aaeU, 0x392ef8e0U, 0x37d48b3aU, 0x6792fe9dU,
1671 0xad32ddfaU, 0x1545f24eU, 0x3a260f73U, 0xb724ca36U, 0xc510d751U,
1672 0x4f8df992U, 0x000b8b37U, 0x292e9b3dU, 0xa32f250fU, 0x8263d144U,
1673 0xfcae0516U, 0x1eae2183U, 0xd4af2027U, 0xc64afae3U, 0xe7b34fe4U,
1674 0xdf864aeaU, 0x80cc71c5U, 0x0e814df3U, 0x66cc5f41U, 0x853a497aU,
1675 0xa2886213U, 0x5e34a2eaU, 0x0f53ba47U, 0x718c484aU, 0xfa0f0b12U,
1676 0x33cc59ffU, 0x72b48e07U, 0x8b6f57bcU, 0x29cf886dU, 0x1950955bU,
1677 0xcd52910cU, 0x4cecef65U, 0x05c2cbfeU, 0x49df4f6aU, 0x1f4c3f34U,
1678 0xfadc1a09U, 0xf2d65a24U, 0x117f5594U, 0xde3a84e6U, 0x48db3024U,
1684 * our delta search blocksize
1686 * smaller gives more hits, but increases the hash size
1688 * must be a multiple of 256
1689 * must be in range [256,32767]
1691 #define DELTA_BSIZE 1024
1693 /* min store block len, smaller blocks are encoded as direct data */
1694 #define MIN_BSIZE 32
1696 /* min meta block len, must be >= 10 */
1697 #define MIN_BSIZE_META 32
1699 /* max meta block len, must be <= DELTA_BSIZE */
1700 #define MAX_BSIZE_META DELTA_BSIZE
1702 /* number of slots per data area */
1703 #define SLOTS_PER_AREA 4095
1706 /* buzhash by Robert C. Uzgalis */
1707 /* General hash functions. Technical Report TR-92-01, The University
1708 of Hong Kong, 1993 */
1710 static unsigned int buzhash(unsigned char *buf)
1712 unsigned int x = 0x83d31df4U;
1714 for (i = DELTA_BSIZE ; i != 0; i--)
1715 x = (x << 1) ^ (x & (1 << 31) ? 1 : 0) ^ buz_noise[*buf++];
1719 static void md5block(unsigned char *buf, int len, unsigned char *out)
1723 md5_update(&ctx, buf, (unsigned long)len);
1724 md5_final(&ctx, out);
1727 #define HASHCHAIN_START 7
1728 #define HASHCHAIN_NEXT(h, hh, mask) (((h) + (hh)++) & (mask))
1732 int fd; /* file descriptor */
1733 int rdonly; /* store is read only */
1735 unsigned long long end; /* store file size */
1737 unsigned long long *offsets; /* the data areas we know about */
1740 unsigned char *hash; /* our hash */
1741 unsigned int hm; /* size of hash */
1742 unsigned int hf; /* hash fill */
1743 unsigned int hd; /* entries not in hash */
1745 int freecnt; /* free slots in last slot area */
1746 int usedcnt; /* used slots in last slot area */
1747 unsigned long long slotsoffset; /* offset of last slot area */
1752 struct deltastore *store;
1754 /* for block coalescence */
1755 unsigned long long oldoffset;
1756 unsigned long long oldsize;
1758 /* for offset encoding */
1759 unsigned long long lastoffset;
1761 /* for meta block creation */
1762 int outbuf_do_meta; /* create meta blocks */
1763 unsigned char outbuf[MAX_BSIZE_META + 16]; /* 16 extra bytes for one encoded block */
1765 /* offset patching */
1766 unsigned long long outbuf_startoffset;
1767 int outbuf_startoffset_set;
1768 int outbuf_set_len1;
1769 int outbuf_set_len2;
1770 unsigned long long outbuf_set_offset; /* offset we need to patch in, already encoded */
1773 static inline unsigned long long getu48(unsigned char *d)
1775 unsigned long long x = d[0] << 8 | d[1];
1776 return (x << 32) | (d[2] << 24 | d[3] << 16 | d[4] << 8 | d[5]);
1779 static inline void putu48(unsigned char *d, unsigned long long x)
1789 static inline unsigned int getu32(unsigned char *d)
1791 return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
1794 static inline void putu32(unsigned char *d, unsigned int x)
1807 finddataarea(struct deltastore *store, unsigned long long offset)
1810 for (i = 0; i < store->noffsets; i += 2)
1811 if (offset >= store->offsets[i] && offset < store->offsets[i + 1])
1817 adddataarea(struct deltastore *store, unsigned long long start, unsigned long long end)
1819 unsigned long long *newoffsets;
1820 if (store->noffsets && store->offsets[store->noffsets - 1] == start)
1822 store->offsets[store->noffsets - 1] = end;
1826 newoffsets = realloc(store->offsets, (store->noffsets + 2) * sizeof(unsigned long long));
1828 newoffsets = malloc((store->noffsets + 2) * sizeof(unsigned long long));
1831 newoffsets[store->noffsets++] = start;
1832 newoffsets[store->noffsets++] = end;
1833 store->offsets = newoffsets;
1837 addslotarea(struct deltastore *store, int cnt)
1839 unsigned char *slots;
1840 if (!cnt || cnt > 65535)
1844 if ((store->end & 4095) != 0) /* pad to multiple of 4096 */
1847 int l = 4096 - (store->end & 4095);
1849 if (pwrite(store->fd, pad, l, store->end) != l)
1851 perror("pwrite pad next slotsarea");
1856 if (store->end + (cnt + 1) * 16 >= (1LL << 48))
1857 return 0; /* store too big! */
1858 slots = calloc(cnt + 1, 16);
1861 memcpy(slots, "OBSDELT", 8);
1862 slots[8] = cnt >> 8;
1864 /* write pointer to next slot area */
1867 putu48(slots + 10, store->end);
1868 if (pwrite(store->fd, slots, 16, store->slotsoffset) != 16)
1870 perror("pwrite update next slotsarea");
1874 memset(slots + 10, 0, 6);
1876 if (pwrite(store->fd, slots, (cnt + 1) * 16, store->end) != (cnt + 1) * 16)
1878 perror("pwrite new slotarea");
1883 store->slotsoffset = store->end;
1884 store->end += (cnt + 1) * 16;
1885 store->freecnt = cnt;
1891 * add a new block to the store.
1892 * returns the store offset, 0 on error
1894 static unsigned long long
1895 putinstore(struct deltastore *store, unsigned char *buf, int size, unsigned char *md5, unsigned int hx)
1897 unsigned char md5buf[16];
1898 unsigned char hp[16];
1899 unsigned long long offset;
1901 unsigned char *hash;
1902 unsigned int h, hh, hm;
1904 if (!size || size > DELTA_BSIZE)
1909 if (store->freecnt == 0 && !addslotarea(store, SLOTS_PER_AREA))
1913 offset = store->end;
1914 if (offset + size >= (1LL << 48))
1915 return 0; /* store too big! */
1916 if (pwrite(store->fd, buf, size, store->end) != size)
1918 perror("pwrite data");
1921 adddataarea(store, store->end, store->end + size);
1927 md5block(buf, size, md5buf);
1932 putu48(hp + 2, offset);
1933 if (size == DELTA_BSIZE)
1938 memcpy(hp + 12, md5, 4);
1942 hp[0] |= 0x80; /* small block marker */
1943 memcpy(hp + 8, md5, 8);
1944 hx = getu32(hp + 8); /* needed later */
1950 for (j = 0; j < 16; j++)
1951 printf(" %02x", hp[j]);
1955 if (pwrite(store->fd, hp, 16, store->slotsoffset + (store->usedcnt + 1) * 16) != 16)
1957 perror("pwrite slot");
1967 hh = HASHCHAIN_START;
1968 while (hash[16 * h] != 0)
1969 h = HASHCHAIN_NEXT(h, hh, hm);
1970 memcpy(hash + 16 * h, hp, 16);
1975 /* make sure that we found the correct block */
1977 checkstore(struct deltastore *store, unsigned long long offset, unsigned char *buf, int size)
1979 unsigned char buf2[4096];
1982 int l = size > 4096 ? 4096 : size;
1983 if (pread(store->fd, buf2, l, offset) != l)
1985 if (memcmp(buf2, buf, l) != 0)
1995 * try to find a (non-rolling) block in the store. If not found, add it.
1996 * returns the store offset, 0 on error
1998 static unsigned long long
1999 reuse_or_add_block(struct deltastore *store, unsigned char *buf, int size)
2001 unsigned char md5[16];
2002 unsigned int h, hh, hm;
2003 unsigned char *hash;
2004 unsigned long long offset;
2006 if (!size || size >= DELTA_BSIZE)
2007 return 0; /* only small non-rolling blocks for now */
2008 md5block(buf, size, md5);
2011 h = (md5[0] << 24 | md5[1] << 16 | md5[2] << 8 | md5[3]) & hm;
2012 hh = HASHCHAIN_START;
2013 while (hash[16 * h] != 0)
2015 unsigned char *hp = hash + 16 * h;
2016 if (((hp[0] & 0x7f) << 8 | hp[1]) == size && !memcmp(hp + 8, md5, 8))
2018 offset = getu48(hp + 2);
2019 if (checkstore(store, offset, buf, size))
2022 h = HASHCHAIN_NEXT(h, hh, hm);
2024 return putinstore(store, buf, size, md5, 0);
2032 encodelonglong(FILE *ofp, unsigned long long x)
2034 unsigned long long z = 1;
2038 z = z << 7 | (x & 127);
2044 c = (z & 127) | 128;
2048 if (putc(c, ofp) == EOF)
2051 if (putc(c ^ 128, ofp) == EOF)
2057 encodelonglong_mem(unsigned char *bp, unsigned long long x)
2059 unsigned long long z = 1;
2064 z = z << 7 | (x & 127);
2070 c = (z & 127) | 128;
2083 /* fancy delta conversion, seems to work better than the simple xor */
2084 static inline unsigned long long
2085 encodeoffset(unsigned long long oldoffset, unsigned long long offset)
2087 if (oldoffset & (1LL << 47))
2089 offset ^= ((1LL << 48) - 1);
2090 oldoffset ^= ((1LL << 48) - 1);
2092 if (offset < oldoffset * 2)
2094 if (offset < oldoffset)
2095 offset = (oldoffset - offset - 1) << 1 | 1;
2097 offset = (offset - oldoffset) << 1;
2102 static inline unsigned long long
2103 decodeoffset(unsigned long long oldoffset, unsigned long long offset)
2105 int neg = oldoffset & (1LL << 47) ? ((1LL << 48) - 1) : 0;
2107 if (offset < oldoffset * 2)
2110 offset = oldoffset - ((offset >> 1) + 1);
2112 offset = oldoffset + (offset >> 1);
2114 return offset ^ neg;
2118 static inline unsigned long long
2119 encodeoffset(unsigned long long oldoffset, unsigned long long offset)
2121 return oldoffset ^ offset;
2124 static inline unsigned long long
2125 decodeoffset(unsigned long long oldoffset, unsigned long long offset)
2127 return oldoffset ^ offset;
2132 flushoutbuf(struct deltaout *out)
2134 if (!out->outbuf_len)
2136 if (out->outbuf_len >= MAX_BSIZE_META)
2139 if (out->outbuf_len >= MIN_BSIZE_META)
2141 /* put as meta block into store! */
2142 int size = out->outbuf_len;
2143 unsigned long long offset;
2145 printf("META size %d\n", out->outbuf_len);
2147 offset = reuse_or_add_block(out->store, out->outbuf, size);
2150 /* encode meta block into outbuf */
2151 if (out->outbuf_startoffset_set)
2152 out->lastoffset = out->outbuf_startoffset;
2153 out->outbuf[0] = 15; /* meta */
2154 out->outbuf_len = 1;
2155 out->outbuf_len += encodelonglong_mem(out->outbuf + out->outbuf_len, size);
2156 out->outbuf_len += encodelonglong_mem(out->outbuf + out->outbuf_len, encodeoffset(out->lastoffset, offset));
2157 out->lastoffset = offset + size;
2158 out->outbuf_startoffset_set = 0;
2161 if (out->outbuf_startoffset_set)
2163 /* tricky: fix up first offset! */
2164 unsigned char buf[9];
2165 int l = encodelonglong_mem(buf, out->outbuf_set_offset);
2166 if (fwrite(out->outbuf, out->outbuf_set_len1, 1, out->fp) != 1)
2168 if (fwrite(buf, l, 1, out->fp) != 1)
2170 if (out->outbuf_set_len2 < out->outbuf_len && fwrite(out->outbuf + out->outbuf_set_len2, out->outbuf_len - out->outbuf_set_len2, 1, out->fp) != 1)
2173 else if (fwrite(out->outbuf, out->outbuf_len, 1, out->fp) != 1)
2175 out->outbuf_len = 0;
2176 out->outbuf_startoffset_set = 0;
2181 encodestoreblock_real(struct deltaout *out, unsigned long long offset, unsigned long long size)
2184 printf("BLOCK %#llx %llu\n", offset, size);
2186 if (out->outbuf_do_meta)
2188 int lastlen = out->outbuf_len;
2189 /* the following code is needed as we want to use a lastoffset of
2190 * zero if this ends up in a meta instruction. So we encode with
2191 * lastoffset zero but also store the real lastoffset and byte offsets,
2192 * in order to fix up the offset in flushbuf */
2193 int set = out->outbuf_startoffset_set;
2196 out->outbuf_startoffset_set = 1;
2197 out->outbuf_startoffset = out->lastoffset;
2198 out->outbuf_set_offset = encodeoffset(out->lastoffset, offset);
2199 out->lastoffset = 0;
2201 out->outbuf_len += encodelonglong_mem(out->outbuf + out->outbuf_len, out->oldsize + 256);
2203 out->outbuf_set_len1 = out->outbuf_len;
2204 out->outbuf_len += encodelonglong_mem(out->outbuf + out->outbuf_len, encodeoffset(out->lastoffset, offset));
2206 out->outbuf_set_len2 = out->outbuf_len;
2208 if (out->outbuf_len >= DELTA_BSIZE)
2210 /* buffer too full. revert changes. flush outbuf. retry */
2211 out->outbuf_len = lastlen;
2214 out->outbuf_startoffset_set = 0;
2215 out->lastoffset = out->outbuf_startoffset;
2217 if (!flushoutbuf(out))
2219 return encodestoreblock_real(out, offset, size);
2224 if (!encodelonglong(out->fp, size + 256))
2226 if (!encodelonglong(out->fp, encodeoffset(out->lastoffset, offset)))
2229 out->lastoffset = offset + size;
2233 /* encode a store block instruction
2234 * we delay the real encoding so that we can join adjacent blocks
2237 encodestoreblock(struct deltaout *out, unsigned long long offset, unsigned long long size)
2241 if (out->oldoffset + out->oldsize == offset)
2243 out->oldsize += size;
2246 if (!encodestoreblock_real(out, out->oldoffset, out->oldsize))
2249 out->oldoffset = offset; /* block not yet written */
2250 out->oldsize = size;
2254 /* encode a direct data instruction
2257 encodedirect(struct deltaout *out, unsigned char *buf, int size)
2261 if (size >= 256 - 16)
2265 if (!encodestoreblock(out, 0, 0)) /* flush */
2269 printf("DIRECT %u\n", size);
2271 if (out->outbuf_do_meta)
2273 if (out->outbuf_len + 1 + size >= DELTA_BSIZE)
2275 /* buffer too full. flush outbuf */
2276 if (!flushoutbuf(out))
2279 out->outbuf[out->outbuf_len++] = 16 + size;
2280 memcpy(out->outbuf + out->outbuf_len, buf, size);
2281 out->outbuf_len += size;
2285 if (putc(16 + size, out->fp) == EOF)
2287 if (fwrite(buf, size, 1, out->fp) != 1)
2294 ** the delta algorithm
2297 static unsigned long long
2298 extendblock(struct deltastore *store, FILE *fp, unsigned long long offset, unsigned long long areaend, unsigned long long maxextend)
2300 unsigned char buf[1024];
2302 unsigned long long extend = 0;
2304 if (offset >= areaend)
2306 if (areaend - offset < maxextend)
2307 maxextend = areaend - offset;
2315 bufl = maxextend > 1024 ? 1024 : maxextend;
2318 if (pread(store->fd, buf, bufl, (off_t)offset) != bufl)
2336 static unsigned long long
2337 extendblock_back(struct deltastore *store, unsigned char *data, unsigned long long offset, unsigned long long areastart, unsigned long long maxextend)
2339 unsigned char buf[1024];
2340 unsigned long long extend = 0;
2343 if (offset <= areastart)
2345 if (offset - areastart < maxextend)
2346 maxextend = offset - areastart;
2354 bufl = maxextend > 1024 ? 1024 : maxextend;
2358 if (pread(store->fd, buf, bufl, (off_t)offset) != bufl)
2362 if (*--data != buf[--bufl])
2369 dosimple(struct deltastore *store, struct deltaout *out, unsigned char *buf, int size)
2371 unsigned long long offset;
2373 while (size >= DELTA_BSIZE)
2375 offset = putinstore(store, buf, DELTA_BSIZE, 0, 0);
2376 if (!offset || !encodestoreblock(out, offset, DELTA_BSIZE))
2378 size -= DELTA_BSIZE;
2381 if (size < MIN_BSIZE)
2382 return encodedirect(out, buf, size);
2383 offset = reuse_or_add_block(store, buf, size);
2386 return encodestoreblock(out, offset, size);
2390 dodelta(struct deltastore *store, FILE *fp, struct deltaout *out, unsigned long long size)
2392 unsigned char buf[DELTA_BSIZE * 16];
2393 unsigned char md5[16];
2394 unsigned long long offset, extendf, extendb;
2395 unsigned int h, hh, hm, hx;
2396 unsigned char *hash;
2400 printf("DODELTA\n");
2406 if (size < DELTA_BSIZE)
2408 if (fread(buf, (int)size, 1, fp) != 1)
2410 if (!dosimple(store, out, buf, (int)size))
2416 if (fread(buf, DELTA_BSIZE, 1, fp) != 1)
2418 size -= DELTA_BSIZE;
2427 /* check if the block at (buf + bi) is in the hash */
2429 if (hx != buzhash(buf + bi))
2432 hh = HASHCHAIN_START;
2433 for (h = hx & hm; hash[16 * h] != 0; h = HASHCHAIN_NEXT(h, hh, hm))
2435 unsigned char *hp = hash + 16 * h;
2436 /* first check block len */
2437 if (hp[0] != (DELTA_BSIZE >> 8) || hp[1] != (DELTA_BSIZE & 0xff))
2439 /* then check complete hash value */
2440 if (hp[8] != (hx >> 24))
2442 if ((hp[8] << 24 | hp[9] << 16 | hp[10] << 8 | hp[11]) != hx)
2444 /* then check strong hash */
2447 md5block(buf + bi, DELTA_BSIZE, md5);
2450 if (memcmp(hp + 12, md5, 4) != 0)
2452 /* looks good. check data */
2453 offset = getu48(hp + 2);
2454 if (!checkstore(store, offset, buf + bi, DELTA_BSIZE))
2456 /* yes! found block in store! */
2457 /* try to extend found block */
2458 c = finddataarea(store, offset);
2459 extendf = extendb = 0;
2462 extendf = extendblock(store, fp, offset + DELTA_BSIZE, store->offsets[c + 1], size);
2463 size -= extendf; /* extended bytes */
2464 extendb = extendblock_back(store, buf + bi, offset, store->offsets[c], bi);
2468 /* encode data before block */
2471 if (!dosimple(store, out, buf, bi))
2476 if (!encodestoreblock(out, offset, DELTA_BSIZE + extendf + extendb))
2484 /* not found. move block one byte */
2487 if (!dosimple(store, out, buf, bi + DELTA_BSIZE))
2495 buf[DELTA_BSIZE + bi] = c;
2496 hx = (hx << 1) ^ (hx & (1 << 31) ? 1 : 0) ^ buz_noise[c];
2498 hx ^= buz_noise[c] ^ (0x83d31df4U ^ 0x07a63be9U);
2499 if (bi == sizeof(buf) - DELTA_BSIZE)
2501 /* trim down, but leave one block for backward extension */
2502 if (!dosimple(store, out, buf, bi - DELTA_BSIZE))
2504 /* no overlap as the buffer is >= 4 * DELTA_BSIZE */
2505 memcpy(buf, buf + bi - DELTA_BSIZE, 2 * DELTA_BSIZE);
2510 if (!encodestoreblock(out, 0, 0)) /* flush */
2512 if (!flushoutbuf(out))
2518 readdeltastore(struct deltastore *store, int fd, int rdonly, unsigned long long xsize)
2520 unsigned char *slots;
2521 unsigned char oneslot[16];
2522 unsigned long long offset, nextoffset, lastgoodoffset;
2524 unsigned long long fsize;
2525 unsigned int nslots = 0, hslots;
2526 unsigned char *hash;
2527 unsigned int hm, h, hh, hf, hd;
2529 int i, lasti, cnt, maxcnt = 0;
2530 unsigned int drop = 0;
2532 memset(store, 0, sizeof(*store));
2534 store->rdonly = rdonly;
2540 fsize = (unsigned long long)st.st_size;
2543 /* first pass: find number of used entries */
2545 lastgoodoffset = -1;
2548 if (offset == fsize)
2550 if (offset + 16 > fsize)
2552 fprintf(stderr, "WARNING: slot area exceeds file size!\n");
2556 if (pread(fd, oneslot, 16, offset) != 16)
2558 if (memcmp(oneslot, "OBSDELT", 8) != 0)
2560 fprintf(stderr, "WARNING: slot magic error!\n");
2564 cnt = oneslot[8] << 8 | oneslot[9];
2565 nextoffset = getu48(oneslot + 10);
2568 offset += (cnt + 1) * 16;
2571 fprintf(stderr, "WARNING: slot area exceeds file size!\n");
2576 lastgoodoffset = offset - (cnt + 1) * 16;
2579 if (offset > nextoffset)
2581 fprintf(stderr, "WARNING: end of slots bigger than nextoffset!\n");
2585 offset = nextoffset;
2588 if (isbad && !store->rdonly)
2590 fprintf(stderr, "WARNING: fixing up bad slots!\n");
2591 if (lastgoodoffset == -1)
2593 /* worst case: first slots area is damaged */
2594 memset(oneslot, 0, 16);
2595 memcpy(oneslot, "OBSDELT", 8);
2596 putu48(oneslot + 10, fsize);
2597 if (pwrite(store->fd, oneslot, 16, 0) != 16)
2599 perror("pwrite repair first slots area");
2605 putu48(oneslot + 10, fsize);
2606 if (pwrite(store->fd, oneslot + 10, 6, lastgoodoffset + 10) != 6)
2608 perror("pwrite repair bad slots area nextoffset");
2615 slots = calloc(maxcnt + 1, 16);
2619 /* find good hash size and allocate hash */
2620 hslots = nslots + xsize / 512;
2621 while (hslots & (hslots - 1))
2622 hslots = hslots & (hslots - 1);
2624 hslots = 16384; /* 1 MByte min mem */
2625 while (hslots > 128 * 1024 * 1024) /* 8 GByte max mem */
2627 /* oh no. max size reached. drop half of slots */
2629 drop += (drop ? drop : nslots) / 2;
2632 store->hm = hm = hslots - 1;
2633 store->hash = hash = calloc(hm + 1, 16);
2636 fprintf(stderr, "could not allocate hash (%u MB)\n", (hm + 1) / (1024 * 1024 / 16));
2641 /* second pass: fill the hash */
2646 int toread = 16 * (maxcnt + 1);
2647 if (isbad && lastgoodoffset == -1)
2649 if (offset >= fsize)
2651 if (offset + toread > fsize)
2652 toread = fsize - offset;
2653 if (pread(fd, slots, toread, offset) != toread)
2658 if (memcmp(slots, "OBSDELT", 8) != 0)
2660 cnt = oneslot[8] << 8 | oneslot[9];
2661 offset += 16 * (cnt + 1);
2662 nextoffset = getu48(slots + 10);
2665 if (offset > nextoffset)
2667 if (offset != nextoffset)
2668 adddataarea(store, offset, nextoffset);
2670 for (i = 1; i < cnt + 1; i++)
2673 unsigned char *hp = slots + 16 * i;
2674 int len = (hp[0] & 127) << 8 | hp[1];
2675 unsigned long long o = getu48(hp + 2);
2682 else if (o >= offset && o + len <= nextoffset)
2684 /* a good one. add to hash. */
2685 h = getu32(hp + 8) & hm;
2686 hh = HASHCHAIN_START;
2687 while (hash[16 * h] != 0)
2688 h = HASHCHAIN_NEXT(h, hh, hm);
2689 memcpy(hash + 16 * h, hp, 16);
2693 store->slotsoffset = offset - 16 * (cnt + 1);
2694 store->freecnt = cnt - lasti;
2695 store->usedcnt = lasti;
2696 if (isbad && lastgoodoffset == store->slotsoffset)
2698 offset = nextoffset;
2703 printf("readdeltastore: have %d entries, %d dropped, hash size %d\n", hf, hd, hm + 1);
2710 printdeltastorestats(struct deltastore *store)
2712 unsigned int buckets[2048];
2713 unsigned int hm, hf, hd;
2717 memset(buckets, 0, sizeof(buckets));
2722 printf("store size: %llu (%u MB)\n", store->end, (unsigned int)(store->end / (1024 * 1024)));
2723 printf("hash mask: 0x%x (%u MB hash mem)\n", hm, (unsigned int)(hm / 65536) + 1);
2724 printf("hash entries set: %u (%.2f %%)\n", hf, ((double)hf * 100) / ((double)hm + 1));
2725 printf("hash entries dropped: %u (%.2f %%)\n", hd, hd ? ((double)hd * 100) / ((double)hf + (double)hd) : 0.);
2726 for (hp = store->hash;; hp += 16)
2729 buckets[((hp[0] & 0x7f) << 8 | hp[1]) / 16]++;
2733 for (i = 2047; i >= 1; i--)
2739 for (j = 0; j < i; j += 2)
2740 buckets[j / 2] = buckets[j] + buckets[j + 1];
2744 printf("block stats:\n");
2745 for (j = 0; j < i; j++)
2746 printf(" size %#6x - %#6x: %10u\n", j * bc, j * bc + bc - 1, buckets[j]);
2747 printf("data areas: %d\n", store->noffsets / 2);
2751 freedeltastore(struct deltastore *store)
2756 free(store->offsets);
2760 settimes(int fd, struct stat *st)
2762 struct timeval tv[2];
2764 tv[0].tv_sec = st->st_atime;
2766 tv[1].tv_sec = st->st_mtime;
2772 checkhexcomp(unsigned char *buf)
2775 for (i = 0; i < 110; i++)
2778 if (c >= '0' && c <= '9')
2780 else if (c >= 'A' && c <= 'F')
2787 else if (c >= 'a' && c <= 'f')
2799 return hexcomp ? hexcomp : 1;
2802 static unsigned int fromhex(unsigned char *hex)
2806 for (i = 0; i < 8; i++, hex++)
2808 if (*hex >= '0' && *hex <= '9')
2809 x = x << 4 | (*hex - '0');
2810 else if (*hex >= 'a' && *hex <= 'f')
2811 x = x << 4 | (*hex - ('a' - 10));
2812 else if (*hex >= 'A' && *hex <= 'F')
2813 x = x << 4 | (*hex - ('A' - 10));
2819 magic_inode_increment(unsigned char *cpio)
2821 unsigned int inode = getu32(cpio + 3);
2823 putu32(cpio + 3, inode + 1);
2827 makedelta(struct deltastore *store, FILE *fp, FILE *ofp, unsigned long long fpsize)
2829 unsigned char cpiohead[1024 + 16384];
2830 unsigned char oldcpio[1024];
2831 int trailerseen = 0;
2833 struct deltaout out;
2835 if (fpsize >= (1LL << 40))
2838 /* init deltaout struct */
2839 memset(&out, 0, sizeof(out));
2842 out.outbuf_do_meta = 1; /* create meta blocks */
2844 /* write our header */
2845 memset(cpiohead, 0, 32);
2846 memcpy(cpiohead, "OBScpio", 8);
2847 putu48(cpiohead + 10, fpsize);
2848 if (fwrite(cpiohead, 16, 1, ofp) != 1)
2851 memset(oldcpio, 0, 1024);
2852 while (!trailerseen)
2854 unsigned long long fsize;
2855 unsigned int hsize, nsize;
2861 /* read the header */
2862 if (fread(cpiohead, 110, 1, fp) != 1)
2864 fprintf(stderr, "cpio header read error\n");
2867 if (memcmp(cpiohead, "070701", 6) != 0)
2869 fprintf(stderr, "not a newc cpio archive\n");
2872 fsize = fromhex(cpiohead + 54);
2873 nsize = fromhex(cpiohead + 94);
2876 fprintf(stderr, "filename size too big\n");
2879 hsize = noff + nsize;
2881 hsize += 4 - (hsize & 3);
2882 /* check if we can do hex compression */
2883 hexcomp = checkhexcomp(cpiohead);
2886 /* do fancy hex compression */
2890 for (i = 3; i < 55; i += 4)
2892 unsigned int x = fromhex(cpiohead + i * 2);
2893 putu32(cpiohead + i, x);
2900 printf("fsize = %d, nsize = %d, hsize = %d\n", fsize, nsize, hsize);
2902 if (fread(cpiohead + noff, hsize - noff, 1, fp) != 1)
2904 fprintf(stderr, "cpio header read error\n");
2907 if (fsize == 0 && nsize == 11 && !memcmp(cpiohead + noff, "TRAILER!!!", 11))
2910 while (hsize < sizeof(cpiohead))
2915 cpiohead[hsize++] = c;
2917 if (hsize == sizeof(cpiohead))
2919 fprintf(stderr, "excess trailer data\n");
2923 /* check trailing zero */
2924 for (zero = 0; zero < 4; zero++)
2925 if (cpiohead[hsize - 1 - zero] != 0)
2927 /* write the header */
2928 if (putc(2 + hexcomp, ofp) == EOF)
2930 for (i = 0; i < 1024 && i < hsize; i++)
2932 cpiohead[i] ^= oldcpio[i];
2933 oldcpio[i] ^= cpiohead[i];
2936 magic_inode_increment(oldcpio);
2939 for (i = 0; i < hsize; i++)
2941 if (cpiohead[i] == 0)
2949 int z = run > 127 ? 127 : run;
2950 if (putc(z, ofp) == EOF)
2954 if (cpiohead[i] == 0)
2955 break; /* ended in zero */
2956 for (j = i; j < hsize - 1; j++)
2957 if (cpiohead[j] == 0 && cpiohead[j + 1] == 0)
2964 if (putc(j + 128, ofp) == EOF)
2968 int z = cpiohead[i++];
2969 if (putc(z, ofp) == EOF)
2974 if (putc(zero ? zero + 251 : 0, ofp) == EOF)
2978 if (!dodelta(store, fp, &out, fsize))
2980 if ((fsize & 3) != 0)
2982 i = 4 - (fsize & 3);
2983 if (putc(4 + i, ofp) == EOF)
2989 fprintf(stderr, "non-zero padding\n");
2996 if (putc(1, ofp) == EOF)
2998 if (fflush(ofp) != 0)
3003 static unsigned long long
3004 expandobscpio_next(FILE *fp)
3006 unsigned long long x = 0;
3012 return (unsigned long long)(-1);
3015 x = x << 7 | (i ^ 128);
3019 static unsigned long long
3020 expandobscpio_next_mem(unsigned char **bp, unsigned int *lp)
3022 unsigned long long x = 0;
3023 unsigned char *b = *bp;
3024 unsigned int l = *lp;
3029 return (unsigned long long)(-1);
3038 x = x << 7 | (i ^ 128);
3043 expandobscpio_direct_mem(unsigned char **bp, unsigned int *lp, void *out, unsigned int outlen)
3048 memcpy(out, *bp, outlen);
3055 expandcpiohead(FILE *fp, FILE *ofp, unsigned char *cpio, int hexcomp)
3080 int x = zero ? 0 : getc(fp);
3089 if (hexcomp && l <= 55)
3091 int lettershift = (hexcomp == 1 ? 'A' : 'a') - ('0' + 10);
3092 int x1 = (x >> 4) + '0';
3093 int x2 = (x & 15) + '0';
3098 if (putc(x1, ofp) == EOF || putc(x2, ofp) == EOF)
3101 else if (putc(x, ofp) == EOF)
3108 magic_inode_increment(cpio);
3113 expandobscpio(FILE *fp, int fdstore, FILE *ofp)
3115 unsigned char magic[16];
3116 unsigned char metabuf[16384];
3117 unsigned char cpio[1024];
3118 unsigned long long o, l;
3120 unsigned long long oldoffset = 0;
3121 unsigned char *meta = 0;
3122 unsigned int metal = 0;
3123 unsigned long long oldoffset_meta = 0;
3125 if (!fp || !ofp || fdstore == -1)
3127 if (fstat(fileno(fp), &st))
3129 if (fread(magic, 16, 1, fp) != 1 || memcmp(magic, "OBScpio", 7) != 0)
3131 memset(cpio, 0, sizeof(cpio));
3137 oldoffset = oldoffset_meta;
3140 l = expandobscpio_next_mem(&meta, &metal);
3142 l = expandobscpio_next(fp);
3143 if (l == (unsigned long long)(-1))
3146 printf("NEXT %d\n", l);
3150 /* first 16 reserved as instructions */
3153 if (l == 1) /* EOF */
3155 if (l == 2 || l == 3 || l == 4) /* CPIO */
3157 if (!expandcpiohead(fp, ofp, cpio, l - 2))
3160 else if (l == 5 || l == 6 || l == 7) /* ZERO */
3164 if (putc(0, ofp) == EOF)
3167 else if (l == 15) /* META */
3169 l = expandobscpio_next(fp);
3170 if (l == (unsigned long long)(-1))
3172 if (l < 16 || l > sizeof(metabuf))
3174 o = expandobscpio_next(fp);
3175 if (o == (unsigned long long)(-1))
3177 o = decodeoffset(oldoffset, o);
3178 oldoffset_meta = o + l;
3180 if (pread(fdstore, metabuf, (size_t)l, (off_t)o) != (size_t)l)
3182 metal = (unsigned int)l;
3197 if (expandobscpio_direct_mem(&meta, &metal, buf, l) != 1)
3200 else if (fread(buf, (int)l, 1, fp) != 1)
3202 if (fwrite(buf, (int)l, 1, ofp) != 1)
3208 /* bytes from the store */
3211 o = expandobscpio_next_mem(&meta, &metal);
3213 o = expandobscpio_next(fp);
3214 if (o == (unsigned long long)(-1))
3216 o = decodeoffset(oldoffset, o);
3221 size_t count = l > 8192 ? 8192 : l;
3222 if (pread(fdstore, buf, count, (off_t)o) != count)
3224 if (fwrite(buf, count, 1, ofp) != 1)
3231 if (fflush(ofp) != 0)
3233 settimes(fileno(ofp), &st);
3238 printobscpioinstr(FILE *fp, int fdstore, int withmeta)
3240 unsigned char magic[16];
3241 unsigned long long oldoffset = 0, o, l;
3242 unsigned char metabuf[16384];
3243 unsigned char *meta = 0;
3244 unsigned int metal = 0;
3245 unsigned long long oldoffset_meta = 0;
3247 unsigned int stats_cpio = 0;
3248 unsigned long long stats_cpio_len = 0;
3249 unsigned int stats_direct = 0;
3250 unsigned long long stats_direct_len = 0;
3251 unsigned int stats_store = 0;
3252 unsigned long long stats_store_len = 0;
3253 unsigned int stats_zero = 0;
3254 unsigned long long stats_zero_len = 0;
3255 unsigned int stats_meta = 0;
3256 unsigned long long stats_meta_len = 0;
3257 unsigned int stats_meta_store = 0;
3258 unsigned long long stats_meta_store_len = 0;
3259 unsigned int stats_meta_direct = 0;
3260 unsigned long long stats_meta_direct_len = 0;
3262 if (fread(magic, 16, 1, fp) != 1 || memcmp(magic, "OBScpio", 7) != 0)
3269 oldoffset = oldoffset_meta;
3272 l = expandobscpio_next_mem(&meta, &metal);
3274 l = expandobscpio_next(fp);
3275 if (l == (unsigned long long)(-1))
3286 if (l == 2 || l == 3 || l == 4) /* CPIO HEADER */
3288 printf("cpio%d", (int)l);
3305 printf(" (%d)", c - 251);
3312 stats_cpio_len += c;
3314 if (getc(fp) == EOF)
3320 else if (l == 5 || l == 6 || l == 7) /* ZERO */
3322 printf("zero %d\n", (int)l - 4);
3324 stats_zero_len += (int)l - 4;
3326 else if (l == 15) /* META */
3328 l = expandobscpio_next(fp);
3329 if (l == (unsigned long long)(-1))
3331 if (l < 16 || l > sizeof(metabuf))
3333 o = expandobscpio_next(fp);
3334 if (o == (unsigned long long)(-1))
3336 o = decodeoffset(oldoffset, o);
3338 printf("meta %#llx %llu\n", o, l);
3340 stats_meta_len += l;
3343 oldoffset_meta = o + l;
3345 if (pread(fdstore, metabuf, (size_t)l, (off_t)o) != (size_t)l)
3347 metal = (unsigned int)l;
3360 printf("direct %d\n", (int)l);
3363 stats_meta_direct++;
3364 stats_meta_direct_len += l;
3369 stats_direct_len += l;
3381 if (getc(fp) == EOF)
3388 o = expandobscpio_next_mem(&meta, &metal);
3390 o = expandobscpio_next(fp);
3391 if (o == (unsigned long long)(-1))
3393 o = decodeoffset(oldoffset, o);
3395 printf("store %#llx %llu\n", o, l);
3399 stats_meta_store_len += l;
3404 stats_store_len += l;
3407 printf("stats cpio %u len %llu\n", stats_cpio, stats_cpio_len);
3408 printf("stats direct %u len %llu\n", stats_direct, stats_direct_len);
3410 printf("stats meta_direct %u len %llu\n", stats_meta_direct, stats_meta_direct_len);
3411 printf("stats store %u len %llu\n", stats_store, stats_store_len);
3413 printf("stats meta_store %u len %llu\n", stats_meta_store, stats_meta_store_len);
3414 printf("stats zero %u len %llu\n", stats_zero, stats_zero_len);
3415 printf("stats meta %u len %llu\n", stats_meta, stats_meta_len);
3417 printf("stats instr %u\n", stats_cpio + stats_direct + stats_store + stats_zero + stats_meta + 1 + stats_meta_direct + stats_meta_store);
3418 printf("stats file_instr %u\n", stats_cpio + stats_direct + stats_store + stats_zero + stats_meta + 1);
3419 printf("stats file_data %lld\n", stats_cpio_len + stats_direct_len);
3420 printf("stats file_size %lld\n", (unsigned long long)ftell(fp));
3423 MODULE = BSSolv PACKAGE = BSSolv
3426 depsort(HV *deps, SV *mapp, SV *cycp, ...)
3429 int i, j, k, cy, cycstart, nv;
3444 XSRETURN_EMPTY; /* nothing to sort */
3448 char *s = SvPV_nolen(ST(3));
3451 PUSHs(sv_2mortal(sv));
3452 XSRETURN(1); /* nothing to sort */
3455 if (mapp && SvROK(mapp) && SvTYPE(SvRV(mapp)) == SVt_PVHV)
3456 mhv = (HV *)SvRV(mapp);
3461 queue_init(&cycles);
3464 ht = solv_calloc(hm + 1, sizeof(*ht));
3465 names = solv_calloc(items, sizeof(char *));
3467 for (i = 3; i < items; i++)
3469 char *s = SvPV_nolen(ST(i));
3470 h = strhash(s) & hm;
3471 hh = HASHCHAIN_START;
3472 while ((id = ht[h]) != 0)
3474 if (!strcmp(names[id], s))
3476 h = HASHCHAIN_NEXT(h, hh, hm);
3479 continue; /* had that one before, ignore */
3485 /* we now know all vertices, create edges */
3486 queue_push(&vedge, 0);
3487 queue_push(&edata, 0);
3488 for (i = 1; i < nv; i++)
3490 svp = hv_fetch(deps, names[i], strlen(names[i]), 0);
3491 sv = svp ? *svp : 0;
3492 queue_push(&vedge, edata.count);
3493 if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV)
3495 AV *av = (AV *)SvRV(sv);
3496 for (j = 0; j <= av_len(av); j++)
3501 svp = av_fetch(av, j, 0);
3510 /* look up in dep map */
3511 svp = hv_fetch(mhv, s, slen, 0);
3514 s = SvPV(*svp, slen);
3519 /* look up in hash */
3520 h = strhash(s) & hm;
3521 hh = HASHCHAIN_START;
3522 while ((id = ht[h]) != 0)
3524 if (!strcmp(names[id], s))
3526 h = HASHCHAIN_NEXT(h, hh, hm);
3529 continue; /* not known, ignore */
3531 continue; /* no self edge */
3532 queue_push(&edata, id);
3535 queue_push(&edata, 0);
3541 printf("vertexes: %d\n", vedge.count - 1);
3542 for (i = 1; i < vedge.count; i++)
3544 printf("%d %s:", i, names[i]);
3545 Id *e = edata.elements + vedge.elements[i];
3553 /* now everything is set up, sort em! */
3554 mark = solv_calloc(vedge.count, sizeof(Id));
3555 for (i = vedge.count - 1; i; i--)
3556 queue_push(&todo, i);
3557 EXTEND(SP, vedge.count - 1);
3560 i = queue_pop(&todo);
3561 // printf("check %d\n", i);
3566 sv = newSVpv(names[i], 0);
3567 PUSHs(sv_2mortal(sv));
3574 int edgestovisit = 0;
3575 Id *e = edata.elements + vedge.elements[i];
3579 continue; /* broken */
3582 if (!edgestovisit++)
3583 queue_push(&todo, -i);
3584 queue_push(&todo, *e);
3589 sv = newSVpv(names[i], 0);
3590 PUSHs(sv_2mortal(sv));
3596 /* oh no, we found a cycle, record and break it */
3598 for (j = todo.count - 1; j >= 0; j--)
3599 if (todo.elements[j] == -i)
3602 // printf("cycle:\n");
3603 for (j = cycstart; j < todo.count; j++)
3604 if (todo.elements[j] < 0)
3606 k = -todo.elements[j];
3608 queue_push(&cycles, k);
3609 // printf(" %d\n", k);
3611 queue_push(&cycles, 0);
3612 todo.elements[cycstart] = i;
3614 for (k = cy; cycles.elements[k]; k++)
3616 if (!cycles.elements[k])
3618 j = cycles.elements[k + 1] ? cycles.elements[k + 1] : cycles.elements[cy];
3619 k = cycles.elements[k];
3620 /* breaking edge from k -> j */
3621 // printf("break %d -> %d\n", k, j);
3622 e = edata.elements + vedge.elements[k];
3629 todo.count = cycstart + 1;
3632 /* recored cycles */
3633 if (cycles.count && cycp && SvROK(cycp) && SvTYPE(SvRV(cycp)) == SVt_PVAV)
3635 AV *av = (AV *)SvRV(cycp);
3636 for (i = 0; i < cycles.count;)
3639 for (; cycles.elements[i]; i++)
3641 SV *sv = newSVpv(names[cycles.elements[i]], 0);
3644 av_push(av, newRV_noinc((SV*)av2));
3648 queue_free(&cycles);
3658 gen_meta(AV *subp, ...)
3664 struct metaline *lines, *lp;
3666 int i, j, cycle, ns;
3673 XSRETURN_EMPTY; /* nothing to generate */
3675 queue_init_buffer(&cycles, cycles_buf, sizeof(cycles_buf)/sizeof(*cycles_buf));
3676 hm = mkmask(av_len(subp) + 2);
3677 ht = solv_calloc(hm + 1, sizeof(*ht));
3678 subpacks = solv_calloc(av_len(subp) + 2, sizeof(char *));
3679 for (j = 0; j <= av_len(subp); j++)
3681 SV **svp = av_fetch(subp, j, 0);
3684 s = SvPV_nolen(*svp);
3685 h = strhash(s) & hm;
3686 hh = HASHCHAIN_START;
3687 while ((id = ht[h]) != 0)
3688 h = HASHCHAIN_NEXT(h, hh, hm);
3690 subpacks[j + 1] = s;
3693 lines = solv_calloc(items - 1, sizeof(*lines));
3695 /* lines are of the form "md5sum pkg/pkg..." */
3696 for (i = 0, lp = lines; i < nlines; i++, lp++)
3698 s = SvPV_nolen(ST(i + 1));
3699 if (strlen(s) < 35 || s[32] != ' ' || s[33] != ' ')
3700 croak("gen_meta: bad line %s\n", s);
3706 for (s2 = lo; *s2; s2++)
3712 h = strhash(lo) & hm;
3713 hh = HASHCHAIN_START;
3714 while ((id = ht[h]) != 0)
3716 if (!strcmp(lo, subpacks[id]))
3718 h = HASHCHAIN_NEXT(h, hh, hm);
3729 h = strhash(lo) & hm;
3730 hh = HASHCHAIN_START;
3731 while ((id = ht[h]) != 0)
3733 if (!strcmp(lo, subpacks[id]))
3735 h = HASHCHAIN_NEXT(h, hh, hm);
3743 if (cycle > 1) /* ignore self cycles */
3744 queue_push(&cycles, i);
3747 lp->lastoff = lo - s;
3750 solv_free(subpacks);
3752 /* if we found cycles, prune em */
3755 char *cycledata = 0;
3756 int cycledatalen = 0;
3758 cycledata = solv_extend(cycledata, cycledatalen, 1, 1, 255);
3761 hm = mkmask(cycles.count);
3762 ht = solv_calloc(hm + 1, sizeof(*ht));
3763 for (i = 0; i < cycles.count; i++)
3766 s = lines[cycles.elements[i]].l + 34;
3767 se = strchr(s, '/');
3770 h = strhash(s) & hm;
3771 hh = HASHCHAIN_START;
3772 while ((id = ht[h]) != 0)
3774 if (!strcmp(s, cycledata + id))
3776 h = HASHCHAIN_NEXT(h, hh, hm);
3780 cycledata = solv_extend(cycledata, cycledatalen, strlen(s) + 1, 1, 255);
3781 ht[h] = cycledatalen;
3782 strcpy(cycledata + cycledatalen, s);
3783 cycledatalen += strlen(s) + 1;
3787 for (i = 0, lp = lines; i < nlines; i++, lp++)
3789 if (lp->killed || !lp->nslash)
3791 lo = strchr(lp->l + 34, '/') + 1;
3792 for (s2 = lo; *s2; s2++)
3796 h = strhash(lo) & hm;
3797 hh = HASHCHAIN_START;
3798 while ((id = ht[h]) != 0)
3800 if (!strcmp(lo, cycledata + id))
3802 h = HASHCHAIN_NEXT(h, hh, hm);
3814 h = strhash(lo) & hm;
3815 hh = HASHCHAIN_START;
3816 while ((id = ht[h]) != 0)
3818 if (!strcmp(lo, cycledata + id))
3820 h = HASHCHAIN_NEXT(h, hh, hm);
3828 cycledata = solv_free(cycledata);
3829 queue_free(&cycles);
3832 /* cycles are pruned, now sort array */
3834 qsort(lines, nlines, sizeof(*lines), metacmp);
3836 hm = mkmask(nlines);
3837 ht = solv_calloc(hm + 1, sizeof(*ht));
3838 for (i = 0, lp = lines; i < nlines; i++, lp++)
3843 h = strnhash(s, 10);
3844 h = strhash_cont(s + lp->lastoff, h) & hm;
3845 hh = HASHCHAIN_START;
3846 while ((id = ht[h]) != 0)
3848 struct metaline *lp2 = lines + (id - 1);
3849 if (!strncmp(lp->l, lp2->l, 32) && !strcmp(lp->l + lp->lastoff, lp2->l + lp2->lastoff))
3851 h = HASHCHAIN_NEXT(h, hh, hm);
3860 for (i = 0, lp = lines; i < nlines; i++, lp++)
3864 for (i = 0, lp = lines; i < nlines; i++, lp++)
3869 sv = newSVpv(lp->l, 0);
3870 PUSHs(sv_2mortal(sv));
3881 croak("thaw: argument is not a string\n");
3884 src = (unsigned char *)SvPV(sv, srcl);
3885 if (srcl < 7 || src[0] != 'p' || src[1] != 's' || src[2] != 't' || src[3] != '0') {
3886 croak("thaw: argument is not a perl storable\n");
3889 if ((src[4] & 1) != 1) {
3890 croak("thaw: argument is not a perl storable in network order\n");
3894 croak("thaw: argument is a perl storable with a too old version\n");
3899 sv = retrieve(&src, &srcl, 0);
3900 if (sv == 0 || srcl) {
3901 croak("thaw: corrupt storable\n");
3904 RETVAL = newRV_noinc(sv);
3909 isobscpio(const char *file)
3913 if ((fd = open(file, O_RDONLY)) != -1) {
3914 unsigned char magic[16];
3915 if (read(fd, magic, 16) == 16 && !memcmp(magic, "OBScpio", 7))
3924 obscpiostat(const char *file)
3929 if ((fd = open(file, O_RDONLY)) != -1) {
3930 if (!fstat(fd, &st)) {
3931 unsigned char magic[16];
3932 if (read(fd, magic, 16) == 16 && !memcmp(magic, "OBScpio", 7)) {
3933 st.st_size = getu48(magic + 10);
3936 PUSHs(&PL_sv_undef);
3937 PUSHs(&PL_sv_undef);
3938 PUSHs(sv_2mortal(newSVuv((UV)st.st_mode)));
3939 PUSHs(sv_2mortal(newSVuv((UV)st.st_nlink)));
3940 PUSHs(&PL_sv_undef);
3941 PUSHs(&PL_sv_undef);
3942 PUSHs(&PL_sv_undef);
3944 PUSHs(sv_2mortal(newSVuv((UV)st.st_size)));
3946 PUSHs(sv_2mortal(newSVnv((double)st.st_size)));
3948 PUSHs(sv_2mortal(newSVuv((UV)st.st_atime)));
3949 PUSHs(sv_2mortal(newSVuv((UV)st.st_mtime)));
3950 PUSHs(sv_2mortal(newSVuv((UV)st.st_ctime)));
3957 obscpioopen(const char *file, const char *store, SV *gvrv, const char *tmpdir = 0)
3961 if (!SvROK(gvrv) || SvTYPE(SvRV(gvrv)) != SVt_PVGV) {
3962 croak("obscpioopen needs a GV reference\n");
3964 if (tmpdir && strlen(tmpdir) > 200) {
3965 croak("tmpdir too long\n");
3967 gv = (GV *)SvRV(gvrv);
3969 if ((fd = open(file, O_RDONLY)) != -1) {
3970 unsigned char magic[16];
3971 if (read(fd, magic, 16) == 16 && !memcmp(magic, "OBScpio", 7)) {
3975 if ((sfd = open(store, O_RDONLY)) != -1) {
3977 strcpy(template, tmpdir);
3978 strcat(template, "/obscpioopen-XXXXXX");
3980 strcpy(template, "/var/tmp/obscpioopen-XXXXXX");
3982 nfd = mkstemp(template);
3984 FILE *fp = 0, *nfp = 0;
3986 lseek(fd, 0, SEEK_SET);
3987 if ((fp = fdopen(fd, "r")) == 0)
3989 if ((nfp = fdopen(nfd, "w+")) == 0)
3991 if (fp && nfp && expandobscpio(fp, sfd, nfp)) {
4014 IO * io = GvIOn(gv);
4017 lseek(fd, 0, SEEK_SET);
4018 fp = PerlIO_fdopen(fd, "rb");
4030 expandobscpio(const char *file, const char *store, const char *tmpfile)
4037 if ((fd = open(file, O_RDONLY)) != -1) {
4038 unsigned char magic[16];
4039 if (!(read(fd, magic, 16) == 16 && !memcmp(magic, "OBScpio", 7))) {
4042 if (link(file, tmpfile) == 0 && (fd = open(tmpfile, O_RDONLY)) != -1) {
4043 if (read(fd, magic, 16) == 16 && !memcmp(magic, "OBScpio", 7)) {
4053 if ((sfd = open(store, O_RDONLY)) != -1) {
4055 lseek(fd, 0, SEEK_SET);
4056 if ((fp = fdopen(fd, "r")) == 0)
4058 if (fp && (nfd = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0666)) != -1) {
4060 if ((nfp = fdopen(nfd, "w")) == 0)
4062 if (nfp && expandobscpio(fp, sfd, nfp)) {
4087 makeobscpio(const char *in, const char *store, const char *out)
4094 if ((fpin = fopen(in, "r")) == 0) {
4096 } else if (fstat(fileno(fpin), &st) != 0) {
4099 } else if ((fpout = fopen(out, "w")) == 0) {
4102 } else if ((fdstore = open(store, O_RDWR|O_CREAT, 0666)) == -1) {
4109 if (flock(fdstore, LOCK_EX) == 0)
4111 else if (errno != EINTR)
4115 struct deltastore store;
4116 if (readdeltastore(&store, fdstore, 0, (unsigned long long)st.st_size)) {
4117 int r = makedelta(&store, fpin, fpout, (unsigned long long)st.st_size);
4119 printf("after makedelta: have %d entries, hash size %d\n", store.hf, store.hm + 1);
4121 if (fsync(store.fd))
4123 freedeltastore(&store);
4125 settimes(fileno(fpout), &st);
4139 obscpiostorestats(const char *store)
4144 if ((fdstore = open(store, O_RDONLY)) == -1)
4149 if (flock(fdstore, LOCK_EX) == 0)
4151 else if (errno != EINTR)
4155 struct deltastore store;
4156 if (readdeltastore(&store, fdstore, 1, (unsigned long long)0)) {
4157 printdeltastorestats(&store);
4159 freedeltastore(&store);
4167 obscpioinstr(const char *file, const char *store = 0)
4172 if ((fp = fopen(file, "r")) == 0)
4176 fdstore = open(store, O_RDONLY);
4180 printobscpioinstr(fp, fdstore, fdstore == -1 ? 0 : 1);
4188 MODULE = BSSolv PACKAGE = BSSolv::pool PREFIX = pool
4193 new(char *packname = "BSSolv::pool")
4196 Pool *pool = pool_create();
4197 set_disttype(pool, DISTTYPE_RPM);
4198 buildservice_id = pool_str2id(pool, "buildservice:id", 1);
4199 buildservice_repocookie= pool_str2id(pool, "buildservice:repocookie", 1);
4200 buildservice_external = pool_str2id(pool, "buildservice:external", 1);
4201 buildservice_dodurl = pool_str2id(pool, "buildservice:dodurl", 1);
4202 expander_directdepsend = pool_str2id(pool, "-directdepsend--", 1);
4203 buildservice_dodcookie = pool_str2id(pool, "buildservice:dodcookie", 1);
4204 pool_freeidhashes(pool);
4211 settype(BSSolv::pool pool, char *type)
4213 if (!strcmp(type, "rpm"))
4214 set_disttype(pool, DISTTYPE_RPM);
4216 else if (!strcmp(type, "deb"))
4217 set_disttype(pool, DISTTYPE_DEB);
4219 #ifdef DISTTYPE_ARCH
4220 else if (!strcmp(type, "arch"))
4221 set_disttype(pool, DISTTYPE_ARCH);
4224 croak("settype: unknown type '%s'\n", type);
4228 repofromfile(BSSolv::pool pool, char *name, char *filename)
4231 fp = fopen(filename, "r");
4233 croak("%s: %s\n", filename, Strerror(errno));
4236 RETVAL = repo_create(pool, name);
4237 repo_add_solv(RETVAL, fp, 0);
4243 repofromstr(BSSolv::pool pool, char *name, SV *sv)
4248 buf = SvPV(sv, len);
4250 croak("repofromstr: undef string\n");
4251 fp = fmemopen(buf, len, "r");
4253 croak("fmemopen failed\n");
4256 RETVAL = repo_create(pool, name);
4257 repo_add_solv(RETVAL, fp, 0);
4263 repofrombins(BSSolv::pool pool, char *name, char *dir, ...)
4269 repo = repo_create(pool, name);
4270 data = repo_add_repodata(repo, 0);
4271 for (i = 3; i + 1 < items; i += 2)
4274 char *s = SvPV(ST(i), sl);
4275 char *sid = SvPV_nolen(ST(i + 1));
4278 if (strcmp(s + sl - 4, ".rpm")
4279 && strcmp(s + sl - 4, ".deb")
4280 #ifdef ARCH_ADD_WITH_PKGID
4281 && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.gz"))
4282 && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.xz"))
4286 if (sl >= 10 && !strcmp(s + sl - 10, ".patch.rpm"))
4288 if (sl >= 10 && !strcmp(s + sl - 10, ".nosrc.rpm"))
4290 if (sl >= 8 && !strcmp(s + sl - 8, ".src.rpm"))
4292 repodata_addbin(data, dir, s, (int)sl, sid);
4294 repo_set_str(repo, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
4295 repo_internalize(repo);
4302 repofromdata(BSSolv::pool pool, char *name, HV *rhv)
4307 repo = repo_create(pool, name);
4308 data = repo_add_repodata(repo, 0);
4309 data2solvables(repo, data, rhv);
4310 if (name && !strcmp(name, "/external/"))
4311 repodata_set_void(data, SOLVID_META, buildservice_external);
4312 repo_internalize(repo);
4319 createwhatprovides(BSSolv::pool pool)
4321 if (pool->considered)
4323 map_free(pool->considered);
4324 solv_free(pool->considered);
4326 pool->considered = solv_calloc(sizeof(Map), 1);
4327 create_considered(pool, 0, pool->considered);
4328 pool_createwhatprovides(pool);
4331 setdebuglevel(BSSolv::pool pool, int level)
4333 pool_setdebuglevel(pool, level);
4336 whatprovides(BSSolv::pool pool, char *str)
4340 id = dep2id(pool, str);
4342 FOR_PROVIDES(p, pp, id)
4343 XPUSHs(sv_2mortal(newSViv((IV)p)));
4347 whatrequires(BSSolv::pool pool, char *str)
4353 id = dep2id(pool, str);
4356 for (p = 2; p < pool->nsolvables; p++)
4358 if (!MAPTST(pool->considered, p))
4360 s = pool->solvables + p;
4363 for (pp = s->repo->idarraydata + s->requires; *pp; pp++)
4364 if (pool_match_dep(pool, id, *pp))
4367 XPUSHs(sv_2mortal(newSViv((IV)p)));
4373 consideredpackages(BSSolv::pool pool)
4377 for (p = 2; p < pool->nsolvables; p++)
4378 if (MAPTST(pool->considered, p))
4381 for (p = 2; p < pool->nsolvables; p++)
4382 if (MAPTST(pool->considered, p))
4383 PUSHs(sv_2mortal(newSViv((IV)p)));
4387 allpackages(BSSolv::pool pool)
4391 for (p = 2; p < pool->nsolvables; p++)
4392 if (pool->solvables[p].repo)
4395 for (p = 2; p < pool->nsolvables; p++)
4396 if (pool->solvables[p].repo)
4397 PUSHs(sv_2mortal(newSViv((IV)p)));
4401 pkg2name(BSSolv::pool pool, int p)
4403 RETVAL = pool_id2str(pool, pool->solvables[p].name);
4408 pkg2srcname(BSSolv::pool pool, int p)
4410 if (solvable_lookup_void(pool->solvables + p, SOLVABLE_SOURCENAME))
4411 RETVAL = pool_id2str(pool, pool->solvables[p].name);
4413 RETVAL = solvable_lookup_str(pool->solvables + p, SOLVABLE_SOURCENAME);
4418 pkg2pkgid(BSSolv::pool pool, int p)
4422 const char *s = solvable_lookup_checksum(pool->solvables + p, SOLVABLE_PKGID, &type);
4429 pkg2bsid(BSSolv::pool pool, int p)
4431 RETVAL = solvable_lookup_str(pool->solvables + p, buildservice_id);
4436 pkg2reponame(BSSolv::pool pool, int p)
4439 Repo *repo = pool->solvables[p].repo;
4440 RETVAL = repo ? repo->name : 0;
4446 pkg2path(BSSolv::pool pool, int p)
4449 unsigned int medianr;
4450 RETVAL = solvable_get_location(pool->solvables + p, &medianr);
4456 pkg2fullpath(BSSolv::pool pool, int p, char *myarch)
4459 unsigned int medianr;
4460 const char *s = solvable_get_location(pool->solvables + p, &medianr);
4461 Repo *repo = pool->solvables[p].repo;
4462 s = pool_tmpjoin(pool, myarch, "/:full/", s);
4463 RETVAL = pool_tmpjoin(pool, repo->name, "/", s);
4469 pkg2sizek(BSSolv::pool pool, int p)
4471 #ifdef SOLV_KV_NUM64
4472 RETVAL = solvable_lookup_sizek(pool->solvables + p, SOLVABLE_DOWNLOADSIZE, 0);
4474 RETVAL = solvable_lookup_num(pool->solvables + p, SOLVABLE_DOWNLOADSIZE, 0);
4480 pkg2checksum(BSSolv::pool pool, int p)
4484 const char *s = solvable_lookup_checksum(pool->solvables + p, SOLVABLE_CHECKSUM, &type);
4486 s = pool_tmpjoin(pool, solv_chksum_type2str(type), ":", s);
4493 verifypkgchecksum(BSSolv::pool pool, int p, char *path)
4497 const unsigned char *cin, *cout;
4505 if ((cin = solvable_lookup_bin_checksum(pool->solvables + p, SOLVABLE_CHECKSUM, &type)) != 0) {
4506 if ((fp = fopen(path, "r")) != 0) {
4507 if ((cs = solv_chksum_create(type)) != 0) {
4508 while ((len = fread(buf, 1, sizeof(buf), fp)) > 0)
4509 solv_chksum_add(cs, buf, len);
4510 if ((cout = solv_chksum_get(cs, &cslen)) != 0 && cslen && !memcmp(cin, cout, cslen))
4512 solv_chksum_free(cs, 0);
4523 pkg2data(BSSolv::pool pool, int p)
4526 Solvable *s = pool->solvables + p;
4528 const char *ss, *se;
4529 unsigned int medianr;
4534 sv_2mortal((SV*)RETVAL);
4535 (void)hv_store(RETVAL, "name", 4, newSVpv(pool_id2str(pool, s->name), 0), 0);
4536 ss = pool_id2str(pool, s->evr);
4538 while (*se >= '0' && *se <= '9')
4540 if (se != ss && *se == ':' && se[1])
4542 (void)hv_store(RETVAL, "epoch", 5, newSVpvn(ss, se - ss), 0);
4545 se = strrchr(ss, '-');
4548 (void)hv_store(RETVAL, "version", 7, newSVpvn(ss, se - ss), 0);
4549 (void)hv_store(RETVAL, "release", 7, newSVpv(se + 1, 0), 0);
4552 (void)hv_store(RETVAL, "version", 7, newSVpv(ss, 0), 0);
4553 (void)hv_store(RETVAL, "arch", 4, newSVpv(pool_id2str(pool, s->arch), 0), 0);
4554 exportdeps(RETVAL, "provides", 8, s->repo, s->provides, SOLVABLE_PROVIDES);
4555 exportdeps(RETVAL, "obsoletes", 9, s->repo, s->obsoletes, SOLVABLE_OBSOLETES);
4556 exportdeps(RETVAL, "conflicts", 9, s->repo, s->conflicts, SOLVABLE_CONFLICTS);
4557 exportdeps(RETVAL, "requires", 8, s->repo, s->requires, SOLVABLE_REQUIRES);
4558 exportdeps(RETVAL, "recommends", 10, s->repo, s->recommends, SOLVABLE_RECOMMENDS);
4559 exportdeps(RETVAL, "suggests", 8, s->repo, s->suggests, SOLVABLE_SUGGESTS);
4560 exportdeps(RETVAL, "supplements", 11, s->repo, s->supplements, SOLVABLE_SUPPLEMENTS);
4561 exportdeps(RETVAL, "enhances", 8, s->repo, s->enhances, SOLVABLE_ENHANCES);
4562 if (solvable_lookup_void(s, SOLVABLE_SOURCENAME))
4563 ss = pool_id2str(pool, s->name);
4565 ss = solvable_lookup_str(s, SOLVABLE_SOURCENAME);
4567 (void)hv_store(RETVAL, "source", 6, newSVpv(ss, 0), 0);
4568 ss = solvable_get_location(s, &medianr);
4570 (void)hv_store(RETVAL, "path", 4, newSVpv(ss, 0), 0);
4571 ss = solvable_lookup_checksum(s, SOLVABLE_PKGID, &id);
4572 if (ss && id == REPOKEY_TYPE_MD5)
4573 (void)hv_store(RETVAL, "hdrmd5", 6, newSVpv(ss, 0), 0);
4574 ss = solvable_lookup_str(s, buildservice_id);
4576 (void)hv_store(RETVAL, "id", 2, newSVpv(ss, 0), 0);
4582 repos(BSSolv::pool pool)
4588 EXTEND(SP, pool->nrepos);
4589 FOR_REPOS(ridx, repo)
4591 SV *sv = sv_newmortal();
4592 sv_setref_pv(sv, "BSSolv::repo", (void *)repo);
4598 preparehashes(BSSolv::pool pool, char *prp, SV *gctxprpnotreadysv = 0)
4601 HV *gctxprpnotready = 0;
4605 HV *depislocal = newHV();
4606 HV *dep2pkg = newHV();
4607 HV *dep2src = newHV();
4608 HV *notready = newHV();
4609 HV *subpacks = newHV();
4613 Id lastsrc, srcname, srctype;
4619 if (gctxprpnotreadysv && SvROK(gctxprpnotreadysv) && SvTYPE(SvRV(gctxprpnotreadysv)) == SVt_PVHV)
4620 gctxprpnotready = (HV *)SvRV(gctxprpnotreadysv);
4622 FOR_REPOS(ridx, repo)
4624 HV *prpnotready = 0;
4625 int islocal = repo->name && !strcmp(repo->name, prp);
4627 if (repo->name && !islocal && gctxprpnotready)
4628 svp = hv_fetch(gctxprpnotready, repo->name, strlen(repo->name), 0);
4629 if (svp && *svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVHV)
4630 prpnotready = (HV *)SvRV(*svp);
4631 FOR_REPO_SOLVABLES(repo, p, s)
4633 if (!MAPTST(pool->considered, p))
4635 srctype = solvable_lookup_type(pool->solvables + p, SOLVABLE_SOURCENAME);
4636 if (srctype == REPOKEY_TYPE_VOID)
4638 else if (srctype == REPOKEY_TYPE_ID)
4639 srcname = solvable_lookup_id(pool->solvables + p, SOLVABLE_SOURCENAME);
4642 srcstr = solvable_lookup_str(pool->solvables + p, SOLVABLE_SOURCENAME);
4643 srcname = srcstr ? pool_str2id(pool, srcstr, 1) : 0;
4645 if (!srcname || srcname == 1)
4647 queue_push2(&subq, s->name, srcname);
4649 str = pool_id2str(pool, s->name);
4650 (void)hv_store(dep2pkg, str, strlen(str), newSViv((IV)p), 0);
4652 (void)hv_store(depislocal, str, strlen(str), newSViv((IV)1), 0);
4653 srcstr = pool_id2str(pool, srcname);
4654 (void)hv_store(dep2src, str, strlen(str), newSVpv(srcstr, 0), 0);
4655 if (!islocal && prpnotready)
4657 svp = hv_fetch(prpnotready, srcstr, strlen(srcstr), 0);
4658 if (svp && *svp && SvTRUE(*svp))
4659 (void)hv_store(notready, srcstr, strlen((char *)srcstr), newSViv((IV)2), 0);
4663 solv_sort(subq.elements, subq.count / 2, sizeof(Id) * 2, subpack_sort_cmp, pool);
4664 queue_push2(&subq, 0, 0);
4666 for (i = j = 0; i < subq.count; i += 2)
4668 if (subq.elements[i + 1] != lastsrc)
4673 for (; j < i; j += 2)
4675 str = pool_id2str(pool, subq.elements[j]);
4676 av_push(subs, newSVpv(str, 0));
4678 str = pool_id2str(pool, lastsrc);
4679 (void)hv_store(subpacks, str, strlen(str), newRV_noinc((SV *)subs), 0);
4681 lastsrc = subq.elements[i + 1];
4686 sv = newRV_noinc((SV *)dep2pkg);
4687 PUSHs(sv_2mortal(sv));
4688 sv = newRV_noinc((SV *)dep2src);
4689 PUSHs(sv_2mortal(sv));
4690 sv = newRV_noinc((SV *)depislocal);
4691 PUSHs(sv_2mortal(sv));
4692 sv = newRV_noinc((SV *)notready);
4693 PUSHs(sv_2mortal(sv));
4694 sv = newRV_noinc((SV *)subpacks);
4695 PUSHs(sv_2mortal(sv));
4699 DESTROY(BSSolv::pool pool)
4701 if (pool->considered)
4703 map_free(pool->considered);
4704 pool->considered = solv_free(pool->considered);
4711 MODULE = BSSolv PACKAGE = BSSolv::repo PREFIX = repo
4714 pkgnames(BSSolv::repo repo)
4717 Pool *pool = repo->pool;
4722 create_considered(pool, repo, &c);
4723 EXTEND(SP, 2 * repo->nsolvables);
4724 FOR_REPO_SOLVABLES(repo, p, s)
4728 PUSHs(sv_2mortal(newSVpv(pool_id2str(pool, s->name), 0)));
4729 PUSHs(sv_2mortal(newSViv(p)));
4735 pkgpaths(BSSolv::repo repo)
4738 Pool *pool = repo->pool;
4743 unsigned int medianr;
4745 create_considered(pool, repo, &c);
4746 EXTEND(SP, 2 * repo->nsolvables);
4747 FOR_REPO_SOLVABLES(repo, p, s)
4751 /* ignore dod packages */
4752 str = solvable_lookup_str(s, buildservice_id);
4753 if (str && !strcmp(str, "dod"))
4755 str = solvable_get_location(pool->solvables + p, &medianr);
4758 PUSHs(sv_2mortal(newSVpv(str, 0)));
4759 PUSHs(sv_2mortal(newSViv(p)));
4765 tofile(BSSolv::repo repo, char *filename)
4769 fp = fopen(filename, "w");
4771 croak("%s: %s\n", filename, Strerror(errno));
4772 repo_write_filtered(repo, fp, myrepowritefilter, 0, 0);
4774 croak("fclose: %s\n", Strerror(errno));
4778 tofile_fd(BSSolv::repo repo, int fd)
4785 croak("dup: %s\n", Strerror(errno));
4786 fp = fdopen(fd2, "w");
4791 croak("fdopen: %s\n", Strerror(e));
4793 repo_write_filtered(repo, fp, myrepowritefilter, 0, 0);
4798 croak("fclose: %s\n", Strerror(e));
4803 tostr(BSSolv::repo repo)
4809 fp = open_memstream(&buf, &len);
4811 croak("open_memstream: %s\n", Strerror(errno));
4812 repo_write_filtered(repo, fp, myrepowritefilter, 0, 0);
4814 croak("fclose: %s\n", Strerror(errno));
4815 RETVAL = newSVpvn(buf, len);
4822 updatefrombins(BSSolv::repo repo, char *dir, ...)
4825 Pool *pool = repo->pool;
4836 const char *oldcookie;
4838 map_init(&reused, repo->end - repo->start);
4839 if (repo_lookup_str(repo, SOLVID_META, buildservice_dodurl))
4841 /* this is a dod repo. keep all dod packages. */
4842 FOR_REPO_SOLVABLES(repo, p, s)
4844 const char *str = solvable_lookup_str(s, buildservice_id);
4845 if (str && !strcmp(str, "dod"))
4846 MAPSET(&reused, p - repo->start);
4849 hm = mkmask(2 * repo->nsolvables + 1);
4850 ht = solv_calloc(hm + 1, sizeof(*ht));
4851 oldcookie = repo_lookup_str(repo, SOLVID_META, buildservice_repocookie);
4852 if (oldcookie && !strcmp(oldcookie, REPOCOOKIE))
4854 FOR_REPO_SOLVABLES(repo, p, s)
4856 const char *str = solvable_lookup_str(s, buildservice_id);
4857 if (!str || !strcmp(str, "dod"))
4859 h = strhash(str) & hm;
4860 hh = HASHCHAIN_START;
4861 while ((id = ht[h]) != 0)
4862 h = HASHCHAIN_NEXT(h, hh, hm);
4866 if (repo->end != repo->start)
4869 for (i = 2; i + 1 < items; i += 2)
4871 char *s = SvPV(ST(i), sl);
4872 char *sid = SvPV_nolen(ST(i + 1));
4875 if (strcmp(s + sl - 4, ".rpm")
4876 && strcmp(s + sl - 4, ".deb")
4877 #ifdef ARCH_ADD_WITH_PKGID
4878 && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.gz"))
4879 && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.xz"))
4882 if (sl > 10 && !strcmp(s + sl - 10, ".patch.rpm"))
4884 if (sl > 10 && !strcmp(s + sl - 10, ".nosrc.rpm"))
4886 if (sl > 8 && !strcmp(s + sl - 8, ".src.rpm"))
4888 h = strhash(sid) & hm;
4889 hh = HASHCHAIN_START;
4890 while ((id = ht[h]) != 0)
4892 const char *str = solvable_lookup_str(pool->solvables + id, buildservice_id);
4893 if (!strcmp(str, sid))
4895 /* check location */
4896 unsigned int medianr;
4897 str = solvable_get_location(pool->solvables + id, &medianr);
4898 if (str[0] == '.' && str[1] == '/')
4900 if (!strcmp(str, s))
4903 h = HASHCHAIN_NEXT(h, hh, hm);
4907 /* same id and location, reuse old entry */
4908 MAPSET(&reused, id - repo->start);
4915 data = repo_add_repodata(repo, 0);
4916 repodata_addbin(data, dir, s, (int)sl, sid);
4922 if (strcmp(oldcookie, REPOCOOKIE) != 0)
4924 Repodata *firstrepodata = repo_id2repodata(repo, 1);
4925 if (data && data != firstrepodata)
4926 repodata_internalize(data);
4927 data = firstrepodata;
4928 repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
4934 data = repo_add_repodata(repo, 0);
4935 repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
4938 repodata_internalize(data);
4941 for (i = repo->start; i < oldend; i++)
4943 if (pool->solvables[i].repo != repo)
4945 if (MAPTST(&reused, i - repo->start))
4949 repo_free_solvable_block(repo, i, 1, 0);
4960 getpathid(BSSolv::repo repo)
4965 EXTEND(SP, repo->nsolvables * 2);
4966 FOR_REPO_SOLVABLES(repo, p, s)
4968 unsigned int medianr;
4970 str = solvable_get_location(s, &medianr);
4971 PUSHs(sv_2mortal(newSVpv(str, 0)));
4972 str = solvable_lookup_str(s, buildservice_id);
4973 PUSHs(sv_2mortal(newSVpv(str, 0)));
4978 name(BSSolv::repo repo)
4980 RETVAL = repo->name;
4985 isexternal(BSSolv::repo repo)
4987 RETVAL = repo_lookup_void(repo, SOLVID_META, buildservice_external) ? 1 : 0;
4992 dodurl(BSSolv::repo repo)
4994 RETVAL = repo_lookup_str(repo, SOLVID_META, buildservice_dodurl);
4999 dodcookie(BSSolv::repo repo)
5001 RETVAL = repo_lookup_str(repo, SOLVID_META, buildservice_dodcookie);
5006 updatedoddata(BSSolv::repo repo, HV *rhv = 0)
5012 /* delete old dod data */
5013 FOR_REPO_SOLVABLES(repo, p, s)
5015 const char *str = solvable_lookup_str(s, buildservice_id);
5016 if (!str || !strcmp(str, "dod"))
5017 repo_free_solvable(repo, p, 1);
5019 data = repo_add_repodata(repo, REPO_REUSE_REPODATA);
5020 repodata_unset(data, SOLVID_META, buildservice_dodurl);
5021 repodata_unset(data, SOLVID_META, buildservice_dodcookie);
5024 data2solvables(repo, data, rhv);
5025 repo_internalize(repo);
5029 MODULE = BSSolv PACKAGE = BSSolv::expander PREFIX = expander
5033 new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
5042 xp = calloc(sizeof(Expander), 1);
5044 svp = hv_fetch(config, "prefer", 6, 0);
5045 sv = svp ? *svp : 0;
5046 if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV)
5048 AV *av = (AV *)SvRV(sv);
5049 for (i = 0; i <= av_len(av); i++)
5051 svp = av_fetch(av, i, 0);
5055 str = SvPV_nolen(sv);
5064 id = pool_str2id(pool, str, 1);
5066 if ((str = strchr(str, ':')) != 0)
5067 id2 = pool_str2id(pool, str + 1, 1);
5070 MAPEXP(&xp->preferneg, id);
5071 MAPSET(&xp->preferneg, id);
5074 MAPEXP(&xp->prefernegx, id2);
5075 MAPSET(&xp->prefernegx, id2);
5080 queue_push(&xp->preferposq, id);
5081 MAPEXP(&xp->preferpos, id);
5082 MAPSET(&xp->preferpos, id);
5085 MAPEXP(&xp->preferposx, id2);
5086 MAPSET(&xp->preferposx, id2);
5091 svp = hv_fetch(config, "ignoreh", 7, 0);
5092 sv = svp ? *svp : 0;
5093 if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV)
5095 HV *hv = (HV *)SvRV(sv);
5099 while ((he = hv_iternext(hv)) != 0)
5102 str = hv_iterkey(he, &strl);
5106 id = pool_str2id(pool, str, 1);
5108 if ((str = strchr(str, ':')) != 0)
5109 id2 = pool_str2id(pool, str + 1, 1);
5110 MAPEXP(&xp->ignored, id);
5111 MAPSET(&xp->ignored, id);
5114 MAPEXP(&xp->ignoredx, id2);
5115 MAPSET(&xp->ignoredx, id2);
5119 svp = hv_fetch(config, "conflict", 8, 0);
5120 sv = svp ? *svp : 0;
5121 if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV)
5123 AV *av = (AV *)SvRV(sv);
5124 for (i = 0; i <= av_len(av); i++)
5129 svp = av_fetch(av, i, 0);
5133 str = SvPV_nolen(sv);
5136 p = strchr(str, ':');
5139 id = pool_strn2id(pool, str, p - str, 1);
5141 while ((p = strchr(str, ',')) != 0)
5143 id2 = pool_strn2id(pool, str, p - str, 1);
5144 queue_push2(&xp->conflictsq, id, id2);
5145 MAPEXP(&xp->conflicts, id);
5146 MAPSET(&xp->conflicts, id);
5147 MAPEXP(&xp->conflicts, id2);
5148 MAPSET(&xp->conflicts, id2);
5151 id2 = pool_str2id(pool, str, 1);
5152 queue_push2(&xp->conflictsq, id, id2);
5153 MAPEXP(&xp->conflicts, id);
5154 MAPSET(&xp->conflicts, id);
5155 MAPEXP(&xp->conflicts, id2);
5156 MAPSET(&xp->conflicts, id2);
5159 /* XXX: this modifies the pool, which is a bit unclean! */
5160 svp = hv_fetch(config, "fileprovides", 12, 0);
5161 sv = svp ? *svp : 0;
5162 if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV)
5164 HV *hv = (HV *)SvRV(sv);
5168 xp->havefileprovides = 1;
5171 while ((sv = hv_iternextsv(hv, &str, &strl)) != 0)
5177 if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV)
5179 id = pool_str2id(pool, str, 1);
5181 FOR_PROVIDES(p, pp, id)
5183 av = (AV *)SvRV(sv);
5184 for (i = 0; i <= av_len(av); i++)
5186 svp = av_fetch(av, i, 0);
5190 str = SvPV_nolen(sv);
5193 id2 = pool_str2id(pool, str, 0);
5194 FOR_PROVIDES(p, pp, id2)
5197 for (j = 0; j < q.count; j++)
5199 if (q.elements[j] == p)
5201 if (q.elements[j] > p)
5203 queue_insert(&q, j, p);
5216 pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
5220 svp = hv_fetch(config, "expandflags:ignoreconflicts", 27, 0);
5221 sv = svp ? *svp : 0;
5222 if (sv && SvTRUE(sv))
5223 xp->ignoreconflicts = 1;
5224 svp = hv_fetch(config, "expand_dbg", 10, 0);
5225 sv = svp ? *svp : 0;
5226 if (sv && SvTRUE(sv))
5228 sv = get_sv("Build::expand_dbg", FALSE);
5229 if (sv && SvTRUE(sv))
5238 expand(BSSolv::expander xp, ...)
5243 Id id, who, conflbuf[16];
5244 Queue revertignore, in, out, confl;
5245 int oldignoreignore = xp->ignoreignore;
5246 int ignoreignore = 0;
5247 Map oldignored, oldignoredx;
5248 int ignoremapssaved = 0;
5250 queue_init(&revertignore);
5253 queue_init_buffer(&confl, conflbuf, sizeof(conflbuf)/sizeof(*conflbuf));
5256 expander_dbg(xp, "expand args:");
5257 for (i = 1; i < items; i++)
5259 char *s = SvPV_nolen(ST(i));
5261 expander_dbg(xp, " %s", s);
5265 if (s[1] == '-' && !strcmp(s, "--ignoreignore--"))
5270 id = pool_str2id(pool, s + 1, 1);
5271 if (id == expander_directdepsend)
5273 queue_push(&in, id);
5276 queue_push(&revertignore, id);
5280 Id id = dep2id(pool, s + (s[1] == '!' ? 2 : 1));
5281 queue_push2(&confl, id, s[1] == '!' ? 1 : 0);
5285 Id id = dep2id(pool, s);
5286 queue_push(&in, id);
5290 expander_dbg(xp, "\n");
5292 if (ignoreignore && revertignore.count)
5294 /* bad: have direct ignores and project config ignores */
5295 oldignored = xp->ignored;
5296 oldignoredx = xp->ignoredx;
5297 ignoremapssaved = 1;
5298 /* clear project config maps */
5299 memset(&xp->ignored, 0, sizeof(xp->ignored));
5300 memset(&xp->ignoredx, 0, sizeof(xp->ignoredx));
5303 if (revertignore.count)
5305 /* mix direct ignores with ignores from project config */
5306 int revertcnt = revertignore.count;
5307 for (i = 0; i < revertcnt; i++)
5310 id = revertignore.elements[i];
5311 MAPEXP(&xp->ignored, id);
5312 if (MAPTST(&xp->ignored, id))
5314 MAPSET(&xp->ignored, id);
5315 queue_push(&revertignore, id);
5316 if ((ss = strchr(pool_id2str(pool, id), ':')) != 0)
5318 id = pool_str2id(pool, ss + 1, 1);
5319 MAPEXP(&xp->ignoredx, id);
5320 if (MAPTST(&xp->ignoredx, id))
5322 MAPSET(&xp->ignoredx, id);
5323 queue_push(&revertignore, -id);
5326 queue_deleten(&revertignore, 0, revertcnt);
5328 else if (ignoreignore)
5330 /* no direct ignores, disable ignore processing */
5331 xp->ignoreignore = 1;
5334 MAPEXP(&xp->ignored, pool->ss.nstrings);
5335 MAPEXP(&xp->ignoredx, pool->ss.nstrings);
5336 MAPEXP(&xp->preferpos, pool->ss.nstrings);
5337 MAPEXP(&xp->preferposx, pool->ss.nstrings);
5338 MAPEXP(&xp->preferneg, pool->ss.nstrings);
5339 MAPEXP(&xp->prefernegx, pool->ss.nstrings);
5340 MAPEXP(&xp->conflicts, pool->ss.nstrings);
5342 nerrors = expander_expand(xp, &in, &out, &confl);
5344 /* revert ignores */
5345 xp->ignoreignore = oldignoreignore;
5346 if (ignoremapssaved)
5348 map_free(&xp->ignored);
5349 map_free(&xp->ignoredx);
5350 xp->ignored = oldignored;
5351 xp->ignoredx = oldignoredx;
5355 for (i = 0; i < revertignore.count; i++)
5357 id = revertignore.elements[i];
5359 MAPCLR(&xp->ignored, id);
5361 MAPCLR(&xp->ignoredx, -id);
5364 queue_free(&revertignore);
5371 EXTEND(SP, nerrors + 1);
5372 PUSHs(sv_2mortal(newSV(0)));
5373 for (i = 0; i < out.count; )
5376 Id type = out.elements[i];
5377 if (type == ERROR_NOPROVIDER)
5379 id = out.elements[i + 1];
5380 who = out.elements[i + 2];
5382 sv = newSVpvf("nothing provides %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
5384 sv = newSVpvf("nothing provides %s", pool_dep2str(pool, id));
5387 else if (type == ERROR_CONFLICTINGPROVIDER)
5389 id = out.elements[i + 1];
5390 who = out.elements[i + 2];
5392 sv = newSVpvf("conflict for provider of %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
5394 sv = newSVpvf("conflict for provider of %s", pool_dep2str(pool, id));
5397 else if (type == ERROR_CONFLICTINGPROVIDERS)
5399 id = out.elements[i + 1];
5400 who = out.elements[i + 2];
5402 sv = newSVpvf("conflict for all providers of %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
5404 sv = newSVpvf("conflict for all providers of %s", pool_dep2str(pool, id));
5407 else if (type == ERROR_PROVIDERINFO)
5409 Id who2 = out.elements[i + 2];
5410 who = out.elements[i + 1];
5412 sv = newSVpvf("(provider %s obsoletes installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[-who2].name));
5414 sv = newSVpvf("(provider %s conflicts with installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[who2].name));
5417 else if (type == ERROR_PROVIDERINFO2)
5419 Id who2 = out.elements[i + 2];
5420 who = out.elements[i + 1];
5422 sv = newSVpvf("(provider %s is obsoleted by installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[-who2].name));
5424 sv = newSVpvf("(provider %s is conflicted by installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[who2].name));
5426 sv = newSVpvf("(provider %s is conflicted by the build config)", pool_id2str(pool, pool->solvables[who].name));
5429 else if (type == ERROR_CHOICE)
5433 for (j = i + 3; out.elements[j]; j++)
5435 Solvable *s = pool->solvables + out.elements[j];
5436 str = pool_tmpjoin(pool, str, " ", pool_id2str(pool, s->name));
5439 str++; /* skip starting ' ' */
5440 id = out.elements[i + 1];
5441 who = out.elements[i + 2];
5443 sv = newSVpvf("have choice for %s needed by %s: %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name), str);
5445 sv = newSVpvf("have choice for %s: %s", pool_dep2str(pool, id), str);
5449 croak("expander: bad error type\n");
5450 PUSHs(sv_2mortal(sv));
5455 EXTEND(SP, out.count + 1);
5456 PUSHs(sv_2mortal(newSViv((IV)1)));
5457 for (i = 0; i < out.count; i++)
5459 Solvable *s = pool->solvables + out.elements[i];
5460 PUSHs(sv_2mortal(newSVpv(pool_id2str(pool, s->name), 0)));
5467 debugstr(BSSolv::expander xp)
5470 xp->debugstr = calloc(1, 1);
5471 RETVAL = xp->debugstr;
5477 DESTROY(BSSolv::expander xp)
5479 map_free(&xp->ignored);
5480 map_free(&xp->ignoredx);
5481 queue_free(&xp->preferposq);
5482 map_free(&xp->preferpos);
5483 map_free(&xp->preferposx);
5484 map_free(&xp->preferneg);
5485 map_free(&xp->prefernegx);
5486 queue_free(&xp->conflictsq);
5487 map_free(&xp->conflicts);
5488 solv_free(xp->debugstr);