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)
639 const char *s = strchr(kv->str, ':');
644 case REPOKEY_TYPE_STR:
646 case REPOKEY_TYPE_DIRSTRARRAY:
647 if (!(flags & SEARCH_FILES))
648 return 1; /* match just the basename */
649 /* Put the full filename into kv->str. */
650 kv->str = repodata_dir2str(data, kv->id, kv->str);
651 /* And to compensate for that put the "empty" directory into
652 kv->id, so that later calls to repodata_dir2str on this data
653 come up with the same filename again. */
662 struct subschema_data {
668 /* search a specific repodata */
670 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
674 Id keyid, *kp, *keyp;
675 unsigned char *dp, *ddp;
681 if (!maybe_load_repodata(data, keyname))
683 if (solvid == SOLVID_SUBSCHEMA)
685 struct subschema_data *subd = cbdata;
686 cbdata = subd->cbdata;
688 schema = subd->parent->id;
689 dp = (unsigned char *)subd->parent->str;
690 kv.parent = subd->parent;
695 dp = solvid2data(data, solvid, &schema);
698 s = data->repo->pool->solvables + solvid;
701 keyp = data->schemadata + data->schemata[schema];
704 /* search for a specific key */
705 for (kp = keyp; *kp; kp++)
706 if (data->keys[*kp].name == keyname)
710 dp = forward_to_key(data, *kp, keyp, dp);
716 while ((keyid = *keyp++) != 0)
719 key = data->keys + keyid;
720 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
722 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
724 struct subschema_data subd;
728 subd.cbdata = cbdata;
731 ddp = data_read_id(ddp, &nentries);
735 while (ddp && nentries > 0)
739 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
740 ddp = data_read_id(ddp, &schema);
742 kv.str = (char *)ddp;
743 stop = callback(cbdata, s, data, key, &kv);
744 if (stop > SEARCH_NEXT_KEY)
746 if (stop && stop != SEARCH_ENTERSUB)
748 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
749 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
750 ddp = data_skip_schema(data, ddp, schema);
753 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
757 kv.str = (char *)ddp;
758 stop = callback(cbdata, s, data, key, &kv);
759 if (stop > SEARCH_NEXT_KEY)
769 ddp = data_fetch(ddp, &kv, key);
772 stop = callback(cbdata, s, data, key, &kv);
775 while (!kv.eof && !stop);
776 if (onekey || stop > SEARCH_NEXT_KEY)
782 repodata_setpos_kv(Repodata *data, KeyValue *kv)
784 Pool *pool = data->repo->pool;
786 pool_clear_pos(pool);
789 pool->pos.repo = data->repo;
790 pool->pos.repodataid = data - data->repo->repodata;
791 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
792 pool->pos.schema = kv->id;
796 /************************************************************************
797 * data iterator functions
800 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
801 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
802 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
803 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
804 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
805 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
806 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
807 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
808 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
809 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
810 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
811 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
812 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
813 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
817 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
831 case SOLVABLE_VENDOR:
834 case SOLVABLE_PROVIDES:
836 return s->provides ? s->repo->idarraydata + s->provides : 0;
837 case SOLVABLE_OBSOLETES:
839 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
840 case SOLVABLE_CONFLICTS:
842 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
843 case SOLVABLE_REQUIRES:
845 return s->requires ? s->repo->idarraydata + s->requires : 0;
846 case SOLVABLE_RECOMMENDS:
848 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
849 case SOLVABLE_SUPPLEMENTS:
851 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
852 case SOLVABLE_SUGGESTS:
854 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
855 case SOLVABLE_ENHANCES:
857 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
860 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
867 datamatcher_init(Datamatcher *ma, const char *match, int flags)
869 ma->match = (void *)match;
872 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
874 ma->match = sat_calloc(1, sizeof(regex_t));
875 ma->error = regcomp((regex_t *)ma->match, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
879 ma->match = (void *)match;
880 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
887 datamatcher_free(Datamatcher *ma)
889 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->match)
892 ma->match = sat_free(ma->match);
897 datamatcher_match(Datamatcher *ma, const char *str)
899 switch ((ma->flags & SEARCH_STRINGMASK))
901 case SEARCH_SUBSTRING:
902 if (ma->flags & SEARCH_NOCASE)
904 if (!strcasestr(str, (const char *)ma->match))
909 if (!strstr(str, (const char *)ma->match))
914 if (ma->flags & SEARCH_NOCASE)
916 if (strcasecmp((const char *)ma->match, str))
921 if (strcmp((const char *)ma->match, str))
926 if (fnmatch((const char *)ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
930 if (regexec((const regex_t *)ma->match, str, 0, NULL, 0))
965 /* see repo.h for documentation */
967 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
969 memset(di, 0, sizeof(*di));
971 if (!pool || (repo && repo->pool != pool))
979 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
986 di->keyname = keyname;
987 di->keynames[0] = keyname;
988 di->flags = flags & ~SEARCH_THISSOLVID;
997 dataiterator_jump_to_solvid(di, p);
1001 di->repo = pool->repos[0];
1002 di->state = di_enterrepo;
1008 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1012 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1014 di->state = di_bye; /* sorry */
1017 for (i = di->nkeynames + 1; i > 0; i--)
1018 di->keynames[i] = di->keynames[i - 1];
1019 di->keynames[0] = di->keyname = keyname;
1024 dataiterator_free(Dataiterator *di)
1026 if (di->matcher.match)
1027 datamatcher_free(&di->matcher);
1030 static inline unsigned char *
1031 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1033 Id *keyp = di->keyp;
1034 Repokey *keys = di->data->keys;
1037 for (keyp = di->keyp; *keyp; keyp++)
1038 if (keys[*keyp].name == keyname)
1042 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1050 dataiterator_step(Dataiterator *di)
1058 case di_enterrepo: di_enterrepo:
1061 if (!(di->flags & SEARCH_THISSOLVID))
1063 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1064 goto di_nextsolvable;
1068 case di_entersolvable: di_entersolvable:
1069 if (di->repodataid >= 0)
1071 di->repodataid = 0; /* reset repodata iterator */
1072 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)
1074 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1076 goto di_entersolvablekey;
1081 case di_enterrepodata: di_enterrepodata:
1082 if (di->repodataid >= 0)
1084 if (di->repodataid >= di->repo->nrepodata)
1085 goto di_nextsolvable;
1086 di->data = di->repo->repodata + di->repodataid;
1088 if (!maybe_load_repodata(di->data, di->keyname))
1089 goto di_nextrepodata;
1090 di->dp = solvid2data(di->data, di->solvid, &schema);
1092 goto di_nextrepodata;
1093 if (di->solvid == SOLVID_POS)
1094 di->solvid = di->pool->pos.solvid;
1095 /* reset key iterator */
1096 di->keyp = di->data->schemadata + di->data->schemata[schema];
1099 case di_enterschema: di_enterschema:
1101 di->dp = dataiterator_find_keyname(di, di->keyname);
1102 if (!di->dp || !*di->keyp)
1106 goto di_nextrepodata;
1110 case di_enterkey: di_enterkey:
1112 di->key = di->data->keys + *di->keyp;
1113 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1116 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1118 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1124 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1126 di->state = di_nextkey;
1128 di->state = di_nextattr;
1131 case di_nextkey: di_nextkey:
1132 if (!di->keyname && *++di->keyp)
1138 case di_nextrepodata: di_nextrepodata:
1139 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1140 goto di_enterrepodata;
1143 case di_nextsolvable: di_nextsolvable:
1144 if (!(di->flags & SEARCH_THISSOLVID))
1147 di->solvid = di->repo->start;
1150 for (; di->solvid < di->repo->end; di->solvid++)
1152 if (di->pool->solvables[di->solvid].repo == di->repo)
1153 goto di_entersolvable;
1159 if (di->repoid >= 0)
1162 if (di->repoid < di->pool->nrepos)
1164 di->repo = di->pool->repos[di->repoid];
1170 case di_bye: di_bye:
1174 case di_enterarray: di_enterarray:
1175 if (di->key->name == REPOSITORY_SOLVABLES)
1177 di->ddp = data_read_id(di->ddp, &di->kv.num);
1182 case di_nextarrayelement: di_nextarrayelement:
1185 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1186 if (di->kv.entry == di->kv.num)
1188 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1190 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1192 di->kv.str = (char *)di->ddp;
1194 di->state = di_nextkey;
1197 if (di->kv.entry == di->kv.num - 1)
1199 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1200 di->ddp = data_read_id(di->ddp, &di->kv.id);
1201 di->kv.str = (char *)di->ddp;
1202 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1204 if ((di->flags & SEARCH_SUB) != 0)
1205 di->state = di_entersub;
1207 di->state = di_nextarrayelement;
1210 case di_entersub: di_entersub:
1211 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1212 goto di_nextarrayelement; /* sorry, full */
1213 di->parents[di->nparents].kv = di->kv;
1214 di->parents[di->nparents].dp = di->dp;
1215 di->parents[di->nparents].keyp = di->keyp;
1216 di->dp = (unsigned char *)di->kv.str;
1217 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1218 memset(&di->kv, 0, sizeof(di->kv));
1219 di->kv.parent = &di->parents[di->nparents].kv;
1221 di->keyname = di->keynames[di->nparents - di->rootlevel];
1222 goto di_enterschema;
1224 case di_leavesub: di_leavesub:
1225 if (di->nparents - 1 < di->rootlevel)
1228 di->dp = di->parents[di->nparents].dp;
1229 di->kv = di->parents[di->nparents].kv;
1230 di->keyp = di->parents[di->nparents].keyp;
1231 di->key = di->data->keys + *di->keyp;
1232 di->ddp = (unsigned char *)di->kv.str;
1233 di->keyname = di->keynames[di->nparents - di->rootlevel];
1234 goto di_nextarrayelement;
1236 /* special solvable attr handling follows */
1238 case di_nextsolvableattr:
1239 di->kv.id = *di->idp++;
1244 di->state = di_nextsolvablekey;
1248 case di_nextsolvablekey: di_nextsolvablekey:
1249 if (di->keyname || di->key->name == RPM_RPMDBID)
1250 goto di_enterrepodata;
1254 case di_entersolvablekey: di_entersolvablekey:
1255 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1256 if (!di->idp || !di->idp[0])
1257 goto di_nextsolvablekey;
1258 di->kv.id = di->idp[0];
1259 di->kv.num = di->idp[0];
1261 if (!di->kv.eof && !di->idp[0])
1265 di->state = di_nextsolvablekey;
1267 di->state = di_nextsolvableattr;
1271 if (di->matcher.match)
1273 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1275 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1279 if (!datamatcher_match(&di->matcher, di->kv.str))
1282 /* found something! */
1288 dataiterator_entersub(Dataiterator *di)
1290 if (di->state == di_nextarrayelement)
1291 di->state = di_entersub;
1295 dataiterator_setpos(Dataiterator *di)
1297 if (di->kv.eof == 2)
1299 pool_clear_pos(di->pool);
1302 di->pool->pos.solvid = di->solvid;
1303 di->pool->pos.repo = di->repo;
1304 di->pool->pos.repodataid = di->data - di->repo->repodata;
1305 di->pool->pos.schema = di->kv.id;
1306 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1310 dataiterator_setpos_parent(Dataiterator *di)
1312 if (!di->kv.parent || di->kv.parent->eof == 2)
1314 pool_clear_pos(di->pool);
1317 di->pool->pos.solvid = di->solvid;
1318 di->pool->pos.repo = di->repo;
1319 di->pool->pos.repodataid = di->data - di->repo->repodata;
1320 di->pool->pos.schema = di->kv.parent->id;
1321 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1324 /* clones just the position, not the search keys/matcher */
1326 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1328 di->state = from->state;
1329 di->flags &= ~SEARCH_THISSOLVID;
1330 di->flags |= (from->flags & SEARCH_THISSOLVID);
1331 di->repo = from->repo;
1332 di->data = from->data;
1334 di->ddp = from->ddp;
1335 di->idp = from->idp;
1336 di->keyp = from->keyp;
1337 di->key = from->key;
1339 di->repodataid = from->repodataid;
1340 di->solvid = from->solvid;
1341 di->repoid = from->repoid;
1342 di->rootlevel = from->rootlevel;
1343 memcpy(di->parents, from->parents, sizeof(from->parents));
1347 for (i = 1; i < di->nparents; i++)
1348 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1349 di->kv.parent = &di->parents[di->nparents - 1].kv;
1354 dataiterator_seek(Dataiterator *di, int whence)
1356 if ((whence & DI_SEEK_STAY) != 0)
1357 di->rootlevel = di->nparents;
1358 switch (whence & ~DI_SEEK_STAY)
1361 if (di->state != di_nextarrayelement)
1363 if ((whence & DI_SEEK_STAY) != 0)
1364 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1365 di->state = di_entersub;
1367 case DI_SEEK_PARENT:
1374 if (di->rootlevel > di->nparents)
1375 di->rootlevel = di->nparents;
1376 di->dp = di->parents[di->nparents].dp;
1377 di->kv = di->parents[di->nparents].kv;
1378 di->keyp = di->parents[di->nparents].keyp;
1379 di->key = di->data->keys + *di->keyp;
1380 di->ddp = (unsigned char *)di->kv.str;
1381 di->keyname = di->keynames[di->nparents - di->rootlevel];
1382 di->state = di_nextarrayelement;
1384 case DI_SEEK_REWIND:
1390 di->dp = (unsigned char *)di->kv.parent->str;
1391 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1392 di->state = di_enterschema;
1400 dataiterator_skip_attribute(Dataiterator *di)
1402 if (di->state == di_nextsolvableattr)
1403 di->state = di_nextsolvablekey;
1405 di->state = di_nextkey;
1409 dataiterator_skip_solvable(Dataiterator *di)
1411 di->state = di_nextsolvable;
1415 dataiterator_skip_repo(Dataiterator *di)
1417 di->state = di_nextrepo;
1421 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1425 if (solvid == SOLVID_POS)
1427 di->repo = di->pool->pos.repo;
1434 di->data = di->repo->repodata + di->pool->pos.repodataid;
1435 di->repodataid = -1;
1436 di->solvid = solvid;
1437 di->state = di_enterrepo;
1438 di->flags |= SEARCH_THISSOLVID;
1443 di->repo = di->pool->solvables[solvid].repo;
1446 else if (di->repoid >= 0)
1448 if (!di->pool->nrepos)
1453 di->repo = di->pool->repos[0];
1457 di->solvid = solvid;
1459 di->flags |= SEARCH_THISSOLVID;
1460 di->state = di_enterrepo;
1464 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1472 di->flags &= ~SEARCH_THISSOLVID;
1473 di->state = di_enterrepo;
1477 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1479 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1483 return datamatcher_match(ma, di->kv.str);
1486 /************************************************************************
1487 * data modify functions
1490 /* extend repodata so that it includes solvables p */
1492 repodata_extend(Repodata *data, Id p)
1494 if (data->start == data->end)
1495 data->start = data->end = p;
1498 int old = data->end - data->start;
1499 int new = p - data->end + 1;
1502 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1503 memset(data->attrs + old, 0, new * sizeof(Id *));
1505 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1506 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1509 if (p < data->start)
1511 int old = data->end - data->start;
1512 int new = data->start - p;
1515 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1516 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1517 memset(data->attrs, 0, new * sizeof(Id *));
1519 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1520 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1521 memset(data->incoreoffset, 0, new * sizeof(Id));
1526 /* extend repodata so that it includes solvables from start to start + num - 1 */
1528 repodata_extend_block(Repodata *data, Id start, Id num)
1532 if (!data->incoreoffset)
1534 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1535 data->start = start;
1536 data->end = start + num;
1539 repodata_extend(data, start);
1541 repodata_extend(data, start + num - 1);
1544 /**********************************************************************/
1546 #define REPODATA_ATTRS_BLOCK 63
1547 #define REPODATA_ATTRDATA_BLOCK 1023
1548 #define REPODATA_ATTRIDDATA_BLOCK 63
1552 repodata_new_handle(Repodata *data)
1556 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1559 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1560 data->xattrs[data->nxattrs] = 0;
1561 return -(data->nxattrs++);
1565 repodata_get_attrp(Repodata *data, Id handle)
1567 if (handle == SOLVID_META)
1571 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1576 return data->xattrs - handle;
1577 if (handle < data->start || handle >= data->end)
1578 repodata_extend(data, handle);
1580 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1581 return data->attrs + (handle - data->start);
1585 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1591 app = repodata_get_attrp(data, handle);
1596 for (pp = ap; *pp; pp += 2)
1597 /* Determine equality based on the name only, allows us to change
1598 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1599 if (data->keys[*pp].name == data->keys[keyid].name)
1612 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1622 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1626 keyid = repodata_key2id(data, key, 1);
1627 repodata_insert_keyid(data, solvid, keyid, val, 1);
1631 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1635 key.type = REPOKEY_TYPE_ID;
1637 key.storage = KEY_STORAGE_INCORE;
1638 repodata_set(data, solvid, &key, id);
1642 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1646 key.type = REPOKEY_TYPE_NUM;
1648 key.storage = KEY_STORAGE_INCORE;
1649 repodata_set(data, solvid, &key, (Id)num);
1653 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1657 if (data->localpool)
1658 id = stringpool_str2id(&data->spool, str, 1);
1660 id = str2id(data->repo->pool, str, 1);
1662 key.type = REPOKEY_TYPE_ID;
1664 key.storage = KEY_STORAGE_INCORE;
1665 repodata_set(data, solvid, &key, id);
1669 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1673 key.type = REPOKEY_TYPE_CONSTANT;
1674 key.size = constant;
1675 key.storage = KEY_STORAGE_INCORE;
1676 repodata_set(data, solvid, &key, 0);
1680 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1684 key.type = REPOKEY_TYPE_CONSTANTID;
1686 key.storage = KEY_STORAGE_INCORE;
1687 repodata_set(data, solvid, &key, 0);
1691 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1695 key.type = REPOKEY_TYPE_VOID;
1697 key.storage = KEY_STORAGE_INCORE;
1698 repodata_set(data, solvid, &key, 0);
1702 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1707 l = strlen(str) + 1;
1709 key.type = REPOKEY_TYPE_STR;
1711 key.storage = KEY_STORAGE_INCORE;
1712 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1713 memcpy(data->attrdata + data->attrdatalen, str, l);
1714 repodata_set(data, solvid, &key, data->attrdatalen);
1715 data->attrdatalen += l;
1718 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1719 * so that the caller can append the new element there */
1721 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1724 Id *ida, *pp, **ppp;
1726 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1728 /* great! just append the new data */
1729 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1730 data->attriddatalen--; /* overwrite terminating 0 */
1731 data->lastdatalen += entrysize;
1734 ppp = repodata_get_attrp(data, handle);
1737 for (; *pp; pp += 2)
1738 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1742 /* not found. allocate new key */
1747 key.storage = KEY_STORAGE_INCORE;
1748 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1749 repodata_set(data, handle, &key, data->attriddatalen);
1750 data->lasthandle = 0; /* next time... */
1754 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1755 oldsize += entrysize;
1756 if (ida + 1 == data->attriddata + data->attriddatalen)
1758 /* this was the last entry, just append it */
1759 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1760 data->attriddatalen--; /* overwrite terminating 0 */
1764 /* too bad. move to back. */
1765 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1766 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1767 pp[1] = data->attriddatalen;
1768 data->attriddatalen += oldsize;
1770 data->lasthandle = handle;
1771 data->lastkey = *pp;
1772 data->lastdatalen = data->attriddatalen + entrysize + 1;
1776 checksumtype2len(Id type)
1780 case REPOKEY_TYPE_MD5:
1782 case REPOKEY_TYPE_SHA1:
1784 case REPOKEY_TYPE_SHA256:
1785 return SIZEOF_SHA256;
1792 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1793 const unsigned char *str)
1796 int l = checksumtype2len(type);
1803 key.storage = KEY_STORAGE_INCORE;
1804 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1805 memcpy(data->attrdata + data->attrdatalen, str, l);
1806 repodata_set(data, solvid, &key, data->attrdatalen);
1807 data->attrdatalen += l;
1811 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1814 for (i = 0; i < buflen; i++)
1816 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1817 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
1818 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
1829 buf[i] = (buf[i] << 4) | v;
1836 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1839 unsigned char buf[64];
1840 int l = checksumtype2len(type);
1844 if (hexstr2bytes(buf, str, l) != l)
1846 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
1850 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1855 l = checksumtype2len(type);
1858 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1859 for (i = 0; i < l; i++)
1861 unsigned char v = buf[i];
1862 unsigned char w = v >> 4;
1863 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1865 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1871 /* rpm filenames don't contain the epoch, so strip it */
1872 static inline const char *
1873 evrid2vrstr(Pool *pool, Id evrid)
1875 const char *p, *evr = id2str(pool, evrid);
1878 for (p = evr; *p >= '0' && *p <= '9'; p++)
1880 return p != evr && *p == ':' ? p + 1 : evr;
1884 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
1886 Pool *pool = data->repo->pool;
1888 const char *str, *fp;
1892 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
1895 if ((dir = strrchr(file, '/')) != 0)
1906 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
1911 if (l == 1 && dir[0] == '.')
1913 s = pool->solvables + solvid;
1916 str = id2str(pool, s->arch);
1917 if (!strncmp(dir, str, l) && !str[l])
1918 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
1920 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
1923 char *dir2 = strdup(dir);
1925 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
1930 str = id2str(pool, s->name);
1932 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
1935 str = evrid2vrstr(pool, s->evr);
1937 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
1940 str = id2str(pool, s->arch);
1942 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
1944 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
1949 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
1953 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
1957 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
1959 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
1960 data->attriddata[data->attriddatalen++] = dir;
1961 data->attriddata[data->attriddatalen++] = num;
1962 data->attriddata[data->attriddatalen++] = num2;
1963 data->attriddata[data->attriddatalen++] = 0;
1967 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
1973 l = strlen(str) + 1;
1974 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1975 memcpy(data->attrdata + data->attrdatalen, str, l);
1976 stroff = data->attrdatalen;
1977 data->attrdatalen += l;
1980 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
1982 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
1983 data->attriddata[data->attriddatalen++] = dir;
1984 data->attriddata[data->attriddatalen++] = stroff;
1985 data->attriddata[data->attriddatalen++] = 0;
1989 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
1992 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
1994 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
1995 data->attriddata[data->attriddatalen++] = id;
1996 data->attriddata[data->attriddatalen++] = 0;
2000 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2004 if (data->localpool)
2005 id = stringpool_str2id(&data->spool, str, 1);
2007 id = str2id(data->repo->pool, str, 1);
2008 repodata_add_idarray(data, solvid, keyname, id);
2012 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2014 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2015 data->attriddata[data->attriddatalen++] = ghandle;
2016 data->attriddata[data->attriddatalen++] = 0;
2020 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2022 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2023 data->attriddata[data->attriddatalen++] = ghandle;
2024 data->attriddata[data->attriddatalen++] = 0;
2027 /* add all attrs from src to dest */
2029 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2032 if (dest == src || !(keyp = data->attrs[src - data->start]))
2034 for (; *keyp; keyp += 2)
2035 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2041 /**********************************************************************/
2043 /* unify with repo_write! */
2045 #define EXTDATA_BLOCK 1023
2053 data_addid(struct extdata *xd, Id x)
2056 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2057 dp = xd->buf + xd->len;
2062 *dp++ = (x >> 28) | 128;
2064 *dp++ = (x >> 21) | 128;
2065 *dp++ = (x >> 14) | 128;
2068 *dp++ = (x >> 7) | 128;
2070 xd->len = dp - xd->buf;
2074 data_addideof(struct extdata *xd, Id x, int eof)
2077 x = (x & 63) | ((x & ~63) << 1);
2078 data_addid(xd, (eof ? x: x | 64));
2082 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2084 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2085 memcpy(xd->buf + xd->len, blob, len);
2089 /*********************************/
2092 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2093 struct extdata *newvincore,
2095 Repokey *key, Id val)
2097 /* Otherwise we have a new value. Parse it into the internal
2101 unsigned int oldvincorelen = 0;
2105 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2108 oldvincorelen = xd->len;
2112 case REPOKEY_TYPE_VOID:
2113 case REPOKEY_TYPE_CONSTANT:
2114 case REPOKEY_TYPE_CONSTANTID:
2116 case REPOKEY_TYPE_STR:
2117 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2119 case REPOKEY_TYPE_MD5:
2120 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2122 case REPOKEY_TYPE_SHA1:
2123 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2125 case REPOKEY_TYPE_SHA256:
2126 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2128 case REPOKEY_TYPE_ID:
2129 case REPOKEY_TYPE_NUM:
2130 case REPOKEY_TYPE_DIR:
2131 data_addid(xd, val);
2133 case REPOKEY_TYPE_IDARRAY:
2134 for (ida = data->attriddata + val; *ida; ida++)
2135 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2137 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2138 for (ida = data->attriddata + val; *ida; ida += 3)
2140 data_addid(xd, ida[0]);
2141 data_addid(xd, ida[1]);
2142 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2145 case REPOKEY_TYPE_DIRSTRARRAY:
2146 for (ida = data->attriddata + val; *ida; ida += 2)
2148 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2149 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2152 case REPOKEY_TYPE_FIXARRAY:
2156 for (ida = data->attriddata + val; *ida; ida++)
2159 fprintf(stderr, "serialize struct %d\n", *ida);
2162 Id *kp = data->xattrs[-*ida];
2169 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2175 schemaid = repodata_schema2id(data, schema, 1);
2176 else if (schemaid != repodata_schema2id(data, schema, 0))
2178 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2182 fprintf(stderr, " schema %d\n", schemaid);
2187 data_addid(xd, num);
2188 data_addid(xd, schemaid);
2189 for (ida = data->attriddata + val; *ida; ida++)
2191 Id *kp = data->xattrs[-*ida];
2196 repodata_serialize_key(data, newincore, newvincore,
2197 schema, data->keys + *kp, kp[1]);
2202 case REPOKEY_TYPE_FLEXARRAY:
2205 for (ida = data->attriddata + val; *ida; ida++)
2207 data_addid(xd, num);
2208 for (ida = data->attriddata + val; *ida; ida++)
2210 Id *kp = data->xattrs[-*ida];
2213 data_addid(xd, 0); /* XXX */
2220 schemaid = repodata_schema2id(data, schema, 1);
2221 data_addid(xd, schemaid);
2222 kp = data->xattrs[-*ida];
2225 repodata_serialize_key(data, newincore, newvincore,
2226 schema, data->keys + *kp, kp[1]);
2232 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2235 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2237 /* put offset/len in incore */
2238 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2239 oldvincorelen = xd->len - oldvincorelen;
2240 data_addid(newincore, oldvincorelen);
2245 repodata_internalize(Repodata *data)
2247 Repokey *key, solvkey;
2249 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2250 unsigned char *dp, *ndp;
2251 int newschema, oldcount;
2252 struct extdata newincore;
2253 struct extdata newvincore;
2256 if (!data->attrs && !data->xattrs)
2259 newvincore.buf = data->vincore;
2260 newvincore.len = data->vincorelen;
2262 /* find the solvables key, create if needed */
2263 memset(&solvkey, 0, sizeof(solvkey));
2264 solvkey.name = REPOSITORY_SOLVABLES;
2265 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2267 solvkey.storage = KEY_STORAGE_INCORE;
2268 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2270 schema = sat_malloc2(data->nkeys, sizeof(Id));
2271 seen = sat_malloc2(data->nkeys, sizeof(Id));
2273 /* Merge the data already existing (in data->schemata, ->incoredata and
2274 friends) with the new attributes in data->attrs[]. */
2275 nentry = data->end - data->start;
2276 memset(&newincore, 0, sizeof(newincore));
2277 data_addid(&newincore, 0); /* start data at offset 1 */
2279 data->mainschema = 0;
2280 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2282 /* join entry data */
2283 /* we start with the meta data, entry -1 */
2284 for (entry = -1; entry < nentry; entry++)
2286 memset(seen, 0, data->nkeys * sizeof(Id));
2288 dp = data->incoredata;
2291 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2292 dp = data_read_id(dp, &oldschema);
2295 fprintf(stderr, "oldschema %d\n", oldschema);
2296 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2297 fprintf(stderr, "schemadata %p\n", data->schemadata);
2299 /* seen: -1: old data 0: skipped >0: id + 1 */
2303 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2307 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2315 keyp = data->attrs ? data->attrs[entry] : 0;
2318 /* strip solvables key */
2320 for (sp = keyp = schema; *sp; sp++)
2321 if (*sp != solvkeyid)
2326 seen[solvkeyid] = 0;
2327 keyp = data->xattrs ? data->xattrs[1] : 0;
2330 for (; *keyp; keyp += 2)
2337 seen[*keyp] = keyp[1] + 1;
2339 if (entry < 0 && data->end != data->start)
2346 /* Ideally we'd like to sort the new schema here, to ensure
2347 schema equality independend of the ordering. We can't do that
2348 yet. For once see below (old ids need to come before new ids).
2349 An additional difficulty is that we also need to move
2350 the values with the keys. */
2351 schemaid = repodata_schema2id(data, schema, 1);
2353 schemaid = oldschema;
2356 /* Now create data blob. We walk through the (possibly new) schema
2357 and either copy over old data, or insert the new. */
2358 /* XXX Here we rely on the fact that the (new) schema has the form
2359 o1 o2 o3 o4 ... | n1 n2 n3 ...
2360 (oX being the old keyids (possibly overwritten), and nX being
2361 the new keyids). This rules out sorting the keyids in order
2362 to ensure a small schema count. */
2364 data->incoreoffset[entry] = newincore.len;
2365 data_addid(&newincore, schemaid);
2368 data->mainschema = schemaid;
2369 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2371 keypstart = data->schemadata + data->schemata[schemaid];
2372 for (keyp = keypstart; *keyp; keyp++)
2375 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2376 if (*keyp == solvkeyid)
2378 /* add flexarray entry count */
2379 data_addid(&newincore, data->end - data->start);
2382 key = data->keys + *keyp;
2384 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2389 /* Skip the data associated with this old key. */
2390 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2392 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2393 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2395 else if (key->storage == KEY_STORAGE_INCORE)
2396 ndp = data_skip_key(data, dp, key);
2399 if (seen[*keyp] == -1)
2401 /* If this key was an old one _and_ was not overwritten with
2402 a different value copy over the old value (we skipped it
2405 data_addblob(&newincore, dp, ndp - dp);
2408 else if (seen[*keyp])
2410 /* Otherwise we have a new value. Parse it into the internal
2412 repodata_serialize_key(data, &newincore, &newvincore,
2413 schema, key, seen[*keyp] - 1);
2417 if (entry >= 0 && data->attrs && data->attrs[entry])
2418 data->attrs[entry] = sat_free(data->attrs[entry]);
2420 /* free all xattrs */
2421 for (entry = 0; entry < data->nxattrs; entry++)
2422 if (data->xattrs[entry])
2423 sat_free(data->xattrs[entry]);
2424 data->xattrs = sat_free(data->xattrs);
2427 data->lasthandle = 0;
2429 data->lastdatalen = 0;
2432 repodata_free_schemahash(data);
2434 sat_free(data->incoredata);
2435 data->incoredata = newincore.buf;
2436 data->incoredatalen = newincore.len;
2437 data->incoredatafree = 0;
2439 sat_free(data->vincore);
2440 data->vincore = newvincore.buf;
2441 data->vincorelen = newvincore.len;
2443 data->attrs = sat_free(data->attrs);
2444 data->attrdata = sat_free(data->attrdata);
2445 data->attriddata = sat_free(data->attriddata);
2446 data->attrdatalen = 0;
2447 data->attriddatalen = 0;
2451 repodata_disable_paging(Repodata *data)
2453 if (maybe_load_repodata(data, 0))
2454 repopagestore_disable_paging(&data->store);
2458 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: