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
13 * a repository can contain multiple repodata entries, consisting of
14 * different sets of keys and different sets of solvables
29 #include "poolid_private.h"
35 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
36 unsigned char *out, unsigned int out_len);
37 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
40 unsigned int out_len);
42 #define REPODATA_BLOCK 255
46 repodata_init(Repodata *data, Repo *repo, int localpool)
48 memset(data, 0, sizeof (*data));
50 data->localpool = localpool;
52 stringpool_init_empty(&data->spool);
53 data->keys = sat_calloc(1, sizeof(Repokey));
55 data->schemata = sat_calloc(1, sizeof(Id));
56 data->schemadata = sat_calloc(1, sizeof(Id));
58 data->schemadatalen = 1;
59 repopagestore_init(&data->store);
63 repodata_free(Repodata *data)
69 sat_free(data->schemata);
70 sat_free(data->schemadata);
71 sat_free(data->schematahash);
73 stringpool_free(&data->spool);
74 dirpool_free(&data->dirpool);
76 sat_free(data->mainschemaoffsets);
77 sat_free(data->incoredata);
78 sat_free(data->incoreoffset);
79 sat_free(data->verticaloffset);
81 repopagestore_free(&data->store);
83 sat_free(data->vincore);
86 for (i = 0; i < data->end - data->start; i++)
87 sat_free(data->attrs[i]);
88 sat_free(data->attrs);
90 for (i = 0; i < data->nxattrs; i++)
91 sat_free(data->xattrs[i]);
92 sat_free(data->xattrs);
94 sat_free(data->attrdata);
95 sat_free(data->attriddata);
99 /***************************************************************
100 * key pool management
103 /* this is not so time critical that we need a hash, so we do a simple
106 repodata_key2id(Repodata *data, Repokey *key, int create)
110 for (keyid = 1; keyid < data->nkeys; keyid++)
111 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
113 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
117 if (keyid == data->nkeys)
121 /* allocate new key */
122 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
123 data->keys[data->nkeys++] = *key;
124 if (data->verticaloffset)
126 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
127 data->verticaloffset[data->nkeys - 1] = 0;
129 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
135 /***************************************************************
136 * schema pool management
139 #define SCHEMATA_BLOCK 31
140 #define SCHEMATADATA_BLOCK 255
143 repodata_schema2id(Repodata *data, Id *schema, int create)
149 if ((schematahash = data->schematahash) == 0)
151 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
152 for (i = 0; i < data->nschemata; i++)
154 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
157 schematahash[h] = i + 1;
159 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
160 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
163 for (sp = schema, len = 0, h = 0; *sp; len++)
168 cid = schematahash[h];
172 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
175 for (cid = 0; cid < data->nschemata; cid++)
176 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
182 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
183 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
185 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
186 data->schemata[data->nschemata] = data->schemadatalen;
187 data->schemadatalen += len;
188 schematahash[h] = data->nschemata + 1;
190 fprintf(stderr, "schema2id: new schema\n");
192 return data->nschemata++;
196 repodata_free_schemahash(Repodata *data)
198 data->schematahash = sat_free(data->schematahash);
200 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
201 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
205 /***************************************************************
206 * dir pool management
210 repodata_str2dir(Repodata *data, const char *dir, int create)
216 while (*dir == '/' && dir[1] == '/')
218 if (*dir == '/' && !dir[1])
222 dire = strchrnul(dir, '/');
224 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
226 id = strn2id(data->repo->pool, dir, dire - dir, create);
229 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
242 repodata_dir2str(Repodata *data, Id did, const char *suf)
244 Pool *pool = data->repo->pool;
251 return suf ? suf : "";
255 comp = dirpool_compid(&data->dirpool, parent);
256 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
258 parent = dirpool_parent(&data->dirpool, parent);
263 l += strlen(suf) + 1;
264 p = pool_alloctmpspace(pool, l + 1) + l;
275 comp = dirpool_compid(&data->dirpool, parent);
276 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
279 strncpy(p, comps, l);
280 parent = dirpool_parent(&data->dirpool, parent);
288 /***************************************************************
292 static inline unsigned char *
293 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
295 Id *keyp = data->schemadata + data->schemata[schema];
296 for (; *keyp; keyp++)
297 dp = data_skip_key(data, dp, data->keys + *keyp);
302 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
304 int nentries, schema;
307 case REPOKEY_TYPE_FIXARRAY:
308 dp = data_read_id(dp, &nentries);
311 dp = data_read_id(dp, &schema);
313 dp = data_skip_schema(data, dp, schema);
315 case REPOKEY_TYPE_FLEXARRAY:
316 dp = data_read_id(dp, &nentries);
319 dp = data_read_id(dp, &schema);
320 dp = data_skip_schema(data, dp, schema);
324 if (key->storage == KEY_STORAGE_INCORE)
325 dp = data_skip(dp, key->type);
326 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
328 dp = data_skip(dp, REPOKEY_TYPE_ID);
329 dp = data_skip(dp, REPOKEY_TYPE_ID);
335 static unsigned char *
336 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
342 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
345 for (i = 0; (k = *keyp++) != 0; i++)
347 return data->incoredata + data->mainschemaoffsets[i];
350 while ((k = *keyp++) != 0)
354 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
356 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
357 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
360 if (data->keys[k].storage != KEY_STORAGE_INCORE)
362 dp = data_skip_key(data, dp, data->keys + k);
367 static unsigned char *
368 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
373 if (off >= data->lastverticaloffset)
375 off -= data->lastverticaloffset;
376 if (off + len > data->vincorelen)
378 return data->vincore + off;
380 if (off + len > key->size)
382 /* we now have the offset, go into vertical */
383 off += data->verticaloffset[key - data->keys];
384 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
385 dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
387 dp += off % BLOB_PAGESIZE;
391 static inline unsigned char *
392 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
394 unsigned char *dp = *dpp;
398 if (key->storage == KEY_STORAGE_INCORE)
401 *dpp = data_skip_key(data, dp, key);
404 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
407 dp = data_read_id(dp, &off);
408 dp = data_read_id(dp, &len);
411 return get_vertical_data(data, key, off, len);
417 load_repodata(Repodata *data)
419 if (data->loadcallback)
421 data->loadcallback(data);
422 if (data->state == REPODATA_AVAILABLE)
425 data->state = REPODATA_ERROR;
430 maybe_load_repodata(Repodata *data, Id keyname)
432 if (keyname && !repodata_precheck_keyname(data, keyname))
433 return 0; /* do not bother... */
440 for (i = 0; i < data->nkeys; i++)
441 if (keyname == data->keys[i].name)
443 if (i == data->nkeys)
446 return load_repodata(data);
449 case REPODATA_AVAILABLE:
452 data->state = REPODATA_ERROR;
457 static inline unsigned char *
458 solvid2data(Repodata *data, Id solvid, Id *schemap)
460 unsigned char *dp = data->incoredata;
463 if (solvid == SOLVID_META) /* META */
465 else if (solvid == SOLVID_POS) /* META */
467 Pool *pool = data->repo->pool;
468 if (data->repo != pool->pos.repo)
470 if (data != data->repo->repodata + pool->pos.repodataid)
472 *schemap = pool->pos.schema;
473 return data->incoredata + pool->pos.dp;
477 if (solvid < data->start || solvid >= data->end)
479 dp += data->incoreoffset[solvid - data->start];
481 return data_read_id(dp, schemap);
484 /************************************************************************
488 static inline unsigned char *
489 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
492 Id schema, *keyp, *kp;
495 if (!maybe_load_repodata(data, keyname))
497 dp = solvid2data(data, solvid, &schema);
500 keyp = data->schemadata + data->schemata[schema];
501 for (kp = keyp; *kp; kp++)
502 if (data->keys[*kp].name == keyname)
506 *keypp = key = data->keys + *kp;
507 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
508 return dp; /* no need to forward... */
509 dp = forward_to_key(data, *kp, keyp, dp);
512 return get_data(data, key, &dp, 0);
517 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
523 dp = find_key_data(data, solvid, keyname, &key);
526 if (key->type == REPOKEY_TYPE_CONSTANTID)
528 if (key->type != REPOKEY_TYPE_ID)
530 dp = data_read_id(dp, &id);
535 repodata_globalize_id(Repodata *data, Id id, int create)
537 if (!id || !data || !data->localpool)
539 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
543 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
549 dp = find_key_data(data, solvid, keyname, &key);
552 if (key->type == REPOKEY_TYPE_STR)
553 return (const char *)dp;
554 if (key->type == REPOKEY_TYPE_CONSTANTID)
555 return id2str(data->repo->pool, key->size);
556 if (key->type == REPOKEY_TYPE_ID)
557 dp = data_read_id(dp, &id);
561 return data->spool.stringspace + data->spool.strings[id];
562 return id2str(data->repo->pool, id);
566 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
573 dp = find_key_data(data, solvid, keyname, &key);
576 if (key->type == REPOKEY_TYPE_NUM
577 || key->type == REPOKEY_TYPE_U32
578 || key->type == REPOKEY_TYPE_CONSTANT)
580 dp = data_fetch(dp, &kv, key);
588 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
594 if (!maybe_load_repodata(data, keyname))
596 dp = solvid2data(data, solvid, &schema);
599 /* can't use find_key_data as we need to test the type */
600 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
601 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
606 const unsigned char *
607 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
612 dp = find_key_data(data, solvid, keyname, &key);
620 /************************************************************************
626 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
630 case REPOKEY_TYPE_ID:
631 case REPOKEY_TYPE_CONSTANTID:
632 case REPOKEY_TYPE_IDARRAY:
633 if (data && data->localpool)
634 kv->str = stringpool_id2str(&data->spool, kv->id);
636 kv->str = id2str(pool, kv->id);
637 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
640 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
642 if (*s == ':' && s > kv->str)
646 case REPOKEY_TYPE_STR:
648 case REPOKEY_TYPE_DIRSTRARRAY:
649 if (!(flags & SEARCH_FILES))
650 return 1; /* match just the basename */
651 /* Put the full filename into kv->str. */
652 kv->str = repodata_dir2str(data, kv->id, kv->str);
653 /* And to compensate for that put the "empty" directory into
654 kv->id, so that later calls to repodata_dir2str on this data
655 come up with the same filename again. */
664 struct subschema_data {
670 /* search a specific repodata */
672 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
676 Id keyid, *kp, *keyp;
677 unsigned char *dp, *ddp;
683 if (!maybe_load_repodata(data, keyname))
685 if (solvid == SOLVID_SUBSCHEMA)
687 struct subschema_data *subd = cbdata;
688 cbdata = subd->cbdata;
690 schema = subd->parent->id;
691 dp = (unsigned char *)subd->parent->str;
692 kv.parent = subd->parent;
697 dp = solvid2data(data, solvid, &schema);
700 s = data->repo->pool->solvables + solvid;
703 keyp = data->schemadata + data->schemata[schema];
706 /* search for a specific key */
707 for (kp = keyp; *kp; kp++)
708 if (data->keys[*kp].name == keyname)
712 dp = forward_to_key(data, *kp, keyp, dp);
718 while ((keyid = *keyp++) != 0)
721 key = data->keys + keyid;
722 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
724 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
726 struct subschema_data subd;
730 subd.cbdata = cbdata;
733 ddp = data_read_id(ddp, &nentries);
737 while (ddp && nentries > 0)
741 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
742 ddp = data_read_id(ddp, &schema);
744 kv.str = (char *)ddp;
745 stop = callback(cbdata, s, data, key, &kv);
746 if (stop > SEARCH_NEXT_KEY)
748 if (stop && stop != SEARCH_ENTERSUB)
750 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
751 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
752 ddp = data_skip_schema(data, ddp, schema);
755 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
759 kv.str = (char *)ddp;
760 stop = callback(cbdata, s, data, key, &kv);
761 if (stop > SEARCH_NEXT_KEY)
771 ddp = data_fetch(ddp, &kv, key);
774 stop = callback(cbdata, s, data, key, &kv);
777 while (!kv.eof && !stop);
778 if (onekey || stop > SEARCH_NEXT_KEY)
784 repodata_setpos_kv(Repodata *data, KeyValue *kv)
786 Pool *pool = data->repo->pool;
788 pool_clear_pos(pool);
791 pool->pos.repo = data->repo;
792 pool->pos.repodataid = data - data->repo->repodata;
793 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
794 pool->pos.schema = kv->id;
798 /************************************************************************
799 * data iterator functions
802 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
803 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
804 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
805 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
806 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
807 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
808 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
809 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
810 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
811 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
812 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
813 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
814 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
815 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
819 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
833 case SOLVABLE_VENDOR:
836 case SOLVABLE_PROVIDES:
838 return s->provides ? s->repo->idarraydata + s->provides : 0;
839 case SOLVABLE_OBSOLETES:
841 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
842 case SOLVABLE_CONFLICTS:
844 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
845 case SOLVABLE_REQUIRES:
847 return s->requires ? s->repo->idarraydata + s->requires : 0;
848 case SOLVABLE_RECOMMENDS:
850 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
851 case SOLVABLE_SUPPLEMENTS:
853 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
854 case SOLVABLE_SUGGESTS:
856 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
857 case SOLVABLE_ENHANCES:
859 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
862 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
869 datamatcher_init(Datamatcher *ma, const char *match, int flags)
875 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
877 ma->matchdata = sat_calloc(1, sizeof(regex_t));
878 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
881 sat_free(ma->matchdata);
882 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
889 datamatcher_free(Datamatcher *ma)
891 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
893 regfree(ma->matchdata);
894 ma->matchdata = sat_free(ma->matchdata);
899 datamatcher_match(Datamatcher *ma, const char *str)
901 switch ((ma->flags & SEARCH_STRINGMASK))
903 case SEARCH_SUBSTRING:
904 if (ma->flags & SEARCH_NOCASE)
906 if (!strcasestr(str, ma->match))
911 if (!strstr(str, ma->match))
916 if (ma->flags & SEARCH_NOCASE)
918 if (strcasecmp(ma->match, str))
923 if (strcmp(ma->match, str))
928 if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
932 if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
967 /* see repo.h for documentation */
969 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
971 memset(di, 0, sizeof(*di));
973 di->flags = flags & ~SEARCH_THISSOLVID;
974 if (!pool || (repo && repo->pool != pool))
982 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
988 di->keyname = keyname;
989 di->keynames[0] = keyname;
990 dataiterator_set_search(di, repo, p);
995 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
998 memset(&di->matcher, 0, sizeof(di->matcher));
999 if (from->matcher.match)
1000 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1005 for (i = 1; i < di->nparents; i++)
1006 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1007 di->kv.parent = &di->parents[di->nparents - 1].kv;
1012 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1014 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1015 datamatcher_free(&di->matcher);
1016 memset(&di->matcher, 0, sizeof(di->matcher));
1020 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1030 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1034 di->flags &= ~SEARCH_THISSOLVID;
1038 if (!di->pool->nrepos)
1046 di->repo = di->pool->repos[0];
1048 di->state = di_enterrepo;
1050 dataiterator_jump_to_solvid(di, p);
1054 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1057 di->keyname = keyname;
1058 di->keynames[0] = keyname;
1062 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1066 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1068 di->state = di_bye; /* sorry */
1071 for (i = di->nkeynames + 1; i > 0; i--)
1072 di->keynames[i] = di->keynames[i - 1];
1073 di->keynames[0] = di->keyname = keyname;
1078 dataiterator_free(Dataiterator *di)
1080 if (di->matcher.match)
1081 datamatcher_free(&di->matcher);
1084 static inline unsigned char *
1085 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1087 Id *keyp = di->keyp;
1088 Repokey *keys = di->data->keys;
1091 for (keyp = di->keyp; *keyp; keyp++)
1092 if (keys[*keyp].name == keyname)
1096 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1104 dataiterator_step(Dataiterator *di)
1112 case di_enterrepo: di_enterrepo:
1115 if (!(di->flags & SEARCH_THISSOLVID))
1117 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1118 goto di_nextsolvable;
1122 case di_entersolvable: di_entersolvable:
1123 if (di->repodataid >= 0)
1125 di->repodataid = 0; /* reset repodata iterator */
1126 if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
1128 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1130 goto di_entersolvablekey;
1135 case di_enterrepodata: di_enterrepodata:
1136 if (di->repodataid >= 0)
1138 if (di->repodataid >= di->repo->nrepodata)
1139 goto di_nextsolvable;
1140 di->data = di->repo->repodata + di->repodataid;
1142 if (!maybe_load_repodata(di->data, di->keyname))
1143 goto di_nextrepodata;
1144 di->dp = solvid2data(di->data, di->solvid, &schema);
1146 goto di_nextrepodata;
1147 if (di->solvid == SOLVID_POS)
1148 di->solvid = di->pool->pos.solvid;
1149 /* reset key iterator */
1150 di->keyp = di->data->schemadata + di->data->schemata[schema];
1153 case di_enterschema: di_enterschema:
1155 di->dp = dataiterator_find_keyname(di, di->keyname);
1156 if (!di->dp || !*di->keyp)
1160 goto di_nextrepodata;
1164 case di_enterkey: di_enterkey:
1166 di->key = di->data->keys + *di->keyp;
1167 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1170 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1172 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1178 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1180 di->state = di_nextkey;
1182 di->state = di_nextattr;
1185 case di_nextkey: di_nextkey:
1186 if (!di->keyname && *++di->keyp)
1192 case di_nextrepodata: di_nextrepodata:
1193 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1194 goto di_enterrepodata;
1197 case di_nextsolvable: di_nextsolvable:
1198 if (!(di->flags & SEARCH_THISSOLVID))
1201 di->solvid = di->repo->start;
1204 for (; di->solvid < di->repo->end; di->solvid++)
1206 if (di->pool->solvables[di->solvid].repo == di->repo)
1207 goto di_entersolvable;
1213 if (di->repoid >= 0)
1216 if (di->repoid < di->pool->nrepos)
1218 di->repo = di->pool->repos[di->repoid];
1224 case di_bye: di_bye:
1228 case di_enterarray: di_enterarray:
1229 if (di->key->name == REPOSITORY_SOLVABLES)
1231 di->ddp = data_read_id(di->ddp, &di->kv.num);
1236 case di_nextarrayelement: di_nextarrayelement:
1239 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1240 if (di->kv.entry == di->kv.num)
1242 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1244 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1246 di->kv.str = (char *)di->ddp;
1248 di->state = di_nextkey;
1251 if (di->kv.entry == di->kv.num - 1)
1253 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1254 di->ddp = data_read_id(di->ddp, &di->kv.id);
1255 di->kv.str = (char *)di->ddp;
1256 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1258 if ((di->flags & SEARCH_SUB) != 0)
1259 di->state = di_entersub;
1261 di->state = di_nextarrayelement;
1264 case di_entersub: di_entersub:
1265 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1266 goto di_nextarrayelement; /* sorry, full */
1267 di->parents[di->nparents].kv = di->kv;
1268 di->parents[di->nparents].dp = di->dp;
1269 di->parents[di->nparents].keyp = di->keyp;
1270 di->dp = (unsigned char *)di->kv.str;
1271 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1272 memset(&di->kv, 0, sizeof(di->kv));
1273 di->kv.parent = &di->parents[di->nparents].kv;
1275 di->keyname = di->keynames[di->nparents - di->rootlevel];
1276 goto di_enterschema;
1278 case di_leavesub: di_leavesub:
1279 if (di->nparents - 1 < di->rootlevel)
1282 di->dp = di->parents[di->nparents].dp;
1283 di->kv = di->parents[di->nparents].kv;
1284 di->keyp = di->parents[di->nparents].keyp;
1285 di->key = di->data->keys + *di->keyp;
1286 di->ddp = (unsigned char *)di->kv.str;
1287 di->keyname = di->keynames[di->nparents - di->rootlevel];
1288 goto di_nextarrayelement;
1290 /* special solvable attr handling follows */
1292 case di_nextsolvableattr:
1293 di->kv.id = *di->idp++;
1298 di->state = di_nextsolvablekey;
1302 case di_nextsolvablekey: di_nextsolvablekey:
1303 if (di->keyname || di->key->name == RPM_RPMDBID)
1304 goto di_enterrepodata;
1308 case di_entersolvablekey: di_entersolvablekey:
1309 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1310 if (!di->idp || !di->idp[0])
1311 goto di_nextsolvablekey;
1312 di->kv.id = di->idp[0];
1313 di->kv.num = di->idp[0];
1315 if (!di->kv.eof && !di->idp[0])
1319 di->state = di_nextsolvablekey;
1321 di->state = di_nextsolvableattr;
1325 if (di->matcher.match)
1327 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1329 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1333 if (!datamatcher_match(&di->matcher, di->kv.str))
1336 /* found something! */
1342 dataiterator_entersub(Dataiterator *di)
1344 if (di->state == di_nextarrayelement)
1345 di->state = di_entersub;
1349 dataiterator_setpos(Dataiterator *di)
1351 if (di->kv.eof == 2)
1353 pool_clear_pos(di->pool);
1356 di->pool->pos.solvid = di->solvid;
1357 di->pool->pos.repo = di->repo;
1358 di->pool->pos.repodataid = di->data - di->repo->repodata;
1359 di->pool->pos.schema = di->kv.id;
1360 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1364 dataiterator_setpos_parent(Dataiterator *di)
1366 if (!di->kv.parent || di->kv.parent->eof == 2)
1368 pool_clear_pos(di->pool);
1371 di->pool->pos.solvid = di->solvid;
1372 di->pool->pos.repo = di->repo;
1373 di->pool->pos.repodataid = di->data - di->repo->repodata;
1374 di->pool->pos.schema = di->kv.parent->id;
1375 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1378 /* clones just the position, not the search keys/matcher */
1380 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1382 di->state = from->state;
1383 di->flags &= ~SEARCH_THISSOLVID;
1384 di->flags |= (from->flags & SEARCH_THISSOLVID);
1385 di->repo = from->repo;
1386 di->data = from->data;
1388 di->ddp = from->ddp;
1389 di->idp = from->idp;
1390 di->keyp = from->keyp;
1391 di->key = from->key;
1393 di->repodataid = from->repodataid;
1394 di->solvid = from->solvid;
1395 di->repoid = from->repoid;
1396 di->rootlevel = from->rootlevel;
1397 memcpy(di->parents, from->parents, sizeof(from->parents));
1398 di->nparents = from->nparents;
1402 for (i = 1; i < di->nparents; i++)
1403 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1404 di->kv.parent = &di->parents[di->nparents - 1].kv;
1409 dataiterator_seek(Dataiterator *di, int whence)
1411 if ((whence & DI_SEEK_STAY) != 0)
1412 di->rootlevel = di->nparents;
1413 switch (whence & ~DI_SEEK_STAY)
1416 if (di->state != di_nextarrayelement)
1418 if ((whence & DI_SEEK_STAY) != 0)
1419 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1420 di->state = di_entersub;
1422 case DI_SEEK_PARENT:
1429 if (di->rootlevel > di->nparents)
1430 di->rootlevel = di->nparents;
1431 di->dp = di->parents[di->nparents].dp;
1432 di->kv = di->parents[di->nparents].kv;
1433 di->keyp = di->parents[di->nparents].keyp;
1434 di->key = di->data->keys + *di->keyp;
1435 di->ddp = (unsigned char *)di->kv.str;
1436 di->keyname = di->keynames[di->nparents - di->rootlevel];
1437 di->state = di_nextarrayelement;
1439 case DI_SEEK_REWIND:
1445 di->dp = (unsigned char *)di->kv.parent->str;
1446 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1447 di->state = di_enterschema;
1455 dataiterator_skip_attribute(Dataiterator *di)
1457 if (di->state == di_nextsolvableattr)
1458 di->state = di_nextsolvablekey;
1460 di->state = di_nextkey;
1464 dataiterator_skip_solvable(Dataiterator *di)
1466 di->state = di_nextsolvable;
1470 dataiterator_skip_repo(Dataiterator *di)
1472 di->state = di_nextrepo;
1476 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1480 if (solvid == SOLVID_POS)
1482 di->repo = di->pool->pos.repo;
1489 di->data = di->repo->repodata + di->pool->pos.repodataid;
1490 di->repodataid = -1;
1491 di->solvid = solvid;
1492 di->state = di_enterrepo;
1493 di->flags |= SEARCH_THISSOLVID;
1498 di->repo = di->pool->solvables[solvid].repo;
1501 else if (di->repoid >= 0)
1503 if (!di->pool->nrepos)
1508 di->repo = di->pool->repos[0];
1512 di->solvid = solvid;
1514 di->flags |= SEARCH_THISSOLVID;
1515 di->state = di_enterrepo;
1519 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1527 di->flags &= ~SEARCH_THISSOLVID;
1528 di->state = di_enterrepo;
1532 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1534 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1538 return datamatcher_match(ma, di->kv.str);
1541 /************************************************************************
1542 * data modify functions
1545 /* extend repodata so that it includes solvables p */
1547 repodata_extend(Repodata *data, Id p)
1549 if (data->start == data->end)
1550 data->start = data->end = p;
1553 int old = data->end - data->start;
1554 int new = p - data->end + 1;
1557 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1558 memset(data->attrs + old, 0, new * sizeof(Id *));
1560 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1561 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1564 if (p < data->start)
1566 int old = data->end - data->start;
1567 int new = data->start - p;
1570 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1571 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1572 memset(data->attrs, 0, new * sizeof(Id *));
1574 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1575 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1576 memset(data->incoreoffset, 0, new * sizeof(Id));
1581 /* extend repodata so that it includes solvables from start to start + num - 1 */
1583 repodata_extend_block(Repodata *data, Id start, Id num)
1587 if (!data->incoreoffset)
1589 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1590 data->start = start;
1591 data->end = start + num;
1594 repodata_extend(data, start);
1596 repodata_extend(data, start + num - 1);
1599 /**********************************************************************/
1601 #define REPODATA_ATTRS_BLOCK 63
1602 #define REPODATA_ATTRDATA_BLOCK 1023
1603 #define REPODATA_ATTRIDDATA_BLOCK 63
1607 repodata_new_handle(Repodata *data)
1611 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1614 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1615 data->xattrs[data->nxattrs] = 0;
1616 return -(data->nxattrs++);
1620 repodata_get_attrp(Repodata *data, Id handle)
1622 if (handle == SOLVID_META)
1626 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1631 return data->xattrs - handle;
1632 if (handle < data->start || handle >= data->end)
1633 repodata_extend(data, handle);
1635 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1636 return data->attrs + (handle - data->start);
1640 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1646 app = repodata_get_attrp(data, handle);
1651 for (pp = ap; *pp; pp += 2)
1652 /* Determine equality based on the name only, allows us to change
1653 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1654 if (data->keys[*pp].name == data->keys[keyid].name)
1667 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1677 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1681 keyid = repodata_key2id(data, key, 1);
1682 repodata_insert_keyid(data, solvid, keyid, val, 1);
1686 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1690 key.type = REPOKEY_TYPE_ID;
1692 key.storage = KEY_STORAGE_INCORE;
1693 repodata_set(data, solvid, &key, id);
1697 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1701 key.type = REPOKEY_TYPE_NUM;
1703 key.storage = KEY_STORAGE_INCORE;
1704 repodata_set(data, solvid, &key, (Id)num);
1708 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1712 if (data->localpool)
1713 id = stringpool_str2id(&data->spool, str, 1);
1715 id = str2id(data->repo->pool, str, 1);
1717 key.type = REPOKEY_TYPE_ID;
1719 key.storage = KEY_STORAGE_INCORE;
1720 repodata_set(data, solvid, &key, id);
1724 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1728 key.type = REPOKEY_TYPE_CONSTANT;
1729 key.size = constant;
1730 key.storage = KEY_STORAGE_INCORE;
1731 repodata_set(data, solvid, &key, 0);
1735 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1739 key.type = REPOKEY_TYPE_CONSTANTID;
1741 key.storage = KEY_STORAGE_INCORE;
1742 repodata_set(data, solvid, &key, 0);
1746 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1750 key.type = REPOKEY_TYPE_VOID;
1752 key.storage = KEY_STORAGE_INCORE;
1753 repodata_set(data, solvid, &key, 0);
1757 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1762 l = strlen(str) + 1;
1764 key.type = REPOKEY_TYPE_STR;
1766 key.storage = KEY_STORAGE_INCORE;
1767 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1768 memcpy(data->attrdata + data->attrdatalen, str, l);
1769 repodata_set(data, solvid, &key, data->attrdatalen);
1770 data->attrdatalen += l;
1773 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1774 * so that the caller can append the new element there */
1776 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1779 Id *ida, *pp, **ppp;
1781 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1783 /* great! just append the new data */
1784 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1785 data->attriddatalen--; /* overwrite terminating 0 */
1786 data->lastdatalen += entrysize;
1789 ppp = repodata_get_attrp(data, handle);
1792 for (; *pp; pp += 2)
1793 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1797 /* not found. allocate new key */
1802 key.storage = KEY_STORAGE_INCORE;
1803 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1804 repodata_set(data, handle, &key, data->attriddatalen);
1805 data->lasthandle = 0; /* next time... */
1809 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1810 oldsize += entrysize;
1811 if (ida + 1 == data->attriddata + data->attriddatalen)
1813 /* this was the last entry, just append it */
1814 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1815 data->attriddatalen--; /* overwrite terminating 0 */
1819 /* too bad. move to back. */
1820 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1821 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1822 pp[1] = data->attriddatalen;
1823 data->attriddatalen += oldsize;
1825 data->lasthandle = handle;
1826 data->lastkey = *pp;
1827 data->lastdatalen = data->attriddatalen + entrysize + 1;
1831 checksumtype2len(Id type)
1835 case REPOKEY_TYPE_MD5:
1837 case REPOKEY_TYPE_SHA1:
1839 case REPOKEY_TYPE_SHA256:
1840 return SIZEOF_SHA256;
1847 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1848 const unsigned char *str)
1851 int l = checksumtype2len(type);
1858 key.storage = KEY_STORAGE_INCORE;
1859 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1860 memcpy(data->attrdata + data->attrdatalen, str, l);
1861 repodata_set(data, solvid, &key, data->attrdatalen);
1862 data->attrdatalen += l;
1866 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1869 for (i = 0; i < buflen; i++)
1871 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1872 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
1873 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
1884 buf[i] = (buf[i] << 4) | v;
1891 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1894 unsigned char buf[64];
1895 int l = checksumtype2len(type);
1899 if (hexstr2bytes(buf, str, l) != l)
1901 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
1905 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1910 l = checksumtype2len(type);
1913 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1914 for (i = 0; i < l; i++)
1916 unsigned char v = buf[i];
1917 unsigned char w = v >> 4;
1918 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1920 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1926 /* rpm filenames don't contain the epoch, so strip it */
1927 static inline const char *
1928 evrid2vrstr(Pool *pool, Id evrid)
1930 const char *p, *evr = id2str(pool, evrid);
1933 for (p = evr; *p >= '0' && *p <= '9'; p++)
1935 return p != evr && *p == ':' ? p + 1 : evr;
1939 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
1941 Pool *pool = data->repo->pool;
1943 const char *str, *fp;
1947 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
1950 if ((dir = strrchr(file, '/')) != 0)
1961 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
1966 if (l == 1 && dir[0] == '.')
1968 s = pool->solvables + solvid;
1971 str = id2str(pool, s->arch);
1972 if (!strncmp(dir, str, l) && !str[l])
1973 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
1975 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
1978 char *dir2 = strdup(dir);
1980 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
1985 str = id2str(pool, s->name);
1987 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
1990 str = evrid2vrstr(pool, s->evr);
1992 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
1995 str = id2str(pool, s->arch);
1997 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
1999 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2004 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2008 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2012 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2014 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2015 data->attriddata[data->attriddatalen++] = dir;
2016 data->attriddata[data->attriddatalen++] = num;
2017 data->attriddata[data->attriddatalen++] = num2;
2018 data->attriddata[data->attriddatalen++] = 0;
2022 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2028 l = strlen(str) + 1;
2029 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2030 memcpy(data->attrdata + data->attrdatalen, str, l);
2031 stroff = data->attrdatalen;
2032 data->attrdatalen += l;
2035 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2037 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2038 data->attriddata[data->attriddatalen++] = dir;
2039 data->attriddata[data->attriddatalen++] = stroff;
2040 data->attriddata[data->attriddatalen++] = 0;
2044 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2047 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2049 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2050 data->attriddata[data->attriddatalen++] = id;
2051 data->attriddata[data->attriddatalen++] = 0;
2055 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2059 if (data->localpool)
2060 id = stringpool_str2id(&data->spool, str, 1);
2062 id = str2id(data->repo->pool, str, 1);
2063 repodata_add_idarray(data, solvid, keyname, id);
2067 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2069 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2070 data->attriddata[data->attriddatalen++] = ghandle;
2071 data->attriddata[data->attriddatalen++] = 0;
2075 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2077 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2078 data->attriddata[data->attriddatalen++] = ghandle;
2079 data->attriddata[data->attriddatalen++] = 0;
2082 /* add all attrs from src to dest */
2084 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2087 if (dest == src || !(keyp = data->attrs[src - data->start]))
2089 for (; *keyp; keyp += 2)
2090 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2096 /**********************************************************************/
2098 /* unify with repo_write! */
2100 #define EXTDATA_BLOCK 1023
2108 data_addid(struct extdata *xd, Id x)
2111 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2112 dp = xd->buf + xd->len;
2117 *dp++ = (x >> 28) | 128;
2119 *dp++ = (x >> 21) | 128;
2120 *dp++ = (x >> 14) | 128;
2123 *dp++ = (x >> 7) | 128;
2125 xd->len = dp - xd->buf;
2129 data_addideof(struct extdata *xd, Id x, int eof)
2132 x = (x & 63) | ((x & ~63) << 1);
2133 data_addid(xd, (eof ? x: x | 64));
2137 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2139 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2140 memcpy(xd->buf + xd->len, blob, len);
2144 /*********************************/
2147 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2148 struct extdata *newvincore,
2150 Repokey *key, Id val)
2152 /* Otherwise we have a new value. Parse it into the internal
2156 unsigned int oldvincorelen = 0;
2160 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2163 oldvincorelen = xd->len;
2167 case REPOKEY_TYPE_VOID:
2168 case REPOKEY_TYPE_CONSTANT:
2169 case REPOKEY_TYPE_CONSTANTID:
2171 case REPOKEY_TYPE_STR:
2172 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2174 case REPOKEY_TYPE_MD5:
2175 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2177 case REPOKEY_TYPE_SHA1:
2178 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2180 case REPOKEY_TYPE_SHA256:
2181 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2183 case REPOKEY_TYPE_ID:
2184 case REPOKEY_TYPE_NUM:
2185 case REPOKEY_TYPE_DIR:
2186 data_addid(xd, val);
2188 case REPOKEY_TYPE_IDARRAY:
2189 for (ida = data->attriddata + val; *ida; ida++)
2190 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2192 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2193 for (ida = data->attriddata + val; *ida; ida += 3)
2195 data_addid(xd, ida[0]);
2196 data_addid(xd, ida[1]);
2197 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2200 case REPOKEY_TYPE_DIRSTRARRAY:
2201 for (ida = data->attriddata + val; *ida; ida += 2)
2203 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2204 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2207 case REPOKEY_TYPE_FIXARRAY:
2211 for (ida = data->attriddata + val; *ida; ida++)
2214 fprintf(stderr, "serialize struct %d\n", *ida);
2217 Id *kp = data->xattrs[-*ida];
2224 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2230 schemaid = repodata_schema2id(data, schema, 1);
2231 else if (schemaid != repodata_schema2id(data, schema, 0))
2233 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2237 fprintf(stderr, " schema %d\n", schemaid);
2242 data_addid(xd, num);
2243 data_addid(xd, schemaid);
2244 for (ida = data->attriddata + val; *ida; ida++)
2246 Id *kp = data->xattrs[-*ida];
2251 repodata_serialize_key(data, newincore, newvincore,
2252 schema, data->keys + *kp, kp[1]);
2257 case REPOKEY_TYPE_FLEXARRAY:
2260 for (ida = data->attriddata + val; *ida; ida++)
2262 data_addid(xd, num);
2263 for (ida = data->attriddata + val; *ida; ida++)
2265 Id *kp = data->xattrs[-*ida];
2268 data_addid(xd, 0); /* XXX */
2275 schemaid = repodata_schema2id(data, schema, 1);
2276 data_addid(xd, schemaid);
2277 kp = data->xattrs[-*ida];
2280 repodata_serialize_key(data, newincore, newvincore,
2281 schema, data->keys + *kp, kp[1]);
2287 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2290 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2292 /* put offset/len in incore */
2293 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2294 oldvincorelen = xd->len - oldvincorelen;
2295 data_addid(newincore, oldvincorelen);
2300 repodata_internalize(Repodata *data)
2302 Repokey *key, solvkey;
2304 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2305 unsigned char *dp, *ndp;
2306 int newschema, oldcount;
2307 struct extdata newincore;
2308 struct extdata newvincore;
2311 if (!data->attrs && !data->xattrs)
2314 newvincore.buf = data->vincore;
2315 newvincore.len = data->vincorelen;
2317 /* find the solvables key, create if needed */
2318 memset(&solvkey, 0, sizeof(solvkey));
2319 solvkey.name = REPOSITORY_SOLVABLES;
2320 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2322 solvkey.storage = KEY_STORAGE_INCORE;
2323 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2325 schema = sat_malloc2(data->nkeys, sizeof(Id));
2326 seen = sat_malloc2(data->nkeys, sizeof(Id));
2328 /* Merge the data already existing (in data->schemata, ->incoredata and
2329 friends) with the new attributes in data->attrs[]. */
2330 nentry = data->end - data->start;
2331 memset(&newincore, 0, sizeof(newincore));
2332 data_addid(&newincore, 0); /* start data at offset 1 */
2334 data->mainschema = 0;
2335 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2337 /* join entry data */
2338 /* we start with the meta data, entry -1 */
2339 for (entry = -1; entry < nentry; entry++)
2341 memset(seen, 0, data->nkeys * sizeof(Id));
2343 dp = data->incoredata;
2346 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2347 dp = data_read_id(dp, &oldschema);
2350 fprintf(stderr, "oldschema %d\n", oldschema);
2351 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2352 fprintf(stderr, "schemadata %p\n", data->schemadata);
2354 /* seen: -1: old data 0: skipped >0: id + 1 */
2358 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2362 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2370 keyp = data->attrs ? data->attrs[entry] : 0;
2373 /* strip solvables key */
2375 for (sp = keyp = schema; *sp; sp++)
2376 if (*sp != solvkeyid)
2381 seen[solvkeyid] = 0;
2382 keyp = data->xattrs ? data->xattrs[1] : 0;
2385 for (; *keyp; keyp += 2)
2392 seen[*keyp] = keyp[1] + 1;
2394 if (entry < 0 && data->end != data->start)
2401 /* Ideally we'd like to sort the new schema here, to ensure
2402 schema equality independend of the ordering. We can't do that
2403 yet. For once see below (old ids need to come before new ids).
2404 An additional difficulty is that we also need to move
2405 the values with the keys. */
2406 schemaid = repodata_schema2id(data, schema, 1);
2408 schemaid = oldschema;
2411 /* Now create data blob. We walk through the (possibly new) schema
2412 and either copy over old data, or insert the new. */
2413 /* XXX Here we rely on the fact that the (new) schema has the form
2414 o1 o2 o3 o4 ... | n1 n2 n3 ...
2415 (oX being the old keyids (possibly overwritten), and nX being
2416 the new keyids). This rules out sorting the keyids in order
2417 to ensure a small schema count. */
2419 data->incoreoffset[entry] = newincore.len;
2420 data_addid(&newincore, schemaid);
2423 data->mainschema = schemaid;
2424 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2426 keypstart = data->schemadata + data->schemata[schemaid];
2427 for (keyp = keypstart; *keyp; keyp++)
2430 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2431 if (*keyp == solvkeyid)
2433 /* add flexarray entry count */
2434 data_addid(&newincore, data->end - data->start);
2437 key = data->keys + *keyp;
2439 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2444 /* Skip the data associated with this old key. */
2445 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2447 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2448 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2450 else if (key->storage == KEY_STORAGE_INCORE)
2451 ndp = data_skip_key(data, dp, key);
2454 if (seen[*keyp] == -1)
2456 /* If this key was an old one _and_ was not overwritten with
2457 a different value copy over the old value (we skipped it
2460 data_addblob(&newincore, dp, ndp - dp);
2463 else if (seen[*keyp])
2465 /* Otherwise we have a new value. Parse it into the internal
2467 repodata_serialize_key(data, &newincore, &newvincore,
2468 schema, key, seen[*keyp] - 1);
2472 if (entry >= 0 && data->attrs && data->attrs[entry])
2473 data->attrs[entry] = sat_free(data->attrs[entry]);
2475 /* free all xattrs */
2476 for (entry = 0; entry < data->nxattrs; entry++)
2477 if (data->xattrs[entry])
2478 sat_free(data->xattrs[entry]);
2479 data->xattrs = sat_free(data->xattrs);
2482 data->lasthandle = 0;
2484 data->lastdatalen = 0;
2487 repodata_free_schemahash(data);
2489 sat_free(data->incoredata);
2490 data->incoredata = newincore.buf;
2491 data->incoredatalen = newincore.len;
2492 data->incoredatafree = 0;
2494 sat_free(data->vincore);
2495 data->vincore = newvincore.buf;
2496 data->vincorelen = newvincore.len;
2498 data->attrs = sat_free(data->attrs);
2499 data->attrdata = sat_free(data->attrdata);
2500 data->attriddata = sat_free(data->attriddata);
2501 data->attrdatalen = 0;
2502 data->attriddatalen = 0;
2506 repodata_disable_paging(Repodata *data)
2508 if (maybe_load_repodata(data, 0))
2509 repopagestore_disable_paging(&data->store);
2513 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: