2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
27 #include "poolid_private.h"
33 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
34 unsigned char *out, unsigned int out_len);
35 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
38 unsigned int out_len);
40 #define REPODATA_BLOCK 255
44 repodata_init(Repodata *data, Repo *repo, int localpool)
46 memset(data, 0, sizeof (*data));
48 data->localpool = localpool;
50 stringpool_init_empty(&data->spool);
51 data->keys = sat_calloc(1, sizeof(Repokey));
53 data->schemata = sat_calloc(1, sizeof(Id));
54 data->schemadata = sat_calloc(1, sizeof(Id));
56 data->schemadatalen = 1;
57 repopagestore_init(&data->store);
61 repodata_free(Repodata *data)
67 sat_free(data->schemata);
68 sat_free(data->schemadata);
69 sat_free(data->schematahash);
71 stringpool_free(&data->spool);
72 dirpool_free(&data->dirpool);
74 sat_free(data->mainschemaoffsets);
75 sat_free(data->incoredata);
76 sat_free(data->incoreoffset);
77 sat_free(data->verticaloffset);
79 repopagestore_free(&data->store);
81 sat_free(data->vincore);
84 for (i = 0; i < data->end - data->start; i++)
85 sat_free(data->attrs[i]);
86 sat_free(data->attrs);
88 for (i = 0; i < data->nxattrs; i++)
89 sat_free(data->xattrs[i]);
90 sat_free(data->xattrs);
92 sat_free(data->attrdata);
93 sat_free(data->attriddata);
97 /***************************************************************
101 /* this is not so time critical that we need a hash, so we do a simple
104 repodata_key2id(Repodata *data, Repokey *key, int create)
108 for (keyid = 1; keyid < data->nkeys; keyid++)
109 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
111 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
115 if (keyid == data->nkeys)
119 /* allocate new key */
120 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
121 data->keys[data->nkeys++] = *key;
122 if (data->verticaloffset)
124 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
125 data->verticaloffset[data->nkeys - 1] = 0;
127 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
133 /***************************************************************
134 * schema pool management
137 #define SCHEMATA_BLOCK 31
138 #define SCHEMATADATA_BLOCK 255
141 repodata_schema2id(Repodata *data, Id *schema, int create)
147 if ((schematahash = data->schematahash) == 0)
149 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
150 for (i = 0; i < data->nschemata; i++)
152 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
155 schematahash[h] = i + 1;
157 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
158 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
161 for (sp = schema, len = 0, h = 0; *sp; len++)
166 cid = schematahash[h];
170 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
173 for (cid = 0; cid < data->nschemata; cid++)
174 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
180 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
181 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
183 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
184 data->schemata[data->nschemata] = data->schemadatalen;
185 data->schemadatalen += len;
186 schematahash[h] = data->nschemata + 1;
188 fprintf(stderr, "schema2id: new schema\n");
190 return data->nschemata++;
194 repodata_free_schemahash(Repodata *data)
196 data->schematahash = sat_free(data->schematahash);
198 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
199 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
203 /***************************************************************
204 * dir pool management
208 repodata_str2dir(Repodata *data, const char *dir, int create)
214 while (*dir == '/' && dir[1] == '/')
216 if (*dir == '/' && !dir[1])
220 dire = strchrnul(dir, '/');
222 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
224 id = strn2id(data->repo->pool, dir, dire - dir, create);
227 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
240 repodata_dir2str(Repodata *data, Id did, const char *suf)
242 Pool *pool = data->repo->pool;
249 return suf ? suf : "";
253 comp = dirpool_compid(&data->dirpool, parent);
254 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
256 parent = dirpool_parent(&data->dirpool, parent);
261 l += strlen(suf) + 1;
262 p = pool_alloctmpspace(pool, l + 1) + l;
273 comp = dirpool_compid(&data->dirpool, parent);
274 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
277 strncpy(p, comps, l);
278 parent = dirpool_parent(&data->dirpool, parent);
286 /***************************************************************
290 static inline unsigned char *
291 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
293 Id *keyp = data->schemadata + data->schemata[schema];
294 for (; *keyp; keyp++)
295 dp = data_skip_key(data, dp, data->keys + *keyp);
300 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
302 int nentries, schema;
305 case REPOKEY_TYPE_FIXARRAY:
306 dp = data_read_id(dp, &nentries);
309 dp = data_read_id(dp, &schema);
311 dp = data_skip_schema(data, dp, schema);
313 case REPOKEY_TYPE_FLEXARRAY:
314 dp = data_read_id(dp, &nentries);
317 dp = data_read_id(dp, &schema);
318 dp = data_skip_schema(data, dp, schema);
322 if (key->storage == KEY_STORAGE_INCORE)
323 dp = data_skip(dp, key->type);
324 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
326 dp = data_skip(dp, REPOKEY_TYPE_ID);
327 dp = data_skip(dp, REPOKEY_TYPE_ID);
333 static unsigned char *
334 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
340 while ((k = *keyp++) != 0)
344 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
346 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
347 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
350 if (data->keys[k].storage != KEY_STORAGE_INCORE)
352 dp = data_skip_key(data, dp, data->keys + k);
357 static unsigned char *
358 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
363 if (off >= data->lastverticaloffset)
365 off -= data->lastverticaloffset;
366 if (off + len > data->vincorelen)
368 return data->vincore + off;
370 if (off + len > key->size)
372 /* we now have the offset, go into vertical */
373 off += data->verticaloffset[key - data->keys];
374 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
375 dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
377 dp += off % BLOB_PAGESIZE;
381 static inline unsigned char *
382 get_data(Repodata *data, Repokey *key, unsigned char **dpp)
384 unsigned char *dp = *dpp;
388 if (key->storage == KEY_STORAGE_INCORE)
390 /* hmm, this is a bit expensive */
391 *dpp = data_skip_key(data, dp, key);
394 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
397 dp = data_read_id(dp, &off);
398 dp = data_read_id(dp, &len);
400 return get_vertical_data(data, key, off, len);
406 load_repodata(Repodata *data)
408 if (data->loadcallback)
410 data->loadcallback(data);
411 if (data->state == REPODATA_AVAILABLE)
414 data->state = REPODATA_ERROR;
419 maybe_load_repodata(Repodata *data, Id keyname)
421 if (keyname && !repodata_precheck_keyname(data, keyname))
422 return 0; /* do not bother... */
429 for (i = 0; i < data->nkeys; i++)
430 if (keyname == data->keys[i].name)
432 if (i == data->nkeys)
435 return load_repodata(data);
438 case REPODATA_AVAILABLE:
441 data->state = REPODATA_ERROR;
446 static inline unsigned char*
447 entry2data(Repodata *data, Id entry, Id *schemap)
449 unsigned char *dp = data->incoredata;
452 if (entry == SOLVID_META) /* META */
454 else if (entry == SOLVID_POS) /* META */
456 Pool *pool = data->repo->pool;
457 if (data->repo != pool->pos.repo)
459 if (data != data->repo->repodata + pool->pos.repodataid)
461 *schemap = pool->pos.schema;
462 return data->incoredata + pool->pos.dp;
466 if (entry < data->start || entry >= data->end)
468 dp += data->incoreoffset[entry - data->start];
470 return data_read_id(dp, schemap);
473 /************************************************************************
478 find_schema_key(Repodata *data, Id schema, Id keyname)
481 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
482 if (data->keys[*keyp].name == keyname)
487 static inline unsigned char *
488 find_key_data(Repodata *data, Id entry, Id keyname, Repokey **keyp)
490 unsigned char *dp, *ddp;
494 if (!maybe_load_repodata(data, keyname))
496 dp = entry2data(data, entry, &schema);
499 keyid = find_schema_key(data, schema, keyname);
502 key = data->keys + keyid;
504 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
506 dp = forward_to_key(data, keyid, data->schemadata + data->schemata[schema], dp);
509 ddp = get_data(data, key, &dp);
515 repodata_lookup_id(Repodata *data, Id entry, Id keyname)
521 dp = find_key_data(data, entry, keyname, &key);
524 if (key->type == REPOKEY_TYPE_CONSTANTID)
526 if (key->type != REPOKEY_TYPE_ID)
528 dp = data_read_id(dp, &id);
533 repodata_lookup_str(Repodata *data, Id entry, Id keyname)
539 dp = find_key_data(data, entry, keyname, &key);
542 if (key->type == REPOKEY_TYPE_STR)
543 return (const char *)dp;
544 if (key->type == REPOKEY_TYPE_CONSTANTID)
545 return id2str(data->repo->pool, key->size);
546 if (key->type == REPOKEY_TYPE_ID)
547 dp = data_read_id(dp, &id);
551 return data->spool.stringspace + data->spool.strings[id];
552 return id2str(data->repo->pool, id);
556 repodata_lookup_num(Repodata *data, Id entry, Id keyname, unsigned int *value)
563 dp = find_key_data(data, entry, keyname, &key);
566 if (key->type == REPOKEY_TYPE_NUM
567 || key->type == REPOKEY_TYPE_U32
568 || key->type == REPOKEY_TYPE_CONSTANT)
570 dp = data_fetch(dp, &kv, key);
578 repodata_lookup_void(Repodata *data, Id entry, Id keyname)
584 if (!maybe_load_repodata(data, keyname))
586 dp = entry2data(data, entry, &schema);
589 /* can't use find_schema_key as we need to test the type */
590 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
591 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
596 const unsigned char *
597 repodata_lookup_bin_checksum(Repodata *data, Id entry, Id keyname, Id *typep)
602 dp = find_key_data(data, entry, keyname, &key);
610 /************************************************************************
614 struct subschema_data {
620 /* search in a specific entry */
622 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
626 Id k, keyid, *kp, *keyp;
627 unsigned char *dp, *ddp;
633 if (!maybe_load_repodata(data, keyname))
635 if (entry == SOLVID_SUBSCHEMA)
637 struct subschema_data *subd = cbdata;
638 cbdata = subd->cbdata;
640 schema = subd->parent->id;
641 dp = (unsigned char *)subd->parent->str;
642 kv.parent = subd->parent;
647 dp = entry2data(data, entry, &schema);
650 s = data->repo->pool->solvables + entry;
653 keyp = data->schemadata + data->schemata[schema];
656 /* search for a specific key */
657 for (kp = keyp; (k = *kp++) != 0; )
658 if (data->keys[k].name == keyname)
662 dp = forward_to_key(data, k, data->schemadata + data->schemata[schema], dp);
668 while ((keyid = *keyp++) != 0)
671 key = data->keys + keyid;
672 ddp = get_data(data, key, &dp);
674 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
676 struct subschema_data subd;
680 subd.cbdata = cbdata;
683 ddp = data_read_id(ddp, &nentries);
687 while (ddp && nentries > 0)
689 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
690 ddp = data_read_id(ddp, &schema);
692 kv.str = (char *)ddp;
693 stop = callback(cbdata, s, data, key, &kv);
694 if (stop > SEARCH_NEXT_KEY)
699 repodata_search(data, SOLVID_SUBSCHEMA, 0, callback, &subd);
700 ddp = data_skip_schema(data, ddp, schema);
708 kv.str = (char *)ddp;
709 stop = callback(cbdata, s, data, key, &kv);
710 if (stop > SEARCH_NEXT_KEY)
720 ddp = data_fetch(ddp, &kv, key);
723 stop = callback(cbdata, s, data, key, &kv);
726 while (!kv.eof && !stop);
727 if (onekey || stop > SEARCH_NEXT_KEY)
733 repodata_setpos_kv(Repodata *data, KeyValue *kv)
735 Pool *pool = data->repo->pool;
739 pool->pos.repodataid = 0;
741 pool->pos.schema = 0;
746 pool->pos.repodataid = data - data->repo->repodata;
747 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
748 pool->pos.schema = kv->id;
752 /************************************************************************/
754 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
755 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
756 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
757 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
758 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
759 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
760 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
761 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
762 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
763 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
764 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
765 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
766 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
767 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
772 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
786 case SOLVABLE_VENDOR:
789 case SOLVABLE_PROVIDES:
791 return s->provides ? s->repo->idarraydata + s->provides : 0;
792 case SOLVABLE_OBSOLETES:
794 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
795 case SOLVABLE_CONFLICTS:
797 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
798 case SOLVABLE_REQUIRES:
800 return s->requires ? s->repo->idarraydata + s->requires : 0;
801 case SOLVABLE_RECOMMENDS:
803 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
804 case SOLVABLE_SUPPLEMENTS:
806 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
807 case SOLVABLE_SUGGESTS:
809 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
810 case SOLVABLE_ENHANCES:
812 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
815 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
822 datamatcher_init(Datamatcher *ma, Pool *pool, const char *match, int flags)
825 ma->match = (void *)match;
828 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
830 ma->match = sat_calloc(1, sizeof(regex_t));
831 ma->error = regcomp((regex_t *)ma->match, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
835 ma->match = (void *)match;
836 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
842 datamatcher_free(Datamatcher *ma)
844 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->match)
847 ma->match = sat_free(ma->match);
852 datamatcher_match(Datamatcher *ma, Repodata *data, Repokey *key, KeyValue *kv)
856 case REPOKEY_TYPE_ID:
857 case REPOKEY_TYPE_IDARRAY:
858 if (data && data->localpool)
859 kv->str = stringpool_id2str(&data->spool, kv->id);
861 kv->str = id2str(ma->pool, kv->id);
863 case REPOKEY_TYPE_STR:
865 case REPOKEY_TYPE_DIRSTRARRAY:
866 if (!(ma->flags & SEARCH_FILES))
868 /* Put the full filename into kv->str. */
869 kv->str = repodata_dir2str(data, kv->id, kv->str);
870 /* And to compensate for that put the "empty" directory into
871 kv->id, so that later calls to repodata_dir2str on this data
872 come up with the same filename again. */
878 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
879 for the others we can't know if a colon separates a kind or not. */
880 if ((ma->flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
882 const char *s = strchr(kv->str, ':');
886 switch ((ma->flags & SEARCH_STRINGMASK))
888 case SEARCH_SUBSTRING:
889 if (ma->flags & SEARCH_NOCASE)
891 if (!strcasestr(kv->str, (const char *)ma->match))
896 if (!strstr(kv->str, (const char *)ma->match))
901 if (ma->flags & SEARCH_NOCASE)
903 if (strcasecmp((const char *)ma->match, kv->str))
908 if (strcmp((const char *)ma->match, kv->str))
913 if (fnmatch((const char *)ma->match, kv->str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
917 if (regexec((const regex_t *)ma->match, kv->str, 0, NULL, 0))
950 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname, const char *match, int flags)
952 memset(di, 0, sizeof(*di));
954 di->keyname = keyname;
956 di->pool = repo->pool;
958 flags |= SEARCH_THISSOLVID;
963 datamatcher_init(&di->matcher, di->pool, match, flags);
966 di->repo = di->pool->pos.repo;
972 di->data = di->repo->repodata + di->pool->pos.repodataid;
976 di->state = di_enterrepo;
980 dataiterator_free(Dataiterator *di)
982 if (di->matcher.match)
983 datamatcher_free(&di->matcher);
987 dataiterator_step(Dataiterator *di)
995 case di_nextattr: di_nextattr:
997 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
999 di->state = di_nextkey;
1001 di->state = di_nextattr;
1004 case di_nextkey: di_nextkey:
1010 else if ((di->flags & SEARCH_SUB) != 0)
1012 Id *keyp = di->keyp;
1013 for (keyp++; *keyp; keyp++)
1014 if (di->data->keys[*keyp].name == di->keyname ||
1015 di->data->keys[*keyp].type == REPOKEY_TYPE_FIXARRAY ||
1016 di->data->keys[*keyp].type == REPOKEY_TYPE_FLEXARRAY)
1018 if (*keyp && (di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp)) != 0)
1029 case di_nextrepodata: di_nextrepodata:
1030 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1031 goto di_enterrepodata;
1034 case di_nextsolvable:
1035 if (!(di->flags & SEARCH_THISSOLVID))
1038 di->solvid = di->repo->start;
1041 for (; di->solvid < di->repo->end; di->solvid++)
1043 if (di->pool->solvables[di->solvid].repo == di->repo)
1044 goto di_entersolvable;
1050 if (di->repoid >= 0)
1053 if (di->repoid < di->pool->nrepos)
1055 di->repo = di->pool->repos[di->repoid];
1065 case di_enterrepo: di_enterrepo:
1066 if (!(di->flags & SEARCH_THISSOLVID))
1067 di->solvid = di->repo->start;
1070 case di_entersolvable: di_entersolvable:
1071 if (di->repodataid >= 0)
1074 if (di->solvid > 0 && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)))
1076 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1078 goto di_entersolvablekey;
1082 case di_enterrepodata: di_enterrepodata:
1083 if (di->repodataid >= 0)
1084 di->data = di->repo->repodata + di->repodataid;
1085 if (!maybe_load_repodata(di->data, di->keyname))
1086 goto di_nextrepodata;
1087 di->dp = entry2data(di->data, di->solvid, &schema);
1089 goto di_nextrepodata;
1090 di->keyp = di->data->schemadata + di->data->schemata[schema];
1094 if ((di->flags & SEARCH_SUB) != 0)
1099 for (keyp = di->keyp; *keyp; keyp++)
1100 if (di->data->keys[*keyp].name == di->keyname)
1103 goto di_nextrepodata;
1104 di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1107 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);
1116 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1118 di->ddp = data_read_id(di->ddp, &di->kv.num);
1121 goto di_nextarrayelement;
1125 case di_nextarrayelement: di_nextarrayelement:
1128 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1129 if (di->kv.entry == di->kv.num)
1131 if (di->keyname && di->key->name != di->keyname)
1133 di->kv.str = (char *)di->ddp;
1135 di->state = di_nextkey;
1138 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1139 di->ddp = data_read_id(di->ddp, &di->kv.id);
1140 di->kv.str = (char *)di->ddp;
1141 if (di->keyname && di->key->name != di->keyname)
1143 if ((di->flags & SEARCH_SUB) != 0)
1144 di->state = di_entersub;
1146 di->state = di_nextarrayelement;
1149 case di_entersub: di_entersub:
1150 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1151 goto di_nextarrayelement; /* sorry, full */
1152 di->parents[di->nparents].kv = di->kv;
1153 di->parents[di->nparents].dp = di->dp;
1154 di->parents[di->nparents].keyp = di->keyp;
1155 di->dp = (unsigned char *)di->kv.str;
1156 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1157 memset(&di->kv, 0, sizeof(di->kv));
1158 di->kv.parent = &di->parents[di->nparents].kv;
1163 case di_leavesub: di_leavesub:
1165 di->dp = di->parents[di->nparents].dp;
1166 di->kv = di->parents[di->nparents].kv;
1167 di->keyp = di->parents[di->nparents].keyp;
1168 di->key = di->data->keys + *di->keyp;
1169 di->ddp = (unsigned char *)di->kv.str;
1170 goto di_nextarrayelement;
1172 /* special solvable attr handling follows */
1174 case di_nextsolvableattr:
1175 di->kv.id = *di->idp++;
1180 di->state = di_nextsolvablekey;
1184 case di_nextsolvablekey: di_nextsolvablekey:
1185 if (di->keyname || di->key->name == RPM_RPMDBID)
1186 goto di_enterrepodata;
1190 case di_entersolvablekey: di_entersolvablekey:
1191 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1192 if (!di->idp || !di->idp[0])
1193 goto di_nextsolvablekey;
1194 di->kv.id = di->idp[0];
1195 di->kv.num = di->idp[0];
1196 if (!di->kv.eof && !di->idp[1])
1200 di->state = di_nextsolvablekey;
1202 di->state = di_nextsolvableattr;
1206 if (di->matcher.match)
1207 if (!datamatcher_match(&di->matcher, di->data, di->key, &di->kv))
1209 /* found something! */
1215 dataiterator_setpos(Dataiterator *di)
1219 memset(&di->pool->pos, 0, sizeof(di->pool->pos));
1222 di->pool->pos.repo = di->repo;
1223 di->pool->pos.repodataid = di->data - di->repo->repodata;
1224 di->pool->pos.schema = di->kv.id;
1225 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1229 dataiterator_setpos_parent(Dataiterator *di)
1233 memset(&di->pool->pos, 0, sizeof(di->pool->pos));
1236 di->pool->pos.repo = di->repo;
1237 di->pool->pos.repodataid = di->data - di->repo->repodata;
1238 di->pool->pos.schema = di->kv.parent->id;
1239 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1243 dataiterator_skip_attribute(Dataiterator *di)
1245 if (di->state == di_nextsolvableattr)
1246 di->state = di_nextsolvablekey;
1248 di->state = di_nextkey;
1252 dataiterator_skip_solvable(Dataiterator *di)
1254 di->state = di_nextsolvable;
1258 dataiterator_skip_repo(Dataiterator *di)
1260 di->state = di_nextrepo;
1264 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1268 di->solvid = s - di->pool->solvables;
1269 di->state = di_entersolvable;
1273 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1277 di->state = di_enterrepo;
1281 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1283 Datamatcher matcher = di->matcher;
1284 matcher.flags = flags;
1285 matcher.match = (void *)vmatch;
1286 matcher.pool = di->pool;
1287 return datamatcher_match(&matcher, di->data, di->key, &di->kv);
1292 /************************************************************************
1293 * data search iterator
1297 dataiterator_newdata(Dataiterator *di)
1299 Id keyname = di->keyname;
1300 Repodata *data = di->data;
1303 if (data->state == REPODATA_STUB)
1308 for (j = 1; j < data->nkeys; j++)
1309 if (keyname == data->keys[j].name)
1311 if (j == data->nkeys)
1315 if (data->loadcallback)
1316 data->loadcallback(data);
1318 data->state = REPODATA_ERROR;
1320 if (data->state == REPODATA_ERROR)
1324 unsigned char *dp = data->incoredata;
1327 if (di->solvid >= 0)
1328 dp += data->incoreoffset[di->solvid - data->start];
1329 dp = data_read_id(dp, &schema);
1330 Id *keyp = data->schemadata + data->schemata[schema];
1334 /* search in a specific key */
1335 for (kp = keyp; (k = *kp++) != 0; )
1336 if (data->keys[k].name == keyname)
1340 dp = forward_to_key(data, k, keyp, dp);
1350 di->key = di->data->keys + keyid;
1355 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1360 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname,
1361 const char *match, int flags)
1367 di->flags |= __SEARCH_ONESOLVABLE;
1368 di->data = repo->repodata - 1;
1369 if (flags & SEARCH_NO_STORAGE_SOLVABLE)
1376 di->solvid = repo->start - 1;
1379 fprintf(stderr, "A repo contains the NULL solvable!\n");
1382 di->data = repo->repodata + repo->nrepodata - 1;
1387 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1391 /* We feed multiple lines eventually (e.g. authors or descriptions),
1392 so set REG_NEWLINE. */
1394 regcomp(&di->regex, di->match,
1395 REG_EXTENDED | REG_NOSUB | REG_NEWLINE
1396 | ((di->flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1398 if (di->regex_err != 0)
1400 fprintf(stderr, "Given regex failed to compile: %s\n", di->match);
1401 fprintf(stderr, "regcomp error code: %d\n", di->regex_err);
1408 di->flags |= (di->flags & SEARCH_STRINGMASK) | SEARCH_STRING;
1414 di->keyname = keyname;
1415 static Id zeroid = 0;
1423 /* FIXME factor and merge with repo_matchvalue */
1425 dataiterator_match_int_real(Dataiterator *di, int flags, const void *vmatch)
1427 KeyValue *kv = &di->kv;
1428 const char *match = vmatch;
1429 if ((flags & SEARCH_STRINGMASK) != 0)
1431 switch (di->key->type)
1433 case REPOKEY_TYPE_ID:
1434 case REPOKEY_TYPE_IDARRAY:
1435 if (di->data && di->data->localpool)
1436 kv->str = stringpool_id2str(&di->data->spool, kv->id);
1438 kv->str = id2str(di->repo->pool, kv->id);
1440 case REPOKEY_TYPE_STR:
1442 case REPOKEY_TYPE_DIRSTRARRAY:
1443 if (!(flags & SEARCH_FILES))
1445 /* Put the full filename into kv->str. */
1446 kv->str = repodata_dir2str(di->data, kv->id, kv->str);
1447 /* And to compensate for that put the "empty" directory into
1448 kv->id, so that later calls to repodata_dir2str on this data
1449 come up with the same filename again. */
1455 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
1456 for the others we can't know if a colon separates a kind or not. */
1457 if ((flags & SEARCH_SKIP_KIND)
1458 && di->key->storage == KEY_STORAGE_SOLVABLE)
1460 const char *s = strchr(kv->str, ':');
1464 switch ((flags & SEARCH_STRINGMASK))
1466 case SEARCH_SUBSTRING:
1467 if (flags & SEARCH_NOCASE)
1469 if (!strcasestr(kv->str, match))
1474 if (!strstr(kv->str, match))
1479 if (flags & SEARCH_NOCASE)
1481 if (strcasecmp(match, kv->str))
1486 if (strcmp(match, kv->str))
1491 if (fnmatch(match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
1495 if (regexec((const regex_t *)vmatch, kv->str, 0, NULL, 0))
1506 dataiterator_match_int(Dataiterator *di)
1508 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1509 return dataiterator_match_int_real(di, di->flags, &di->regex);
1511 return dataiterator_match_int_real(di, di->flags, di->match);
1515 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1517 return dataiterator_match_int_real(di, flags, vmatch);
1521 dataiterator_step(Dataiterator *di)
1528 /* we're stepping through solvable data, 1 -> SOLVABLE_NAME... */
1531 /* we're stepping through an id array */
1537 di->kv.eof = idp[1] ? 0 : 1;
1543 Solvable *s = di->repo->pool->solvables + di->solvid;
1544 int state = di->state;
1545 di->key = solvablekeys + state - 1;
1547 di->state = RPM_RPMDBID;
1554 state = di->keyname - 1;
1561 di->kv.id = s->name;
1567 di->kv.id = s->arch;
1576 case SOLVABLE_VENDOR:
1579 di->kv.id = s->vendor;
1582 case SOLVABLE_PROVIDES:
1583 di->idp = s->provides
1584 ? di->repo->idarraydata + s->provides : 0;
1586 case SOLVABLE_OBSOLETES:
1587 di->idp = s->obsoletes
1588 ? di->repo->idarraydata + s->obsoletes : 0;
1590 case SOLVABLE_CONFLICTS:
1591 di->idp = s->conflicts
1592 ? di->repo->idarraydata + s->conflicts : 0;
1594 case SOLVABLE_REQUIRES:
1595 di->idp = s->requires
1596 ? di->repo->idarraydata + s->requires : 0;
1598 case SOLVABLE_RECOMMENDS:
1599 di->idp = s->recommends
1600 ? di->repo->idarraydata + s->recommends : 0;
1602 case SOLVABLE_SUPPLEMENTS:
1603 di->idp = s->supplements
1604 ? di->repo->idarraydata + s->supplements : 0;
1606 case SOLVABLE_SUGGESTS:
1607 di->idp = s->suggests
1608 ? di->repo->idarraydata + s->suggests : 0;
1610 case SOLVABLE_ENHANCES:
1611 di->idp = s->enhances
1612 ? di->repo->idarraydata + s->enhances : 0;
1615 if (!di->repo->rpmdbid)
1617 di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
1621 di->data = di->repo->repodata - 1;
1627 else if (di->subkeyp)
1632 /* Send end-of-substruct. We are here only when we saw a
1633 _COUNTED key one level up. Since then we didn't increment
1634 ->keyp, so it still can be found at keyp[-1]. */
1636 di->key = di->data->keys + di->keyp[-1];
1639 else if (!(keyid = *di->subkeyp++))
1641 /* Send end-of-element. See above for keyp[-1]. */
1643 di->key = di->data->keys + di->keyp[-1];
1645 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1648 di->dp = data_read_id(di->dp, &di->subschema);
1649 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1656 di->key = di->data->keys + keyid;
1657 di->dp = data_fetch(di->dp, &di->kv, di->key);
1667 di->dp = data_fetch(di->dp, &di->kv, di->key);
1672 if (di->keyname || !(keyid = *di->keyp++))
1676 Repo *repo = di->repo;
1677 Repodata *data = ++di->data;
1678 if (data >= repo->repodata + repo->nrepodata)
1680 if (di->flags & __SEARCH_ONESOLVABLE)
1682 if (di->solvid >= 0)
1684 while (++di->solvid < repo->end)
1685 if (repo->pool->solvables[di->solvid].repo == repo)
1687 if (di->solvid >= repo->end)
1689 if (!(di->flags & SEARCH_EXTRA))
1698 Pool *pool = di->repo->pool;
1699 if (!(di->flags & SEARCH_ALL_REPOS)
1700 || di->repo == pool->repos[pool->nrepos - 1])
1703 for (i = 0; i < pool->nrepos; i++)
1704 if (di->repo == pool->repos[i])
1706 di->repo = pool->repos[i + 1];
1707 dataiterator_init(di, di->repo, 0, di->keyname, di->match, di->flags);
1711 di->data = repo->repodata - 1;
1712 if ((di->flags & SEARCH_NO_STORAGE_SOLVABLE))
1714 static Id zeroid = 0;
1719 if ((di->solvid >= 0 && di->solvid >= data->start && di->solvid < data->end))
1721 dataiterator_newdata(di);
1729 di->key = di->data->keys + keyid;
1730 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1732 di->dp = data_fetch(di->dp, &di->kv, di->key);
1734 if (di->key->type == REPOKEY_TYPE_FIXARRAY)
1736 di->subnum = di->kv.num;
1737 di->subschema = di->kv.id;
1739 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1741 if (di->key->type == REPOKEY_TYPE_FLEXARRAY)
1743 di->subnum = di->kv.num;
1745 di->dp = data_read_id(di->dp, &di->subschema);
1746 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1752 || dataiterator_match_int(di))
1759 dataiterator_skip_attribute(Dataiterator *di)
1763 /* This will make the next _step call to retrieve the next field. */
1768 dataiterator_skip_solvable(Dataiterator *di)
1770 /* We're done with this field. */
1772 /* And with solvable data. */
1774 /* And with all keys for this repodata and thing. */
1775 static Id zeroid = 0;
1777 /* And with all repodatas for this thing. */
1778 di->data = di->repo->repodata + di->repo->nrepodata - 1;
1779 /* Hence the next call to _step will retrieve the next thing. */
1783 dataiterator_skip_repo(Dataiterator *di)
1785 dataiterator_skip_solvable(di);
1786 /* We're done with all solvables and all extra things for this repo. */
1791 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1794 /* Simulate us being done with the solvable before the requested one. */
1795 dataiterator_skip_solvable(di);
1796 di->solvid = s - s->repo->pool->solvables;
1801 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1804 dataiterator_skip_solvable(di);
1805 di->solvid = repo->start - 1;
1810 /************************************************************************
1811 * data modify functions
1814 /* extend repodata so that it includes solvables p */
1816 repodata_extend(Repodata *data, Id p)
1818 if (data->start == data->end)
1819 data->start = data->end = p;
1822 int old = data->end - data->start;
1823 int new = p - data->end + 1;
1826 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id), REPODATA_BLOCK);
1827 memset(data->attrs + old, 0, new * sizeof(Id));
1829 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1830 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1833 if (p < data->start)
1835 int old = data->end - data->start;
1836 int new = data->start - p;
1839 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id), REPODATA_BLOCK);
1840 memmove(data->attrs + new, data->attrs, old * sizeof(Id));
1841 memset(data->attrs, 0, new * sizeof(Id));
1843 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1844 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1845 memset(data->incoreoffset, 0, new * sizeof(Id));
1851 repodata_extend_block(Repodata *data, Id start, Id num)
1855 if (!data->incoreoffset)
1857 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1858 data->start = start;
1859 data->end = start + num;
1862 repodata_extend(data, start);
1864 repodata_extend(data, start + num - 1);
1867 /**********************************************************************/
1869 #define REPODATA_ATTRS_BLOCK 63
1870 #define REPODATA_ATTRDATA_BLOCK 1023
1871 #define REPODATA_ATTRIDDATA_BLOCK 63
1875 repodata_new_handle(Repodata *data)
1879 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1882 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1883 data->xattrs[data->nxattrs] = 0;
1884 return -(data->nxattrs++);
1888 repodata_get_attrp(Repodata *data, Id handle)
1890 if (handle == SOLVID_META)
1894 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1899 return data->xattrs - handle;
1900 if (handle < data->start || handle >= data->end)
1901 repodata_extend(data, handle);
1903 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1904 return data->attrs + (handle - data->start);
1908 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1914 app = repodata_get_attrp(data, handle);
1919 for (pp = ap; *pp; pp += 2)
1920 /* Determine equality based on the name only, allows us to change
1921 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1922 if (data->keys[*pp].name == data->keys[keyid].name)
1935 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1945 repodata_set(Repodata *data, Id handle, Repokey *key, Id val)
1949 keyid = repodata_key2id(data, key, 1);
1950 repodata_insert_keyid(data, handle, keyid, val, 1);
1954 repodata_set_id(Repodata *data, Id handle, Id keyname, Id id)
1958 key.type = REPOKEY_TYPE_ID;
1960 key.storage = KEY_STORAGE_INCORE;
1961 repodata_set(data, handle, &key, id);
1965 repodata_set_num(Repodata *data, Id handle, Id keyname, unsigned int num)
1969 key.type = REPOKEY_TYPE_NUM;
1971 key.storage = KEY_STORAGE_INCORE;
1972 repodata_set(data, handle, &key, (Id)num);
1976 repodata_set_poolstr(Repodata *data, Id handle, Id keyname, const char *str)
1980 if (data->localpool)
1981 id = stringpool_str2id(&data->spool, str, 1);
1983 id = str2id(data->repo->pool, str, 1);
1985 key.type = REPOKEY_TYPE_ID;
1987 key.storage = KEY_STORAGE_INCORE;
1988 repodata_set(data, handle, &key, id);
1992 repodata_set_constant(Repodata *data, Id handle, Id keyname, unsigned int constant)
1996 key.type = REPOKEY_TYPE_CONSTANT;
1997 key.size = constant;
1998 key.storage = KEY_STORAGE_INCORE;
1999 repodata_set(data, handle, &key, 0);
2003 repodata_set_constantid(Repodata *data, Id handle, Id keyname, Id id)
2007 key.type = REPOKEY_TYPE_CONSTANTID;
2009 key.storage = KEY_STORAGE_INCORE;
2010 repodata_set(data, handle, &key, 0);
2014 repodata_set_void(Repodata *data, Id handle, Id keyname)
2018 key.type = REPOKEY_TYPE_VOID;
2020 key.storage = KEY_STORAGE_INCORE;
2021 repodata_set(data, handle, &key, 0);
2025 repodata_set_str(Repodata *data, Id handle, Id keyname, const char *str)
2030 l = strlen(str) + 1;
2032 key.type = REPOKEY_TYPE_STR;
2034 key.storage = KEY_STORAGE_INCORE;
2035 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2036 memcpy(data->attrdata + data->attrdatalen, str, l);
2037 repodata_set(data, handle, &key, data->attrdatalen);
2038 data->attrdatalen += l;
2042 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2045 Id *ida, *pp, **ppp;
2047 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2049 /* great! just append the new data */
2050 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2051 data->attriddatalen--; /* overwrite terminating 0 */
2052 data->lastdatalen += entrysize;
2055 ppp = repodata_get_attrp(data, handle);
2058 for (; *pp; pp += 2)
2059 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
2063 /* not found. allocate new key */
2068 key.storage = KEY_STORAGE_INCORE;
2069 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2070 repodata_set(data, handle, &key, data->attriddatalen);
2071 data->lasthandle = 0; /* next time... */
2075 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2076 oldsize += entrysize;
2077 if (ida + 1 == data->attriddata + data->attriddatalen)
2079 /* this was the last entry, just append it */
2080 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2081 data->attriddatalen--; /* overwrite terminating 0 */
2085 /* too bad. move to back. */
2086 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2087 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2088 pp[1] = data->attriddatalen;
2089 data->attriddatalen += oldsize;
2091 data->lasthandle = handle;
2092 data->lastkey = *pp;
2093 data->lastdatalen = data->attriddatalen + entrysize + 1;
2097 checksumtype2len(Id type)
2101 case REPOKEY_TYPE_MD5:
2103 case REPOKEY_TYPE_SHA1:
2105 case REPOKEY_TYPE_SHA256:
2106 return SIZEOF_SHA256;
2113 repodata_set_bin_checksum(Repodata *data, Id handle, Id keyname, Id type,
2114 const unsigned char *str)
2117 int l = checksumtype2len(type);
2124 key.storage = KEY_STORAGE_INCORE;
2125 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2126 memcpy(data->attrdata + data->attrdatalen, str, l);
2127 repodata_set(data, handle, &key, data->attrdatalen);
2128 data->attrdatalen += l;
2132 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
2135 for (i = 0; i < buflen; i++)
2137 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
2138 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
2139 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
2150 buf[i] = (buf[i] << 4) | v;
2157 repodata_set_checksum(Repodata *data, Id handle, Id keyname, Id type,
2160 unsigned char buf[64];
2161 int l = checksumtype2len(type);
2165 if (hexstr2bytes(buf, str, l) != l)
2167 fprintf(stderr, "Invalid hex character in '%s'\n", str);
2170 repodata_set_bin_checksum(data, handle, keyname, type, buf);
2174 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2179 l = checksumtype2len(type);
2182 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2183 for (i = 0; i < l; i++)
2185 unsigned char v = buf[i];
2186 unsigned char w = v >> 4;
2187 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2189 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2196 repodata_globalize_id(Repodata *data, Id id)
2198 if (!data || !data->localpool)
2200 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
2204 repodata_add_dirnumnum(Repodata *data, Id handle, Id keyname, Id dir, Id num, Id num2)
2208 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", handle, dir, num, num2, data->attriddatalen);
2210 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2211 data->attriddata[data->attriddatalen++] = dir;
2212 data->attriddata[data->attriddatalen++] = num;
2213 data->attriddata[data->attriddatalen++] = num2;
2214 data->attriddata[data->attriddatalen++] = 0;
2218 repodata_add_dirstr(Repodata *data, Id handle, Id keyname, Id dir, const char *str)
2224 l = strlen(str) + 1;
2225 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2226 memcpy(data->attrdata + data->attrdatalen, str, l);
2227 stroff = data->attrdatalen;
2228 data->attrdatalen += l;
2231 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", handle, dir, str, data->attriddatalen);
2233 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2234 data->attriddata[data->attriddatalen++] = dir;
2235 data->attriddata[data->attriddatalen++] = stroff;
2236 data->attriddata[data->attriddatalen++] = 0;
2240 repodata_add_idarray(Repodata *data, Id handle, Id keyname, Id id)
2243 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", handle, id, data->attriddatalen);
2245 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_IDARRAY, 1);
2246 data->attriddata[data->attriddatalen++] = id;
2247 data->attriddata[data->attriddatalen++] = 0;
2251 repodata_add_poolstr_array(Repodata *data, Id handle, Id keyname,
2255 if (data->localpool)
2256 id = stringpool_str2id(&data->spool, str, 1);
2258 id = str2id(data->repo->pool, str, 1);
2259 repodata_add_idarray(data, handle, keyname, id);
2263 repodata_add_fixarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2265 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2266 data->attriddata[data->attriddatalen++] = ghandle;
2267 data->attriddata[data->attriddatalen++] = 0;
2271 repodata_add_flexarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2273 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2274 data->attriddata[data->attriddatalen++] = ghandle;
2275 data->attriddata[data->attriddatalen++] = 0;
2279 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2282 if (dest == src || !(keyp = data->attrs[src]))
2284 for (; *keyp; keyp += 2)
2285 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2291 /**********************************************************************/
2293 /* unify with repo_write! */
2295 #define EXTDATA_BLOCK 1023
2303 data_addid(struct extdata *xd, Id x)
2306 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2307 dp = xd->buf + xd->len;
2312 *dp++ = (x >> 28) | 128;
2314 *dp++ = (x >> 21) | 128;
2315 *dp++ = (x >> 14) | 128;
2318 *dp++ = (x >> 7) | 128;
2320 xd->len = dp - xd->buf;
2324 data_addideof(struct extdata *xd, Id x, int eof)
2327 x = (x & 63) | ((x & ~63) << 1);
2328 data_addid(xd, (eof ? x: x | 64));
2332 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2334 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2335 memcpy(xd->buf + xd->len, blob, len);
2339 /*********************************/
2342 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2343 struct extdata *newvincore,
2345 Repokey *key, Id val)
2347 /* Otherwise we have a new value. Parse it into the internal
2351 unsigned int oldvincorelen = 0;
2355 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2358 oldvincorelen = xd->len;
2362 case REPOKEY_TYPE_VOID:
2363 case REPOKEY_TYPE_CONSTANT:
2364 case REPOKEY_TYPE_CONSTANTID:
2366 case REPOKEY_TYPE_STR:
2367 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2369 case REPOKEY_TYPE_MD5:
2370 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2372 case REPOKEY_TYPE_SHA1:
2373 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2375 case REPOKEY_TYPE_SHA256:
2376 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2378 case REPOKEY_TYPE_ID:
2379 case REPOKEY_TYPE_NUM:
2380 case REPOKEY_TYPE_DIR:
2381 data_addid(xd, val);
2383 case REPOKEY_TYPE_IDARRAY:
2384 for (ida = data->attriddata + val; *ida; ida++)
2385 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2387 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2388 for (ida = data->attriddata + val; *ida; ida += 3)
2390 data_addid(xd, ida[0]);
2391 data_addid(xd, ida[1]);
2392 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2395 case REPOKEY_TYPE_DIRSTRARRAY:
2396 for (ida = data->attriddata + val; *ida; ida += 2)
2398 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2399 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2402 case REPOKEY_TYPE_FIXARRAY:
2406 for (ida = data->attriddata + val; *ida; ida++)
2409 fprintf(stderr, "serialize struct %d\n", *ida);
2412 Id *kp = data->xattrs[-*ida];
2419 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2425 schemaid = repodata_schema2id(data, schema, 1);
2426 else if (schemaid != repodata_schema2id(data, schema, 0))
2428 fprintf(stderr, " not yet implemented: substructs with different schemas\n");
2432 fprintf(stderr, " schema %d\n", schemaid);
2437 data_addid(xd, num);
2438 data_addid(xd, schemaid);
2439 for (ida = data->attriddata + val; *ida; ida++)
2441 Id *kp = data->xattrs[-*ida];
2446 repodata_serialize_key(data, newincore, newvincore,
2447 schema, data->keys + *kp, kp[1]);
2452 case REPOKEY_TYPE_FLEXARRAY:
2455 for (ida = data->attriddata + val; *ida; ida++)
2457 data_addid(xd, num);
2458 for (ida = data->attriddata + val; *ida; ida++)
2460 Id *kp = data->xattrs[-*ida];
2463 data_addid(xd, 0); /* XXX */
2470 schemaid = repodata_schema2id(data, schema, 1);
2471 data_addid(xd, schemaid);
2472 kp = data->xattrs[-*ida];
2475 repodata_serialize_key(data, newincore, newvincore,
2476 schema, data->keys + *kp, kp[1]);
2482 fprintf(stderr, "don't know how to handle type %d\n", key->type);
2485 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2487 /* put offset/len in incore */
2488 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2489 oldvincorelen = xd->len - oldvincorelen;
2490 data_addid(newincore, oldvincorelen);
2495 repodata_internalize(Repodata *data)
2497 Repokey *key, solvkey;
2499 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2500 unsigned char *dp, *ndp;
2501 int newschema, oldcount;
2502 struct extdata newincore;
2503 struct extdata newvincore;
2506 if (!data->attrs && !data->xattrs)
2509 newvincore.buf = data->vincore;
2510 newvincore.len = data->vincorelen;
2512 /* find the solvables key, create if needed */
2513 memset(&solvkey, 0, sizeof(solvkey));
2514 solvkey.name = REPOSITORY_SOLVABLES;
2515 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2517 solvkey.storage = KEY_STORAGE_INCORE;
2518 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2520 schema = sat_malloc2(data->nkeys, sizeof(Id));
2521 seen = sat_malloc2(data->nkeys, sizeof(Id));
2523 /* Merge the data already existing (in data->schemata, ->incoredata and
2524 friends) with the new attributes in data->attrs[]. */
2525 nentry = data->end - data->start;
2526 memset(&newincore, 0, sizeof(newincore));
2527 data_addid(&newincore, 0); /* start data at offset 1 */
2529 data->mainschema = 0;
2530 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2532 /* join entry data */
2533 /* we start with the meta data, entry -1 */
2534 for (entry = -1; entry < nentry; entry++)
2536 memset(seen, 0, data->nkeys * sizeof(Id));
2538 dp = data->incoredata;
2541 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2542 dp = data_read_id(dp, &oldschema);
2545 fprintf(stderr, "oldschema %d\n", oldschema);
2546 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2547 fprintf(stderr, "schemadata %p\n", data->schemadata);
2549 /* seen: -1: old data 0: skipped >0: id + 1 */
2553 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2557 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
2565 keyp = data->attrs ? data->attrs[entry] : 0;
2568 /* strip solvables key */
2570 for (sp = keyp = schema; *sp; sp++)
2571 if (*sp != solvkeyid)
2576 seen[solvkeyid] = 0;
2577 keyp = data->xattrs ? data->xattrs[1] : 0;
2580 for (; *keyp; keyp += 2)
2587 seen[*keyp] = keyp[1] + 1;
2589 if (entry < 0 && data->end != data->start)
2596 /* Ideally we'd like to sort the new schema here, to ensure
2597 schema equality independend of the ordering. We can't do that
2598 yet. For once see below (old ids need to come before new ids).
2599 An additional difficulty is that we also need to move
2600 the values with the keys. */
2601 schemaid = repodata_schema2id(data, schema, 1);
2603 schemaid = oldschema;
2606 /* Now create data blob. We walk through the (possibly new) schema
2607 and either copy over old data, or insert the new. */
2608 /* XXX Here we rely on the fact that the (new) schema has the form
2609 o1 o2 o3 o4 ... | n1 n2 n3 ...
2610 (oX being the old keyids (possibly overwritten), and nX being
2611 the new keyids). This rules out sorting the keyids in order
2612 to ensure a small schema count. */
2614 data->incoreoffset[entry] = newincore.len;
2615 data_addid(&newincore, schemaid);
2618 data->mainschema = schemaid;
2619 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2621 keypstart = data->schemadata + data->schemata[schemaid];
2622 for (keyp = keypstart; *keyp; keyp++)
2625 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2626 if (*keyp == solvkeyid)
2628 /* add flexarray entry count */
2629 data_addid(&newincore, data->end - data->start);
2632 key = data->keys + *keyp;
2634 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2639 /* Skip the data associated with this old key. */
2640 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2642 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2643 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2645 else if (key->storage == KEY_STORAGE_INCORE)
2646 ndp = data_skip_key(data, dp, key);
2649 if (seen[*keyp] == -1)
2651 /* If this key was an old one _and_ was not overwritten with
2652 a different value copy over the old value (we skipped it
2655 data_addblob(&newincore, dp, ndp - dp);
2658 else if (seen[*keyp])
2660 /* Otherwise we have a new value. Parse it into the internal
2662 repodata_serialize_key(data, &newincore, &newvincore,
2663 schema, key, seen[*keyp] - 1);
2667 if (entry >= 0 && data->attrs && data->attrs[entry])
2668 data->attrs[entry] = sat_free(data->attrs[entry]);
2670 /* free all xattrs */
2671 for (entry = 0; entry < data->nxattrs; entry++)
2672 if (data->xattrs[entry])
2673 sat_free(data->xattrs[entry]);
2674 data->xattrs = sat_free(data->xattrs);
2677 data->lasthandle = 0;
2679 data->lastdatalen = 0;
2682 repodata_free_schemahash(data);
2684 sat_free(data->incoredata);
2685 data->incoredata = newincore.buf;
2686 data->incoredatalen = newincore.len;
2687 data->incoredatafree = 0;
2689 sat_free(data->vincore);
2690 data->vincore = newvincore.buf;
2691 data->vincorelen = newvincore.len;
2693 data->attrs = sat_free(data->attrs);
2694 data->attrdata = sat_free(data->attrdata);
2695 data->attriddata = sat_free(data->attriddata);
2696 data->attrdatalen = 0;
2697 data->attriddatalen = 0;
2701 repodata_disable_paging(Repodata *data)
2703 if (maybe_load_repodata(data, 0))
2704 repopagestore_disable_paging(&data->store);
2708 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: