2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Read the binary dump of a Repo and create a Repo * from it
14 * Repo *pool_addrepo_solv(Pool *pool, FILE *fp)
26 #include "repo_solv.h"
29 #define INTERESTED_START SOLVABLE_NAME
30 #define INTERESTED_END SOLVABLE_FRESHENS
32 /*-----------------------------------------------------------------*/
33 /* .solv read functions */
45 for (i = 0; i < 4; i++)
50 fprintf(stderr, "unexpected EOF\n");
70 fprintf(stderr, "unexpected EOF\n");
82 read_id(FILE *fp, Id max)
87 for (i = 0; i < 5; i++)
92 fprintf(stderr, "unexpected EOF\n");
100 fprintf(stderr, "read_id: id too large (%u/%u)\n", x, max);
105 x = (x << 7) ^ c ^ 128;
107 fprintf(stderr, "read_id: id too long\n");
117 read_idarray(FILE *fp, Id max, Id *map, Id *store, Id *end)
126 fprintf(stderr, "unexpected EOF\n");
131 x = (x << 6) | (c & 63);
134 fprintf(stderr, "read_idarray: id too large (%u/%u)\n", x, max);
139 fprintf(stderr, "read_idarray: array overflow\n");
147 fprintf(stderr, "read_idarray: array overflow\n");
156 x = (x << 7) ^ c ^ 128;
161 /*-----------------------------------------------------------------*/
163 typedef struct solvdata {
170 // ----------------------------------------------
173 * read repo from .solv file
178 repo_add_solv(Repo *repo, FILE *fp)
180 Pool *pool = repo->pool;
182 unsigned int numid, numrel, numsolv, numsrcdata, numsolvdata;
183 int numsolvdatabits, type;
185 Offset *str; /* map Id -> Offset into string space */
186 char *strsp; /* repo string space */
187 char *sp; /* pointer into string space */
188 Id *idmap; /* map of repo Ids to pool Ids */
190 unsigned int hashmask, h;
197 unsigned int size, size_str, size_idarray;
198 Id *idarraydatap, *idarraydataend;
200 unsigned int databits;
203 if (read_u32(fp) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
205 fprintf(stderr, "not a SOLV file\n");
208 if (read_u32(fp) != SOLV_VERSION)
210 fprintf(stderr, "unsupported SOLV version\n");
214 pool_freeidhashes(pool);
216 numid = read_u32(fp);
217 numrel = read_u32(fp);
218 numsolv= read_u32(fp);
220 sizeid = read_u32(fp); /* size of string+Id space */
223 * read strings and Ids
232 /* alloc string buffer */
233 strsp = (char *)xrealloc(pool->stringspace, pool->sstrings + sizeid + 1);
234 /* alloc string offsets (Id -> Offset into string space) */
235 str = (Offset *)xrealloc(pool->strings, (pool->nstrings + numid) * sizeof(Offset));
237 pool->stringspace = strsp;
238 pool->strings = str; /* array of offsets into strsp, indexed by Id */
240 /* point to _BEHIND_ already allocated string/Id space */
241 strsp += pool->sstrings;
243 /* alloc id map for name and rel Ids. this maps ids in the solv files
244 * to the ids in our pool */
245 idmap = (Id *)xcalloc(numid + numrel, sizeof(Id));
248 * read new repo at end of pool
251 if (fread(strsp, sizeid, 1, fp) != 1)
253 fprintf(stderr, "read error while reading strings\n");
256 strsp[sizeid] = 0; /* make string space \0 terminated */
260 * build hashes for all read strings
264 hashmask = mkmask(pool->nstrings + numid);
267 printf("read %d strings\n", numid);
268 printf("string hash buckets: %d\n", hashmask + 1);
272 * ensure sufficient hash size
275 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
278 * fill hashtable with strings already in pool
281 for (i = 1; i < pool->nstrings; i++) /* leave out our dummy zero id */
283 h = strhash(pool->stringspace + pool->strings[i]) & hashmask;
284 hh = HASHCHAIN_START;
286 h = HASHCHAIN_NEXT(h, hh, hashmask);
291 * run over string space, calculate offsets
293 * build id map (maps solv Id -> pool Id)
296 for (i = 1; i < numid; i++)
298 if (sp >= strsp + sizeid)
300 fprintf(stderr, "not enough strings\n");
303 if (!*sp) /* empty string */
311 h = strhash(sp) & hashmask;
312 hh = HASHCHAIN_START;
318 if (!strcmp(pool->stringspace + pool->strings[id], sp))
319 break; /* existing string */
320 h = HASHCHAIN_NEXT(h, hh, hashmask);
323 /* length == offset to next string */
325 if (id == ID_NULL) /* end of hash chain -> new string */
327 id = pool->nstrings++;
329 str[id] = pool->sstrings; /* save Offset */
330 if (sp != pool->stringspace + pool->sstrings) /* not at end-of-buffer */
331 memmove(pool->stringspace + pool->sstrings, sp, l); /* append to pool buffer */
334 idmap[i] = id; /* repo relative -> pool relative */
335 sp += l; /* next string */
338 pool_shrink_strings(pool); /* vacuum */
349 ran = (Reldep *)xrealloc(pool->rels, (pool->nrels + numrel) * sizeof(Reldep));
352 fprintf(stderr, "no mem for rel space\n");
355 pool->rels = ran; /* extended rel space */
357 hashmask = mkmask(pool->nrels + numrel);
359 printf("read %d rels\n", numrel);
360 printf("rel hash buckets: %d\n", hashmask + 1);
363 * prep hash table with already existing RelDeps
366 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
367 for (i = 1; i < pool->nrels; i++)
369 h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
370 hh = HASHCHAIN_START;
372 h = HASHCHAIN_NEXT(h, hh, hashmask);
377 * read RelDeps from repo
380 for (i = 0; i < numrel; i++)
382 name = read_id(fp, i + numid); /* read (repo relative) Ids */
383 evr = read_id(fp, i + numid);
385 name = idmap[name]; /* map to (pool relative) Ids */
387 h = relhash(name, evr, flags) & hashmask;
388 hh = HASHCHAIN_START;
392 if (id == ID_NULL) /* end of hash chain */
394 if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
396 h = HASHCHAIN_NEXT(h, hh, hashmask);
398 if (id == ID_NULL) /* new RelDep */
404 ran[id].flags = flags;
406 idmap[i + numid] = MAKERELDEP(id); /* fill Id map */
409 pool_shrink_rels(pool); /* vacuum */
413 * read (but dont store yet) repo data
417 printf("read repo data\n");
419 numsrcdata = read_u32(fp);
420 for (i = 0; i < numsrcdata; i++)
423 id = idmap[read_id(fp, numid)];
427 read_id(fp, numid + numrel); /* just check Id */
433 while(read_u8(fp) != 0)
437 fprintf(stderr, "unknown type\n");
448 printf("read solvable data info\n");
450 numsolvdata = read_u32(fp);
452 solvdata = (SolvData *)xmalloc(numsolvdata * sizeof(SolvData));
456 for (i = 0; i < numsolvdata; i++)
459 solvdata[i].type = type;
460 if ((type & TYPE_BITMAP) != 0)
465 id = idmap[read_id(fp, numid)];
467 printf("#%d: %s\n", i, id2str(pool, id));
471 solvdata[i].size = size;
472 if (id >= INTERESTED_START && id <= INTERESTED_END)
474 if (type == TYPE_STR)
476 if (type == TYPE_IDARRAY)
477 size_idarray += size;
481 if (numsolvdatabits >= 32)
483 fprintf(stderr, "too many data map bits\n");
487 /* make room for our idarrays */
490 repo_reserve_ids(repo, 0, size_idarray);
491 idarraydatap = repo->idarraydata + repo->idarraysize;
492 repo->idarraysize += size_idarray;
493 idarraydataend = repo->idarraydata + repo->idarraysize;
503 /* alloc space for our solvables */
504 if (numsolv) /* clear newly allocated area */
506 pool->solvables = (Solvable *)xrealloc(pool->solvables, (pool->nsolvables + numsolv) * sizeof(Solvable));
508 memset(pool->solvables + pool->nsolvables, 0, numsolv * sizeof(Solvable));
509 if (!repo->start || repo->start == repo->end)
510 repo->start = pool->nsolvables;
511 repo->end = pool->nsolvables;
519 printf("read solvables\n");
521 for (i = 0, s = pool->solvables + pool->nsolvables; i < numsolv; i++, s++)
527 for (j = 0; j < (numsolvdatabits + 7) >> 3; j++)
528 databits = (databits << 8) | read_u8(fp);
530 for (j = 0; j < numsolvdata; j++)
532 type = solvdata[j].type;
533 if ((type & TYPE_BITMAP) != 0)
547 did = idmap[read_id(fp, numid + numrel)];
548 if (id == SOLVABLE_NAME)
550 else if (id == SOLVABLE_ARCH)
552 else if (id == SOLVABLE_EVR)
554 else if (id == SOLVABLE_VENDOR)
557 printf("%s -> %s\n", id2str(pool, id), id2str(pool, did));
563 printf("%s -> %u\n", id2str(pool, id), h);
565 if (id == RPM_RPMDBID)
568 repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
569 repo->rpmdbid[i] = h;
573 while(read_u8(fp) != 0)
577 if (id < INTERESTED_START || id > INTERESTED_END)
579 /* not interested in array */
580 while ((read_u8(fp) & 0xc0) != 0)
584 ido = idarraydatap - repo->idarraydata;
585 idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend);
586 if (id == SOLVABLE_PROVIDES)
588 else if (id == SOLVABLE_OBSOLETES)
590 else if (id == SOLVABLE_CONFLICTS)
592 else if (id == SOLVABLE_REQUIRES)
594 else if (id == SOLVABLE_RECOMMENDS)
596 else if (id == SOLVABLE_SUPPLEMENTS)
597 s->supplements = ido;
598 else if (id == SOLVABLE_SUGGESTS)
600 else if (id == SOLVABLE_ENHANCES)
602 else if (id == SOLVABLE_FRESHENS)
605 printf("%s ->\n", id2str(pool, id));
606 for (; repo->idarraydata[ido]; ido++)
607 printf(" %s\n", dep2str(pool, repo->idarraydata[ido]));
617 repo->end += numsolv;
618 repo->nsolvables += numsolv;
619 pool->nsolvables += numsolv;