Fix build error about binding python 2.7 path
[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  * Add a repo in solv format
12  *
13  */
14
15
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <string.h>
21
22 #include "repo_solv.h"
23 #include "util.h"
24
25 #include "repopack.h"
26 #include "repopage.h"
27
28 #include "poolid_private.h"     /* WHATPROVIDES_BLOCK */
29
30 #define INTERESTED_START        SOLVABLE_NAME
31 #define INTERESTED_END          SOLVABLE_ENHANCES
32
33 #define SOLV_ERROR_NOT_SOLV     1
34 #define SOLV_ERROR_UNSUPPORTED  2
35 #define SOLV_ERROR_EOF          3
36 #define SOLV_ERROR_ID_RANGE     4
37 #define SOLV_ERROR_OVERFLOW     5
38 #define SOLV_ERROR_CORRUPT      6
39
40
41
42 /*******************************************************************************
43  * functions to extract data from a file handle
44  */
45
46 /*
47  * read u32
48  */
49
50 static unsigned int
51 read_u32(Repodata *data)
52 {
53   int c, i;
54   unsigned int x = 0;
55
56   if (data->error)
57     return 0;
58   for (i = 0; i < 4; i++)
59     {
60       c = getc(data->fp);
61       if (c == EOF)
62         {
63           data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
64           return 0;
65         }
66       x = (x << 8) | c;
67     }
68   return x;
69 }
70
71
72 /*
73  * read u8
74  */
75
76 static unsigned int
77 read_u8(Repodata *data)
78 {
79   int c;
80
81   if (data->error)
82     return 0;
83   c = getc(data->fp);
84   if (c == EOF)
85     {
86       data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
87       return 0;
88     }
89   return c;
90 }
91
92
93 /*
94  * read Id
95  */
96
97 static Id
98 read_id(Repodata *data, Id max)
99 {
100   unsigned int x = 0;
101   int c, i;
102
103   if (data->error)
104     return 0;
105   for (i = 0; i < 5; i++)
106     {
107       c = getc(data->fp);
108       if (c == EOF)
109         {
110           data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
111           return 0;
112         }
113       if (!(c & 128))
114         {
115           x = (x << 7) | c;
116           if (max && x >= (unsigned int)max)
117             {
118               data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_id: id too large (%u/%u)", x, max);
119               return 0;
120             }
121           return x;
122         }
123       x = (x << 7) ^ c ^ 128;
124     }
125   data->error = pool_error(data->repo->pool, SOLV_ERROR_CORRUPT, "read_id: id too long");
126   return 0;
127 }
128
129
130 static Id *
131 read_idarray(Repodata *data, Id max, Id *map, Id *store, Id *end)
132 {
133   unsigned int x = 0;
134   int c;
135
136   if (data->error)
137     return 0;
138   for (;;)
139     {
140       c = getc(data->fp);
141       if (c == EOF)
142         {
143           data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
144           return 0;
145         }
146       if ((c & 128) != 0)
147         {
148           x = (x << 7) ^ c ^ 128;
149           continue;
150         }
151       x = (x << 6) | (c & 63);
152       if (max && x >= (unsigned int)max)
153         {
154           data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_idarray: id too large (%u/%u)", x, max);
155           return 0;
156         }
157       if (map)
158         x = map[x];
159       if (store == end)
160         {
161           data->error = pool_error(data->repo->pool, SOLV_ERROR_OVERFLOW, "read_idarray: array overflow");
162           return 0;
163         }
164       *store++ = x;
165       if ((c & 64) == 0)
166         {
167           if (x == 0)   /* already have trailing zero? */
168             return store;
169           if (store == end)
170             {
171               data->error = pool_error(data->repo->pool, SOLV_ERROR_OVERFLOW, "read_idarray: array overflow");
172               return 0;
173             }
174           *store++ = 0;
175           return store;
176         }
177       x = 0;
178     }
179 }
180
181 static void
182 read_idarray_block(Repodata *data, Id *block, int size)
183 {
184   unsigned char buf[65536 + 5 + 1], *bp = buf, *oldbp;
185   unsigned char cbuf[65536 + 4];        /* can overshoot 4 bytes */
186   int left = 0;
187   int eof = 0;
188   int clen, flags;
189   Id x;
190   for (;;)
191     {
192       if (left < 5 && !eof)
193         {
194           if (left)
195             memmove(buf, bp, left);
196           bp = buf + left;
197           flags = read_u8(data);
198           clen = read_u8(data);
199           clen = (clen << 8) | read_u8(data);
200           if (data->error)
201             return;
202           if (!clen)
203             clen = 65536;
204           eof = flags & 0x80;
205           if (fread(flags & 0x40 ? cbuf : bp, clen, 1, data->fp) != 1)
206             {
207               data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
208               return;
209             }
210           if (flags & 0x40)     /* compressed block */
211             clen = repopagestore_decompress_page(cbuf, clen, bp, 65536);
212           bp = buf;
213           left += clen;
214           bp[left] = 0;         /* make data_read_id return */
215           continue;
216         }
217       if (size < 2)
218         {
219           data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "idarray data overrun in block decompression");
220           return;
221         }
222       oldbp = bp;
223       bp = data_read_id(bp, &x);
224       left -= bp - oldbp;
225       if (left < 0)
226         {
227           data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "compression buffer underrun");
228           return;
229         }
230       size--;
231       *block++ = (x & 63) + (((unsigned int)x & ~127) >> 1) + 1;
232       if ((x & 64) == 0)
233         {
234           *block++ = 0;
235           if (--size == 0)
236             break;
237         }
238     }
239   if (left || !eof)
240     data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "idarray size overrun in block decompression");
241 }
242
243 /*******************************************************************************
244  * functions to extract data from memory
245  */
246
247 /*
248  * read array of Ids
249  */
250
251 static inline unsigned char *
252 data_read_id_max(unsigned char *dp, Id *ret, Id *map, int max, Repodata *data)
253 {
254   Id x;
255   dp = data_read_id(dp, &x);
256   if (x < 0 || (max && x >= max))
257     {
258       data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_id_max: id too large (%u/%u)", x, max);
259       x = 0;
260     }
261   *ret = map ? map[x] : x;
262   return dp;
263 }
264
265 static unsigned char *
266 data_read_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data)
267 {
268   Id *store = *storep;
269   unsigned int x = 0;
270   int c;
271
272   for (;;)
273     {
274       c = *dp++;
275       if ((c & 128) != 0)
276         {
277           x = (x << 7) ^ c ^ 128;
278           continue;
279         }
280       x = (x << 6) | (c & 63);
281       if (max && x >= (unsigned int)max)
282         {
283           data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_idarray: id too large (%u/%u)", x, max);
284           data->error = SOLV_ERROR_ID_RANGE;
285           break;
286         }
287       *store++ = map ? map[x] : x;
288       if ((c & 64) == 0)
289         break;
290       x = 0;
291     }
292   *store++ = 0;
293   *storep = store;
294   return dp;
295 }
296
297 static unsigned char *
298 data_read_rel_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data, Id keyid)
299 {
300   Id marker = 0;
301   Id *store = *storep;
302   Id old = 0;
303   unsigned int x = 0;
304   int c;
305
306   if (keyid == SOLVABLE_REQUIRES)
307     marker = SOLVABLE_PREREQMARKER;
308   if (keyid == SOLVABLE_PROVIDES)
309     marker = SOLVABLE_FILEMARKER;
310   for (;;)
311     {
312       c = *dp++;
313       if ((c & 128) != 0)
314         {
315           x = (x << 7) ^ c ^ 128;
316           continue;
317         }
318       x = (x << 6) | (c & 63);
319       if (x == 0)
320         {
321           if (!(c & 64))
322             break;
323           if (marker)
324             *store++ = marker;
325           old = 0;
326           continue;
327         }
328       x = old + (x - 1);
329       old = x;
330       if (max && x >= (unsigned int)max)
331         {
332           data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_rel_idarray: id too large (%u/%u)", x, max);
333           break;
334         }
335       *store++ = map ? map[x] : x;
336       if (!(c & 64))
337         break;
338       x = 0;
339     }
340   *store++ = 0;
341   *storep = store;
342   return dp;
343 }
344
345
346
347
348 /*******************************************************************************
349  * functions to add data to our incore memory space
350  */
351
352 #define INCORE_ADD_CHUNK 8192
353 #define DATA_READ_CHUNK 8192
354
355 static void
356 incore_add_id(Repodata *data, Id sx)
357 {
358   unsigned int x = (unsigned int)sx;
359   unsigned char *dp;
360   /* make sure we have at least 5 bytes free */
361   if (data->incoredatafree < 5)
362     {
363       data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
364       data->incoredatafree = INCORE_ADD_CHUNK;
365     }
366   dp = data->incoredata + data->incoredatalen;
367   if (x >= (1 << 14))
368     {
369       if (x >= (1 << 28))
370         *dp++ = (x >> 28) | 128;
371       if (x >= (1 << 21))
372         *dp++ = (x >> 21) | 128;
373       *dp++ = (x >> 14) | 128;
374     }
375   if (x >= (1 << 7))
376     *dp++ = (x >> 7) | 128;
377   *dp++ = x & 127;
378   data->incoredatafree -= dp - (data->incoredata + data->incoredatalen);
379   data->incoredatalen = dp - data->incoredata;
380 }
381
382 static void
383 incore_add_sizek(Repodata *data, unsigned int sx)
384 {
385   if (sx < (1 << 22))
386     incore_add_id(data, (Id)(sx << 10));
387   else
388     {
389       if ((sx >> 25) != 0)
390         {
391           incore_add_id(data, (Id)(sx >> 25));
392           data->incoredata[data->incoredatalen - 1] |= 128;
393         }
394       incore_add_id(data, (Id)((sx << 10) | 0x80000000));
395       data->incoredata[data->incoredatalen - 5] = (sx >> 18) | 128;
396     }
397 }
398
399 static void
400 incore_add_ideof(Repodata *data, Id sx, int eof)
401 {
402   unsigned int x = (unsigned int)sx;
403   unsigned char *dp;
404   /* make sure we have at least 5 bytes free */
405   if (data->incoredatafree < 5)
406     {
407       data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
408       data->incoredatafree = INCORE_ADD_CHUNK;
409     }
410   dp = data->incoredata + data->incoredatalen;
411   if (x >= (1 << 13))
412     {
413       if (x >= (1 << 27))
414         *dp++ = (x >> 27) | 128;
415       if (x >= (1 << 20))
416         *dp++ = (x >> 20) | 128;
417       *dp++ = (x >> 13) | 128;
418     }
419   if (x >= (1 << 6))
420     *dp++ = (x >> 6) | 128;
421   *dp++ = eof ? (x & 63) : (x & 63) | 64;
422   data->incoredatafree -= dp - (data->incoredata + data->incoredatalen);
423   data->incoredatalen = dp - data->incoredata;
424 }
425
426 static void
427 incore_add_blob(Repodata *data, unsigned char *buf, int len)
428 {
429   if (data->incoredatafree < (unsigned int)len)
430     {
431       data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK + len);
432       data->incoredatafree = INCORE_ADD_CHUNK + len;
433     }
434   memcpy(data->incoredata + data->incoredatalen, buf, len);
435   data->incoredatafree -= len;
436   data->incoredatalen += len;
437 }
438
439 static void
440 incore_map_idarray(Repodata *data, unsigned char *dp, Id *map, Id max)
441 {
442   /* We have to map the IDs, which might also change
443      the necessary number of bytes, so we can't just copy
444      over the blob and adjust it.  */
445   for (;;)
446     {
447       Id id;
448       int eof;
449       dp = data_read_ideof(dp, &id, &eof);
450       if (id < 0 || (max && id >= max))
451         {
452           data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "incore_map_idarray: id too large (%u/%u)", id, max);
453           break;
454         }
455       if (map)
456         id = map[id];
457       incore_add_ideof(data, id, eof);
458       if (eof)
459         break;
460     }
461 }
462
463 static int
464 convert_idarray_block(Repodata *data, Id *block, Id *map, Id max)
465 {
466   int cnt = 0;
467   int old = 0;
468   for (;;)
469     {
470       Id id = *block;
471       cnt++;
472       if (!id)
473         return cnt;
474       id--;     /* idarray_block unpacking added 1 */
475       if (id < 2 * old)
476         {
477           if (id & 1)
478             id = old - (id >> 1) - 1;
479           else
480             id = old + (id >> 1);
481         }
482       old = id;
483       if (id < 0 || (max && id >= max))
484         {
485           data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "convert_idarray_block: id too large (%u/%u)", id, max);
486           return cnt;
487         }
488       if (map)
489         id = map[id];
490       *block++ = id;
491     }
492 }
493
494 #if 0
495 static void
496 incore_add_u32(Repodata *data, unsigned int x)
497 {
498   unsigned char *dp;
499   /* make sure we have at least 4 bytes free */
500   if (data->incoredatafree < 4)
501     {
502       data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
503       data->incoredatafree = INCORE_ADD_CHUNK;
504     }
505   dp = data->incoredata + data->incoredatalen;
506   *dp++ = x >> 24;
507   *dp++ = x >> 16;
508   *dp++ = x >> 8;
509   *dp++ = x;
510   data->incoredatafree -= 4;
511   data->incoredatalen += 4;
512 }
513
514 static void
515 incore_add_u8(Repodata *data, unsigned int x)
516 {
517   unsigned char *dp;
518   /* make sure we have at least 1 byte free */
519   if (data->incoredatafree < 1)
520     {
521       data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + 1024);
522       data->incoredatafree = 1024;
523     }
524   dp = data->incoredata + data->incoredatalen;
525   *dp++ = x;
526   data->incoredatafree--;
527   data->incoredatalen++;
528 }
529 #endif
530
531
532 /*******************************************************************************
533  * our main function
534  */
535
536 /*
537  * read repo from .solv file and add it to pool
538  */
539
540 int
541 repo_add_solv(Repo *repo, FILE *fp, int flags)
542 {
543   Pool *pool = repo->pool;
544   int i, l;
545   int numid, numrel, numdir, numsolv;
546   int numkeys, numschemata;
547
548   Offset sizeid;
549   Offset *str;                         /* map Id -> Offset into string space */
550   char *strsp;                         /* repo string space */
551   char *sp;                            /* pointer into string space */
552   Id *idmap;                           /* map of repo Ids to pool Ids */
553   Id id, type;
554   Hashval hashmask, h, hh;
555   Hashtable hashtbl;
556   Id name, evr, did;
557   int relflags;
558   Reldep *ran;
559   unsigned int size_idarray;
560   Id *idarraydatap, *idarraydataend;
561   Offset ido;
562   Solvable *s;
563   unsigned int solvflags;
564   unsigned int solvversion;
565   Repokey *keys;
566   Id *schemadata, *schemadatap, *schemadataend;
567   Id *schemata, key, *keyp;
568   int nentries;
569   int have_incoredata;
570   int maxsize, allsize;
571   unsigned char *buf, *bufend, *dp, *dps;
572   Id stack[3 * 5];
573   int keydepth;
574   int needchunk;        /* need a new chunk of data */
575   unsigned int now;
576   int oldnstrings = pool->ss.nstrings;
577   int oldnrels = pool->nrels;
578
579   struct s_Stringpool *spool;
580
581   Repodata *parent = 0;
582   Repodata data;
583
584   int extendstart = 0, extendend = 0;   /* set in case we're extending */
585   int idarray_block_offset = 0;
586   int idarray_block_end = 0;
587
588   now = solv_timems(0);
589
590   if ((flags & REPO_USE_LOADING) != 0)
591     {
592       /* this is a stub replace operation */
593       flags |= REPO_EXTEND_SOLVABLES;
594       /* use REPO_REUSE_REPODATA hack so that the old repodata is kept */
595       parent = repo_add_repodata(repo, flags | REPO_REUSE_REPODATA);
596       extendstart = parent->start;
597       extendend = parent->end;
598     }
599   else if (flags & REPO_EXTEND_SOLVABLES)
600     {
601       /* extend all solvables of this repo */
602       extendstart = repo->start;
603       extendend = repo->end;
604     }
605
606   memset(&data, 0, sizeof(data));
607   data.repo = repo;
608   data.fp = fp;
609   repopagestore_init(&data.store);
610
611   if (read_u32(&data) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
612      return pool_error(pool, SOLV_ERROR_NOT_SOLV, "not a SOLV file");
613   solvversion = read_u32(&data);
614   switch (solvversion)
615     {
616       case SOLV_VERSION_8:
617       case SOLV_VERSION_9:
618         break;
619       default:
620         return pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported SOLV version");
621     }
622
623   numid = (int)read_u32(&data);
624   numrel = (int)read_u32(&data);
625   numdir = (int)read_u32(&data);
626   numsolv = (int)read_u32(&data);
627   numkeys = (int)read_u32(&data);
628   numschemata = (int)read_u32(&data);
629   solvflags = read_u32(&data);
630
631   if (numid < 0 || numid >= 0x20000000)
632     return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of ids");
633   if (numrel < 0 || numrel >= 0x20000000)
634     return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of rels");
635   if (numdir && (numdir < 2 || numdir >= 0x20000000))
636     return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of dirs");
637   if (numsolv < 0 || numsolv >= 0x20000000)
638     return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of solvables");
639   if (numkeys < 0 || numkeys >= 0x20000000)
640     return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of keys");
641   if (numschemata < 0 || numschemata >= 0x20000000)
642     return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of schematas");
643
644   if (numrel && (flags & REPO_LOCALPOOL) != 0)
645     return pool_error(pool, SOLV_ERROR_CORRUPT, "relations are forbidden in a local pool");
646   if ((flags & REPO_EXTEND_SOLVABLES) && numsolv)
647     {
648       /* make sure that we exactly replace the stub repodata */
649       if (extendend - extendstart != numsolv)
650         return pool_error(pool, SOLV_ERROR_CORRUPT, "sub-repository solvable number does not match main repository (%d - %d)", extendend - extendstart, numsolv);
651       for (i = 0; i < numsolv; i++)
652         if (pool->solvables[extendstart + i].repo != repo)
653           return pool_error(pool, SOLV_ERROR_CORRUPT, "main repository contains holes, cannot extend");
654     }
655
656   /*******  Part 0: skip optional userdata ******************************/
657
658   if (solvflags & SOLV_FLAG_USERDATA)
659     {
660       unsigned int userdatalen = read_u32(&data);
661       if (userdatalen >= 65536)
662         return pool_error(pool, SOLV_ERROR_CORRUPT, "illegal userdata length");
663       while (userdatalen--)
664         if (getc(data.fp) == EOF)
665           return pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
666     }
667
668   /*******  Part 1: string IDs  *****************************************/
669
670   sizeid = read_u32(&data);            /* size of string space */
671
672   /*
673    * read strings and Ids
674    *
675    */
676
677
678   /*
679    * alloc buffers
680    */
681
682   if (!(flags & REPO_LOCALPOOL))
683     {
684       spool = &pool->ss;
685       /* alloc max needed string buffer and string pointers, will shrink again later */
686 #if 0
687       spool->stringspace = solv_realloc(spool->stringspace, spool->sstrings + sizeid + 1);
688       spool->strings = solv_realloc2(spool->strings, spool->nstrings + numid, sizeof(Offset));
689 #else
690       spool->sstrings += sizeid + 1;
691       spool->nstrings += numid;
692       stringpool_shrink(spool);         /* we misuse stringpool_shrink so that the correct BLOCK factor is used */
693       spool->sstrings -= sizeid + 1;
694       spool->nstrings -= numid;
695 #endif
696     }
697   else
698     {
699       data.localpool = 1;
700       spool = &data.spool;
701       spool->stringspace = solv_malloc(7 + sizeid + 1);
702       spool->strings = solv_malloc2(numid < 2 ?  2 : numid, sizeof(Offset));
703       strcpy(spool->stringspace, "<NULL>");
704       spool->sstrings = 7;
705       spool->nstrings = 1;
706       spool->strings[0] = 0;    /* <NULL> */
707     }
708
709
710   /*
711    * read string data and append to old string space
712    */
713
714   strsp = spool->stringspace + spool->sstrings; /* append new entries */
715   if ((solvflags & SOLV_FLAG_PREFIX_POOL) == 0)
716     {
717       if (sizeid && fread(strsp, sizeid, 1, fp) != 1)
718         {
719           repodata_freedata(&data);
720           return pool_error(pool, SOLV_ERROR_EOF, "read error while reading strings");
721         }
722     }
723   else
724     {
725       unsigned int pfsize = read_u32(&data);
726       char *prefix = solv_malloc(pfsize);
727       char *pp = prefix;
728       char *old_str = strsp;
729       char *dest = strsp;
730       int freesp = sizeid;
731
732       if (pfsize && fread(prefix, pfsize, 1, fp) != 1)
733         {
734           solv_free(prefix);
735           repodata_freedata(&data);
736           return pool_error(pool, SOLV_ERROR_EOF, "read error while reading strings");
737         }
738       for (i = 1; i < numid; i++)
739         {
740           int same = (unsigned char)*pp++;
741           size_t len = strlen(pp) + 1;
742           freesp -= same + len;
743           if (freesp < 0)
744             {
745               solv_free(prefix);
746               repodata_freedata(&data);
747               return pool_error(pool, SOLV_ERROR_OVERFLOW, "overflow while expanding strings");
748             }
749           if (same)
750             memcpy(dest, old_str, same);
751           memcpy(dest + same, pp, len);
752           pp += len;
753           old_str = dest;
754           dest += same + len;
755         }
756       solv_free(prefix);
757       if (freesp != 0)
758         {
759           repodata_freedata(&data);
760           return pool_error(pool, SOLV_ERROR_CORRUPT, "expanding strings size mismatch");
761         }
762     }
763   strsp[sizeid] = 0;                   /* make string space \0 terminated */
764   sp = strsp;
765
766   /* now merge */
767   str = spool->strings;                 /* array of offsets into strsp, indexed by Id */
768   if ((flags & REPO_LOCALPOOL) != 0)
769     {
770       /* no shared pool, thus no idmap and no unification needed */
771       idmap = 0;
772       spool->nstrings = numid < 2 ? 2 : numid;  /* make sure we have at least id 0 and 1 */
773       if (*sp)
774         {
775           /* we need id 1 to be '' for directories */
776           repodata_freedata(&data);
777           return pool_error(pool, SOLV_ERROR_CORRUPT, "store strings don't start with an empty string");
778         }
779       for (i = 1; i < spool->nstrings; i++)
780         {
781           if (sp >= strsp + sizeid && numid >= 2)
782             {
783               repodata_freedata(&data);
784               return pool_error(pool, SOLV_ERROR_OVERFLOW, "not enough strings");
785             }
786           str[i] = sp - spool->stringspace;
787           sp += strlen(sp) + 1;
788         }
789       spool->sstrings = sp - spool->stringspace;
790     }
791   else
792     {
793       Offset oldsstrings = spool->sstrings;
794
795       /* alloc id map for name and rel Ids. this maps ids in the solv files
796        * to the ids in our pool */
797       idmap = solv_calloc(numid + numrel, sizeof(Id));
798       stringpool_resize_hash(spool, numid);
799       hashtbl = spool->stringhashtbl;
800       hashmask = spool->stringhashmask;
801 #if 0
802       POOL_DEBUG(SOLV_DEBUG_STATS, "read %d strings\n", numid);
803       POOL_DEBUG(SOLV_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
804 #endif
805       /*
806        * run over strings and merge with pool.
807        * we could use stringpool_str2id, but this is faster.
808        * also populate id map (maps solv Id -> pool Id)
809        */
810       for (i = 1; i < numid; i++)
811         {
812           if (sp >= strsp + sizeid)
813             {
814               solv_free(idmap);
815               spool->nstrings = oldnstrings;
816               spool->sstrings = oldsstrings;
817               stringpool_freehash(spool);
818               repodata_freedata(&data);
819               return pool_error(pool, SOLV_ERROR_OVERFLOW, "not enough strings %d %d", i, numid);
820             }
821           if (!*sp)                            /* empty string */
822             {
823               idmap[i] = ID_EMPTY;
824               sp++;
825               continue;
826             }
827
828           /* find hash slot */
829           h = strhash(sp) & hashmask;
830           hh = HASHCHAIN_START;
831           for (;;)
832             {
833               id = hashtbl[h];
834               if (!id)
835                 break;
836               if (!strcmp(spool->stringspace + spool->strings[id], sp))
837                 break;          /* already in pool */
838               h = HASHCHAIN_NEXT(h, hh, hashmask);
839             }
840
841           /* length == offset to next string */
842           l = strlen(sp) + 1;
843           if (!id)             /* end of hash chain -> new string */
844             {
845               id = spool->nstrings++;
846               hashtbl[h] = id;
847               str[id] = spool->sstrings;        /* save offset */
848               if (sp != spool->stringspace + spool->sstrings)
849                 memmove(spool->stringspace + spool->sstrings, sp, l);
850               spool->sstrings += l;
851             }
852           idmap[i] = id;       /* repo relative -> pool relative */
853           sp += l;             /* next string */
854         }
855       stringpool_shrink(spool);         /* vacuum */
856     }
857
858
859   /*******  Part 2: Relation IDs  ***************************************/
860
861   /*
862    * read RelDeps
863    *
864    */
865
866   if (numrel)
867     {
868       /* extend rels */
869       pool->rels = solv_realloc2(pool->rels, pool->nrels + numrel, sizeof(Reldep));
870       ran = pool->rels;
871
872       pool_resize_rels_hash(pool, numrel);
873       hashtbl = pool->relhashtbl;
874       hashmask = pool->relhashmask;
875 #if 0
876       POOL_DEBUG(SOLV_DEBUG_STATS, "read %d rels\n", numrel);
877       POOL_DEBUG(SOLV_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
878 #endif
879
880       /*
881        * read RelDeps from repo
882        */
883       for (i = 0; i < numrel; i++)
884         {
885           name = read_id(&data, i + numid);     /* read (repo relative) Ids */
886           evr = read_id(&data, i + numid);
887           relflags = read_u8(&data);
888           name = idmap[name];           /* map to (pool relative) Ids */
889           evr = idmap[evr];
890           h = relhash(name, evr, relflags) & hashmask;
891           hh = HASHCHAIN_START;
892           for (;;)
893             {
894               id = hashtbl[h];
895               if (!id)          /* end of hash chain reached */
896                 break;
897               if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == relflags)
898                 break;
899               h = HASHCHAIN_NEXT(h, hh, hashmask);
900             }
901           if (!id)              /* new RelDep */
902             {
903               id = pool->nrels++;
904               hashtbl[h] = id;
905               ran[id].name = name;
906               ran[id].evr = evr;
907               ran[id].flags = relflags;
908             }
909           idmap[i + numid] = MAKERELDEP(id);   /* fill Id map */
910         }
911       pool_shrink_rels(pool);           /* vacuum */
912     }
913
914   /* if we added ids/rels, make room in our whatprovide arrays */
915   if (!(flags & REPO_LOCALPOOL))
916     {
917       if (pool->whatprovides && oldnstrings != pool->ss.nstrings)
918         {
919           int newlen = (pool->ss.nstrings + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK;
920           pool->whatprovides = solv_realloc2(pool->whatprovides, newlen, sizeof(Offset));
921           memset(pool->whatprovides + oldnstrings, 0, (newlen - oldnstrings) * sizeof(Offset));
922         }
923       if (pool->whatprovides_rel && oldnrels != pool->nrels)
924         {
925           int newlen = (pool->nrels + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK;
926           pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, newlen, sizeof(Offset));
927           memset(pool->whatprovides_rel + oldnrels, 0, (newlen - oldnrels) * sizeof(Offset));
928         }
929     }
930
931   /*******  Part 3: Dirs  ***********************************************/
932   if (numdir)
933     {
934       data.dirpool.dirs = solv_malloc2(numdir, sizeof(Id));
935       data.dirpool.ndirs = numdir;
936       data.dirpool.dirs[0] = 0;         /* dir 0: virtual root */
937       data.dirpool.dirs[1] = 1;         /* dir 1: / */
938       for (i = 2; i < numdir; i++)
939         {
940           id = read_id(&data, i + numid);
941           if (id >= numid)
942             {
943               data.dirpool.dirs[i++] = -(id - numid);
944               if (i >= numdir)
945                 {
946                   data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "last dir entry is not a component");
947                   break;
948                 }
949               id = read_id(&data, numid);
950             }
951           if (idmap)
952             id = idmap[id];
953           data.dirpool.dirs[i] = id;
954           if (id <= 0)
955             data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "bad dir component");
956         }
957     }
958
959   /*******  Part 4: Keys  ***********************************************/
960
961   keys = solv_calloc(numkeys, sizeof(*keys));
962   /* keys start at 1 */
963   for (i = 1; i < numkeys; i++)
964     {
965       Repokey *key;
966       if (data.error)
967         break;
968       id = read_id(&data, numid);
969       if (idmap)
970         id = idmap[id];
971       else if ((flags & REPO_LOCALPOOL) != 0)
972         id = pool_str2id(pool, stringpool_id2str(spool, id), 1);
973       type = read_id(&data, numid);
974       if (idmap)
975         type = idmap[type];
976       else if ((flags & REPO_LOCALPOOL) != 0)
977         type = pool_str2id(pool, stringpool_id2str(spool, type), 1);
978       if (type < REPOKEY_TYPE_VOID || type > REPOKEY_TYPE_DELETED)
979         {
980           data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported data type '%s'", pool_id2str(pool, type));
981           type = REPOKEY_TYPE_VOID;
982         }
983       key = keys + i;
984       key->name = id;
985       key->type = type;
986       key->size = read_id(&data, type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : 0);
987       key->storage = read_id(&data, 0);
988       /* old versions used SOLVABLE for main solvable data */
989       if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET && key->storage != KEY_STORAGE_SOLVABLE && key->storage != KEY_STORAGE_IDARRAYBLOCK)
990         data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported storage type %d", key->storage);
991       /* change KEY_STORAGE_SOLVABLE to KEY_STORAGE_INCORE */
992       if (key->storage == KEY_STORAGE_SOLVABLE)
993         key->storage = KEY_STORAGE_INCORE;
994       if (key->storage == KEY_STORAGE_IDARRAYBLOCK && type != REPOKEY_TYPE_IDARRAY)
995         data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "typr %d does not support idarrayblock storage\n", type);
996       if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
997         {
998           /* we will put those directly into the storable */
999           if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_IDARRAYBLOCK)
1000             data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "main solvable data must use incore storage, not %d", key->storage);
1001         }
1002       if ((type == REPOKEY_TYPE_FIXARRAY || type == REPOKEY_TYPE_FLEXARRAY) && key->storage != KEY_STORAGE_INCORE)
1003         data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "flex/fixarrays must use incore storage\n");
1004       /* cannot handle rel idarrays in incore/vertical */
1005       if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_INCORE)
1006         data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "type REL_IDARRAY is only supported for STORAGE_INCORE");
1007       /* cannot handle mapped ids in vertical */
1008       if (!(flags & REPO_LOCALPOOL) && key->storage == KEY_STORAGE_VERTICAL_OFFSET && (type == REPOKEY_TYPE_ID || type == REPOKEY_TYPE_IDARRAY))
1009         data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "mapped ids are not supported for STORAGE_VERTICAL_OFFSET");
1010
1011       if (type == REPOKEY_TYPE_CONSTANTID && idmap)
1012         key->size = idmap[key->size];
1013 #if 0
1014       fprintf(stderr, "key %d %s %s %d %d\n", i, pool_id2str(pool, id), pool_id2str(pool, type), key->size, key->storage);
1015 #endif
1016     }
1017
1018   have_incoredata = 0;
1019   for (i = 1; i < numkeys; i++)
1020     {
1021       id = keys[i].name;
1022       if (id == REPOSITORY_SOLVABLES && keys[i].type == REPOKEY_TYPE_FLEXARRAY)
1023         continue;
1024       if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
1025         continue;
1026       have_incoredata = 1;
1027     }
1028
1029   data.keys = keys;
1030   data.nkeys = numkeys;
1031   for (i = 1; i < numkeys; i++)
1032     {
1033       id = keys[i].name;
1034       data.keybits[(id >> 3) & (sizeof(data.keybits) - 1)] |= 1 << (id & 7);
1035     }
1036
1037   /*******  Part 5: Schemata ********************************************/
1038
1039   id = read_id(&data, 0);
1040   schemadata = solv_calloc(id + 1, sizeof(Id));
1041   schemadatap = schemadata + 1;
1042   schemadataend = schemadatap + id;
1043   schemata = solv_calloc(numschemata, sizeof(Id));
1044   for (i = 1; i < numschemata; i++)
1045     {
1046       schemata[i] = schemadatap - schemadata;
1047       schemadatap = read_idarray(&data, numid, 0, schemadatap, schemadataend);
1048 #if 0
1049       Id *sp = schemadata + schemata[i];
1050       fprintf(stderr, "schema %d:", i);
1051       for (; *sp; sp++)
1052         fprintf(stderr, " %d", *sp);
1053       fprintf(stderr, "\n");
1054 #endif
1055     }
1056   data.schemata = schemata;
1057   data.nschemata = numschemata;
1058   data.schemadata = schemadata;
1059   data.schemadatalen = schemadataend - data.schemadata;
1060
1061   /*******  Part 6: Idarray block ***********************************/
1062   if ((solvflags & SOLV_FLAG_IDARRAYBLOCK) != 0)
1063     {
1064       unsigned int idarray_block_size = read_id(&data, 0x30000000);
1065       repo_reserve_ids(repo, 0, idarray_block_size + 1);
1066       idarray_block_offset = repo->idarraysize;
1067       repo->idarraysize += idarray_block_size;
1068       idarray_block_end = repo->idarraysize;
1069       repo->idarraydata[repo->idarraysize++] = 0;
1070       if (idarray_block_size)
1071         read_idarray_block(&data, repo->idarraydata + idarray_block_offset, idarray_block_size);
1072     }
1073
1074   /*******  Part 7: Data ********************************************/
1075
1076   idarraydatap = idarraydataend = 0;
1077   size_idarray = 0;
1078
1079   maxsize = read_id(&data, 0);
1080   allsize = read_id(&data, 0);
1081   maxsize += 5; /* so we can read the next schema of an array */
1082   if (maxsize > allsize)
1083     maxsize = allsize;
1084
1085   buf = solv_calloc(maxsize + DATA_READ_CHUNK + 4, 1);  /* 4 extra bytes to detect overflows */
1086   bufend = buf;
1087   dp = buf;
1088
1089   l = maxsize;
1090   if (l < DATA_READ_CHUNK)
1091     l = DATA_READ_CHUNK;
1092   if (l > allsize)
1093     l = allsize;
1094   if (!l || fread(buf, l, 1, data.fp) != 1)
1095     {
1096       if (!data.error)
1097         data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
1098       id = 0;
1099     }
1100   else
1101     {
1102       bufend = buf + l;
1103       allsize -= l;
1104       dp = data_read_id_max(dp, &id, 0, numschemata, &data);
1105     }
1106
1107   incore_add_id(&data, 0);      /* so that incoreoffset 0 means schema 0 */
1108   incore_add_id(&data, id);     /* main schema id */
1109   keyp = schemadata + schemata[id];
1110   data.mainschema = id;
1111   for (i = 0; keyp[i]; i++)
1112     ;
1113   if (i)
1114     data.mainschemaoffsets = solv_calloc(i, sizeof(Id));
1115
1116   nentries = 0;
1117   keydepth = 0;
1118   s = 0;
1119   needchunk = 1;
1120   for(;;)
1121     {
1122       /* make sure we have enough room */
1123       if (keydepth == 0 || needchunk)
1124         {
1125           int left = bufend - dp;
1126           /* read data chunk to dp */
1127           if (data.error)
1128             break;
1129           if (left < 0)
1130             {
1131               data.error = pool_error(pool, SOLV_ERROR_EOF, "buffer overrun");
1132               break;
1133             }
1134           if (left < maxsize)
1135             {
1136               if (left)
1137                 memmove(buf, dp, left);
1138               l = maxsize - left;
1139               if (l < DATA_READ_CHUNK)
1140                 l = DATA_READ_CHUNK;
1141               if (l > allsize)
1142                 l = allsize;
1143               if (l && fread(buf + left, l, 1, data.fp) != 1)
1144                 {
1145                   data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
1146                   break;
1147                 }
1148               allsize -= l;
1149               left += l;
1150               bufend = buf + left;
1151               if (allsize + left < maxsize)
1152                 maxsize = allsize + left;
1153               dp = buf;
1154             }
1155           needchunk = 0;
1156         }
1157
1158       key = *keyp++;
1159 #if 0
1160 printf("key %d at %d\n", key, (int)(keyp - 1 - schemadata));
1161 #endif
1162       if (!key)
1163         {
1164           if (keydepth <= 3)
1165             needchunk = 1;
1166           if (nentries)
1167             {
1168               if (s && keydepth == 3)
1169                 {
1170                   s++;  /* next solvable */
1171                   if (have_incoredata)
1172                     data.incoreoffset[(s - pool->solvables) - data.start] = data.incoredatalen;
1173                 }
1174               id = stack[keydepth - 1];
1175               if (!id)
1176                 {
1177                   dp = data_read_id_max(dp, &id, 0, numschemata, &data);
1178                   incore_add_id(&data, id);
1179                 }
1180               keyp = schemadata + schemata[id];
1181               nentries--;
1182               continue;
1183             }
1184           if (!keydepth)
1185             break;
1186           --keydepth;
1187           keyp = schemadata + stack[--keydepth];
1188           nentries = stack[--keydepth];
1189 #if 0
1190 printf("pop flexarray %d %d\n", keydepth, nentries);
1191 #endif
1192           if (!keydepth && s)
1193             s = 0;      /* back from solvables */
1194           continue;
1195         }
1196
1197       if (keydepth == 0)
1198         data.mainschemaoffsets[keyp - 1 - (schemadata + schemata[data.mainschema])] = data.incoredatalen;
1199
1200 #if 0
1201 printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, keys[key].type), s);
1202 #endif
1203       id = keys[key].name;
1204       if (keys[key].storage == KEY_STORAGE_VERTICAL_OFFSET)
1205         {
1206           dps = dp;
1207           dp = data_skip(dp, REPOKEY_TYPE_ID);
1208           dp = data_skip(dp, REPOKEY_TYPE_ID);
1209           incore_add_blob(&data, dps, dp - dps);        /* just record offset/size */
1210           continue;
1211         }
1212       switch (keys[key].type)
1213         {
1214         case REPOKEY_TYPE_ID:
1215           dp = data_read_id_max(dp, &did, idmap, numid + numrel, &data);
1216           if (s && id == SOLVABLE_NAME)
1217             s->name = did;
1218           else if (s && id == SOLVABLE_ARCH)
1219             s->arch = did;
1220           else if (s && id == SOLVABLE_EVR)
1221             s->evr = did;
1222           else if (s && id == SOLVABLE_VENDOR)
1223             s->vendor = did;
1224           else if (keys[key].storage == KEY_STORAGE_INCORE)
1225             incore_add_id(&data, did);
1226 #if 0
1227           POOL_DEBUG(SOLV_DEBUG_STATS, "%s -> %s\n", pool_id2str(pool, id), pool_id2str(pool, did));
1228 #endif
1229           break;
1230         case REPOKEY_TYPE_IDARRAY:
1231         case REPOKEY_TYPE_REL_IDARRAY:
1232           if (keys[key].storage == KEY_STORAGE_IDARRAYBLOCK)
1233             {
1234               int cnt = convert_idarray_block(&data, repo->idarraydata + idarray_block_offset, idmap, numid + numrel);
1235               ido = idarray_block_offset;
1236               idarray_block_offset += cnt;
1237               if (idarray_block_offset > idarray_block_end)
1238                 {
1239                   data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray block underflow");
1240                   idarray_block_offset = idarray_block_end;
1241                   break;
1242                 }
1243               if (!s || id < INTERESTED_START || id > INTERESTED_END)
1244                 {
1245                   do
1246                     incore_add_ideof(&data, repo->idarraydata[ido++], --cnt > 1 ? 0 : 1);
1247                   while (cnt > 1);
1248                   break;
1249                 }
1250             }
1251           else
1252             {
1253               if (!s || id < INTERESTED_START || id > INTERESTED_END)
1254                 {
1255                   dps = dp;
1256                   dp = data_skip(dp, REPOKEY_TYPE_IDARRAY);
1257                   if (keys[key].storage != KEY_STORAGE_INCORE)
1258                     break;
1259                   if (idmap)
1260                     incore_map_idarray(&data, dps, idmap, numid + numrel);
1261                   else
1262                     incore_add_blob(&data, dps, dp - dps);
1263                   break;
1264                 }
1265               ido = idarraydatap - repo->idarraydata;
1266               if (keys[key].type == REPOKEY_TYPE_IDARRAY)
1267                 dp = data_read_idarray(dp, &idarraydatap, idmap, numid + numrel, &data);
1268               else
1269                 dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, id);
1270               if (idarraydatap > idarraydataend)
1271                 {
1272                   data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray overflow");
1273                   break;
1274                 }
1275             }
1276           if (id == SOLVABLE_PROVIDES)
1277             s->provides = ido;
1278           else if (id == SOLVABLE_OBSOLETES)
1279             s->obsoletes = ido;
1280           else if (id == SOLVABLE_CONFLICTS)
1281             s->conflicts = ido;
1282           else if (id == SOLVABLE_REQUIRES)
1283             s->requires = ido;
1284           else if (id == SOLVABLE_RECOMMENDS)
1285             s->recommends= ido;
1286           else if (id == SOLVABLE_SUPPLEMENTS)
1287             s->supplements = ido;
1288           else if (id == SOLVABLE_SUGGESTS)
1289             s->suggests = ido;
1290           else if (id == SOLVABLE_ENHANCES)
1291             s->enhances = ido;
1292 #if 0
1293           POOL_DEBUG(SOLV_DEBUG_STATS, "%s ->\n", pool_id2str(pool, id));
1294           for (; repo->idarraydata[ido]; ido++)
1295             POOL_DEBUG(SOLV_DEBUG_STATS,"  %s\n", pool_dep2str(pool, repo->idarraydata[ido]));
1296 #endif
1297           break;
1298         case REPOKEY_TYPE_FIXARRAY:
1299         case REPOKEY_TYPE_FLEXARRAY:
1300           if (!keydepth)
1301             needchunk = 1;
1302           if (keydepth == sizeof(stack)/sizeof(*stack))
1303             {
1304               data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "array stack overflow");
1305               break;
1306             }
1307           stack[keydepth++] = nentries;
1308           stack[keydepth++] = keyp - schemadata;
1309           stack[keydepth++] = 0;
1310           dp = data_read_id_max(dp, &nentries, 0, 0, &data);
1311           incore_add_id(&data, nentries);
1312           if (!nentries)
1313             {
1314               /* zero size array? */
1315               keydepth -= 2;
1316               nentries = stack[--keydepth];
1317               break;
1318             }
1319           if (keydepth == 3 && id == REPOSITORY_SOLVABLES)
1320             {
1321               /* horray! here come the solvables */
1322               if (nentries != numsolv)
1323                 {
1324                   data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "inconsistent number of solvables: %d %d", nentries, numsolv);
1325                   break;
1326                 }
1327               if (idarraydatap)
1328                 {
1329                   data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "more than one solvable block");
1330                   break;
1331                 }
1332               if ((flags & REPO_EXTEND_SOLVABLES) != 0)
1333                 s = pool_id2solvable(pool, extendstart);
1334               else
1335                 s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
1336               data.start = s - pool->solvables;
1337               data.end = data.start + numsolv;
1338               repodata_extend_block(&data, data.start, numsolv);
1339               for (i = 1; i < numkeys; i++)
1340                 {
1341                   id = keys[i].name;
1342                   if ((keys[i].type == REPOKEY_TYPE_IDARRAY || keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
1343                       && id >= INTERESTED_START && id <= INTERESTED_END)
1344                     size_idarray += keys[i].size;
1345                 }
1346               /* allocate needed space in repo */
1347               /* we add maxsize because it is an upper limit for all idarrays, thus we can't overflow */
1348               repo_reserve_ids(repo, 0, size_idarray + maxsize + 1);
1349               idarraydatap = repo->idarraydata + repo->idarraysize;
1350               repo->idarraysize += size_idarray;
1351               idarraydataend = idarraydatap + size_idarray;
1352               repo->lastoff = 0;
1353               if (have_incoredata)
1354                 data.incoreoffset[(s - pool->solvables) - data.start] = data.incoredatalen;
1355             }
1356           nentries--;
1357           dp = data_read_id_max(dp, &id, 0, numschemata, &data);
1358           incore_add_id(&data, id);
1359           if (keys[key].type == REPOKEY_TYPE_FIXARRAY)
1360             {
1361               if (!id)
1362                 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "illegal fixarray");
1363               stack[keydepth - 1] = id;
1364             }
1365           keyp = schemadata + schemata[id];
1366           break;
1367         case REPOKEY_TYPE_NUM:
1368           if (!(solvflags & SOLV_FLAG_SIZE_BYTES) && keys[key].storage == KEY_STORAGE_INCORE &&
1369                 (id == SOLVABLE_INSTALLSIZE || id == SOLVABLE_DOWNLOADSIZE || id == DELTA_DOWNLOADSIZE))
1370             {
1371               /* old solv file with sizes in kilos. transcode. */
1372               dp = data_read_id(dp, &id);
1373               incore_add_sizek(&data, (unsigned int)id);
1374               break;
1375             }
1376           if (s && id == RPM_RPMDBID)
1377             {
1378               dp = data_read_id(dp, &id);
1379               if (!repo->rpmdbid)
1380                 repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
1381               repo->rpmdbid[(s - pool->solvables) - repo->start] = id;
1382               break;
1383             }
1384           /* FALLTHROUGH */
1385         default:
1386           dps = dp;
1387           dp = data_skip(dp, keys[key].type);
1388           if (keys[key].storage == KEY_STORAGE_INCORE)
1389             incore_add_blob(&data, dps, dp - dps);
1390           break;
1391         }
1392     }
1393   /* should shrink idarraydata again */
1394
1395   if (keydepth)
1396     data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF, depth = %d", keydepth);
1397   if (!data.error)
1398     {
1399       if (dp > bufend)
1400         data.error = pool_error(pool, SOLV_ERROR_EOF, "buffer overrun");
1401       else if (idarray_block_offset != idarray_block_end)
1402         data.error = pool_error(pool, SOLV_ERROR_EOF, "unconsumed idarray block entries");
1403     }
1404   solv_free(buf);
1405
1406   if (data.error)
1407     {
1408       /* free solvables */
1409       repo_free_solvable_block(repo, data.start, data.end - data.start, 1);
1410       /* free id array */
1411       repo->idarraysize -= size_idarray;
1412       /* free incore data */
1413       data.incoredata = solv_free(data.incoredata);
1414       data.incoredatalen = data.incoredatafree = 0;
1415     }
1416
1417   if (data.incoredatafree)
1418     {
1419       /* shrink excess size */
1420       data.incoredata = solv_realloc(data.incoredata, data.incoredatalen);
1421       data.incoredatafree = 0;
1422     }
1423   solv_free(idmap);
1424
1425   /* fixup key data */
1426   for (i = 1; i < numkeys; i++)
1427     {
1428       if (keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
1429         keys[i].type = REPOKEY_TYPE_IDARRAY;
1430       if (keys[i].storage == KEY_STORAGE_IDARRAYBLOCK)
1431         keys[i].storage = KEY_STORAGE_INCORE;
1432       if (keys[i].name >= SOLVABLE_NAME && keys[i].name <= RPM_RPMDBID)
1433         keys[i].storage = KEY_STORAGE_SOLVABLE;
1434     }
1435
1436   for (i = 1; i < numkeys; i++)
1437     if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && keys[i].size)
1438       break;
1439   if (i < numkeys && !data.error)
1440     {
1441       Id fileoffset = 0;
1442       unsigned int pagesize;
1443
1444       /* we have vertical data, make it available */
1445       data.verticaloffset = solv_calloc(numkeys, sizeof(Id));
1446       for (i = 1; i < numkeys; i++)
1447         if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
1448           {
1449             data.verticaloffset[i] = fileoffset;
1450             fileoffset += keys[i].size;
1451           }
1452       data.lastverticaloffset = fileoffset;
1453       pagesize = read_u32(&data);
1454       if (!data.error)
1455         {
1456           data.error = repopagestore_read_or_setup_pages(&data.store, data.fp, pagesize, fileoffset);
1457           if (data.error == SOLV_ERROR_EOF)
1458             pool_error(pool, data.error, "repopagestore setup: unexpected EOF");
1459           else if (data.error)
1460             pool_error(pool, data.error, "repopagestore setup failed");
1461         }
1462     }
1463   data.fp = 0; /* no longer needed */
1464
1465   if (data.error)
1466     {
1467       i = data.error;
1468       repodata_freedata(&data);
1469       return i;
1470     }
1471
1472   if (parent)
1473     {
1474       /* overwrite stub repodata */
1475       repodata_freedata(parent);
1476       data.repodataid = parent->repodataid;
1477       data.loadcallback = parent->loadcallback;
1478       *parent = data;
1479     }
1480   else
1481     {
1482       /* make it available as new repodata */
1483       if (!repo->nrepodata)
1484         {
1485           repo->nrepodata = 1;
1486           repo->repodata = solv_calloc(2, sizeof(data));
1487         }
1488       else
1489         repo->repodata = solv_realloc2(repo->repodata, repo->nrepodata + 1, sizeof(data));
1490       data.repodataid = repo->nrepodata;
1491       repo->repodata[repo->nrepodata++] = data;
1492     }
1493
1494   if ((flags & REPO_EXTEND_SOLVABLES) != 0)
1495     {
1496       if (repodata_has_keyname(&data, SOLVABLE_FILELIST))
1497         repodata_set_filelisttype(repo->repodata + data.repodataid, REPODATA_FILELIST_EXTENSION);
1498     }
1499   else
1500     {
1501       if (repodata_lookup_type(&data, SOLVID_META, REPOSITORY_FILTEREDFILELIST))
1502         repodata_set_filelisttype(repo->repodata + data.repodataid, REPODATA_FILELIST_FILTERED);
1503     }
1504
1505   /* create stub repodata entries for all external */
1506   if (!(flags & SOLV_ADD_NO_STUBS) && !parent)
1507     {
1508       for (key = 1 ; key < data.nkeys; key++)
1509         if (data.keys[key].name == REPOSITORY_EXTERNAL && data.keys[key].type == REPOKEY_TYPE_FLEXARRAY)
1510           break;
1511       if (key < data.nkeys)
1512         repodata_create_stubs(repo->repodata + data.repodataid);
1513     }
1514
1515   POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_solv took %d ms\n", solv_timems(now));
1516   POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
1517   POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", data.incoredatalen/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
1518   return 0;
1519 }
1520
1521 int
1522 solv_read_userdata(FILE *fp, unsigned char **datap, int *lenp)
1523 {
1524   unsigned char d[4 * 10], *ud = 0;
1525   unsigned int n;
1526   if (fread(d, sizeof(d), 1, fp) != 1)
1527     return SOLV_ERROR_EOF;
1528   n = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
1529   if (n != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
1530     return SOLV_ERROR_NOT_SOLV;
1531   n = d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7];
1532   switch(n)
1533     {
1534     case SOLV_VERSION_8:
1535     case SOLV_VERSION_9:
1536       break;
1537     default:
1538       return SOLV_ERROR_UNSUPPORTED;
1539     }
1540   n = d[32] << 24 | d[33] << 16 | d[34] << 8 | d[35];
1541   if (!(n & SOLV_FLAG_USERDATA))
1542     n = 0;
1543   else
1544     n = d[36] << 24 | d[37] << 16 | d[38] << 8 | d[39];
1545   if (n >= 65536)
1546     return SOLV_ERROR_CORRUPT;
1547   if (n)
1548     {
1549       ud = solv_malloc(n + 1);
1550       if (fread(ud, n, 1, fp) != 1)
1551         {
1552           solv_free(ud);
1553           return SOLV_ERROR_EOF;
1554         }
1555       ud[n] = 0;
1556     }
1557   *datap = ud;
1558   if (lenp)
1559     *lenp = (int)n;
1560   return 0;
1561 }