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
26 #include "poolid_private.h"
32 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
33 unsigned char *out, unsigned int out_len);
34 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
37 unsigned int out_len);
39 #define REPODATA_BLOCK 255
43 repodata_init(Repodata *data, Repo *repo, int localpool)
45 memset(data, 0, sizeof (*data));
47 data->localpool = localpool;
49 stringpool_init_empty(&data->spool);
50 data->keys = sat_calloc(1, sizeof(Repokey));
52 data->schemata = sat_calloc(1, sizeof(Id));
53 data->schemadata = sat_calloc(1, sizeof(Id));
55 data->schemadatalen = 1;
56 repopagestore_init(&data->store);
60 repodata_free(Repodata *data)
66 sat_free(data->schemata);
67 sat_free(data->schemadata);
68 sat_free(data->schematahash);
70 stringpool_free(&data->spool);
71 dirpool_free(&data->dirpool);
73 sat_free(data->mainschemaoffsets);
74 sat_free(data->incoredata);
75 sat_free(data->incoreoffset);
76 sat_free(data->verticaloffset);
78 repopagestore_free(&data->store);
80 sat_free(data->vincore);
83 for (i = 0; i < data->end - data->start; i++)
84 sat_free(data->attrs[i]);
85 sat_free(data->attrs);
87 for (i = 0; i < data->nxattrs; i++)
88 sat_free(data->xattrs[i]);
89 sat_free(data->xattrs);
91 sat_free(data->attrdata);
92 sat_free(data->attriddata);
96 /***************************************************************
100 /* this is not so time critical that we need a hash, so we do a simple
103 repodata_key2id(Repodata *data, Repokey *key, int create)
107 for (keyid = 1; keyid < data->nkeys; keyid++)
108 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
110 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
114 if (keyid == data->nkeys)
118 /* allocate new key */
119 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
120 data->keys[data->nkeys++] = *key;
121 if (data->verticaloffset)
123 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
124 data->verticaloffset[data->nkeys - 1] = 0;
126 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
132 /***************************************************************
133 * schema pool management
136 #define SCHEMATA_BLOCK 31
137 #define SCHEMATADATA_BLOCK 255
140 repodata_schema2id(Repodata *data, Id *schema, int create)
146 if ((schematahash = data->schematahash) == 0)
148 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
149 for (i = 0; i < data->nschemata; i++)
151 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
154 schematahash[h] = i + 1;
156 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
157 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
160 for (sp = schema, len = 0, h = 0; *sp; len++)
165 cid = schematahash[h];
169 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
172 for (cid = 0; cid < data->nschemata; cid++)
173 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
179 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
180 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
182 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
183 data->schemata[data->nschemata] = data->schemadatalen;
184 data->schemadatalen += len;
185 schematahash[h] = data->nschemata + 1;
187 fprintf(stderr, "schema2id: new schema\n");
189 return data->nschemata++;
193 repodata_free_schemahash(Repodata *data)
195 data->schematahash = sat_free(data->schematahash);
197 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
198 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
202 /***************************************************************
203 * dir pool management
207 repodata_str2dir(Repodata *data, const char *dir, int create)
213 while (*dir == '/' && dir[1] == '/')
215 if (*dir == '/' && !dir[1])
219 dire = strchrnul(dir, '/');
221 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
223 id = strn2id(data->repo->pool, dir, dire - dir, create);
226 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
239 repodata_dir2str(Repodata *data, Id did, const char *suf)
241 Pool *pool = data->repo->pool;
248 return suf ? suf : "";
252 comp = dirpool_compid(&data->dirpool, parent);
253 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
255 parent = dirpool_parent(&data->dirpool, parent);
260 l += strlen(suf) + 1;
261 p = pool_alloctmpspace(pool, l + 1) + l;
272 comp = dirpool_compid(&data->dirpool, parent);
273 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
276 strncpy(p, comps, l);
277 parent = dirpool_parent(&data->dirpool, parent);
285 /***************************************************************
289 static inline unsigned char *
290 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
292 Id *keyp = data->schemadata + data->schemata[schema];
293 for (; *keyp; keyp++)
294 dp = data_skip_key(data, dp, data->keys + *keyp);
299 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
301 int nentries, schema;
304 case REPOKEY_TYPE_FIXARRAY:
305 dp = data_read_id(dp, &nentries);
308 dp = data_read_id(dp, &schema);
310 dp = data_skip_schema(data, dp, schema);
312 case REPOKEY_TYPE_FLEXARRAY:
313 dp = data_read_id(dp, &nentries);
316 dp = data_read_id(dp, &schema);
317 dp = data_skip_schema(data, dp, schema);
321 if (key->storage == KEY_STORAGE_INCORE)
322 dp = data_skip(dp, key->type);
323 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
325 dp = data_skip(dp, REPOKEY_TYPE_ID);
326 dp = data_skip(dp, REPOKEY_TYPE_ID);
332 static unsigned char *
333 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
339 while ((k = *keyp++) != 0)
343 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
345 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
346 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
349 if (data->keys[k].storage != KEY_STORAGE_INCORE)
351 dp = data_skip_key(data, dp, data->keys + k);
356 static unsigned char *
357 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
362 if (off >= data->lastverticaloffset)
364 off -= data->lastverticaloffset;
365 if (off + len > data->vincorelen)
367 return data->vincore + off;
369 if (off + len > key->size)
371 /* we now have the offset, go into vertical */
372 off += data->verticaloffset[key - data->keys];
373 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
374 dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
376 dp += off % BLOB_PAGESIZE;
380 static inline unsigned char *
381 get_data(Repodata *data, Repokey *key, unsigned char **dpp)
383 unsigned char *dp = *dpp;
387 if (key->storage == KEY_STORAGE_INCORE)
389 /* hmm, this is a bit expensive */
390 *dpp = data_skip_key(data, dp, key);
393 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
396 dp = data_read_id(dp, &off);
397 dp = data_read_id(dp, &len);
399 return get_vertical_data(data, key, off, len);
405 load_repodata(Repodata *data)
407 if (data->loadcallback)
409 data->loadcallback(data);
410 if (data->state == REPODATA_AVAILABLE)
413 data->state = REPODATA_ERROR;
418 maybe_load_repodata(Repodata *data, Id keyname)
420 if (keyname && !repodata_precheck_keyname(data, keyname))
421 return 0; /* do not bother... */
428 for (i = 0; i < data->nkeys; i++)
429 if (keyname == data->keys[i].name)
431 if (i == data->nkeys)
434 return load_repodata(data);
437 case REPODATA_AVAILABLE:
440 data->state = REPODATA_ERROR;
445 static inline unsigned char*
446 entry2data(Repodata *data, Id entry, Id *schemap)
448 unsigned char *dp = data->incoredata;
451 if (entry == REPOENTRY_META) /* META */
453 else if (entry == REPOENTRY_POS) /* META */
455 Pool *pool = data->repo->pool;
456 if (data->repo != pool->pos.repo)
458 if (data != data->repo->repodata + pool->pos.repodataid)
460 *schemap = pool->pos.schema;
461 return data->incoredata + pool->pos.dp;
465 if (entry < data->start || entry >= data->end)
467 dp += data->incoreoffset[entry - data->start];
469 return data_read_id(dp, schemap);
472 /************************************************************************
477 find_schema_key(Repodata *data, Id schema, Id keyname)
480 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
481 if (data->keys[*keyp].name == keyname)
486 static inline unsigned char *
487 find_key_data(Repodata *data, Id entry, Id keyname, Repokey **keyp)
489 unsigned char *dp, *ddp;
493 if (!maybe_load_repodata(data, keyname))
495 dp = entry2data(data, entry, &schema);
498 keyid = find_schema_key(data, schema, keyname);
501 key = data->keys + keyid;
503 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
505 dp = forward_to_key(data, keyid, data->schemadata + data->schemata[schema], dp);
508 ddp = get_data(data, key, &dp);
514 repodata_lookup_id(Repodata *data, Id entry, Id keyname)
520 dp = find_key_data(data, entry, keyname, &key);
523 if (key->type == REPOKEY_TYPE_CONSTANTID)
525 if (key->type != REPOKEY_TYPE_ID)
527 dp = data_read_id(dp, &id);
532 repodata_lookup_str(Repodata *data, Id entry, Id keyname)
538 dp = find_key_data(data, entry, keyname, &key);
541 if (key->type == REPOKEY_TYPE_STR)
542 return (const char *)dp;
543 if (key->type == REPOKEY_TYPE_CONSTANTID)
544 return id2str(data->repo->pool, key->size);
545 if (key->type == REPOKEY_TYPE_ID)
546 dp = data_read_id(dp, &id);
550 return data->spool.stringspace + data->spool.strings[id];
551 return id2str(data->repo->pool, id);
555 repodata_lookup_num(Repodata *data, Id entry, Id keyname, unsigned int *value)
562 dp = find_key_data(data, entry, keyname, &key);
565 if (key->type == REPOKEY_TYPE_NUM
566 || key->type == REPOKEY_TYPE_U32
567 || key->type == REPOKEY_TYPE_CONSTANT)
569 dp = data_fetch(dp, &kv, key);
577 repodata_lookup_void(Repodata *data, Id entry, Id keyname)
583 if (!maybe_load_repodata(data, keyname))
585 dp = entry2data(data, entry, &schema);
588 /* can't use find_schema_key as we need to test the type */
589 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
590 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
595 const unsigned char *
596 repodata_lookup_bin_checksum(Repodata *data, Id entry, Id keyname, Id *typep)
601 dp = find_key_data(data, entry, keyname, &key);
609 /************************************************************************
613 struct subschema_data {
619 /* search in a specific entry */
621 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
625 Id k, keyid, *kp, *keyp;
626 unsigned char *dp, *ddp;
632 if (!maybe_load_repodata(data, keyname))
634 if (entry == REPOENTRY_SUBSCHEMA)
636 struct subschema_data *subd = cbdata;
637 cbdata = subd->cbdata;
639 schema = subd->parent->id;
640 dp = (unsigned char *)subd->parent->str;
641 kv.parent = subd->parent;
646 dp = entry2data(data, entry, &schema);
649 s = data->repo->pool->solvables + entry;
652 keyp = data->schemadata + data->schemata[schema];
655 /* search for a specific key */
656 for (kp = keyp; (k = *kp++) != 0; )
657 if (data->keys[k].name == keyname)
661 dp = forward_to_key(data, k, data->schemadata + data->schemata[schema], dp);
667 while ((keyid = *keyp++) != 0)
670 key = data->keys + keyid;
671 ddp = get_data(data, key, &dp);
673 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
675 struct subschema_data subd;
679 subd.cbdata = cbdata;
682 ddp = data_read_id(ddp, &nentries);
686 while (ddp && nentries > 0)
688 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
689 ddp = data_read_id(ddp, &schema);
691 kv.str = (char *)ddp;
692 stop = callback(cbdata, s, data, key, &kv);
693 if (stop > SEARCH_NEXT_KEY)
698 repodata_search(data, REPOENTRY_SUBSCHEMA, 0, callback, &subd);
699 ddp = data_skip_schema(data, ddp, schema);
707 kv.str = (char *)ddp;
708 stop = callback(cbdata, s, data, key, &kv);
709 if (stop > SEARCH_NEXT_KEY)
719 ddp = data_fetch(ddp, &kv, key);
722 stop = callback(cbdata, s, data, key, &kv);
725 while (!kv.eof && !stop);
726 if (onekey || stop > SEARCH_NEXT_KEY)
732 repodata_setpos_kv(Repodata *data, KeyValue *kv)
734 Pool *pool = data->repo->pool;
738 pool->pos.repodataid = 0;
740 pool->pos.schema = 0;
745 pool->pos.repodataid = data - data->repo->repodata;
746 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
747 pool->pos.schema = kv->id;
751 /************************************************************************/
753 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
754 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
755 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
756 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
757 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
758 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
759 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
760 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
761 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
762 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
763 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
764 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
765 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
766 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
771 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
785 case SOLVABLE_VENDOR:
788 case SOLVABLE_PROVIDES:
790 return s->provides ? s->repo->idarraydata + s->provides : 0;
791 case SOLVABLE_OBSOLETES:
793 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
794 case SOLVABLE_CONFLICTS:
796 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
797 case SOLVABLE_REQUIRES:
799 return s->requires ? s->repo->idarraydata + s->requires : 0;
800 case SOLVABLE_RECOMMENDS:
802 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
803 case SOLVABLE_SUPPLEMENTS:
805 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
806 case SOLVABLE_SUGGESTS:
808 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
809 case SOLVABLE_ENHANCES:
811 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
814 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
821 datamatcher_init(Datamatcher *ma, Pool *pool, const char *match, int flags)
824 ma->match = (void *)match;
827 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
829 ma->match = sat_calloc(1, sizeof(regex_t));
830 ma->error = regcomp((regex_t *)ma->match, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
834 ma->match = (void *)match;
835 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
841 datamatcher_free(Datamatcher *ma)
843 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->match)
846 ma->match = sat_free(ma->match);
851 datamatcher_match(Datamatcher *ma, Repodata *data, Repokey *key, KeyValue *kv)
855 case REPOKEY_TYPE_ID:
856 case REPOKEY_TYPE_IDARRAY:
857 if (data && data->localpool)
858 kv->str = stringpool_id2str(&data->spool, kv->id);
860 kv->str = id2str(ma->pool, kv->id);
862 case REPOKEY_TYPE_STR:
864 case REPOKEY_TYPE_DIRSTRARRAY:
865 if (!(ma->flags & SEARCH_FILES))
867 /* Put the full filename into kv->str. */
868 kv->str = repodata_dir2str(data, kv->id, kv->str);
869 /* And to compensate for that put the "empty" directory into
870 kv->id, so that later calls to repodata_dir2str on this data
871 come up with the same filename again. */
877 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
878 for the others we can't know if a colon separates a kind or not. */
879 if ((ma->flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
881 const char *s = strchr(kv->str, ':');
885 switch ((ma->flags & SEARCH_STRINGMASK))
887 case SEARCH_SUBSTRING:
888 if (ma->flags & SEARCH_NOCASE)
890 if (!strcasestr(kv->str, (const char *)ma->match))
895 if (!strstr(kv->str, (const char *)ma->match))
900 if (ma->flags & SEARCH_NOCASE)
902 if (strcasecmp((const char *)ma->match, kv->str))
907 if (strcmp((const char *)ma->match, kv->str))
912 if (fnmatch((const char *)ma->match, kv->str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
916 if (regexec((const regex_t *)ma->match, kv->str, 0, NULL, 0))
949 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname, const char *match, int flags)
951 memset(di, 0, sizeof(*di));
953 di->keyname = keyname;
955 di->pool = repo->pool;
957 flags |= SEARCH_THISENTRY;
962 datamatcher_init(&di->matcher, di->pool, match, flags);
963 if (p == REPOENTRY_POS)
965 di->repo = di->pool->pos.repo;
966 di->data = di->repo->repodata + di->pool->pos.repodataid;
970 di->state = di_enterrepo;
974 dataiterator_free(Dataiterator *di)
976 if (di->matcher.match)
977 datamatcher_free(&di->matcher);
981 dataiterator_step(Dataiterator *di)
989 case di_nextattr: di_nextattr:
991 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
993 di->state = di_nextkey;
995 di->state = di_nextattr;
998 case di_nextkey: di_nextkey:
1004 else if ((di->flags & SEARCH_SUB) != 0)
1006 Id *keyp = di->keyp;
1007 for (keyp++; *keyp; keyp++)
1008 if (di->data->keys[*keyp].name == di->keyname ||
1009 di->data->keys[*keyp].type == REPOKEY_TYPE_FIXARRAY ||
1010 di->data->keys[*keyp].type == REPOKEY_TYPE_FLEXARRAY)
1012 if (*keyp && (di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp)) != 0)
1023 case di_nextrepodata: di_nextrepodata:
1024 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1025 goto di_enterrepodata;
1028 case di_nextsolvable:
1029 if (!(di->flags & SEARCH_THISENTRY))
1032 di->entry = di->repo->start;
1035 for (; di->entry < di->repo->end; di->entry++)
1037 if (di->pool->solvables[di->entry].repo == di->repo)
1038 goto di_entersolvable;
1044 if (di->repoid >= 0)
1047 if (di->repoid < di->pool->nrepos)
1049 di->repo = di->pool->repos[di->repoid];
1059 case di_enterrepo: di_enterrepo:
1060 if (!(di->flags & SEARCH_THISENTRY))
1061 di->entry = di->repo->start;
1064 case di_entersolvable: di_entersolvable:
1065 if (di->repodataid >= 0)
1068 if (di->entry > 0 && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)))
1070 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1072 goto di_entersolvablekey;
1076 case di_enterrepodata: di_enterrepodata:
1077 if (di->repodataid >= 0)
1078 di->data = di->repo->repodata + di->repodataid;
1079 if (!maybe_load_repodata(di->data, di->keyname))
1080 goto di_nextrepodata;
1081 di->dp = entry2data(di->data, di->entry, &schema);
1083 goto di_nextrepodata;
1084 di->keyp = di->data->schemadata + di->data->schemata[schema];
1088 if ((di->flags & SEARCH_SUB) != 0)
1093 for (keyp = di->keyp; *keyp; keyp++)
1094 if (di->data->keys[*keyp].name == di->keyname)
1097 goto di_nextrepodata;
1098 di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1101 goto di_nextrepodata;
1104 case di_enterkey: di_enterkey:
1106 di->key = di->data->keys + *di->keyp;
1107 di->ddp = get_data(di->data, di->key, &di->dp);
1110 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1112 di->ddp = data_read_id(di->ddp, &di->kv.num);
1115 goto di_nextarrayelement;
1119 case di_nextarrayelement: di_nextarrayelement:
1122 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1123 if (di->kv.entry == di->kv.num)
1125 if (di->keyname && di->key->name != di->keyname)
1127 di->kv.str = (char *)di->ddp;
1129 di->state = di_nextkey;
1132 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1133 di->ddp = data_read_id(di->ddp, &di->kv.id);
1134 di->kv.str = (char *)di->ddp;
1135 if (di->keyname && di->key->name != di->keyname)
1137 if ((di->flags & SEARCH_SUB) != 0)
1138 di->state = di_entersub;
1140 di->state = di_nextarrayelement;
1143 case di_entersub: di_entersub:
1144 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1145 goto di_nextarrayelement; /* sorry, full */
1146 di->parents[di->nparents].kv = di->kv;
1147 di->parents[di->nparents].dp = di->dp;
1148 di->parents[di->nparents].keyp = di->keyp;
1149 di->dp = (unsigned char *)di->kv.str;
1150 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1151 memset(&di->kv, 0, sizeof(di->kv));
1152 di->kv.parent = &di->parents[di->nparents].kv;
1157 case di_leavesub: di_leavesub:
1159 di->dp = di->parents[di->nparents].dp;
1160 di->kv = di->parents[di->nparents].kv;
1161 di->keyp = di->parents[di->nparents].keyp;
1162 di->key = di->data->keys + *di->keyp;
1163 di->ddp = (unsigned char *)di->kv.str;
1164 goto di_nextarrayelement;
1166 /* special solvable attr handling follows */
1168 case di_nextsolvableattr:
1169 di->kv.id = *di->idp++;
1174 di->state = di_nextsolvablekey;
1178 case di_nextsolvablekey: di_nextsolvablekey:
1179 if (di->keyname || di->key->name == RPM_RPMDBID)
1180 goto di_enterrepodata;
1184 case di_entersolvablekey: di_entersolvablekey:
1185 di->idp = solvabledata_fetch(di->pool->solvables + di->entry, &di->kv, di->key->name);
1186 if (!di->idp || !di->idp[0])
1187 goto di_nextsolvablekey;
1188 di->kv.id = di->idp[0];
1189 di->kv.num = di->idp[0];
1190 if (!di->kv.eof && !di->idp[1])
1194 di->state = di_nextsolvablekey;
1196 di->state = di_nextsolvableattr;
1200 if (di->matcher.match)
1201 if (!datamatcher_match(&di->matcher, di->data, di->key, &di->kv))
1203 /* found something! */
1209 dataiterator_setpos(Dataiterator *di)
1211 di->pool->pos.repo = di->repo;
1212 di->pool->pos.repodataid = di->data - di->repo->repodata;
1213 di->pool->pos.schema = di->kv.id;
1214 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1218 dataiterator_skip_attribute(Dataiterator *di)
1220 if (di->state == di_nextsolvableattr)
1221 di->state = di_nextsolvablekey;
1223 di->state = di_nextkey;
1227 dataiterator_skip_solvable(Dataiterator *di)
1229 di->state = di_nextsolvable;
1233 dataiterator_skip_repo(Dataiterator *di)
1235 di->state = di_nextrepo;
1239 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1243 di->entry = s - di->pool->solvables;
1244 di->state = di_entersolvable;
1248 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1252 di->state = di_enterrepo;
1256 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1258 Datamatcher matcher = di->matcher;
1259 matcher.flags = flags;
1260 matcher.match = (void *)vmatch;
1261 return datamatcher_match(&matcher, di->data, di->key, &di->kv);
1266 /************************************************************************
1267 * data search iterator
1271 dataiterator_newdata(Dataiterator *di)
1273 Id keyname = di->keyname;
1274 Repodata *data = di->data;
1277 if (data->state == REPODATA_STUB)
1282 for (j = 1; j < data->nkeys; j++)
1283 if (keyname == data->keys[j].name)
1285 if (j == data->nkeys)
1289 if (data->loadcallback)
1290 data->loadcallback(data);
1292 data->state = REPODATA_ERROR;
1294 if (data->state == REPODATA_ERROR)
1298 unsigned char *dp = data->incoredata;
1301 if (di->solvid >= 0)
1302 dp += data->incoreoffset[di->solvid - data->start];
1303 dp = data_read_id(dp, &schema);
1304 Id *keyp = data->schemadata + data->schemata[schema];
1308 /* search in a specific key */
1309 for (kp = keyp; (k = *kp++) != 0; )
1310 if (data->keys[k].name == keyname)
1314 dp = forward_to_key(data, k, keyp, dp);
1324 di->key = di->data->keys + keyid;
1329 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1334 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname,
1335 const char *match, int flags)
1341 di->flags |= __SEARCH_ONESOLVABLE;
1342 di->data = repo->repodata - 1;
1343 if (flags & SEARCH_NO_STORAGE_SOLVABLE)
1350 di->solvid = repo->start - 1;
1353 fprintf(stderr, "A repo contains the NULL solvable!\n");
1356 di->data = repo->repodata + repo->nrepodata - 1;
1361 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1365 /* We feed multiple lines eventually (e.g. authors or descriptions),
1366 so set REG_NEWLINE. */
1368 regcomp(&di->regex, di->match,
1369 REG_EXTENDED | REG_NOSUB | REG_NEWLINE
1370 | ((di->flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1372 if (di->regex_err != 0)
1374 fprintf(stderr, "Given regex failed to compile: %s\n", di->match);
1375 fprintf(stderr, "regcomp error code: %d\n", di->regex_err);
1382 di->flags |= (di->flags & SEARCH_STRINGMASK) | SEARCH_STRING;
1388 di->keyname = keyname;
1389 static Id zeroid = 0;
1397 /* FIXME factor and merge with repo_matchvalue */
1399 dataiterator_match_int_real(Dataiterator *di, int flags, const void *vmatch)
1401 KeyValue *kv = &di->kv;
1402 const char *match = vmatch;
1403 if ((flags & SEARCH_STRINGMASK) != 0)
1405 switch (di->key->type)
1407 case REPOKEY_TYPE_ID:
1408 case REPOKEY_TYPE_IDARRAY:
1409 if (di->data && di->data->localpool)
1410 kv->str = stringpool_id2str(&di->data->spool, kv->id);
1412 kv->str = id2str(di->repo->pool, kv->id);
1414 case REPOKEY_TYPE_STR:
1416 case REPOKEY_TYPE_DIRSTRARRAY:
1417 if (!(flags & SEARCH_FILES))
1419 /* Put the full filename into kv->str. */
1420 kv->str = repodata_dir2str(di->data, kv->id, kv->str);
1421 /* And to compensate for that put the "empty" directory into
1422 kv->id, so that later calls to repodata_dir2str on this data
1423 come up with the same filename again. */
1429 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
1430 for the others we can't know if a colon separates a kind or not. */
1431 if ((flags & SEARCH_SKIP_KIND)
1432 && di->key->storage == KEY_STORAGE_SOLVABLE)
1434 const char *s = strchr(kv->str, ':');
1438 switch ((flags & SEARCH_STRINGMASK))
1440 case SEARCH_SUBSTRING:
1441 if (flags & SEARCH_NOCASE)
1443 if (!strcasestr(kv->str, match))
1448 if (!strstr(kv->str, match))
1453 if (flags & SEARCH_NOCASE)
1455 if (strcasecmp(match, kv->str))
1460 if (strcmp(match, kv->str))
1465 if (fnmatch(match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
1469 if (regexec((const regex_t *)vmatch, kv->str, 0, NULL, 0))
1480 dataiterator_match_int(Dataiterator *di)
1482 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1483 return dataiterator_match_int_real(di, di->flags, &di->regex);
1485 return dataiterator_match_int_real(di, di->flags, di->match);
1489 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1491 return dataiterator_match_int_real(di, flags, vmatch);
1495 dataiterator_step(Dataiterator *di)
1502 /* we're stepping through solvable data, 1 -> SOLVABLE_NAME... */
1505 /* we're stepping through an id array */
1511 di->kv.eof = idp[1] ? 0 : 1;
1517 Solvable *s = di->repo->pool->solvables + di->solvid;
1518 int state = di->state;
1519 di->key = solvablekeys + state - 1;
1521 di->state = RPM_RPMDBID;
1528 state = di->keyname - 1;
1535 di->kv.id = s->name;
1541 di->kv.id = s->arch;
1550 case SOLVABLE_VENDOR:
1553 di->kv.id = s->vendor;
1556 case SOLVABLE_PROVIDES:
1557 di->idp = s->provides
1558 ? di->repo->idarraydata + s->provides : 0;
1560 case SOLVABLE_OBSOLETES:
1561 di->idp = s->obsoletes
1562 ? di->repo->idarraydata + s->obsoletes : 0;
1564 case SOLVABLE_CONFLICTS:
1565 di->idp = s->conflicts
1566 ? di->repo->idarraydata + s->conflicts : 0;
1568 case SOLVABLE_REQUIRES:
1569 di->idp = s->requires
1570 ? di->repo->idarraydata + s->requires : 0;
1572 case SOLVABLE_RECOMMENDS:
1573 di->idp = s->recommends
1574 ? di->repo->idarraydata + s->recommends : 0;
1576 case SOLVABLE_SUPPLEMENTS:
1577 di->idp = s->supplements
1578 ? di->repo->idarraydata + s->supplements : 0;
1580 case SOLVABLE_SUGGESTS:
1581 di->idp = s->suggests
1582 ? di->repo->idarraydata + s->suggests : 0;
1584 case SOLVABLE_ENHANCES:
1585 di->idp = s->enhances
1586 ? di->repo->idarraydata + s->enhances : 0;
1589 if (!di->repo->rpmdbid)
1591 di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
1595 di->data = di->repo->repodata - 1;
1601 else if (di->subkeyp)
1606 /* Send end-of-substruct. We are here only when we saw a
1607 _COUNTED key one level up. Since then we didn't increment
1608 ->keyp, so it still can be found at keyp[-1]. */
1610 di->key = di->data->keys + di->keyp[-1];
1613 else if (!(keyid = *di->subkeyp++))
1615 /* Send end-of-element. See above for keyp[-1]. */
1617 di->key = di->data->keys + di->keyp[-1];
1619 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1622 di->dp = data_read_id(di->dp, &di->subschema);
1623 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1630 di->key = di->data->keys + keyid;
1631 di->dp = data_fetch(di->dp, &di->kv, di->key);
1641 di->dp = data_fetch(di->dp, &di->kv, di->key);
1646 if (di->keyname || !(keyid = *di->keyp++))
1650 Repo *repo = di->repo;
1651 Repodata *data = ++di->data;
1652 if (data >= repo->repodata + repo->nrepodata)
1654 if (di->flags & __SEARCH_ONESOLVABLE)
1656 if (di->solvid >= 0)
1658 while (++di->solvid < repo->end)
1659 if (repo->pool->solvables[di->solvid].repo == repo)
1661 if (di->solvid >= repo->end)
1663 if (!(di->flags & SEARCH_EXTRA))
1672 Pool *pool = di->repo->pool;
1673 if (!(di->flags & SEARCH_ALL_REPOS)
1674 || di->repo == pool->repos[pool->nrepos - 1])
1677 for (i = 0; i < pool->nrepos; i++)
1678 if (di->repo == pool->repos[i])
1680 di->repo = pool->repos[i + 1];
1681 dataiterator_init(di, di->repo, 0, di->keyname, di->match, di->flags);
1685 di->data = repo->repodata - 1;
1686 if ((di->flags & SEARCH_NO_STORAGE_SOLVABLE))
1688 static Id zeroid = 0;
1693 if ((di->solvid >= 0 && di->solvid >= data->start && di->solvid < data->end))
1695 dataiterator_newdata(di);
1703 di->key = di->data->keys + keyid;
1704 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1706 di->dp = data_fetch(di->dp, &di->kv, di->key);
1708 if (di->key->type == REPOKEY_TYPE_FIXARRAY)
1710 di->subnum = di->kv.num;
1711 di->subschema = di->kv.id;
1713 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1715 if (di->key->type == REPOKEY_TYPE_FLEXARRAY)
1717 di->subnum = di->kv.num;
1719 di->dp = data_read_id(di->dp, &di->subschema);
1720 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1726 || dataiterator_match_int(di))
1733 dataiterator_skip_attribute(Dataiterator *di)
1737 /* This will make the next _step call to retrieve the next field. */
1742 dataiterator_skip_solvable(Dataiterator *di)
1744 /* We're done with this field. */
1746 /* And with solvable data. */
1748 /* And with all keys for this repodata and thing. */
1749 static Id zeroid = 0;
1751 /* And with all repodatas for this thing. */
1752 di->data = di->repo->repodata + di->repo->nrepodata - 1;
1753 /* Hence the next call to _step will retrieve the next thing. */
1757 dataiterator_skip_repo(Dataiterator *di)
1759 dataiterator_skip_solvable(di);
1760 /* We're done with all solvables and all extra things for this repo. */
1765 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1768 /* Simulate us being done with the solvable before the requested one. */
1769 dataiterator_skip_solvable(di);
1770 di->solvid = s - s->repo->pool->solvables;
1775 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1778 dataiterator_skip_solvable(di);
1779 di->solvid = repo->start - 1;
1784 /************************************************************************
1785 * data modify functions
1788 /* extend repodata so that it includes solvables p */
1790 repodata_extend(Repodata *data, Id p)
1792 if (data->start == data->end)
1793 data->start = data->end = p;
1796 int old = data->end - data->start;
1797 int new = p - data->end + 1;
1800 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id), REPODATA_BLOCK);
1801 memset(data->attrs + old, 0, new * sizeof(Id));
1803 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1804 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1807 if (p < data->start)
1809 int old = data->end - data->start;
1810 int new = data->start - p;
1813 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id), REPODATA_BLOCK);
1814 memmove(data->attrs + new, data->attrs, old * sizeof(Id));
1815 memset(data->attrs, 0, new * sizeof(Id));
1817 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1818 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1819 memset(data->incoreoffset, 0, new * sizeof(Id));
1825 repodata_extend_block(Repodata *data, Id start, Id num)
1829 if (!data->incoreoffset)
1831 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1832 data->start = start;
1833 data->end = start + num;
1836 repodata_extend(data, start);
1838 repodata_extend(data, start + num - 1);
1841 /**********************************************************************/
1843 #define REPODATA_ATTRS_BLOCK 63
1844 #define REPODATA_ATTRDATA_BLOCK 1023
1845 #define REPODATA_ATTRIDDATA_BLOCK 63
1849 repodata_new_handle(Repodata *data)
1853 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1856 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1857 data->xattrs[data->nxattrs] = 0;
1858 return -(data->nxattrs++);
1862 repodata_get_attrp(Repodata *data, Id handle)
1864 if (handle == REPOENTRY_META)
1868 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1873 return data->xattrs - handle;
1874 if (handle < data->start || handle >= data->end)
1875 repodata_extend(data, handle);
1877 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1878 return data->attrs + (handle - data->start);
1882 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1888 app = repodata_get_attrp(data, handle);
1893 for (pp = ap; *pp; pp += 2)
1894 /* Determine equality based on the name only, allows us to change
1895 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1896 if (data->keys[*pp].name == data->keys[keyid].name)
1909 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1919 repodata_set(Repodata *data, Id handle, Repokey *key, Id val)
1923 keyid = repodata_key2id(data, key, 1);
1924 repodata_insert_keyid(data, handle, keyid, val, 1);
1928 repodata_set_id(Repodata *data, Id handle, Id keyname, Id id)
1932 key.type = REPOKEY_TYPE_ID;
1934 key.storage = KEY_STORAGE_INCORE;
1935 repodata_set(data, handle, &key, id);
1939 repodata_set_num(Repodata *data, Id handle, Id keyname, unsigned int num)
1943 key.type = REPOKEY_TYPE_NUM;
1945 key.storage = KEY_STORAGE_INCORE;
1946 repodata_set(data, handle, &key, (Id)num);
1950 repodata_set_poolstr(Repodata *data, Id handle, Id keyname, const char *str)
1954 if (data->localpool)
1955 id = stringpool_str2id(&data->spool, str, 1);
1957 id = str2id(data->repo->pool, str, 1);
1959 key.type = REPOKEY_TYPE_ID;
1961 key.storage = KEY_STORAGE_INCORE;
1962 repodata_set(data, handle, &key, id);
1966 repodata_set_constant(Repodata *data, Id handle, Id keyname, unsigned int constant)
1970 key.type = REPOKEY_TYPE_CONSTANT;
1971 key.size = constant;
1972 key.storage = KEY_STORAGE_INCORE;
1973 repodata_set(data, handle, &key, 0);
1977 repodata_set_constantid(Repodata *data, Id handle, Id keyname, Id id)
1981 key.type = REPOKEY_TYPE_CONSTANTID;
1983 key.storage = KEY_STORAGE_INCORE;
1984 repodata_set(data, handle, &key, 0);
1988 repodata_set_void(Repodata *data, Id handle, Id keyname)
1992 key.type = REPOKEY_TYPE_VOID;
1994 key.storage = KEY_STORAGE_INCORE;
1995 repodata_set(data, handle, &key, 0);
1999 repodata_set_str(Repodata *data, Id handle, Id keyname, const char *str)
2004 l = strlen(str) + 1;
2006 key.type = REPOKEY_TYPE_STR;
2008 key.storage = KEY_STORAGE_INCORE;
2009 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2010 memcpy(data->attrdata + data->attrdatalen, str, l);
2011 repodata_set(data, handle, &key, data->attrdatalen);
2012 data->attrdatalen += l;
2016 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2019 Id *ida, *pp, **ppp;
2021 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2023 /* great! just append the new data */
2024 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2025 data->attriddatalen--; /* overwrite terminating 0 */
2026 data->lastdatalen += entrysize;
2029 ppp = repodata_get_attrp(data, handle);
2032 for (; *pp; pp += 2)
2033 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
2037 /* not found. allocate new key */
2042 key.storage = KEY_STORAGE_INCORE;
2043 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2044 repodata_set(data, handle, &key, data->attriddatalen);
2045 data->lasthandle = 0; /* next time... */
2049 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2050 oldsize += entrysize;
2051 if (ida + 1 == data->attriddata + data->attriddatalen)
2053 /* this was the last entry, just append it */
2054 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2055 data->attriddatalen--; /* overwrite terminating 0 */
2059 /* too bad. move to back. */
2060 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2061 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2062 pp[1] = data->attriddatalen;
2063 data->attriddatalen += oldsize;
2065 data->lasthandle = handle;
2066 data->lastkey = *pp;
2067 data->lastdatalen = data->attriddatalen + entrysize + 1;
2071 checksumtype2len(Id type)
2075 case REPOKEY_TYPE_MD5:
2077 case REPOKEY_TYPE_SHA1:
2079 case REPOKEY_TYPE_SHA256:
2080 return SIZEOF_SHA256;
2087 repodata_set_bin_checksum(Repodata *data, Id handle, Id keyname, Id type,
2088 const unsigned char *str)
2091 int l = checksumtype2len(type);
2098 key.storage = KEY_STORAGE_INCORE;
2099 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2100 memcpy(data->attrdata + data->attrdatalen, str, l);
2101 repodata_set(data, handle, &key, data->attrdatalen);
2102 data->attrdatalen += l;
2106 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
2109 for (i = 0; i < buflen; i++)
2111 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
2112 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
2113 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
2124 buf[i] = (buf[i] << 4) | v;
2131 repodata_set_checksum(Repodata *data, Id handle, Id keyname, Id type,
2134 unsigned char buf[64];
2135 int l = checksumtype2len(type);
2139 if (hexstr2bytes(buf, str, l) != l)
2141 fprintf(stderr, "Invalid hex character in '%s'\n", str);
2144 repodata_set_bin_checksum(data, handle, keyname, type, buf);
2148 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2153 l = checksumtype2len(type);
2156 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2157 for (i = 0; i < l; i++)
2159 unsigned char v = buf[i];
2160 unsigned char w = v >> 4;
2161 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2163 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2170 repodata_globalize_id(Repodata *data, Id id)
2172 if (!data || !data->localpool)
2174 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
2178 repodata_add_dirnumnum(Repodata *data, Id handle, Id keyname, Id dir, Id num, Id num2)
2182 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", handle, dir, num, num2, data->attriddatalen);
2184 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2185 data->attriddata[data->attriddatalen++] = dir;
2186 data->attriddata[data->attriddatalen++] = num;
2187 data->attriddata[data->attriddatalen++] = num2;
2188 data->attriddata[data->attriddatalen++] = 0;
2192 repodata_add_dirstr(Repodata *data, Id handle, Id keyname, Id dir, const char *str)
2198 l = strlen(str) + 1;
2199 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2200 memcpy(data->attrdata + data->attrdatalen, str, l);
2201 stroff = data->attrdatalen;
2202 data->attrdatalen += l;
2205 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", handle, dir, str, data->attriddatalen);
2207 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2208 data->attriddata[data->attriddatalen++] = dir;
2209 data->attriddata[data->attriddatalen++] = stroff;
2210 data->attriddata[data->attriddatalen++] = 0;
2214 repodata_add_idarray(Repodata *data, Id handle, Id keyname, Id id)
2217 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", handle, id, data->attriddatalen);
2219 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_IDARRAY, 1);
2220 data->attriddata[data->attriddatalen++] = id;
2221 data->attriddata[data->attriddatalen++] = 0;
2225 repodata_add_poolstr_array(Repodata *data, Id handle, Id keyname,
2229 if (data->localpool)
2230 id = stringpool_str2id(&data->spool, str, 1);
2232 id = str2id(data->repo->pool, str, 1);
2233 repodata_add_idarray(data, handle, keyname, id);
2237 repodata_add_fixarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2239 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2240 data->attriddata[data->attriddatalen++] = ghandle;
2241 data->attriddata[data->attriddatalen++] = 0;
2245 repodata_add_flexarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2247 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2248 data->attriddata[data->attriddatalen++] = ghandle;
2249 data->attriddata[data->attriddatalen++] = 0;
2253 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2256 if (dest == src || !(keyp = data->attrs[src]))
2258 for (; *keyp; keyp += 2)
2259 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2265 /**********************************************************************/
2267 /* unify with repo_write! */
2269 #define EXTDATA_BLOCK 1023
2277 data_addid(struct extdata *xd, Id x)
2280 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2281 dp = xd->buf + xd->len;
2286 *dp++ = (x >> 28) | 128;
2288 *dp++ = (x >> 21) | 128;
2289 *dp++ = (x >> 14) | 128;
2292 *dp++ = (x >> 7) | 128;
2294 xd->len = dp - xd->buf;
2298 data_addideof(struct extdata *xd, Id x, int eof)
2301 x = (x & 63) | ((x & ~63) << 1);
2302 data_addid(xd, (eof ? x: x | 64));
2306 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2308 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2309 memcpy(xd->buf + xd->len, blob, len);
2313 /*********************************/
2316 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2317 struct extdata *newvincore,
2319 Repokey *key, Id val)
2321 /* Otherwise we have a new value. Parse it into the internal
2325 unsigned int oldvincorelen = 0;
2329 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2332 oldvincorelen = xd->len;
2336 case REPOKEY_TYPE_VOID:
2337 case REPOKEY_TYPE_CONSTANT:
2338 case REPOKEY_TYPE_CONSTANTID:
2340 case REPOKEY_TYPE_STR:
2341 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2343 case REPOKEY_TYPE_MD5:
2344 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2346 case REPOKEY_TYPE_SHA1:
2347 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2349 case REPOKEY_TYPE_SHA256:
2350 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2352 case REPOKEY_TYPE_ID:
2353 case REPOKEY_TYPE_NUM:
2354 case REPOKEY_TYPE_DIR:
2355 data_addid(xd, val);
2357 case REPOKEY_TYPE_IDARRAY:
2358 for (ida = data->attriddata + val; *ida; ida++)
2359 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2361 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2362 for (ida = data->attriddata + val; *ida; ida += 3)
2364 data_addid(xd, ida[0]);
2365 data_addid(xd, ida[1]);
2366 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2369 case REPOKEY_TYPE_DIRSTRARRAY:
2370 for (ida = data->attriddata + val; *ida; ida += 2)
2372 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2373 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2376 case REPOKEY_TYPE_FIXARRAY:
2380 for (ida = data->attriddata + val; *ida; ida++)
2383 fprintf(stderr, "serialize struct %d\n", *ida);
2386 Id *kp = data->xattrs[-*ida];
2393 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2399 schemaid = repodata_schema2id(data, schema, 1);
2400 else if (schemaid != repodata_schema2id(data, schema, 0))
2402 fprintf(stderr, " not yet implemented: substructs with different schemas\n");
2406 fprintf(stderr, " schema %d\n", schemaid);
2411 data_addid(xd, num);
2412 data_addid(xd, schemaid);
2413 for (ida = data->attriddata + val; *ida; ida++)
2415 Id *kp = data->xattrs[-*ida];
2420 repodata_serialize_key(data, newincore, newvincore,
2421 schema, data->keys + *kp, kp[1]);
2426 case REPOKEY_TYPE_FLEXARRAY:
2429 for (ida = data->attriddata + val; *ida; ida++)
2431 data_addid(xd, num);
2432 for (ida = data->attriddata + val; *ida; ida++)
2434 Id *kp = data->xattrs[-*ida];
2437 data_addid(xd, 0); /* XXX */
2444 schemaid = repodata_schema2id(data, schema, 1);
2445 data_addid(xd, schemaid);
2446 kp = data->xattrs[-*ida];
2449 repodata_serialize_key(data, newincore, newvincore,
2450 schema, data->keys + *kp, kp[1]);
2456 fprintf(stderr, "don't know how to handle type %d\n", key->type);
2459 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2461 /* put offset/len in incore */
2462 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2463 oldvincorelen = xd->len - oldvincorelen;
2464 data_addid(newincore, oldvincorelen);
2469 repodata_internalize(Repodata *data)
2471 Repokey *key, solvkey;
2473 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2474 unsigned char *dp, *ndp;
2475 int newschema, oldcount;
2476 struct extdata newincore;
2477 struct extdata newvincore;
2480 if (!data->attrs && !data->xattrs)
2483 newvincore.buf = data->vincore;
2484 newvincore.len = data->vincorelen;
2486 /* find the solvables key, create if needed */
2487 memset(&solvkey, 0, sizeof(solvkey));
2488 solvkey.name = REPOSITORY_SOLVABLES;
2489 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2491 solvkey.storage = KEY_STORAGE_INCORE;
2492 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2494 schema = sat_malloc2(data->nkeys, sizeof(Id));
2495 seen = sat_malloc2(data->nkeys, sizeof(Id));
2497 /* Merge the data already existing (in data->schemata, ->incoredata and
2498 friends) with the new attributes in data->attrs[]. */
2499 nentry = data->end - data->start;
2500 memset(&newincore, 0, sizeof(newincore));
2501 data_addid(&newincore, 0); /* start data at offset 1 */
2503 data->mainschema = 0;
2504 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2506 /* join entry data */
2507 /* we start with the meta data, entry -1 */
2508 for (entry = -1; entry < nentry; entry++)
2510 memset(seen, 0, data->nkeys * sizeof(Id));
2512 dp = data->incoredata;
2515 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2516 dp = data_read_id(dp, &oldschema);
2519 fprintf(stderr, "oldschema %d\n", oldschema);
2520 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2521 fprintf(stderr, "schemadata %p\n", data->schemadata);
2523 /* seen: -1: old data 0: skipped >0: id + 1 */
2527 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2531 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
2539 keyp = data->attrs ? data->attrs[entry] : 0;
2542 /* strip solvables key */
2544 for (sp = keyp = schema; *sp; sp++)
2545 if (*sp != solvkeyid)
2550 seen[solvkeyid] = 0;
2551 keyp = data->xattrs ? data->xattrs[1] : 0;
2554 for (; *keyp; keyp += 2)
2561 seen[*keyp] = keyp[1] + 1;
2563 if (entry < 0 && data->end != data->start)
2570 /* Ideally we'd like to sort the new schema here, to ensure
2571 schema equality independend of the ordering. We can't do that
2572 yet. For once see below (old ids need to come before new ids).
2573 An additional difficulty is that we also need to move
2574 the values with the keys. */
2575 schemaid = repodata_schema2id(data, schema, 1);
2577 schemaid = oldschema;
2580 /* Now create data blob. We walk through the (possibly new) schema
2581 and either copy over old data, or insert the new. */
2582 /* XXX Here we rely on the fact that the (new) schema has the form
2583 o1 o2 o3 o4 ... | n1 n2 n3 ...
2584 (oX being the old keyids (possibly overwritten), and nX being
2585 the new keyids). This rules out sorting the keyids in order
2586 to ensure a small schema count. */
2588 data->incoreoffset[entry] = newincore.len;
2589 data_addid(&newincore, schemaid);
2592 data->mainschema = schemaid;
2593 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2595 keypstart = data->schemadata + data->schemata[schemaid];
2596 for (keyp = keypstart; *keyp; keyp++)
2599 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2600 if (*keyp == solvkeyid)
2602 /* add flexarray entry count */
2603 data_addid(&newincore, data->end - data->start);
2606 key = data->keys + *keyp;
2608 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2613 /* Skip the data associated with this old key. */
2614 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2616 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2617 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2619 else if (key->storage == KEY_STORAGE_INCORE)
2620 ndp = data_skip_key(data, dp, key);
2623 if (seen[*keyp] == -1)
2625 /* If this key was an old one _and_ was not overwritten with
2626 a different value copy over the old value (we skipped it
2629 data_addblob(&newincore, dp, ndp - dp);
2632 else if (seen[*keyp])
2634 /* Otherwise we have a new value. Parse it into the internal
2636 repodata_serialize_key(data, &newincore, &newvincore,
2637 schema, key, seen[*keyp] - 1);
2641 if (entry >= 0 && data->attrs && data->attrs[entry])
2642 data->attrs[entry] = sat_free(data->attrs[entry]);
2644 /* free all xattrs */
2645 for (entry = 0; entry < data->nxattrs; entry++)
2646 if (data->xattrs[entry])
2647 sat_free(data->xattrs[entry]);
2648 data->xattrs = sat_free(data->xattrs);
2651 data->lasthandle = 0;
2653 data->lastdatalen = 0;
2656 repodata_free_schemahash(data);
2658 sat_free(data->incoredata);
2659 data->incoredata = newincore.buf;
2660 data->incoredatalen = newincore.len;
2661 data->incoredatafree = 0;
2663 sat_free(data->vincore);
2664 data->vincore = newvincore.buf;
2665 data->vincorelen = newvincore.len;
2667 data->attrs = sat_free(data->attrs);
2668 data->attrdata = sat_free(data->attrdata);
2669 data->attriddata = sat_free(data->attriddata);
2670 data->attrdatalen = 0;
2671 data->attriddatalen = 0;
2675 repodata_disable_paging(Repodata *data)
2677 if (maybe_load_repodata(data, 0))
2678 repopagestore_disable_paging(&data->store);
2682 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: