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"
28 #include "attr_store_p.h"
30 #define INTERESTED_START SOLVABLE_NAME
31 #define INTERESTED_END SOLVABLE_FRESHENS
33 static Pool *mypool; /* for pool_debug... */
35 /*-----------------------------------------------------------------*/
36 /* .solv read functions */
48 for (i = 0; i < 4; i++)
53 pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
73 pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
85 read_id(FILE *fp, Id max)
90 for (i = 0; i < 5; i++)
95 pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
103 pool_debug(mypool, SAT_FATAL, "read_id: id too large (%u/%u)\n", x, max);
108 x = (x << 7) ^ c ^ 128;
110 pool_debug(mypool, SAT_FATAL, "read_id: id too long\n");
120 read_idarray(FILE *fp, Id max, Id *map, Id *store, Id *end, int relative)
130 pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
135 x = (x << 6) | (c & 63);
138 if (x == 0 && c == 0x40)
143 pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
146 *store++ = SOLVABLE_PREREQMARKER;
156 pool_debug(mypool, SAT_FATAL, "read_idarray: id too large (%u/%u)\n", x, max);
163 pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
169 if (x == 0) /* already have trailing zero? */
173 pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
182 x = (x << 7) ^ c ^ 128;
188 skip_item (FILE *fp, unsigned type, Id *idmap, unsigned numid, unsigned numrel)
193 read_id(fp, numid + numrel); /* just check Id */
198 case TYPE_ATTR_STRING:
200 while(read_u8(fp) != 0)
204 case TYPE_REL_IDARRAY:
205 while ((read_u8(fp) & 0xc0) != 0)
208 case TYPE_COUNT_NAMED:
210 unsigned count = read_id (fp, 0);
213 read_id (fp, numid); /* Name */
214 unsigned t = read_id (fp, TYPE_ATTR_TYPE_MAX + 1);
215 skip_item (fp, t, idmap, numid, numrel);
219 case TYPE_ATTR_CHUNK:
225 case TYPE_ATTR_INTLIST:
226 case TYPE_ATTR_LOCALIDS:
227 while (read_id(fp, 0) != 0)
231 pool_debug(mypool, SAT_FATAL, "unknown type %d\n", type);
236 /*-----------------------------------------------------------------*/
244 // ----------------------------------------------
247 * read repo from .solv file
252 repo_add_solv(Repo *repo, FILE *fp)
254 Pool *pool = repo->pool;
256 unsigned int numid, numrel, numsolv;
257 unsigned int numkeys, numschemata, numinfo;
258 Attrstore *embedded_store = 0;
261 Offset *str; /* map Id -> Offset into string space */
262 char *strsp; /* repo string space */
263 char *sp; /* pointer into string space */
264 Id *idmap; /* map of repo Ids to pool Ids */
266 unsigned int hashmask, h;
272 unsigned int size_idarray;
273 Id *idarraydatap, *idarraydataend;
276 unsigned int solvflags;
277 unsigned int solvversion;
279 Id *schemadata, *schemadatap, *schemadataend;
284 if (read_u32(fp) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
286 pool_debug(pool, SAT_FATAL, "not a SOLV file\n");
289 solvversion = read_u32(fp);
297 pool_debug(pool, SAT_FATAL, "unsupported SOLV version\n");
301 pool_freeidhashes(pool);
303 numid = read_u32(fp);
304 numrel = read_u32(fp);
305 numsolv = read_u32(fp);
306 numkeys = read_u32(fp);
307 numschemata = read_u32(fp);
308 numinfo = read_u32(fp);
309 solvflags = read_u32(fp);
311 if (solvversion < SOLV_VERSION_3
314 pool_debug(pool, SAT_FATAL, "unsupported SOLV format (has info)\n");
318 /******* Part 1: string IDs *****************************************/
320 sizeid = read_u32(fp); /* size of string+Id space */
323 * read strings and Ids
332 /* alloc string buffer */
333 strsp = (char *)xrealloc(pool->ss.stringspace, pool->ss.sstrings + sizeid + 1);
334 /* alloc string offsets (Id -> Offset into string space) */
335 str = (Offset *)xrealloc(pool->ss.strings, (pool->ss.nstrings + numid) * sizeof(Offset));
337 pool->ss.stringspace = strsp;
338 pool->ss.strings = str; /* array of offsets into strsp, indexed by Id */
340 /* point to _BEHIND_ already allocated string/Id space */
341 strsp += pool->ss.sstrings;
343 /* alloc id map for name and rel Ids. this maps ids in the solv files
344 * to the ids in our pool */
345 idmap = (Id *)xcalloc(numid + numrel, sizeof(Id));
348 * read new repo at end of pool
351 if ((solvflags & SOLV_FLAG_PREFIX_POOL) == 0)
353 if (fread(strsp, sizeid, 1, fp) != 1)
355 pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
361 unsigned int pfsize = read_u32 (fp);
362 char *prefix = xmalloc (pfsize);
366 if (fread (prefix, pfsize, 1, fp) != 1)
368 pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
371 for (i = 1; i < numid; i++)
373 int same = (unsigned char)*pp++;
374 size_t len = strlen (pp) + 1;
376 memcpy (dest, old_str, same);
377 memcpy (dest + same, pp, len);
384 strsp[sizeid] = 0; /* make string space \0 terminated */
388 * build hashes for all read strings
392 hashmask = mkmask(pool->ss.nstrings + numid);
395 POOL_DEBUG(SAT_DEBUG_STATS, "read %d strings\n", numid);
396 POOL_DEBUG(SAT_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
400 * ensure sufficient hash size
403 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
406 * fill hashtable with strings already in pool
409 for (i = 1; i < pool->ss.nstrings; i++) /* leave out our dummy zero id */
411 h = strhash(pool->ss.stringspace + pool->ss.strings[i]) & hashmask;
412 hh = HASHCHAIN_START;
414 h = HASHCHAIN_NEXT(h, hh, hashmask);
419 * run over string space, calculate offsets
421 * build id map (maps solv Id -> pool Id)
424 for (i = 1; i < numid; i++)
426 if (sp >= strsp + sizeid)
428 pool_debug(pool, SAT_FATAL, "not enough strings\n");
431 if (!*sp) /* empty string */
439 h = strhash(sp) & hashmask;
440 hh = HASHCHAIN_START;
446 if (!strcmp(pool->ss.stringspace + pool->ss.strings[id], sp))
447 break; /* existing string */
448 h = HASHCHAIN_NEXT(h, hh, hashmask);
451 /* length == offset to next string */
453 if (id == ID_NULL) /* end of hash chain -> new string */
455 id = pool->ss.nstrings++;
457 str[id] = pool->ss.sstrings; /* save Offset */
458 if (sp != pool->ss.stringspace + pool->ss.sstrings) /* not at end-of-buffer */
459 memmove(pool->ss.stringspace + pool->ss.sstrings, sp, l); /* append to pool buffer */
460 pool->ss.sstrings += l;
462 idmap[i] = id; /* repo relative -> pool relative */
463 sp += l; /* next string */
466 pool_shrink_strings(pool); /* vacuum */
469 /******* Part 2: Relation IDs ***************************************/
479 ran = (Reldep *)xrealloc(pool->rels, (pool->nrels + numrel) * sizeof(Reldep));
482 pool_debug(pool, SAT_FATAL, "no mem for rel space\n");
485 pool->rels = ran; /* extended rel space */
487 hashmask = mkmask(pool->nrels + numrel);
489 POOL_DEBUG(SAT_DEBUG_STATS, "read %d rels\n", numrel);
490 POOL_DEBUG(SAT_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
493 * prep hash table with already existing RelDeps
496 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
497 for (i = 1; i < pool->nrels; i++)
499 h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
500 hh = HASHCHAIN_START;
502 h = HASHCHAIN_NEXT(h, hh, hashmask);
507 * read RelDeps from repo
510 for (i = 0; i < numrel; i++)
512 name = read_id(fp, i + numid); /* read (repo relative) Ids */
513 evr = read_id(fp, i + numid);
515 name = idmap[name]; /* map to (pool relative) Ids */
517 h = relhash(name, evr, flags) & hashmask;
518 hh = HASHCHAIN_START;
522 if (id == ID_NULL) /* end of hash chain */
524 if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
526 h = HASHCHAIN_NEXT(h, hh, hashmask);
528 if (id == ID_NULL) /* new RelDep */
534 ran[id].flags = flags;
536 idmap[i + numid] = MAKERELDEP(id); /* fill Id map */
539 pool_shrink_rels(pool); /* vacuum */
543 /******* Part 3: Keys ***********************************************/
545 keys = xcalloc(numkeys, sizeof(*keys));
546 /* keys start at 1 */
547 for (i = 1; i < numkeys; i++)
549 keys[i].name = idmap[read_id(fp, numid)];
550 keys[i].type = read_id(fp, 0);
551 keys[i].size = read_id(fp, 0);
554 /******* Part 4: Schemata ********************************************/
557 schemadata = xcalloc(id, sizeof(Id));
558 schemadatap = schemadata;
559 schemadataend = schemadata + id;
560 schemata = xcalloc(numschemata, sizeof(Id));
561 for (i = 0; i < numschemata; i++)
563 schemata[i] = schemadatap - schemadata;
564 schemadatap = read_idarray(fp, numid, 0, schemadatap, schemadataend, 0);
567 /******* Part 5: Info ***********************************************/
568 /* we skip the info for now... */
569 for (i = 0; i < numinfo; i++)
571 unsigned name = idmap[read_id (fp, numid)];
572 unsigned type = read_id (fp, TYPE_ATTR_TYPE_MAX + 1);
573 if (type == TYPE_COUNT_NAMED
574 && !strcmp (id2str (pool, name), "repodata"))
575 skip_item (fp, type, idmap, numid, numrel);
577 skip_item (fp, type, idmap, numid, numrel);
580 /******* Part 6: packed sizes (optional) ****************************/
582 if ((solvflags & SOLV_FLAG_PACKEDSIZES) != 0)
584 exists = xmalloc (numsolv);
585 for (i = 0; i < numsolv; i++)
586 exists[i] = read_id(fp, 0) != 0;
589 /******* Part 7: item data *******************************************/
591 /* calculate idarray size */
593 for (i = 1; i < numkeys; i++)
596 if ((keys[i].type == TYPE_IDARRAY || keys[i].type == TYPE_REL_IDARRAY)
597 && id >= INTERESTED_START && id <= INTERESTED_END)
598 size_idarray += keys[i].size;
601 /* allocate needed space in repo */
604 repo_reserve_ids(repo, 0, size_idarray);
605 idarraydatap = repo->idarraydata + repo->idarraysize;
606 repo->idarraysize += size_idarray;
607 idarraydataend = repo->idarraydata + repo->idarraysize;
617 s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
619 if ((solvflags & SOLV_FLAG_VERTICAL) != 0)
621 Id *solvschema = xcalloc(numsolv, sizeof(Id));
622 unsigned char *used = xmalloc(numschemata);
623 Solvable *sstart = s;
626 for (i = 0; i < numsolv; i++)
627 solvschema[i] = read_id(fp, numschemata);
628 for (key = 1; key < numkeys; key++)
631 type = keys[key].type;
632 memset(used, 0, numschemata);
633 for (i = 0; i < numschemata; i++)
635 Id *keyp = schemadata + schemata[i];
643 for (i = 0, s = sstart; i < numsolv; i++, s++)
645 if (!used[solvschema[i]])
650 did = idmap[read_id(fp, numid + numrel)];
651 if (id == SOLVABLE_NAME)
653 else if (id == SOLVABLE_ARCH)
655 else if (id == SOLVABLE_EVR)
657 else if (id == SOLVABLE_VENDOR)
662 if (id == RPM_RPMDBID)
665 repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
666 repo->rpmdbid[i] = h;
670 while(read_u8(fp) != 0)
674 case TYPE_REL_IDARRAY:
675 if (id < INTERESTED_START || id > INTERESTED_END)
677 /* not interested in array */
678 while ((read_u8(fp) & 0xc0) != 0)
682 ido = idarraydatap - repo->idarraydata;
683 idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, type == TYPE_REL_IDARRAY);
684 if (id == SOLVABLE_PROVIDES)
686 else if (id == SOLVABLE_OBSOLETES)
688 else if (id == SOLVABLE_CONFLICTS)
690 else if (id == SOLVABLE_REQUIRES)
692 else if (id == SOLVABLE_RECOMMENDS)
694 else if (id == SOLVABLE_SUPPLEMENTS)
695 s->supplements = ido;
696 else if (id == SOLVABLE_SUGGESTS)
698 else if (id == SOLVABLE_ENHANCES)
700 else if (id == SOLVABLE_FRESHENS)
704 case TYPE_ATTR_CHUNK:
705 case TYPE_ATTR_STRING:
706 case TYPE_ATTR_INTLIST:
707 case TYPE_ATTR_LOCALIDS:
709 embedded_store = new_store (pool);
710 add_attr_from_file (embedded_store, i, id, type, idmap, numid, fp);
724 for (i = 0; i < numsolv; i++, s++)
726 if (exists && !exists[i])
728 Id *keyp = schemadata + schemata[read_id(fp, numschemata)];
729 while ((key = *keyp++) != 0)
732 switch (keys[key].type)
735 did = idmap[read_id(fp, numid + numrel)];
736 if (id == SOLVABLE_NAME)
738 else if (id == SOLVABLE_ARCH)
740 else if (id == SOLVABLE_EVR)
742 else if (id == SOLVABLE_VENDOR)
745 POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %s\n", id2str(pool, id), id2str(pool, did));
751 POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %u\n", id2str(pool, id), h);
753 if (id == RPM_RPMDBID)
756 repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
757 repo->rpmdbid[i] = h;
761 while(read_u8(fp) != 0)
765 case TYPE_REL_IDARRAY:
766 if (id < INTERESTED_START || id > INTERESTED_END)
768 /* not interested in array */
769 while ((read_u8(fp) & 0xc0) != 0)
773 ido = idarraydatap - repo->idarraydata;
774 idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, keys[key].type == TYPE_REL_IDARRAY);
775 if (id == SOLVABLE_PROVIDES)
777 else if (id == SOLVABLE_OBSOLETES)
779 else if (id == SOLVABLE_CONFLICTS)
781 else if (id == SOLVABLE_REQUIRES)
783 else if (id == SOLVABLE_RECOMMENDS)
785 else if (id == SOLVABLE_SUPPLEMENTS)
786 s->supplements = ido;
787 else if (id == SOLVABLE_SUGGESTS)
789 else if (id == SOLVABLE_ENHANCES)
791 else if (id == SOLVABLE_FRESHENS)
794 POOL_DEBUG(SAT_DEBUG_STATS, "%s ->\n", id2str(pool, id));
795 for (; repo->idarraydata[ido]; ido++)
796 POOL_DEBUG(SAT_DEBUG_STATS," %s\n", dep2str(pool, repo->idarraydata[ido]));
800 case TYPE_ATTR_CHUNK:
801 case TYPE_ATTR_STRING:
802 case TYPE_ATTR_INTLIST:
803 case TYPE_ATTR_LOCALIDS:
805 embedded_store = new_store (pool);
806 add_attr_from_file (embedded_store, i, id, keys[key].type, idmap, numid, fp);
814 attr_store_pack (embedded_store);
815 /* If we have any attributes we also have pages. */
816 read_or_setup_pages (fp, embedded_store);
817 repo_add_attrstore (repo, embedded_store);