2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
27 #include "poolid_private.h"
33 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
34 unsigned char *out, unsigned int out_len);
35 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
38 unsigned int out_len);
40 #define REPODATA_BLOCK 255
44 repodata_init(Repodata *data, Repo *repo, int localpool)
46 memset(data, 0, sizeof (*data));
48 data->localpool = localpool;
50 stringpool_init_empty(&data->spool);
51 data->keys = sat_calloc(1, sizeof(Repokey));
53 data->schemata = sat_calloc(1, sizeof(Id));
54 data->schemadata = sat_calloc(1, sizeof(Id));
56 data->schemadatalen = 1;
57 repopagestore_init(&data->store);
61 repodata_free(Repodata *data)
67 sat_free(data->schemata);
68 sat_free(data->schemadata);
69 sat_free(data->schematahash);
71 stringpool_free(&data->spool);
72 dirpool_free(&data->dirpool);
74 sat_free(data->mainschemaoffsets);
75 sat_free(data->incoredata);
76 sat_free(data->incoreoffset);
77 sat_free(data->verticaloffset);
79 repopagestore_free(&data->store);
81 sat_free(data->vincore);
84 for (i = 0; i < data->end - data->start; i++)
85 sat_free(data->attrs[i]);
86 sat_free(data->attrs);
88 for (i = 0; i < data->nxattrs; i++)
89 sat_free(data->xattrs[i]);
90 sat_free(data->xattrs);
92 sat_free(data->attrdata);
93 sat_free(data->attriddata);
97 /***************************************************************
101 /* this is not so time critical that we need a hash, so we do a simple
104 repodata_key2id(Repodata *data, Repokey *key, int create)
108 for (keyid = 1; keyid < data->nkeys; keyid++)
109 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
111 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
115 if (keyid == data->nkeys)
119 /* allocate new key */
120 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
121 data->keys[data->nkeys++] = *key;
122 if (data->verticaloffset)
124 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
125 data->verticaloffset[data->nkeys - 1] = 0;
127 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
133 /***************************************************************
134 * schema pool management
137 #define SCHEMATA_BLOCK 31
138 #define SCHEMATADATA_BLOCK 255
141 repodata_schema2id(Repodata *data, Id *schema, int create)
147 if ((schematahash = data->schematahash) == 0)
149 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
150 for (i = 0; i < data->nschemata; i++)
152 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
155 schematahash[h] = i + 1;
157 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
158 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
161 for (sp = schema, len = 0, h = 0; *sp; len++)
166 cid = schematahash[h];
170 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
173 for (cid = 0; cid < data->nschemata; cid++)
174 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
180 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
181 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
183 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
184 data->schemata[data->nschemata] = data->schemadatalen;
185 data->schemadatalen += len;
186 schematahash[h] = data->nschemata + 1;
188 fprintf(stderr, "schema2id: new schema\n");
190 return data->nschemata++;
194 repodata_free_schemahash(Repodata *data)
196 data->schematahash = sat_free(data->schematahash);
198 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
199 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
203 /***************************************************************
204 * dir pool management
208 repodata_str2dir(Repodata *data, const char *dir, int create)
214 while (*dir == '/' && dir[1] == '/')
216 if (*dir == '/' && !dir[1])
220 dire = strchrnul(dir, '/');
222 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
224 id = strn2id(data->repo->pool, dir, dire - dir, create);
227 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
240 repodata_dir2str(Repodata *data, Id did, const char *suf)
242 Pool *pool = data->repo->pool;
249 return suf ? suf : "";
253 comp = dirpool_compid(&data->dirpool, parent);
254 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
256 parent = dirpool_parent(&data->dirpool, parent);
261 l += strlen(suf) + 1;
262 p = pool_alloctmpspace(pool, l + 1) + l;
273 comp = dirpool_compid(&data->dirpool, parent);
274 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
277 strncpy(p, comps, l);
278 parent = dirpool_parent(&data->dirpool, parent);
286 /***************************************************************
290 static inline unsigned char *
291 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
293 Id *keyp = data->schemadata + data->schemata[schema];
294 for (; *keyp; keyp++)
295 dp = data_skip_key(data, dp, data->keys + *keyp);
300 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
302 int nentries, schema;
305 case REPOKEY_TYPE_FIXARRAY:
306 dp = data_read_id(dp, &nentries);
309 dp = data_read_id(dp, &schema);
311 dp = data_skip_schema(data, dp, schema);
313 case REPOKEY_TYPE_FLEXARRAY:
314 dp = data_read_id(dp, &nentries);
317 dp = data_read_id(dp, &schema);
318 dp = data_skip_schema(data, dp, schema);
322 if (key->storage == KEY_STORAGE_INCORE)
323 dp = data_skip(dp, key->type);
324 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
326 dp = data_skip(dp, REPOKEY_TYPE_ID);
327 dp = data_skip(dp, REPOKEY_TYPE_ID);
333 static unsigned char *
334 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
340 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
343 for (i = 0; (k = *keyp++) != 0; i++)
345 return data->incoredata + data->mainschemaoffsets[i];
348 while ((k = *keyp++) != 0)
352 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
354 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
355 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
358 if (data->keys[k].storage != KEY_STORAGE_INCORE)
360 dp = data_skip_key(data, dp, data->keys + k);
365 static unsigned char *
366 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
371 if (off >= data->lastverticaloffset)
373 off -= data->lastverticaloffset;
374 if (off + len > data->vincorelen)
376 return data->vincore + off;
378 if (off + len > key->size)
380 /* we now have the offset, go into vertical */
381 off += data->verticaloffset[key - data->keys];
382 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
383 dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
385 dp += off % BLOB_PAGESIZE;
389 static inline unsigned char *
390 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
392 unsigned char *dp = *dpp;
396 if (key->storage == KEY_STORAGE_INCORE)
399 *dpp = data_skip_key(data, dp, key);
402 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
405 dp = data_read_id(dp, &off);
406 dp = data_read_id(dp, &len);
409 return get_vertical_data(data, key, off, len);
415 load_repodata(Repodata *data)
417 if (data->loadcallback)
419 data->loadcallback(data);
420 if (data->state == REPODATA_AVAILABLE)
423 data->state = REPODATA_ERROR;
428 maybe_load_repodata(Repodata *data, Id keyname)
430 if (keyname && !repodata_precheck_keyname(data, keyname))
431 return 0; /* do not bother... */
438 for (i = 0; i < data->nkeys; i++)
439 if (keyname == data->keys[i].name)
441 if (i == data->nkeys)
444 return load_repodata(data);
447 case REPODATA_AVAILABLE:
450 data->state = REPODATA_ERROR;
455 static inline unsigned char*
456 solvid2data(Repodata *data, Id solvid, Id *schemap)
458 unsigned char *dp = data->incoredata;
461 if (solvid == SOLVID_META) /* META */
463 else if (solvid == SOLVID_POS) /* META */
465 Pool *pool = data->repo->pool;
466 if (data->repo != pool->pos.repo)
468 if (data != data->repo->repodata + pool->pos.repodataid)
470 *schemap = pool->pos.schema;
471 return data->incoredata + pool->pos.dp;
475 if (solvid < data->start || solvid >= data->end)
477 dp += data->incoreoffset[solvid - data->start];
479 return data_read_id(dp, schemap);
482 /************************************************************************
486 static inline unsigned char *
487 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
490 Id schema, *keyp, *kp;
493 if (!maybe_load_repodata(data, keyname))
495 dp = solvid2data(data, solvid, &schema);
498 keyp = data->schemadata + data->schemata[schema];
499 for (kp = keyp; *kp; kp++)
500 if (data->keys[*kp].name == keyname)
504 *keypp = key = data->keys + *kp;
505 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
506 return dp; /* no need to forward... */
507 dp = forward_to_key(data, *kp, keyp, dp);
510 return get_data(data, key, &dp, 0);
515 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
521 dp = find_key_data(data, solvid, keyname, &key);
524 if (key->type == REPOKEY_TYPE_CONSTANTID)
526 if (key->type != REPOKEY_TYPE_ID)
528 dp = data_read_id(dp, &id);
533 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
539 dp = find_key_data(data, solvid, keyname, &key);
542 if (key->type == REPOKEY_TYPE_STR)
543 return (const char *)dp;
544 if (key->type == REPOKEY_TYPE_CONSTANTID)
545 return id2str(data->repo->pool, key->size);
546 if (key->type == REPOKEY_TYPE_ID)
547 dp = data_read_id(dp, &id);
551 return data->spool.stringspace + data->spool.strings[id];
552 return id2str(data->repo->pool, id);
556 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
563 dp = find_key_data(data, solvid, keyname, &key);
566 if (key->type == REPOKEY_TYPE_NUM
567 || key->type == REPOKEY_TYPE_U32
568 || key->type == REPOKEY_TYPE_CONSTANT)
570 dp = data_fetch(dp, &kv, key);
578 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
584 if (!maybe_load_repodata(data, keyname))
586 dp = solvid2data(data, solvid, &schema);
589 /* can't use find_key_data as we need to test the type */
590 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
591 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
596 const unsigned char *
597 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
602 dp = find_key_data(data, solvid, keyname, &key);
610 /************************************************************************
614 struct subschema_data {
620 /* search a specific repodata */
622 repodata_search(Repodata *data, Id solvid, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
626 Id keyid, *kp, *keyp;
627 unsigned char *dp, *ddp;
633 if (!maybe_load_repodata(data, keyname))
635 if (solvid == SOLVID_SUBSCHEMA)
637 struct subschema_data *subd = cbdata;
638 cbdata = subd->cbdata;
640 schema = subd->parent->id;
641 dp = (unsigned char *)subd->parent->str;
642 kv.parent = subd->parent;
647 dp = solvid2data(data, solvid, &schema);
650 s = data->repo->pool->solvables + solvid;
653 keyp = data->schemadata + data->schemata[schema];
656 /* search for a specific key */
657 for (kp = keyp; *kp; kp++)
658 if (data->keys[*kp].name == keyname)
662 dp = forward_to_key(data, *kp, keyp, dp);
668 while ((keyid = *keyp++) != 0)
671 key = data->keys + keyid;
672 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
674 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
676 struct subschema_data subd;
680 subd.cbdata = cbdata;
683 ddp = data_read_id(ddp, &nentries);
687 while (ddp && nentries > 0)
689 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
690 ddp = data_read_id(ddp, &schema);
692 kv.str = (char *)ddp;
693 stop = callback(cbdata, s, data, key, &kv);
694 if (stop > SEARCH_NEXT_KEY)
699 repodata_search(data, SOLVID_SUBSCHEMA, 0, callback, &subd);
700 ddp = data_skip_schema(data, ddp, schema);
708 kv.str = (char *)ddp;
709 stop = callback(cbdata, s, data, key, &kv);
710 if (stop > SEARCH_NEXT_KEY)
720 ddp = data_fetch(ddp, &kv, key);
723 stop = callback(cbdata, s, data, key, &kv);
726 while (!kv.eof && !stop);
727 if (onekey || stop > SEARCH_NEXT_KEY)
733 repodata_setpos_kv(Repodata *data, KeyValue *kv)
735 Pool *pool = data->repo->pool;
739 pool->pos.repodataid = 0;
741 pool->pos.schema = 0;
746 pool->pos.repodataid = data - data->repo->repodata;
747 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
748 pool->pos.schema = kv->id;
752 /************************************************************************
753 * data iterator functions
756 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
757 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
758 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
759 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
760 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
761 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
762 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
763 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
764 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
765 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
766 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
767 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
768 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
769 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
773 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
787 case SOLVABLE_VENDOR:
790 case SOLVABLE_PROVIDES:
792 return s->provides ? s->repo->idarraydata + s->provides : 0;
793 case SOLVABLE_OBSOLETES:
795 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
796 case SOLVABLE_CONFLICTS:
798 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
799 case SOLVABLE_REQUIRES:
801 return s->requires ? s->repo->idarraydata + s->requires : 0;
802 case SOLVABLE_RECOMMENDS:
804 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
805 case SOLVABLE_SUPPLEMENTS:
807 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
808 case SOLVABLE_SUGGESTS:
810 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
811 case SOLVABLE_ENHANCES:
813 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
816 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
823 datamatcher_init(Datamatcher *ma, Pool *pool, const char *match, int flags)
826 ma->match = (void *)match;
829 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
831 ma->match = sat_calloc(1, sizeof(regex_t));
832 ma->error = regcomp((regex_t *)ma->match, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
836 ma->match = (void *)match;
837 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
843 datamatcher_free(Datamatcher *ma)
845 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->match)
848 ma->match = sat_free(ma->match);
853 datamatcher_match(Datamatcher *ma, Repodata *data, Repokey *key, KeyValue *kv)
857 case REPOKEY_TYPE_ID:
858 case REPOKEY_TYPE_IDARRAY:
859 if (data && data->localpool)
860 kv->str = stringpool_id2str(&data->spool, kv->id);
862 kv->str = id2str(ma->pool, kv->id);
864 case REPOKEY_TYPE_STR:
866 case REPOKEY_TYPE_DIRSTRARRAY:
867 if (!(ma->flags & SEARCH_FILES))
869 /* Put the full filename into kv->str. */
870 kv->str = repodata_dir2str(data, kv->id, kv->str);
871 /* And to compensate for that put the "empty" directory into
872 kv->id, so that later calls to repodata_dir2str on this data
873 come up with the same filename again. */
879 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
880 for the others we can't know if a colon separates a kind or not. */
881 if ((ma->flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
883 const char *s = strchr(kv->str, ':');
887 switch ((ma->flags & SEARCH_STRINGMASK))
889 case SEARCH_SUBSTRING:
890 if (ma->flags & SEARCH_NOCASE)
892 if (!strcasestr(kv->str, (const char *)ma->match))
897 if (!strstr(kv->str, (const char *)ma->match))
902 if (ma->flags & SEARCH_NOCASE)
904 if (strcasecmp((const char *)ma->match, kv->str))
909 if (strcmp((const char *)ma->match, kv->str))
914 if (fnmatch((const char *)ma->match, kv->str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
918 if (regexec((const regex_t *)ma->match, kv->str, 0, NULL, 0))
953 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname, const char *match, int flags)
955 memset(di, 0, sizeof(*di));
957 di->keyname = keyname;
959 di->pool = repo->pool;
961 flags |= SEARCH_THISSOLVID;
966 datamatcher_init(&di->matcher, di->pool, match, flags);
969 di->repo = di->pool->pos.repo;
975 di->data = di->repo->repodata + di->pool->pos.repodataid;
979 di->state = di_enterrepo;
983 dataiterator_free(Dataiterator *di)
985 if (di->matcher.match)
986 datamatcher_free(&di->matcher);
989 static inline unsigned char *
990 dataiterator_find_keyname(Dataiterator *di, Id keyname)
993 Repokey *keys = di->data->keys;
996 if (!(di->flags & SEARCH_SUB))
998 for (keyp = di->keyp; *keyp; keyp++)
999 if (keys[*keyp].name == di->keyname)
1004 for (keyp++; *keyp; keyp++)
1005 if (keys[*keyp].name == di->keyname ||
1006 keys[*keyp].type == REPOKEY_TYPE_FIXARRAY ||
1007 keys[*keyp].type == REPOKEY_TYPE_FLEXARRAY)
1012 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1020 dataiterator_step(Dataiterator *di)
1028 case di_enterrepo: di_enterrepo:
1029 if (!(di->flags & SEARCH_THISSOLVID))
1030 di->solvid = di->repo->start;
1033 case di_entersolvable: di_entersolvable:
1034 if (di->repodataid >= 0)
1037 if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)))
1039 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1041 goto di_entersolvablekey;
1046 case di_enterrepodata: di_enterrepodata:
1047 if (di->repodataid >= 0)
1048 di->data = di->repo->repodata + di->repodataid;
1049 if (!maybe_load_repodata(di->data, di->keyname))
1050 goto di_nextrepodata;
1051 di->dp = solvid2data(di->data, di->solvid, &schema);
1053 goto di_nextrepodata;
1054 di->keyp = di->data->schemadata + di->data->schemata[schema];
1057 di->dp = dataiterator_find_keyname(di, di->keyname);
1059 goto di_nextrepodata;
1063 case di_enterkey: di_enterkey:
1065 di->key = di->data->keys + *di->keyp;
1066 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1069 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1075 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1077 di->state = di_nextkey;
1079 di->state = di_nextattr;
1082 case di_nextkey: di_nextkey:
1088 else if ((di->flags & SEARCH_SUB) != 0)
1090 di->dp = dataiterator_find_keyname(di, di->keyname);
1098 case di_nextrepodata: di_nextrepodata:
1099 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1100 goto di_enterrepodata;
1103 case di_nextsolvable:
1104 if (!(di->flags & SEARCH_THISSOLVID))
1107 di->solvid = di->repo->start;
1110 for (; di->solvid < di->repo->end; di->solvid++)
1112 if (di->pool->solvables[di->solvid].repo == di->repo)
1113 goto di_entersolvable;
1119 if (di->repoid >= 0)
1122 if (di->repoid < di->pool->nrepos)
1124 di->repo = di->pool->repos[di->repoid];
1134 case di_enterarray: di_enterarray:
1135 di->ddp = data_read_id(di->ddp, &di->kv.num);
1140 case di_nextarrayelement: di_nextarrayelement:
1143 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1144 if (di->kv.entry == di->kv.num)
1146 if (di->keyname && di->key->name != di->keyname)
1148 di->kv.str = (char *)di->ddp;
1150 di->state = di_nextkey;
1153 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1154 di->ddp = data_read_id(di->ddp, &di->kv.id);
1155 di->kv.str = (char *)di->ddp;
1156 if (di->keyname && di->key->name != di->keyname)
1158 if ((di->flags & SEARCH_SUB) != 0)
1159 di->state = di_entersub;
1161 di->state = di_nextarrayelement;
1164 case di_entersub: di_entersub:
1165 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1166 goto di_nextarrayelement; /* sorry, full */
1167 di->parents[di->nparents].kv = di->kv;
1168 di->parents[di->nparents].dp = di->dp;
1169 di->parents[di->nparents].keyp = di->keyp;
1170 di->dp = (unsigned char *)di->kv.str;
1171 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1172 memset(&di->kv, 0, sizeof(di->kv));
1173 di->kv.parent = &di->parents[di->nparents].kv;
1178 case di_leavesub: di_leavesub:
1180 di->dp = di->parents[di->nparents].dp;
1181 di->kv = di->parents[di->nparents].kv;
1182 di->keyp = di->parents[di->nparents].keyp;
1183 di->key = di->data->keys + *di->keyp;
1184 di->ddp = (unsigned char *)di->kv.str;
1185 goto di_nextarrayelement;
1187 /* special solvable attr handling follows */
1189 case di_nextsolvableattr:
1190 di->kv.id = *di->idp++;
1195 di->state = di_nextsolvablekey;
1199 case di_nextsolvablekey: di_nextsolvablekey:
1200 if (di->keyname || di->key->name == RPM_RPMDBID)
1201 goto di_enterrepodata;
1205 case di_entersolvablekey: di_entersolvablekey:
1206 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1207 if (!di->idp || !di->idp[0])
1208 goto di_nextsolvablekey;
1209 di->kv.id = di->idp[0];
1210 di->kv.num = di->idp[0];
1211 if (!di->kv.eof && !di->idp[1])
1215 di->state = di_nextsolvablekey;
1217 di->state = di_nextsolvableattr;
1221 if (di->matcher.match)
1222 if (!datamatcher_match(&di->matcher, di->data, di->key, &di->kv))
1224 /* found something! */
1230 dataiterator_entersub(Dataiterator *di)
1232 if (di->state == di_nextarrayelement)
1233 di->state = di_entersub;
1237 dataiterator_setpos(Dataiterator *di)
1241 memset(&di->pool->pos, 0, sizeof(di->pool->pos));
1244 di->pool->pos.repo = di->repo;
1245 di->pool->pos.repodataid = di->data - di->repo->repodata;
1246 di->pool->pos.schema = di->kv.id;
1247 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1251 dataiterator_setpos_parent(Dataiterator *di)
1255 memset(&di->pool->pos, 0, sizeof(di->pool->pos));
1258 di->pool->pos.repo = di->repo;
1259 di->pool->pos.repodataid = di->data - di->repo->repodata;
1260 di->pool->pos.schema = di->kv.parent->id;
1261 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1265 dataiterator_skip_attribute(Dataiterator *di)
1267 if (di->state == di_nextsolvableattr)
1268 di->state = di_nextsolvablekey;
1270 di->state = di_nextkey;
1274 dataiterator_skip_solvable(Dataiterator *di)
1276 di->state = di_nextsolvable;
1280 dataiterator_skip_repo(Dataiterator *di)
1282 di->state = di_nextrepo;
1286 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1290 di->solvid = s - di->pool->solvables;
1291 di->state = di_entersolvable;
1295 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1299 di->state = di_enterrepo;
1303 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1305 Datamatcher matcher = di->matcher;
1306 matcher.flags = flags;
1307 matcher.match = (void *)vmatch;
1308 matcher.pool = di->pool;
1309 return datamatcher_match(&matcher, di->data, di->key, &di->kv);
1313 /************************************************************************
1314 * data modify functions
1317 /* extend repodata so that it includes solvables p */
1319 repodata_extend(Repodata *data, Id p)
1321 if (data->start == data->end)
1322 data->start = data->end = p;
1325 int old = data->end - data->start;
1326 int new = p - data->end + 1;
1329 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1330 memset(data->attrs + old, 0, new * sizeof(Id *));
1332 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1333 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1336 if (p < data->start)
1338 int old = data->end - data->start;
1339 int new = data->start - p;
1342 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1343 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1344 memset(data->attrs, 0, new * sizeof(Id *));
1346 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1347 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1348 memset(data->incoreoffset, 0, new * sizeof(Id));
1354 repodata_extend_block(Repodata *data, Id start, Id num)
1358 if (!data->incoreoffset)
1360 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1361 data->start = start;
1362 data->end = start + num;
1365 repodata_extend(data, start);
1367 repodata_extend(data, start + num - 1);
1370 /**********************************************************************/
1372 #define REPODATA_ATTRS_BLOCK 63
1373 #define REPODATA_ATTRDATA_BLOCK 1023
1374 #define REPODATA_ATTRIDDATA_BLOCK 63
1378 repodata_new_handle(Repodata *data)
1382 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1385 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1386 data->xattrs[data->nxattrs] = 0;
1387 return -(data->nxattrs++);
1391 repodata_get_attrp(Repodata *data, Id handle)
1393 if (handle == SOLVID_META)
1397 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1402 return data->xattrs - handle;
1403 if (handle < data->start || handle >= data->end)
1404 repodata_extend(data, handle);
1406 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1407 return data->attrs + (handle - data->start);
1411 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1417 app = repodata_get_attrp(data, handle);
1422 for (pp = ap; *pp; pp += 2)
1423 /* Determine equality based on the name only, allows us to change
1424 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1425 if (data->keys[*pp].name == data->keys[keyid].name)
1438 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1448 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1452 keyid = repodata_key2id(data, key, 1);
1453 repodata_insert_keyid(data, solvid, keyid, val, 1);
1457 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1461 key.type = REPOKEY_TYPE_ID;
1463 key.storage = KEY_STORAGE_INCORE;
1464 repodata_set(data, solvid, &key, id);
1468 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1472 key.type = REPOKEY_TYPE_NUM;
1474 key.storage = KEY_STORAGE_INCORE;
1475 repodata_set(data, solvid, &key, (Id)num);
1479 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1483 if (data->localpool)
1484 id = stringpool_str2id(&data->spool, str, 1);
1486 id = str2id(data->repo->pool, str, 1);
1488 key.type = REPOKEY_TYPE_ID;
1490 key.storage = KEY_STORAGE_INCORE;
1491 repodata_set(data, solvid, &key, id);
1495 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1499 key.type = REPOKEY_TYPE_CONSTANT;
1500 key.size = constant;
1501 key.storage = KEY_STORAGE_INCORE;
1502 repodata_set(data, solvid, &key, 0);
1506 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1510 key.type = REPOKEY_TYPE_CONSTANTID;
1512 key.storage = KEY_STORAGE_INCORE;
1513 repodata_set(data, solvid, &key, 0);
1517 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1521 key.type = REPOKEY_TYPE_VOID;
1523 key.storage = KEY_STORAGE_INCORE;
1524 repodata_set(data, solvid, &key, 0);
1528 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1533 l = strlen(str) + 1;
1535 key.type = REPOKEY_TYPE_STR;
1537 key.storage = KEY_STORAGE_INCORE;
1538 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1539 memcpy(data->attrdata + data->attrdatalen, str, l);
1540 repodata_set(data, solvid, &key, data->attrdatalen);
1541 data->attrdatalen += l;
1545 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1548 Id *ida, *pp, **ppp;
1550 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1552 /* great! just append the new data */
1553 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1554 data->attriddatalen--; /* overwrite terminating 0 */
1555 data->lastdatalen += entrysize;
1558 ppp = repodata_get_attrp(data, handle);
1561 for (; *pp; pp += 2)
1562 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1566 /* not found. allocate new key */
1571 key.storage = KEY_STORAGE_INCORE;
1572 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1573 repodata_set(data, handle, &key, data->attriddatalen);
1574 data->lasthandle = 0; /* next time... */
1578 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1579 oldsize += entrysize;
1580 if (ida + 1 == data->attriddata + data->attriddatalen)
1582 /* this was the last entry, just append it */
1583 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1584 data->attriddatalen--; /* overwrite terminating 0 */
1588 /* too bad. move to back. */
1589 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1590 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1591 pp[1] = data->attriddatalen;
1592 data->attriddatalen += oldsize;
1594 data->lasthandle = handle;
1595 data->lastkey = *pp;
1596 data->lastdatalen = data->attriddatalen + entrysize + 1;
1600 checksumtype2len(Id type)
1604 case REPOKEY_TYPE_MD5:
1606 case REPOKEY_TYPE_SHA1:
1608 case REPOKEY_TYPE_SHA256:
1609 return SIZEOF_SHA256;
1616 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1617 const unsigned char *str)
1620 int l = checksumtype2len(type);
1627 key.storage = KEY_STORAGE_INCORE;
1628 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1629 memcpy(data->attrdata + data->attrdatalen, str, l);
1630 repodata_set(data, solvid, &key, data->attrdatalen);
1631 data->attrdatalen += l;
1635 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1638 for (i = 0; i < buflen; i++)
1640 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1641 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
1642 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
1653 buf[i] = (buf[i] << 4) | v;
1660 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1663 unsigned char buf[64];
1664 int l = checksumtype2len(type);
1668 if (hexstr2bytes(buf, str, l) != l)
1670 fprintf(stderr, "Invalid hex character in '%s'\n", str);
1673 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
1677 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1682 l = checksumtype2len(type);
1685 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1686 for (i = 0; i < l; i++)
1688 unsigned char v = buf[i];
1689 unsigned char w = v >> 4;
1690 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1692 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1699 repodata_globalize_id(Repodata *data, Id id)
1701 if (!data || !data->localpool)
1703 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
1707 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
1711 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
1713 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
1714 data->attriddata[data->attriddatalen++] = dir;
1715 data->attriddata[data->attriddatalen++] = num;
1716 data->attriddata[data->attriddatalen++] = num2;
1717 data->attriddata[data->attriddatalen++] = 0;
1721 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
1727 l = strlen(str) + 1;
1728 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1729 memcpy(data->attrdata + data->attrdatalen, str, l);
1730 stroff = data->attrdatalen;
1731 data->attrdatalen += l;
1734 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
1736 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
1737 data->attriddata[data->attriddatalen++] = dir;
1738 data->attriddata[data->attriddatalen++] = stroff;
1739 data->attriddata[data->attriddatalen++] = 0;
1743 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
1746 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
1748 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
1749 data->attriddata[data->attriddatalen++] = id;
1750 data->attriddata[data->attriddatalen++] = 0;
1754 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
1758 if (data->localpool)
1759 id = stringpool_str2id(&data->spool, str, 1);
1761 id = str2id(data->repo->pool, str, 1);
1762 repodata_add_idarray(data, solvid, keyname, id);
1766 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
1768 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
1769 data->attriddata[data->attriddatalen++] = ghandle;
1770 data->attriddata[data->attriddatalen++] = 0;
1774 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
1776 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
1777 data->attriddata[data->attriddatalen++] = ghandle;
1778 data->attriddata[data->attriddatalen++] = 0;
1782 repodata_merge_attrs(Repodata *data, Id dest, Id src)
1785 if (dest == src || !(keyp = data->attrs[src]))
1787 for (; *keyp; keyp += 2)
1788 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
1794 /**********************************************************************/
1796 /* unify with repo_write! */
1798 #define EXTDATA_BLOCK 1023
1806 data_addid(struct extdata *xd, Id x)
1809 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
1810 dp = xd->buf + xd->len;
1815 *dp++ = (x >> 28) | 128;
1817 *dp++ = (x >> 21) | 128;
1818 *dp++ = (x >> 14) | 128;
1821 *dp++ = (x >> 7) | 128;
1823 xd->len = dp - xd->buf;
1827 data_addideof(struct extdata *xd, Id x, int eof)
1830 x = (x & 63) | ((x & ~63) << 1);
1831 data_addid(xd, (eof ? x: x | 64));
1835 data_addblob(struct extdata *xd, unsigned char *blob, int len)
1837 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
1838 memcpy(xd->buf + xd->len, blob, len);
1842 /*********************************/
1845 repodata_serialize_key(Repodata *data, struct extdata *newincore,
1846 struct extdata *newvincore,
1848 Repokey *key, Id val)
1850 /* Otherwise we have a new value. Parse it into the internal
1854 unsigned int oldvincorelen = 0;
1858 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1861 oldvincorelen = xd->len;
1865 case REPOKEY_TYPE_VOID:
1866 case REPOKEY_TYPE_CONSTANT:
1867 case REPOKEY_TYPE_CONSTANTID:
1869 case REPOKEY_TYPE_STR:
1870 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
1872 case REPOKEY_TYPE_MD5:
1873 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
1875 case REPOKEY_TYPE_SHA1:
1876 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
1878 case REPOKEY_TYPE_SHA256:
1879 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
1881 case REPOKEY_TYPE_ID:
1882 case REPOKEY_TYPE_NUM:
1883 case REPOKEY_TYPE_DIR:
1884 data_addid(xd, val);
1886 case REPOKEY_TYPE_IDARRAY:
1887 for (ida = data->attriddata + val; *ida; ida++)
1888 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
1890 case REPOKEY_TYPE_DIRNUMNUMARRAY:
1891 for (ida = data->attriddata + val; *ida; ida += 3)
1893 data_addid(xd, ida[0]);
1894 data_addid(xd, ida[1]);
1895 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
1898 case REPOKEY_TYPE_DIRSTRARRAY:
1899 for (ida = data->attriddata + val; *ida; ida += 2)
1901 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
1902 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
1905 case REPOKEY_TYPE_FIXARRAY:
1909 for (ida = data->attriddata + val; *ida; ida++)
1912 fprintf(stderr, "serialize struct %d\n", *ida);
1915 Id *kp = data->xattrs[-*ida];
1922 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
1928 schemaid = repodata_schema2id(data, schema, 1);
1929 else if (schemaid != repodata_schema2id(data, schema, 0))
1931 fprintf(stderr, " not yet implemented: substructs with different schemas\n");
1935 fprintf(stderr, " schema %d\n", schemaid);
1940 data_addid(xd, num);
1941 data_addid(xd, schemaid);
1942 for (ida = data->attriddata + val; *ida; ida++)
1944 Id *kp = data->xattrs[-*ida];
1949 repodata_serialize_key(data, newincore, newvincore,
1950 schema, data->keys + *kp, kp[1]);
1955 case REPOKEY_TYPE_FLEXARRAY:
1958 for (ida = data->attriddata + val; *ida; ida++)
1960 data_addid(xd, num);
1961 for (ida = data->attriddata + val; *ida; ida++)
1963 Id *kp = data->xattrs[-*ida];
1966 data_addid(xd, 0); /* XXX */
1973 schemaid = repodata_schema2id(data, schema, 1);
1974 data_addid(xd, schemaid);
1975 kp = data->xattrs[-*ida];
1978 repodata_serialize_key(data, newincore, newvincore,
1979 schema, data->keys + *kp, kp[1]);
1985 fprintf(stderr, "don't know how to handle type %d\n", key->type);
1988 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1990 /* put offset/len in incore */
1991 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
1992 oldvincorelen = xd->len - oldvincorelen;
1993 data_addid(newincore, oldvincorelen);
1998 repodata_internalize(Repodata *data)
2000 Repokey *key, solvkey;
2002 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2003 unsigned char *dp, *ndp;
2004 int newschema, oldcount;
2005 struct extdata newincore;
2006 struct extdata newvincore;
2009 if (!data->attrs && !data->xattrs)
2012 newvincore.buf = data->vincore;
2013 newvincore.len = data->vincorelen;
2015 /* find the solvables key, create if needed */
2016 memset(&solvkey, 0, sizeof(solvkey));
2017 solvkey.name = REPOSITORY_SOLVABLES;
2018 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2020 solvkey.storage = KEY_STORAGE_INCORE;
2021 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2023 schema = sat_malloc2(data->nkeys, sizeof(Id));
2024 seen = sat_malloc2(data->nkeys, sizeof(Id));
2026 /* Merge the data already existing (in data->schemata, ->incoredata and
2027 friends) with the new attributes in data->attrs[]. */
2028 nentry = data->end - data->start;
2029 memset(&newincore, 0, sizeof(newincore));
2030 data_addid(&newincore, 0); /* start data at offset 1 */
2032 data->mainschema = 0;
2033 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2035 /* join entry data */
2036 /* we start with the meta data, entry -1 */
2037 for (entry = -1; entry < nentry; entry++)
2039 memset(seen, 0, data->nkeys * sizeof(Id));
2041 dp = data->incoredata;
2044 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2045 dp = data_read_id(dp, &oldschema);
2048 fprintf(stderr, "oldschema %d\n", oldschema);
2049 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2050 fprintf(stderr, "schemadata %p\n", data->schemadata);
2052 /* seen: -1: old data 0: skipped >0: id + 1 */
2056 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2060 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
2068 keyp = data->attrs ? data->attrs[entry] : 0;
2071 /* strip solvables key */
2073 for (sp = keyp = schema; *sp; sp++)
2074 if (*sp != solvkeyid)
2079 seen[solvkeyid] = 0;
2080 keyp = data->xattrs ? data->xattrs[1] : 0;
2083 for (; *keyp; keyp += 2)
2090 seen[*keyp] = keyp[1] + 1;
2092 if (entry < 0 && data->end != data->start)
2099 /* Ideally we'd like to sort the new schema here, to ensure
2100 schema equality independend of the ordering. We can't do that
2101 yet. For once see below (old ids need to come before new ids).
2102 An additional difficulty is that we also need to move
2103 the values with the keys. */
2104 schemaid = repodata_schema2id(data, schema, 1);
2106 schemaid = oldschema;
2109 /* Now create data blob. We walk through the (possibly new) schema
2110 and either copy over old data, or insert the new. */
2111 /* XXX Here we rely on the fact that the (new) schema has the form
2112 o1 o2 o3 o4 ... | n1 n2 n3 ...
2113 (oX being the old keyids (possibly overwritten), and nX being
2114 the new keyids). This rules out sorting the keyids in order
2115 to ensure a small schema count. */
2117 data->incoreoffset[entry] = newincore.len;
2118 data_addid(&newincore, schemaid);
2121 data->mainschema = schemaid;
2122 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2124 keypstart = data->schemadata + data->schemata[schemaid];
2125 for (keyp = keypstart; *keyp; keyp++)
2128 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2129 if (*keyp == solvkeyid)
2131 /* add flexarray entry count */
2132 data_addid(&newincore, data->end - data->start);
2135 key = data->keys + *keyp;
2137 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2142 /* Skip the data associated with this old key. */
2143 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2145 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2146 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2148 else if (key->storage == KEY_STORAGE_INCORE)
2149 ndp = data_skip_key(data, dp, key);
2152 if (seen[*keyp] == -1)
2154 /* If this key was an old one _and_ was not overwritten with
2155 a different value copy over the old value (we skipped it
2158 data_addblob(&newincore, dp, ndp - dp);
2161 else if (seen[*keyp])
2163 /* Otherwise we have a new value. Parse it into the internal
2165 repodata_serialize_key(data, &newincore, &newvincore,
2166 schema, key, seen[*keyp] - 1);
2170 if (entry >= 0 && data->attrs && data->attrs[entry])
2171 data->attrs[entry] = sat_free(data->attrs[entry]);
2173 /* free all xattrs */
2174 for (entry = 0; entry < data->nxattrs; entry++)
2175 if (data->xattrs[entry])
2176 sat_free(data->xattrs[entry]);
2177 data->xattrs = sat_free(data->xattrs);
2180 data->lasthandle = 0;
2182 data->lastdatalen = 0;
2185 repodata_free_schemahash(data);
2187 sat_free(data->incoredata);
2188 data->incoredata = newincore.buf;
2189 data->incoredatalen = newincore.len;
2190 data->incoredatafree = 0;
2192 sat_free(data->vincore);
2193 data->vincore = newvincore.buf;
2194 data->vincorelen = newvincore.len;
2196 data->attrs = sat_free(data->attrs);
2197 data->attrdata = sat_free(data->attrdata);
2198 data->attriddata = sat_free(data->attriddata);
2199 data->attrdatalen = 0;
2200 data->attriddatalen = 0;
2204 repodata_disable_paging(Repodata *data)
2206 if (maybe_load_repodata(data, 0))
2207 repopagestore_disable_paging(&data->store);
2211 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: