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 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)
128 pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
133 x = (x << 6) | (c & 63);
136 pool_debug(mypool, SAT_FATAL, "read_idarray: id too large (%u/%u)\n", x, max);
141 pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
149 pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
158 x = (x << 7) ^ c ^ 128;
163 /*-----------------------------------------------------------------*/
165 typedef struct solvdata {
172 // ----------------------------------------------
175 * read repo from .solv file
180 repo_add_solv(Repo *repo, FILE *fp)
182 Pool *pool = repo->pool;
184 unsigned int numid, numrel, numsolv, numsrcdata, numsolvdata;
185 int numsolvdatabits, type;
187 Offset *str; /* map Id -> Offset into string space */
188 char *strsp; /* repo string space */
189 char *sp; /* pointer into string space */
190 Id *idmap; /* map of repo Ids to pool Ids */
192 unsigned int hashmask, h;
199 unsigned int size, size_str, size_idarray;
200 Id *idarraydatap, *idarraydataend;
202 unsigned int databits;
207 if (read_u32(fp) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
209 pool_debug(pool, SAT_FATAL, "not a SOLV file\n");
212 if (read_u32(fp) != SOLV_VERSION)
214 pool_debug(pool, SAT_FATAL, "unsupported SOLV version\n");
218 pool_freeidhashes(pool);
220 numid = read_u32(fp);
221 numrel = read_u32(fp);
222 numsolv= read_u32(fp);
224 sizeid = read_u32(fp); /* size of string+Id space */
227 * read strings and Ids
236 /* alloc string buffer */
237 strsp = (char *)xrealloc(pool->ss.stringspace, pool->ss.sstrings + sizeid + 1);
238 /* alloc string offsets (Id -> Offset into string space) */
239 str = (Offset *)xrealloc(pool->ss.strings, (pool->ss.nstrings + numid) * sizeof(Offset));
241 pool->ss.stringspace = strsp;
242 pool->ss.strings = str; /* array of offsets into strsp, indexed by Id */
244 /* point to _BEHIND_ already allocated string/Id space */
245 strsp += pool->ss.sstrings;
247 /* alloc id map for name and rel Ids. this maps ids in the solv files
248 * to the ids in our pool */
249 idmap = (Id *)xcalloc(numid + numrel, sizeof(Id));
252 * read new repo at end of pool
255 if (fread(strsp, sizeid, 1, fp) != 1)
257 pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
260 strsp[sizeid] = 0; /* make string space \0 terminated */
264 * build hashes for all read strings
268 hashmask = mkmask(pool->ss.nstrings + numid);
271 POOL_DEBUG(SAT_DEBUG_STATS, "read %d strings\n", numid);
272 POOL_DEBUG(SAT_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
276 * ensure sufficient hash size
279 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
282 * fill hashtable with strings already in pool
285 for (i = 1; i < pool->ss.nstrings; i++) /* leave out our dummy zero id */
287 h = strhash(pool->ss.stringspace + pool->ss.strings[i]) & hashmask;
288 hh = HASHCHAIN_START;
290 h = HASHCHAIN_NEXT(h, hh, hashmask);
295 * run over string space, calculate offsets
297 * build id map (maps solv Id -> pool Id)
300 for (i = 1; i < numid; i++)
302 if (sp >= strsp + sizeid)
304 pool_debug(pool, SAT_FATAL, "not enough strings\n");
307 if (!*sp) /* empty string */
315 h = strhash(sp) & hashmask;
316 hh = HASHCHAIN_START;
322 if (!strcmp(pool->ss.stringspace + pool->ss.strings[id], sp))
323 break; /* existing string */
324 h = HASHCHAIN_NEXT(h, hh, hashmask);
327 /* length == offset to next string */
329 if (id == ID_NULL) /* end of hash chain -> new string */
331 id = pool->ss.nstrings++;
333 str[id] = pool->ss.sstrings; /* save Offset */
334 if (sp != pool->ss.stringspace + pool->ss.sstrings) /* not at end-of-buffer */
335 memmove(pool->ss.stringspace + pool->ss.sstrings, sp, l); /* append to pool buffer */
336 pool->ss.sstrings += l;
338 idmap[i] = id; /* repo relative -> pool relative */
339 sp += l; /* next string */
342 pool_shrink_strings(pool); /* vacuum */
353 ran = (Reldep *)xrealloc(pool->rels, (pool->nrels + numrel) * sizeof(Reldep));
356 pool_debug(pool, SAT_FATAL, "no mem for rel space\n");
359 pool->rels = ran; /* extended rel space */
361 hashmask = mkmask(pool->nrels + numrel);
363 POOL_DEBUG(SAT_DEBUG_STATS, "read %d rels\n", numrel);
364 POOL_DEBUG(SAT_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
367 * prep hash table with already existing RelDeps
370 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
371 for (i = 1; i < pool->nrels; i++)
373 h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
374 hh = HASHCHAIN_START;
376 h = HASHCHAIN_NEXT(h, hh, hashmask);
381 * read RelDeps from repo
384 for (i = 0; i < numrel; i++)
386 name = read_id(fp, i + numid); /* read (repo relative) Ids */
387 evr = read_id(fp, i + numid);
389 name = idmap[name]; /* map to (pool relative) Ids */
391 h = relhash(name, evr, flags) & hashmask;
392 hh = HASHCHAIN_START;
396 if (id == ID_NULL) /* end of hash chain */
398 if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
400 h = HASHCHAIN_NEXT(h, hh, hashmask);
402 if (id == ID_NULL) /* new RelDep */
408 ran[id].flags = flags;
410 idmap[i + numid] = MAKERELDEP(id); /* fill Id map */
413 pool_shrink_rels(pool); /* vacuum */
417 * read (but dont store yet) repo data
421 POOL_DEBUG(SAT_DEBUG_STATS, "read repo data\n");
423 numsrcdata = read_u32(fp);
424 for (i = 0; i < numsrcdata; i++)
427 id = idmap[read_id(fp, numid)];
431 read_id(fp, numid + numrel); /* just check Id */
437 while(read_u8(fp) != 0)
441 pool_debug(pool, SAT_FATAL, "unknown type %d\n", type);
452 POOL_DEBUG(SAT_DEBUG_STATS, "read solvable data info\n");
454 numsolvdata = read_u32(fp);
456 solvdata = (SolvData *)xmalloc(numsolvdata * sizeof(SolvData));
460 for (i = 0; i < numsolvdata; i++)
463 solvdata[i].type = type;
464 if ((type & TYPE_BITMAP) != 0)
469 id = idmap[read_id(fp, numid)];
471 POOL_DEBUG(SAT_DEBUG_STATS, "#%d: %s\n", i, id2str(pool, id));
475 solvdata[i].size = size;
476 if (id >= INTERESTED_START && id <= INTERESTED_END)
478 if (type == TYPE_STR)
480 if (type == TYPE_IDARRAY)
481 size_idarray += size;
485 if (numsolvdatabits >= 32)
487 pool_debug(pool, SAT_FATAL, "too many data map bits\n");
491 /* make room for our idarrays */
494 repo_reserve_ids(repo, 0, size_idarray);
495 idarraydatap = repo->idarraydata + repo->idarraysize;
496 repo->idarraysize += size_idarray;
497 idarraydataend = repo->idarraydata + repo->idarraysize;
511 POOL_DEBUG(SAT_DEBUG_STATS, "read solvables\n");
513 s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
514 for (i = 0; i < numsolv; i++, s++)
519 for (j = 0; j < (numsolvdatabits + 7) >> 3; j++)
520 databits = (databits << 8) | read_u8(fp);
522 for (j = 0; j < numsolvdata; j++)
524 type = solvdata[j].type;
525 if ((type & TYPE_BITMAP) != 0)
539 did = idmap[read_id(fp, numid + numrel)];
540 if (id == SOLVABLE_NAME)
542 else if (id == SOLVABLE_ARCH)
544 else if (id == SOLVABLE_EVR)
546 else if (id == SOLVABLE_VENDOR)
549 POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %s\n", id2str(pool, id), id2str(pool, did));
555 POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %u\n", id2str(pool, id), h);
557 if (id == RPM_RPMDBID)
560 repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
561 repo->rpmdbid[i] = h;
565 while(read_u8(fp) != 0)
569 if (id < INTERESTED_START || id > INTERESTED_END)
571 /* not interested in array */
572 while ((read_u8(fp) & 0xc0) != 0)
576 ido = idarraydatap - repo->idarraydata;
577 idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend);
578 if (id == SOLVABLE_PROVIDES)
580 else if (id == SOLVABLE_OBSOLETES)
582 else if (id == SOLVABLE_CONFLICTS)
584 else if (id == SOLVABLE_REQUIRES)
586 else if (id == SOLVABLE_RECOMMENDS)
588 else if (id == SOLVABLE_SUPPLEMENTS)
589 s->supplements = ido;
590 else if (id == SOLVABLE_SUGGESTS)
592 else if (id == SOLVABLE_ENHANCES)
594 else if (id == SOLVABLE_FRESHENS)
597 POOL_DEBUG(SAT_DEBUG_STATS, "%s ->\n", id2str(pool, id));
598 for (; repo->idarraydata[ido]; ido++)
599 POOL_DEBUG(SAT_DEBUG_STATS," %s\n", dep2str(pool, repo->idarraydata[ido]));