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 "sat_debug.h"
30 #define INTERESTED_START SOLVABLE_NAME
31 #define INTERESTED_END SOLVABLE_FRESHENS
33 /*-----------------------------------------------------------------*/
34 /* .solv read functions */
46 for (i = 0; i < 4; i++)
51 sat_debug (ERROR, "unexpected EOF\n");
71 sat_debug (ERROR, "unexpected EOF\n");
83 read_id(FILE *fp, Id max)
88 for (i = 0; i < 5; i++)
93 sat_debug (ERROR, "unexpected EOF\n");
101 sat_debug (ERROR, "read_id: id too large (%u/%u)\n", x, max);
106 x = (x << 7) ^ c ^ 128;
108 sat_debug (ERROR, "read_id: id too long\n");
118 read_idarray(FILE *fp, Id max, Id *map, Id *store, Id *end)
127 sat_debug (ERROR, "unexpected EOF\n");
132 x = (x << 6) | (c & 63);
135 sat_debug (ERROR, "read_idarray: id too large (%u/%u)\n", x, max);
140 sat_debug (ERROR, "read_idarray: array overflow\n");
148 sat_debug (ERROR, "read_idarray: array overflow\n");
157 x = (x << 7) ^ c ^ 128;
162 /*-----------------------------------------------------------------*/
164 typedef struct solvdata {
171 // ----------------------------------------------
174 * read repo from .solv file
179 repo_add_solv(Repo *repo, FILE *fp)
181 Pool *pool = repo->pool;
183 unsigned int numid, numrel, numsolv, numsrcdata, numsolvdata;
184 int numsolvdatabits, type;
186 Offset *str; /* map Id -> Offset into string space */
187 char *strsp; /* repo string space */
188 char *sp; /* pointer into string space */
189 Id *idmap; /* map of repo Ids to pool Ids */
191 unsigned int hashmask, h;
198 unsigned int size, size_str, size_idarray;
199 Id *idarraydatap, *idarraydataend;
201 unsigned int databits;
204 if (read_u32(fp) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
206 sat_debug (ERROR, "not a SOLV file\n");
209 if (read_u32(fp) != SOLV_VERSION)
211 sat_debug (ERROR, "unsupported SOLV version\n");
215 pool_freeidhashes(pool);
217 numid = read_u32(fp);
218 numrel = read_u32(fp);
219 numsolv= read_u32(fp);
221 sizeid = read_u32(fp); /* size of string+Id space */
224 * read strings and Ids
233 /* alloc string buffer */
234 strsp = (char *)xrealloc(pool->ss.stringspace, pool->ss.sstrings + sizeid + 1);
235 /* alloc string offsets (Id -> Offset into string space) */
236 str = (Offset *)xrealloc(pool->ss.strings, (pool->ss.nstrings + numid) * sizeof(Offset));
238 pool->ss.stringspace = strsp;
239 pool->ss.strings = str; /* array of offsets into strsp, indexed by Id */
241 /* point to _BEHIND_ already allocated string/Id space */
242 strsp += pool->ss.sstrings;
244 /* alloc id map for name and rel Ids. this maps ids in the solv files
245 * to the ids in our pool */
246 idmap = (Id *)xcalloc(numid + numrel, sizeof(Id));
249 * read new repo at end of pool
252 if (fread(strsp, sizeid, 1, fp) != 1)
254 sat_debug (ERROR, "read error while reading strings\n");
257 strsp[sizeid] = 0; /* make string space \0 terminated */
261 * build hashes for all read strings
265 hashmask = mkmask(pool->ss.nstrings + numid);
268 sat_debug (ALWAYS, "read %d strings\n", numid);
269 sat_debug (ALWAYS, "string hash buckets: %d\n", hashmask + 1);
273 * ensure sufficient hash size
276 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
279 * fill hashtable with strings already in pool
282 for (i = 1; i < pool->ss.nstrings; i++) /* leave out our dummy zero id */
284 h = strhash(pool->ss.stringspace + pool->ss.strings[i]) & hashmask;
285 hh = HASHCHAIN_START;
287 h = HASHCHAIN_NEXT(h, hh, hashmask);
292 * run over string space, calculate offsets
294 * build id map (maps solv Id -> pool Id)
297 for (i = 1; i < numid; i++)
299 if (sp >= strsp + sizeid)
301 sat_debug (ERROR, "not enough strings\n");
304 if (!*sp) /* empty string */
312 h = strhash(sp) & hashmask;
313 hh = HASHCHAIN_START;
319 if (!strcmp(pool->ss.stringspace + pool->ss.strings[id], sp))
320 break; /* existing string */
321 h = HASHCHAIN_NEXT(h, hh, hashmask);
324 /* length == offset to next string */
326 if (id == ID_NULL) /* end of hash chain -> new string */
328 id = pool->ss.nstrings++;
330 str[id] = pool->ss.sstrings; /* save Offset */
331 if (sp != pool->ss.stringspace + pool->ss.sstrings) /* not at end-of-buffer */
332 memmove(pool->ss.stringspace + pool->ss.sstrings, sp, l); /* append to pool buffer */
333 pool->ss.sstrings += l;
335 idmap[i] = id; /* repo relative -> pool relative */
336 sp += l; /* next string */
339 pool_shrink_strings(pool); /* vacuum */
350 ran = (Reldep *)xrealloc(pool->rels, (pool->nrels + numrel) * sizeof(Reldep));
353 sat_debug (ERROR, "no mem for rel space\n");
356 pool->rels = ran; /* extended rel space */
358 hashmask = mkmask(pool->nrels + numrel);
360 sat_debug (ALWAYS, "read %d rels\n", numrel);
361 sat_debug (ALWAYS, "rel hash buckets: %d\n", hashmask + 1);
364 * prep hash table with already existing RelDeps
367 hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
368 for (i = 1; i < pool->nrels; i++)
370 h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
371 hh = HASHCHAIN_START;
373 h = HASHCHAIN_NEXT(h, hh, hashmask);
378 * read RelDeps from repo
381 for (i = 0; i < numrel; i++)
383 name = read_id(fp, i + numid); /* read (repo relative) Ids */
384 evr = read_id(fp, i + numid);
386 name = idmap[name]; /* map to (pool relative) Ids */
388 h = relhash(name, evr, flags) & hashmask;
389 hh = HASHCHAIN_START;
393 if (id == ID_NULL) /* end of hash chain */
395 if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
397 h = HASHCHAIN_NEXT(h, hh, hashmask);
399 if (id == ID_NULL) /* new RelDep */
405 ran[id].flags = flags;
407 idmap[i + numid] = MAKERELDEP(id); /* fill Id map */
410 pool_shrink_rels(pool); /* vacuum */
414 * read (but dont store yet) repo data
418 sat_debug (ALWAYS, "read repo data\n");
420 numsrcdata = read_u32(fp);
421 for (i = 0; i < numsrcdata; i++)
424 id = idmap[read_id(fp, numid)];
428 read_id(fp, numid + numrel); /* just check Id */
434 while(read_u8(fp) != 0)
438 sat_debug (ERROR, "unknown type\n");
449 sat_debug (ALWAYS, "read solvable data info\n");
451 numsolvdata = read_u32(fp);
453 solvdata = (SolvData *)xmalloc(numsolvdata * sizeof(SolvData));
457 for (i = 0; i < numsolvdata; i++)
460 solvdata[i].type = type;
461 if ((type & TYPE_BITMAP) != 0)
466 id = idmap[read_id(fp, numid)];
468 sat_debug (ALWAYS, "#%d: %s\n", i, id2str(pool, id));
472 solvdata[i].size = size;
473 if (id >= INTERESTED_START && id <= INTERESTED_END)
475 if (type == TYPE_STR)
477 if (type == TYPE_IDARRAY)
478 size_idarray += size;
482 if (numsolvdatabits >= 32)
484 sat_debug (ERROR, "too many data map bits\n");
488 /* make room for our idarrays */
491 repo_reserve_ids(repo, 0, size_idarray);
492 idarraydatap = repo->idarraydata + repo->idarraysize;
493 repo->idarraysize += size_idarray;
494 idarraydataend = repo->idarraydata + repo->idarraysize;
508 sat_debug (ALWAYS, "read solvables\n");
510 s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
511 for (i = 0; i < numsolv; i++, s++)
516 for (j = 0; j < (numsolvdatabits + 7) >> 3; j++)
517 databits = (databits << 8) | read_u8(fp);
519 for (j = 0; j < numsolvdata; j++)
521 type = solvdata[j].type;
522 if ((type & TYPE_BITMAP) != 0)
536 did = idmap[read_id(fp, numid + numrel)];
537 if (id == SOLVABLE_NAME)
539 else if (id == SOLVABLE_ARCH)
541 else if (id == SOLVABLE_EVR)
543 else if (id == SOLVABLE_VENDOR)
546 sat_debug (ALWAYS, "%s -> %s\n", id2str(pool, id), id2str(pool, did));
552 sat_debug (ALWAYS, "%s -> %u\n", id2str(pool, id), h);
554 if (id == RPM_RPMDBID)
557 repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
558 repo->rpmdbid[i] = h;
562 while(read_u8(fp) != 0)
566 if (id < INTERESTED_START || id > INTERESTED_END)
568 /* not interested in array */
569 while ((read_u8(fp) & 0xc0) != 0)
573 ido = idarraydatap - repo->idarraydata;
574 idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend);
575 if (id == SOLVABLE_PROVIDES)
577 else if (id == SOLVABLE_OBSOLETES)
579 else if (id == SOLVABLE_CONFLICTS)
581 else if (id == SOLVABLE_REQUIRES)
583 else if (id == SOLVABLE_RECOMMENDS)
585 else if (id == SOLVABLE_SUPPLEMENTS)
586 s->supplements = ido;
587 else if (id == SOLVABLE_SUGGESTS)
589 else if (id == SOLVABLE_ENHANCES)
591 else if (id == SOLVABLE_FRESHENS)
594 sat_debug (ALWAYS, "%s ->\n", id2str(pool, id));
595 for (; repo->idarraydata[ido]; ido++)
596 sat_debug (ALWAYS," %s\n", dep2str(pool, repo->idarraydata[ido]));