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 static Pool *mypool; /* for pool_debug... */
34 /*-----------------------------------------------------------------*/
35 /* .solv read functions */
47 for (i = 0; i < 4; i++)
52 pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
72 pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
84 read_id(FILE *fp, Id max)
89 for (i = 0; i < 5; i++)
94 pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
102 pool_debug(mypool, SAT_FATAL, "read_id: id too large (%u/%u)\n", x, max);
107 x = (x << 7) ^ c ^ 128;
109 pool_debug(mypool, SAT_FATAL, "read_id: id too long\n");
119 read_idarray(FILE *fp, Id max, Id *map, Id *store, Id *end, int relative)
129 pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
134 x = (x << 6) | (c & 63);
135 if (!relative || x != 0)
145 pool_debug(mypool, SAT_FATAL, "read_idarray: id too large (%u/%u)\n", x, max);
152 /* (relative && x==0) :
153 Ugly PREREQ handling. See repo_write.c. */
154 x = SOLVABLE_PREREQMARKER, old = 0;
157 pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
165 pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
174 x = (x << 7) ^ c ^ 128;
179 /*-----------------------------------------------------------------*/
188 // ----------------------------------------------
191 * read repo from .solv file
196 repo_add_solv(Repo *repo, FILE *fp)
198 Pool *pool = repo->pool;
200 unsigned int numid, numrel, numsolv;
201 unsigned int numkeys, numschemata, numinfo;
205 Offset *str; /* map Id -> Offset into string space */
206 char *strsp; /* repo string space */
207 char *sp; /* pointer into string space */
208 Id *idmap; /* map of repo Ids to pool Ids */
210 unsigned int hashmask, h;
216 unsigned int size_idarray;
217 Id *idarraydatap, *idarraydataend;
220 unsigned int solvflags;
221 unsigned int solvversion;
223 Id *schemadata, *schemadatap, *schemadataend;
228 if (read_u32(fp) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
230 pool_debug(pool, SAT_FATAL, "not a SOLV file\n");
233 solvversion = read_u32(fp);
240 pool_debug(pool, SAT_FATAL, "unsupported SOLV version\n");
244 pool_freeidhashes(pool);
246 numid = read_u32(fp);
247 numrel = read_u32(fp);
248 numsolv = read_u32(fp);
249 numkeys = read_u32(fp);
250 numschemata = read_u32(fp);
251 numinfo = read_u32(fp);
252 solvflags = read_u32(fp);
254 /******* Part 1: string IDs *****************************************/
256 sizeid = read_u32(fp); /* size of string+Id space */
259 * read strings and Ids
268 /* alloc string buffer */
269 strsp = (char *)xrealloc(pool->ss.stringspace, pool->ss.sstrings + sizeid + 1);
270 /* alloc string offsets (Id -> Offset into string space) */
271 str = (Offset *)xrealloc(pool->ss.strings, (pool->ss.nstrings + numid) * sizeof(Offset));
273 pool->ss.stringspace = strsp;
274 pool->ss.strings = str; /* array of offsets into strsp, indexed by Id */
276 /* point to _BEHIND_ already allocated string/Id space */
277 strsp += pool->ss.sstrings;
279 /* alloc id map for name and rel Ids. this maps ids in the solv files
280 * to the ids in our pool */
281 idmap = (Id *)xcalloc(numid + numrel, sizeof(Id));
284 * read new repo at end of pool
287 if ((solvflags & SOLV_FLAG_PREFIX_POOL) == 0)
289 if (fread(strsp, sizeid, 1, fp) != 1)
291 pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
297 unsigned int pfsize = read_u32 (fp);
298 char *prefix = xmalloc (pfsize);
302 if (fread (prefix, pfsize, 1, fp) != 1)
304 pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
307 for (i = 1; i < numid; i++)
309 int same = (unsigned char)*pp++;
310 size_t len = strlen (pp) + 1;
312 memcpy (dest, old_str, same);
313 memcpy (dest + same, pp, len);
320 strsp[sizeid] = 0; /* make string space \0 terminated */
324 * build hashes for all read strings
328 hashmask = mkmask(pool->ss.nstrings + numid);
331 POOL_DEBUG(SAT_DEBUG_STATS, "read %d strings\n", numid);
332 POOL_DEBUG(SAT_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
336 * ensure sufficient hash size
339 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
342 * fill hashtable with strings already in pool
345 for (i = 1; i < pool->ss.nstrings; i++) /* leave out our dummy zero id */
347 h = strhash(pool->ss.stringspace + pool->ss.strings[i]) & hashmask;
348 hh = HASHCHAIN_START;
350 h = HASHCHAIN_NEXT(h, hh, hashmask);
355 * run over string space, calculate offsets
357 * build id map (maps solv Id -> pool Id)
360 for (i = 1; i < numid; i++)
362 if (sp >= strsp + sizeid)
364 pool_debug(pool, SAT_FATAL, "not enough strings\n");
367 if (!*sp) /* empty string */
375 h = strhash(sp) & hashmask;
376 hh = HASHCHAIN_START;
382 if (!strcmp(pool->ss.stringspace + pool->ss.strings[id], sp))
383 break; /* existing string */
384 h = HASHCHAIN_NEXT(h, hh, hashmask);
387 /* length == offset to next string */
389 if (id == ID_NULL) /* end of hash chain -> new string */
391 id = pool->ss.nstrings++;
393 str[id] = pool->ss.sstrings; /* save Offset */
394 if (sp != pool->ss.stringspace + pool->ss.sstrings) /* not at end-of-buffer */
395 memmove(pool->ss.stringspace + pool->ss.sstrings, sp, l); /* append to pool buffer */
396 pool->ss.sstrings += l;
398 idmap[i] = id; /* repo relative -> pool relative */
399 sp += l; /* next string */
402 pool_shrink_strings(pool); /* vacuum */
405 /******* Part 2: Relation IDs ***************************************/
415 ran = (Reldep *)xrealloc(pool->rels, (pool->nrels + numrel) * sizeof(Reldep));
418 pool_debug(pool, SAT_FATAL, "no mem for rel space\n");
421 pool->rels = ran; /* extended rel space */
423 hashmask = mkmask(pool->nrels + numrel);
425 POOL_DEBUG(SAT_DEBUG_STATS, "read %d rels\n", numrel);
426 POOL_DEBUG(SAT_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
429 * prep hash table with already existing RelDeps
432 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
433 for (i = 1; i < pool->nrels; i++)
435 h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
436 hh = HASHCHAIN_START;
438 h = HASHCHAIN_NEXT(h, hh, hashmask);
443 * read RelDeps from repo
446 for (i = 0; i < numrel; i++)
448 name = read_id(fp, i + numid); /* read (repo relative) Ids */
449 evr = read_id(fp, i + numid);
451 name = idmap[name]; /* map to (pool relative) Ids */
453 h = relhash(name, evr, flags) & hashmask;
454 hh = HASHCHAIN_START;
458 if (id == ID_NULL) /* end of hash chain */
460 if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
462 h = HASHCHAIN_NEXT(h, hh, hashmask);
464 if (id == ID_NULL) /* new RelDep */
470 ran[id].flags = flags;
472 idmap[i + numid] = MAKERELDEP(id); /* fill Id map */
475 pool_shrink_rels(pool); /* vacuum */
479 /******* Part 3: Keys ***********************************************/
481 keys = xcalloc(numkeys, sizeof(*keys));
482 /* keys start at 1 */
483 for (i = 1; i < numkeys; i++)
485 keys[i].name = idmap[read_id(fp, numid)];
486 keys[i].type = read_id(fp, 0);
487 keys[i].size = read_id(fp, 0);
490 /******* Part 4: Schemata ********************************************/
493 schemadata = xcalloc(id, sizeof(Id));
494 schemadatap = schemadata;
495 schemadataend = schemadata + id;
496 schemata = xcalloc(numschemata, sizeof(Id));
497 for (i = 0; i < numschemata; i++)
499 schemata[i] = schemadatap - schemadata;
500 schemadatap = read_idarray(fp, numid, 0, schemadatap, schemadataend, 0);
503 /******* Part 5: Info ***********************************************/
504 /* we skip the info for now... */
505 for (i = 0; i < numinfo; i++)
507 Id *schema = schemadata + schemata[read_id(fp, numschemata)];
508 while ((key = *schema++) != 0)
510 type = keys[key].type;
514 read_id(fp, numid + numrel); /* just check Id */
520 while(read_u8(fp) != 0)
524 case TYPE_REL_IDARRAY:
525 while ((read_u8(fp) & 0xc0) != 0)
529 pool_debug(pool, SAT_FATAL, "unknown type %d\n", type);
535 /******* Part 6: packed sizes (optional) ****************************/
536 if ((solvflags & SOLV_FLAG_PACKEDSIZES) != 0)
538 for (i = 0; i < numsolv; i++)
542 /******* Part 7: item data *******************************************/
544 /* calculate idarray size */
546 for (i = 1; i < numkeys; i++)
549 if ((keys[i].type == TYPE_IDARRAY || keys[i].type == TYPE_REL_IDARRAY)
550 && id >= INTERESTED_START && id <= INTERESTED_END)
551 size_idarray += keys[i].size;
554 /* allocate needed space in repo */
557 repo_reserve_ids(repo, 0, size_idarray);
558 idarraydatap = repo->idarraydata + repo->idarraysize;
559 repo->idarraysize += size_idarray;
560 idarraydataend = repo->idarraydata + repo->idarraysize;
570 s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
572 if ((solvflags & SOLV_FLAG_VERTICAL) != 0)
574 Id *solvschema = xcalloc(numsolv, sizeof(Id));
575 unsigned char *used = xmalloc(numschemata);
576 Solvable *sstart = s;
579 for (i = 0; i < numsolv; i++)
580 solvschema[i] = read_id(fp, numschemata);
581 for (key = 1; key < numkeys; key++)
584 type = keys[key].type;
585 memset(used, 0, numschemata);
586 for (i = 0; i < numschemata; i++)
588 Id *keyp = schemadata + schemata[i];
596 for (i = 0, s = sstart; i < numsolv; i++, s++)
598 if (!used[solvschema[i]])
603 did = idmap[read_id(fp, numid + numrel)];
604 if (id == SOLVABLE_NAME)
606 else if (id == SOLVABLE_ARCH)
608 else if (id == SOLVABLE_EVR)
610 else if (id == SOLVABLE_VENDOR)
615 if (id == RPM_RPMDBID)
618 repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
619 repo->rpmdbid[i] = h;
623 while(read_u8(fp) != 0)
627 case TYPE_REL_IDARRAY:
628 if (id < INTERESTED_START || id > INTERESTED_END)
630 /* not interested in array */
631 while ((read_u8(fp) & 0xc0) != 0)
635 ido = idarraydatap - repo->idarraydata;
636 idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, type == TYPE_REL_IDARRAY);
637 if (id == SOLVABLE_PROVIDES)
639 else if (id == SOLVABLE_OBSOLETES)
641 else if (id == SOLVABLE_CONFLICTS)
643 else if (id == SOLVABLE_REQUIRES)
645 else if (id == SOLVABLE_RECOMMENDS)
647 else if (id == SOLVABLE_SUPPLEMENTS)
648 s->supplements = ido;
649 else if (id == SOLVABLE_SUGGESTS)
651 else if (id == SOLVABLE_ENHANCES)
653 else if (id == SOLVABLE_FRESHENS)
668 for (i = 0; i < numsolv; i++, s++)
670 Id *keyp = schemadata + schemata[read_id(fp, numschemata)];
671 while ((key = *keyp++) != 0)
674 switch (keys[key].type)
677 did = idmap[read_id(fp, numid + numrel)];
678 if (id == SOLVABLE_NAME)
680 else if (id == SOLVABLE_ARCH)
682 else if (id == SOLVABLE_EVR)
684 else if (id == SOLVABLE_VENDOR)
687 POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %s\n", id2str(pool, id), id2str(pool, did));
693 POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %u\n", id2str(pool, id), h);
695 if (id == RPM_RPMDBID)
698 repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
699 repo->rpmdbid[i] = h;
703 while(read_u8(fp) != 0)
707 case TYPE_REL_IDARRAY:
708 if (id < INTERESTED_START || id > INTERESTED_END)
710 /* not interested in array */
711 while ((read_u8(fp) & 0xc0) != 0)
715 ido = idarraydatap - repo->idarraydata;
716 idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, keys[key].type == TYPE_REL_IDARRAY);
717 if (id == SOLVABLE_PROVIDES)
719 else if (id == SOLVABLE_OBSOLETES)
721 else if (id == SOLVABLE_CONFLICTS)
723 else if (id == SOLVABLE_REQUIRES)
725 else if (id == SOLVABLE_RECOMMENDS)
727 else if (id == SOLVABLE_SUPPLEMENTS)
728 s->supplements = ido;
729 else if (id == SOLVABLE_SUGGESTS)
731 else if (id == SOLVABLE_ENHANCES)
733 else if (id == SOLVABLE_FRESHENS)
736 POOL_DEBUG(SAT_DEBUG_STATS, "%s ->\n", id2str(pool, id));
737 for (; repo->idarraydata[ido]; ido++)
738 POOL_DEBUG(SAT_DEBUG_STATS," %s\n", dep2str(pool, repo->idarraydata[ido]));