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)
873 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
875 ma->matchdata = sat_calloc(1, sizeof(regex_t));
876 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
879 sat_free(ma->matchdata);
880 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
887 datamatcher_free(Datamatcher *ma)
889 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
891 regfree(ma->matchdata);
892 ma->matchdata = sat_free(ma->matchdata);
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, ma->match))
909 if (!strstr(str, ma->match))
914 if (ma->flags & SEARCH_NOCASE)
916 if (strcasecmp(ma->match, str))
921 if (strcmp(ma->match, str))
926 if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
930 if (regexec((const regex_t *)ma->matchdata, 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)
985 di->keyname = keyname;
986 di->keynames[0] = keyname;
987 dataiterator_set_search(di, repo, p);
992 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
995 memset(&di->matcher, 0, sizeof(di->matcher));
996 if (from->matcher.match)
997 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1002 for (i = 1; i < di->nparents; i++)
1003 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1004 di->kv.parent = &di->parents[di->nparents - 1].kv;
1009 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1011 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1012 datamatcher_free(&di->matcher);
1013 memset(&di->matcher, 0, sizeof(di->matcher));
1017 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1027 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1031 di->flags &= ~SEARCH_THISSOLVID;
1035 if (!di->pool->nrepos)
1043 di->repo = di->pool->repos[0];
1045 di->state = di_enterrepo;
1047 dataiterator_jump_to_solvid(di, p);
1051 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1054 di->keyname = keyname;
1055 di->keynames[0] = keyname;
1059 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1063 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1065 di->state = di_bye; /* sorry */
1068 for (i = di->nkeynames + 1; i > 0; i--)
1069 di->keynames[i] = di->keynames[i - 1];
1070 di->keynames[0] = di->keyname = keyname;
1075 dataiterator_free(Dataiterator *di)
1077 if (di->matcher.match)
1078 datamatcher_free(&di->matcher);
1081 static inline unsigned char *
1082 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1084 Id *keyp = di->keyp;
1085 Repokey *keys = di->data->keys;
1088 for (keyp = di->keyp; *keyp; keyp++)
1089 if (keys[*keyp].name == keyname)
1093 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1101 dataiterator_step(Dataiterator *di)
1109 case di_enterrepo: di_enterrepo:
1112 if (!(di->flags & SEARCH_THISSOLVID))
1114 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1115 goto di_nextsolvable;
1119 case di_entersolvable: di_entersolvable:
1120 if (di->repodataid >= 0)
1122 di->repodataid = 0; /* reset repodata iterator */
1123 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)
1125 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1127 goto di_entersolvablekey;
1132 case di_enterrepodata: di_enterrepodata:
1133 if (di->repodataid >= 0)
1135 if (di->repodataid >= di->repo->nrepodata)
1136 goto di_nextsolvable;
1137 di->data = di->repo->repodata + di->repodataid;
1139 if (!maybe_load_repodata(di->data, di->keyname))
1140 goto di_nextrepodata;
1141 di->dp = solvid2data(di->data, di->solvid, &schema);
1143 goto di_nextrepodata;
1144 if (di->solvid == SOLVID_POS)
1145 di->solvid = di->pool->pos.solvid;
1146 /* reset key iterator */
1147 di->keyp = di->data->schemadata + di->data->schemata[schema];
1150 case di_enterschema: di_enterschema:
1152 di->dp = dataiterator_find_keyname(di, di->keyname);
1153 if (!di->dp || !*di->keyp)
1157 goto di_nextrepodata;
1161 case di_enterkey: di_enterkey:
1163 di->key = di->data->keys + *di->keyp;
1164 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1167 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1169 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1175 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1177 di->state = di_nextkey;
1179 di->state = di_nextattr;
1182 case di_nextkey: di_nextkey:
1183 if (!di->keyname && *++di->keyp)
1189 case di_nextrepodata: di_nextrepodata:
1190 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1191 goto di_enterrepodata;
1194 case di_nextsolvable: di_nextsolvable:
1195 if (!(di->flags & SEARCH_THISSOLVID))
1198 di->solvid = di->repo->start;
1201 for (; di->solvid < di->repo->end; di->solvid++)
1203 if (di->pool->solvables[di->solvid].repo == di->repo)
1204 goto di_entersolvable;
1210 if (di->repoid >= 0)
1213 if (di->repoid < di->pool->nrepos)
1215 di->repo = di->pool->repos[di->repoid];
1221 case di_bye: di_bye:
1225 case di_enterarray: di_enterarray:
1226 if (di->key->name == REPOSITORY_SOLVABLES)
1228 di->ddp = data_read_id(di->ddp, &di->kv.num);
1233 case di_nextarrayelement: di_nextarrayelement:
1236 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1237 if (di->kv.entry == di->kv.num)
1239 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1241 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1243 di->kv.str = (char *)di->ddp;
1245 di->state = di_nextkey;
1248 if (di->kv.entry == di->kv.num - 1)
1250 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1251 di->ddp = data_read_id(di->ddp, &di->kv.id);
1252 di->kv.str = (char *)di->ddp;
1253 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1255 if ((di->flags & SEARCH_SUB) != 0)
1256 di->state = di_entersub;
1258 di->state = di_nextarrayelement;
1261 case di_entersub: di_entersub:
1262 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1263 goto di_nextarrayelement; /* sorry, full */
1264 di->parents[di->nparents].kv = di->kv;
1265 di->parents[di->nparents].dp = di->dp;
1266 di->parents[di->nparents].keyp = di->keyp;
1267 di->dp = (unsigned char *)di->kv.str;
1268 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1269 memset(&di->kv, 0, sizeof(di->kv));
1270 di->kv.parent = &di->parents[di->nparents].kv;
1272 di->keyname = di->keynames[di->nparents - di->rootlevel];
1273 goto di_enterschema;
1275 case di_leavesub: di_leavesub:
1276 if (di->nparents - 1 < di->rootlevel)
1279 di->dp = di->parents[di->nparents].dp;
1280 di->kv = di->parents[di->nparents].kv;
1281 di->keyp = di->parents[di->nparents].keyp;
1282 di->key = di->data->keys + *di->keyp;
1283 di->ddp = (unsigned char *)di->kv.str;
1284 di->keyname = di->keynames[di->nparents - di->rootlevel];
1285 goto di_nextarrayelement;
1287 /* special solvable attr handling follows */
1289 case di_nextsolvableattr:
1290 di->kv.id = *di->idp++;
1295 di->state = di_nextsolvablekey;
1299 case di_nextsolvablekey: di_nextsolvablekey:
1300 if (di->keyname || di->key->name == RPM_RPMDBID)
1301 goto di_enterrepodata;
1305 case di_entersolvablekey: di_entersolvablekey:
1306 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1307 if (!di->idp || !di->idp[0])
1308 goto di_nextsolvablekey;
1309 di->kv.id = di->idp[0];
1310 di->kv.num = di->idp[0];
1312 if (!di->kv.eof && !di->idp[0])
1316 di->state = di_nextsolvablekey;
1318 di->state = di_nextsolvableattr;
1322 if (di->matcher.match)
1324 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1326 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1330 if (!datamatcher_match(&di->matcher, di->kv.str))
1333 /* found something! */
1339 dataiterator_entersub(Dataiterator *di)
1341 if (di->state == di_nextarrayelement)
1342 di->state = di_entersub;
1346 dataiterator_setpos(Dataiterator *di)
1348 if (di->kv.eof == 2)
1350 pool_clear_pos(di->pool);
1353 di->pool->pos.solvid = di->solvid;
1354 di->pool->pos.repo = di->repo;
1355 di->pool->pos.repodataid = di->data - di->repo->repodata;
1356 di->pool->pos.schema = di->kv.id;
1357 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1361 dataiterator_setpos_parent(Dataiterator *di)
1363 if (!di->kv.parent || di->kv.parent->eof == 2)
1365 pool_clear_pos(di->pool);
1368 di->pool->pos.solvid = di->solvid;
1369 di->pool->pos.repo = di->repo;
1370 di->pool->pos.repodataid = di->data - di->repo->repodata;
1371 di->pool->pos.schema = di->kv.parent->id;
1372 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1375 /* clones just the position, not the search keys/matcher */
1377 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1379 di->state = from->state;
1380 di->flags &= ~SEARCH_THISSOLVID;
1381 di->flags |= (from->flags & SEARCH_THISSOLVID);
1382 di->repo = from->repo;
1383 di->data = from->data;
1385 di->ddp = from->ddp;
1386 di->idp = from->idp;
1387 di->keyp = from->keyp;
1388 di->key = from->key;
1390 di->repodataid = from->repodataid;
1391 di->solvid = from->solvid;
1392 di->repoid = from->repoid;
1393 di->rootlevel = from->rootlevel;
1394 memcpy(di->parents, from->parents, sizeof(from->parents));
1395 di->nparents = from->nparents;
1399 for (i = 1; i < di->nparents; i++)
1400 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1401 di->kv.parent = &di->parents[di->nparents - 1].kv;
1406 dataiterator_seek(Dataiterator *di, int whence)
1408 if ((whence & DI_SEEK_STAY) != 0)
1409 di->rootlevel = di->nparents;
1410 switch (whence & ~DI_SEEK_STAY)
1413 if (di->state != di_nextarrayelement)
1415 if ((whence & DI_SEEK_STAY) != 0)
1416 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1417 di->state = di_entersub;
1419 case DI_SEEK_PARENT:
1426 if (di->rootlevel > di->nparents)
1427 di->rootlevel = di->nparents;
1428 di->dp = di->parents[di->nparents].dp;
1429 di->kv = di->parents[di->nparents].kv;
1430 di->keyp = di->parents[di->nparents].keyp;
1431 di->key = di->data->keys + *di->keyp;
1432 di->ddp = (unsigned char *)di->kv.str;
1433 di->keyname = di->keynames[di->nparents - di->rootlevel];
1434 di->state = di_nextarrayelement;
1436 case DI_SEEK_REWIND:
1442 di->dp = (unsigned char *)di->kv.parent->str;
1443 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1444 di->state = di_enterschema;
1452 dataiterator_skip_attribute(Dataiterator *di)
1454 if (di->state == di_nextsolvableattr)
1455 di->state = di_nextsolvablekey;
1457 di->state = di_nextkey;
1461 dataiterator_skip_solvable(Dataiterator *di)
1463 di->state = di_nextsolvable;
1467 dataiterator_skip_repo(Dataiterator *di)
1469 di->state = di_nextrepo;
1473 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1477 if (solvid == SOLVID_POS)
1479 di->repo = di->pool->pos.repo;
1486 di->data = di->repo->repodata + di->pool->pos.repodataid;
1487 di->repodataid = -1;
1488 di->solvid = solvid;
1489 di->state = di_enterrepo;
1490 di->flags |= SEARCH_THISSOLVID;
1495 di->repo = di->pool->solvables[solvid].repo;
1498 else if (di->repoid >= 0)
1500 if (!di->pool->nrepos)
1505 di->repo = di->pool->repos[0];
1509 di->solvid = solvid;
1511 di->flags |= SEARCH_THISSOLVID;
1512 di->state = di_enterrepo;
1516 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1524 di->flags &= ~SEARCH_THISSOLVID;
1525 di->state = di_enterrepo;
1529 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1531 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1535 return datamatcher_match(ma, di->kv.str);
1538 /************************************************************************
1539 * data modify functions
1542 /* extend repodata so that it includes solvables p */
1544 repodata_extend(Repodata *data, Id p)
1546 if (data->start == data->end)
1547 data->start = data->end = p;
1550 int old = data->end - data->start;
1551 int new = p - data->end + 1;
1554 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1555 memset(data->attrs + old, 0, new * sizeof(Id *));
1557 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1558 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1561 if (p < data->start)
1563 int old = data->end - data->start;
1564 int new = data->start - p;
1567 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1568 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1569 memset(data->attrs, 0, new * sizeof(Id *));
1571 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1572 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1573 memset(data->incoreoffset, 0, new * sizeof(Id));
1578 /* extend repodata so that it includes solvables from start to start + num - 1 */
1580 repodata_extend_block(Repodata *data, Id start, Id num)
1584 if (!data->incoreoffset)
1586 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1587 data->start = start;
1588 data->end = start + num;
1591 repodata_extend(data, start);
1593 repodata_extend(data, start + num - 1);
1596 /**********************************************************************/
1598 #define REPODATA_ATTRS_BLOCK 63
1599 #define REPODATA_ATTRDATA_BLOCK 1023
1600 #define REPODATA_ATTRIDDATA_BLOCK 63
1604 repodata_new_handle(Repodata *data)
1608 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1611 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1612 data->xattrs[data->nxattrs] = 0;
1613 return -(data->nxattrs++);
1617 repodata_get_attrp(Repodata *data, Id handle)
1619 if (handle == SOLVID_META)
1623 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1628 return data->xattrs - handle;
1629 if (handle < data->start || handle >= data->end)
1630 repodata_extend(data, handle);
1632 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1633 return data->attrs + (handle - data->start);
1637 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1643 app = repodata_get_attrp(data, handle);
1648 for (pp = ap; *pp; pp += 2)
1649 /* Determine equality based on the name only, allows us to change
1650 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1651 if (data->keys[*pp].name == data->keys[keyid].name)
1664 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1674 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1678 keyid = repodata_key2id(data, key, 1);
1679 repodata_insert_keyid(data, solvid, keyid, val, 1);
1683 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1687 key.type = REPOKEY_TYPE_ID;
1689 key.storage = KEY_STORAGE_INCORE;
1690 repodata_set(data, solvid, &key, id);
1694 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1698 key.type = REPOKEY_TYPE_NUM;
1700 key.storage = KEY_STORAGE_INCORE;
1701 repodata_set(data, solvid, &key, (Id)num);
1705 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1709 if (data->localpool)
1710 id = stringpool_str2id(&data->spool, str, 1);
1712 id = str2id(data->repo->pool, str, 1);
1714 key.type = REPOKEY_TYPE_ID;
1716 key.storage = KEY_STORAGE_INCORE;
1717 repodata_set(data, solvid, &key, id);
1721 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1725 key.type = REPOKEY_TYPE_CONSTANT;
1726 key.size = constant;
1727 key.storage = KEY_STORAGE_INCORE;
1728 repodata_set(data, solvid, &key, 0);
1732 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1736 key.type = REPOKEY_TYPE_CONSTANTID;
1738 key.storage = KEY_STORAGE_INCORE;
1739 repodata_set(data, solvid, &key, 0);
1743 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1747 key.type = REPOKEY_TYPE_VOID;
1749 key.storage = KEY_STORAGE_INCORE;
1750 repodata_set(data, solvid, &key, 0);
1754 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1759 l = strlen(str) + 1;
1761 key.type = REPOKEY_TYPE_STR;
1763 key.storage = KEY_STORAGE_INCORE;
1764 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1765 memcpy(data->attrdata + data->attrdatalen, str, l);
1766 repodata_set(data, solvid, &key, data->attrdatalen);
1767 data->attrdatalen += l;
1770 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1771 * so that the caller can append the new element there */
1773 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1776 Id *ida, *pp, **ppp;
1778 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1780 /* great! just append the new data */
1781 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1782 data->attriddatalen--; /* overwrite terminating 0 */
1783 data->lastdatalen += entrysize;
1786 ppp = repodata_get_attrp(data, handle);
1789 for (; *pp; pp += 2)
1790 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1794 /* not found. allocate new key */
1799 key.storage = KEY_STORAGE_INCORE;
1800 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1801 repodata_set(data, handle, &key, data->attriddatalen);
1802 data->lasthandle = 0; /* next time... */
1806 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1807 oldsize += entrysize;
1808 if (ida + 1 == data->attriddata + data->attriddatalen)
1810 /* this was the last entry, just append it */
1811 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1812 data->attriddatalen--; /* overwrite terminating 0 */
1816 /* too bad. move to back. */
1817 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1818 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1819 pp[1] = data->attriddatalen;
1820 data->attriddatalen += oldsize;
1822 data->lasthandle = handle;
1823 data->lastkey = *pp;
1824 data->lastdatalen = data->attriddatalen + entrysize + 1;
1828 checksumtype2len(Id type)
1832 case REPOKEY_TYPE_MD5:
1834 case REPOKEY_TYPE_SHA1:
1836 case REPOKEY_TYPE_SHA256:
1837 return SIZEOF_SHA256;
1844 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1845 const unsigned char *str)
1848 int l = checksumtype2len(type);
1855 key.storage = KEY_STORAGE_INCORE;
1856 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1857 memcpy(data->attrdata + data->attrdatalen, str, l);
1858 repodata_set(data, solvid, &key, data->attrdatalen);
1859 data->attrdatalen += l;
1863 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1866 for (i = 0; i < buflen; i++)
1868 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1869 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
1870 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
1881 buf[i] = (buf[i] << 4) | v;
1888 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1891 unsigned char buf[64];
1892 int l = checksumtype2len(type);
1896 if (hexstr2bytes(buf, str, l) != l)
1898 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
1902 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1907 l = checksumtype2len(type);
1910 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1911 for (i = 0; i < l; i++)
1913 unsigned char v = buf[i];
1914 unsigned char w = v >> 4;
1915 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1917 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1923 /* rpm filenames don't contain the epoch, so strip it */
1924 static inline const char *
1925 evrid2vrstr(Pool *pool, Id evrid)
1927 const char *p, *evr = id2str(pool, evrid);
1930 for (p = evr; *p >= '0' && *p <= '9'; p++)
1932 return p != evr && *p == ':' ? p + 1 : evr;
1936 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
1938 Pool *pool = data->repo->pool;
1940 const char *str, *fp;
1944 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
1947 if ((dir = strrchr(file, '/')) != 0)
1958 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
1963 if (l == 1 && dir[0] == '.')
1965 s = pool->solvables + solvid;
1968 str = id2str(pool, s->arch);
1969 if (!strncmp(dir, str, l) && !str[l])
1970 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
1972 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
1975 char *dir2 = strdup(dir);
1977 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
1982 str = id2str(pool, s->name);
1984 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
1987 str = evrid2vrstr(pool, s->evr);
1989 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
1992 str = id2str(pool, s->arch);
1994 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
1996 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2001 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2005 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2009 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2011 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2012 data->attriddata[data->attriddatalen++] = dir;
2013 data->attriddata[data->attriddatalen++] = num;
2014 data->attriddata[data->attriddatalen++] = num2;
2015 data->attriddata[data->attriddatalen++] = 0;
2019 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2025 l = strlen(str) + 1;
2026 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2027 memcpy(data->attrdata + data->attrdatalen, str, l);
2028 stroff = data->attrdatalen;
2029 data->attrdatalen += l;
2032 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2034 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2035 data->attriddata[data->attriddatalen++] = dir;
2036 data->attriddata[data->attriddatalen++] = stroff;
2037 data->attriddata[data->attriddatalen++] = 0;
2041 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2044 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2046 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2047 data->attriddata[data->attriddatalen++] = id;
2048 data->attriddata[data->attriddatalen++] = 0;
2052 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2056 if (data->localpool)
2057 id = stringpool_str2id(&data->spool, str, 1);
2059 id = str2id(data->repo->pool, str, 1);
2060 repodata_add_idarray(data, solvid, keyname, id);
2064 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2066 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2067 data->attriddata[data->attriddatalen++] = ghandle;
2068 data->attriddata[data->attriddatalen++] = 0;
2072 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2074 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2075 data->attriddata[data->attriddatalen++] = ghandle;
2076 data->attriddata[data->attriddatalen++] = 0;
2079 /* add all attrs from src to dest */
2081 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2084 if (dest == src || !(keyp = data->attrs[src - data->start]))
2086 for (; *keyp; keyp += 2)
2087 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2093 /**********************************************************************/
2095 /* unify with repo_write! */
2097 #define EXTDATA_BLOCK 1023
2105 data_addid(struct extdata *xd, Id x)
2108 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2109 dp = xd->buf + xd->len;
2114 *dp++ = (x >> 28) | 128;
2116 *dp++ = (x >> 21) | 128;
2117 *dp++ = (x >> 14) | 128;
2120 *dp++ = (x >> 7) | 128;
2122 xd->len = dp - xd->buf;
2126 data_addideof(struct extdata *xd, Id x, int eof)
2129 x = (x & 63) | ((x & ~63) << 1);
2130 data_addid(xd, (eof ? x: x | 64));
2134 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2136 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2137 memcpy(xd->buf + xd->len, blob, len);
2141 /*********************************/
2144 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2145 struct extdata *newvincore,
2147 Repokey *key, Id val)
2149 /* Otherwise we have a new value. Parse it into the internal
2153 unsigned int oldvincorelen = 0;
2157 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2160 oldvincorelen = xd->len;
2164 case REPOKEY_TYPE_VOID:
2165 case REPOKEY_TYPE_CONSTANT:
2166 case REPOKEY_TYPE_CONSTANTID:
2168 case REPOKEY_TYPE_STR:
2169 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2171 case REPOKEY_TYPE_MD5:
2172 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2174 case REPOKEY_TYPE_SHA1:
2175 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2177 case REPOKEY_TYPE_SHA256:
2178 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2180 case REPOKEY_TYPE_ID:
2181 case REPOKEY_TYPE_NUM:
2182 case REPOKEY_TYPE_DIR:
2183 data_addid(xd, val);
2185 case REPOKEY_TYPE_IDARRAY:
2186 for (ida = data->attriddata + val; *ida; ida++)
2187 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2189 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2190 for (ida = data->attriddata + val; *ida; ida += 3)
2192 data_addid(xd, ida[0]);
2193 data_addid(xd, ida[1]);
2194 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2197 case REPOKEY_TYPE_DIRSTRARRAY:
2198 for (ida = data->attriddata + val; *ida; ida += 2)
2200 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2201 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2204 case REPOKEY_TYPE_FIXARRAY:
2208 for (ida = data->attriddata + val; *ida; ida++)
2211 fprintf(stderr, "serialize struct %d\n", *ida);
2214 Id *kp = data->xattrs[-*ida];
2221 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2227 schemaid = repodata_schema2id(data, schema, 1);
2228 else if (schemaid != repodata_schema2id(data, schema, 0))
2230 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2234 fprintf(stderr, " schema %d\n", schemaid);
2239 data_addid(xd, num);
2240 data_addid(xd, schemaid);
2241 for (ida = data->attriddata + val; *ida; ida++)
2243 Id *kp = data->xattrs[-*ida];
2248 repodata_serialize_key(data, newincore, newvincore,
2249 schema, data->keys + *kp, kp[1]);
2254 case REPOKEY_TYPE_FLEXARRAY:
2257 for (ida = data->attriddata + val; *ida; ida++)
2259 data_addid(xd, num);
2260 for (ida = data->attriddata + val; *ida; ida++)
2262 Id *kp = data->xattrs[-*ida];
2265 data_addid(xd, 0); /* XXX */
2272 schemaid = repodata_schema2id(data, schema, 1);
2273 data_addid(xd, schemaid);
2274 kp = data->xattrs[-*ida];
2277 repodata_serialize_key(data, newincore, newvincore,
2278 schema, data->keys + *kp, kp[1]);
2284 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2287 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2289 /* put offset/len in incore */
2290 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2291 oldvincorelen = xd->len - oldvincorelen;
2292 data_addid(newincore, oldvincorelen);
2297 repodata_internalize(Repodata *data)
2299 Repokey *key, solvkey;
2301 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2302 unsigned char *dp, *ndp;
2303 int newschema, oldcount;
2304 struct extdata newincore;
2305 struct extdata newvincore;
2308 if (!data->attrs && !data->xattrs)
2311 newvincore.buf = data->vincore;
2312 newvincore.len = data->vincorelen;
2314 /* find the solvables key, create if needed */
2315 memset(&solvkey, 0, sizeof(solvkey));
2316 solvkey.name = REPOSITORY_SOLVABLES;
2317 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2319 solvkey.storage = KEY_STORAGE_INCORE;
2320 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2322 schema = sat_malloc2(data->nkeys, sizeof(Id));
2323 seen = sat_malloc2(data->nkeys, sizeof(Id));
2325 /* Merge the data already existing (in data->schemata, ->incoredata and
2326 friends) with the new attributes in data->attrs[]. */
2327 nentry = data->end - data->start;
2328 memset(&newincore, 0, sizeof(newincore));
2329 data_addid(&newincore, 0); /* start data at offset 1 */
2331 data->mainschema = 0;
2332 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2334 /* join entry data */
2335 /* we start with the meta data, entry -1 */
2336 for (entry = -1; entry < nentry; entry++)
2338 memset(seen, 0, data->nkeys * sizeof(Id));
2340 dp = data->incoredata;
2343 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2344 dp = data_read_id(dp, &oldschema);
2347 fprintf(stderr, "oldschema %d\n", oldschema);
2348 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2349 fprintf(stderr, "schemadata %p\n", data->schemadata);
2351 /* seen: -1: old data 0: skipped >0: id + 1 */
2355 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2359 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2367 keyp = data->attrs ? data->attrs[entry] : 0;
2370 /* strip solvables key */
2372 for (sp = keyp = schema; *sp; sp++)
2373 if (*sp != solvkeyid)
2378 seen[solvkeyid] = 0;
2379 keyp = data->xattrs ? data->xattrs[1] : 0;
2382 for (; *keyp; keyp += 2)
2389 seen[*keyp] = keyp[1] + 1;
2391 if (entry < 0 && data->end != data->start)
2398 /* Ideally we'd like to sort the new schema here, to ensure
2399 schema equality independend of the ordering. We can't do that
2400 yet. For once see below (old ids need to come before new ids).
2401 An additional difficulty is that we also need to move
2402 the values with the keys. */
2403 schemaid = repodata_schema2id(data, schema, 1);
2405 schemaid = oldschema;
2408 /* Now create data blob. We walk through the (possibly new) schema
2409 and either copy over old data, or insert the new. */
2410 /* XXX Here we rely on the fact that the (new) schema has the form
2411 o1 o2 o3 o4 ... | n1 n2 n3 ...
2412 (oX being the old keyids (possibly overwritten), and nX being
2413 the new keyids). This rules out sorting the keyids in order
2414 to ensure a small schema count. */
2416 data->incoreoffset[entry] = newincore.len;
2417 data_addid(&newincore, schemaid);
2420 data->mainschema = schemaid;
2421 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2423 keypstart = data->schemadata + data->schemata[schemaid];
2424 for (keyp = keypstart; *keyp; keyp++)
2427 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2428 if (*keyp == solvkeyid)
2430 /* add flexarray entry count */
2431 data_addid(&newincore, data->end - data->start);
2434 key = data->keys + *keyp;
2436 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2441 /* Skip the data associated with this old key. */
2442 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2444 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2445 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2447 else if (key->storage == KEY_STORAGE_INCORE)
2448 ndp = data_skip_key(data, dp, key);
2451 if (seen[*keyp] == -1)
2453 /* If this key was an old one _and_ was not overwritten with
2454 a different value copy over the old value (we skipped it
2457 data_addblob(&newincore, dp, ndp - dp);
2460 else if (seen[*keyp])
2462 /* Otherwise we have a new value. Parse it into the internal
2464 repodata_serialize_key(data, &newincore, &newvincore,
2465 schema, key, seen[*keyp] - 1);
2469 if (entry >= 0 && data->attrs && data->attrs[entry])
2470 data->attrs[entry] = sat_free(data->attrs[entry]);
2472 /* free all xattrs */
2473 for (entry = 0; entry < data->nxattrs; entry++)
2474 if (data->xattrs[entry])
2475 sat_free(data->xattrs[entry]);
2476 data->xattrs = sat_free(data->xattrs);
2479 data->lasthandle = 0;
2481 data->lastdatalen = 0;
2484 repodata_free_schemahash(data);
2486 sat_free(data->incoredata);
2487 data->incoredata = newincore.buf;
2488 data->incoredatalen = newincore.len;
2489 data->incoredatafree = 0;
2491 sat_free(data->vincore);
2492 data->vincore = newvincore.buf;
2493 data->vincorelen = newvincore.len;
2495 data->attrs = sat_free(data->attrs);
2496 data->attrdata = sat_free(data->attrdata);
2497 data->attriddata = sat_free(data->attriddata);
2498 data->attrdatalen = 0;
2499 data->attriddatalen = 0;
2503 repodata_disable_paging(Repodata *data)
2505 if (maybe_load_repodata(data, 0))
2506 repopagestore_disable_paging(&data->store);
2510 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: