2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Add a repo in solv format
22 #include "repo_solv.h"
28 #include "poolid_private.h" /* WHATPROVIDES_BLOCK */
30 #define INTERESTED_START SOLVABLE_NAME
31 #define INTERESTED_END SOLVABLE_ENHANCES
33 #define SOLV_ERROR_NOT_SOLV 1
34 #define SOLV_ERROR_UNSUPPORTED 2
35 #define SOLV_ERROR_EOF 3
36 #define SOLV_ERROR_ID_RANGE 4
37 #define SOLV_ERROR_OVERFLOW 5
38 #define SOLV_ERROR_CORRUPT 6
42 /*******************************************************************************
43 * functions to extract data from a file handle
51 read_u32(Repodata *data)
58 for (i = 0; i < 4; i++)
63 data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
77 read_u8(Repodata *data)
86 data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
98 read_id(Repodata *data, Id max)
105 for (i = 0; i < 5; i++)
110 data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
116 if (max && x >= (unsigned int)max)
118 data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_id: id too large (%u/%u)", x, max);
123 x = (x << 7) ^ c ^ 128;
125 data->error = pool_error(data->repo->pool, SOLV_ERROR_CORRUPT, "read_id: id too long");
131 read_idarray(Repodata *data, Id max, Id *map, Id *store, Id *end)
143 data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
148 x = (x << 7) ^ c ^ 128;
151 x = (x << 6) | (c & 63);
152 if (max && x >= (unsigned int)max)
154 data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_idarray: id too large (%u/%u)", x, max);
161 data->error = pool_error(data->repo->pool, SOLV_ERROR_OVERFLOW, "read_idarray: array overflow");
167 if (x == 0) /* already have trailing zero? */
171 data->error = pool_error(data->repo->pool, SOLV_ERROR_OVERFLOW, "read_idarray: array overflow");
182 read_idarray_block(Repodata *data, Id *block, int size)
184 unsigned char buf[65536 + 5 + 1], *bp = buf, *oldbp;
185 unsigned char cbuf[65536 + 4]; /* can overshoot 4 bytes */
192 if (left < 5 && !eof)
195 memmove(buf, bp, left);
197 flags = read_u8(data);
198 clen = read_u8(data);
199 clen = (clen << 8) | read_u8(data);
205 if (fread(flags & 0x40 ? cbuf : bp, clen, 1, data->fp) != 1)
207 data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
210 if (flags & 0x40) /* compressed block */
211 clen = repopagestore_decompress_page(cbuf, clen, bp, 65536);
214 bp[left] = 0; /* make data_read_id return */
219 data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "idarray data overrun in block decompression");
223 bp = data_read_id(bp, &x);
227 data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "compression buffer underrun");
231 *block++ = (x & 63) + (((unsigned int)x & ~127) >> 1) + 1;
240 data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "idarray size overrun in block decompression");
243 /*******************************************************************************
244 * functions to extract data from memory
251 static inline unsigned char *
252 data_read_id_max(unsigned char *dp, Id *ret, Id *map, int max, Repodata *data)
255 dp = data_read_id(dp, &x);
256 if (x < 0 || (max && x >= max))
258 data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_id_max: id too large (%u/%u)", x, max);
261 *ret = map ? map[x] : x;
265 static unsigned char *
266 data_read_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data)
277 x = (x << 7) ^ c ^ 128;
280 x = (x << 6) | (c & 63);
281 if (max && x >= (unsigned int)max)
283 data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_idarray: id too large (%u/%u)", x, max);
284 data->error = SOLV_ERROR_ID_RANGE;
287 *store++ = map ? map[x] : x;
297 static unsigned char *
298 data_read_rel_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data, Id keyid)
306 if (keyid == SOLVABLE_REQUIRES)
307 marker = SOLVABLE_PREREQMARKER;
308 if (keyid == SOLVABLE_PROVIDES)
309 marker = SOLVABLE_FILEMARKER;
315 x = (x << 7) ^ c ^ 128;
318 x = (x << 6) | (c & 63);
330 if (max && x >= (unsigned int)max)
332 data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_rel_idarray: id too large (%u/%u)", x, max);
335 *store++ = map ? map[x] : x;
348 /*******************************************************************************
349 * functions to add data to our incore memory space
352 #define INCORE_ADD_CHUNK 8192
353 #define DATA_READ_CHUNK 8192
356 incore_add_id(Repodata *data, Id sx)
358 unsigned int x = (unsigned int)sx;
360 /* make sure we have at least 5 bytes free */
361 if (data->incoredatafree < 5)
363 data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
364 data->incoredatafree = INCORE_ADD_CHUNK;
366 dp = data->incoredata + data->incoredatalen;
370 *dp++ = (x >> 28) | 128;
372 *dp++ = (x >> 21) | 128;
373 *dp++ = (x >> 14) | 128;
376 *dp++ = (x >> 7) | 128;
378 data->incoredatafree -= dp - (data->incoredata + data->incoredatalen);
379 data->incoredatalen = dp - data->incoredata;
383 incore_add_sizek(Repodata *data, unsigned int sx)
386 incore_add_id(data, (Id)(sx << 10));
391 incore_add_id(data, (Id)(sx >> 25));
392 data->incoredata[data->incoredatalen - 1] |= 128;
394 incore_add_id(data, (Id)((sx << 10) | 0x80000000));
395 data->incoredata[data->incoredatalen - 5] = (sx >> 18) | 128;
400 incore_add_ideof(Repodata *data, Id sx, int eof)
402 unsigned int x = (unsigned int)sx;
404 /* make sure we have at least 5 bytes free */
405 if (data->incoredatafree < 5)
407 data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
408 data->incoredatafree = INCORE_ADD_CHUNK;
410 dp = data->incoredata + data->incoredatalen;
414 *dp++ = (x >> 27) | 128;
416 *dp++ = (x >> 20) | 128;
417 *dp++ = (x >> 13) | 128;
420 *dp++ = (x >> 6) | 128;
421 *dp++ = eof ? (x & 63) : (x & 63) | 64;
422 data->incoredatafree -= dp - (data->incoredata + data->incoredatalen);
423 data->incoredatalen = dp - data->incoredata;
427 incore_add_blob(Repodata *data, unsigned char *buf, int len)
429 if (data->incoredatafree < (unsigned int)len)
431 data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK + len);
432 data->incoredatafree = INCORE_ADD_CHUNK + len;
434 memcpy(data->incoredata + data->incoredatalen, buf, len);
435 data->incoredatafree -= len;
436 data->incoredatalen += len;
440 incore_map_idarray(Repodata *data, unsigned char *dp, Id *map, Id max)
442 /* We have to map the IDs, which might also change
443 the necessary number of bytes, so we can't just copy
444 over the blob and adjust it. */
449 dp = data_read_ideof(dp, &id, &eof);
450 if (id < 0 || (max && id >= max))
452 data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "incore_map_idarray: id too large (%u/%u)", id, max);
457 incore_add_ideof(data, id, eof);
464 convert_idarray_block(Repodata *data, Id *block, Id *map, Id max)
474 id--; /* idarray_block unpacking added 1 */
478 id = old - (id >> 1) - 1;
480 id = old + (id >> 1);
483 if (id < 0 || (max && id >= max))
485 data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "convert_idarray_block: id too large (%u/%u)", id, max);
496 incore_add_u32(Repodata *data, unsigned int x)
499 /* make sure we have at least 4 bytes free */
500 if (data->incoredatafree < 4)
502 data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
503 data->incoredatafree = INCORE_ADD_CHUNK;
505 dp = data->incoredata + data->incoredatalen;
510 data->incoredatafree -= 4;
511 data->incoredatalen += 4;
515 incore_add_u8(Repodata *data, unsigned int x)
518 /* make sure we have at least 1 byte free */
519 if (data->incoredatafree < 1)
521 data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + 1024);
522 data->incoredatafree = 1024;
524 dp = data->incoredata + data->incoredatalen;
526 data->incoredatafree--;
527 data->incoredatalen++;
532 /*******************************************************************************
537 * read repo from .solv file and add it to pool
541 repo_add_solv(Repo *repo, FILE *fp, int flags)
543 Pool *pool = repo->pool;
545 int numid, numrel, numdir, numsolv;
546 int numkeys, numschemata;
549 Offset *str; /* map Id -> Offset into string space */
550 char *strsp; /* repo string space */
551 char *sp; /* pointer into string space */
552 Id *idmap; /* map of repo Ids to pool Ids */
554 Hashval hashmask, h, hh;
559 unsigned int size_idarray;
560 Id *idarraydatap, *idarraydataend;
563 unsigned int solvflags;
564 unsigned int solvversion;
566 Id *schemadata, *schemadatap, *schemadataend;
567 Id *schemata, key, *keyp;
570 int maxsize, allsize;
571 unsigned char *buf, *bufend, *dp, *dps;
574 int needchunk; /* need a new chunk of data */
576 int oldnstrings = pool->ss.nstrings;
577 int oldnrels = pool->nrels;
579 struct s_Stringpool *spool;
581 Repodata *parent = 0;
584 int extendstart = 0, extendend = 0; /* set in case we're extending */
585 int idarray_block_offset = 0;
586 int idarray_block_end = 0;
588 now = solv_timems(0);
590 if ((flags & REPO_USE_LOADING) != 0)
592 /* this is a stub replace operation */
593 flags |= REPO_EXTEND_SOLVABLES;
594 /* use REPO_REUSE_REPODATA hack so that the old repodata is kept */
595 parent = repo_add_repodata(repo, flags | REPO_REUSE_REPODATA);
596 extendstart = parent->start;
597 extendend = parent->end;
599 else if (flags & REPO_EXTEND_SOLVABLES)
601 /* extend all solvables of this repo */
602 extendstart = repo->start;
603 extendend = repo->end;
606 memset(&data, 0, sizeof(data));
609 repopagestore_init(&data.store);
611 if (read_u32(&data) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
612 return pool_error(pool, SOLV_ERROR_NOT_SOLV, "not a SOLV file");
613 solvversion = read_u32(&data);
620 return pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported SOLV version");
623 numid = (int)read_u32(&data);
624 numrel = (int)read_u32(&data);
625 numdir = (int)read_u32(&data);
626 numsolv = (int)read_u32(&data);
627 numkeys = (int)read_u32(&data);
628 numschemata = (int)read_u32(&data);
629 solvflags = read_u32(&data);
631 if (numid < 0 || numid >= 0x20000000)
632 return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of ids");
633 if (numrel < 0 || numrel >= 0x20000000)
634 return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of rels");
635 if (numdir && (numdir < 2 || numdir >= 0x20000000))
636 return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of dirs");
637 if (numsolv < 0 || numsolv >= 0x20000000)
638 return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of solvables");
639 if (numkeys < 0 || numkeys >= 0x20000000)
640 return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of keys");
641 if (numschemata < 0 || numschemata >= 0x20000000)
642 return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of schematas");
644 if (numrel && (flags & REPO_LOCALPOOL) != 0)
645 return pool_error(pool, SOLV_ERROR_CORRUPT, "relations are forbidden in a local pool");
646 if ((flags & REPO_EXTEND_SOLVABLES) && numsolv)
648 /* make sure that we exactly replace the stub repodata */
649 if (extendend - extendstart != numsolv)
650 return pool_error(pool, SOLV_ERROR_CORRUPT, "sub-repository solvable number does not match main repository (%d - %d)", extendend - extendstart, numsolv);
651 for (i = 0; i < numsolv; i++)
652 if (pool->solvables[extendstart + i].repo != repo)
653 return pool_error(pool, SOLV_ERROR_CORRUPT, "main repository contains holes, cannot extend");
656 /******* Part 0: skip optional userdata ******************************/
658 if (solvflags & SOLV_FLAG_USERDATA)
660 unsigned int userdatalen = read_u32(&data);
661 if (userdatalen >= 65536)
662 return pool_error(pool, SOLV_ERROR_CORRUPT, "illegal userdata length");
663 while (userdatalen--)
664 if (getc(data.fp) == EOF)
665 return pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
668 /******* Part 1: string IDs *****************************************/
670 sizeid = read_u32(&data); /* size of string space */
673 * read strings and Ids
682 if (!(flags & REPO_LOCALPOOL))
685 /* alloc max needed string buffer and string pointers, will shrink again later */
687 spool->stringspace = solv_realloc(spool->stringspace, spool->sstrings + sizeid + 1);
688 spool->strings = solv_realloc2(spool->strings, spool->nstrings + numid, sizeof(Offset));
690 spool->sstrings += sizeid + 1;
691 spool->nstrings += numid;
692 stringpool_shrink(spool); /* we misuse stringpool_shrink so that the correct BLOCK factor is used */
693 spool->sstrings -= sizeid + 1;
694 spool->nstrings -= numid;
701 spool->stringspace = solv_malloc(7 + sizeid + 1);
702 spool->strings = solv_malloc2(numid < 2 ? 2 : numid, sizeof(Offset));
703 strcpy(spool->stringspace, "<NULL>");
706 spool->strings[0] = 0; /* <NULL> */
711 * read string data and append to old string space
714 strsp = spool->stringspace + spool->sstrings; /* append new entries */
715 if ((solvflags & SOLV_FLAG_PREFIX_POOL) == 0)
717 if (sizeid && fread(strsp, sizeid, 1, fp) != 1)
719 repodata_freedata(&data);
720 return pool_error(pool, SOLV_ERROR_EOF, "read error while reading strings");
725 unsigned int pfsize = read_u32(&data);
726 char *prefix = solv_malloc(pfsize);
728 char *old_str = strsp;
732 if (pfsize && fread(prefix, pfsize, 1, fp) != 1)
735 repodata_freedata(&data);
736 return pool_error(pool, SOLV_ERROR_EOF, "read error while reading strings");
738 for (i = 1; i < numid; i++)
740 int same = (unsigned char)*pp++;
741 size_t len = strlen(pp) + 1;
742 freesp -= same + len;
746 repodata_freedata(&data);
747 return pool_error(pool, SOLV_ERROR_OVERFLOW, "overflow while expanding strings");
750 memcpy(dest, old_str, same);
751 memcpy(dest + same, pp, len);
759 repodata_freedata(&data);
760 return pool_error(pool, SOLV_ERROR_CORRUPT, "expanding strings size mismatch");
763 strsp[sizeid] = 0; /* make string space \0 terminated */
767 str = spool->strings; /* array of offsets into strsp, indexed by Id */
768 if ((flags & REPO_LOCALPOOL) != 0)
770 /* no shared pool, thus no idmap and no unification needed */
772 spool->nstrings = numid < 2 ? 2 : numid; /* make sure we have at least id 0 and 1 */
775 /* we need id 1 to be '' for directories */
776 repodata_freedata(&data);
777 return pool_error(pool, SOLV_ERROR_CORRUPT, "store strings don't start with an empty string");
779 for (i = 1; i < spool->nstrings; i++)
781 if (sp >= strsp + sizeid && numid >= 2)
783 repodata_freedata(&data);
784 return pool_error(pool, SOLV_ERROR_OVERFLOW, "not enough strings");
786 str[i] = sp - spool->stringspace;
787 sp += strlen(sp) + 1;
789 spool->sstrings = sp - spool->stringspace;
793 Offset oldsstrings = spool->sstrings;
795 /* alloc id map for name and rel Ids. this maps ids in the solv files
796 * to the ids in our pool */
797 idmap = solv_calloc(numid + numrel, sizeof(Id));
798 stringpool_resize_hash(spool, numid);
799 hashtbl = spool->stringhashtbl;
800 hashmask = spool->stringhashmask;
802 POOL_DEBUG(SOLV_DEBUG_STATS, "read %d strings\n", numid);
803 POOL_DEBUG(SOLV_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
806 * run over strings and merge with pool.
807 * we could use stringpool_str2id, but this is faster.
808 * also populate id map (maps solv Id -> pool Id)
810 for (i = 1; i < numid; i++)
812 if (sp >= strsp + sizeid)
815 spool->nstrings = oldnstrings;
816 spool->sstrings = oldsstrings;
817 stringpool_freehash(spool);
818 repodata_freedata(&data);
819 return pool_error(pool, SOLV_ERROR_OVERFLOW, "not enough strings %d %d", i, numid);
821 if (!*sp) /* empty string */
829 h = strhash(sp) & hashmask;
830 hh = HASHCHAIN_START;
836 if (!strcmp(spool->stringspace + spool->strings[id], sp))
837 break; /* already in pool */
838 h = HASHCHAIN_NEXT(h, hh, hashmask);
841 /* length == offset to next string */
843 if (!id) /* end of hash chain -> new string */
845 id = spool->nstrings++;
847 str[id] = spool->sstrings; /* save offset */
848 if (sp != spool->stringspace + spool->sstrings)
849 memmove(spool->stringspace + spool->sstrings, sp, l);
850 spool->sstrings += l;
852 idmap[i] = id; /* repo relative -> pool relative */
853 sp += l; /* next string */
855 stringpool_shrink(spool); /* vacuum */
859 /******* Part 2: Relation IDs ***************************************/
869 pool->rels = solv_realloc2(pool->rels, pool->nrels + numrel, sizeof(Reldep));
872 pool_resize_rels_hash(pool, numrel);
873 hashtbl = pool->relhashtbl;
874 hashmask = pool->relhashmask;
876 POOL_DEBUG(SOLV_DEBUG_STATS, "read %d rels\n", numrel);
877 POOL_DEBUG(SOLV_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
881 * read RelDeps from repo
883 for (i = 0; i < numrel; i++)
885 name = read_id(&data, i + numid); /* read (repo relative) Ids */
886 evr = read_id(&data, i + numid);
887 relflags = read_u8(&data);
888 name = idmap[name]; /* map to (pool relative) Ids */
890 h = relhash(name, evr, relflags) & hashmask;
891 hh = HASHCHAIN_START;
895 if (!id) /* end of hash chain reached */
897 if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == relflags)
899 h = HASHCHAIN_NEXT(h, hh, hashmask);
901 if (!id) /* new RelDep */
907 ran[id].flags = relflags;
909 idmap[i + numid] = MAKERELDEP(id); /* fill Id map */
911 pool_shrink_rels(pool); /* vacuum */
914 /* if we added ids/rels, make room in our whatprovide arrays */
915 if (!(flags & REPO_LOCALPOOL))
917 if (pool->whatprovides && oldnstrings != pool->ss.nstrings)
919 int newlen = (pool->ss.nstrings + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK;
920 pool->whatprovides = solv_realloc2(pool->whatprovides, newlen, sizeof(Offset));
921 memset(pool->whatprovides + oldnstrings, 0, (newlen - oldnstrings) * sizeof(Offset));
923 if (pool->whatprovides_rel && oldnrels != pool->nrels)
925 int newlen = (pool->nrels + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK;
926 pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, newlen, sizeof(Offset));
927 memset(pool->whatprovides_rel + oldnrels, 0, (newlen - oldnrels) * sizeof(Offset));
931 /******* Part 3: Dirs ***********************************************/
934 data.dirpool.dirs = solv_malloc2(numdir, sizeof(Id));
935 data.dirpool.ndirs = numdir;
936 data.dirpool.dirs[0] = 0; /* dir 0: virtual root */
937 data.dirpool.dirs[1] = 1; /* dir 1: / */
938 for (i = 2; i < numdir; i++)
940 id = read_id(&data, i + numid);
943 data.dirpool.dirs[i++] = -(id - numid);
946 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "last dir entry is not a component");
949 id = read_id(&data, numid);
953 data.dirpool.dirs[i] = id;
955 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "bad dir component");
959 /******* Part 4: Keys ***********************************************/
961 keys = solv_calloc(numkeys, sizeof(*keys));
962 /* keys start at 1 */
963 for (i = 1; i < numkeys; i++)
968 id = read_id(&data, numid);
971 else if ((flags & REPO_LOCALPOOL) != 0)
972 id = pool_str2id(pool, stringpool_id2str(spool, id), 1);
973 type = read_id(&data, numid);
976 else if ((flags & REPO_LOCALPOOL) != 0)
977 type = pool_str2id(pool, stringpool_id2str(spool, type), 1);
978 if (type < REPOKEY_TYPE_VOID || type > REPOKEY_TYPE_DELETED)
980 data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported data type '%s'", pool_id2str(pool, type));
981 type = REPOKEY_TYPE_VOID;
986 key->size = read_id(&data, type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : 0);
987 key->storage = read_id(&data, 0);
988 /* old versions used SOLVABLE for main solvable data */
989 if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET && key->storage != KEY_STORAGE_SOLVABLE && key->storage != KEY_STORAGE_IDARRAYBLOCK)
990 data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported storage type %d", key->storage);
991 /* change KEY_STORAGE_SOLVABLE to KEY_STORAGE_INCORE */
992 if (key->storage == KEY_STORAGE_SOLVABLE)
993 key->storage = KEY_STORAGE_INCORE;
994 if (key->storage == KEY_STORAGE_IDARRAYBLOCK && type != REPOKEY_TYPE_IDARRAY)
995 data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "typr %d does not support idarrayblock storage\n", type);
996 if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
998 /* we will put those directly into the storable */
999 if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_IDARRAYBLOCK)
1000 data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "main solvable data must use incore storage, not %d", key->storage);
1002 if ((type == REPOKEY_TYPE_FIXARRAY || type == REPOKEY_TYPE_FLEXARRAY) && key->storage != KEY_STORAGE_INCORE)
1003 data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "flex/fixarrays must use incore storage\n");
1004 /* cannot handle rel idarrays in incore/vertical */
1005 if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_INCORE)
1006 data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "type REL_IDARRAY is only supported for STORAGE_INCORE");
1007 /* cannot handle mapped ids in vertical */
1008 if (!(flags & REPO_LOCALPOOL) && key->storage == KEY_STORAGE_VERTICAL_OFFSET && (type == REPOKEY_TYPE_ID || type == REPOKEY_TYPE_IDARRAY))
1009 data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "mapped ids are not supported for STORAGE_VERTICAL_OFFSET");
1011 if (type == REPOKEY_TYPE_CONSTANTID && idmap)
1012 key->size = idmap[key->size];
1014 fprintf(stderr, "key %d %s %s %d %d\n", i, pool_id2str(pool, id), pool_id2str(pool, type), key->size, key->storage);
1018 have_incoredata = 0;
1019 for (i = 1; i < numkeys; i++)
1022 if (id == REPOSITORY_SOLVABLES && keys[i].type == REPOKEY_TYPE_FLEXARRAY)
1024 if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
1026 have_incoredata = 1;
1030 data.nkeys = numkeys;
1031 for (i = 1; i < numkeys; i++)
1034 data.keybits[(id >> 3) & (sizeof(data.keybits) - 1)] |= 1 << (id & 7);
1037 /******* Part 5: Schemata ********************************************/
1039 id = read_id(&data, 0);
1040 schemadata = solv_calloc(id + 1, sizeof(Id));
1041 schemadatap = schemadata + 1;
1042 schemadataend = schemadatap + id;
1043 schemata = solv_calloc(numschemata, sizeof(Id));
1044 for (i = 1; i < numschemata; i++)
1046 schemata[i] = schemadatap - schemadata;
1047 schemadatap = read_idarray(&data, numid, 0, schemadatap, schemadataend);
1049 Id *sp = schemadata + schemata[i];
1050 fprintf(stderr, "schema %d:", i);
1052 fprintf(stderr, " %d", *sp);
1053 fprintf(stderr, "\n");
1056 data.schemata = schemata;
1057 data.nschemata = numschemata;
1058 data.schemadata = schemadata;
1059 data.schemadatalen = schemadataend - data.schemadata;
1061 /******* Part 6: Idarray block ***********************************/
1062 if ((solvflags & SOLV_FLAG_IDARRAYBLOCK) != 0)
1064 unsigned int idarray_block_size = read_id(&data, 0x30000000);
1065 repo_reserve_ids(repo, 0, idarray_block_size + 1);
1066 idarray_block_offset = repo->idarraysize;
1067 repo->idarraysize += idarray_block_size;
1068 idarray_block_end = repo->idarraysize;
1069 repo->idarraydata[repo->idarraysize++] = 0;
1070 if (idarray_block_size)
1071 read_idarray_block(&data, repo->idarraydata + idarray_block_offset, idarray_block_size);
1074 /******* Part 7: Data ********************************************/
1076 idarraydatap = idarraydataend = 0;
1079 maxsize = read_id(&data, 0);
1080 allsize = read_id(&data, 0);
1081 maxsize += 5; /* so we can read the next schema of an array */
1082 if (maxsize > allsize)
1085 buf = solv_calloc(maxsize + DATA_READ_CHUNK + 4, 1); /* 4 extra bytes to detect overflows */
1090 if (l < DATA_READ_CHUNK)
1091 l = DATA_READ_CHUNK;
1094 if (!l || fread(buf, l, 1, data.fp) != 1)
1097 data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
1104 dp = data_read_id_max(dp, &id, 0, numschemata, &data);
1107 incore_add_id(&data, 0); /* so that incoreoffset 0 means schema 0 */
1108 incore_add_id(&data, id); /* main schema id */
1109 keyp = schemadata + schemata[id];
1110 data.mainschema = id;
1111 for (i = 0; keyp[i]; i++)
1114 data.mainschemaoffsets = solv_calloc(i, sizeof(Id));
1122 /* make sure we have enough room */
1123 if (keydepth == 0 || needchunk)
1125 int left = bufend - dp;
1126 /* read data chunk to dp */
1131 data.error = pool_error(pool, SOLV_ERROR_EOF, "buffer overrun");
1137 memmove(buf, dp, left);
1139 if (l < DATA_READ_CHUNK)
1140 l = DATA_READ_CHUNK;
1143 if (l && fread(buf + left, l, 1, data.fp) != 1)
1145 data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
1150 bufend = buf + left;
1151 if (allsize + left < maxsize)
1152 maxsize = allsize + left;
1160 printf("key %d at %d\n", key, (int)(keyp - 1 - schemadata));
1168 if (s && keydepth == 3)
1170 s++; /* next solvable */
1171 if (have_incoredata)
1172 data.incoreoffset[(s - pool->solvables) - data.start] = data.incoredatalen;
1174 id = stack[keydepth - 1];
1177 dp = data_read_id_max(dp, &id, 0, numschemata, &data);
1178 incore_add_id(&data, id);
1180 keyp = schemadata + schemata[id];
1187 keyp = schemadata + stack[--keydepth];
1188 nentries = stack[--keydepth];
1190 printf("pop flexarray %d %d\n", keydepth, nentries);
1193 s = 0; /* back from solvables */
1198 data.mainschemaoffsets[keyp - 1 - (schemadata + schemata[data.mainschema])] = data.incoredatalen;
1201 printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, keys[key].type), s);
1203 id = keys[key].name;
1204 if (keys[key].storage == KEY_STORAGE_VERTICAL_OFFSET)
1207 dp = data_skip(dp, REPOKEY_TYPE_ID);
1208 dp = data_skip(dp, REPOKEY_TYPE_ID);
1209 incore_add_blob(&data, dps, dp - dps); /* just record offset/size */
1212 switch (keys[key].type)
1214 case REPOKEY_TYPE_ID:
1215 dp = data_read_id_max(dp, &did, idmap, numid + numrel, &data);
1216 if (s && id == SOLVABLE_NAME)
1218 else if (s && id == SOLVABLE_ARCH)
1220 else if (s && id == SOLVABLE_EVR)
1222 else if (s && id == SOLVABLE_VENDOR)
1224 else if (keys[key].storage == KEY_STORAGE_INCORE)
1225 incore_add_id(&data, did);
1227 POOL_DEBUG(SOLV_DEBUG_STATS, "%s -> %s\n", pool_id2str(pool, id), pool_id2str(pool, did));
1230 case REPOKEY_TYPE_IDARRAY:
1231 case REPOKEY_TYPE_REL_IDARRAY:
1232 if (keys[key].storage == KEY_STORAGE_IDARRAYBLOCK)
1234 int cnt = convert_idarray_block(&data, repo->idarraydata + idarray_block_offset, idmap, numid + numrel);
1235 ido = idarray_block_offset;
1236 idarray_block_offset += cnt;
1237 if (idarray_block_offset > idarray_block_end)
1239 data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray block underflow");
1240 idarray_block_offset = idarray_block_end;
1243 if (!s || id < INTERESTED_START || id > INTERESTED_END)
1246 incore_add_ideof(&data, repo->idarraydata[ido++], --cnt > 1 ? 0 : 1);
1253 if (!s || id < INTERESTED_START || id > INTERESTED_END)
1256 dp = data_skip(dp, REPOKEY_TYPE_IDARRAY);
1257 if (keys[key].storage != KEY_STORAGE_INCORE)
1260 incore_map_idarray(&data, dps, idmap, numid + numrel);
1262 incore_add_blob(&data, dps, dp - dps);
1265 ido = idarraydatap - repo->idarraydata;
1266 if (keys[key].type == REPOKEY_TYPE_IDARRAY)
1267 dp = data_read_idarray(dp, &idarraydatap, idmap, numid + numrel, &data);
1269 dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, id);
1270 if (idarraydatap > idarraydataend)
1272 data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray overflow");
1276 if (id == SOLVABLE_PROVIDES)
1278 else if (id == SOLVABLE_OBSOLETES)
1280 else if (id == SOLVABLE_CONFLICTS)
1282 else if (id == SOLVABLE_REQUIRES)
1284 else if (id == SOLVABLE_RECOMMENDS)
1286 else if (id == SOLVABLE_SUPPLEMENTS)
1287 s->supplements = ido;
1288 else if (id == SOLVABLE_SUGGESTS)
1290 else if (id == SOLVABLE_ENHANCES)
1293 POOL_DEBUG(SOLV_DEBUG_STATS, "%s ->\n", pool_id2str(pool, id));
1294 for (; repo->idarraydata[ido]; ido++)
1295 POOL_DEBUG(SOLV_DEBUG_STATS," %s\n", pool_dep2str(pool, repo->idarraydata[ido]));
1298 case REPOKEY_TYPE_FIXARRAY:
1299 case REPOKEY_TYPE_FLEXARRAY:
1302 if (keydepth == sizeof(stack)/sizeof(*stack))
1304 data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "array stack overflow");
1307 stack[keydepth++] = nentries;
1308 stack[keydepth++] = keyp - schemadata;
1309 stack[keydepth++] = 0;
1310 dp = data_read_id_max(dp, &nentries, 0, 0, &data);
1311 incore_add_id(&data, nentries);
1314 /* zero size array? */
1316 nentries = stack[--keydepth];
1319 if (keydepth == 3 && id == REPOSITORY_SOLVABLES)
1321 /* horray! here come the solvables */
1322 if (nentries != numsolv)
1324 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "inconsistent number of solvables: %d %d", nentries, numsolv);
1329 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "more than one solvable block");
1332 if ((flags & REPO_EXTEND_SOLVABLES) != 0)
1333 s = pool_id2solvable(pool, extendstart);
1335 s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
1336 data.start = s - pool->solvables;
1337 data.end = data.start + numsolv;
1338 repodata_extend_block(&data, data.start, numsolv);
1339 for (i = 1; i < numkeys; i++)
1342 if ((keys[i].type == REPOKEY_TYPE_IDARRAY || keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
1343 && id >= INTERESTED_START && id <= INTERESTED_END)
1344 size_idarray += keys[i].size;
1346 /* allocate needed space in repo */
1347 /* we add maxsize because it is an upper limit for all idarrays, thus we can't overflow */
1348 repo_reserve_ids(repo, 0, size_idarray + maxsize + 1);
1349 idarraydatap = repo->idarraydata + repo->idarraysize;
1350 repo->idarraysize += size_idarray;
1351 idarraydataend = idarraydatap + size_idarray;
1353 if (have_incoredata)
1354 data.incoreoffset[(s - pool->solvables) - data.start] = data.incoredatalen;
1357 dp = data_read_id_max(dp, &id, 0, numschemata, &data);
1358 incore_add_id(&data, id);
1359 if (keys[key].type == REPOKEY_TYPE_FIXARRAY)
1362 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "illegal fixarray");
1363 stack[keydepth - 1] = id;
1365 keyp = schemadata + schemata[id];
1367 case REPOKEY_TYPE_NUM:
1368 if (!(solvflags & SOLV_FLAG_SIZE_BYTES) && keys[key].storage == KEY_STORAGE_INCORE &&
1369 (id == SOLVABLE_INSTALLSIZE || id == SOLVABLE_DOWNLOADSIZE || id == DELTA_DOWNLOADSIZE))
1371 /* old solv file with sizes in kilos. transcode. */
1372 dp = data_read_id(dp, &id);
1373 incore_add_sizek(&data, (unsigned int)id);
1376 if (s && id == RPM_RPMDBID)
1378 dp = data_read_id(dp, &id);
1380 repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
1381 repo->rpmdbid[(s - pool->solvables) - repo->start] = id;
1387 dp = data_skip(dp, keys[key].type);
1388 if (keys[key].storage == KEY_STORAGE_INCORE)
1389 incore_add_blob(&data, dps, dp - dps);
1393 /* should shrink idarraydata again */
1396 data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF, depth = %d", keydepth);
1400 data.error = pool_error(pool, SOLV_ERROR_EOF, "buffer overrun");
1401 else if (idarray_block_offset != idarray_block_end)
1402 data.error = pool_error(pool, SOLV_ERROR_EOF, "unconsumed idarray block entries");
1408 /* free solvables */
1409 repo_free_solvable_block(repo, data.start, data.end - data.start, 1);
1411 repo->idarraysize -= size_idarray;
1412 /* free incore data */
1413 data.incoredata = solv_free(data.incoredata);
1414 data.incoredatalen = data.incoredatafree = 0;
1417 if (data.incoredatafree)
1419 /* shrink excess size */
1420 data.incoredata = solv_realloc(data.incoredata, data.incoredatalen);
1421 data.incoredatafree = 0;
1425 /* fixup key data */
1426 for (i = 1; i < numkeys; i++)
1428 if (keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
1429 keys[i].type = REPOKEY_TYPE_IDARRAY;
1430 if (keys[i].storage == KEY_STORAGE_IDARRAYBLOCK)
1431 keys[i].storage = KEY_STORAGE_INCORE;
1432 if (keys[i].name >= SOLVABLE_NAME && keys[i].name <= RPM_RPMDBID)
1433 keys[i].storage = KEY_STORAGE_SOLVABLE;
1436 for (i = 1; i < numkeys; i++)
1437 if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && keys[i].size)
1439 if (i < numkeys && !data.error)
1442 unsigned int pagesize;
1444 /* we have vertical data, make it available */
1445 data.verticaloffset = solv_calloc(numkeys, sizeof(Id));
1446 for (i = 1; i < numkeys; i++)
1447 if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
1449 data.verticaloffset[i] = fileoffset;
1450 fileoffset += keys[i].size;
1452 data.lastverticaloffset = fileoffset;
1453 pagesize = read_u32(&data);
1456 data.error = repopagestore_read_or_setup_pages(&data.store, data.fp, pagesize, fileoffset);
1457 if (data.error == SOLV_ERROR_EOF)
1458 pool_error(pool, data.error, "repopagestore setup: unexpected EOF");
1459 else if (data.error)
1460 pool_error(pool, data.error, "repopagestore setup failed");
1463 data.fp = 0; /* no longer needed */
1468 repodata_freedata(&data);
1474 /* overwrite stub repodata */
1475 repodata_freedata(parent);
1476 data.repodataid = parent->repodataid;
1477 data.loadcallback = parent->loadcallback;
1482 /* make it available as new repodata */
1483 if (!repo->nrepodata)
1485 repo->nrepodata = 1;
1486 repo->repodata = solv_calloc(2, sizeof(data));
1489 repo->repodata = solv_realloc2(repo->repodata, repo->nrepodata + 1, sizeof(data));
1490 data.repodataid = repo->nrepodata;
1491 repo->repodata[repo->nrepodata++] = data;
1494 if ((flags & REPO_EXTEND_SOLVABLES) != 0)
1496 if (repodata_has_keyname(&data, SOLVABLE_FILELIST))
1497 repodata_set_filelisttype(repo->repodata + data.repodataid, REPODATA_FILELIST_EXTENSION);
1501 if (repodata_lookup_type(&data, SOLVID_META, REPOSITORY_FILTEREDFILELIST))
1502 repodata_set_filelisttype(repo->repodata + data.repodataid, REPODATA_FILELIST_FILTERED);
1505 /* create stub repodata entries for all external */
1506 if (!(flags & SOLV_ADD_NO_STUBS) && !parent)
1508 for (key = 1 ; key < data.nkeys; key++)
1509 if (data.keys[key].name == REPOSITORY_EXTERNAL && data.keys[key].type == REPOKEY_TYPE_FLEXARRAY)
1511 if (key < data.nkeys)
1512 repodata_create_stubs(repo->repodata + data.repodataid);
1515 POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_solv took %d ms\n", solv_timems(now));
1516 POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
1517 POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", data.incoredatalen/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
1522 solv_read_userdata(FILE *fp, unsigned char **datap, int *lenp)
1524 unsigned char d[4 * 10], *ud = 0;
1526 if (fread(d, sizeof(d), 1, fp) != 1)
1527 return SOLV_ERROR_EOF;
1528 n = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
1529 if (n != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
1530 return SOLV_ERROR_NOT_SOLV;
1531 n = d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7];
1534 case SOLV_VERSION_8:
1535 case SOLV_VERSION_9:
1538 return SOLV_ERROR_UNSUPPORTED;
1540 n = d[32] << 24 | d[33] << 16 | d[34] << 8 | d[35];
1541 if (!(n & SOLV_FLAG_USERDATA))
1544 n = d[36] << 24 | d[37] << 16 | d[38] << 8 | d[39];
1546 return SOLV_ERROR_CORRUPT;
1549 ud = solv_malloc(n + 1);
1550 if (fread(ud, n, 1, fp) != 1)
1553 return SOLV_ERROR_EOF;