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 return datamatcher_match(&matcher, di->data, di->key, &di->kv);
1291 /************************************************************************
1292 * data search iterator
1296 dataiterator_newdata(Dataiterator *di)
1298 Id keyname = di->keyname;
1299 Repodata *data = di->data;
1302 if (data->state == REPODATA_STUB)
1307 for (j = 1; j < data->nkeys; j++)
1308 if (keyname == data->keys[j].name)
1310 if (j == data->nkeys)
1314 if (data->loadcallback)
1315 data->loadcallback(data);
1317 data->state = REPODATA_ERROR;
1319 if (data->state == REPODATA_ERROR)
1323 unsigned char *dp = data->incoredata;
1326 if (di->solvid >= 0)
1327 dp += data->incoreoffset[di->solvid - data->start];
1328 dp = data_read_id(dp, &schema);
1329 Id *keyp = data->schemadata + data->schemata[schema];
1333 /* search in a specific key */
1334 for (kp = keyp; (k = *kp++) != 0; )
1335 if (data->keys[k].name == keyname)
1339 dp = forward_to_key(data, k, keyp, dp);
1349 di->key = di->data->keys + keyid;
1354 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1359 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname,
1360 const char *match, int flags)
1366 di->flags |= __SEARCH_ONESOLVABLE;
1367 di->data = repo->repodata - 1;
1368 if (flags & SEARCH_NO_STORAGE_SOLVABLE)
1375 di->solvid = repo->start - 1;
1378 fprintf(stderr, "A repo contains the NULL solvable!\n");
1381 di->data = repo->repodata + repo->nrepodata - 1;
1386 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1390 /* We feed multiple lines eventually (e.g. authors or descriptions),
1391 so set REG_NEWLINE. */
1393 regcomp(&di->regex, di->match,
1394 REG_EXTENDED | REG_NOSUB | REG_NEWLINE
1395 | ((di->flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1397 if (di->regex_err != 0)
1399 fprintf(stderr, "Given regex failed to compile: %s\n", di->match);
1400 fprintf(stderr, "regcomp error code: %d\n", di->regex_err);
1407 di->flags |= (di->flags & SEARCH_STRINGMASK) | SEARCH_STRING;
1413 di->keyname = keyname;
1414 static Id zeroid = 0;
1422 /* FIXME factor and merge with repo_matchvalue */
1424 dataiterator_match_int_real(Dataiterator *di, int flags, const void *vmatch)
1426 KeyValue *kv = &di->kv;
1427 const char *match = vmatch;
1428 if ((flags & SEARCH_STRINGMASK) != 0)
1430 switch (di->key->type)
1432 case REPOKEY_TYPE_ID:
1433 case REPOKEY_TYPE_IDARRAY:
1434 if (di->data && di->data->localpool)
1435 kv->str = stringpool_id2str(&di->data->spool, kv->id);
1437 kv->str = id2str(di->repo->pool, kv->id);
1439 case REPOKEY_TYPE_STR:
1441 case REPOKEY_TYPE_DIRSTRARRAY:
1442 if (!(flags & SEARCH_FILES))
1444 /* Put the full filename into kv->str. */
1445 kv->str = repodata_dir2str(di->data, kv->id, kv->str);
1446 /* And to compensate for that put the "empty" directory into
1447 kv->id, so that later calls to repodata_dir2str on this data
1448 come up with the same filename again. */
1454 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
1455 for the others we can't know if a colon separates a kind or not. */
1456 if ((flags & SEARCH_SKIP_KIND)
1457 && di->key->storage == KEY_STORAGE_SOLVABLE)
1459 const char *s = strchr(kv->str, ':');
1463 switch ((flags & SEARCH_STRINGMASK))
1465 case SEARCH_SUBSTRING:
1466 if (flags & SEARCH_NOCASE)
1468 if (!strcasestr(kv->str, match))
1473 if (!strstr(kv->str, match))
1478 if (flags & SEARCH_NOCASE)
1480 if (strcasecmp(match, kv->str))
1485 if (strcmp(match, kv->str))
1490 if (fnmatch(match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
1494 if (regexec((const regex_t *)vmatch, kv->str, 0, NULL, 0))
1505 dataiterator_match_int(Dataiterator *di)
1507 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1508 return dataiterator_match_int_real(di, di->flags, &di->regex);
1510 return dataiterator_match_int_real(di, di->flags, di->match);
1514 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1516 return dataiterator_match_int_real(di, flags, vmatch);
1520 dataiterator_step(Dataiterator *di)
1527 /* we're stepping through solvable data, 1 -> SOLVABLE_NAME... */
1530 /* we're stepping through an id array */
1536 di->kv.eof = idp[1] ? 0 : 1;
1542 Solvable *s = di->repo->pool->solvables + di->solvid;
1543 int state = di->state;
1544 di->key = solvablekeys + state - 1;
1546 di->state = RPM_RPMDBID;
1553 state = di->keyname - 1;
1560 di->kv.id = s->name;
1566 di->kv.id = s->arch;
1575 case SOLVABLE_VENDOR:
1578 di->kv.id = s->vendor;
1581 case SOLVABLE_PROVIDES:
1582 di->idp = s->provides
1583 ? di->repo->idarraydata + s->provides : 0;
1585 case SOLVABLE_OBSOLETES:
1586 di->idp = s->obsoletes
1587 ? di->repo->idarraydata + s->obsoletes : 0;
1589 case SOLVABLE_CONFLICTS:
1590 di->idp = s->conflicts
1591 ? di->repo->idarraydata + s->conflicts : 0;
1593 case SOLVABLE_REQUIRES:
1594 di->idp = s->requires
1595 ? di->repo->idarraydata + s->requires : 0;
1597 case SOLVABLE_RECOMMENDS:
1598 di->idp = s->recommends
1599 ? di->repo->idarraydata + s->recommends : 0;
1601 case SOLVABLE_SUPPLEMENTS:
1602 di->idp = s->supplements
1603 ? di->repo->idarraydata + s->supplements : 0;
1605 case SOLVABLE_SUGGESTS:
1606 di->idp = s->suggests
1607 ? di->repo->idarraydata + s->suggests : 0;
1609 case SOLVABLE_ENHANCES:
1610 di->idp = s->enhances
1611 ? di->repo->idarraydata + s->enhances : 0;
1614 if (!di->repo->rpmdbid)
1616 di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
1620 di->data = di->repo->repodata - 1;
1626 else if (di->subkeyp)
1631 /* Send end-of-substruct. We are here only when we saw a
1632 _COUNTED key one level up. Since then we didn't increment
1633 ->keyp, so it still can be found at keyp[-1]. */
1635 di->key = di->data->keys + di->keyp[-1];
1638 else if (!(keyid = *di->subkeyp++))
1640 /* Send end-of-element. See above for keyp[-1]. */
1642 di->key = di->data->keys + di->keyp[-1];
1644 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1647 di->dp = data_read_id(di->dp, &di->subschema);
1648 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1655 di->key = di->data->keys + keyid;
1656 di->dp = data_fetch(di->dp, &di->kv, di->key);
1666 di->dp = data_fetch(di->dp, &di->kv, di->key);
1671 if (di->keyname || !(keyid = *di->keyp++))
1675 Repo *repo = di->repo;
1676 Repodata *data = ++di->data;
1677 if (data >= repo->repodata + repo->nrepodata)
1679 if (di->flags & __SEARCH_ONESOLVABLE)
1681 if (di->solvid >= 0)
1683 while (++di->solvid < repo->end)
1684 if (repo->pool->solvables[di->solvid].repo == repo)
1686 if (di->solvid >= repo->end)
1688 if (!(di->flags & SEARCH_EXTRA))
1697 Pool *pool = di->repo->pool;
1698 if (!(di->flags & SEARCH_ALL_REPOS)
1699 || di->repo == pool->repos[pool->nrepos - 1])
1702 for (i = 0; i < pool->nrepos; i++)
1703 if (di->repo == pool->repos[i])
1705 di->repo = pool->repos[i + 1];
1706 dataiterator_init(di, di->repo, 0, di->keyname, di->match, di->flags);
1710 di->data = repo->repodata - 1;
1711 if ((di->flags & SEARCH_NO_STORAGE_SOLVABLE))
1713 static Id zeroid = 0;
1718 if ((di->solvid >= 0 && di->solvid >= data->start && di->solvid < data->end))
1720 dataiterator_newdata(di);
1728 di->key = di->data->keys + keyid;
1729 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1731 di->dp = data_fetch(di->dp, &di->kv, di->key);
1733 if (di->key->type == REPOKEY_TYPE_FIXARRAY)
1735 di->subnum = di->kv.num;
1736 di->subschema = di->kv.id;
1738 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1740 if (di->key->type == REPOKEY_TYPE_FLEXARRAY)
1742 di->subnum = di->kv.num;
1744 di->dp = data_read_id(di->dp, &di->subschema);
1745 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1751 || dataiterator_match_int(di))
1758 dataiterator_skip_attribute(Dataiterator *di)
1762 /* This will make the next _step call to retrieve the next field. */
1767 dataiterator_skip_solvable(Dataiterator *di)
1769 /* We're done with this field. */
1771 /* And with solvable data. */
1773 /* And with all keys for this repodata and thing. */
1774 static Id zeroid = 0;
1776 /* And with all repodatas for this thing. */
1777 di->data = di->repo->repodata + di->repo->nrepodata - 1;
1778 /* Hence the next call to _step will retrieve the next thing. */
1782 dataiterator_skip_repo(Dataiterator *di)
1784 dataiterator_skip_solvable(di);
1785 /* We're done with all solvables and all extra things for this repo. */
1790 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1793 /* Simulate us being done with the solvable before the requested one. */
1794 dataiterator_skip_solvable(di);
1795 di->solvid = s - s->repo->pool->solvables;
1800 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1803 dataiterator_skip_solvable(di);
1804 di->solvid = repo->start - 1;
1809 /************************************************************************
1810 * data modify functions
1813 /* extend repodata so that it includes solvables p */
1815 repodata_extend(Repodata *data, Id p)
1817 if (data->start == data->end)
1818 data->start = data->end = p;
1821 int old = data->end - data->start;
1822 int new = p - data->end + 1;
1825 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id), REPODATA_BLOCK);
1826 memset(data->attrs + old, 0, new * sizeof(Id));
1828 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1829 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1832 if (p < data->start)
1834 int old = data->end - data->start;
1835 int new = data->start - p;
1838 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id), REPODATA_BLOCK);
1839 memmove(data->attrs + new, data->attrs, old * sizeof(Id));
1840 memset(data->attrs, 0, new * sizeof(Id));
1842 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1843 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1844 memset(data->incoreoffset, 0, new * sizeof(Id));
1850 repodata_extend_block(Repodata *data, Id start, Id num)
1854 if (!data->incoreoffset)
1856 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1857 data->start = start;
1858 data->end = start + num;
1861 repodata_extend(data, start);
1863 repodata_extend(data, start + num - 1);
1866 /**********************************************************************/
1868 #define REPODATA_ATTRS_BLOCK 63
1869 #define REPODATA_ATTRDATA_BLOCK 1023
1870 #define REPODATA_ATTRIDDATA_BLOCK 63
1874 repodata_new_handle(Repodata *data)
1878 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1881 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1882 data->xattrs[data->nxattrs] = 0;
1883 return -(data->nxattrs++);
1887 repodata_get_attrp(Repodata *data, Id handle)
1889 if (handle == SOLVID_META)
1893 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1898 return data->xattrs - handle;
1899 if (handle < data->start || handle >= data->end)
1900 repodata_extend(data, handle);
1902 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1903 return data->attrs + (handle - data->start);
1907 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1913 app = repodata_get_attrp(data, handle);
1918 for (pp = ap; *pp; pp += 2)
1919 /* Determine equality based on the name only, allows us to change
1920 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1921 if (data->keys[*pp].name == data->keys[keyid].name)
1934 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1944 repodata_set(Repodata *data, Id handle, Repokey *key, Id val)
1948 keyid = repodata_key2id(data, key, 1);
1949 repodata_insert_keyid(data, handle, keyid, val, 1);
1953 repodata_set_id(Repodata *data, Id handle, Id keyname, Id id)
1957 key.type = REPOKEY_TYPE_ID;
1959 key.storage = KEY_STORAGE_INCORE;
1960 repodata_set(data, handle, &key, id);
1964 repodata_set_num(Repodata *data, Id handle, Id keyname, unsigned int num)
1968 key.type = REPOKEY_TYPE_NUM;
1970 key.storage = KEY_STORAGE_INCORE;
1971 repodata_set(data, handle, &key, (Id)num);
1975 repodata_set_poolstr(Repodata *data, Id handle, Id keyname, const char *str)
1979 if (data->localpool)
1980 id = stringpool_str2id(&data->spool, str, 1);
1982 id = str2id(data->repo->pool, str, 1);
1984 key.type = REPOKEY_TYPE_ID;
1986 key.storage = KEY_STORAGE_INCORE;
1987 repodata_set(data, handle, &key, id);
1991 repodata_set_constant(Repodata *data, Id handle, Id keyname, unsigned int constant)
1995 key.type = REPOKEY_TYPE_CONSTANT;
1996 key.size = constant;
1997 key.storage = KEY_STORAGE_INCORE;
1998 repodata_set(data, handle, &key, 0);
2002 repodata_set_constantid(Repodata *data, Id handle, Id keyname, Id id)
2006 key.type = REPOKEY_TYPE_CONSTANTID;
2008 key.storage = KEY_STORAGE_INCORE;
2009 repodata_set(data, handle, &key, 0);
2013 repodata_set_void(Repodata *data, Id handle, Id keyname)
2017 key.type = REPOKEY_TYPE_VOID;
2019 key.storage = KEY_STORAGE_INCORE;
2020 repodata_set(data, handle, &key, 0);
2024 repodata_set_str(Repodata *data, Id handle, Id keyname, const char *str)
2029 l = strlen(str) + 1;
2031 key.type = REPOKEY_TYPE_STR;
2033 key.storage = KEY_STORAGE_INCORE;
2034 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2035 memcpy(data->attrdata + data->attrdatalen, str, l);
2036 repodata_set(data, handle, &key, data->attrdatalen);
2037 data->attrdatalen += l;
2041 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2044 Id *ida, *pp, **ppp;
2046 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2048 /* great! just append the new data */
2049 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2050 data->attriddatalen--; /* overwrite terminating 0 */
2051 data->lastdatalen += entrysize;
2054 ppp = repodata_get_attrp(data, handle);
2057 for (; *pp; pp += 2)
2058 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
2062 /* not found. allocate new key */
2067 key.storage = KEY_STORAGE_INCORE;
2068 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2069 repodata_set(data, handle, &key, data->attriddatalen);
2070 data->lasthandle = 0; /* next time... */
2074 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2075 oldsize += entrysize;
2076 if (ida + 1 == data->attriddata + data->attriddatalen)
2078 /* this was the last entry, just append it */
2079 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2080 data->attriddatalen--; /* overwrite terminating 0 */
2084 /* too bad. move to back. */
2085 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2086 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2087 pp[1] = data->attriddatalen;
2088 data->attriddatalen += oldsize;
2090 data->lasthandle = handle;
2091 data->lastkey = *pp;
2092 data->lastdatalen = data->attriddatalen + entrysize + 1;
2096 checksumtype2len(Id type)
2100 case REPOKEY_TYPE_MD5:
2102 case REPOKEY_TYPE_SHA1:
2104 case REPOKEY_TYPE_SHA256:
2105 return SIZEOF_SHA256;
2112 repodata_set_bin_checksum(Repodata *data, Id handle, Id keyname, Id type,
2113 const unsigned char *str)
2116 int l = checksumtype2len(type);
2123 key.storage = KEY_STORAGE_INCORE;
2124 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2125 memcpy(data->attrdata + data->attrdatalen, str, l);
2126 repodata_set(data, handle, &key, data->attrdatalen);
2127 data->attrdatalen += l;
2131 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
2134 for (i = 0; i < buflen; i++)
2136 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
2137 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
2138 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
2149 buf[i] = (buf[i] << 4) | v;
2156 repodata_set_checksum(Repodata *data, Id handle, Id keyname, Id type,
2159 unsigned char buf[64];
2160 int l = checksumtype2len(type);
2164 if (hexstr2bytes(buf, str, l) != l)
2166 fprintf(stderr, "Invalid hex character in '%s'\n", str);
2169 repodata_set_bin_checksum(data, handle, keyname, type, buf);
2173 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2178 l = checksumtype2len(type);
2181 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2182 for (i = 0; i < l; i++)
2184 unsigned char v = buf[i];
2185 unsigned char w = v >> 4;
2186 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2188 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2195 repodata_globalize_id(Repodata *data, Id id)
2197 if (!data || !data->localpool)
2199 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
2203 repodata_add_dirnumnum(Repodata *data, Id handle, Id keyname, Id dir, Id num, Id num2)
2207 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", handle, dir, num, num2, data->attriddatalen);
2209 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2210 data->attriddata[data->attriddatalen++] = dir;
2211 data->attriddata[data->attriddatalen++] = num;
2212 data->attriddata[data->attriddatalen++] = num2;
2213 data->attriddata[data->attriddatalen++] = 0;
2217 repodata_add_dirstr(Repodata *data, Id handle, Id keyname, Id dir, const char *str)
2223 l = strlen(str) + 1;
2224 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2225 memcpy(data->attrdata + data->attrdatalen, str, l);
2226 stroff = data->attrdatalen;
2227 data->attrdatalen += l;
2230 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", handle, dir, str, data->attriddatalen);
2232 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2233 data->attriddata[data->attriddatalen++] = dir;
2234 data->attriddata[data->attriddatalen++] = stroff;
2235 data->attriddata[data->attriddatalen++] = 0;
2239 repodata_add_idarray(Repodata *data, Id handle, Id keyname, Id id)
2242 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", handle, id, data->attriddatalen);
2244 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_IDARRAY, 1);
2245 data->attriddata[data->attriddatalen++] = id;
2246 data->attriddata[data->attriddatalen++] = 0;
2250 repodata_add_poolstr_array(Repodata *data, Id handle, Id keyname,
2254 if (data->localpool)
2255 id = stringpool_str2id(&data->spool, str, 1);
2257 id = str2id(data->repo->pool, str, 1);
2258 repodata_add_idarray(data, handle, keyname, id);
2262 repodata_add_fixarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2264 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2265 data->attriddata[data->attriddatalen++] = ghandle;
2266 data->attriddata[data->attriddatalen++] = 0;
2270 repodata_add_flexarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2272 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2273 data->attriddata[data->attriddatalen++] = ghandle;
2274 data->attriddata[data->attriddatalen++] = 0;
2278 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2281 if (dest == src || !(keyp = data->attrs[src]))
2283 for (; *keyp; keyp += 2)
2284 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2290 /**********************************************************************/
2292 /* unify with repo_write! */
2294 #define EXTDATA_BLOCK 1023
2302 data_addid(struct extdata *xd, Id x)
2305 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2306 dp = xd->buf + xd->len;
2311 *dp++ = (x >> 28) | 128;
2313 *dp++ = (x >> 21) | 128;
2314 *dp++ = (x >> 14) | 128;
2317 *dp++ = (x >> 7) | 128;
2319 xd->len = dp - xd->buf;
2323 data_addideof(struct extdata *xd, Id x, int eof)
2326 x = (x & 63) | ((x & ~63) << 1);
2327 data_addid(xd, (eof ? x: x | 64));
2331 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2333 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2334 memcpy(xd->buf + xd->len, blob, len);
2338 /*********************************/
2341 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2342 struct extdata *newvincore,
2344 Repokey *key, Id val)
2346 /* Otherwise we have a new value. Parse it into the internal
2350 unsigned int oldvincorelen = 0;
2354 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2357 oldvincorelen = xd->len;
2361 case REPOKEY_TYPE_VOID:
2362 case REPOKEY_TYPE_CONSTANT:
2363 case REPOKEY_TYPE_CONSTANTID:
2365 case REPOKEY_TYPE_STR:
2366 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2368 case REPOKEY_TYPE_MD5:
2369 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2371 case REPOKEY_TYPE_SHA1:
2372 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2374 case REPOKEY_TYPE_SHA256:
2375 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2377 case REPOKEY_TYPE_ID:
2378 case REPOKEY_TYPE_NUM:
2379 case REPOKEY_TYPE_DIR:
2380 data_addid(xd, val);
2382 case REPOKEY_TYPE_IDARRAY:
2383 for (ida = data->attriddata + val; *ida; ida++)
2384 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2386 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2387 for (ida = data->attriddata + val; *ida; ida += 3)
2389 data_addid(xd, ida[0]);
2390 data_addid(xd, ida[1]);
2391 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2394 case REPOKEY_TYPE_DIRSTRARRAY:
2395 for (ida = data->attriddata + val; *ida; ida += 2)
2397 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2398 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2401 case REPOKEY_TYPE_FIXARRAY:
2405 for (ida = data->attriddata + val; *ida; ida++)
2408 fprintf(stderr, "serialize struct %d\n", *ida);
2411 Id *kp = data->xattrs[-*ida];
2418 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2424 schemaid = repodata_schema2id(data, schema, 1);
2425 else if (schemaid != repodata_schema2id(data, schema, 0))
2427 fprintf(stderr, " not yet implemented: substructs with different schemas\n");
2431 fprintf(stderr, " schema %d\n", schemaid);
2436 data_addid(xd, num);
2437 data_addid(xd, schemaid);
2438 for (ida = data->attriddata + val; *ida; ida++)
2440 Id *kp = data->xattrs[-*ida];
2445 repodata_serialize_key(data, newincore, newvincore,
2446 schema, data->keys + *kp, kp[1]);
2451 case REPOKEY_TYPE_FLEXARRAY:
2454 for (ida = data->attriddata + val; *ida; ida++)
2456 data_addid(xd, num);
2457 for (ida = data->attriddata + val; *ida; ida++)
2459 Id *kp = data->xattrs[-*ida];
2462 data_addid(xd, 0); /* XXX */
2469 schemaid = repodata_schema2id(data, schema, 1);
2470 data_addid(xd, schemaid);
2471 kp = data->xattrs[-*ida];
2474 repodata_serialize_key(data, newincore, newvincore,
2475 schema, data->keys + *kp, kp[1]);
2481 fprintf(stderr, "don't know how to handle type %d\n", key->type);
2484 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2486 /* put offset/len in incore */
2487 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2488 oldvincorelen = xd->len - oldvincorelen;
2489 data_addid(newincore, oldvincorelen);
2494 repodata_internalize(Repodata *data)
2496 Repokey *key, solvkey;
2498 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2499 unsigned char *dp, *ndp;
2500 int newschema, oldcount;
2501 struct extdata newincore;
2502 struct extdata newvincore;
2505 if (!data->attrs && !data->xattrs)
2508 newvincore.buf = data->vincore;
2509 newvincore.len = data->vincorelen;
2511 /* find the solvables key, create if needed */
2512 memset(&solvkey, 0, sizeof(solvkey));
2513 solvkey.name = REPOSITORY_SOLVABLES;
2514 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2516 solvkey.storage = KEY_STORAGE_INCORE;
2517 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2519 schema = sat_malloc2(data->nkeys, sizeof(Id));
2520 seen = sat_malloc2(data->nkeys, sizeof(Id));
2522 /* Merge the data already existing (in data->schemata, ->incoredata and
2523 friends) with the new attributes in data->attrs[]. */
2524 nentry = data->end - data->start;
2525 memset(&newincore, 0, sizeof(newincore));
2526 data_addid(&newincore, 0); /* start data at offset 1 */
2528 data->mainschema = 0;
2529 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2531 /* join entry data */
2532 /* we start with the meta data, entry -1 */
2533 for (entry = -1; entry < nentry; entry++)
2535 memset(seen, 0, data->nkeys * sizeof(Id));
2537 dp = data->incoredata;
2540 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2541 dp = data_read_id(dp, &oldschema);
2544 fprintf(stderr, "oldschema %d\n", oldschema);
2545 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2546 fprintf(stderr, "schemadata %p\n", data->schemadata);
2548 /* seen: -1: old data 0: skipped >0: id + 1 */
2552 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2556 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
2564 keyp = data->attrs ? data->attrs[entry] : 0;
2567 /* strip solvables key */
2569 for (sp = keyp = schema; *sp; sp++)
2570 if (*sp != solvkeyid)
2575 seen[solvkeyid] = 0;
2576 keyp = data->xattrs ? data->xattrs[1] : 0;
2579 for (; *keyp; keyp += 2)
2586 seen[*keyp] = keyp[1] + 1;
2588 if (entry < 0 && data->end != data->start)
2595 /* Ideally we'd like to sort the new schema here, to ensure
2596 schema equality independend of the ordering. We can't do that
2597 yet. For once see below (old ids need to come before new ids).
2598 An additional difficulty is that we also need to move
2599 the values with the keys. */
2600 schemaid = repodata_schema2id(data, schema, 1);
2602 schemaid = oldschema;
2605 /* Now create data blob. We walk through the (possibly new) schema
2606 and either copy over old data, or insert the new. */
2607 /* XXX Here we rely on the fact that the (new) schema has the form
2608 o1 o2 o3 o4 ... | n1 n2 n3 ...
2609 (oX being the old keyids (possibly overwritten), and nX being
2610 the new keyids). This rules out sorting the keyids in order
2611 to ensure a small schema count. */
2613 data->incoreoffset[entry] = newincore.len;
2614 data_addid(&newincore, schemaid);
2617 data->mainschema = schemaid;
2618 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2620 keypstart = data->schemadata + data->schemata[schemaid];
2621 for (keyp = keypstart; *keyp; keyp++)
2624 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2625 if (*keyp == solvkeyid)
2627 /* add flexarray entry count */
2628 data_addid(&newincore, data->end - data->start);
2631 key = data->keys + *keyp;
2633 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2638 /* Skip the data associated with this old key. */
2639 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2641 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2642 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2644 else if (key->storage == KEY_STORAGE_INCORE)
2645 ndp = data_skip_key(data, dp, key);
2648 if (seen[*keyp] == -1)
2650 /* If this key was an old one _and_ was not overwritten with
2651 a different value copy over the old value (we skipped it
2654 data_addblob(&newincore, dp, ndp - dp);
2657 else if (seen[*keyp])
2659 /* Otherwise we have a new value. Parse it into the internal
2661 repodata_serialize_key(data, &newincore, &newvincore,
2662 schema, key, seen[*keyp] - 1);
2666 if (entry >= 0 && data->attrs && data->attrs[entry])
2667 data->attrs[entry] = sat_free(data->attrs[entry]);
2669 /* free all xattrs */
2670 for (entry = 0; entry < data->nxattrs; entry++)
2671 if (data->xattrs[entry])
2672 sat_free(data->xattrs[entry]);
2673 data->xattrs = sat_free(data->xattrs);
2676 data->lasthandle = 0;
2678 data->lastdatalen = 0;
2681 repodata_free_schemahash(data);
2683 sat_free(data->incoredata);
2684 data->incoredata = newincore.buf;
2685 data->incoredatalen = newincore.len;
2686 data->incoredatafree = 0;
2688 sat_free(data->vincore);
2689 data->vincore = newvincore.buf;
2690 data->vincorelen = newvincore.len;
2692 data->attrs = sat_free(data->attrs);
2693 data->attrdata = sat_free(data->attrdata);
2694 data->attriddata = sat_free(data->attriddata);
2695 data->attrdatalen = 0;
2696 data->attriddatalen = 0;
2700 repodata_disable_paging(Repodata *data)
2702 if (maybe_load_repodata(data, 0))
2703 repopagestore_disable_paging(&data->store);
2707 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: