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;
963 if (repo && !(flags & SEARCH_ALL_REPOS))
966 di->repo = di->pool->repos[0];
968 datamatcher_init(&di->matcher, di->pool, match, flags);
971 di->repo = di->pool->pos.repo;
977 di->data = di->repo->repodata + di->pool->pos.repodataid;
981 di->state = di_enterrepo;
985 dataiterator_free(Dataiterator *di)
987 if (di->matcher.match)
988 datamatcher_free(&di->matcher);
991 static inline unsigned char *
992 dataiterator_find_keyname(Dataiterator *di, Id keyname)
995 Repokey *keys = di->data->keys;
998 if (!(di->flags & SEARCH_SUB))
1000 for (keyp = di->keyp; *keyp; keyp++)
1001 if (keys[*keyp].name == di->keyname)
1006 for (keyp++; *keyp; keyp++)
1007 if (keys[*keyp].name == di->keyname ||
1008 keys[*keyp].type == REPOKEY_TYPE_FIXARRAY ||
1009 keys[*keyp].type == REPOKEY_TYPE_FLEXARRAY)
1014 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1022 dataiterator_step(Dataiterator *di)
1030 case di_enterrepo: di_enterrepo:
1031 if (!(di->flags & SEARCH_THISSOLVID))
1032 di->solvid = di->repo->start;
1035 case di_entersolvable: di_entersolvable:
1036 if (di->repodataid >= 0)
1039 if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)))
1041 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1043 goto di_entersolvablekey;
1048 case di_enterrepodata: di_enterrepodata:
1049 if (di->repodataid >= 0)
1050 di->data = di->repo->repodata + di->repodataid;
1051 if (!maybe_load_repodata(di->data, di->keyname))
1052 goto di_nextrepodata;
1053 di->dp = solvid2data(di->data, di->solvid, &schema);
1055 goto di_nextrepodata;
1056 di->keyp = di->data->schemadata + di->data->schemata[schema];
1059 di->dp = dataiterator_find_keyname(di, di->keyname);
1061 goto di_nextrepodata;
1065 case di_enterkey: di_enterkey:
1067 di->key = di->data->keys + *di->keyp;
1068 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1071 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1077 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1079 di->state = di_nextkey;
1081 di->state = di_nextattr;
1084 case di_nextkey: di_nextkey:
1090 else if ((di->flags & SEARCH_SUB) != 0)
1092 di->dp = dataiterator_find_keyname(di, di->keyname);
1100 case di_nextrepodata: di_nextrepodata:
1101 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1102 goto di_enterrepodata;
1105 case di_nextsolvable:
1106 if (!(di->flags & SEARCH_THISSOLVID))
1109 di->solvid = di->repo->start;
1112 for (; di->solvid < di->repo->end; di->solvid++)
1114 if (di->pool->solvables[di->solvid].repo == di->repo)
1115 goto di_entersolvable;
1121 if (di->repoid >= 0)
1124 if (di->repoid < di->pool->nrepos)
1126 di->repo = di->pool->repos[di->repoid];
1136 case di_enterarray: di_enterarray:
1137 di->ddp = data_read_id(di->ddp, &di->kv.num);
1142 case di_nextarrayelement: di_nextarrayelement:
1145 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1146 if (di->kv.entry == di->kv.num)
1148 if (di->keyname && di->key->name != di->keyname)
1150 di->kv.str = (char *)di->ddp;
1152 di->state = di_nextkey;
1155 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1156 di->ddp = data_read_id(di->ddp, &di->kv.id);
1157 di->kv.str = (char *)di->ddp;
1158 if (di->keyname && di->key->name != di->keyname)
1160 if ((di->flags & SEARCH_SUB) != 0)
1161 di->state = di_entersub;
1163 di->state = di_nextarrayelement;
1166 case di_entersub: di_entersub:
1167 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1168 goto di_nextarrayelement; /* sorry, full */
1169 di->parents[di->nparents].kv = di->kv;
1170 di->parents[di->nparents].dp = di->dp;
1171 di->parents[di->nparents].keyp = di->keyp;
1172 di->dp = (unsigned char *)di->kv.str;
1173 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1174 memset(&di->kv, 0, sizeof(di->kv));
1175 di->kv.parent = &di->parents[di->nparents].kv;
1180 case di_leavesub: di_leavesub:
1182 di->dp = di->parents[di->nparents].dp;
1183 di->kv = di->parents[di->nparents].kv;
1184 di->keyp = di->parents[di->nparents].keyp;
1185 di->key = di->data->keys + *di->keyp;
1186 di->ddp = (unsigned char *)di->kv.str;
1187 goto di_nextarrayelement;
1189 /* special solvable attr handling follows */
1191 case di_nextsolvableattr:
1192 di->kv.id = *di->idp++;
1197 di->state = di_nextsolvablekey;
1201 case di_nextsolvablekey: di_nextsolvablekey:
1202 if (di->keyname || di->key->name == RPM_RPMDBID)
1203 goto di_enterrepodata;
1207 case di_entersolvablekey: di_entersolvablekey:
1208 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1209 if (!di->idp || !di->idp[0])
1210 goto di_nextsolvablekey;
1211 di->kv.id = di->idp[0];
1212 di->kv.num = di->idp[0];
1213 if (!di->kv.eof && !di->idp[1])
1217 di->state = di_nextsolvablekey;
1219 di->state = di_nextsolvableattr;
1223 if (di->matcher.match)
1224 if (!datamatcher_match(&di->matcher, di->data, di->key, &di->kv))
1226 /* found something! */
1232 dataiterator_entersub(Dataiterator *di)
1234 if (di->state == di_nextarrayelement)
1235 di->state = di_entersub;
1239 dataiterator_setpos(Dataiterator *di)
1243 memset(&di->pool->pos, 0, sizeof(di->pool->pos));
1246 di->pool->pos.repo = di->repo;
1247 di->pool->pos.repodataid = di->data - di->repo->repodata;
1248 di->pool->pos.schema = di->kv.id;
1249 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1253 dataiterator_setpos_parent(Dataiterator *di)
1257 memset(&di->pool->pos, 0, sizeof(di->pool->pos));
1260 di->pool->pos.repo = di->repo;
1261 di->pool->pos.repodataid = di->data - di->repo->repodata;
1262 di->pool->pos.schema = di->kv.parent->id;
1263 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1267 dataiterator_skip_attribute(Dataiterator *di)
1269 if (di->state == di_nextsolvableattr)
1270 di->state = di_nextsolvablekey;
1272 di->state = di_nextkey;
1276 dataiterator_skip_solvable(Dataiterator *di)
1278 di->state = di_nextsolvable;
1282 dataiterator_skip_repo(Dataiterator *di)
1284 di->state = di_nextrepo;
1288 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1292 di->solvid = s - di->pool->solvables;
1293 di->state = di_entersolvable;
1297 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1301 di->state = di_enterrepo;
1305 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1307 Datamatcher matcher = di->matcher;
1308 matcher.flags = flags;
1309 matcher.match = (void *)vmatch;
1310 matcher.pool = di->pool;
1311 return datamatcher_match(&matcher, di->data, di->key, &di->kv);
1315 /************************************************************************
1316 * data modify functions
1319 /* extend repodata so that it includes solvables p */
1321 repodata_extend(Repodata *data, Id p)
1323 if (data->start == data->end)
1324 data->start = data->end = p;
1327 int old = data->end - data->start;
1328 int new = p - data->end + 1;
1331 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1332 memset(data->attrs + old, 0, new * sizeof(Id *));
1334 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1335 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1338 if (p < data->start)
1340 int old = data->end - data->start;
1341 int new = data->start - p;
1344 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1345 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1346 memset(data->attrs, 0, new * sizeof(Id *));
1348 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1349 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1350 memset(data->incoreoffset, 0, new * sizeof(Id));
1356 repodata_extend_block(Repodata *data, Id start, Id num)
1360 if (!data->incoreoffset)
1362 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1363 data->start = start;
1364 data->end = start + num;
1367 repodata_extend(data, start);
1369 repodata_extend(data, start + num - 1);
1372 /**********************************************************************/
1374 #define REPODATA_ATTRS_BLOCK 63
1375 #define REPODATA_ATTRDATA_BLOCK 1023
1376 #define REPODATA_ATTRIDDATA_BLOCK 63
1380 repodata_new_handle(Repodata *data)
1384 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1387 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1388 data->xattrs[data->nxattrs] = 0;
1389 return -(data->nxattrs++);
1393 repodata_get_attrp(Repodata *data, Id handle)
1395 if (handle == SOLVID_META)
1399 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1404 return data->xattrs - handle;
1405 if (handle < data->start || handle >= data->end)
1406 repodata_extend(data, handle);
1408 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1409 return data->attrs + (handle - data->start);
1413 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1419 app = repodata_get_attrp(data, handle);
1424 for (pp = ap; *pp; pp += 2)
1425 /* Determine equality based on the name only, allows us to change
1426 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1427 if (data->keys[*pp].name == data->keys[keyid].name)
1440 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1450 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1454 keyid = repodata_key2id(data, key, 1);
1455 repodata_insert_keyid(data, solvid, keyid, val, 1);
1459 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1463 key.type = REPOKEY_TYPE_ID;
1465 key.storage = KEY_STORAGE_INCORE;
1466 repodata_set(data, solvid, &key, id);
1470 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1474 key.type = REPOKEY_TYPE_NUM;
1476 key.storage = KEY_STORAGE_INCORE;
1477 repodata_set(data, solvid, &key, (Id)num);
1481 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1485 if (data->localpool)
1486 id = stringpool_str2id(&data->spool, str, 1);
1488 id = str2id(data->repo->pool, str, 1);
1490 key.type = REPOKEY_TYPE_ID;
1492 key.storage = KEY_STORAGE_INCORE;
1493 repodata_set(data, solvid, &key, id);
1497 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1501 key.type = REPOKEY_TYPE_CONSTANT;
1502 key.size = constant;
1503 key.storage = KEY_STORAGE_INCORE;
1504 repodata_set(data, solvid, &key, 0);
1508 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1512 key.type = REPOKEY_TYPE_CONSTANTID;
1514 key.storage = KEY_STORAGE_INCORE;
1515 repodata_set(data, solvid, &key, 0);
1519 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1523 key.type = REPOKEY_TYPE_VOID;
1525 key.storage = KEY_STORAGE_INCORE;
1526 repodata_set(data, solvid, &key, 0);
1530 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1535 l = strlen(str) + 1;
1537 key.type = REPOKEY_TYPE_STR;
1539 key.storage = KEY_STORAGE_INCORE;
1540 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1541 memcpy(data->attrdata + data->attrdatalen, str, l);
1542 repodata_set(data, solvid, &key, data->attrdatalen);
1543 data->attrdatalen += l;
1547 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1550 Id *ida, *pp, **ppp;
1552 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1554 /* great! just append the new data */
1555 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1556 data->attriddatalen--; /* overwrite terminating 0 */
1557 data->lastdatalen += entrysize;
1560 ppp = repodata_get_attrp(data, handle);
1563 for (; *pp; pp += 2)
1564 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1568 /* not found. allocate new key */
1573 key.storage = KEY_STORAGE_INCORE;
1574 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1575 repodata_set(data, handle, &key, data->attriddatalen);
1576 data->lasthandle = 0; /* next time... */
1580 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1581 oldsize += entrysize;
1582 if (ida + 1 == data->attriddata + data->attriddatalen)
1584 /* this was the last entry, just append it */
1585 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1586 data->attriddatalen--; /* overwrite terminating 0 */
1590 /* too bad. move to back. */
1591 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1592 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1593 pp[1] = data->attriddatalen;
1594 data->attriddatalen += oldsize;
1596 data->lasthandle = handle;
1597 data->lastkey = *pp;
1598 data->lastdatalen = data->attriddatalen + entrysize + 1;
1602 checksumtype2len(Id type)
1606 case REPOKEY_TYPE_MD5:
1608 case REPOKEY_TYPE_SHA1:
1610 case REPOKEY_TYPE_SHA256:
1611 return SIZEOF_SHA256;
1618 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1619 const unsigned char *str)
1622 int l = checksumtype2len(type);
1629 key.storage = KEY_STORAGE_INCORE;
1630 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1631 memcpy(data->attrdata + data->attrdatalen, str, l);
1632 repodata_set(data, solvid, &key, data->attrdatalen);
1633 data->attrdatalen += l;
1637 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1640 for (i = 0; i < buflen; i++)
1642 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1643 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
1644 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
1655 buf[i] = (buf[i] << 4) | v;
1662 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1665 unsigned char buf[64];
1666 int l = checksumtype2len(type);
1670 if (hexstr2bytes(buf, str, l) != l)
1672 fprintf(stderr, "Invalid hex character in '%s'\n", str);
1675 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
1679 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1684 l = checksumtype2len(type);
1687 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1688 for (i = 0; i < l; i++)
1690 unsigned char v = buf[i];
1691 unsigned char w = v >> 4;
1692 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1694 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1701 repodata_globalize_id(Repodata *data, Id id)
1703 if (!data || !data->localpool)
1705 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
1709 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
1713 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
1715 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
1716 data->attriddata[data->attriddatalen++] = dir;
1717 data->attriddata[data->attriddatalen++] = num;
1718 data->attriddata[data->attriddatalen++] = num2;
1719 data->attriddata[data->attriddatalen++] = 0;
1723 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
1729 l = strlen(str) + 1;
1730 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1731 memcpy(data->attrdata + data->attrdatalen, str, l);
1732 stroff = data->attrdatalen;
1733 data->attrdatalen += l;
1736 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
1738 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
1739 data->attriddata[data->attriddatalen++] = dir;
1740 data->attriddata[data->attriddatalen++] = stroff;
1741 data->attriddata[data->attriddatalen++] = 0;
1745 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
1748 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
1750 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
1751 data->attriddata[data->attriddatalen++] = id;
1752 data->attriddata[data->attriddatalen++] = 0;
1756 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
1760 if (data->localpool)
1761 id = stringpool_str2id(&data->spool, str, 1);
1763 id = str2id(data->repo->pool, str, 1);
1764 repodata_add_idarray(data, solvid, keyname, id);
1768 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
1770 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
1771 data->attriddata[data->attriddatalen++] = ghandle;
1772 data->attriddata[data->attriddatalen++] = 0;
1776 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
1778 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
1779 data->attriddata[data->attriddatalen++] = ghandle;
1780 data->attriddata[data->attriddatalen++] = 0;
1784 repodata_merge_attrs(Repodata *data, Id dest, Id src)
1787 if (dest == src || !(keyp = data->attrs[src]))
1789 for (; *keyp; keyp += 2)
1790 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
1796 /**********************************************************************/
1798 /* unify with repo_write! */
1800 #define EXTDATA_BLOCK 1023
1808 data_addid(struct extdata *xd, Id x)
1811 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
1812 dp = xd->buf + xd->len;
1817 *dp++ = (x >> 28) | 128;
1819 *dp++ = (x >> 21) | 128;
1820 *dp++ = (x >> 14) | 128;
1823 *dp++ = (x >> 7) | 128;
1825 xd->len = dp - xd->buf;
1829 data_addideof(struct extdata *xd, Id x, int eof)
1832 x = (x & 63) | ((x & ~63) << 1);
1833 data_addid(xd, (eof ? x: x | 64));
1837 data_addblob(struct extdata *xd, unsigned char *blob, int len)
1839 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
1840 memcpy(xd->buf + xd->len, blob, len);
1844 /*********************************/
1847 repodata_serialize_key(Repodata *data, struct extdata *newincore,
1848 struct extdata *newvincore,
1850 Repokey *key, Id val)
1852 /* Otherwise we have a new value. Parse it into the internal
1856 unsigned int oldvincorelen = 0;
1860 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1863 oldvincorelen = xd->len;
1867 case REPOKEY_TYPE_VOID:
1868 case REPOKEY_TYPE_CONSTANT:
1869 case REPOKEY_TYPE_CONSTANTID:
1871 case REPOKEY_TYPE_STR:
1872 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
1874 case REPOKEY_TYPE_MD5:
1875 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
1877 case REPOKEY_TYPE_SHA1:
1878 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
1880 case REPOKEY_TYPE_SHA256:
1881 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
1883 case REPOKEY_TYPE_ID:
1884 case REPOKEY_TYPE_NUM:
1885 case REPOKEY_TYPE_DIR:
1886 data_addid(xd, val);
1888 case REPOKEY_TYPE_IDARRAY:
1889 for (ida = data->attriddata + val; *ida; ida++)
1890 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
1892 case REPOKEY_TYPE_DIRNUMNUMARRAY:
1893 for (ida = data->attriddata + val; *ida; ida += 3)
1895 data_addid(xd, ida[0]);
1896 data_addid(xd, ida[1]);
1897 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
1900 case REPOKEY_TYPE_DIRSTRARRAY:
1901 for (ida = data->attriddata + val; *ida; ida += 2)
1903 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
1904 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
1907 case REPOKEY_TYPE_FIXARRAY:
1911 for (ida = data->attriddata + val; *ida; ida++)
1914 fprintf(stderr, "serialize struct %d\n", *ida);
1917 Id *kp = data->xattrs[-*ida];
1924 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
1930 schemaid = repodata_schema2id(data, schema, 1);
1931 else if (schemaid != repodata_schema2id(data, schema, 0))
1933 fprintf(stderr, " not yet implemented: substructs with different schemas\n");
1937 fprintf(stderr, " schema %d\n", schemaid);
1942 data_addid(xd, num);
1943 data_addid(xd, schemaid);
1944 for (ida = data->attriddata + val; *ida; ida++)
1946 Id *kp = data->xattrs[-*ida];
1951 repodata_serialize_key(data, newincore, newvincore,
1952 schema, data->keys + *kp, kp[1]);
1957 case REPOKEY_TYPE_FLEXARRAY:
1960 for (ida = data->attriddata + val; *ida; ida++)
1962 data_addid(xd, num);
1963 for (ida = data->attriddata + val; *ida; ida++)
1965 Id *kp = data->xattrs[-*ida];
1968 data_addid(xd, 0); /* XXX */
1975 schemaid = repodata_schema2id(data, schema, 1);
1976 data_addid(xd, schemaid);
1977 kp = data->xattrs[-*ida];
1980 repodata_serialize_key(data, newincore, newvincore,
1981 schema, data->keys + *kp, kp[1]);
1987 fprintf(stderr, "don't know how to handle type %d\n", key->type);
1990 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1992 /* put offset/len in incore */
1993 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
1994 oldvincorelen = xd->len - oldvincorelen;
1995 data_addid(newincore, oldvincorelen);
2000 repodata_internalize(Repodata *data)
2002 Repokey *key, solvkey;
2004 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2005 unsigned char *dp, *ndp;
2006 int newschema, oldcount;
2007 struct extdata newincore;
2008 struct extdata newvincore;
2011 if (!data->attrs && !data->xattrs)
2014 newvincore.buf = data->vincore;
2015 newvincore.len = data->vincorelen;
2017 /* find the solvables key, create if needed */
2018 memset(&solvkey, 0, sizeof(solvkey));
2019 solvkey.name = REPOSITORY_SOLVABLES;
2020 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2022 solvkey.storage = KEY_STORAGE_INCORE;
2023 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2025 schema = sat_malloc2(data->nkeys, sizeof(Id));
2026 seen = sat_malloc2(data->nkeys, sizeof(Id));
2028 /* Merge the data already existing (in data->schemata, ->incoredata and
2029 friends) with the new attributes in data->attrs[]. */
2030 nentry = data->end - data->start;
2031 memset(&newincore, 0, sizeof(newincore));
2032 data_addid(&newincore, 0); /* start data at offset 1 */
2034 data->mainschema = 0;
2035 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2037 /* join entry data */
2038 /* we start with the meta data, entry -1 */
2039 for (entry = -1; entry < nentry; entry++)
2041 memset(seen, 0, data->nkeys * sizeof(Id));
2043 dp = data->incoredata;
2046 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2047 dp = data_read_id(dp, &oldschema);
2050 fprintf(stderr, "oldschema %d\n", oldschema);
2051 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2052 fprintf(stderr, "schemadata %p\n", data->schemadata);
2054 /* seen: -1: old data 0: skipped >0: id + 1 */
2058 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2062 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
2070 keyp = data->attrs ? data->attrs[entry] : 0;
2073 /* strip solvables key */
2075 for (sp = keyp = schema; *sp; sp++)
2076 if (*sp != solvkeyid)
2081 seen[solvkeyid] = 0;
2082 keyp = data->xattrs ? data->xattrs[1] : 0;
2085 for (; *keyp; keyp += 2)
2092 seen[*keyp] = keyp[1] + 1;
2094 if (entry < 0 && data->end != data->start)
2101 /* Ideally we'd like to sort the new schema here, to ensure
2102 schema equality independend of the ordering. We can't do that
2103 yet. For once see below (old ids need to come before new ids).
2104 An additional difficulty is that we also need to move
2105 the values with the keys. */
2106 schemaid = repodata_schema2id(data, schema, 1);
2108 schemaid = oldschema;
2111 /* Now create data blob. We walk through the (possibly new) schema
2112 and either copy over old data, or insert the new. */
2113 /* XXX Here we rely on the fact that the (new) schema has the form
2114 o1 o2 o3 o4 ... | n1 n2 n3 ...
2115 (oX being the old keyids (possibly overwritten), and nX being
2116 the new keyids). This rules out sorting the keyids in order
2117 to ensure a small schema count. */
2119 data->incoreoffset[entry] = newincore.len;
2120 data_addid(&newincore, schemaid);
2123 data->mainschema = schemaid;
2124 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2126 keypstart = data->schemadata + data->schemata[schemaid];
2127 for (keyp = keypstart; *keyp; keyp++)
2130 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2131 if (*keyp == solvkeyid)
2133 /* add flexarray entry count */
2134 data_addid(&newincore, data->end - data->start);
2137 key = data->keys + *keyp;
2139 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2144 /* Skip the data associated with this old key. */
2145 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2147 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2148 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2150 else if (key->storage == KEY_STORAGE_INCORE)
2151 ndp = data_skip_key(data, dp, key);
2154 if (seen[*keyp] == -1)
2156 /* If this key was an old one _and_ was not overwritten with
2157 a different value copy over the old value (we skipped it
2160 data_addblob(&newincore, dp, ndp - dp);
2163 else if (seen[*keyp])
2165 /* Otherwise we have a new value. Parse it into the internal
2167 repodata_serialize_key(data, &newincore, &newvincore,
2168 schema, key, seen[*keyp] - 1);
2172 if (entry >= 0 && data->attrs && data->attrs[entry])
2173 data->attrs[entry] = sat_free(data->attrs[entry]);
2175 /* free all xattrs */
2176 for (entry = 0; entry < data->nxattrs; entry++)
2177 if (data->xattrs[entry])
2178 sat_free(data->xattrs[entry]);
2179 data->xattrs = sat_free(data->xattrs);
2182 data->lasthandle = 0;
2184 data->lastdatalen = 0;
2187 repodata_free_schemahash(data);
2189 sat_free(data->incoredata);
2190 data->incoredata = newincore.buf;
2191 data->incoredatalen = newincore.len;
2192 data->incoredatafree = 0;
2194 sat_free(data->vincore);
2195 data->vincore = newvincore.buf;
2196 data->vincorelen = newvincore.len;
2198 data->attrs = sat_free(data->attrs);
2199 data->attrdata = sat_free(data->attrdata);
2200 data->attriddata = sat_free(data->attriddata);
2201 data->attrdatalen = 0;
2202 data->attriddatalen = 0;
2206 repodata_disable_paging(Repodata *data)
2208 if (maybe_load_repodata(data, 0))
2209 repopagestore_disable_paging(&data->store);
2213 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: