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