Imported Upstream version 0.6.31
[platform/upstream/libsolv.git] / ext / repo_rpmdb.c
1 /*
2  * Copyright (c) 2007-2018, SUSE Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * repo_rpmdb
10  *
11  * convert rpm db to repo
12  *
13  */
14
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <limits.h>
18 #include <fcntl.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <assert.h>
24 #include <stdint.h>
25 #include <errno.h>
26
27 #ifdef ENABLE_RPMDB
28
29 #include <rpm/rpmio.h>
30 #include <rpm/rpmpgp.h>
31 #ifndef RPM5
32 #include <rpm/header.h>
33 #endif
34 #include <rpm/rpmdb.h>
35
36 #endif
37
38 #include "pool.h"
39 #include "repo.h"
40 #include "hash.h"
41 #include "util.h"
42 #include "queue.h"
43 #include "chksum.h"
44 #include "repo_rpmdb.h"
45 #include "repo_solv.h"
46 #ifdef ENABLE_COMPLEX_DEPS
47 #include "pool_parserpmrichdep.h"
48 #endif
49
50 /* 3: added triggers */
51 /* 4: fixed triggers */
52 /* 5: fixed checksum copying */
53 /* 6: add SOLVABLE_PREREQ_IGNOREINST support */
54 /* 7: fix bug in ignoreinst logic */
55 #define RPMDB_COOKIE_VERSION 7
56
57 #define TAG_NAME                1000
58 #define TAG_VERSION             1001
59 #define TAG_RELEASE             1002
60 #define TAG_EPOCH               1003
61 #define TAG_SUMMARY             1004
62 #define TAG_DESCRIPTION         1005
63 #define TAG_BUILDTIME           1006
64 #define TAG_BUILDHOST           1007
65 #define TAG_INSTALLTIME         1008
66 #define TAG_SIZE                1009
67 #define TAG_DISTRIBUTION        1010
68 #define TAG_VENDOR              1011
69 #define TAG_LICENSE             1014
70 #define TAG_PACKAGER            1015
71 #define TAG_GROUP               1016
72 #define TAG_URL                 1020
73 #define TAG_ARCH                1022
74 #define TAG_FILESIZES           1028
75 #define TAG_FILEMODES           1030
76 #define TAG_FILEMD5S            1035
77 #define TAG_FILELINKTOS         1036
78 #define TAG_FILEFLAGS           1037
79 #define TAG_SOURCERPM           1044
80 #define TAG_PROVIDENAME         1047
81 #define TAG_REQUIREFLAGS        1048
82 #define TAG_REQUIRENAME         1049
83 #define TAG_REQUIREVERSION      1050
84 #define TAG_NOSOURCE            1051
85 #define TAG_NOPATCH             1052
86 #define TAG_CONFLICTFLAGS       1053
87 #define TAG_CONFLICTNAME        1054
88 #define TAG_CONFLICTVERSION     1055
89 #define TAG_TRIGGERNAME         1066
90 #define TAG_TRIGGERVERSION      1067
91 #define TAG_TRIGGERFLAGS        1068
92 #define TAG_CHANGELOGTIME       1080
93 #define TAG_CHANGELOGNAME       1081
94 #define TAG_CHANGELOGTEXT       1082
95 #define TAG_OBSOLETENAME        1090
96 #define TAG_FILEDEVICES         1095
97 #define TAG_FILEINODES          1096
98 #define TAG_SOURCEPACKAGE       1106
99 #define TAG_PROVIDEFLAGS        1112
100 #define TAG_PROVIDEVERSION      1113
101 #define TAG_OBSOLETEFLAGS       1114
102 #define TAG_OBSOLETEVERSION     1115
103 #define TAG_DIRINDEXES          1116
104 #define TAG_BASENAMES           1117
105 #define TAG_DIRNAMES            1118
106 #define TAG_PAYLOADFORMAT       1124
107 #define TAG_PATCHESNAME         1133
108 #define TAG_FILECOLORS          1140
109 #define TAG_OLDSUGGESTSNAME     1156
110 #define TAG_OLDSUGGESTSVERSION  1157
111 #define TAG_OLDSUGGESTSFLAGS    1158
112 #define TAG_OLDENHANCESNAME     1159
113 #define TAG_OLDENHANCESVERSION  1160
114 #define TAG_OLDENHANCESFLAGS    1161
115
116 /* rpm5 tags */
117 #define TAG_DISTEPOCH           1218
118
119 /* rpm4 tags */
120 #define TAG_LONGFILESIZES       5008
121 #define TAG_LONGSIZE            5009
122 #define TAG_RECOMMENDNAME       5046
123 #define TAG_RECOMMENDVERSION    5047
124 #define TAG_RECOMMENDFLAGS      5048
125 #define TAG_SUGGESTNAME         5049
126 #define TAG_SUGGESTVERSION      5050
127 #define TAG_SUGGESTFLAGS        5051
128 #define TAG_SUPPLEMENTNAME      5052
129 #define TAG_SUPPLEMENTVERSION   5053
130 #define TAG_SUPPLEMENTFLAGS     5054
131 #define TAG_ENHANCENAME         5055
132 #define TAG_ENHANCEVERSION      5056
133 #define TAG_ENHANCEFLAGS        5057
134
135 /* signature tags */
136 #define TAG_SIGBASE             256
137 #define TAG_SIGMD5              (TAG_SIGBASE + 5)
138 #define TAG_SHA1HEADER          (TAG_SIGBASE + 13)
139 #define TAG_SHA256HEADER        (TAG_SIGBASE + 17)
140
141 #define SIGTAG_SIZE             1000
142 #define SIGTAG_PGP              1002    /* RSA signature */
143 #define SIGTAG_MD5              1004    /* header+payload md5 checksum */
144 #define SIGTAG_GPG              1005    /* DSA signature */
145
146 #define DEP_LESS                (1 << 1)
147 #define DEP_GREATER             (1 << 2)
148 #define DEP_EQUAL               (1 << 3)
149 #define DEP_STRONG              (1 << 27)
150 #define DEP_PRE_IN              ((1 << 6) | (1 << 9) | (1 << 10))
151 #define DEP_PRE_UN              ((1 << 6) | (1 << 11) | (1 << 12))
152
153 #define FILEFLAG_GHOST          (1 << 6)
154
155
156 /* some limits to guard against corrupt rpms */
157 /* dsize limits taken from rpm's lib/header.c */
158 #define MAX_SIG_CNT             0x10000
159 #define MAX_SIG_DSIZE           0x4000000
160
161 #define MAX_HDR_CNT             0x10000
162 #define MAX_HDR_DSIZE           0x10000000
163
164
165 #ifndef ENABLE_RPMPKG_LIBRPM
166
167 typedef struct rpmhead {
168   int cnt;
169   unsigned int dcnt;
170   unsigned char *dp;
171   unsigned char data[1];
172 } RpmHead;
173
174
175 static inline unsigned char *
176 headfindtag(RpmHead *h, int tag)
177 {
178   unsigned int i;
179   unsigned char *d, taga[4];
180   d = h->dp - 16;
181   taga[0] = tag >> 24;
182   taga[1] = tag >> 16;
183   taga[2] = tag >> 8;
184   taga[3] = tag;
185   for (i = 0; i < h->cnt; i++, d -= 16)
186     if (d[3] == taga[3] && d[2] == taga[2] && d[1] == taga[1] && d[0] == taga[0])
187       return d;
188   return 0;
189 }
190
191 static int
192 headexists(RpmHead *h, int tag)
193 {
194   return headfindtag(h, tag) ? 1 : 0;
195 }
196
197 static uint32_t *
198 headint32array(RpmHead *h, int tag, int *cnt)
199 {
200   uint32_t *r;
201   unsigned int i, o;
202   unsigned char *d = headfindtag(h, tag);
203
204   if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4)
205     return 0;
206   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
207   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
208   if (o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt)
209     return 0;
210   d = h->dp + o;
211   r = solv_calloc(i ? i : 1, sizeof(uint32_t));
212   if (cnt)
213     *cnt = i;
214   for (o = 0; o < i; o++, d += 4)
215     r[o] = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
216   return r;
217 }
218
219 /* returns the first entry of an integer array */
220 static uint32_t
221 headint32(RpmHead *h, int tag)
222 {
223   unsigned int i, o;
224   unsigned char *d = headfindtag(h, tag);
225
226   if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4)
227     return 0;
228   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
229   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
230   if (i == 0 || o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt)
231     return 0;
232   d = h->dp + o;
233   return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
234 }
235
236 static uint64_t *
237 headint64array(RpmHead *h, int tag, int *cnt)
238 {
239   uint64_t *r;
240   unsigned int i, o;
241   unsigned char *d = headfindtag(h, tag);
242
243   if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5)
244     return 0;
245   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
246   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
247   if (o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt)
248     return 0;
249   d = h->dp + o;
250   r = solv_calloc(i ? i : 1, sizeof(uint64_t));
251   if (cnt)
252     *cnt = i;
253   for (o = 0; o < i; o++, d += 8)
254     {
255       uint32_t x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
256       r[o] = (uint64_t)x << 32 | (uint32_t)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
257     }
258   return r;
259 }
260
261 /* returns the first entry of an 64bit integer array */
262 static uint64_t
263 headint64(RpmHead *h, int tag)
264 {
265   uint32_t x;
266   unsigned int i, o;
267   unsigned char *d = headfindtag(h, tag);
268
269   if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5)
270     return 0;
271   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
272   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
273   if (i == 0 || o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt)
274     return 0;
275   d = h->dp + o;
276   x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
277   return (uint64_t)x << 32 | (uint32_t)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
278 }
279
280 static uint16_t *
281 headint16array(RpmHead *h, int tag, int *cnt)
282 {
283   uint16_t *r;
284   unsigned int i, o;
285   unsigned char *d = headfindtag(h, tag);
286
287   if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 3)
288     return 0;
289   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
290   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
291   if (o > h->dcnt || i > h->dcnt || o + 2 * i > h->dcnt)
292     return 0;
293   d = h->dp + o;
294   r = solv_calloc(i ? i : 1, sizeof(uint16_t));
295   if (cnt)
296     *cnt = i;
297   for (o = 0; o < i; o++, d += 2)
298     r[o] = d[0] << 8 | d[1];
299   return r;
300 }
301
302 static char *
303 headstring(RpmHead *h, int tag)
304 {
305   unsigned int o;
306   unsigned char *d = headfindtag(h, tag);
307   /* 6: STRING, 9: I18NSTRING */
308   if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || (d[7] != 6 && d[7] != 9))
309     return 0;
310   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
311   if (o >= h->dcnt)
312     return 0;
313   return (char *)h->dp + o;
314 }
315
316 static char **
317 headstringarray(RpmHead *h, int tag, int *cnt)
318 {
319   unsigned int i, o;
320   unsigned char *d = headfindtag(h, tag);
321   char **r;
322
323   if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 8)
324     return 0;
325   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
326   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
327   if (o > h->dcnt || i > h->dcnt)
328     return 0;
329   r = solv_calloc(i ? i : 1, sizeof(char *));
330   if (cnt)
331     *cnt = i;
332   d = h->dp + o;
333   for (o = 0; o < i; o++)
334     {
335       r[o] = (char *)d;
336       if (o + 1 < i)
337         d += strlen((char *)d) + 1;
338       if (d >= h->dp + h->dcnt)
339         {
340           solv_free(r);
341           return 0;
342         }
343     }
344   return r;
345 }
346
347 static unsigned char *
348 headbinary(RpmHead *h, int tag, unsigned int *sizep)
349 {
350   unsigned int i, o;
351   unsigned char *d = headfindtag(h, tag);
352   if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 7)
353     return 0;
354   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
355   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
356   if (o > h->dcnt || i > h->dcnt || o + i > h->dcnt)
357     return 0;
358   if (sizep)
359     *sizep = i;
360   return h->dp + o;
361 }
362
363 static int
364 headissourceheuristic(RpmHead *h)
365 {
366   unsigned int i, o;
367   unsigned char *d = headfindtag(h, TAG_DIRNAMES);
368   if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 8)
369     return 0;
370   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
371   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
372   return i == 1 && o < h->dcnt && !h->dp[o] ? 1 : 0;
373 }
374
375 static inline void
376 headfree(RpmHead *h)
377 {
378   solv_free(h);
379 }
380
381 #else
382
383 typedef struct headerToken_s RpmHead;
384
385 static int
386 headexists(RpmHead *h, int tag)
387 {
388   return headerIsEntry(h, tag);
389 }
390
391 static void *headget(RpmHead *h, int tag, int *cnt, int alloc)
392 {
393   struct rpmtd_s td;
394   if (!headerGet(h, tag, &td, alloc ? HEADERGET_ALLOC : HEADERGET_MINMEM))
395     return 0;
396   if (cnt)
397     *cnt = td.count;
398   return td.data;
399 }
400
401 static uint32_t *
402 headint32array(RpmHead *h, int tag, int *cnt)
403 {
404   return headget(h, tag, cnt, 1);
405 }
406
407 static uint32_t
408 headint32(RpmHead *h, int tag)
409 {
410   uint32_t *arr = headget(h, tag, 0, 0);
411   return arr ? arr[0] : 0;
412 }
413
414 static uint64_t *
415 headint64array(RpmHead *h, int tag, int *cnt)
416 {
417   return headget(h, tag, cnt, 1);
418 }
419
420 /* returns the first entry of an 64bit integer array */
421 static uint64_t
422 headint64(RpmHead *h, int tag)
423 {
424   uint64_t *arr = headget(h, tag, 0, 0);
425   return arr ? arr[0] : 0;
426 }
427
428 static uint16_t *
429 headint16array(RpmHead *h, int tag, int *cnt)
430 {
431   return headget(h, tag, cnt, 1);
432 }
433
434 static char *
435 headstring(RpmHead *h, int tag)
436 {
437   return headget(h, tag, 0, 0);
438 }
439
440 static char **
441 headstringarray(RpmHead *h, int tag, int *cnt)
442 {
443   return headget(h, tag, cnt, 1);
444 }
445
446 static unsigned char *
447 headbinary(RpmHead *h, int tag, unsigned int *sizep)
448 {
449   return headget(h, tag, (int *)sizep, 0);
450 }
451
452 static int
453 headissourceheuristic(RpmHead *h)
454 {
455   return headerIsSource(h);
456 }
457
458 static inline void
459 headfree(RpmHead *h)
460 {
461   headerFree(h);
462 }
463
464 #endif
465
466 static char *headtoevr(RpmHead *h)
467 {
468   unsigned int epoch;
469   char *version, *v;
470   char *release;
471   char *evr;
472   char *distepoch;
473
474   version  = headstring(h, TAG_VERSION);
475   release  = headstring(h, TAG_RELEASE);
476   epoch = headint32(h, TAG_EPOCH);
477   if (!version || !release)
478     {
479       fprintf(stderr, "headtoevr: bad rpm header\n");
480       return 0;
481     }
482   for (v = version; *v >= '0' && *v <= '9'; v++)
483     ;
484   if (epoch || (v != version && *v == ':'))
485     {
486       char epochbuf[11];        /* 32bit decimal will fit in */
487       sprintf(epochbuf, "%u", epoch);
488       evr = solv_malloc(strlen(epochbuf) + 1 + strlen(version) + 1 + strlen(release) + 1);
489       sprintf(evr, "%s:%s-%s", epochbuf, version, release);
490     }
491   else
492     {
493       evr = solv_malloc(strlen(version) + 1 + strlen(release) + 1);
494       sprintf(evr, "%s-%s", version, release);
495     }
496   distepoch = headstring(h, TAG_DISTEPOCH);
497   if (distepoch && *distepoch)
498     {
499       int l = strlen(evr);
500       evr = solv_realloc(evr, l + strlen(distepoch) + 2);
501       evr[l++] = ':';
502       strcpy(evr + l, distepoch);
503     }
504   return evr;
505 }
506
507
508 static void
509 setutf8string(Repodata *repodata, Id handle, Id tag, const char *str)
510 {
511   if (str[solv_validutf8(str)])
512     {
513       char *ustr = solv_latin1toutf8(str);      /* not utf8, assume latin1 */
514       repodata_set_str(repodata, handle, tag, ustr);
515       solv_free(ustr);
516     }
517   else
518     repodata_set_str(repodata, handle, tag, str);
519 }
520
521 static int
522 ignq_sortcmp(const void *va, const void *vb, void *dp)
523 {
524   int r = *(Id *)va - *(Id *)vb;
525   if (!r)
526     r = ((Id *)va)[1] - ((Id *)vb)[1];
527   return r;
528 }
529
530 /*
531  * strong: 0: ignore strongness
532  *         1: filter to strong
533  *         2: filter to weak
534  */
535 static unsigned int
536 makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags, Queue *ignq)
537 {
538   char **n, **v;
539   uint32_t *f;
540   int i, cc, nc, vc, fc;
541   int haspre, premask, has_ign;
542   unsigned int olddeps;
543   Id *ida;
544   int strong = 0;
545
546   n = headstringarray(rpmhead, tagn, &nc);
547   if (!n)
548     {
549       switch (tagn)
550         {
551         case TAG_SUGGESTNAME:
552           tagn = TAG_OLDSUGGESTSNAME;
553           tagv = TAG_OLDSUGGESTSVERSION;
554           tagf = TAG_OLDSUGGESTSFLAGS;
555           strong = -1;
556           break;
557         case TAG_ENHANCENAME:
558           tagn = TAG_OLDENHANCESNAME;
559           tagv = TAG_OLDENHANCESVERSION;
560           tagf = TAG_OLDENHANCESFLAGS;
561           strong = -1;
562           break;
563         case TAG_RECOMMENDNAME:
564           tagn = TAG_OLDSUGGESTSNAME;
565           tagv = TAG_OLDSUGGESTSVERSION;
566           tagf = TAG_OLDSUGGESTSFLAGS;
567           strong = 1;
568           break;
569         case TAG_SUPPLEMENTNAME:
570           tagn = TAG_OLDENHANCESNAME;
571           tagv = TAG_OLDENHANCESVERSION;
572           tagf = TAG_OLDENHANCESFLAGS;
573           strong = 1;
574           break;
575         default:
576           return 0;
577         }
578       n = headstringarray(rpmhead, tagn, &nc);
579     }
580   if (!n || !nc)
581     return 0;
582   vc = fc = 0;
583   v = headstringarray(rpmhead, tagv, &vc);
584   f = headint32array(rpmhead, tagf, &fc);
585   if (!v || !f || nc != vc || nc != fc)
586     {
587       char *pkgname = rpm_query(rpmhead, 0);
588       pool_error(pool, 0, "bad dependency entries for %s: %d %d %d", pkgname ? pkgname : "<NULL>", nc, vc, fc);
589       solv_free(pkgname);
590       solv_free(n);
591       solv_free(v);
592       solv_free(f);
593       return 0;
594     }
595
596   cc = nc;
597   haspre = 0;   /* add no prereq marker */
598   premask = tagn == TAG_REQUIRENAME ? DEP_PRE_IN | DEP_PRE_UN : 0;
599   if ((flags & RPM_ADD_NO_RPMLIBREQS) || strong)
600     {
601       /* we do filtering */
602       cc = 0;
603       for (i = 0; i < nc; i++)
604         {
605           if (strong && (f[i] & DEP_STRONG) != (strong < 0 ? 0 : DEP_STRONG))
606             continue;
607           if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0)
608             if (!strncmp(n[i], "rpmlib(", 7))
609               continue;
610           if ((f[i] & premask) != 0)
611             haspre = 1;
612           cc++;
613         }
614     }
615   else if (premask)
616     {
617       /* no filtering, just look for the first prereq */
618       for (i = 0; i < nc; i++)
619         if ((f[i] & premask) != 0)
620           {
621             haspre = 1;
622             break;
623           }
624     }
625   if (cc == 0)
626     {
627       solv_free(n);
628       solv_free(v);
629       solv_free(f);
630       return 0;
631     }
632   cc += haspre;         /* add slot for the prereq marker */
633   olddeps = repo_reserve_ids(repo, 0, cc);
634   ida = repo->idarraydata + olddeps;
635
636   has_ign = 0;
637   for (i = 0; ; i++)
638     {
639       Id id;
640       if (i == nc)
641         {
642           if (haspre != 1)
643             break;
644           haspre = 2;   /* pass two: prereqs */
645           i = 0;
646           *ida++ = SOLVABLE_PREREQMARKER;
647         }
648       if (strong && (f[i] & DEP_STRONG) != (strong < 0 ? 0 : DEP_STRONG))
649         continue;
650       if (haspre)
651         {
652           if (haspre == 1 && (f[i] & premask) != 0)
653             continue;
654           if (haspre == 2 && (f[i] & premask) == 0)
655             continue;
656         }
657       if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0)
658         if (!strncmp(n[i], "rpmlib(", 7))
659           continue;
660 #ifdef ENABLE_COMPLEX_DEPS
661       if ((f[i] & (DEP_LESS|DEP_EQUAL|DEP_GREATER)) == 0 && n[i][0] == '(')
662         {
663           id = pool_parserpmrichdep(pool, n[i]);
664           if (id)
665             *ida++ = id;
666           else
667             cc--;
668           continue;
669         }
670 #endif
671       id = pool_str2id(pool, n[i], 1);
672       if (f[i] & (DEP_LESS|DEP_GREATER|DEP_EQUAL))
673         {
674           Id evr;
675           int fl = 0;
676           if ((f[i] & DEP_LESS) != 0)
677             fl |= REL_LT;
678           if ((f[i] & DEP_EQUAL) != 0)
679             fl |= REL_EQ;
680           if ((f[i] & DEP_GREATER) != 0)
681             fl |= REL_GT;
682           if (v[i][0] == '0' && v[i][1] == ':' && v[i][2])
683             evr = pool_str2id(pool, v[i] + 2, 1);
684           else
685             evr = pool_str2id(pool, v[i], 1);
686           id = pool_rel2id(pool, id, evr, fl, 1);
687         }
688       *ida++ = id;
689       if (haspre == 2 && ignq)
690         {
691           int is_ign = (f[i] & DEP_PRE_IN) != 0 && (f[i] & DEP_PRE_UN) == 0 ? 1 : 0;
692           has_ign |= is_ign;
693           queue_push2(ignq, id, is_ign);
694         }
695     }
696   *ida++ = 0;
697   repo->idarraysize += cc + 1;
698   solv_free(n);
699   solv_free(v);
700   solv_free(f);
701   if (ignq && ignq->count)
702     {
703       int j = 0;
704       if (has_ign && ignq->count == 2)
705         j = 1;
706       else if (has_ign)
707         {
708           Id id, lastid = 0;
709
710           solv_sort(ignq->elements, ignq->count / 2, sizeof(Id) * 2, ignq_sortcmp, 0);
711           for (i = j = 0; i < ignq->count; i += 2)
712             {
713               id = ignq->elements[i];
714               if (id != lastid && ignq->elements[i + 1] > 0)
715                 ignq->elements[j++] = id;
716               lastid = id;
717             }
718         }
719       queue_truncate(ignq, j);
720     }
721   return olddeps;
722 }
723
724 static Id
725 repodata_str2dir_rooted(Repodata *data, char *str, int create)
726 {
727   char buf[256], *bp;
728   int l = strlen(str);
729   Id id;
730
731   if (l + 2 <= sizeof(buf))
732     bp = buf;
733   else
734     bp = solv_malloc(l + 2);
735   bp[0] = '/';
736   strcpy(bp + 1, str);
737   id = repodata_str2dir(data, bp, create);
738   if (bp != buf)
739     solv_free(bp);
740   return id;
741 }
742
743 static void
744 adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, uint32_t *di, int fc, int dc)
745 {
746   Id did;
747   int i, fszc;
748   unsigned int *fkb, *fn;
749   uint64_t *fsz64;
750   uint32_t *fsz, *fino;
751   uint16_t *fm;
752   unsigned int inotest[256], inotestok;
753
754   if (!fc)
755     return;
756   if ((fsz64 = headint64array(rpmhead, TAG_LONGFILESIZES, &fszc)) != 0)
757     {
758       /* convert to kbyte */
759       fsz = solv_malloc2(fszc, sizeof(*fsz));
760       for (i = 0; i < fszc; i++)
761         fsz[i] = fsz64[i] ? fsz64[i] / 1024 + 1 : 0;
762       solv_free(fsz64);
763     }
764   else if ((fsz = headint32array(rpmhead, TAG_FILESIZES, &fszc)) != 0)
765     {
766       /* convert to kbyte */
767       for (i = 0; i < fszc; i++)
768         if (fsz[i])
769           fsz[i] = fsz[i] / 1024 + 1;
770     }
771   else
772     return;
773   if (fc != fszc)
774     {
775       solv_free(fsz);
776       return;
777     }
778
779   /* stupid rpm records sizes of directories, so we have to check the mode */
780   fm = headint16array(rpmhead, TAG_FILEMODES, &fszc);
781   if (!fm || fc != fszc)
782     {
783       solv_free(fsz);
784       solv_free(fm);
785       return;
786     }
787   fino = headint32array(rpmhead, TAG_FILEINODES, &fszc);
788   if (!fino || fc != fszc)
789     {
790       solv_free(fsz);
791       solv_free(fm);
792       solv_free(fino);
793       return;
794     }
795
796   /* kill hardlinked entries */
797   inotestok = 0;
798   if (fc < sizeof(inotest))
799     {
800       /* quick test just hashing the inode numbers */
801       memset(inotest, 0, sizeof(inotest));
802       for (i = 0; i < fc; i++)
803         {
804           int off, bit;
805           if (fsz[i] == 0 || !S_ISREG(fm[i]))
806             continue;   /* does not matter */
807           off = (fino[i] >> 5) & (sizeof(inotest)/sizeof(*inotest) - 1);
808           bit = 1 << (fino[i] & 31);
809           if ((inotest[off] & bit) != 0)
810             break;
811           inotest[off] |= bit;
812         }
813       if (i == fc)
814         inotestok = 1;  /* no conflict found */
815     }
816   if (!inotestok)
817     {
818       /* hardlinked files are possible, check ino/dev pairs */
819       unsigned int *fdev = headint32array(rpmhead, TAG_FILEDEVICES, &fszc);
820       unsigned int *fx, j;
821       unsigned int mask, hash, hh;
822       if (!fdev || fc != fszc)
823         {
824           solv_free(fsz);
825           solv_free(fm);
826           solv_free(fdev);
827           solv_free(fino);
828           return;
829         }
830       mask = fc;
831       while ((mask & (mask - 1)) != 0)
832         mask = mask & (mask - 1);
833       mask <<= 2;
834       if (mask > sizeof(inotest)/sizeof(*inotest))
835         fx = solv_calloc(mask, sizeof(unsigned int));
836       else
837         {
838           fx = inotest;
839           memset(fx, 0, mask * sizeof(unsigned int));
840         }
841       mask--;
842       for (i = 0; i < fc; i++)
843         {
844           if (fsz[i] == 0 || !S_ISREG(fm[i]))
845             continue;
846           hash = (fino[i] + fdev[i] * 31) & mask;
847           hh = 7;
848           while ((j = fx[hash]) != 0)
849             {
850               if (fino[j - 1] == fino[i] && fdev[j - 1] == fdev[i])
851                 {
852                   fsz[i] = 0;   /* kill entry */
853                   break;
854                 }
855               hash = (hash + hh++) & mask;
856             }
857           if (!j)
858             fx[hash] = i + 1;
859         }
860       if (fx != inotest)
861         solv_free(fx);
862       solv_free(fdev);
863     }
864   solv_free(fino);
865
866   /* sum up inode count and kbytes for each directory */
867   fn = solv_calloc(dc, sizeof(unsigned int));
868   fkb = solv_calloc(dc, sizeof(unsigned int));
869   for (i = 0; i < fc; i++)
870     {
871       if (di[i] >= dc)
872         continue;       /* corrupt entry */
873       fn[di[i]]++;
874       if (fsz[i] == 0 || !S_ISREG(fm[i]))
875         continue;
876       fkb[di[i]] += fsz[i];
877     }
878   solv_free(fsz);
879   solv_free(fm);
880   /* commit */
881   for (i = 0; i < dc; i++)
882     {
883       if (!fn[i])
884         continue;
885       if (dn[i][0] != '/')
886         {
887           Solvable *s = data->repo->pool->solvables + handle;
888           if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
889             did = repodata_str2dir(data, "/usr/src", 1);
890           else
891             did = repodata_str2dir_rooted(data, dn[i], 1);
892         }
893       else
894         did = repodata_str2dir(data, dn[i], 1);
895       repodata_add_dirnumnum(data, handle, SOLVABLE_DISKUSAGE, did, fkb[i], fn[i]);
896     }
897   solv_free(fn);
898   solv_free(fkb);
899 }
900
901 static int
902 is_filtered(const char *dir)
903 {
904   if (!dir)
905     return 1;
906   /* the dirs always have a trailing / in rpm */
907   if (strstr(dir, "bin/"))
908     return 0;
909   if (!strncmp(dir, "/etc/", 5))
910     return 0;
911   if (!strcmp(dir, "/usr/lib/"))
912     return 2;
913   return 1;
914 }
915
916 static void
917 addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags)
918 {
919   char **bn;
920   char **dn;
921   uint32_t *di;
922   int bnc, dnc, dic;
923   int i;
924   Id did;
925   uint32_t lastdii = -1;
926   int lastfiltered = 0;
927
928   if (!data)
929     return;
930   bn = headstringarray(rpmhead, TAG_BASENAMES, &bnc);
931   if (!bn)
932     return;
933   dn = headstringarray(rpmhead, TAG_DIRNAMES, &dnc);
934   if (!dn)
935     {
936       solv_free(bn);
937       return;
938     }
939   di = headint32array(rpmhead, TAG_DIRINDEXES, &dic);
940   if (!di)
941     {
942       solv_free(bn);
943       solv_free(dn);
944       return;
945     }
946   if (bnc != dic)
947     {
948       pool_error(data->repo->pool, 0, "bad filelist");
949       return;
950     }
951
952   adddudata(data, handle, rpmhead, dn, di, bnc, dnc);
953
954   did = -1;
955   for (i = 0; i < bnc; i++)
956     {
957       char *b = bn[i];
958
959       if (did < 0 || di[i] != lastdii)
960         {
961           if (di[i] >= dnc)
962             continue;   /* corrupt entry */
963           did = 0;
964           lastdii = di[i];
965           if ((flags & RPM_ADD_FILTERED_FILELIST) != 0)
966             {
967               lastfiltered = is_filtered(dn[di[i]]);
968               if (lastfiltered == 1)
969                 continue;
970             }
971           if (dn[lastdii][0] != '/')
972             did = repodata_str2dir_rooted(data, dn[lastdii], 1);
973           else
974             did = repodata_str2dir(data, dn[lastdii], 1);
975         }
976       if (!b)
977         continue;
978       if (*b == '/')    /* work around rpm bug */
979         b++;
980       if (lastfiltered && (lastfiltered != 2 || strcmp(b, "sendmail")))
981         continue;
982       repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, b);
983     }
984   solv_free(bn);
985   solv_free(dn);
986   solv_free(di);
987 }
988
989 static void
990 addchangelog(Repodata *data, Id handle, RpmHead *rpmhead)
991 {
992   char **cn;
993   char **cx;
994   uint32_t *ct;
995   int i, cnc, cxc, ctc;
996   Queue hq;
997
998   ct = headint32array(rpmhead, TAG_CHANGELOGTIME, &ctc);
999   cx = headstringarray(rpmhead, TAG_CHANGELOGTEXT, &cxc);
1000   cn = headstringarray(rpmhead, TAG_CHANGELOGNAME, &cnc);
1001   if (!ct || !cx || !cn || !ctc || ctc != cxc || ctc != cnc)
1002     {
1003       solv_free(ct);
1004       solv_free(cx);
1005       solv_free(cn);
1006       return;
1007     }
1008   queue_init(&hq);
1009   for (i = 0; i < ctc; i++)
1010     {
1011       Id h = repodata_new_handle(data);
1012       if (ct[i])
1013         repodata_set_num(data, h, SOLVABLE_CHANGELOG_TIME, ct[i]);
1014       if (cn[i])
1015         setutf8string(data, h, SOLVABLE_CHANGELOG_AUTHOR, cn[i]);
1016       if (cx[i])
1017         setutf8string(data, h, SOLVABLE_CHANGELOG_TEXT, cx[i]);
1018       queue_push(&hq, h);
1019     }
1020   for (i = 0; i < hq.count; i++)
1021     repodata_add_flexarray(data, handle, SOLVABLE_CHANGELOG, hq.elements[i]);
1022   queue_free(&hq);
1023   solv_free(ct);
1024   solv_free(cx);
1025   solv_free(cn);
1026 }
1027
1028 static void
1029 set_description_author(Repodata *data, Id handle, char *str)
1030 {
1031   char *aut, *p;
1032   for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++)
1033     if (!strncmp(aut, "\nAuthors:\n--------\n", 19))
1034       break;
1035   if (aut)
1036     {
1037       /* oh my, found SUSE special author section */
1038       int l = aut - str;
1039       str = solv_strdup(str);
1040       aut = str + l;
1041       str[l] = 0;
1042       while (l > 0 && str[l - 1] == '\n')
1043         str[--l] = 0;
1044       if (l)
1045         setutf8string(data, handle, SOLVABLE_DESCRIPTION, str);
1046       p = aut + 19;
1047       aut = str;        /* copy over */
1048       while (*p == ' ' || *p == '\n')
1049         p++;
1050       while (*p)
1051         {
1052           if (*p == '\n')
1053             {
1054               *aut++ = *p++;
1055               while (*p == ' ')
1056                 p++;
1057               continue;
1058             }
1059           *aut++ = *p++;
1060         }
1061       while (aut != str && aut[-1] == '\n')
1062         aut--;
1063       *aut = 0;
1064       if (*str)
1065         setutf8string(data, handle, SOLVABLE_AUTHORS, str);
1066       free(str);
1067     }
1068   else if (*str)
1069     setutf8string(data, handle, SOLVABLE_DESCRIPTION, str);
1070 }
1071
1072 static int
1073 rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags)
1074 {
1075   char *name;
1076   char *evr;
1077   char *sourcerpm;
1078   Queue ignq;
1079   Id ignqbuf[64];
1080
1081   name = headstring(rpmhead, TAG_NAME);
1082   if (!name)
1083     {
1084       pool_error(pool, 0, "package has no name");
1085       return 0;
1086     }
1087   if (!strcmp(name, "gpg-pubkey"))
1088     return 0;
1089   s->name = pool_str2id(pool, name, 1);
1090   sourcerpm = headstring(rpmhead, TAG_SOURCERPM);
1091   if (sourcerpm || !(headexists(rpmhead, TAG_SOURCEPACKAGE) || headissourceheuristic(rpmhead)))
1092     s->arch = pool_str2id(pool, headstring(rpmhead, TAG_ARCH), 1);
1093   else
1094     {
1095       if (headexists(rpmhead, TAG_NOSOURCE) || headexists(rpmhead, TAG_NOPATCH))
1096         s->arch = ARCH_NOSRC;
1097       else
1098         s->arch = ARCH_SRC;
1099     }
1100   if (!s->arch)
1101     s->arch = ARCH_NOARCH;
1102   evr = headtoevr(rpmhead);
1103   s->evr = pool_str2id(pool, evr, 1);
1104   s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1);
1105
1106   queue_init_buffer(&ignq, ignqbuf, sizeof(ignqbuf)/sizeof(*ignqbuf));
1107
1108   s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0, 0);
1109   if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
1110     s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
1111   s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags, &ignq);
1112   s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0, 0);
1113   s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0, 0);
1114
1115   s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0, 0);
1116   s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0, 0);
1117   s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0, 0);
1118   s->enhances  = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0, 0);
1119
1120   repo_rewrite_suse_deps(s, 0);
1121
1122   if (data && ignq.count)
1123     repodata_set_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, &ignq);
1124   queue_free(&ignq);
1125
1126   if (data)
1127     {
1128       Id handle;
1129       char *str;
1130       unsigned int u32;
1131       unsigned long long u64;
1132
1133       handle = s - pool->solvables;
1134       str = headstring(rpmhead, TAG_SUMMARY);
1135       if (str)
1136         setutf8string(data, handle, SOLVABLE_SUMMARY, str);
1137       str = headstring(rpmhead, TAG_DESCRIPTION);
1138       if (str)
1139         set_description_author(data, handle, str);
1140       str = headstring(rpmhead, TAG_GROUP);
1141       if (str)
1142         repodata_set_poolstr(data, handle, SOLVABLE_GROUP, str);
1143       str = headstring(rpmhead, TAG_LICENSE);
1144       if (str)
1145         repodata_set_poolstr(data, handle, SOLVABLE_LICENSE, str);
1146       str = headstring(rpmhead, TAG_URL);
1147       if (str)
1148         repodata_set_str(data, handle, SOLVABLE_URL, str);
1149       str = headstring(rpmhead, TAG_DISTRIBUTION);
1150       if (str)
1151         repodata_set_poolstr(data, handle, SOLVABLE_DISTRIBUTION, str);
1152       str = headstring(rpmhead, TAG_PACKAGER);
1153       if (str)
1154         repodata_set_poolstr(data, handle, SOLVABLE_PACKAGER, str);
1155       if ((flags & RPM_ADD_WITH_PKGID) != 0)
1156         {
1157           unsigned char *chksum;
1158           unsigned int chksumsize;
1159           chksum = headbinary(rpmhead, TAG_SIGMD5, &chksumsize);
1160           if (chksum && chksumsize == 16)
1161             repodata_set_bin_checksum(data, handle, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, chksum);
1162         }
1163       if ((flags & RPM_ADD_WITH_HDRID) != 0)
1164         {
1165           str = headstring(rpmhead, TAG_SHA1HEADER);
1166           if (str && strlen(str) == 40)
1167             repodata_set_checksum(data, handle, SOLVABLE_HDRID, REPOKEY_TYPE_SHA1, str);
1168           else if (str && strlen(str) == 64)
1169             repodata_set_checksum(data, handle, SOLVABLE_HDRID, REPOKEY_TYPE_SHA256, str);
1170         }
1171       u32 = headint32(rpmhead, TAG_BUILDTIME);
1172       if (u32)
1173         repodata_set_num(data, handle, SOLVABLE_BUILDTIME, u32);
1174       u32 = headint32(rpmhead, TAG_INSTALLTIME);
1175       if (u32)
1176         repodata_set_num(data, handle, SOLVABLE_INSTALLTIME, u32);
1177       u64 = headint64(rpmhead, TAG_LONGSIZE);
1178       if (u64)
1179         repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, u64);
1180       else
1181         {
1182           u32 = headint32(rpmhead, TAG_SIZE);
1183           if (u32)
1184             repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, u32);
1185         }
1186       if (sourcerpm)
1187         repodata_set_sourcepkg(data, handle, sourcerpm);
1188       if ((flags & RPM_ADD_TRIGGERS) != 0)
1189         {
1190           unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0, 0);
1191           Id id, lastid = 0;
1192           for (lastid = 0; (id = repo->idarraydata[ida]) != 0; ida++, lastid = id)
1193             if (id != lastid)
1194               repodata_add_idarray(data, handle, SOLVABLE_TRIGGERS, id);
1195         }
1196       if ((flags & RPM_ADD_NO_FILELIST) == 0)
1197         addfilelist(data, handle, rpmhead, flags);
1198       if ((flags & RPM_ADD_WITH_CHANGELOG) != 0)
1199         addchangelog(data, handle, rpmhead);
1200     }
1201   solv_free(evr);
1202   return 1;
1203 }
1204
1205 static inline unsigned int
1206 getu32(const unsigned char *dp)
1207 {
1208   return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3];
1209 }
1210
1211 #ifdef ENABLE_RPMDB
1212
1213 struct rpmdbentry {
1214   Id rpmdbid;
1215   Id nameoff;
1216 };
1217
1218 #define ENTRIES_BLOCK 255
1219 #define NAMEDATA_BLOCK 1023
1220
1221 # ifdef ENABLE_RPMDB_LIBRPM
1222 #  include "repo_rpmdb_librpm.h"
1223 # else
1224 #  include "repo_rpmdb_bdb.h"
1225 # endif
1226
1227 #else
1228
1229 /* dummy state just to store pool/rootdir and header data */
1230 struct rpmdbstate {
1231   Pool *pool;
1232   char *rootdir;
1233
1234   RpmHead *rpmhead;     /* header storage space */
1235   int rpmheadsize;
1236 };
1237
1238 #endif
1239
1240
1241 #ifndef ENABLE_RPMPKG_LIBRPM
1242
1243 static int
1244 headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2)
1245 {
1246   RpmHead *rpmhead;
1247   unsigned int len = 16 * cnt + dsize + pad;
1248   if (len + 1 > state->rpmheadsize)
1249     {
1250       state->rpmheadsize = len + 128;
1251       state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
1252     }
1253   rpmhead = state->rpmhead;
1254   if (fread(rpmhead->data, len, 1, fp) != 1)
1255     {
1256       fclose(fp);
1257       return pool_error(state->pool, 0, "%s: unexpected EOF", name);
1258     }
1259   if (chk1)
1260     solv_chksum_add(chk1, rpmhead->data, len);
1261   if (chk2)
1262     solv_chksum_add(chk2, rpmhead->data, len);
1263   rpmhead->data[len] = 0;
1264   rpmhead->cnt = cnt;
1265   rpmhead->dcnt = dsize;
1266   rpmhead->dp = rpmhead->data + cnt * 16;
1267   return 1;
1268 }
1269
1270 #if defined(ENABLE_RPMDB_BYRPMHEADER)
1271 static void
1272 headfromblob(struct rpmdbstate *state, const unsigned char *blob, unsigned int cnt, unsigned int dsize)
1273 {
1274   RpmHead *rpmhead;
1275   unsigned int len = 16 * cnt + dsize;
1276   if (len + 1 > state->rpmheadsize)
1277     {
1278       state->rpmheadsize = len + 128;
1279       state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
1280     }
1281   rpmhead = state->rpmhead;
1282   memcpy(rpmhead->data, blob, len);
1283   rpmhead->data[len] = 0;
1284   rpmhead->cnt = cnt;
1285   rpmhead->dcnt = dsize;
1286   rpmhead->dp = rpmhead->data + cnt * 16;
1287 }
1288 #endif
1289
1290 #else
1291
1292 static int
1293 headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2)
1294 {
1295   unsigned int len = 16 * cnt + dsize + pad;
1296   char *buf = solv_malloc(8 + len);
1297   Header h;
1298   memcpy(buf, lead + 8, 8);
1299   if (fread(buf + 8, len, 1, fp) != 1)
1300     {
1301       solv_free(buf);
1302       return pool_error(state->pool, 0, "%s: unexpected EOF", name);
1303     }
1304   if (chk1)
1305     solv_chksum_add(chk1, buf + 8, len);
1306   if (chk2)
1307     solv_chksum_add(chk2, buf + 8, len);
1308   h = headerImport(buf, 8 + len - pad, HEADERIMPORT_FAST);
1309   if (!h)
1310     {
1311       solv_free(buf);
1312       return pool_error(state->pool, 0, "%s: headerImport error", name);
1313     }
1314   if (state->rpmhead)
1315     headfree(state->rpmhead);
1316   state->rpmhead = h;
1317   return 1;
1318 }
1319
1320 #endif
1321
1322 static void
1323 freestate(struct rpmdbstate *state)
1324 {
1325   /* close down */
1326 #ifdef ENABLE_RPMDB
1327   if (state->pkgdbopened)
1328     closepkgdb(state);
1329   if (state->dbenvopened)
1330     closedbenv(state);
1331 #endif
1332   if (state->rootdir)
1333     solv_free(state->rootdir);
1334   headfree(state->rpmhead);
1335 }
1336
1337 void *
1338 rpm_state_create(Pool *pool, const char *rootdir)
1339 {
1340   struct rpmdbstate *state;
1341   state = solv_calloc(1, sizeof(*state));
1342   state->pool = pool;
1343   if (rootdir)
1344     state->rootdir = solv_strdup(rootdir);
1345   return state;
1346 }
1347
1348 void *
1349 rpm_state_free(void *state)
1350 {
1351   if (state)
1352     freestate(state);
1353   return solv_free(state);
1354 }
1355
1356
1357 #ifdef ENABLE_RPMDB
1358
1359
1360 /******************************************************************/
1361
1362 static Offset
1363 copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
1364 {
1365   int cc;
1366   Id *ida, *from;
1367   Offset ido;
1368
1369   if (!fromoff)
1370     return 0;
1371   from = fromrepo->idarraydata + fromoff;
1372   for (ida = from, cc = 0; *ida; ida++, cc++)
1373     ;
1374   if (cc == 0)
1375     return 0;
1376   ido = repo_reserve_ids(repo, 0, cc);
1377   ida = repo->idarraydata + ido;
1378   memcpy(ida, from, (cc + 1) * sizeof(Id));
1379   repo->idarraysize += cc + 1;
1380   return ido;
1381 }
1382
1383 #define COPYDIR_DIRCACHE_SIZE 512
1384
1385 static Id copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache);
1386
1387 static inline Id
1388 copydir(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache)
1389 {
1390   if (cache && did && cache[did & 255] == did)
1391     return cache[(did & 255) + 256];
1392   return copydir_complex(pool, data, fromdata, did, cache);
1393 }
1394
1395 static Id
1396 copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache)
1397 {
1398   Id parent, compid;
1399   if (!did)
1400     {
1401       /* make sure that the dirpool has an entry */
1402       if (!data->dirpool.ndirs)
1403         dirpool_add_dir(&data->dirpool, 0, 0, 1);
1404       return 0;
1405     }
1406   parent = dirpool_parent(&fromdata->dirpool, did);
1407   compid = dirpool_compid(&fromdata->dirpool, did);
1408   if (parent)
1409     parent = copydir(pool, data, fromdata, parent, cache);
1410   if (data->localpool || fromdata->localpool)
1411     compid = repodata_translate_id(data, fromdata, compid, 1);
1412   compid = dirpool_add_dir(&data->dirpool, parent, compid, 1);
1413   if (cache)
1414     {
1415       cache[did & 255] = did;
1416       cache[(did & 255) + 256] = compid;
1417     }
1418   return compid;
1419 }
1420
1421 struct solvable_copy_cbdata {
1422   Repodata *data;
1423   Id handle;
1424   Id subhandle;
1425   Id *dircache;
1426 };
1427
1428 static int
1429 solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, KeyValue *kv)
1430 {
1431   struct solvable_copy_cbdata *cbdata = vcbdata;
1432   Id id, keyname;
1433   Repodata *data = cbdata->data;
1434   Id handle = cbdata->handle;
1435   Pool *pool = data->repo->pool;
1436
1437   keyname = key->name;
1438   switch(key->type)
1439     {
1440     case REPOKEY_TYPE_ID:
1441     case REPOKEY_TYPE_CONSTANTID:
1442     case REPOKEY_TYPE_IDARRAY:  /* used for triggers */
1443       id = kv->id;
1444       if (data->localpool || fromdata->localpool)
1445         id = repodata_translate_id(data, fromdata, id, 1);
1446       if (key->type == REPOKEY_TYPE_ID)
1447         repodata_set_id(data, handle, keyname, id);
1448       else if (key->type == REPOKEY_TYPE_CONSTANTID)
1449         repodata_set_constantid(data, handle, keyname, id);
1450       else
1451         repodata_add_idarray(data, handle, keyname, id);
1452       break;
1453     case REPOKEY_TYPE_STR:
1454       repodata_set_str(data, handle, keyname, kv->str);
1455       break;
1456     case REPOKEY_TYPE_VOID:
1457       repodata_set_void(data, handle, keyname);
1458       break;
1459     case REPOKEY_TYPE_NUM:
1460       repodata_set_num(data, handle, keyname, SOLV_KV_NUM64(kv));
1461       break;
1462     case REPOKEY_TYPE_CONSTANT:
1463       repodata_set_constant(data, handle, keyname, kv->num);
1464       break;
1465     case REPOKEY_TYPE_DIRNUMNUMARRAY:
1466       id = kv->id;
1467       id = copydir(pool, data, fromdata, id, cbdata->dircache);
1468       if (id)
1469         repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2);
1470       break;
1471     case REPOKEY_TYPE_DIRSTRARRAY:
1472       id = kv->id;
1473       id = copydir(pool, data, fromdata, id, cbdata->dircache);
1474       if (id)
1475         repodata_add_dirstr(data, handle, keyname, id, kv->str);
1476       break;
1477     case REPOKEY_TYPE_FLEXARRAY:
1478       if (kv->eof == 2)
1479         {
1480           assert(cbdata->subhandle);
1481           cbdata->handle = cbdata->subhandle;
1482           cbdata->subhandle = 0;
1483           break;
1484         }
1485       if (!kv->entry)
1486         {
1487           assert(!cbdata->subhandle);
1488           cbdata->subhandle = cbdata->handle;
1489         }
1490       cbdata->handle = repodata_new_handle(data);
1491       repodata_add_flexarray(data, cbdata->subhandle, keyname, cbdata->handle);
1492       break;
1493     default:
1494       if (solv_chksum_len(key->type))
1495         {
1496           repodata_set_bin_checksum(data, handle, keyname, key->type, (const unsigned char *)kv->str);
1497           break;
1498         }
1499       break;
1500     }
1501   return 0;
1502 }
1503
1504 static void
1505 solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
1506 {
1507   int p, i;
1508   Repo *repo = s->repo;
1509   Pool *pool = repo->pool;
1510   Repo *fromrepo = r->repo;
1511   struct solvable_copy_cbdata cbdata;
1512
1513   /* copy solvable data */
1514   s->name = r->name;
1515   s->evr = r->evr;
1516   s->arch = r->arch;
1517   s->vendor = r->vendor;
1518   s->provides = copydeps(pool, repo, r->provides, fromrepo);
1519   s->requires = copydeps(pool, repo, r->requires, fromrepo);
1520   s->conflicts = copydeps(pool, repo, r->conflicts, fromrepo);
1521   s->obsoletes = copydeps(pool, repo, r->obsoletes, fromrepo);
1522   s->recommends = copydeps(pool, repo, r->recommends, fromrepo);
1523   s->suggests = copydeps(pool, repo, r->suggests, fromrepo);
1524   s->supplements = copydeps(pool, repo, r->supplements, fromrepo);
1525   s->enhances  = copydeps(pool, repo, r->enhances, fromrepo);
1526
1527   /* copy all attributes */
1528   if (!data)
1529     return;
1530   cbdata.data = data;
1531   cbdata.handle = s - pool->solvables;
1532   cbdata.subhandle = 0;
1533   cbdata.dircache = dircache;
1534   p = r - fromrepo->pool->solvables;
1535 #if 0
1536   repo_search(fromrepo, p, 0, 0, SEARCH_NO_STORAGE_SOLVABLE | SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
1537 #else
1538   FOR_REPODATAS(fromrepo, i, data)
1539     {
1540       if (p >= data->start && p < data->end)
1541         repodata_search(data, p, 0, SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
1542       cbdata.dircache = 0;      /* only for first repodata */
1543     }
1544 #endif
1545 }
1546
1547 /* used to sort entries by package name that got returned in some database order */
1548 static int
1549 rpmids_sort_cmp(const void *va, const void *vb, void *dp)
1550 {
1551   struct rpmdbentry const *a = va, *b = vb;
1552   char *namedata = dp;
1553   int r;
1554   r = strcmp(namedata + a->nameoff, namedata + b->nameoff);
1555   if (r)
1556     return r;
1557   return a->rpmdbid - b->rpmdbid;
1558 }
1559
1560 static int
1561 pkgids_sort_cmp(const void *va, const void *vb, void *dp)
1562 {
1563   Repo *repo = dp;
1564   Pool *pool = repo->pool;
1565   Solvable *a = pool->solvables + *(Id *)va;
1566   Solvable *b = pool->solvables + *(Id *)vb;
1567   Id *rpmdbid;
1568
1569   if (a->name != b->name)
1570     return strcmp(pool_id2str(pool, a->name), pool_id2str(pool, b->name));
1571   rpmdbid = repo->rpmdbid;
1572   return rpmdbid[(a - pool->solvables) - repo->start] - rpmdbid[(b - pool->solvables) - repo->start];
1573 }
1574
1575 static void
1576 swap_solvables(Repo *repo, Repodata *data, Id pa, Id pb)
1577 {
1578   Pool *pool = repo->pool;
1579   Solvable tmp;
1580
1581   tmp = pool->solvables[pa];
1582   pool->solvables[pa] = pool->solvables[pb];
1583   pool->solvables[pb] = tmp;
1584   if (repo->rpmdbid)
1585     {
1586       Id tmpid = repo->rpmdbid[pa - repo->start];
1587       repo->rpmdbid[pa - repo->start] = repo->rpmdbid[pb - repo->start];
1588       repo->rpmdbid[pb - repo->start] = tmpid;
1589     }
1590   /* only works if nothing is already internalized! */
1591   if (data)
1592     repodata_swap_attrs(data, pa, pb);
1593 }
1594
1595 static void
1596 mkrpmdbcookie(struct stat *st, unsigned char *cookie, int flags)
1597 {
1598   int f = 0;
1599   memset(cookie, 0, 32);
1600   cookie[3] = RPMDB_COOKIE_VERSION;
1601   memcpy(cookie + 16, &st->st_ino, sizeof(st->st_ino));
1602   memcpy(cookie + 24, &st->st_dev, sizeof(st->st_dev));
1603   if ((flags & RPM_ADD_WITH_PKGID) != 0)
1604     f |= 1;
1605   if ((flags & RPM_ADD_WITH_HDRID) != 0)
1606     f |= 2;
1607   if ((flags & RPM_ADD_WITH_CHANGELOG) != 0)
1608     f |= 4;
1609   if ((flags & RPM_ADD_NO_FILELIST) == 0)
1610     f |= 8;
1611   if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0)
1612     cookie[1] = 1;
1613   cookie[0] = f;
1614 }
1615
1616 /*
1617  * read rpm db as repo
1618  *
1619  */
1620
1621 int
1622 repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
1623 {
1624   Pool *pool = repo->pool;
1625   struct stat packagesstat;
1626   unsigned char newcookie[32];
1627   const unsigned char *oldcookie = 0;
1628   Id oldcookietype = 0;
1629   Repodata *data;
1630   int count = 0, done = 0;
1631   struct rpmdbstate state;
1632   int i;
1633   Solvable *s;
1634   unsigned int now;
1635
1636   now = solv_timems(0);
1637   memset(&state, 0, sizeof(state));
1638   state.pool = pool;
1639   if (flags & REPO_USE_ROOTDIR)
1640     state.rootdir = solv_strdup(pool_get_rootdir(pool));
1641
1642   data = repo_add_repodata(repo, flags);
1643
1644   if (ref && !(ref->nsolvables && ref->rpmdbid && ref->pool == repo->pool))
1645     {
1646       if ((flags & RPMDB_EMPTY_REFREPO) != 0)
1647         repo_empty(ref, 1);
1648       ref = 0;
1649     }
1650
1651   if (!opendbenv(&state))
1652     {
1653       solv_free(state.rootdir);
1654       return -1;
1655     }
1656
1657   /* XXX: should get ro lock of Packages database! */
1658   if (stat_database(&state, "Packages", &packagesstat, 1))
1659     {
1660       freestate(&state);
1661       return -1;
1662     }
1663   mkrpmdbcookie(&packagesstat, newcookie, flags);
1664   repodata_set_bin_checksum(data, SOLVID_META, REPOSITORY_RPMDBCOOKIE, REPOKEY_TYPE_SHA256, newcookie);
1665
1666   if (ref)
1667     oldcookie = repo_lookup_bin_checksum(ref, SOLVID_META, REPOSITORY_RPMDBCOOKIE, &oldcookietype);
1668   if (!ref || !oldcookie || oldcookietype != REPOKEY_TYPE_SHA256 || memcmp(oldcookie, newcookie, 32) != 0)
1669     {
1670       int solvstart = 0, solvend = 0;
1671       Id dbid;
1672
1673       if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
1674         repo_empty(ref, 1);     /* get it out of the way */
1675       if ((flags & RPMDB_REPORT_PROGRESS) != 0)
1676         count = count_headers(&state);
1677       if (!openpkgdb(&state))
1678         {
1679           freestate(&state);
1680           return -1;
1681         }
1682       if (pkgdb_cursor_open(&state))
1683         {
1684           freestate(&state);
1685           return -1;
1686         }
1687       i = 0;
1688       s = 0;
1689       while ((dbid = pkgdb_cursor_getrpm(&state)) != 0)
1690         {
1691           if (dbid == -1)
1692             {
1693               pkgdb_cursor_close(&state);
1694               freestate(&state);
1695               return -1;
1696             }
1697           if (!s)
1698             {
1699               s = pool_id2solvable(pool, repo_add_solvable(repo));
1700               if (!solvstart)
1701                 solvstart = s - pool->solvables;
1702               solvend = s - pool->solvables + 1;
1703             }
1704           if (!repo->rpmdbid)
1705             repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
1706           repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid;
1707           if (rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS))
1708             {
1709               i++;
1710               s = 0;
1711             }
1712           else
1713             {
1714               /* We can reuse this solvable, but make sure it's still
1715                  associated with this repo.  */
1716               memset(s, 0, sizeof(*s));
1717               s->repo = repo;
1718             }
1719           if ((flags & RPMDB_REPORT_PROGRESS) != 0)
1720             {
1721               if (done < count)
1722                 done++;
1723               if (done < count && (done - 1) * 100 / count != done * 100 / count)
1724                 pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count);
1725             }
1726         }
1727       pkgdb_cursor_close(&state);
1728       if (s)
1729         {
1730           /* oops, could not reuse. free it instead */
1731           repo_free_solvable(repo, s - pool->solvables, 1);
1732           solvend--;
1733           s = 0;
1734         }
1735       /* now sort all solvables in the new solvstart..solvend block */
1736       if (solvend - solvstart > 1)
1737         {
1738           Id *pkgids = solv_malloc2(solvend - solvstart, sizeof(Id));
1739           for (i = solvstart; i < solvend; i++)
1740             pkgids[i - solvstart] = i;
1741           solv_sort(pkgids, solvend - solvstart, sizeof(Id), pkgids_sort_cmp, repo);
1742           /* adapt order */
1743           for (i = solvstart; i < solvend; i++)
1744             {
1745               int j = pkgids[i - solvstart];
1746               while (j < i)
1747                 j = pkgids[i - solvstart] = pkgids[j - solvstart];
1748               if (j != i)
1749                 swap_solvables(repo, data, i, j);
1750             }
1751           solv_free(pkgids);
1752         }
1753     }
1754   else
1755     {
1756       Id dircache[COPYDIR_DIRCACHE_SIZE];               /* see copydir */
1757       struct rpmdbentry *entries = 0, *rp;
1758       int nentries = 0;
1759       char *namedata = 0;
1760       unsigned int refmask, h;
1761       Id id, *refhash;
1762       int res;
1763
1764       memset(dircache, 0, sizeof(dircache));
1765
1766       /* get ids of installed rpms */
1767       entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata);
1768       if (!entries)
1769         {
1770           freestate(&state);
1771           return -1;
1772         }
1773
1774       /* sort by name */
1775       if (nentries > 1)
1776         solv_sort(entries, nentries, sizeof(*entries), rpmids_sort_cmp, namedata);
1777
1778       /* create hash from dbid to ref */
1779       refmask = mkmask(ref->nsolvables);
1780       refhash = solv_calloc(refmask + 1, sizeof(Id));
1781       for (i = 0; i < ref->end - ref->start; i++)
1782         {
1783           if (!ref->rpmdbid[i])
1784             continue;
1785           h = ref->rpmdbid[i] & refmask;
1786           while (refhash[h])
1787             h = (h + 317) & refmask;
1788           refhash[h] = i + 1;   /* make it non-zero */
1789         }
1790
1791       /* count the misses, they will cost us time */
1792       if ((flags & RPMDB_REPORT_PROGRESS) != 0)
1793         {
1794           for (i = 0, rp = entries; i < nentries; i++, rp++)
1795             {
1796               if (refhash)
1797                 {
1798                   Id dbid = rp->rpmdbid;
1799                   h = dbid & refmask;
1800                   while ((id = refhash[h]))
1801                     {
1802                       if (ref->rpmdbid[id - 1] == dbid)
1803                         break;
1804                       h = (h + 317) & refmask;
1805                     }
1806                   if (id)
1807                     continue;
1808                 }
1809               count++;
1810             }
1811         }
1812
1813       if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
1814         s = pool_id2solvable(pool, repo_add_solvable_block_before(repo, nentries, ref));
1815       else
1816         s = pool_id2solvable(pool, repo_add_solvable_block(repo, nentries));
1817       if (!repo->rpmdbid)
1818         repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
1819
1820       for (i = 0, rp = entries; i < nentries; i++, rp++, s++)
1821         {
1822           Id dbid = rp->rpmdbid;
1823           repo->rpmdbid[(s - pool->solvables) - repo->start] = rp->rpmdbid;
1824           if (refhash)
1825             {
1826               h = dbid & refmask;
1827               while ((id = refhash[h]))
1828                 {
1829                   if (ref->rpmdbid[id - 1] == dbid)
1830                     break;
1831                   h = (h + 317) & refmask;
1832                 }
1833               if (id)
1834                 {
1835                   Solvable *r = ref->pool->solvables + ref->start + (id - 1);
1836                   if (r->repo == ref)
1837                     {
1838                       solvable_copy(s, r, data, dircache);
1839                       continue;
1840                     }
1841                 }
1842             }
1843           res = getrpm_dbid(&state, dbid);
1844           if (res <= 0)
1845             {
1846               if (!res)
1847                 pool_error(pool, -1, "inconsistent rpm database, key %d not found. run 'rpm --rebuilddb' to fix.", dbid);
1848               freestate(&state);
1849               solv_free(entries);
1850               solv_free(namedata);
1851               solv_free(refhash);
1852               return -1;
1853             }
1854           rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS);
1855           if ((flags & RPMDB_REPORT_PROGRESS) != 0)
1856             {
1857               if (done < count)
1858                 done++;
1859               if (done < count && (done - 1) * 100 / count != done * 100 / count)
1860                 pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count);
1861             }
1862         }
1863
1864       solv_free(entries);
1865       solv_free(namedata);
1866       solv_free(refhash);
1867       if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
1868         repo_empty(ref, 1);
1869     }
1870
1871   freestate(&state);
1872   if (!(flags & REPO_NO_INTERNALIZE))
1873     repodata_internalize(data);
1874   if ((flags & RPMDB_REPORT_PROGRESS) != 0)
1875     pool_debug(pool, SOLV_ERROR, "%%%% 100\n");
1876   POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_rpmdb took %d ms\n", solv_timems(now));
1877   POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
1878   POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", repodata_memused(data)/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
1879   return 0;
1880 }
1881
1882 int
1883 repo_add_rpmdb_reffp(Repo *repo, FILE *fp, int flags)
1884 {
1885   int res;
1886   Repo *ref = 0;
1887
1888   if (!fp)
1889     return repo_add_rpmdb(repo, 0, flags);
1890   ref = repo_create(repo->pool, "add_rpmdb_reffp");
1891   if (repo_add_solv(ref, fp, 0) != 0)
1892     {
1893       repo_free(ref, 1);
1894       ref = 0;
1895     }
1896   if (ref && ref->start == ref->end)
1897     {
1898       repo_free(ref, 1);
1899       ref = 0;
1900     }
1901   if (ref)
1902     repo_disable_paging(ref);
1903   res = repo_add_rpmdb(repo, ref, flags | RPMDB_EMPTY_REFREPO);
1904   if (ref)
1905     repo_free(ref, 1);
1906   return res;
1907 }
1908
1909 #endif  /* ENABLE_RPMDB */
1910
1911 Id
1912 repo_add_rpm(Repo *repo, const char *rpm, int flags)
1913 {
1914   unsigned int sigdsize, sigcnt, sigpad, l;
1915   Pool *pool = repo->pool;
1916   Solvable *s;
1917   struct rpmdbstate state;
1918   char *payloadformat;
1919   FILE *fp;
1920   unsigned char lead[4096];
1921   int headerstart, headerend;
1922   struct stat stb;
1923   Repodata *data;
1924   unsigned char pkgid[16];
1925   unsigned char leadsigid[16];
1926   unsigned char hdrid[32];
1927   int pkgidtype, leadsigidtype, hdridtype;
1928   Id chksumtype = 0;
1929   Chksum *chksumh = 0;
1930   Chksum *leadsigchksumh = 0;
1931
1932   data = repo_add_repodata(repo, flags);
1933
1934   if ((flags & RPM_ADD_WITH_SHA256SUM) != 0)
1935     chksumtype = REPOKEY_TYPE_SHA256;
1936   else if ((flags & RPM_ADD_WITH_SHA1SUM) != 0)
1937     chksumtype = REPOKEY_TYPE_SHA1;
1938
1939   /* open rpm */
1940   if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, rpm) : rpm, "r")) == 0)
1941     {
1942       pool_error(pool, -1, "%s: %s", rpm, strerror(errno));
1943       return 0;
1944     }
1945   if (fstat(fileno(fp), &stb))
1946     {
1947       pool_error(pool, -1, "fstat: %s", strerror(errno));
1948       fclose(fp);
1949       return 0;
1950     }
1951
1952   /* setup state */
1953   memset(&state, 0, sizeof(state));
1954   state.pool = pool;
1955
1956   /* process lead */
1957   if (chksumtype)
1958     chksumh = solv_chksum_create(chksumtype);
1959   if ((flags & RPM_ADD_WITH_LEADSIGID) != 0)
1960     leadsigchksumh = solv_chksum_create(REPOKEY_TYPE_MD5);
1961   if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
1962     {
1963       pool_error(pool, -1, "%s: not a rpm", rpm);
1964       fclose(fp);
1965       return 0;
1966     }
1967   if (chksumh)
1968     solv_chksum_add(chksumh, lead, 96 + 16);
1969   if (leadsigchksumh)
1970     solv_chksum_add(leadsigchksumh, lead, 96 + 16);
1971
1972   /* process signature header */
1973   if (lead[78] != 0 || lead[79] != 5)
1974     {
1975       pool_error(pool, -1, "%s: not a rpm v5 header", rpm);
1976       fclose(fp);
1977       return 0;
1978     }
1979   if (getu32(lead + 96) != 0x8eade801)
1980     {
1981       pool_error(pool, -1, "%s: bad signature header", rpm);
1982       fclose(fp);
1983       return 0;
1984     }
1985   sigcnt = getu32(lead + 96 + 8);
1986   sigdsize = getu32(lead + 96 + 12);
1987   if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
1988     {
1989       pool_error(pool, -1, "%s: bad signature header", rpm);
1990       fclose(fp);
1991       return 0;
1992     }
1993   sigpad = sigdsize & 7 ? 8 - (sigdsize & 7) : 0;
1994   headerstart = 96 + 16 + sigcnt * 16 + sigdsize + sigpad;
1995   pkgidtype = leadsigidtype = hdridtype = 0;
1996   if ((flags & (RPM_ADD_WITH_PKGID | RPM_ADD_WITH_HDRID)) != 0)
1997     {
1998       if (!headfromfp(&state, rpm, fp, lead + 96, sigcnt, sigdsize, sigpad, chksumh, leadsigchksumh))
1999         {
2000           fclose(fp);
2001           return 0;
2002         }
2003       if ((flags & RPM_ADD_WITH_PKGID) != 0)
2004         {
2005           unsigned char *chksum;
2006           unsigned int chksumsize;
2007           chksum = headbinary(state.rpmhead, SIGTAG_MD5, &chksumsize);
2008           if (chksum && chksumsize == 16)
2009             {
2010               pkgidtype = REPOKEY_TYPE_MD5;
2011               memcpy(pkgid, chksum, 16);
2012             }
2013         }
2014       if ((flags & RPM_ADD_WITH_HDRID) != 0)
2015         {
2016           const char *str = headstring(state.rpmhead, TAG_SHA1HEADER);
2017           if (str && strlen(str) == 40)
2018             {
2019               if (solv_hex2bin(&str, hdrid, 20) == 20)
2020                 hdridtype = REPOKEY_TYPE_SHA1;
2021             }
2022           else if (str && strlen(str) == 64)
2023             {
2024               if (solv_hex2bin(&str, hdrid, 32) == 32)
2025                 hdridtype = REPOKEY_TYPE_SHA256;
2026             }
2027         }
2028     }
2029   else
2030     {
2031       /* just skip the signature header */
2032       unsigned int len = sigcnt * 16 + sigdsize + sigpad;
2033       while (len)
2034         {
2035           l = len > 4096 ? 4096 : len;
2036           if (fread(lead, l, 1, fp) != 1)
2037             {
2038               pool_error(pool, -1, "%s: unexpected EOF", rpm);
2039               fclose(fp);
2040               return 0;
2041             }
2042           if (chksumh)
2043             solv_chksum_add(chksumh, lead, l);
2044           if (leadsigchksumh)
2045             solv_chksum_add(leadsigchksumh, lead, l);
2046           len -= l;
2047         }
2048     }
2049   if (leadsigchksumh)
2050     {
2051       leadsigchksumh = solv_chksum_free(leadsigchksumh, leadsigid);
2052       leadsigidtype = REPOKEY_TYPE_MD5;
2053     }
2054
2055   /* process main header */
2056   if (fread(lead, 16, 1, fp) != 1)
2057     {
2058       pool_error(pool, -1, "%s: unexpected EOF", rpm);
2059       fclose(fp);
2060       return 0;
2061     }
2062   if (chksumh)
2063     solv_chksum_add(chksumh, lead, 16);
2064   if (getu32(lead) != 0x8eade801)
2065     {
2066       pool_error(pool, -1, "%s: bad header", rpm);
2067       fclose(fp);
2068       return 0;
2069     }
2070   sigcnt = getu32(lead + 8);
2071   sigdsize = getu32(lead + 12);
2072   if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
2073     {
2074       pool_error(pool, -1, "%s: bad header", rpm);
2075       fclose(fp);
2076       return 0;
2077     }
2078   headerend = headerstart + 16 + sigdsize + sigcnt * 16;
2079
2080   if (!headfromfp(&state, rpm, fp, lead, sigcnt, sigdsize, 0, chksumh, 0))
2081     {
2082       fclose(fp);
2083       return 0;
2084     }
2085   if (headexists(state.rpmhead, TAG_PATCHESNAME))
2086     {
2087       /* this is a patch rpm, ignore */
2088       pool_error(pool, -1, "%s: is patch rpm", rpm);
2089       fclose(fp);
2090       solv_chksum_free(chksumh, 0);
2091       headfree(state.rpmhead);
2092       return 0;
2093     }
2094   payloadformat = headstring(state.rpmhead, TAG_PAYLOADFORMAT);
2095   if (payloadformat && !strcmp(payloadformat, "drpm"))
2096     {
2097       /* this is a delta rpm */
2098       pool_error(pool, -1, "%s: is delta rpm", rpm);
2099       fclose(fp);
2100       solv_chksum_free(chksumh, 0);
2101       headfree(state.rpmhead);
2102       return 0;
2103     }
2104   if (chksumh)
2105     while ((l = fread(lead, 1, sizeof(lead), fp)) > 0)
2106       solv_chksum_add(chksumh, lead, l);
2107   fclose(fp);
2108   s = pool_id2solvable(pool, repo_add_solvable(repo));
2109   if (!rpmhead2solv(pool, repo, data, s, state.rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
2110     {
2111       repo_free_solvable(repo, s - pool->solvables, 1);
2112       solv_chksum_free(chksumh, 0);
2113       headfree(state.rpmhead);
2114       return 0;
2115     }
2116   if (!(flags & REPO_NO_LOCATION))
2117     repodata_set_location(data, s - pool->solvables, 0, 0, rpm);
2118   if (S_ISREG(stb.st_mode))
2119     repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
2120   repodata_set_num(data, s - pool->solvables, SOLVABLE_HEADEREND, headerend);
2121   if (pkgidtype)
2122     repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, pkgidtype, pkgid);
2123   if (hdridtype)
2124     repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_HDRID, hdridtype, hdrid);
2125   if (leadsigidtype)
2126     repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_LEADSIGID, leadsigidtype, leadsigid);
2127   if (chksumh)
2128     {
2129       repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, chksumtype, solv_chksum_get(chksumh, 0));
2130       chksumh = solv_chksum_free(chksumh, 0);
2131     }
2132   headfree(state.rpmhead);
2133   if (!(flags & REPO_NO_INTERNALIZE))
2134     repodata_internalize(data);
2135   return s - pool->solvables;
2136 }
2137
2138 Id
2139 repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags)
2140 {
2141   Pool *pool = repo->pool;
2142   Repodata *data;
2143   RpmHead *rpmhead = rpmhandle;
2144   Solvable *s;
2145   char *payloadformat;
2146
2147   data = repo_add_repodata(repo, flags);
2148   if (headexists(rpmhead, TAG_PATCHESNAME))
2149     {
2150       pool_error(pool, -1, "is a patch rpm");
2151       return 0;
2152     }
2153   payloadformat = headstring(rpmhead, TAG_PAYLOADFORMAT);
2154   if (payloadformat && !strcmp(payloadformat, "drpm"))
2155     {
2156       /* this is a delta rpm */
2157       pool_error(pool, -1, "is a delta rpm");
2158       return 0;
2159     }
2160   s = pool_id2solvable(pool, repo_add_solvable(repo));
2161   if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags))
2162     {
2163       repo_free_solvable(repo, s - pool->solvables, 1);
2164       return 0;
2165     }
2166   if (!(flags & REPO_NO_INTERNALIZE))
2167     repodata_internalize(data);
2168   return s - pool->solvables;
2169 }
2170
2171 static inline void
2172 linkhash(const char *lt, char *hash)
2173 {
2174   unsigned int r = 0;
2175   const unsigned char *str = (const unsigned char *)lt;
2176   int l, c;
2177
2178   l = strlen(lt);
2179   while ((c = *str++) != 0)
2180     r += (r << 3) + c;
2181   sprintf(hash, "%08x%08x%08x%08x", r, l, 0, 0);
2182 }
2183
2184 void
2185 rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char *, struct filelistinfo *), void *cbdata)
2186 {
2187   RpmHead *rpmhead = rpmhandle;
2188   char **bn;
2189   char **dn;
2190   char **md = 0;
2191   char **lt = 0;
2192   uint32_t *di, diidx;
2193   uint32_t *co = 0;
2194   uint32_t *ff = 0;
2195   uint16_t *fm;
2196   unsigned int lastdir;
2197   int lastdirl;
2198   int cnt, dcnt, cnt2;
2199   int i, l1, l;
2200   char *space = 0;
2201   int spacen = 0;
2202   char md5[33];
2203   struct filelistinfo info;
2204
2205   dn = headstringarray(rpmhead, TAG_DIRNAMES, &dcnt);
2206   if (!dn)
2207     return;
2208   if ((flags & RPM_ITERATE_FILELIST_ONLYDIRS) != 0)
2209     {
2210       for (i = 0; i < dcnt; i++)
2211         (*cb)(cbdata, dn[i], 0);
2212       solv_free(dn);
2213       return;
2214     }
2215   bn = headstringarray(rpmhead, TAG_BASENAMES, &cnt);
2216   if (!bn)
2217     {
2218       solv_free(dn);
2219       return;
2220     }
2221   di = headint32array(rpmhead, TAG_DIRINDEXES, &cnt2);
2222   if (!di || cnt != cnt2)
2223     {
2224       solv_free(di);
2225       solv_free(bn);
2226       solv_free(dn);
2227       return;
2228     }
2229   fm = headint16array(rpmhead, TAG_FILEMODES, &cnt2);
2230   if (!fm || cnt != cnt2)
2231     {
2232       solv_free(fm);
2233       solv_free(di);
2234       solv_free(bn);
2235       solv_free(dn);
2236       return;
2237     }
2238   if ((flags & RPM_ITERATE_FILELIST_WITHMD5) != 0)
2239     {
2240       md = headstringarray(rpmhead, TAG_FILEMD5S, &cnt2);
2241       if (!md || cnt != cnt2)
2242         {
2243           solv_free(md);
2244           solv_free(fm);
2245           solv_free(di);
2246           solv_free(bn);
2247           solv_free(dn);
2248           return;
2249         }
2250     }
2251   if ((flags & RPM_ITERATE_FILELIST_WITHCOL) != 0)
2252     {
2253       co = headint32array(rpmhead, TAG_FILECOLORS, &cnt2);
2254       if (co && cnt != cnt2)
2255         {
2256           solv_free(co);
2257           solv_free(md);
2258           solv_free(fm);
2259           solv_free(di);
2260           solv_free(bn);
2261           solv_free(dn);
2262           return;
2263         }
2264     }
2265   if ((flags & RPM_ITERATE_FILELIST_NOGHOSTS) != 0)
2266     {
2267       ff = headint32array(rpmhead, TAG_FILEFLAGS, &cnt2);
2268       if (!ff || cnt != cnt2)
2269         {
2270           solv_free(ff);
2271           solv_free(co);
2272           solv_free(md);
2273           solv_free(fm);
2274           solv_free(di);
2275           solv_free(bn);
2276           solv_free(dn);
2277           return;
2278         }
2279     }
2280   lastdir = dcnt;
2281   lastdirl = 0;
2282   memset(&info, 0, sizeof(info));
2283   for (i = 0; i < cnt; i++)
2284     {
2285       if (ff && (ff[i] & FILEFLAG_GHOST) != 0)
2286         continue;
2287       diidx = di[i];
2288       if (diidx >= dcnt)
2289         continue;
2290       l1 = lastdir == diidx ? lastdirl : strlen(dn[diidx]);
2291       l = l1 + strlen(bn[i]) + 1;
2292       if (l > spacen)
2293         {
2294           spacen = l + 16;
2295           space = solv_realloc(space, spacen);
2296         }
2297       if (lastdir != diidx)
2298         {
2299           strcpy(space, dn[diidx]);
2300           lastdir = diidx;
2301           lastdirl = l1;
2302         }
2303       strcpy(space + l1, bn[i]);
2304       info.diridx = diidx;
2305       info.dirlen = l1;
2306       if (fm)
2307         info.mode = fm[i];
2308       if (md)
2309         {
2310           info.digest = md[i];
2311           if (fm && S_ISLNK(fm[i]))
2312             {
2313               info.digest = 0;
2314               if (!lt)
2315                 {
2316                   lt = headstringarray(rpmhead, TAG_FILELINKTOS, &cnt2);
2317                   if (cnt != cnt2)
2318                     lt = solv_free(lt);
2319                 }
2320               if (lt)
2321                 {
2322                   linkhash(lt[i], md5);
2323                   info.digest = md5;
2324                 }
2325             }
2326           if (!info.digest)
2327             {
2328               sprintf(md5, "%08x%08x%08x%08x", (fm[i] >> 12) & 65535, 0, 0, 0);
2329               info.digest = md5;
2330             }
2331         }
2332       info.color = co ? co[i] : 0;
2333       (*cb)(cbdata, space, &info);
2334     }
2335   solv_free(space);
2336   solv_free(lt);
2337   solv_free(md);
2338   solv_free(fm);
2339   solv_free(di);
2340   solv_free(bn);
2341   solv_free(dn);
2342   solv_free(co);
2343   solv_free(ff);
2344 }
2345
2346 char *
2347 rpm_query(void *rpmhandle, Id what)
2348 {
2349   const char *name, *arch, *sourcerpm;
2350   char *evr, *r;
2351   int l;
2352
2353   RpmHead *rpmhead = rpmhandle;
2354   r = 0;
2355   switch (what)
2356     {
2357     case 0:
2358       name = headstring(rpmhead, TAG_NAME);
2359       if (!name)
2360         name = "";
2361       sourcerpm = headstring(rpmhead, TAG_SOURCERPM);
2362       if (sourcerpm || !(headexists(rpmhead, TAG_SOURCEPACKAGE) || headissourceheuristic(rpmhead)))
2363         arch = headstring(rpmhead, TAG_ARCH);
2364       else
2365         {
2366           if (headexists(rpmhead, TAG_NOSOURCE) || headexists(rpmhead, TAG_NOPATCH))
2367             arch = "nosrc";
2368           else
2369             arch = "src";
2370         }
2371       if (!arch)
2372         arch = "noarch";
2373       evr = headtoevr(rpmhead);
2374       l = strlen(name) + 1 + strlen(evr ? evr : "") + 1 + strlen(arch) + 1;
2375       r = solv_malloc(l);
2376       sprintf(r, "%s-%s.%s", name, evr ? evr : "", arch);
2377       solv_free(evr);
2378       break;
2379     case SOLVABLE_NAME:
2380       name = headstring(rpmhead, TAG_NAME);
2381       r = solv_strdup(name);
2382       break;
2383     case SOLVABLE_SUMMARY:
2384       name = headstring(rpmhead, TAG_SUMMARY);
2385       r = solv_strdup(name);
2386       break;
2387     case SOLVABLE_DESCRIPTION:
2388       name = headstring(rpmhead, TAG_DESCRIPTION);
2389       r = solv_strdup(name);
2390       break;
2391     case SOLVABLE_EVR:
2392       r = headtoevr(rpmhead);
2393       break;
2394     }
2395   return r;
2396 }
2397
2398 unsigned long long
2399 rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound)
2400 {
2401   RpmHead *rpmhead = rpmhandle;
2402   unsigned int u32;
2403
2404   switch (what)
2405     {
2406     case SOLVABLE_INSTALLTIME:
2407       u32 = headint32(rpmhead, TAG_INSTALLTIME);
2408       return u32 ? u32 : notfound;
2409     }
2410   return notfound;
2411 }
2412
2413 #ifdef ENABLE_RPMDB
2414
2415 int
2416 rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq)
2417 {
2418   struct rpmdbentry *entries;
2419   int nentries, i;
2420
2421   entries = getinstalledrpmdbids(rpmstate, index ? index : "Name", match, &nentries, 0);
2422   if (rpmdbidq)
2423     {
2424       queue_empty(rpmdbidq);
2425       for (i = 0; i < nentries; i++)
2426         queue_push(rpmdbidq, entries[i].rpmdbid);
2427     }
2428   solv_free(entries);
2429   return nentries;
2430 }
2431
2432 void *
2433 rpm_byrpmdbid(void *rpmstate, Id rpmdbid)
2434 {
2435   struct rpmdbstate *state = rpmstate;
2436   int r;
2437
2438   r = getrpm_dbid(state, rpmdbid);
2439   if (!r)
2440     pool_error(state->pool, 0, "header #%d not in database", rpmdbid);
2441   return r <= 0 ? 0 : state->rpmhead;
2442 }
2443
2444 #endif  /* ENABLE_RPMDB */
2445
2446 void *
2447 rpm_byfp(void *rpmstate, FILE *fp, const char *name)
2448 {
2449   struct rpmdbstate *state = rpmstate;
2450   unsigned int sigdsize, sigcnt, l;
2451   unsigned char lead[4096];
2452
2453   if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
2454     {
2455       pool_error(state->pool, 0, "%s: not a rpm", name);
2456       return 0;
2457     }
2458   if (lead[78] != 0 || lead[79] != 5)
2459     {
2460       pool_error(state->pool, 0, "%s: not a V5 header", name);
2461       return 0;
2462     }
2463
2464   /* skip signature header */
2465   if (getu32(lead + 96) != 0x8eade801)
2466     {
2467       pool_error(state->pool, 0, "%s: bad signature header", name);
2468       return 0;
2469     }
2470   sigcnt = getu32(lead + 96 + 8);
2471   sigdsize = getu32(lead + 96 + 12);
2472   if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
2473     {
2474       pool_error(state->pool, 0, "%s: bad signature header", name);
2475       return 0;
2476     }
2477   sigdsize += sigcnt * 16;
2478   sigdsize = (sigdsize + 7) & ~7;
2479   while (sigdsize)
2480     {
2481       l = sigdsize > 4096 ? 4096 : sigdsize;
2482       if (fread(lead, l, 1, fp) != 1)
2483         {
2484           pool_error(state->pool, 0, "%s: unexpected EOF", name);
2485           return 0;
2486         }
2487       sigdsize -= l;
2488     }
2489
2490   if (fread(lead, 16, 1, fp) != 1)
2491     {
2492       pool_error(state->pool, 0, "%s: unexpected EOF", name);
2493       return 0;
2494     }
2495   if (getu32(lead) != 0x8eade801)
2496     {
2497       pool_error(state->pool, 0, "%s: bad header", name);
2498       return 0;
2499     }
2500   sigcnt = getu32(lead + 8);
2501   sigdsize = getu32(lead + 12);
2502   if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
2503     {
2504       pool_error(state->pool, 0, "%s: bad header", name);
2505       return 0;
2506     }
2507   if (!headfromfp(state, name, fp, lead, sigcnt, sigdsize, 0, 0, 0))
2508     return 0;
2509   return state->rpmhead;
2510 }
2511
2512 #if defined(ENABLE_RPMDB_BYRPMHEADER) || defined(ENABLE_RPMDB_LIBRPM)
2513
2514 void *
2515 rpm_byrpmh(void *rpmstate, Header h)
2516 {
2517   struct rpmdbstate *state = rpmstate;
2518 #ifndef ENABLE_RPMPKG_LIBRPM
2519   const unsigned char *uh;
2520   unsigned int dsize, cnt;
2521
2522   if (!h)
2523     return 0;
2524 #ifndef RPM5
2525   uh = headerUnload(h);
2526 #else
2527   uh = headerUnload(h, NULL);
2528 #endif
2529   if (!uh)
2530     return 0;
2531   cnt = getu32(uh);
2532   dsize = getu32(uh + 4);
2533   if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE)
2534     {
2535       free((void *)uh);
2536       return 0;
2537     }
2538   headfromblob(state, uh + 8, cnt, dsize);
2539   free((void *)uh);
2540 #else
2541   if (!h)
2542     return 0;
2543   if (state->rpmhead)
2544     headfree(state->rpmhead);
2545   state->rpmhead = headerLink(h);
2546 #endif
2547   return state->rpmhead;
2548 }
2549
2550 #endif  /* defined(ENABLE_RPMDB_BYRPMHEADER) || defined(ENABLE_RPMDB_LIBRPM) */
2551