I'm going to use the file info block real soon now and noticed that
[platform/upstream/libsolv.git] / src / repo_solv.c
1 /*
2  * Copyright (c) 2007, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * repo_solv.c
10  * 
11  * Read the binary dump of a Repo and create a Repo * from it
12  * 
13  *  See
14  *   Repo *pool_addrepo_solv(Pool *pool, FILE *fp)
15  * below
16  * 
17  */
18
19
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25
26 #include "repo_solv.h"
27 #include "util.h"
28 #include "attr_store_p.h"
29
30 #define INTERESTED_START        SOLVABLE_NAME
31 #define INTERESTED_END          SOLVABLE_FRESHENS
32
33 static Pool *mypool;            /* for pool_debug... */
34
35 /*-----------------------------------------------------------------*/
36 /* .solv read functions */
37
38 /*
39  * read u32
40  */
41
42 static unsigned int
43 read_u32(FILE *fp)
44 {
45   int c, i;
46   unsigned int x = 0;
47
48   for (i = 0; i < 4; i++)
49     {
50       c = getc(fp);
51       if (c == EOF)
52         {
53           pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
54           exit(1);
55         }
56       x = (x << 8) | c;
57     }
58   return x;
59 }
60
61
62 /*
63  * read u8
64  */
65
66 static unsigned int
67 read_u8(FILE *fp)
68 {
69   int c;
70   c = getc(fp);
71   if (c == EOF)
72     {
73       pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
74       exit(1);
75     }
76   return c;
77 }
78
79
80 /*
81  * read Id
82  */
83
84 static Id
85 read_id(FILE *fp, Id max)
86 {
87   unsigned int x = 0;
88   int c, i;
89
90   for (i = 0; i < 5; i++)
91     {
92       c = getc(fp);
93       if (c == EOF)
94         {
95           pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
96           exit(1);
97         }
98       if (!(c & 128))
99         {
100           x = (x << 7) | c;
101           if (max && x >= max)
102             {
103               pool_debug(mypool, SAT_FATAL, "read_id: id too large (%u/%u)\n", x, max);
104               exit(1);
105             }
106           return x;
107         }
108       x = (x << 7) ^ c ^ 128;
109     }
110   pool_debug(mypool, SAT_FATAL, "read_id: id too long\n");
111   exit(1);
112 }
113
114
115 /*
116  * read array of Ids
117  */
118
119 static Id *
120 read_idarray(FILE *fp, Id max, Id *map, Id *store, Id *end, int relative)
121 {
122   unsigned int x = 0;
123   int c;
124   Id old = 0;
125   for (;;)
126     {
127       c = getc(fp);
128       if (c == EOF)
129         {
130           pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
131           exit(1);
132         }
133       if ((c & 128) == 0)
134         {
135           x = (x << 6) | (c & 63);
136           if (relative)
137             {
138               if (x == 0 && c == 0x40)
139                 {
140                   /* prereq hack */
141                   if (store == end)
142                     {
143                       pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
144                       exit(1);
145                     }
146                   *store++ = SOLVABLE_PREREQMARKER;
147                   old = 0;
148                   x = 0;
149                   continue;
150                 }
151               x = (x - 1) + old;
152               old = x;
153             }
154           if (x >= max)
155             {
156               pool_debug(mypool, SAT_FATAL, "read_idarray: id too large (%u/%u)\n", x, max);
157               exit(1);
158             }
159           if (map)
160             x = map[x];
161           if (store == end)
162             {
163               pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
164               exit(1);
165             }
166           *store++ = x;
167           if ((c & 64) == 0)
168             {
169               if (x == 0)       /* already have trailing zero? */
170                 return store;
171               if (store == end)
172                 {
173                   pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
174                   exit(1);
175                 }
176               *store++ = 0;
177               return store;
178             }
179           x = 0;
180           continue;
181         }
182       x = (x << 7) ^ c ^ 128;
183     }
184 }
185
186
187 static void
188 skip_item (FILE *fp, unsigned type, Id *idmap, unsigned numid, unsigned numrel)
189 {
190   switch (type)
191     {
192       case TYPE_ID:
193         read_id(fp, numid + numrel);   /* just check Id */
194         break;
195       case TYPE_U32:
196         read_u32(fp);
197         break;
198       case TYPE_ATTR_STRING:
199       case TYPE_STR:
200         while(read_u8(fp) != 0)
201           ;
202         break;
203       case TYPE_IDARRAY:
204       case TYPE_REL_IDARRAY:
205         while ((read_u8(fp) & 0xc0) != 0)
206           ;
207         break;
208       case TYPE_COUNT_NAMED:
209         {
210           unsigned count = read_id (fp, 0);
211           while (count--)
212             {
213               read_id (fp, numid);    /* Name */
214               unsigned t = read_id (fp, TYPE_ATTR_TYPE_MAX + 1);
215               skip_item (fp, t, idmap, numid, numrel);
216             }
217         }
218         break;
219       case TYPE_ATTR_CHUNK:
220         read_id(fp, 0);
221         /* Fallthrough.  */
222       case TYPE_ATTR_INT:
223         read_id(fp, 0);
224         break;
225       case TYPE_ATTR_INTLIST:
226       case TYPE_ATTR_LOCALIDS:
227         while (read_id(fp, 0) != 0)
228           ;
229         break;
230       default:
231         pool_debug(mypool, SAT_FATAL, "unknown type %d\n", type);
232         exit(1);
233     }
234 }
235
236 /*-----------------------------------------------------------------*/
237
238 struct key {
239   Id name;
240   Id type;
241   Id size;
242 };
243
244 // ----------------------------------------------
245
246 /*
247  * read repo from .solv file
248  *  and add it to pool
249  */
250
251 void
252 repo_add_solv(Repo *repo, FILE *fp)
253 {
254   Pool *pool = repo->pool;
255   int i, l;
256   unsigned int numid, numrel, numsolv;
257   unsigned int numkeys, numschemata, numinfo;
258   Attrstore *embedded_store = 0;
259
260   Offset sizeid;
261   Offset *str;                         /* map Id -> Offset into string space */
262   char *strsp;                         /* repo string space */
263   char *sp;                            /* pointer into string space */
264   Id *idmap;                           /* map of repo Ids to pool Ids */
265   Id id;
266   unsigned int hashmask, h;
267   int hh;
268   Id *hashtbl;
269   Id name, evr, did;
270   int flags;
271   Reldep *ran;
272   unsigned int size_idarray;
273   Id *idarraydatap, *idarraydataend;
274   Offset ido;
275   Solvable *s;
276   unsigned int solvflags;
277   unsigned int solvversion;
278   struct key *keys;
279   Id *schemadata, *schemadatap, *schemadataend;
280   Id *schemata, key;
281
282   mypool = pool;
283
284   if (read_u32(fp) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
285     {
286       pool_debug(pool, SAT_FATAL, "not a SOLV file\n");
287       exit(1);
288     }
289   solvversion = read_u32(fp);
290   switch (solvversion)
291     {
292       case SOLV_VERSION_1:
293       case SOLV_VERSION_2:
294       case SOLV_VERSION_3:
295         break;
296       default:
297         pool_debug(pool, SAT_FATAL, "unsupported SOLV version\n");
298         exit(1);
299     }
300
301   pool_freeidhashes(pool);
302
303   numid = read_u32(fp);
304   numrel = read_u32(fp);
305   numsolv = read_u32(fp);
306   numkeys = read_u32(fp);
307   numschemata = read_u32(fp);
308   numinfo = read_u32(fp);
309   solvflags = read_u32(fp);
310
311   if (solvversion < SOLV_VERSION_3
312       && numinfo)
313     {
314       pool_debug(pool, SAT_FATAL, "unsupported SOLV format (has info)\n");
315       exit(1);
316     }
317
318   /*******  Part 1: string IDs  *****************************************/
319
320   sizeid = read_u32(fp);               /* size of string+Id space */
321
322   /*
323    * read strings and Ids
324    * 
325    */
326
327   
328   /*
329    * alloc buffers
330    */
331
332   /* alloc string buffer */
333   strsp = (char *)xrealloc(pool->ss.stringspace, pool->ss.sstrings + sizeid + 1);
334   /* alloc string offsets (Id -> Offset into string space) */
335   str = (Offset *)xrealloc(pool->ss.strings, (pool->ss.nstrings + numid) * sizeof(Offset));
336
337   pool->ss.stringspace = strsp;
338   pool->ss.strings = str;                      /* array of offsets into strsp, indexed by Id */
339
340   /* point to _BEHIND_ already allocated string/Id space */
341   strsp += pool->ss.sstrings;
342
343   /* alloc id map for name and rel Ids. this maps ids in the solv files
344    * to the ids in our pool */
345   idmap = (Id *)xcalloc(numid + numrel, sizeof(Id));
346
347   /*
348    * read new repo at end of pool
349    */
350   
351   if ((solvflags & SOLV_FLAG_PREFIX_POOL) == 0)
352     {
353       if (fread(strsp, sizeid, 1, fp) != 1)
354         {
355           pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
356           exit(1);
357         }
358     }
359   else
360     {
361       unsigned int pfsize = read_u32 (fp);
362       char *prefix = xmalloc (pfsize);
363       char *pp = prefix;
364       char *old_str = "";
365       char *dest = strsp;
366       if (fread (prefix, pfsize, 1, fp) != 1)
367         {
368           pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
369           exit(1);
370         }
371       for (i = 1; i < numid; i++)
372         {
373           int same = (unsigned char)*pp++;
374           size_t len = strlen (pp) + 1;
375           if (same)
376             memcpy (dest, old_str, same);
377           memcpy (dest + same, pp, len);
378           pp += len;
379           old_str = dest;
380           dest += same + len;
381         }
382       xfree (prefix);
383     }
384   strsp[sizeid] = 0;                   /* make string space \0 terminated */
385   sp = strsp;
386
387   /*
388    * build hashes for all read strings
389    * 
390    */
391   
392   hashmask = mkmask(pool->ss.nstrings + numid);
393
394 #if 0
395   POOL_DEBUG(SAT_DEBUG_STATS, "read %d strings\n", numid);
396   POOL_DEBUG(SAT_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
397 #endif
398
399   /*
400    * ensure sufficient hash size
401    */
402   
403   hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
404
405   /*
406    * fill hashtable with strings already in pool
407    */
408   
409   for (i = 1; i < pool->ss.nstrings; i++)  /* leave out our dummy zero id */
410     {
411       h = strhash(pool->ss.stringspace + pool->ss.strings[i]) & hashmask;
412       hh = HASHCHAIN_START;
413       while (hashtbl[h])
414         h = HASHCHAIN_NEXT(h, hh, hashmask);
415       hashtbl[h] = i;
416     }
417
418   /*
419    * run over string space, calculate offsets
420    * 
421    * build id map (maps solv Id -> pool Id)
422    */
423   
424   for (i = 1; i < numid; i++)
425     {
426       if (sp >= strsp + sizeid)
427         {
428           pool_debug(pool, SAT_FATAL, "not enough strings\n");
429           exit(1);
430         }
431       if (!*sp)                        /* empty string */
432         {
433           idmap[i] = ID_EMPTY;
434           sp++;
435           continue;
436         }
437
438       /* find hash slot */
439       h = strhash(sp) & hashmask;
440       hh = HASHCHAIN_START;
441       for (;;)
442         {
443           id = hashtbl[h];
444           if (id == 0)
445             break;
446           if (!strcmp(pool->ss.stringspace + pool->ss.strings[id], sp))
447             break;                     /* existing string */
448           h = HASHCHAIN_NEXT(h, hh, hashmask);
449         }
450
451       /* length == offset to next string */
452       l = strlen(sp) + 1;
453       if (id == ID_NULL)               /* end of hash chain -> new string */
454         {
455           id = pool->ss.nstrings++;
456           hashtbl[h] = id;
457           str[id] = pool->ss.sstrings;    /* save Offset */
458           if (sp != pool->ss.stringspace + pool->ss.sstrings)   /* not at end-of-buffer */
459             memmove(pool->ss.stringspace + pool->ss.sstrings, sp, l);   /* append to pool buffer */
460           pool->ss.sstrings += l;
461         }
462       idmap[i] = id;                   /* repo relative -> pool relative */
463       sp += l;                         /* next string */
464     }
465   xfree(hashtbl);
466   pool_shrink_strings(pool);           /* vacuum */
467
468   
469   /*******  Part 2: Relation IDs  ***************************************/
470
471   /*
472    * read RelDeps
473    * 
474    */
475   
476   if (numrel)
477     {
478       /* extend rels */
479       ran = (Reldep *)xrealloc(pool->rels, (pool->nrels + numrel) * sizeof(Reldep));
480       if (!ran)
481         {
482           pool_debug(pool, SAT_FATAL, "no mem for rel space\n");
483           exit(1);
484         }
485       pool->rels = ran;        /* extended rel space */
486
487       hashmask = mkmask(pool->nrels + numrel);
488 #if 0
489       POOL_DEBUG(SAT_DEBUG_STATS, "read %d rels\n", numrel);
490       POOL_DEBUG(SAT_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
491 #endif
492       /*
493        * prep hash table with already existing RelDeps
494        */
495       
496       hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
497       for (i = 1; i < pool->nrels; i++)
498         {
499           h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
500           hh = HASHCHAIN_START;
501           while (hashtbl[h])
502             h = HASHCHAIN_NEXT(h, hh, hashmask);
503           hashtbl[h] = i;
504         }
505
506       /*
507        * read RelDeps from repo
508        */
509       
510       for (i = 0; i < numrel; i++)
511         {
512           name = read_id(fp, i + numid);        /* read (repo relative) Ids */
513           evr = read_id(fp, i + numid);
514           flags = read_u8(fp);
515           name = idmap[name];           /* map to (pool relative) Ids */
516           evr = idmap[evr];
517           h = relhash(name, evr, flags) & hashmask;
518           hh = HASHCHAIN_START;
519           for (;;)
520             {
521               id = hashtbl[h];
522               if (id == ID_NULL)        /* end of hash chain */
523                 break;
524               if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
525                 break;
526               h = HASHCHAIN_NEXT(h, hh, hashmask);
527             }
528           if (id == ID_NULL)            /* new RelDep */
529             {
530               id = pool->nrels++;
531               hashtbl[h] = id;
532               ran[id].name = name;
533               ran[id].evr = evr;
534               ran[id].flags = flags;
535             }
536           idmap[i + numid] = MAKERELDEP(id);   /* fill Id map */
537         }
538       xfree(hashtbl);
539       pool_shrink_rels(pool);           /* vacuum */
540     }
541
542
543   /*******  Part 3: Keys  ***********************************************/
544
545   keys = xcalloc(numkeys, sizeof(*keys));
546   /* keys start at 1 */
547   for (i = 1; i < numkeys; i++)
548     {
549       keys[i].name = idmap[read_id(fp, numid)];
550       keys[i].type = read_id(fp, 0);
551       keys[i].size = read_id(fp, 0);
552     }
553
554   /*******  Part 4: Schemata ********************************************/
555   
556   id = read_id(fp, 0);
557   schemadata = xcalloc(id, sizeof(Id));
558   schemadatap = schemadata;
559   schemadataend = schemadata + id;
560   schemata = xcalloc(numschemata, sizeof(Id));
561   for (i = 0; i < numschemata; i++)
562     {
563       schemata[i] = schemadatap - schemadata;
564       schemadatap = read_idarray(fp, numid, 0, schemadatap, schemadataend, 0);
565     }
566
567   /*******  Part 5: Info  ***********************************************/
568   /* we skip the info for now... */
569   for (i = 0; i < numinfo; i++)
570     {
571       unsigned name = idmap[read_id (fp, numid)];
572       unsigned type = read_id (fp, TYPE_ATTR_TYPE_MAX + 1);
573       if (type == TYPE_COUNT_NAMED
574           && !strcmp (id2str (pool, name), "repodata"))
575         skip_item (fp, type, idmap, numid, numrel);
576       else
577         skip_item (fp, type, idmap, numid, numrel);
578     }
579
580   /*******  Part 6: packed sizes (optional)  ****************************/
581   char *exists = 0;
582   if ((solvflags & SOLV_FLAG_PACKEDSIZES) != 0)
583     {
584       exists = xmalloc (numsolv);
585       for (i = 0; i < numsolv; i++)
586         exists[i] = read_id(fp, 0) != 0;
587     }
588
589   /*******  Part 7: item data *******************************************/
590
591   /* calculate idarray size */
592   size_idarray = 0;
593   for (i = 1; i < numkeys; i++)
594     {
595       id = keys[i].name;
596       if ((keys[i].type == TYPE_IDARRAY || keys[i].type == TYPE_REL_IDARRAY)
597           && id >= INTERESTED_START && id <= INTERESTED_END)
598         size_idarray += keys[i].size;
599     }
600
601   /* allocate needed space in repo */
602   if (size_idarray)
603     {
604       repo_reserve_ids(repo, 0, size_idarray);
605       idarraydatap = repo->idarraydata + repo->idarraysize;
606       repo->idarraysize += size_idarray;
607       idarraydataend = repo->idarraydata + repo->idarraysize;
608       repo->lastoff = 0;
609     }
610   else
611     {
612       idarraydatap = 0;
613       idarraydataend = 0;
614     }
615
616   /* read solvables */
617   s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
618
619   if ((solvflags & SOLV_FLAG_VERTICAL) != 0)
620     {
621       Id *solvschema = xcalloc(numsolv, sizeof(Id));
622       unsigned char *used = xmalloc(numschemata);
623       Solvable *sstart = s;
624       Id type;
625
626       for (i = 0; i < numsolv; i++)
627         solvschema[i] = read_id(fp, numschemata);
628       for (key = 1; key < numkeys; key++)
629         {
630           id = keys[key].name;
631           type = keys[key].type;
632           memset(used, 0, numschemata);
633           for (i = 0; i < numschemata; i++)
634             {
635               Id *keyp = schemadata + schemata[i];
636               while (*keyp)
637                 if (*keyp++ == key)
638                   {
639                     used[i] = 1;
640                     break;
641                   }
642             }
643           for (i = 0, s = sstart; i < numsolv; i++, s++)
644              {
645               if (!used[solvschema[i]])
646                 continue;
647               switch (type)
648                 {
649                 case TYPE_ID:
650                   did = idmap[read_id(fp, numid + numrel)];
651                   if (id == SOLVABLE_NAME)
652                     s->name = did;
653                   else if (id == SOLVABLE_ARCH)
654                     s->arch = did;
655                   else if (id == SOLVABLE_EVR)
656                     s->evr = did;
657                   else if (id == SOLVABLE_VENDOR)
658                     s->vendor = did;
659                   break;
660                 case TYPE_U32:
661                   h = read_u32(fp);
662                   if (id == RPM_RPMDBID)
663                     {
664                       if (!repo->rpmdbid)
665                         repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
666                       repo->rpmdbid[i] = h;
667                     }
668                   break;
669                 case TYPE_STR:
670                   while(read_u8(fp) != 0)
671                     ;
672                   break;
673                 case TYPE_IDARRAY:
674                 case TYPE_REL_IDARRAY:
675                   if (id < INTERESTED_START || id > INTERESTED_END)
676                     {
677                       /* not interested in array */
678                       while ((read_u8(fp) & 0xc0) != 0)
679                         ;
680                       break;
681                     }
682                   ido = idarraydatap - repo->idarraydata;
683                   idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, type == TYPE_REL_IDARRAY);
684                   if (id == SOLVABLE_PROVIDES)
685                     s->provides = ido;
686                   else if (id == SOLVABLE_OBSOLETES)
687                     s->obsoletes = ido;
688                   else if (id == SOLVABLE_CONFLICTS)
689                     s->conflicts = ido;
690                   else if (id == SOLVABLE_REQUIRES)
691                     s->requires = ido;
692                   else if (id == SOLVABLE_RECOMMENDS)
693                     s->recommends= ido;
694                   else if (id == SOLVABLE_SUPPLEMENTS)
695                     s->supplements = ido;
696                   else if (id == SOLVABLE_SUGGESTS)
697                     s->suggests = ido;
698                   else if (id == SOLVABLE_ENHANCES)
699                     s->enhances = ido;
700                   else if (id == SOLVABLE_FRESHENS)
701                     s->freshens = ido;
702                   break;
703                 case TYPE_ATTR_INT:
704                 case TYPE_ATTR_CHUNK:
705                 case TYPE_ATTR_STRING:
706                 case TYPE_ATTR_INTLIST:
707                 case TYPE_ATTR_LOCALIDS:
708                   if (!embedded_store)
709                     embedded_store = new_store (pool);
710                   add_attr_from_file (embedded_store, i, id, type, idmap, numid, fp);
711                   break;
712                 }
713             }
714         }
715       xfree(used);
716       xfree(solvschema);
717       xfree(idmap);
718       xfree(schemata);
719       xfree(schemadata);
720       xfree(keys);
721       mypool = 0;
722       return;
723     }
724   for (i = 0; i < numsolv; i++, s++)
725     {
726       if (exists && !exists[i])
727         continue;
728       Id *keyp = schemadata + schemata[read_id(fp, numschemata)];
729       while ((key = *keyp++) != 0)
730         {
731           id = keys[key].name;
732           switch (keys[key].type)
733             {
734             case TYPE_ID:
735               did = idmap[read_id(fp, numid + numrel)];
736               if (id == SOLVABLE_NAME)
737                 s->name = did;
738               else if (id == SOLVABLE_ARCH)
739                 s->arch = did;
740               else if (id == SOLVABLE_EVR)
741                 s->evr = did;
742               else if (id == SOLVABLE_VENDOR)
743                 s->vendor = did;
744 #if 0
745               POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %s\n", id2str(pool, id), id2str(pool, did));
746 #endif
747               break;
748             case TYPE_U32:
749               h = read_u32(fp);
750 #if 0
751               POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %u\n", id2str(pool, id), h);
752 #endif
753               if (id == RPM_RPMDBID)
754                 {
755                   if (!repo->rpmdbid)
756                     repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
757                   repo->rpmdbid[i] = h;
758                 }
759               break;
760             case TYPE_STR:
761               while(read_u8(fp) != 0)
762                 ;
763               break;
764             case TYPE_IDARRAY:
765             case TYPE_REL_IDARRAY:
766               if (id < INTERESTED_START || id > INTERESTED_END)
767                 {
768                   /* not interested in array */
769                   while ((read_u8(fp) & 0xc0) != 0)
770                     ;
771                   break;
772                 }
773               ido = idarraydatap - repo->idarraydata;
774               idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, keys[key].type == TYPE_REL_IDARRAY);
775               if (id == SOLVABLE_PROVIDES)
776                 s->provides = ido;
777               else if (id == SOLVABLE_OBSOLETES)
778                 s->obsoletes = ido;
779               else if (id == SOLVABLE_CONFLICTS)
780                 s->conflicts = ido;
781               else if (id == SOLVABLE_REQUIRES)
782                 s->requires = ido;
783               else if (id == SOLVABLE_RECOMMENDS)
784                 s->recommends= ido;
785               else if (id == SOLVABLE_SUPPLEMENTS)
786                 s->supplements = ido;
787               else if (id == SOLVABLE_SUGGESTS)
788                 s->suggests = ido;
789               else if (id == SOLVABLE_ENHANCES)
790                 s->enhances = ido;
791               else if (id == SOLVABLE_FRESHENS)
792                 s->freshens = ido;
793 #if 0
794               POOL_DEBUG(SAT_DEBUG_STATS, "%s ->\n", id2str(pool, id));
795               for (; repo->idarraydata[ido]; ido++)
796                 POOL_DEBUG(SAT_DEBUG_STATS,"  %s\n", dep2str(pool, repo->idarraydata[ido]));
797 #endif
798               break;
799             case TYPE_ATTR_INT:
800             case TYPE_ATTR_CHUNK:
801             case TYPE_ATTR_STRING:
802             case TYPE_ATTR_INTLIST:
803             case TYPE_ATTR_LOCALIDS:
804               if (!embedded_store)
805                 embedded_store = new_store (pool);
806               add_attr_from_file (embedded_store, i, id, keys[key].type, idmap, numid, fp);
807               break;
808             }
809         }
810     }
811   xfree(exists);
812   if (embedded_store)
813     {
814       attr_store_pack (embedded_store);
815       /* If we have any attributes we also have pages.  */
816       read_or_setup_pages (fp, embedded_store);
817       repo_add_attrstore (repo, embedded_store);
818     }
819   xfree(idmap);
820   xfree(schemata);
821   xfree(schemadata);
822   xfree(keys);
823   mypool = 0;
824 }
825
826 // EOF