satsolver  0.17.2
repo_solv.c
Go to the documentation of this file.
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 
29 #include "repopack.h"
30 #include "repopage.h"
31 
32 #define INTERESTED_START SOLVABLE_NAME
33 #define INTERESTED_END SOLVABLE_ENHANCES
34 
35 #define SOLV_ERROR_NOT_SOLV 1
36 #define SOLV_ERROR_UNSUPPORTED 2
37 #define SOLV_ERROR_EOF 3
38 #define SOLV_ERROR_ID_RANGE 4
39 #define SOLV_ERROR_OVERFLOW 5
40 #define SOLV_ERROR_CORRUPT 6
41 
42 static Pool *mypool; /* for pool_debug... */
43 
44 
45 
46 /*******************************************************************************
47  * functions to extract data from a file handle
48  */
49 
50 /*
51  * read u32
52  */
53 
54 static unsigned int
56 {
57  int c, i;
58  unsigned int x = 0;
59 
60  if (data->error)
61  return 0;
62  for (i = 0; i < 4; i++)
63  {
64  c = getc(data->fp);
65  if (c == EOF)
66  {
67  pool_debug(mypool, SAT_ERROR, "unexpected EOF\n");
68  data->error = SOLV_ERROR_EOF;
69  return 0;
70  }
71  x = (x << 8) | c;
72  }
73  return x;
74 }
75 
76 
77 /*
78  * read u8
79  */
80 
81 static unsigned int
83 {
84  int c;
85 
86  if (data->error)
87  return 0;
88  c = getc(data->fp);
89  if (c == EOF)
90  {
91  pool_debug(mypool, SAT_ERROR, "unexpected EOF\n");
92  data->error = SOLV_ERROR_EOF;
93  return 0;
94  }
95  return c;
96 }
97 
98 
99 /*
100  * read Id
101  */
102 
103 static Id
104 read_id(Repodata *data, Id max)
105 {
106  unsigned int x = 0;
107  int c, i;
108 
109  if (data->error)
110  return 0;
111  for (i = 0; i < 5; i++)
112  {
113  c = getc(data->fp);
114  if (c == EOF)
115  {
116  pool_debug(mypool, SAT_ERROR, "unexpected EOF\n");
117  data->error = SOLV_ERROR_EOF;
118  return 0;
119  }
120  if (!(c & 128))
121  {
122  x = (x << 7) | c;
123  if (max && x >= max)
124  {
125  pool_debug(mypool, SAT_ERROR, "read_id: id too large (%u/%u)\n", x, max);
126  data->error = SOLV_ERROR_ID_RANGE;
127  return 0;
128  }
129  return x;
130  }
131  x = (x << 7) ^ c ^ 128;
132  }
133  pool_debug(mypool, SAT_ERROR, "read_id: id too long\n");
134  data->error = SOLV_ERROR_CORRUPT;
135  return 0;
136 }
137 
138 
139 static Id *
140 read_idarray(Repodata *data, Id max, Id *map, Id *store, Id *end)
141 {
142  unsigned int x = 0;
143  int c;
144 
145  if (data->error)
146  return 0;
147  for (;;)
148  {
149  c = getc(data->fp);
150  if (c == EOF)
151  {
152  pool_debug(mypool, SAT_ERROR, "unexpected EOF\n");
153  data->error = SOLV_ERROR_EOF;
154  return 0;
155  }
156  if ((c & 128) != 0)
157  {
158  x = (x << 7) ^ c ^ 128;
159  continue;
160  }
161  x = (x << 6) | (c & 63);
162  if (max && x >= max)
163  {
164  pool_debug(mypool, SAT_ERROR, "read_idarray: id too large (%u/%u)\n", x, max);
165  data->error = SOLV_ERROR_ID_RANGE;
166  return 0;
167  }
168  if (map)
169  x = map[x];
170  if (store == end)
171  {
172  pool_debug(mypool, SAT_ERROR, "read_idarray: array overflow\n");
173  return 0;
174  }
175  *store++ = x;
176  if ((c & 64) == 0)
177  {
178  if (x == 0) /* already have trailing zero? */
179  return store;
180  if (store == end)
181  {
182  pool_debug(mypool, SAT_ERROR, "read_idarray: array overflow\n");
183  data->error = SOLV_ERROR_OVERFLOW;
184  return 0;
185  }
186  *store++ = 0;
187  return store;
188  }
189  x = 0;
190  }
191 }
192 
193 
194 /*******************************************************************************
195  * functions to extract data from memory
196  */
197 
198 /*
199  * read array of Ids
200  */
201 
202 static inline unsigned char *
203 data_read_id_max(unsigned char *dp, Id *ret, Id *map, int max, int *error)
204 {
205  Id x;
206  dp = data_read_id(dp, &x);
207  if (max && x >= max)
208  {
209  pool_debug(mypool, SAT_ERROR, "data_read_idarray: id too large (%u/%u)\n", x, max);
210  *error = SOLV_ERROR_ID_RANGE;
211  x = 0;
212  }
213  *ret = map ? map[x] : x;
214  return dp;
215 }
216 
217 static unsigned char *
218 data_read_idarray(unsigned char *dp, Id **storep, Id *map, int max, int *error)
219 {
220  Id *store = *storep;
221  unsigned int x = 0;
222  int c;
223 
224  for (;;)
225  {
226  c = *dp++;
227  if ((c & 128) != 0)
228  {
229  x = (x << 7) ^ c ^ 128;
230  continue;
231  }
232  x = (x << 6) | (c & 63);
233  if (max && x >= max)
234  {
235  pool_debug(mypool, SAT_ERROR, "data_read_idarray: id too large (%u/%u)\n", x, max);
236  *error = SOLV_ERROR_ID_RANGE;
237  break;
238  }
239  *store++ = x;
240  if ((c & 64) == 0)
241  break;
242  x = 0;
243  }
244  *store++ = 0;
245  *storep = store;
246  return dp;
247 }
248 
249 static unsigned char *
250 data_read_rel_idarray(unsigned char *dp, Id **storep, Id *map, int max, int *error, Id marker)
251 {
252  Id *store = *storep;
253  Id old = 0;
254  unsigned int x = 0;
255  int c;
256 
257  for (;;)
258  {
259  c = *dp++;
260  if ((c & 128) != 0)
261  {
262  x = (x << 7) ^ c ^ 128;
263  continue;
264  }
265  x = (x << 6) | (c & 63);
266  if (x == 0)
267  {
268  if (!(c & 64))
269  break;
270  if (marker)
271  *store++ = marker;
272  old = 0;
273  continue;
274  }
275  x = old + (x - 1);
276  old = x;
277  if (max && x >= max)
278  {
279  pool_debug(mypool, SAT_ERROR, "data_read_rel_idarray: id too large (%u/%u)\n", x, max);
280  *error = SOLV_ERROR_ID_RANGE;
281  break;
282  }
283  *store++ = map ? map[x] : x;
284  if (!(c & 64))
285  break;
286  x = 0;
287  }
288  *store++ = 0;
289  *storep = store;
290  return dp;
291 }
292 
293 
294 
295 
296 /*******************************************************************************
297  * functions to add data to our incore memory space
298  */
299 
300 #define INCORE_ADD_CHUNK 8192
301 #define DATA_READ_CHUNK 8192
302 
303 static void
305 {
306  unsigned char *dp;
307  /* make sure we have at least 5 bytes free */
308  if (data->incoredatafree < 5)
309  {
312  }
313  dp = data->incoredata + data->incoredatalen;
314  if (x < 0)
315  abort();
316  if (x >= (1 << 14))
317  {
318  if (x >= (1 << 28))
319  *dp++ = (x >> 28) | 128;
320  if (x >= (1 << 21))
321  *dp++ = (x >> 21) | 128;
322  *dp++ = (x >> 14) | 128;
323  }
324  if (x >= (1 << 7))
325  *dp++ = (x >> 7) | 128;
326  *dp++ = x & 127;
327  data->incoredatafree -= dp - (data->incoredata + data->incoredatalen);
328  data->incoredatalen = dp - data->incoredata;
329 }
330 
331 static void
332 incore_add_blob(Repodata *data, unsigned char *buf, int len)
333 {
334  if (data->incoredatafree < len)
335  {
336  data->incoredata = sat_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK + len);
337  data->incoredatafree = INCORE_ADD_CHUNK + len;
338  }
339  memcpy(data->incoredata + data->incoredatalen, buf, len);
340  data->incoredatafree -= len;
341  data->incoredatalen += len;
342 }
343 
344 static void
345 incore_map_idarray(Repodata *data, unsigned char *dp, Id *map, Id max)
346 {
347  /* We have to map the IDs, which might also change
348  the necessary number of bytes, so we can't just copy
349  over the blob and adjust it. */
350  for (;;)
351  {
352  Id id;
353  int eof;
354  dp = data_read_ideof(dp, &id, &eof);
355  if (max && id >= max)
356  {
357  pool_debug(mypool, SAT_ERROR, "incore_map_idarray: id too large (%u/%u)\n", id, max);
358  data->error = SOLV_ERROR_ID_RANGE;
359  break;
360  }
361  id = map[id];
362  if (id >= 64)
363  id = (id & 63) | ((id & ~63) << 1);
364  incore_add_id(data, eof ? id : id | 64);
365  if (eof)
366  break;
367  }
368 }
369 
370 static void
371 incore_add_u32(Repodata *data, unsigned int x)
372 {
373  unsigned char *dp;
374  /* make sure we have at least 4 bytes free */
375  if (data->incoredatafree < 4)
376  {
379  }
380  dp = data->incoredata + data->incoredatalen;
381  *dp++ = x >> 24;
382  *dp++ = x >> 16;
383  *dp++ = x >> 8;
384  *dp++ = x;
385  data->incoredatafree -= 4;
386  data->incoredatalen += 4;
387 }
388 
389 #if 0
390 static void
391 incore_add_u8(Repodata *data, unsigned int x)
392 {
393  unsigned char *dp;
394  /* make sure we have at least 1 byte free */
395  if (data->incoredatafree < 1)
396  {
397  data->incoredata = sat_realloc(data->incoredata, data->incoredatalen + 1024);
398  data->incoredatafree = 1024;
399  }
400  dp = data->incoredata + data->incoredatalen;
401  *dp++ = x;
402  data->incoredatafree--;
403  data->incoredatalen++;
404 }
405 #endif
406 
407 
408 /*******************************************************************************
409  * our main function
410  */
411 
412 /*
413  * read repo from .solv file and add it to pool
414  */
415 
416 int
417 repo_add_solv_flags(Repo *repo, FILE *fp, int flags)
418 {
419  Pool *pool = repo->pool;
420  int i, l;
421  unsigned int numid, numrel, numdir, numsolv;
422  unsigned int numkeys, numschemata;
423 
424  Offset sizeid;
425  Offset *str; /* map Id -> Offset into string space */
426  char *strsp; /* repo string space */
427  char *sp; /* pointer into string space */
428  Id *idmap; /* map of repo Ids to pool Ids */
429  Id id, type;
430  unsigned int hashmask, h;
431  int hh;
432  Id *hashtbl;
433  Id name, evr, did;
434  int relflags;
435  Reldep *ran;
436  unsigned int size_idarray;
437  Id *idarraydatap, *idarraydataend;
438  Offset ido;
439  Solvable *s;
440  unsigned int solvflags;
441  unsigned int solvversion;
442  Repokey *keys;
443  Id *schemadata, *schemadatap, *schemadataend;
444  Id *schemata, key, *keyp;
445  int nentries;
446  int have_xdata;
447  int maxsize, allsize;
448  unsigned char *buf, *bufend, *dp, *dps;
449  Id stack[3 * 5];
450  int keydepth;
451  int needchunk; /* need a new chunk of data */
452  unsigned int now;
453 
454  struct _Stringpool *spool;
455 
456  Repodata *parent = 0;
457  Repodata data;
458 
459  now = sat_timems(0);
460 
461  if ((flags & REPO_USE_LOADING) != 0)
462  {
463  /* this is a stub replace operation */
464  flags |= REPO_EXTEND_SOLVABLES;
465  /* use REPO_REUSE_REPODATA hack so that the old repodata is kept */
466  parent = repo_add_repodata(repo, flags | REPO_REUSE_REPODATA);
467  }
468 
469  memset(&data, 0, sizeof(data));
470  data.repo = repo;
471  data.fp = fp;
472  repopagestore_init(&data.store);
473 
474  mypool = pool;
475 
476  if (read_u32(&data) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
477  {
478  pool_debug(pool, SAT_ERROR, "not a SOLV file\n");
479  return SOLV_ERROR_NOT_SOLV;
480  }
481  solvversion = read_u32(&data);
482  switch (solvversion)
483  {
484  case SOLV_VERSION_8:
485  break;
486  default:
487  pool_debug(pool, SAT_ERROR, "unsupported SOLV version\n");
488  return SOLV_ERROR_UNSUPPORTED;
489  }
490 
491  pool_freeidhashes(pool);
492 
493  numid = read_u32(&data);
494  numrel = read_u32(&data);
495  numdir = read_u32(&data);
496  numsolv = read_u32(&data);
497  numkeys = read_u32(&data);
498  numschemata = read_u32(&data);
499  solvflags = read_u32(&data);
500 
501  if (numdir && numdir < 2)
502  {
503  pool_debug(pool, SAT_ERROR, "bad number of dirs\n");
504  return SOLV_ERROR_CORRUPT;
505  }
506 
507  if (numrel && (flags & REPO_LOCALPOOL) != 0)
508  {
509  pool_debug(pool, SAT_ERROR, "relations are forbidden in a local pool\n");
510  return SOLV_ERROR_CORRUPT;
511  }
512  if (parent && numsolv)
513  {
514  /* make sure that we exactly replace the stub repodata */
515  if (parent->end - parent->start != numsolv)
516  {
517  pool_debug(pool, SAT_ERROR, "sub-repository solvable number does not match main repository (%d - %d)\n", parent->end - parent->start, numsolv);
518  return SOLV_ERROR_CORRUPT;
519  }
520  for (i = 0; i < numsolv; i++)
521  if (pool->solvables[parent->start + i].repo != repo)
522  {
523  pool_debug(pool, SAT_ERROR, "main repository contains holes\n");
524  return SOLV_ERROR_CORRUPT;
525  }
526  }
527 
528  /******* Part 1: string IDs *****************************************/
529 
530  sizeid = read_u32(&data); /* size of string+Id space */
531 
532  /*
533  * read strings and Ids
534  *
535  */
536 
537 
538  /*
539  * alloc buffers
540  */
541 
542  if (!(flags & REPO_LOCALPOOL))
543  spool = &pool->ss;
544  else
545  {
546  data.localpool = 1;
547  spool = &data.spool;
548  spool->stringspace = sat_malloc(7);
549  strcpy(spool->stringspace, "<NULL>");
550  spool->sstrings = 7;
551  spool->nstrings = 0;
552  }
553 
554  /* alloc string buffer */
555  spool->stringspace = sat_realloc(spool->stringspace, spool->sstrings + sizeid + 1);
556  /* alloc string offsets (Id -> Offset into string space) */
557  spool->strings = sat_realloc2(spool->strings, spool->nstrings + numid, sizeof(Offset));
558 
559  strsp = spool->stringspace;
560  str = spool->strings; /* array of offsets into strsp, indexed by Id */
561 
562  /* point to _BEHIND_ already allocated string/Id space */
563  strsp += spool->sstrings;
564 
565 
566  /*
567  * read new repo at end of pool
568  */
569 
570  if ((solvflags & SOLV_FLAG_PREFIX_POOL) == 0)
571  {
572  if (sizeid && fread(strsp, sizeid, 1, fp) != 1)
573  {
574  pool_debug(pool, SAT_ERROR, "read error while reading strings\n");
575  return SOLV_ERROR_EOF;
576  }
577  }
578  else
579  {
580  unsigned int pfsize = read_u32(&data);
581  char *prefix = sat_malloc(pfsize);
582  char *pp = prefix;
583  char *old_str = 0;
584  char *dest = strsp;
585  int freesp = sizeid;
586 
587  if (pfsize && fread(prefix, pfsize, 1, fp) != 1)
588  {
589  pool_debug(pool, SAT_ERROR, "read error while reading strings\n");
590  sat_free(prefix);
591  return SOLV_ERROR_EOF;
592  }
593  for (i = 1; i < numid; i++)
594  {
595  int same = (unsigned char)*pp++;
596  size_t len = strlen(pp) + 1;
597  freesp -= same + len;
598  if (freesp < 0)
599  {
600  pool_debug(pool, SAT_ERROR, "overflow while expanding strings\n");
601  sat_free(prefix);
602  return SOLV_ERROR_OVERFLOW;
603  }
604  if (same)
605  memcpy(dest, old_str, same);
606  memcpy(dest + same, pp, len);
607  pp += len;
608  old_str = dest;
609  dest += same + len;
610  }
611  sat_free(prefix);
612  if (freesp != 0)
613  {
614  pool_debug(pool, SAT_ERROR, "expanding strings size mismatch\n");
615  return SOLV_ERROR_CORRUPT;
616  }
617  }
618  strsp[sizeid] = 0; /* make string space \0 terminated */
619  sp = strsp;
620 
621  if ((flags & REPO_LOCALPOOL) != 0)
622  {
623  /* no shared pool, thus no idmap and no unification */
624  idmap = 0;
625  spool->nstrings = numid;
626  str[0] = 0;
627  if (*sp)
628  {
629  /* we need the '' for directories */
630  pool_debug(pool, SAT_ERROR, "store strings don't start with ''\n");
631  return SOLV_ERROR_CORRUPT;
632  }
633  for (i = 1; i < spool->nstrings; i++)
634  {
635  if (sp >= strsp + sizeid)
636  {
637  pool_debug(pool, SAT_ERROR, "not enough strings\n");
638  return SOLV_ERROR_OVERFLOW;
639  }
640  str[i] = sp - spool->stringspace;
641  sp += strlen(sp) + 1;
642  }
643  spool->sstrings = sp - spool->stringspace;
644  }
645  else
646  {
647 
648  /* alloc id map for name and rel Ids. this maps ids in the solv files
649  * to the ids in our pool */
650  idmap = sat_calloc(numid + numrel, sizeof(Id));
651 
652  /*
653  * build hashes for all read strings
654  *
655  */
656 
657  hashmask = mkmask(spool->nstrings + numid);
658 
659 #if 0
660  POOL_DEBUG(SAT_DEBUG_STATS, "read %d strings\n", numid);
661  POOL_DEBUG(SAT_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
662 #endif
663 
664  /*
665  * create hashtable with strings already in pool
666  */
667 
668  hashtbl = sat_calloc(hashmask + 1, sizeof(Id));
669  for (i = 1; i < spool->nstrings; i++) /* leave out our dummy zero id */
670  {
671  h = strhash(spool->stringspace + spool->strings[i]) & hashmask;
672  hh = HASHCHAIN_START;
673  while (hashtbl[h])
674  h = HASHCHAIN_NEXT(h, hh, hashmask);
675  hashtbl[h] = i;
676  }
677 
678  /*
679  * run over string space, calculate offsets
680  *
681  * build id map (maps solv Id -> pool Id)
682  */
683 
684  for (i = 1; i < numid; i++)
685  {
686  if (sp >= strsp + sizeid)
687  {
688  sat_free(hashtbl);
689  sat_free(idmap);
690  pool_debug(pool, SAT_ERROR, "not enough strings %d %d\n", i, numid);
691  return SOLV_ERROR_OVERFLOW;
692  }
693  if (!*sp) /* empty string */
694  {
695  idmap[i] = ID_EMPTY;
696  sp++;
697  continue;
698  }
699 
700  /* find hash slot */
701  h = strhash(sp) & hashmask;
702  hh = HASHCHAIN_START;
703  for (;;)
704  {
705  id = hashtbl[h];
706  if (id == 0)
707  break;
708  if (!strcmp(spool->stringspace + spool->strings[id], sp))
709  break; /* existing string */
710  h = HASHCHAIN_NEXT(h, hh, hashmask);
711  }
712 
713  /* length == offset to next string */
714  l = strlen(sp) + 1;
715  if (id == ID_NULL) /* end of hash chain -> new string */
716  {
717  id = spool->nstrings++;
718  hashtbl[h] = id;
719  str[id] = spool->sstrings; /* save Offset */
720  if (sp != spool->stringspace + spool->sstrings) /* not at end-of-buffer */
721  memmove(spool->stringspace + spool->sstrings, sp, l); /* append to pool buffer */
722  spool->sstrings += l;
723  }
724  idmap[i] = id; /* repo relative -> pool relative */
725  sp += l; /* next string */
726  }
727  sat_free(hashtbl);
728  }
729  pool_shrink_strings(pool); /* vacuum */
730 
731 
732  /******* Part 2: Relation IDs ***************************************/
733 
734  /*
735  * read RelDeps
736  *
737  */
738 
739  if (numrel)
740  {
741  /* extend rels */
742  pool->rels = sat_realloc2(pool->rels, pool->nrels + numrel, sizeof(Reldep));
743  ran = pool->rels;
744 
745  hashmask = mkmask(pool->nrels + numrel);
746 #if 0
747  POOL_DEBUG(SAT_DEBUG_STATS, "read %d rels\n", numrel);
748  POOL_DEBUG(SAT_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
749 #endif
750  /*
751  * prep hash table with already existing RelDeps
752  */
753 
754  hashtbl = sat_calloc(hashmask + 1, sizeof(Id));
755  for (i = 1; i < pool->nrels; i++)
756  {
757  h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
758  hh = HASHCHAIN_START;
759  while (hashtbl[h])
760  h = HASHCHAIN_NEXT(h, hh, hashmask);
761  hashtbl[h] = i;
762  }
763 
764  /*
765  * read RelDeps from repo
766  */
767 
768  for (i = 0; i < numrel; i++)
769  {
770  name = read_id(&data, i + numid); /* read (repo relative) Ids */
771  evr = read_id(&data, i + numid);
772  relflags = read_u8(&data);
773  name = idmap[name]; /* map to (pool relative) Ids */
774  evr = idmap[evr];
775  h = relhash(name, evr, relflags) & hashmask;
776  hh = HASHCHAIN_START;
777  for (;;)
778  {
779  id = hashtbl[h];
780  if (id == ID_NULL) /* end of hash chain */
781  break;
782  if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == relflags)
783  break;
784  h = HASHCHAIN_NEXT(h, hh, hashmask);
785  }
786  if (id == ID_NULL) /* new RelDep */
787  {
788  id = pool->nrels++;
789  hashtbl[h] = id;
790  ran[id].name = name;
791  ran[id].evr = evr;
792  ran[id].flags = relflags;
793  }
794  idmap[i + numid] = MAKERELDEP(id); /* fill Id map */
795  }
796  sat_free(hashtbl);
797  pool_shrink_rels(pool); /* vacuum */
798  }
799 
800 
801  /******* Part 3: Dirs ***********************************************/
802  if (numdir)
803  {
804  data.dirpool.dirs = sat_malloc2(numdir, sizeof(Id));
805  data.dirpool.ndirs = numdir;
806  data.dirpool.dirs[0] = 0; /* dir 0: virtual root */
807  data.dirpool.dirs[1] = 1; /* dir 1: / */
808  for (i = 2; i < numdir; i++)
809  {
810  id = read_id(&data, i + numid);
811  if (id >= numid)
812  data.dirpool.dirs[i] = -(id - numid);
813  else if (idmap)
814  data.dirpool.dirs[i] = idmap[id];
815  else
816  data.dirpool.dirs[i] = id;
817  }
818  }
819 
820  /******* Part 4: Keys ***********************************************/
821 
822  keys = sat_calloc(numkeys, sizeof(*keys));
823  /* keys start at 1 */
824  for (i = 1; i < numkeys; i++)
825  {
826  id = read_id(&data, numid);
827  if (idmap)
828  id = idmap[id];
829  else if ((flags & REPO_LOCALPOOL) != 0)
830  id = str2id(pool, stringpool_id2str(spool, id), 1);
831  type = read_id(&data, numid);
832  if (idmap)
833  type = idmap[type];
834  else if ((flags & REPO_LOCALPOOL) != 0)
835  type = str2id(pool, stringpool_id2str(spool, type), 1);
836  if (type < REPOKEY_TYPE_VOID || type > REPOKEY_TYPE_FLEXARRAY)
837  {
838  pool_debug(pool, SAT_ERROR, "unsupported data type '%s'\n", id2str(pool, type));
840  type = REPOKEY_TYPE_VOID;
841  }
842  keys[i].name = id;
843  keys[i].type = type;
844  keys[i].size = read_id(&data, keys[i].type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : 0);
845  keys[i].storage = read_id(&data, 0);
846  /* old versions used SOLVABLE for main solvable data */
847  if (keys[i].storage == KEY_STORAGE_SOLVABLE)
848  keys[i].storage = KEY_STORAGE_INCORE;
849  if (keys[i].storage != KEY_STORAGE_INCORE && keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
850  {
851  pool_debug(pool, SAT_ERROR, "unsupported storage type %d\n", keys[i].storage);
853  }
854  if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
855  {
856  if (keys[i].storage != KEY_STORAGE_INCORE)
857  {
858  pool_debug(pool, SAT_ERROR, "main solvable data must use incore storage%d\n", keys[i].storage);
860  }
861  keys[i].storage = KEY_STORAGE_SOLVABLE;
862  }
863  /* cannot handle rel idarrays in incore/vertical */
864  if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_SOLVABLE)
865  {
866  pool_debug(pool, SAT_ERROR, "type REL_IDARRAY only supported for STORAGE_SOLVABLE\n");
868  }
869  if (keys[i].type == REPOKEY_TYPE_CONSTANTID && idmap)
870  keys[i].size = idmap[keys[i].size];
871 #if 0
872  fprintf(stderr, "key %d %s %s %d %d\n", i, id2str(pool,id), id2str(pool, keys[i].type),
873  keys[i].size, keys[i].storage);
874 #endif
875  }
876 
877  have_xdata = parent ? 1 : 0;
878  for (i = 1; i < numkeys; i++)
879  if (keys[i].storage == KEY_STORAGE_INCORE || keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
880  have_xdata = 1;
881 
882  data.keys = keys;
883  data.nkeys = numkeys;
884  for (i = 1; i < numkeys; i++)
885  {
886  id = keys[i].name;
887  data.keybits[(id >> 3) & (sizeof(data.keybits) - 1)] |= 1 << (id & 7);
888  }
889 
890  /******* Part 5: Schemata ********************************************/
891 
892  id = read_id(&data, 0);
893  schemadata = sat_calloc(id + 1, sizeof(Id));
894  schemadatap = schemadata + 1;
895  schemadataend = schemadatap + id;
896  schemata = sat_calloc(numschemata, sizeof(Id));
897  for (i = 1; i < numschemata; i++)
898  {
899  schemata[i] = schemadatap - schemadata;
900  schemadatap = read_idarray(&data, numid, 0, schemadatap, schemadataend);
901 #if 0
902  Id *sp = schemadata + schemata[i];
903  fprintf(stderr, "schema %d:", i);
904  for (; *sp; sp++)
905  fprintf(stderr, " %d", *sp);
906  fprintf(stderr, "\n");
907 #endif
908  }
909  data.schemata = schemata;
910  data.nschemata = numschemata;
911  data.schemadata = schemadata;
912  data.schemadatalen = schemadataend - data.schemadata;
913 
914  /******* Part 6: Data ********************************************/
915 
916  idarraydatap = idarraydataend = 0;
917  size_idarray = 0;
918 
919  maxsize = read_id(&data, 0);
920  allsize = read_id(&data, 0);
921  maxsize += 5; /* so we can read the next schema of an array */
922  if (maxsize > allsize)
923  maxsize = allsize;
924 
925  buf = sat_calloc(maxsize + DATA_READ_CHUNK + 4, 1); /* 4 extra bytes to detect overflows */
926  bufend = buf;
927  dp = buf;
928 
929  l = maxsize;
930  if (l < DATA_READ_CHUNK)
931  l = DATA_READ_CHUNK;
932  if (l > allsize)
933  l = allsize;
934  if (!l || fread(buf, l, 1, data.fp) != 1)
935  {
936  pool_debug(mypool, SAT_ERROR, "unexpected EOF\n");
937  data.error = SOLV_ERROR_EOF;
938  id = 0;
939  }
940  else
941  {
942  bufend = buf + l;
943  allsize -= l;
944  dp = data_read_id_max(dp, &id, 0, numschemata, &data.error);
945  }
946 
947  incore_add_id(&data, 0); /* XXX? */
948  incore_add_id(&data, id);
949  keyp = schemadata + schemata[id];
950  data.mainschema = id;
951  for (i = 0; keyp[i]; i++)
952  ;
953  if (i)
954  data.mainschemaoffsets = sat_calloc(i, sizeof(Id));
955 
956  nentries = 0;
957  keydepth = 0;
958  s = 0;
959  needchunk = 1;
960  for(;;)
961  {
962  /* make sure we have enough room */
963  if (keydepth == 0 || needchunk)
964  {
965  int left = bufend - dp;
966  /* read data chunk to dp */
967  if (data.error)
968  break;
969  if (left < 0)
970  {
971  pool_debug(mypool, SAT_ERROR, "buffer overrun\n");
972  data.error = SOLV_ERROR_EOF;
973  break;
974  }
975  if (left < maxsize)
976  {
977  if (left)
978  memmove(buf, dp, left);
979  l = maxsize - left;
980  if (l < DATA_READ_CHUNK)
981  l = DATA_READ_CHUNK;
982  if (l > allsize)
983  l = allsize;
984  if (l && fread(buf + left, l, 1, data.fp) != 1)
985  {
986  pool_debug(mypool, SAT_ERROR, "unexpected EOF\n");
987  data.error = SOLV_ERROR_EOF;
988  break;
989  }
990  allsize -= l;
991  left += l;
992  bufend = buf + left;
993  if (allsize + left < maxsize)
994  maxsize = allsize + left;
995  dp = buf;
996  }
997  needchunk = 0;
998  }
999 
1000  key = *keyp++;
1001 #if 0
1002 printf("key %d at %d\n", key, (int)(keyp - 1 - schemadata));
1003 #endif
1004  if (!key)
1005  {
1006  if (keydepth <= 3)
1007  needchunk = 1;
1008  if (nentries)
1009  {
1010  if (s && keydepth == 3)
1011  {
1012  s++; /* next solvable */
1013  if (have_xdata)
1014  data.incoreoffset[(s - pool->solvables) - data.start] = data.incoredatalen;
1015  }
1016  id = stack[keydepth - 1];
1017  if (!id)
1018  {
1019  dp = data_read_id_max(dp, &id, 0, numschemata, &data.error);
1020  incore_add_id(&data, id);
1021  }
1022  keyp = schemadata + schemata[id];
1023  nentries--;
1024  continue;
1025  }
1026  if (!keydepth)
1027  break;
1028  --keydepth;
1029  keyp = schemadata + stack[--keydepth];
1030  nentries = stack[--keydepth];
1031 #if 0
1032 printf("pop flexarray %d %d\n", keydepth, nentries);
1033 #endif
1034  if (!keydepth && s)
1035  s = 0; /* back from solvables */
1036  continue;
1037  }
1038 
1039  if (keydepth == 0)
1040  data.mainschemaoffsets[keyp - 1 - (schemadata + schemata[data.mainschema])] = data.incoredatalen;
1041 
1042 #if 0
1043 printf("=> %s %s %p\n", id2str(pool, keys[key].name), id2str(pool, keys[key].type), s);
1044 #endif
1045  id = keys[key].name;
1046  if (keys[key].storage == KEY_STORAGE_VERTICAL_OFFSET)
1047  {
1048  dps = dp;
1049  dp = data_skip(dp, REPOKEY_TYPE_ID);
1050  dp = data_skip(dp, REPOKEY_TYPE_ID);
1051  incore_add_blob(&data, dps, dp - dps); /* just record offset/size */
1052  continue;
1053  }
1054  switch (keys[key].type)
1055  {
1056  case REPOKEY_TYPE_ID:
1057  dp = data_read_id_max(dp, &did, idmap, numid + numrel, &data.error);
1058  if (s && id == SOLVABLE_NAME)
1059  s->name = did;
1060  else if (s && id == SOLVABLE_ARCH)
1061  s->arch = did;
1062  else if (s && id == SOLVABLE_EVR)
1063  s->evr = did;
1064  else if (s && id == SOLVABLE_VENDOR)
1065  s->vendor = did;
1066  else if (keys[key].storage == KEY_STORAGE_INCORE)
1067  incore_add_id(&data, did);
1068 #if 0
1069  POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %s\n", id2str(pool, id), id2str(pool, did));
1070 #endif
1071  break;
1072  case REPOKEY_TYPE_U32:
1073  dp = data_read_u32(dp, &h);
1074 #if 0
1075  POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %u\n", id2str(pool, id), h);
1076 #endif
1077  if (s && id == RPM_RPMDBID)
1078  {
1079  if (!repo->rpmdbid)
1080  repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
1081  repo->rpmdbid[(s - pool->solvables) - repo->start] = h;
1082  }
1083  else if (keys[key].storage == KEY_STORAGE_INCORE)
1084  incore_add_u32(&data, h);
1085  break;
1086  case REPOKEY_TYPE_IDARRAY:
1087  case REPOKEY_TYPE_REL_IDARRAY:
1088  if (!s || id < INTERESTED_START || id > INTERESTED_END)
1089  {
1090  dps = dp;
1091  dp = data_skip(dp, REPOKEY_TYPE_IDARRAY);
1092  if (keys[key].storage != KEY_STORAGE_INCORE)
1093  break;
1094  if (idmap)
1095  incore_map_idarray(&data, dps, idmap, numid);
1096  else
1097  incore_add_blob(&data, dps, dp - dps);
1098  break;
1099  }
1100  ido = idarraydatap - repo->idarraydata;
1101  if (keys[key].type == REPOKEY_TYPE_IDARRAY)
1102  dp = data_read_idarray(dp, &idarraydatap, idmap, numid + numrel, &data.error);
1103  else if (id == SOLVABLE_REQUIRES)
1104  dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data.error, SOLVABLE_PREREQMARKER);
1105  else if (id == SOLVABLE_PROVIDES)
1106  dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data.error, SOLVABLE_FILEMARKER);
1107  else
1108  dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data.error, 0);
1109  if (idarraydatap > idarraydataend)
1110  {
1111  pool_debug(pool, SAT_ERROR, "idarray overflow\n");
1112  data.error = SOLV_ERROR_OVERFLOW;
1113  break;
1114  }
1115  if (id == SOLVABLE_PROVIDES)
1116  s->provides = ido;
1117  else if (id == SOLVABLE_OBSOLETES)
1118  s->obsoletes = ido;
1119  else if (id == SOLVABLE_CONFLICTS)
1120  s->conflicts = ido;
1121  else if (id == SOLVABLE_REQUIRES)
1122  s->requires = ido;
1123  else if (id == SOLVABLE_RECOMMENDS)
1124  s->recommends= ido;
1125  else if (id == SOLVABLE_SUPPLEMENTS)
1126  s->supplements = ido;
1127  else if (id == SOLVABLE_SUGGESTS)
1128  s->suggests = ido;
1129  else if (id == SOLVABLE_ENHANCES)
1130  s->enhances = ido;
1131 #if 0
1132  POOL_DEBUG(SAT_DEBUG_STATS, "%s ->\n", id2str(pool, id));
1133  for (; repo->idarraydata[ido]; ido++)
1134  POOL_DEBUG(SAT_DEBUG_STATS," %s\n", dep2str(pool, repo->idarraydata[ido]));
1135 #endif
1136  break;
1137  case REPOKEY_TYPE_FIXARRAY:
1138  case REPOKEY_TYPE_FLEXARRAY:
1139  if (!keydepth)
1140  needchunk = 1;
1141  if (keydepth == sizeof(stack)/sizeof(*stack))
1142  {
1143  pool_debug(pool, SAT_ERROR, "array stack overflow\n");
1144  data.error = SOLV_ERROR_CORRUPT;
1145  break;
1146  }
1147  stack[keydepth++] = nentries;
1148  stack[keydepth++] = keyp - schemadata;
1149  stack[keydepth++] = 0;
1150  dp = data_read_id(dp, &nentries);
1151  incore_add_id(&data, nentries);
1152  if (!nentries)
1153  {
1154  /* zero size array? */
1155  keydepth -= 2;
1156  nentries = stack[--keydepth];
1157  break;
1158  }
1159  if (keydepth == 3 && id == REPOSITORY_SOLVABLES)
1160  {
1161  /* horray! here come the solvables */
1162  if (nentries != numsolv)
1163  {
1164  pool_debug(pool, SAT_ERROR, "inconsistent number of solvables: %d %d\n", nentries, numsolv);
1165  data.error = SOLV_ERROR_CORRUPT;
1166  break;
1167  }
1168  if (idarraydatap)
1169  {
1170  pool_debug(pool, SAT_ERROR, "more than one solvable block\n");
1171  data.error = SOLV_ERROR_CORRUPT;
1172  break;
1173  }
1174  if (parent)
1175  s = pool_id2solvable(pool, parent->start);
1176  else
1177  s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
1178  data.start = s - pool->solvables;
1179  data.end = data.start + numsolv;
1180  repodata_extend_block(&data, data.start, numsolv);
1181  for (i = 1; i < numkeys; i++)
1182  {
1183  id = keys[i].name;
1184  if ((keys[i].type == REPOKEY_TYPE_IDARRAY || keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
1185  && id >= INTERESTED_START && id <= INTERESTED_END)
1186  size_idarray += keys[i].size;
1187  }
1188  /* allocate needed space in repo */
1189  /* we add maxsize because it is an upper limit for all idarrays, thus we can't overflow */
1190  repo_reserve_ids(repo, 0, size_idarray + maxsize + 1);
1191  idarraydatap = repo->idarraydata + repo->idarraysize;
1192  repo->idarraysize += size_idarray;
1193  idarraydataend = idarraydatap + size_idarray;
1194  repo->lastoff = 0;
1195  if (have_xdata)
1196  data.incoreoffset[(s - pool->solvables) - data.start] = data.incoredatalen;
1197  }
1198  nentries--;
1199  dp = data_read_id_max(dp, &id, 0, numschemata, &data.error);
1200  incore_add_id(&data, id);
1201  if (keys[key].type == REPOKEY_TYPE_FIXARRAY)
1202  {
1203  if (!id)
1204  {
1205  pool_debug(pool, SAT_ERROR, "illegal fixarray\n");
1206  data.error = SOLV_ERROR_CORRUPT;
1207  }
1208  stack[keydepth - 1] = id;
1209  }
1210  keyp = schemadata + schemata[id];
1211  break;
1212  default:
1213  dps = dp;
1214  dp = data_skip(dp, keys[key].type);
1215  if (keys[key].storage == KEY_STORAGE_INCORE)
1216  incore_add_blob(&data, dps, dp - dps);
1217  break;
1218  }
1219  }
1220  /* should shrink idarraydata again */
1221 
1222  if (keydepth)
1223  {
1224  pool_debug(pool, SAT_ERROR, "unexpected EOF, depth = %d\n", keydepth);
1225  data.error = SOLV_ERROR_CORRUPT;
1226  }
1227  if (!data.error)
1228  {
1229  if (dp > bufend)
1230  {
1231  pool_debug(mypool, SAT_ERROR, "buffer overrun\n");
1232  data.error = SOLV_ERROR_EOF;
1233  }
1234  }
1235  sat_free(buf);
1236 
1237  if (data.error)
1238  {
1239  /* free solvables */
1240  repo_free_solvable_block(repo, data.start, data.end - data.start, 1);
1241  /* free id array */
1242  repo->idarraysize -= size_idarray;
1243  /* free incore data */
1244  data.incoredata = sat_free(data.incoredata);
1245  data.incoredatalen = data.incoredatafree = 0;
1246  }
1247 
1248  if (data.incoredatafree)
1249  {
1250  /* shrink excess size */
1251  data.incoredata = sat_realloc(data.incoredata, data.incoredatalen);
1252  data.incoredatafree = 0;
1253  }
1254 
1255  for (i = 1; i < numkeys; i++)
1256  if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
1257  break;
1258  if (i < numkeys && !data.error)
1259  {
1260  Id fileoffset = 0;
1261  unsigned int pagesize;
1262 
1263  /* we have vertical data, make it available */
1264  data.verticaloffset = sat_calloc(numkeys, sizeof(Id));
1265  for (i = 1; i < numkeys; i++)
1266  if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
1267  {
1268  data.verticaloffset[i] = fileoffset;
1269  fileoffset += keys[i].size;
1270  }
1271  data.lastverticaloffset = fileoffset;
1272  pagesize = read_u32(&data);
1273  data.error = repopagestore_read_or_setup_pages(&data.store, data.fp, pagesize, fileoffset);
1274  }
1275  else
1276  {
1277  /* no longer needed */
1278  data.fp = 0;
1279  }
1280  sat_free(idmap);
1281  mypool = 0;
1282 
1283  if (data.error)
1284  {
1285  /* XXX: free repodata? */
1286  return data.error;
1287  }
1288 
1289  if (parent)
1290  {
1291  /* overwrite stub repodata */
1292  repodata_freedata(parent);
1293  *parent = data;
1294  }
1295  else
1296  {
1297  /* make it available as new repodata */
1298  repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata + 1, sizeof(data));
1299  repo->repodata[repo->nrepodata++] = data;
1300  }
1301 
1302  /* create stub repodata entries for all external */
1303  if (!(flags & SOLV_ADD_NO_STUBS) && !parent)
1304  {
1305  for (key = 1 ; key < data.nkeys; key++)
1306  if (data.keys[key].name == REPOSITORY_EXTERNAL && data.keys[key].type == REPOKEY_TYPE_FLEXARRAY)
1307  break;
1308  if (key < data.nkeys)
1309  repodata_create_stubs(repo->repodata + (repo->nrepodata - 1));
1310  }
1311 
1312  POOL_DEBUG(SAT_DEBUG_STATS, "repo_add_solv took %d ms\n", sat_timems(now));
1313  POOL_DEBUG(SAT_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
1314  POOL_DEBUG(SAT_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", data.incoredatalen/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
1315  return 0;
1316 }
1317 
1318 int
1319 repo_add_solv(Repo *repo, FILE *fp)
1320 {
1321  return repo_add_solv_flags(repo, fp, 0);
1322 }