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;
187 /*-----------------------------------------------------------------*/
195 // ----------------------------------------------
198 * read repo from .solv file
203 repo_add_solv(Repo *repo, FILE *fp)
205 Pool *pool = repo->pool;
207 unsigned int numid, numrel, numsolv;
208 unsigned int numkeys, numschemata, numinfo;
209 Attrstore *embedded_store = 0;
213 Offset *str; /* map Id -> Offset into string space */
214 char *strsp; /* repo string space */
215 char *sp; /* pointer into string space */
216 Id *idmap; /* map of repo Ids to pool Ids */
218 unsigned int hashmask, h;
224 unsigned int size_idarray;
225 Id *idarraydatap, *idarraydataend;
228 unsigned int solvflags;
229 unsigned int solvversion;
231 Id *schemadata, *schemadatap, *schemadataend;
236 if (read_u32(fp) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
238 pool_debug(pool, SAT_FATAL, "not a SOLV file\n");
241 solvversion = read_u32(fp);
248 pool_debug(pool, SAT_FATAL, "unsupported SOLV version\n");
252 pool_freeidhashes(pool);
254 numid = read_u32(fp);
255 numrel = read_u32(fp);
256 numsolv = read_u32(fp);
257 numkeys = read_u32(fp);
258 numschemata = read_u32(fp);
259 numinfo = read_u32(fp);
260 solvflags = read_u32(fp);
262 /******* Part 1: string IDs *****************************************/
264 sizeid = read_u32(fp); /* size of string+Id space */
267 * read strings and Ids
276 /* alloc string buffer */
277 strsp = (char *)xrealloc(pool->ss.stringspace, pool->ss.sstrings + sizeid + 1);
278 /* alloc string offsets (Id -> Offset into string space) */
279 str = (Offset *)xrealloc(pool->ss.strings, (pool->ss.nstrings + numid) * sizeof(Offset));
281 pool->ss.stringspace = strsp;
282 pool->ss.strings = str; /* array of offsets into strsp, indexed by Id */
284 /* point to _BEHIND_ already allocated string/Id space */
285 strsp += pool->ss.sstrings;
287 /* alloc id map for name and rel Ids. this maps ids in the solv files
288 * to the ids in our pool */
289 idmap = (Id *)xcalloc(numid + numrel, sizeof(Id));
292 * read new repo at end of pool
295 if ((solvflags & SOLV_FLAG_PREFIX_POOL) == 0)
297 if (fread(strsp, sizeid, 1, fp) != 1)
299 pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
305 unsigned int pfsize = read_u32 (fp);
306 char *prefix = xmalloc (pfsize);
310 if (fread (prefix, pfsize, 1, fp) != 1)
312 pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
315 for (i = 1; i < numid; i++)
317 int same = (unsigned char)*pp++;
318 size_t len = strlen (pp) + 1;
320 memcpy (dest, old_str, same);
321 memcpy (dest + same, pp, len);
328 strsp[sizeid] = 0; /* make string space \0 terminated */
332 * build hashes for all read strings
336 hashmask = mkmask(pool->ss.nstrings + numid);
339 POOL_DEBUG(SAT_DEBUG_STATS, "read %d strings\n", numid);
340 POOL_DEBUG(SAT_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
344 * ensure sufficient hash size
347 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
350 * fill hashtable with strings already in pool
353 for (i = 1; i < pool->ss.nstrings; i++) /* leave out our dummy zero id */
355 h = strhash(pool->ss.stringspace + pool->ss.strings[i]) & hashmask;
356 hh = HASHCHAIN_START;
358 h = HASHCHAIN_NEXT(h, hh, hashmask);
363 * run over string space, calculate offsets
365 * build id map (maps solv Id -> pool Id)
368 for (i = 1; i < numid; i++)
370 if (sp >= strsp + sizeid)
372 pool_debug(pool, SAT_FATAL, "not enough strings\n");
375 if (!*sp) /* empty string */
383 h = strhash(sp) & hashmask;
384 hh = HASHCHAIN_START;
390 if (!strcmp(pool->ss.stringspace + pool->ss.strings[id], sp))
391 break; /* existing string */
392 h = HASHCHAIN_NEXT(h, hh, hashmask);
395 /* length == offset to next string */
397 if (id == ID_NULL) /* end of hash chain -> new string */
399 id = pool->ss.nstrings++;
401 str[id] = pool->ss.sstrings; /* save Offset */
402 if (sp != pool->ss.stringspace + pool->ss.sstrings) /* not at end-of-buffer */
403 memmove(pool->ss.stringspace + pool->ss.sstrings, sp, l); /* append to pool buffer */
404 pool->ss.sstrings += l;
406 idmap[i] = id; /* repo relative -> pool relative */
407 sp += l; /* next string */
410 pool_shrink_strings(pool); /* vacuum */
413 /******* Part 2: Relation IDs ***************************************/
423 ran = (Reldep *)xrealloc(pool->rels, (pool->nrels + numrel) * sizeof(Reldep));
426 pool_debug(pool, SAT_FATAL, "no mem for rel space\n");
429 pool->rels = ran; /* extended rel space */
431 hashmask = mkmask(pool->nrels + numrel);
433 POOL_DEBUG(SAT_DEBUG_STATS, "read %d rels\n", numrel);
434 POOL_DEBUG(SAT_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
437 * prep hash table with already existing RelDeps
440 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
441 for (i = 1; i < pool->nrels; i++)
443 h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
444 hh = HASHCHAIN_START;
446 h = HASHCHAIN_NEXT(h, hh, hashmask);
451 * read RelDeps from repo
454 for (i = 0; i < numrel; i++)
456 name = read_id(fp, i + numid); /* read (repo relative) Ids */
457 evr = read_id(fp, i + numid);
459 name = idmap[name]; /* map to (pool relative) Ids */
461 h = relhash(name, evr, flags) & hashmask;
462 hh = HASHCHAIN_START;
466 if (id == ID_NULL) /* end of hash chain */
468 if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
470 h = HASHCHAIN_NEXT(h, hh, hashmask);
472 if (id == ID_NULL) /* new RelDep */
478 ran[id].flags = flags;
480 idmap[i + numid] = MAKERELDEP(id); /* fill Id map */
483 pool_shrink_rels(pool); /* vacuum */
487 /******* Part 3: Keys ***********************************************/
489 keys = xcalloc(numkeys, sizeof(*keys));
490 /* keys start at 1 */
491 for (i = 1; i < numkeys; i++)
493 keys[i].name = idmap[read_id(fp, numid)];
494 keys[i].type = read_id(fp, 0);
495 keys[i].size = read_id(fp, 0);
498 /******* Part 4: Schemata ********************************************/
501 schemadata = xcalloc(id, sizeof(Id));
502 schemadatap = schemadata;
503 schemadataend = schemadata + id;
504 schemata = xcalloc(numschemata, sizeof(Id));
505 for (i = 0; i < numschemata; i++)
507 schemata[i] = schemadatap - schemadata;
508 schemadatap = read_idarray(fp, numid, 0, schemadatap, schemadataend, 0);
511 /******* Part 5: Info ***********************************************/
512 /* we skip the info for now... */
513 for (i = 0; i < numinfo; i++)
515 Id *schema = schemadata + schemata[read_id(fp, numschemata)];
516 while ((key = *schema++) != 0)
518 type = keys[key].type;
522 read_id(fp, numid + numrel); /* just check Id */
527 case TYPE_ATTR_STRING:
529 while(read_u8(fp) != 0)
533 case TYPE_REL_IDARRAY:
534 while ((read_u8(fp) & 0xc0) != 0)
537 case TYPE_ATTR_CHUNK:
543 case TYPE_ATTR_INTLIST:
544 case TYPE_ATTR_LOCALIDS:
545 while (read_id(fp, 0) != 0)
549 pool_debug(pool, SAT_FATAL, "unknown type %d\n", type);
555 /******* Part 6: packed sizes (optional) ****************************/
557 if ((solvflags & SOLV_FLAG_PACKEDSIZES) != 0)
559 exists = xmalloc (numsolv);
560 for (i = 0; i < numsolv; i++)
561 exists[i] = read_id(fp, 0) != 0;
564 /******* Part 7: item data *******************************************/
566 /* calculate idarray size */
568 for (i = 1; i < numkeys; i++)
571 if ((keys[i].type == TYPE_IDARRAY || keys[i].type == TYPE_REL_IDARRAY)
572 && id >= INTERESTED_START && id <= INTERESTED_END)
573 size_idarray += keys[i].size;
576 /* allocate needed space in repo */
579 repo_reserve_ids(repo, 0, size_idarray);
580 idarraydatap = repo->idarraydata + repo->idarraysize;
581 repo->idarraysize += size_idarray;
582 idarraydataend = repo->idarraydata + repo->idarraysize;
592 s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
594 if ((solvflags & SOLV_FLAG_VERTICAL) != 0)
596 Id *solvschema = xcalloc(numsolv, sizeof(Id));
597 unsigned char *used = xmalloc(numschemata);
598 Solvable *sstart = s;
601 for (i = 0; i < numsolv; i++)
602 solvschema[i] = read_id(fp, numschemata);
603 for (key = 1; key < numkeys; key++)
606 type = keys[key].type;
607 memset(used, 0, numschemata);
608 for (i = 0; i < numschemata; i++)
610 Id *keyp = schemadata + schemata[i];
618 for (i = 0, s = sstart; i < numsolv; i++, s++)
620 if (!used[solvschema[i]])
625 did = idmap[read_id(fp, numid + numrel)];
626 if (id == SOLVABLE_NAME)
628 else if (id == SOLVABLE_ARCH)
630 else if (id == SOLVABLE_EVR)
632 else if (id == SOLVABLE_VENDOR)
637 if (id == RPM_RPMDBID)
640 repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
641 repo->rpmdbid[i] = h;
645 while(read_u8(fp) != 0)
649 case TYPE_REL_IDARRAY:
650 if (id < INTERESTED_START || id > INTERESTED_END)
652 /* not interested in array */
653 while ((read_u8(fp) & 0xc0) != 0)
657 ido = idarraydatap - repo->idarraydata;
658 idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, type == TYPE_REL_IDARRAY);
659 if (id == SOLVABLE_PROVIDES)
661 else if (id == SOLVABLE_OBSOLETES)
663 else if (id == SOLVABLE_CONFLICTS)
665 else if (id == SOLVABLE_REQUIRES)
667 else if (id == SOLVABLE_RECOMMENDS)
669 else if (id == SOLVABLE_SUPPLEMENTS)
670 s->supplements = ido;
671 else if (id == SOLVABLE_SUGGESTS)
673 else if (id == SOLVABLE_ENHANCES)
675 else if (id == SOLVABLE_FRESHENS)
679 case TYPE_ATTR_CHUNK:
680 case TYPE_ATTR_STRING:
681 case TYPE_ATTR_INTLIST:
682 case TYPE_ATTR_LOCALIDS:
684 embedded_store = new_store (pool);
685 add_attr_from_file (embedded_store, i, id, type, idmap, numid, fp);
699 for (i = 0; i < numsolv; i++, s++)
701 if (exists && !exists[i])
703 Id *keyp = schemadata + schemata[read_id(fp, numschemata)];
704 while ((key = *keyp++) != 0)
707 switch (keys[key].type)
710 did = idmap[read_id(fp, numid + numrel)];
711 if (id == SOLVABLE_NAME)
713 else if (id == SOLVABLE_ARCH)
715 else if (id == SOLVABLE_EVR)
717 else if (id == SOLVABLE_VENDOR)
720 POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %s\n", id2str(pool, id), id2str(pool, did));
726 POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %u\n", id2str(pool, id), h);
728 if (id == RPM_RPMDBID)
731 repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
732 repo->rpmdbid[i] = h;
736 while(read_u8(fp) != 0)
740 case TYPE_REL_IDARRAY:
741 if (id < INTERESTED_START || id > INTERESTED_END)
743 /* not interested in array */
744 while ((read_u8(fp) & 0xc0) != 0)
748 ido = idarraydatap - repo->idarraydata;
749 idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, keys[key].type == TYPE_REL_IDARRAY);
750 if (id == SOLVABLE_PROVIDES)
752 else if (id == SOLVABLE_OBSOLETES)
754 else if (id == SOLVABLE_CONFLICTS)
756 else if (id == SOLVABLE_REQUIRES)
758 else if (id == SOLVABLE_RECOMMENDS)
760 else if (id == SOLVABLE_SUPPLEMENTS)
761 s->supplements = ido;
762 else if (id == SOLVABLE_SUGGESTS)
764 else if (id == SOLVABLE_ENHANCES)
766 else if (id == SOLVABLE_FRESHENS)
769 POOL_DEBUG(SAT_DEBUG_STATS, "%s ->\n", id2str(pool, id));
770 for (; repo->idarraydata[ido]; ido++)
771 POOL_DEBUG(SAT_DEBUG_STATS," %s\n", dep2str(pool, repo->idarraydata[ido]));
775 case TYPE_ATTR_CHUNK:
776 case TYPE_ATTR_STRING:
777 case TYPE_ATTR_INTLIST:
778 case TYPE_ATTR_LOCALIDS:
780 embedded_store = new_store (pool);
781 add_attr_from_file (embedded_store, i, id, keys[key].type, idmap, numid, fp);
789 attr_store_pack (embedded_store);
790 /* If we have any attributes we also have pages. */
791 read_or_setup_pages (fp, embedded_store);
792 repo_add_attrstore (repo, embedded_store);