to follow SUSE tools conventions
[platform/upstream/libsolv.git] / tools / repo_rpmdb.c
1 /*
2  * repo_rpmdb
3  * 
4  * convert rpm db to repo
5  * 
6  */
7
8 #include <sys/types.h>
9 #include <limits.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <db43/db.h>
16
17 #include "pool.h"
18 #include "hash.h"
19 #include "repo_rpmdb.h"
20
21 #define TAG_NAME                1000
22 #define TAG_VERSION             1001
23 #define TAG_RELEASE             1002
24 #define TAG_EPOCH               1003
25 #define TAG_SUMMARY             1004
26 #define TAG_DESCRIPTION         1005
27 #define TAG_BUILDTIME           1006
28 #define TAG_VENDOR              1011
29 #define TAG_ARCH                1022
30 #define TAG_PROVIDENAME         1047
31 #define TAG_REQUIREFLAGS        1048
32 #define TAG_REQUIRENAME         1049
33 #define TAG_REQUIREVERSION      1050
34 #define TAG_CONFLICTFLAGS       1053
35 #define TAG_CONFLICTNAME        1054
36 #define TAG_CONFLICTVERSION     1055
37 #define TAG_OBSOLETENAME        1090
38 #define TAG_PROVIDEFLAGS        1112
39 #define TAG_PROVIDEVERSION      1113
40 #define TAG_OBSOLETEFLAGS       1114
41 #define TAG_OBSOLETEVERSION     1115
42 #define TAG_DIRINDEXES          1116
43 #define TAG_BASENAMES           1117
44 #define TAG_DIRNAMES            1118
45 #define TAG_SUGGESTSNAME        1156
46 #define TAG_SUGGESTSVERSION     1157
47 #define TAG_SUGGESTSFLAGS       1158
48 #define TAG_ENHANCESNAME        1159
49 #define TAG_ENHANCESVERSION     1160
50 #define TAG_ENHANCESFLAGS       1161
51
52 #define DEP_LESS                (1 << 1)
53 #define DEP_GREATER             (1 << 2)
54 #define DEP_EQUAL               (1 << 3)
55 #define DEP_STRONG              (1 << 27)
56 #define DEP_PRE                 ((1 << 6) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12))
57
58
59 static DBT key;
60 static DBT data;
61
62 struct rpmid {
63   unsigned int dbid;
64   char *name;
65 };
66
67 typedef struct rpmhead {
68   int cnt;
69   int dcnt;
70   unsigned char *dp;
71   unsigned char data[1];
72 } RpmHead;
73
74 static unsigned int *
75 headint32(RpmHead *h, int tag, int *cnt)
76 {
77   unsigned int i, o, *r;
78   unsigned char *d, taga[4];
79
80   d = h->dp - 16;
81   taga[0] = tag >> 24;
82   taga[1] = tag >> 16;
83   taga[2] = tag >> 8;
84   taga[3] = tag;
85   for (i = 0; i < h->cnt; i++, d -= 16)
86     if (d[3] == taga[3] && d[2] == taga[2] && d[1] == taga[1] && d[0] == taga[0])
87       break;
88   if (i >= h->cnt)
89     return 0;
90   if (d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4)
91     return 0;
92   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
93   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
94   if (o + 4 * i > h->dcnt)
95     return 0;
96   d = h->dp + o;
97   r = calloc(i ? i : 1, sizeof(unsigned int));
98   if (cnt)
99     *cnt = i;
100   for (o = 0; o < i; o++, d += 4)
101     r[o] = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
102   return r;
103 }
104
105 static char *
106 headstring(RpmHead *h, int tag)
107 {
108   unsigned int i, o;
109   unsigned char *d, taga[4];
110   d = h->dp - 16;
111   taga[0] = tag >> 24;
112   taga[1] = tag >> 16;
113   taga[2] = tag >> 8;
114   taga[3] = tag;
115   for (i = 0; i < h->cnt; i++, d -= 16)
116     if (d[3] == taga[3] && d[2] == taga[2] && d[1] == taga[1] && d[0] == taga[0])
117       break;
118   if (i >= h->cnt)
119     return 0;
120   if (d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 6)
121     return 0;
122   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
123   return (char *)h->dp + o;
124 }
125
126 static char **
127 headstringarray(RpmHead *h, int tag, int *cnt)
128 {
129   unsigned int i, o;
130   unsigned char *d, taga[4];
131   char **r;
132
133   d = h->dp - 16;
134   taga[0] = tag >> 24;
135   taga[1] = tag >> 16;
136   taga[2] = tag >> 8;
137   taga[3] = tag;
138   for (i = 0; i < h->cnt; i++, d -= 16)
139     if (d[3] == taga[3] && d[2] == taga[2] && d[1] == taga[1] && d[0] == taga[0])
140       break;
141   if (i >= h->cnt)
142     return 0;
143   if (d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 8)
144     return 0;
145   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
146   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
147   r = calloc(i ? i : 1, sizeof(char *));
148   if (cnt)
149     *cnt = i;
150   d = h->dp + o;
151   for (o = 0; o < i; o++)
152     {
153       r[o] = (char *)d;
154       if (o + 1 < i)
155         d += strlen((char *)d) + 1;
156       if (d >= h->dp + h->dcnt)
157         {
158           free(r);
159           return 0;
160         }
161     }
162   return r;
163 }
164
165 static char *headtoevr(RpmHead *h)
166 {
167   unsigned int epoch, *epochp; 
168   char *version, *v;
169   char *release;
170   char *evr;
171   int epochcnt = 0;
172
173   version  = headstring(h, TAG_VERSION);
174   release  = headstring(h, TAG_RELEASE);
175   epochp = headint32(h, TAG_EPOCH, &epochcnt);
176   if (!version || !release)
177     {
178       fprintf(stderr, "headtoevr: bad rpm header\n");
179       exit(1);
180     }
181   for (v = version; *v >= 0 && *v <= '9'; v++)
182     ;
183   epoch = epochp && epochcnt ? *epochp : 0;
184   if (epoch || (v != version && *v == ':'))
185     {
186       char epochbuf[11];        /* 32bit decimal will fit in */
187       sprintf(epochbuf, "%u", epoch);
188       evr = malloc(strlen(epochbuf) + 1 + strlen(version) + 1 + strlen(release) + 1);
189       sprintf(evr, "%s:%s-%s", epochbuf, version, release);
190     }
191   else
192     {
193       evr = malloc(strlen(version) + 1 + strlen(release) + 1);
194       sprintf(evr, "%s-%s", version, release);
195     }
196   if (epochp)
197     free(epochp);
198   return evr;
199 }
200
201 static unsigned int
202 makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int strong)
203 {
204   char **n, **v;
205   unsigned int *f;
206   int i, cc, nc, vc, fc;
207   int haspre = 0;
208   unsigned int olddeps;
209   Id *ida;
210
211   n = headstringarray(rpmhead, tagn, &nc);
212   if (!n)
213     return 0;
214   v = headstringarray(rpmhead, tagv, &vc);
215   if (!v)
216     {
217       free(n);
218       return 0;
219     }
220   f = headint32(rpmhead, tagf, &fc);
221   if (!f)
222     {
223       free(n);
224       free(v);
225       return 0;
226     }
227   if (nc != vc || nc != fc)
228     {
229       fprintf(stderr, "bad dependency entries\n");
230       exit(1);
231     }
232
233   cc = nc;
234   if (strong)
235     {
236       cc = 0;
237       for (i = 0; i < nc; i++)
238         if ((f[i] & DEP_STRONG) == (strong == 1 ? 0 : DEP_STRONG))
239           {
240             cc++;
241             if ((f[i] & DEP_PRE) != 0)
242               haspre = 1;
243           }
244     }
245   else
246     {
247       for (i = 0; i < nc; i++)
248         if ((f[i] & DEP_PRE) != 0)
249           {
250             haspre = 1;
251             break;
252           }
253     }
254   if (tagn != TAG_REQUIRENAME)
255      haspre = 0;
256   if (cc == 0)
257     {
258       free(n);
259       free(v);
260       free(f);
261       return 0;
262     }
263   cc += haspre;
264   olddeps = repo_reserve_ids(repo, 0, cc);
265   ida = repo->idarraydata + olddeps;
266   for (i = 0; ; i++)
267     {
268       if (i == nc)
269         {
270           if (haspre != 1)
271             break;
272           haspre = 2;
273           i = 0;
274           *ida++ = SOLVABLE_PREREQMARKER;
275         }
276       if (strong && (f[i] & DEP_STRONG) != (strong == 1 ? 0 : DEP_STRONG))
277         continue;
278       if (haspre == 1 && (f[i] & DEP_PRE) != 0)
279         continue;
280       if (haspre == 2 && (f[i] & DEP_PRE) == 0)
281         continue;
282       if (f[i] & (DEP_LESS|DEP_GREATER|DEP_EQUAL))
283         {
284           Id name, evr;
285           int flags = 0;
286           if ((f[i] & DEP_LESS) != 0)
287             flags |= 4;
288           if ((f[i] & DEP_EQUAL) != 0)
289             flags |= 2;
290           if ((f[i] & DEP_GREATER) != 0)
291             flags |= 1;
292           name = str2id(pool, n[i], 1);
293           if (v[i][0] == '0' && v[i][1] == ':' && v[i][2])
294             evr = str2id(pool, v[i] + 2, 1);
295           else
296             evr = str2id(pool, v[i], 1);
297           *ida++ = rel2id(pool, name, evr, flags, 1);
298         }
299       else
300         *ida++ = str2id(pool, n[i], 1);
301     }
302   *ida++ = 0;
303   repo->idarraysize += cc + 1;
304   free(n);
305   free(v);
306   free(f);
307   return olddeps;
308 }
309
310 static Offset
311 copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
312 {
313   int cc;
314   Id id, *ida, *from;
315   Offset ido;
316   Pool *frompool = fromrepo->pool;
317
318   if (!fromoff)
319     return 0;
320   from = fromrepo->idarraydata + fromoff;
321   for (ida = from, cc = 0; *ida; ida++, cc++)
322     ;
323   if (cc == 0)
324     return 0;
325   ido = repo_reserve_ids(repo, 0, cc);
326   ida = repo->idarraydata + ido;
327   if (frompool && pool != frompool)
328     {
329       while (*from)
330         {
331           id = *from++;
332           if (ISRELDEP(id))
333             {
334               Reldep *rd = GETRELDEP(frompool, id);
335               Id name = str2id(pool, id2str(frompool, rd->name), 1);
336               Id evr = str2id(pool, id2str(frompool, rd->evr), 1);
337               id = rel2id(pool, name, evr, rd->flags, 1);
338             }
339           else
340             id = str2id(pool, id2str(frompool, id), 1);
341           *ida++ = id;
342         }
343       *ida = 0;
344     }
345   else
346     memcpy(ida, from, (cc + 1) * sizeof(Id));
347   repo->idarraysize += cc + 1;
348   return ido;
349 }
350
351
352 #define FILEFILTER_EXACT    0
353 #define FILEFILTER_STARTS   1
354 #define FILEFILTER_CONTAINS 2
355
356 struct filefilter {
357   int dirmatch;
358   char *dir;
359   char *base;
360 };
361
362 static struct filefilter filefilters[] = {
363   { FILEFILTER_CONTAINS, "/bin/", 0},
364   { FILEFILTER_CONTAINS, "/sbin/", 0},
365   { FILEFILTER_CONTAINS, "/lib/", 0},
366   { FILEFILTER_CONTAINS, "/lib64/", 0},
367   { FILEFILTER_CONTAINS, "/etc/", 0},
368   { FILEFILTER_STARTS, "/usr/games/", 0},
369   { FILEFILTER_EXACT, "/usr/share/dict/", "words"},
370   { FILEFILTER_STARTS, "/usr/share/", "magic.mime"},
371   { FILEFILTER_STARTS, "/opt/gnome/games/", 0},
372 };
373
374 /* assumes last processed array is provides! */
375 static unsigned int
376 addfileprovides(Pool *pool, Repo *repo, RpmHead *rpmhead, unsigned int olddeps)
377 {
378   char **bn;
379   char **dn;
380   unsigned int *di;
381   int bnc, dnc, dic;
382   int i, j;
383   struct filefilter *ff;
384   char *fn = 0;
385   int fna = 0;
386
387   bn = headstringarray(rpmhead, TAG_BASENAMES, &bnc);
388   if (!bn)
389     return olddeps;
390   dn = headstringarray(rpmhead, TAG_DIRNAMES, &dnc);
391   if (!dn)
392     {
393       free(bn);
394       return olddeps;
395     }
396   di = headint32(rpmhead, TAG_DIRINDEXES, &dic);
397   if (!di)
398     {
399       free(bn);
400       free(dn);
401       return olddeps;
402     }
403   if (bnc != dic)
404     {
405       fprintf(stderr, "bad filelist\n");
406       exit(1);
407     }
408   for (i = 0; i < bnc; i++)
409     {
410       ff = filefilters;
411       for (j = 0; j < sizeof(filefilters)/sizeof(*filefilters); j++, ff++)
412         {
413           if (ff->dir)
414             {
415               switch (ff->dirmatch)
416                 {
417                 case FILEFILTER_STARTS:
418                   if (strncmp(dn[di[i]], ff->dir, strlen(ff->dir)))
419                     continue;
420                   break;
421                 case FILEFILTER_CONTAINS:
422                   if (!strstr(dn[di[i]], ff->dir))
423                     continue;
424                   break;
425                 case FILEFILTER_EXACT:
426                 default:
427                   if (strcmp(dn[di[i]], ff->dir))
428                     continue;
429                   break;
430                 }
431             }
432           if (ff->base)
433             {
434               if (strcmp(bn[i], ff->base))
435                 continue;
436             }
437           break;
438         }
439       if (j == sizeof(filefilters)/sizeof(*filefilters))
440         continue;
441       j = strlen(bn[i]) + strlen(dn[di[i]]) + 1;
442       if (j > fna)
443         {
444           if (fn)
445             fn = realloc(fn, j + 256);
446           else
447             fn = malloc(j + 256);
448           fna = j + 256;
449         }
450       strcpy(fn, dn[di[i]]);
451       strcat(fn, bn[i]);
452       olddeps = repo_addid(repo, olddeps, str2id(pool, fn, 1));
453     }
454   if (fn)
455     free(fn);
456   free(bn);
457   free(dn);
458   free(di);
459   return olddeps;
460 }
461
462 static int
463 rpm2solv(Pool *pool, Repo *repo, Solvable *s, RpmHead *rpmhead)
464 {
465   char *name;
466   char *evr;
467
468   name = headstring(rpmhead, TAG_NAME);
469   if (!strcmp(name, "gpg-pubkey"))
470     return 0;
471   s->name = str2id(pool, name, 1);
472   if (!s->name)
473     {
474       fprintf(stderr, "package has no name\n");
475       exit(1);
476     }
477   s->arch = str2id(pool, headstring(rpmhead, TAG_ARCH), 1);
478   if (!s->arch)
479     {
480       fprintf(stderr, "package %s has no arch\n", id2str(pool, s->name));
481       exit(1);
482     }
483   evr = headtoevr(rpmhead);
484   s->evr = str2id(pool, evr, 1);
485   free(evr);
486
487   s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0);
488   s->provides = addfileprovides(pool, repo, rpmhead, s->provides);
489   s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
490   s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, 0);
491   s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0);
492   s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0);
493
494   s->recommends = makedeps(pool, repo, rpmhead, TAG_SUGGESTSNAME, TAG_SUGGESTSVERSION, TAG_SUGGESTSFLAGS, 2);
495   s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTSNAME, TAG_SUGGESTSVERSION, TAG_SUGGESTSFLAGS, 1);
496   s->supplements = makedeps(pool, repo, rpmhead, TAG_ENHANCESNAME, TAG_ENHANCESVERSION, TAG_ENHANCESFLAGS, 2);
497   s->enhances  = makedeps(pool, repo, rpmhead, TAG_ENHANCESNAME, TAG_ENHANCESVERSION, TAG_ENHANCESFLAGS, 1);
498   s->freshens = 0;
499   s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
500   return 1;
501 }
502
503
504 /*
505  * read rpm db as repo
506  * 
507  */
508
509 Repo *
510 pool_addrepo_rpmdb(Pool *pool, Repo *ref)
511 {
512   unsigned char buf[16];
513   DB *db = 0;
514   DBC *dbc = 0;
515   int byteswapped;
516   unsigned int dbid;
517   unsigned char *dp, *dbidp;
518   int dl, nrpmids;
519   struct rpmid *rpmids, *rp;
520   int i;
521   int rpmheadsize;
522   RpmHead *rpmhead;
523   Repo *repo;
524   Solvable *s;
525   Id id, *refhash;
526   unsigned int refmask, h;
527   int asolv;
528
529   repo = pool_addrepo_empty(pool);
530
531   if (ref && !(ref->nsolvables && ref->rpmdbid))
532     ref = 0;
533
534   if (db_create(&db, 0, 0))
535     {
536       perror("db_create");
537       exit(1);
538     }
539
540   if (!ref)
541     {
542       if (db->open(db, 0, "/var/lib/rpm/Packages", 0, DB_HASH, DB_RDONLY, 0664))
543         {
544           perror("db->open /var/lib/rpm/Packages");
545           exit(1);
546         }
547       if (db->get_byteswapped(db, &byteswapped))
548         {
549           perror("db->get_byteswapped");
550           exit(1);
551         }
552       if (db->cursor(db, NULL, &dbc, 0))
553         {
554           perror("db->cursor");
555           exit(1);
556         }
557       dbidp = (unsigned char *)&dbid;
558       pool->solvables = realloc(pool->solvables, (pool->nsolvables + 256) * sizeof(Solvable));
559       memset(pool->solvables + repo->start, 0, 256 * sizeof(Solvable));
560       repo->rpmdbid = calloc(256, sizeof(unsigned int));
561       asolv = 256;
562       rpmheadsize = 0;
563       rpmhead = 0;
564       i = 0;
565       while (dbc->c_get(dbc, &key, &data, DB_NEXT) == 0)
566         {
567           if (i >= asolv)
568             {
569               pool->solvables = realloc(pool->solvables, (pool->nsolvables + asolv + 256) * sizeof(Solvable));
570               memset(pool->solvables + repo->start + asolv, 0, 256 * sizeof(Solvable));
571               repo->rpmdbid = realloc(repo->rpmdbid, (asolv + 256) * sizeof(unsigned int));
572               memset(repo->rpmdbid + asolv, 0, 256 * sizeof(unsigned int));
573               asolv += 256;
574             }
575           pool->solvables[repo->start + i].repo = repo;
576           if (key.size != 4)
577             {
578               fprintf(stderr, "corrupt Packages database (key size)\n");
579               exit(1);
580             }
581           dp = key.data;
582           if (byteswapped)
583             {
584               dbidp[0] = dp[3];
585               dbidp[1] = dp[2];
586               dbidp[2] = dp[1];
587               dbidp[3] = dp[0];
588             }
589           else
590             memcpy(dbidp, dp, 4);
591           if (dbid == 0)                /* the join key */
592             continue;
593           if (data.size < 8)
594             {
595               fprintf(stderr, "corrupt rpm database (size %u)\n", data.size);
596               exit(1);
597             }
598           if (!rpmhead)
599             rpmhead = malloc(sizeof(*rpmhead) + data.size);
600           else if (data.size > rpmheadsize)
601             rpmhead = realloc(rpmhead, sizeof(*rpmhead) + data.size);
602           memcpy(buf, data.data, 8);
603           rpmhead->cnt = buf[0] << 24  | buf[1] << 16  | buf[2] << 8 | buf[3];
604           rpmhead->dcnt = buf[4] << 24  | buf[5] << 16  | buf[6] << 8 | buf[7];
605           if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > data.size)
606             {
607               fprintf(stderr, "corrupt rpm database (data size)\n");
608               exit(1);
609             }
610           memcpy(rpmhead->data, (unsigned char *)data.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
611           rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
612           repo->rpmdbid[i] = dbid;
613           if (rpm2solv(pool, repo, pool->solvables + repo->start + i, rpmhead))
614             i++;
615         }
616       nrpmids = i;
617       dbc->c_close(dbc);
618       db->close(db, 0);
619       db = 0;
620     }
621   else
622     {
623       if (db->open(db, 0, "/var/lib/rpm/Name", 0, DB_HASH, DB_RDONLY, 0664))
624         {
625           perror("db->open /var/lib/rpm/Name");
626           exit(1);
627         }
628       if (db->get_byteswapped(db, &byteswapped))
629         {
630           perror("db->get_byteswapped");
631           exit(1);
632         }
633       if (db->cursor(db, NULL, &dbc, 0))
634         {
635           perror("db->cursor");
636           exit(1);
637         }
638       dbidp = (unsigned char *)&dbid;
639       nrpmids = 0;
640       rpmids = 0;
641       while (dbc->c_get(dbc, &key, &data, DB_NEXT) == 0)
642         {
643           if (key.size == 10 && !memcmp(key.data, "gpg-pubkey", 10))
644             continue;
645           dl = data.size;
646           dp = data.data;
647           while(dl >= 8)
648             {
649               if (byteswapped)
650                 {
651                   dbidp[0] = dp[3];
652                   dbidp[1] = dp[2];
653                   dbidp[2] = dp[1];
654                   dbidp[3] = dp[0];
655                 }
656               else
657                 memcpy(dbidp, dp, 4);
658               if ((nrpmids & 255) == 0)
659                 {
660                   if (rpmids)
661                     rpmids = realloc(rpmids, sizeof(*rpmids) * (nrpmids + 256));
662                   else
663                     rpmids = malloc(sizeof(*rpmids) * 256);
664                 }
665               rpmids[nrpmids].dbid = dbid;
666               rpmids[nrpmids].name = malloc((int)key.size + 1);
667               memcpy(rpmids[nrpmids].name, key.data, (int)key.size);
668               rpmids[nrpmids].name[(int)key.size] = 0;
669               nrpmids++;
670               dp += 8;
671               dl -= 8;
672             }
673           
674         }
675       dbc->c_close(dbc);
676       db->close(db, 0);
677       db = 0;
678
679       rp = rpmids;
680       dbidp = (unsigned char *)&dbid;
681       rpmheadsize = 0;
682       rpmhead = 0;
683
684       pool->solvables = realloc(pool->solvables, (pool->nsolvables + nrpmids) * sizeof(Solvable));
685       memset(pool->solvables + repo->start, 0, nrpmids * sizeof(Solvable));
686       repo->rpmdbid = calloc(nrpmids, sizeof(unsigned int));
687
688       refhash = 0;
689       refmask = 0;
690       if (ref)
691         {
692           refmask = mkmask(ref->nsolvables);
693           refhash = calloc(refmask + 1, sizeof(Id));
694           for (i = 0; i < ref->nsolvables; i++)
695             {
696               h = ref->rpmdbid[i] & refmask;
697               while (refhash[h])
698                 h = (h + 317) & refmask;
699               refhash[h] = i + 1;       /* make it non-zero */
700             }
701         }
702       s = pool->solvables + repo->start;
703       for (i = 0; i < nrpmids; i++, rp++, s++)
704         {
705           s->repo = repo;
706           dbid = rp->dbid;
707           repo->rpmdbid[i] = dbid;
708           if (refhash)
709             {
710               h = dbid & refmask;
711               while ((id = refhash[h]))
712                 {
713                   if (ref->rpmdbid[id - 1] == dbid)
714                     break;
715                   h = (h + 317) & refmask;
716                 }
717               if (id)
718                 {
719                   Solvable *r = ref->pool->solvables + ref->start + (id - 1);
720                   if (pool == ref->pool)
721                     {
722                       s->name = r->name;
723                       s->evr = r->evr;
724                       s->arch = r->arch;
725                     }
726                   else
727                     {
728                       if (r->name)
729                         s->name = str2id(pool, id2str(ref->pool, r->name), 1);
730                       if (r->evr)
731                         s->evr = str2id(pool, id2str(ref->pool, r->evr), 1);
732                       if (r->arch)
733                         s->arch = str2id(pool, id2str(ref->pool, r->arch), 1);
734                     }
735                   s->provides = copydeps(pool, repo, r->provides, ref);
736                   s->requires = copydeps(pool, repo, r->requires, ref);
737                   s->conflicts = copydeps(pool, repo, r->conflicts, ref);
738                   s->obsoletes = copydeps(pool, repo, r->obsoletes, ref);
739                   s->recommends = copydeps(pool, repo, r->recommends, ref);
740                   s->suggests = copydeps(pool, repo, r->suggests, ref);
741                   s->supplements = copydeps(pool, repo, r->supplements, ref);
742                   s->enhances  = copydeps(pool, repo, r->enhances, ref);
743                   s->freshens = copydeps(pool, repo, r->freshens, ref);
744                   continue;
745                 }
746             }
747           if (!db)
748             {
749               if (db_create(&db, 0, 0))
750                 {
751                   perror("db_create");
752                   exit(1);
753                 }
754               if (db->open(db, 0, "/var/lib/rpm/Packages", 0, DB_HASH, DB_RDONLY, 0664))
755                 {
756                   perror("db->open /var/lib/rpm/Packages");
757                   exit(1);
758                 }
759               if (db->get_byteswapped(db, &byteswapped))
760                 {
761                   perror("db->get_byteswapped");
762                   exit(1);
763                 }
764             }
765           if (byteswapped)
766             {
767               buf[0] = dbidp[3];
768               buf[1] = dbidp[2];
769               buf[2] = dbidp[1];
770               buf[3] = dbidp[0];
771             }
772           else
773             memcpy(buf, dbidp, 4);
774           key.data = buf;
775           key.size = 4;
776           data.data = 0;
777           data.size = 0;
778           if (db->get(db, NULL, &key, &data, 0))
779             {
780               perror("db->get");
781               fprintf(stderr, "corrupt rpm database\n");
782               exit(1);
783             }
784           if (data.size < 8)
785             {
786               fprintf(stderr, "corrupt rpm database (size)\n");
787               exit(1);
788             }
789           if (!rpmhead)
790             rpmhead = malloc(sizeof(*rpmhead) + data.size);
791           else if (data.size > rpmheadsize)
792             rpmhead = realloc(rpmhead, sizeof(*rpmhead) + data.size);
793           memcpy(buf, data.data, 8);
794           rpmhead->cnt = buf[0] << 24  | buf[1] << 16  | buf[2] << 8 | buf[3];
795           rpmhead->dcnt = buf[4] << 24  | buf[5] << 16  | buf[6] << 8 | buf[7];
796           if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > data.size)
797             {
798               fprintf(stderr, "corrupt rpm database (data size)\n");
799               exit(1);
800             }
801           memcpy(rpmhead->data, (unsigned char *)data.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
802           rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
803
804           rpm2solv(pool, repo, s, rpmhead);
805         }
806
807       if (refhash)
808         free(refhash);
809       if (rpmids)
810         {
811           for (i = 0; i < nrpmids; i++)
812             free(rpmids[i].name);
813           free(rpmids);
814         }
815     }
816   if (rpmhead)
817     free(rpmhead);
818   pool->nsolvables += nrpmids;
819   repo->nsolvables = nrpmids;
820
821   if (db)
822     db->close(db, 0);
823   return repo;
824 }