2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
13 * a repository can contain multiple repodata entries, consisting of
14 * different sets of keys and different sets of solvables
29 #include "poolid_private.h"
37 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
38 unsigned char *out, unsigned int out_len);
39 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
42 unsigned int out_len);
44 #define REPODATA_BLOCK 255
48 repodata_initdata(Repodata *data, Repo *repo, int localpool)
50 memset(data, 0, sizeof (*data));
52 data->localpool = localpool;
54 stringpool_init_empty(&data->spool);
55 data->keys = sat_calloc(1, sizeof(Repokey));
57 data->schemata = sat_calloc(1, sizeof(Id));
58 data->schemadata = sat_calloc(1, sizeof(Id));
60 data->schemadatalen = 1;
61 repopagestore_init(&data->store);
65 repodata_freedata(Repodata *data)
71 sat_free(data->schemata);
72 sat_free(data->schemadata);
73 sat_free(data->schematahash);
75 stringpool_free(&data->spool);
76 dirpool_free(&data->dirpool);
78 sat_free(data->mainschemaoffsets);
79 sat_free(data->incoredata);
80 sat_free(data->incoreoffset);
81 sat_free(data->verticaloffset);
83 repopagestore_free(&data->store);
85 sat_free(data->vincore);
88 for (i = 0; i < data->end - data->start; i++)
89 sat_free(data->attrs[i]);
90 sat_free(data->attrs);
92 for (i = 0; i < data->nxattrs; i++)
93 sat_free(data->xattrs[i]);
94 sat_free(data->xattrs);
96 sat_free(data->attrdata);
97 sat_free(data->attriddata);
101 repodata_create(Repo *repo, int localpool)
106 repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
107 data = repo->repodata + repo->nrepodata - 1;
108 repodata_initdata(data, repo, localpool);
113 repodata_free(Repodata *data)
115 Repo *repo = data->repo;
116 int i = data - repo->repodata;
117 repodata_freedata(data);
118 if (i < repo->nrepodata - 1)
119 memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
124 /***************************************************************
125 * key pool management
128 /* this is not so time critical that we need a hash, so we do a simple
131 repodata_key2id(Repodata *data, Repokey *key, int create)
135 for (keyid = 1; keyid < data->nkeys; keyid++)
136 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
138 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
142 if (keyid == data->nkeys)
146 /* allocate new key */
147 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
148 data->keys[data->nkeys++] = *key;
149 if (data->verticaloffset)
151 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
152 data->verticaloffset[data->nkeys - 1] = 0;
154 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
160 /***************************************************************
161 * schema pool management
164 #define SCHEMATA_BLOCK 31
165 #define SCHEMATADATA_BLOCK 255
168 repodata_schema2id(Repodata *data, Id *schema, int create)
174 if ((schematahash = data->schematahash) == 0)
176 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
177 for (i = 0; i < data->nschemata; i++)
179 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
182 schematahash[h] = i + 1;
184 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
185 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
188 for (sp = schema, len = 0, h = 0; *sp; len++)
193 cid = schematahash[h];
197 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
200 for (cid = 0; cid < data->nschemata; cid++)
201 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
207 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
208 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
210 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
211 data->schemata[data->nschemata] = data->schemadatalen;
212 data->schemadatalen += len;
213 schematahash[h] = data->nschemata + 1;
215 fprintf(stderr, "schema2id: new schema\n");
217 return data->nschemata++;
221 repodata_free_schemahash(Repodata *data)
223 data->schematahash = sat_free(data->schematahash);
225 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
226 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
230 /***************************************************************
231 * dir pool management
235 repodata_str2dir(Repodata *data, const char *dir, int create)
241 while (*dir == '/' && dir[1] == '/')
243 if (*dir == '/' && !dir[1])
247 dire = strchrnul(dir, '/');
249 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
251 id = strn2id(data->repo->pool, dir, dire - dir, create);
254 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
267 repodata_dir2str(Repodata *data, Id did, const char *suf)
269 Pool *pool = data->repo->pool;
276 return suf ? suf : "";
280 comp = dirpool_compid(&data->dirpool, parent);
281 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
283 parent = dirpool_parent(&data->dirpool, parent);
288 l += strlen(suf) + 1;
289 p = pool_alloctmpspace(pool, l + 1) + l;
300 comp = dirpool_compid(&data->dirpool, parent);
301 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
304 strncpy(p, comps, l);
305 parent = dirpool_parent(&data->dirpool, parent);
313 /***************************************************************
317 static inline unsigned char *
318 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
320 Id *keyp = data->schemadata + data->schemata[schema];
321 for (; *keyp; keyp++)
322 dp = data_skip_key(data, dp, data->keys + *keyp);
327 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
329 int nentries, schema;
332 case REPOKEY_TYPE_FIXARRAY:
333 dp = data_read_id(dp, &nentries);
336 dp = data_read_id(dp, &schema);
338 dp = data_skip_schema(data, dp, schema);
340 case REPOKEY_TYPE_FLEXARRAY:
341 dp = data_read_id(dp, &nentries);
344 dp = data_read_id(dp, &schema);
345 dp = data_skip_schema(data, dp, schema);
349 if (key->storage == KEY_STORAGE_INCORE)
350 dp = data_skip(dp, key->type);
351 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
353 dp = data_skip(dp, REPOKEY_TYPE_ID);
354 dp = data_skip(dp, REPOKEY_TYPE_ID);
360 static unsigned char *
361 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
367 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
370 for (i = 0; (k = *keyp++) != 0; i++)
372 return data->incoredata + data->mainschemaoffsets[i];
375 while ((k = *keyp++) != 0)
379 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
381 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
382 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
385 if (data->keys[k].storage != KEY_STORAGE_INCORE)
387 dp = data_skip_key(data, dp, data->keys + k);
392 static unsigned char *
393 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
398 if (off >= data->lastverticaloffset)
400 off -= data->lastverticaloffset;
401 if (off + len > data->vincorelen)
403 return data->vincore + off;
405 if (off + len > key->size)
407 /* we now have the offset, go into vertical */
408 off += data->verticaloffset[key - data->keys];
409 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
410 dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
412 dp += off % BLOB_PAGESIZE;
416 static inline unsigned char *
417 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
419 unsigned char *dp = *dpp;
423 if (key->storage == KEY_STORAGE_INCORE)
426 *dpp = data_skip_key(data, dp, key);
429 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
432 dp = data_read_id(dp, &off);
433 dp = data_read_id(dp, &len);
436 return get_vertical_data(data, key, off, len);
442 load_repodata(Repodata *data)
444 if (data->loadcallback)
446 data->loadcallback(data);
447 if (data->state == REPODATA_AVAILABLE)
450 data->state = REPODATA_ERROR;
455 maybe_load_repodata(Repodata *data, Id keyname)
457 if (keyname && !repodata_precheck_keyname(data, keyname))
458 return 0; /* do not bother... */
465 for (i = 0; i < data->nkeys; i++)
466 if (keyname == data->keys[i].name)
468 if (i == data->nkeys)
471 return load_repodata(data);
474 case REPODATA_AVAILABLE:
477 data->state = REPODATA_ERROR;
482 static inline unsigned char *
483 solvid2data(Repodata *data, Id solvid, Id *schemap)
485 unsigned char *dp = data->incoredata;
488 if (solvid == SOLVID_META) /* META */
490 else if (solvid == SOLVID_POS) /* META */
492 Pool *pool = data->repo->pool;
493 if (data->repo != pool->pos.repo)
495 if (data != data->repo->repodata + pool->pos.repodataid)
497 *schemap = pool->pos.schema;
498 return data->incoredata + pool->pos.dp;
502 if (solvid < data->start || solvid >= data->end)
504 dp += data->incoreoffset[solvid - data->start];
506 return data_read_id(dp, schemap);
509 /************************************************************************
513 static inline unsigned char *
514 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
517 Id schema, *keyp, *kp;
520 if (!maybe_load_repodata(data, keyname))
522 dp = solvid2data(data, solvid, &schema);
525 keyp = data->schemadata + data->schemata[schema];
526 for (kp = keyp; *kp; kp++)
527 if (data->keys[*kp].name == keyname)
531 *keypp = key = data->keys + *kp;
532 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
533 return dp; /* no need to forward... */
534 dp = forward_to_key(data, *kp, keyp, dp);
537 return get_data(data, key, &dp, 0);
542 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
548 dp = find_key_data(data, solvid, keyname, &key);
551 if (key->type == REPOKEY_TYPE_CONSTANTID)
553 if (key->type != REPOKEY_TYPE_ID)
555 dp = data_read_id(dp, &id);
560 repodata_globalize_id(Repodata *data, Id id, int create)
562 if (!id || !data || !data->localpool)
564 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
568 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
574 dp = find_key_data(data, solvid, keyname, &key);
577 if (key->type == REPOKEY_TYPE_STR)
578 return (const char *)dp;
579 if (key->type == REPOKEY_TYPE_CONSTANTID)
580 return id2str(data->repo->pool, key->size);
581 if (key->type == REPOKEY_TYPE_ID)
582 dp = data_read_id(dp, &id);
586 return data->spool.stringspace + data->spool.strings[id];
587 return id2str(data->repo->pool, id);
591 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
598 dp = find_key_data(data, solvid, keyname, &key);
601 if (key->type == REPOKEY_TYPE_NUM
602 || key->type == REPOKEY_TYPE_U32
603 || key->type == REPOKEY_TYPE_CONSTANT)
605 dp = data_fetch(dp, &kv, key);
613 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
619 if (!maybe_load_repodata(data, keyname))
621 dp = solvid2data(data, solvid, &schema);
624 /* can't use find_key_data as we need to test the type */
625 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
626 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
631 const unsigned char *
632 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
637 dp = find_key_data(data, solvid, keyname, &key);
645 /************************************************************************
651 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
655 case REPOKEY_TYPE_ID:
656 case REPOKEY_TYPE_CONSTANTID:
657 case REPOKEY_TYPE_IDARRAY:
658 if (data && data->localpool)
659 kv->str = stringpool_id2str(&data->spool, kv->id);
661 kv->str = id2str(pool, kv->id);
662 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
665 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
667 if (*s == ':' && s > kv->str)
671 case REPOKEY_TYPE_STR:
673 case REPOKEY_TYPE_DIRSTRARRAY:
674 if (!(flags & SEARCH_FILES))
675 return 1; /* match just the basename */
676 /* Put the full filename into kv->str. */
677 kv->str = repodata_dir2str(data, kv->id, kv->str);
678 /* And to compensate for that put the "empty" directory into
679 kv->id, so that later calls to repodata_dir2str on this data
680 come up with the same filename again. */
683 case REPOKEY_TYPE_MD5:
684 case REPOKEY_TYPE_SHA1:
685 case REPOKEY_TYPE_SHA256:
686 if (!(flags & SEARCH_CHECKSUMS))
687 return 0; /* skip em */
688 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
696 struct subschema_data {
702 /* search a specific repodata */
704 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
708 Id keyid, *kp, *keyp;
709 unsigned char *dp, *ddp;
715 if (!maybe_load_repodata(data, keyname))
717 if (solvid == SOLVID_SUBSCHEMA)
719 struct subschema_data *subd = cbdata;
720 cbdata = subd->cbdata;
722 schema = subd->parent->id;
723 dp = (unsigned char *)subd->parent->str;
724 kv.parent = subd->parent;
729 dp = solvid2data(data, solvid, &schema);
732 s = data->repo->pool->solvables + solvid;
735 keyp = data->schemadata + data->schemata[schema];
738 /* search for a specific key */
739 for (kp = keyp; *kp; kp++)
740 if (data->keys[*kp].name == keyname)
744 dp = forward_to_key(data, *kp, keyp, dp);
750 while ((keyid = *keyp++) != 0)
753 key = data->keys + keyid;
754 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
756 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
758 struct subschema_data subd;
762 subd.cbdata = cbdata;
765 ddp = data_read_id(ddp, &nentries);
769 while (ddp && nentries > 0)
773 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
774 ddp = data_read_id(ddp, &schema);
776 kv.str = (char *)ddp;
777 stop = callback(cbdata, s, data, key, &kv);
778 if (stop > SEARCH_NEXT_KEY)
780 if (stop && stop != SEARCH_ENTERSUB)
782 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
783 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
784 ddp = data_skip_schema(data, ddp, schema);
787 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
791 kv.str = (char *)ddp;
792 stop = callback(cbdata, s, data, key, &kv);
793 if (stop > SEARCH_NEXT_KEY)
803 ddp = data_fetch(ddp, &kv, key);
806 stop = callback(cbdata, s, data, key, &kv);
809 while (!kv.eof && !stop);
810 if (onekey || stop > SEARCH_NEXT_KEY)
816 repodata_setpos_kv(Repodata *data, KeyValue *kv)
818 Pool *pool = data->repo->pool;
820 pool_clear_pos(pool);
823 pool->pos.repo = data->repo;
824 pool->pos.repodataid = data - data->repo->repodata;
825 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
826 pool->pos.schema = kv->id;
830 /************************************************************************
831 * data iterator functions
834 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
835 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
836 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
837 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
838 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
839 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
840 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
841 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
842 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
843 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
844 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
845 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
846 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
847 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
851 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
865 case SOLVABLE_VENDOR:
868 case SOLVABLE_PROVIDES:
870 return s->provides ? s->repo->idarraydata + s->provides : 0;
871 case SOLVABLE_OBSOLETES:
873 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
874 case SOLVABLE_CONFLICTS:
876 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
877 case SOLVABLE_REQUIRES:
879 return s->requires ? s->repo->idarraydata + s->requires : 0;
880 case SOLVABLE_RECOMMENDS:
882 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
883 case SOLVABLE_SUPPLEMENTS:
885 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
886 case SOLVABLE_SUGGESTS:
888 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
889 case SOLVABLE_ENHANCES:
891 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
894 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
901 datamatcher_init(Datamatcher *ma, const char *match, int flags)
907 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
909 ma->matchdata = sat_calloc(1, sizeof(regex_t));
910 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
913 sat_free(ma->matchdata);
914 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
921 datamatcher_free(Datamatcher *ma)
923 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
925 regfree(ma->matchdata);
926 ma->matchdata = sat_free(ma->matchdata);
931 datamatcher_match(Datamatcher *ma, const char *str)
933 switch ((ma->flags & SEARCH_STRINGMASK))
935 case SEARCH_SUBSTRING:
936 if (ma->flags & SEARCH_NOCASE)
938 if (!strcasestr(str, ma->match))
943 if (!strstr(str, ma->match))
948 if (ma->flags & SEARCH_NOCASE)
950 if (strcasecmp(ma->match, str))
955 if (strcmp(ma->match, str))
960 if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
964 if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
999 /* see repo.h for documentation */
1001 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1003 memset(di, 0, sizeof(*di));
1005 di->flags = flags & ~SEARCH_THISSOLVID;
1006 if (!pool || (repo && repo->pool != pool))
1014 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1020 di->keyname = keyname;
1021 di->keynames[0] = keyname;
1022 dataiterator_set_search(di, repo, p);
1027 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1030 memset(&di->matcher, 0, sizeof(di->matcher));
1031 if (from->matcher.match)
1032 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1037 for (i = 1; i < di->nparents; i++)
1038 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1039 di->kv.parent = &di->parents[di->nparents - 1].kv;
1044 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1046 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1047 datamatcher_free(&di->matcher);
1048 memset(&di->matcher, 0, sizeof(di->matcher));
1052 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1062 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1066 di->flags &= ~SEARCH_THISSOLVID;
1070 if (!di->pool->nrepos)
1078 di->repo = di->pool->repos[0];
1080 di->state = di_enterrepo;
1082 dataiterator_jump_to_solvid(di, p);
1086 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1089 di->keyname = keyname;
1090 di->keynames[0] = keyname;
1094 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1098 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1100 di->state = di_bye; /* sorry */
1103 for (i = di->nkeynames + 1; i > 0; i--)
1104 di->keynames[i] = di->keynames[i - 1];
1105 di->keynames[0] = di->keyname = keyname;
1110 dataiterator_free(Dataiterator *di)
1112 if (di->matcher.match)
1113 datamatcher_free(&di->matcher);
1116 static inline unsigned char *
1117 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1119 Id *keyp = di->keyp;
1120 Repokey *keys = di->data->keys;
1123 for (keyp = di->keyp; *keyp; keyp++)
1124 if (keys[*keyp].name == keyname)
1128 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1136 dataiterator_step(Dataiterator *di)
1144 case di_enterrepo: di_enterrepo:
1147 if (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS))
1149 if (!(di->flags & SEARCH_THISSOLVID))
1151 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1152 goto di_nextsolvable;
1156 case di_entersolvable: di_entersolvable:
1157 if (di->repodataid >= 0)
1159 di->repodataid = 0; /* reset repodata iterator */
1160 if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
1162 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1164 goto di_entersolvablekey;
1169 case di_enterrepodata: di_enterrepodata:
1170 if (di->repodataid >= 0)
1172 if (di->repodataid >= di->repo->nrepodata)
1173 goto di_nextsolvable;
1174 di->data = di->repo->repodata + di->repodataid;
1176 if (!maybe_load_repodata(di->data, di->keyname))
1177 goto di_nextrepodata;
1178 di->dp = solvid2data(di->data, di->solvid, &schema);
1180 goto di_nextrepodata;
1181 if (di->solvid == SOLVID_POS)
1182 di->solvid = di->pool->pos.solvid;
1183 /* reset key iterator */
1184 di->keyp = di->data->schemadata + di->data->schemata[schema];
1187 case di_enterschema: di_enterschema:
1189 di->dp = dataiterator_find_keyname(di, di->keyname);
1190 if (!di->dp || !*di->keyp)
1194 goto di_nextrepodata;
1198 case di_enterkey: di_enterkey:
1200 di->key = di->data->keys + *di->keyp;
1201 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1204 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1206 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1212 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1214 di->state = di_nextkey;
1216 di->state = di_nextattr;
1219 case di_nextkey: di_nextkey:
1220 if (!di->keyname && *++di->keyp)
1226 case di_nextrepodata: di_nextrepodata:
1227 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1228 goto di_enterrepodata;
1231 case di_nextsolvable: di_nextsolvable:
1232 if (!(di->flags & SEARCH_THISSOLVID))
1235 di->solvid = di->repo->start;
1238 for (; di->solvid < di->repo->end; di->solvid++)
1240 if (di->pool->solvables[di->solvid].repo == di->repo)
1241 goto di_entersolvable;
1246 case di_nextrepo: di_nextrepo:
1247 if (di->repoid >= 0)
1250 if (di->repoid < di->pool->nrepos)
1252 di->repo = di->pool->repos[di->repoid];
1258 case di_bye: di_bye:
1262 case di_enterarray: di_enterarray:
1263 if (di->key->name == REPOSITORY_SOLVABLES)
1265 di->ddp = data_read_id(di->ddp, &di->kv.num);
1270 case di_nextarrayelement: di_nextarrayelement:
1273 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1274 if (di->kv.entry == di->kv.num)
1276 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1278 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1280 di->kv.str = (char *)di->ddp;
1282 di->state = di_nextkey;
1285 if (di->kv.entry == di->kv.num - 1)
1287 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1288 di->ddp = data_read_id(di->ddp, &di->kv.id);
1289 di->kv.str = (char *)di->ddp;
1290 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1292 if ((di->flags & SEARCH_SUB) != 0)
1293 di->state = di_entersub;
1295 di->state = di_nextarrayelement;
1298 case di_entersub: di_entersub:
1299 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1300 goto di_nextarrayelement; /* sorry, full */
1301 di->parents[di->nparents].kv = di->kv;
1302 di->parents[di->nparents].dp = di->dp;
1303 di->parents[di->nparents].keyp = di->keyp;
1304 di->dp = (unsigned char *)di->kv.str;
1305 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1306 memset(&di->kv, 0, sizeof(di->kv));
1307 di->kv.parent = &di->parents[di->nparents].kv;
1309 di->keyname = di->keynames[di->nparents - di->rootlevel];
1310 goto di_enterschema;
1312 case di_leavesub: di_leavesub:
1313 if (di->nparents - 1 < di->rootlevel)
1316 di->dp = di->parents[di->nparents].dp;
1317 di->kv = di->parents[di->nparents].kv;
1318 di->keyp = di->parents[di->nparents].keyp;
1319 di->key = di->data->keys + *di->keyp;
1320 di->ddp = (unsigned char *)di->kv.str;
1321 di->keyname = di->keynames[di->nparents - di->rootlevel];
1322 goto di_nextarrayelement;
1324 /* special solvable attr handling follows */
1326 case di_nextsolvableattr:
1327 di->kv.id = *di->idp++;
1332 di->state = di_nextsolvablekey;
1336 case di_nextsolvablekey: di_nextsolvablekey:
1337 if (di->keyname || di->key->name == RPM_RPMDBID)
1338 goto di_enterrepodata;
1342 case di_entersolvablekey: di_entersolvablekey:
1343 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1344 if (!di->idp || !di->idp[0])
1345 goto di_nextsolvablekey;
1346 di->kv.id = di->idp[0];
1347 di->kv.num = di->idp[0];
1349 if (!di->kv.eof && !di->idp[0])
1353 di->state = di_nextsolvablekey;
1355 di->state = di_nextsolvableattr;
1359 if (di->matcher.match)
1361 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1363 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1367 if (!datamatcher_match(&di->matcher, di->kv.str))
1370 /* found something! */
1376 dataiterator_entersub(Dataiterator *di)
1378 if (di->state == di_nextarrayelement)
1379 di->state = di_entersub;
1383 dataiterator_setpos(Dataiterator *di)
1385 if (di->kv.eof == 2)
1387 pool_clear_pos(di->pool);
1390 di->pool->pos.solvid = di->solvid;
1391 di->pool->pos.repo = di->repo;
1392 di->pool->pos.repodataid = di->data - di->repo->repodata;
1393 di->pool->pos.schema = di->kv.id;
1394 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1398 dataiterator_setpos_parent(Dataiterator *di)
1400 if (!di->kv.parent || di->kv.parent->eof == 2)
1402 pool_clear_pos(di->pool);
1405 di->pool->pos.solvid = di->solvid;
1406 di->pool->pos.repo = di->repo;
1407 di->pool->pos.repodataid = di->data - di->repo->repodata;
1408 di->pool->pos.schema = di->kv.parent->id;
1409 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1412 /* clones just the position, not the search keys/matcher */
1414 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1416 di->state = from->state;
1417 di->flags &= ~SEARCH_THISSOLVID;
1418 di->flags |= (from->flags & SEARCH_THISSOLVID);
1419 di->repo = from->repo;
1420 di->data = from->data;
1422 di->ddp = from->ddp;
1423 di->idp = from->idp;
1424 di->keyp = from->keyp;
1425 di->key = from->key;
1427 di->repodataid = from->repodataid;
1428 di->solvid = from->solvid;
1429 di->repoid = from->repoid;
1430 di->rootlevel = from->rootlevel;
1431 memcpy(di->parents, from->parents, sizeof(from->parents));
1432 di->nparents = from->nparents;
1436 for (i = 1; i < di->nparents; i++)
1437 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1438 di->kv.parent = &di->parents[di->nparents - 1].kv;
1443 dataiterator_seek(Dataiterator *di, int whence)
1445 if ((whence & DI_SEEK_STAY) != 0)
1446 di->rootlevel = di->nparents;
1447 switch (whence & ~DI_SEEK_STAY)
1450 if (di->state != di_nextarrayelement)
1452 if ((whence & DI_SEEK_STAY) != 0)
1453 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1454 di->state = di_entersub;
1456 case DI_SEEK_PARENT:
1463 if (di->rootlevel > di->nparents)
1464 di->rootlevel = di->nparents;
1465 di->dp = di->parents[di->nparents].dp;
1466 di->kv = di->parents[di->nparents].kv;
1467 di->keyp = di->parents[di->nparents].keyp;
1468 di->key = di->data->keys + *di->keyp;
1469 di->ddp = (unsigned char *)di->kv.str;
1470 di->keyname = di->keynames[di->nparents - di->rootlevel];
1471 di->state = di_nextarrayelement;
1473 case DI_SEEK_REWIND:
1479 di->dp = (unsigned char *)di->kv.parent->str;
1480 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1481 di->state = di_enterschema;
1489 dataiterator_skip_attribute(Dataiterator *di)
1491 if (di->state == di_nextsolvableattr)
1492 di->state = di_nextsolvablekey;
1494 di->state = di_nextkey;
1498 dataiterator_skip_solvable(Dataiterator *di)
1500 di->state = di_nextsolvable;
1504 dataiterator_skip_repo(Dataiterator *di)
1506 di->state = di_nextrepo;
1510 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1514 if (solvid == SOLVID_POS)
1516 di->repo = di->pool->pos.repo;
1523 di->data = di->repo->repodata + di->pool->pos.repodataid;
1524 di->repodataid = -1;
1525 di->solvid = solvid;
1526 di->state = di_enterrepo;
1527 di->flags |= SEARCH_THISSOLVID;
1532 di->repo = di->pool->solvables[solvid].repo;
1535 else if (di->repoid >= 0)
1537 if (!di->pool->nrepos)
1542 di->repo = di->pool->repos[0];
1546 di->solvid = solvid;
1548 di->flags |= SEARCH_THISSOLVID;
1549 di->state = di_enterrepo;
1553 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1561 di->flags &= ~SEARCH_THISSOLVID;
1562 di->state = di_enterrepo;
1566 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1568 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1572 return datamatcher_match(ma, di->kv.str);
1575 /************************************************************************
1576 * data modify functions
1579 /* extend repodata so that it includes solvables p */
1581 repodata_extend(Repodata *data, Id p)
1583 if (data->start == data->end)
1584 data->start = data->end = p;
1587 int old = data->end - data->start;
1588 int new = p - data->end + 1;
1591 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1592 memset(data->attrs + old, 0, new * sizeof(Id *));
1594 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1595 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1598 if (p < data->start)
1600 int old = data->end - data->start;
1601 int new = data->start - p;
1604 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1605 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1606 memset(data->attrs, 0, new * sizeof(Id *));
1608 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1609 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1610 memset(data->incoreoffset, 0, new * sizeof(Id));
1616 repodata_shrink(Repodata *data, int end)
1620 if (data->end <= end)
1622 if (data->start >= end)
1626 for (i = 0; i < data->end - data->start; i++)
1627 sat_free(data->attrs[i]);
1628 data->attrs = sat_free(data->attrs);
1630 data->incoreoffset = sat_free(data->incoreoffset);
1631 data->start = data->end = 0;
1636 for (i = end; i < data->end; i++)
1637 sat_free(data->attrs[i - data->start]);
1638 data->attrs = sat_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1640 if (data->incoreoffset)
1641 data->incoreoffset = sat_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1645 /* extend repodata so that it includes solvables from start to start + num - 1 */
1647 repodata_extend_block(Repodata *data, Id start, Id num)
1651 if (!data->incoreoffset)
1653 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1654 data->start = start;
1655 data->end = start + num;
1658 repodata_extend(data, start);
1660 repodata_extend(data, start + num - 1);
1663 /**********************************************************************/
1665 #define REPODATA_ATTRS_BLOCK 63
1666 #define REPODATA_ATTRDATA_BLOCK 1023
1667 #define REPODATA_ATTRIDDATA_BLOCK 63
1671 repodata_new_handle(Repodata *data)
1675 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1678 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1679 data->xattrs[data->nxattrs] = 0;
1680 return -(data->nxattrs++);
1684 repodata_get_attrp(Repodata *data, Id handle)
1686 if (handle == SOLVID_META)
1690 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1695 return data->xattrs - handle;
1696 if (handle < data->start || handle >= data->end)
1697 repodata_extend(data, handle);
1699 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1700 return data->attrs + (handle - data->start);
1704 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1710 app = repodata_get_attrp(data, handle);
1715 for (pp = ap; *pp; pp += 2)
1716 /* Determine equality based on the name only, allows us to change
1717 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1718 if (data->keys[*pp].name == data->keys[keyid].name)
1731 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1741 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1745 keyid = repodata_key2id(data, key, 1);
1746 repodata_insert_keyid(data, solvid, keyid, val, 1);
1750 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1754 key.type = REPOKEY_TYPE_ID;
1756 key.storage = KEY_STORAGE_INCORE;
1757 repodata_set(data, solvid, &key, id);
1761 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1765 key.type = REPOKEY_TYPE_NUM;
1767 key.storage = KEY_STORAGE_INCORE;
1768 repodata_set(data, solvid, &key, (Id)num);
1772 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1776 if (data->localpool)
1777 id = stringpool_str2id(&data->spool, str, 1);
1779 id = str2id(data->repo->pool, str, 1);
1781 key.type = REPOKEY_TYPE_ID;
1783 key.storage = KEY_STORAGE_INCORE;
1784 repodata_set(data, solvid, &key, id);
1788 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1792 key.type = REPOKEY_TYPE_CONSTANT;
1793 key.size = constant;
1794 key.storage = KEY_STORAGE_INCORE;
1795 repodata_set(data, solvid, &key, 0);
1799 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1803 key.type = REPOKEY_TYPE_CONSTANTID;
1805 key.storage = KEY_STORAGE_INCORE;
1806 repodata_set(data, solvid, &key, 0);
1810 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1814 key.type = REPOKEY_TYPE_VOID;
1816 key.storage = KEY_STORAGE_INCORE;
1817 repodata_set(data, solvid, &key, 0);
1821 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1826 l = strlen(str) + 1;
1828 key.type = REPOKEY_TYPE_STR;
1830 key.storage = KEY_STORAGE_INCORE;
1831 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1832 memcpy(data->attrdata + data->attrdatalen, str, l);
1833 repodata_set(data, solvid, &key, data->attrdatalen);
1834 data->attrdatalen += l;
1837 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1838 * so that the caller can append the new element there */
1840 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1843 Id *ida, *pp, **ppp;
1845 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1847 /* great! just append the new data */
1848 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1849 data->attriddatalen--; /* overwrite terminating 0 */
1850 data->lastdatalen += entrysize;
1853 ppp = repodata_get_attrp(data, handle);
1856 for (; *pp; pp += 2)
1857 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1861 /* not found. allocate new key */
1866 key.storage = KEY_STORAGE_INCORE;
1867 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1868 repodata_set(data, handle, &key, data->attriddatalen);
1869 data->lasthandle = 0; /* next time... */
1873 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1874 oldsize += entrysize;
1875 if (ida + 1 == data->attriddata + data->attriddatalen)
1877 /* this was the last entry, just append it */
1878 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1879 data->attriddatalen--; /* overwrite terminating 0 */
1883 /* too bad. move to back. */
1884 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1885 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1886 pp[1] = data->attriddatalen;
1887 data->attriddatalen += oldsize;
1889 data->lasthandle = handle;
1890 data->lastkey = *pp;
1891 data->lastdatalen = data->attriddatalen + entrysize + 1;
1895 checksumtype2len(Id type)
1899 case REPOKEY_TYPE_MD5:
1901 case REPOKEY_TYPE_SHA1:
1903 case REPOKEY_TYPE_SHA256:
1904 return SIZEOF_SHA256;
1911 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1912 const unsigned char *str)
1915 int l = checksumtype2len(type);
1922 key.storage = KEY_STORAGE_INCORE;
1923 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1924 memcpy(data->attrdata + data->attrdatalen, str, l);
1925 repodata_set(data, solvid, &key, data->attrdatalen);
1926 data->attrdatalen += l;
1930 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1933 for (i = 0; i < buflen; i++)
1935 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1936 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
1937 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
1948 buf[i] = (buf[i] << 4) | v;
1955 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1958 unsigned char buf[64];
1959 int l = checksumtype2len(type);
1963 if (hexstr2bytes(buf, str, l) != l)
1965 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
1969 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1974 l = checksumtype2len(type);
1977 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1978 for (i = 0; i < l; i++)
1980 unsigned char v = buf[i];
1981 unsigned char w = v >> 4;
1982 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1984 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1990 /* rpm filenames don't contain the epoch, so strip it */
1991 static inline const char *
1992 evrid2vrstr(Pool *pool, Id evrid)
1994 const char *p, *evr = id2str(pool, evrid);
1997 for (p = evr; *p >= '0' && *p <= '9'; p++)
1999 return p != evr && *p == ':' ? p + 1 : evr;
2003 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2005 Pool *pool = data->repo->pool;
2007 const char *str, *fp;
2011 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2014 if ((dir = strrchr(file, '/')) != 0)
2025 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2030 if (l == 1 && dir[0] == '.')
2032 s = pool->solvables + solvid;
2035 str = id2str(pool, s->arch);
2036 if (!strncmp(dir, str, l) && !str[l])
2037 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2039 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
2042 char *dir2 = strdup(dir);
2044 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
2049 str = id2str(pool, s->name);
2051 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2054 str = evrid2vrstr(pool, s->evr);
2056 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2059 str = id2str(pool, s->arch);
2061 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2063 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2068 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2072 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2076 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2078 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2079 data->attriddata[data->attriddatalen++] = dir;
2080 data->attriddata[data->attriddatalen++] = num;
2081 data->attriddata[data->attriddatalen++] = num2;
2082 data->attriddata[data->attriddatalen++] = 0;
2086 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2092 l = strlen(str) + 1;
2093 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2094 memcpy(data->attrdata + data->attrdatalen, str, l);
2095 stroff = data->attrdatalen;
2096 data->attrdatalen += l;
2099 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2101 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2102 data->attriddata[data->attriddatalen++] = dir;
2103 data->attriddata[data->attriddatalen++] = stroff;
2104 data->attriddata[data->attriddatalen++] = 0;
2108 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2111 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2113 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2114 data->attriddata[data->attriddatalen++] = id;
2115 data->attriddata[data->attriddatalen++] = 0;
2119 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2123 if (data->localpool)
2124 id = stringpool_str2id(&data->spool, str, 1);
2126 id = str2id(data->repo->pool, str, 1);
2127 repodata_add_idarray(data, solvid, keyname, id);
2131 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2133 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2134 data->attriddata[data->attriddatalen++] = ghandle;
2135 data->attriddata[data->attriddatalen++] = 0;
2139 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2141 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2142 data->attriddata[data->attriddatalen++] = ghandle;
2143 data->attriddata[data->attriddatalen++] = 0;
2146 /* add all attrs from src to dest */
2148 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2151 if (dest == src || !(keyp = data->attrs[src - data->start]))
2153 for (; *keyp; keyp += 2)
2154 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2160 /**********************************************************************/
2162 /* unify with repo_write! */
2164 #define EXTDATA_BLOCK 1023
2172 data_addid(struct extdata *xd, Id x)
2175 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2176 dp = xd->buf + xd->len;
2181 *dp++ = (x >> 28) | 128;
2183 *dp++ = (x >> 21) | 128;
2184 *dp++ = (x >> 14) | 128;
2187 *dp++ = (x >> 7) | 128;
2189 xd->len = dp - xd->buf;
2193 data_addideof(struct extdata *xd, Id x, int eof)
2196 x = (x & 63) | ((x & ~63) << 1);
2197 data_addid(xd, (eof ? x: x | 64));
2201 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2203 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2204 memcpy(xd->buf + xd->len, blob, len);
2208 /*********************************/
2211 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2212 struct extdata *newvincore,
2214 Repokey *key, Id val)
2216 /* Otherwise we have a new value. Parse it into the internal
2220 unsigned int oldvincorelen = 0;
2224 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2227 oldvincorelen = xd->len;
2231 case REPOKEY_TYPE_VOID:
2232 case REPOKEY_TYPE_CONSTANT:
2233 case REPOKEY_TYPE_CONSTANTID:
2235 case REPOKEY_TYPE_STR:
2236 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2238 case REPOKEY_TYPE_MD5:
2239 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2241 case REPOKEY_TYPE_SHA1:
2242 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2244 case REPOKEY_TYPE_SHA256:
2245 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2247 case REPOKEY_TYPE_ID:
2248 case REPOKEY_TYPE_NUM:
2249 case REPOKEY_TYPE_DIR:
2250 data_addid(xd, val);
2252 case REPOKEY_TYPE_IDARRAY:
2253 for (ida = data->attriddata + val; *ida; ida++)
2254 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2256 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2257 for (ida = data->attriddata + val; *ida; ida += 3)
2259 data_addid(xd, ida[0]);
2260 data_addid(xd, ida[1]);
2261 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2264 case REPOKEY_TYPE_DIRSTRARRAY:
2265 for (ida = data->attriddata + val; *ida; ida += 2)
2267 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2268 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2271 case REPOKEY_TYPE_FIXARRAY:
2275 for (ida = data->attriddata + val; *ida; ida++)
2278 fprintf(stderr, "serialize struct %d\n", *ida);
2281 Id *kp = data->xattrs[-*ida];
2288 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2294 schemaid = repodata_schema2id(data, schema, 1);
2295 else if (schemaid != repodata_schema2id(data, schema, 0))
2297 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2301 fprintf(stderr, " schema %d\n", schemaid);
2306 data_addid(xd, num);
2307 data_addid(xd, schemaid);
2308 for (ida = data->attriddata + val; *ida; ida++)
2310 Id *kp = data->xattrs[-*ida];
2315 repodata_serialize_key(data, newincore, newvincore,
2316 schema, data->keys + *kp, kp[1]);
2321 case REPOKEY_TYPE_FLEXARRAY:
2324 for (ida = data->attriddata + val; *ida; ida++)
2326 data_addid(xd, num);
2327 for (ida = data->attriddata + val; *ida; ida++)
2329 Id *kp = data->xattrs[-*ida];
2332 data_addid(xd, 0); /* XXX */
2339 schemaid = repodata_schema2id(data, schema, 1);
2340 data_addid(xd, schemaid);
2341 kp = data->xattrs[-*ida];
2344 repodata_serialize_key(data, newincore, newvincore,
2345 schema, data->keys + *kp, kp[1]);
2351 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2354 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2356 /* put offset/len in incore */
2357 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2358 oldvincorelen = xd->len - oldvincorelen;
2359 data_addid(newincore, oldvincorelen);
2364 repodata_internalize(Repodata *data)
2366 Repokey *key, solvkey;
2368 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2369 unsigned char *dp, *ndp;
2370 int newschema, oldcount;
2371 struct extdata newincore;
2372 struct extdata newvincore;
2375 if (!data->attrs && !data->xattrs)
2378 newvincore.buf = data->vincore;
2379 newvincore.len = data->vincorelen;
2381 /* find the solvables key, create if needed */
2382 memset(&solvkey, 0, sizeof(solvkey));
2383 solvkey.name = REPOSITORY_SOLVABLES;
2384 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2386 solvkey.storage = KEY_STORAGE_INCORE;
2387 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2389 schema = sat_malloc2(data->nkeys, sizeof(Id));
2390 seen = sat_malloc2(data->nkeys, sizeof(Id));
2392 /* Merge the data already existing (in data->schemata, ->incoredata and
2393 friends) with the new attributes in data->attrs[]. */
2394 nentry = data->end - data->start;
2395 memset(&newincore, 0, sizeof(newincore));
2396 data_addid(&newincore, 0); /* start data at offset 1 */
2398 data->mainschema = 0;
2399 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2401 /* join entry data */
2402 /* we start with the meta data, entry -1 */
2403 for (entry = -1; entry < nentry; entry++)
2405 memset(seen, 0, data->nkeys * sizeof(Id));
2407 dp = data->incoredata;
2410 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2411 dp = data_read_id(dp, &oldschema);
2414 fprintf(stderr, "oldschema %d\n", oldschema);
2415 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2416 fprintf(stderr, "schemadata %p\n", data->schemadata);
2418 /* seen: -1: old data 0: skipped >0: id + 1 */
2422 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2426 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2434 keyp = data->attrs ? data->attrs[entry] : 0;
2437 /* strip solvables key */
2439 for (sp = keyp = schema; *sp; sp++)
2440 if (*sp != solvkeyid)
2445 seen[solvkeyid] = 0;
2446 keyp = data->xattrs ? data->xattrs[1] : 0;
2449 for (; *keyp; keyp += 2)
2456 seen[*keyp] = keyp[1] + 1;
2458 if (entry < 0 && data->end != data->start)
2465 /* Ideally we'd like to sort the new schema here, to ensure
2466 schema equality independend of the ordering. We can't do that
2467 yet. For once see below (old ids need to come before new ids).
2468 An additional difficulty is that we also need to move
2469 the values with the keys. */
2470 schemaid = repodata_schema2id(data, schema, 1);
2472 schemaid = oldschema;
2475 /* Now create data blob. We walk through the (possibly new) schema
2476 and either copy over old data, or insert the new. */
2477 /* XXX Here we rely on the fact that the (new) schema has the form
2478 o1 o2 o3 o4 ... | n1 n2 n3 ...
2479 (oX being the old keyids (possibly overwritten), and nX being
2480 the new keyids). This rules out sorting the keyids in order
2481 to ensure a small schema count. */
2483 data->incoreoffset[entry] = newincore.len;
2484 data_addid(&newincore, schemaid);
2487 data->mainschema = schemaid;
2488 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2490 keypstart = data->schemadata + data->schemata[schemaid];
2491 for (keyp = keypstart; *keyp; keyp++)
2494 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2495 if (*keyp == solvkeyid)
2497 /* add flexarray entry count */
2498 data_addid(&newincore, data->end - data->start);
2501 key = data->keys + *keyp;
2503 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2508 /* Skip the data associated with this old key. */
2509 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2511 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2512 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2514 else if (key->storage == KEY_STORAGE_INCORE)
2515 ndp = data_skip_key(data, dp, key);
2518 if (seen[*keyp] == -1)
2520 /* If this key was an old one _and_ was not overwritten with
2521 a different value copy over the old value (we skipped it
2524 data_addblob(&newincore, dp, ndp - dp);
2527 else if (seen[*keyp])
2529 /* Otherwise we have a new value. Parse it into the internal
2531 repodata_serialize_key(data, &newincore, &newvincore,
2532 schema, key, seen[*keyp] - 1);
2536 if (entry >= 0 && data->attrs && data->attrs[entry])
2537 data->attrs[entry] = sat_free(data->attrs[entry]);
2539 /* free all xattrs */
2540 for (entry = 0; entry < data->nxattrs; entry++)
2541 if (data->xattrs[entry])
2542 sat_free(data->xattrs[entry]);
2543 data->xattrs = sat_free(data->xattrs);
2546 data->lasthandle = 0;
2548 data->lastdatalen = 0;
2551 repodata_free_schemahash(data);
2553 sat_free(data->incoredata);
2554 data->incoredata = newincore.buf;
2555 data->incoredatalen = newincore.len;
2556 data->incoredatafree = 0;
2558 sat_free(data->vincore);
2559 data->vincore = newvincore.buf;
2560 data->vincorelen = newvincore.len;
2562 data->attrs = sat_free(data->attrs);
2563 data->attrdata = sat_free(data->attrdata);
2564 data->attriddata = sat_free(data->attriddata);
2565 data->attrdatalen = 0;
2566 data->attriddatalen = 0;
2570 repodata_disable_paging(Repodata *data)
2572 if (maybe_load_repodata(data, 0))
2573 repopagestore_disable_paging(&data->store);
2576 static inline Hashval
2577 repodata_join_hash(Solvable *s, Id joinkey)
2579 if (joinkey == SOLVABLE_NAME)
2581 if (joinkey == SOLVABLE_CHECKSUM)
2584 const unsigned char *chk = solvable_lookup_bin_checksum(s, joinkey, &type);
2586 return 1 << 31 | chk[0] << 24 | chk[1] << 16 | chk[2] << 7 | chk[3];
2592 repodata_join_match(Solvable *s1, Solvable *s2, Id joinkey)
2594 if (joinkey == SOLVABLE_NAME)
2595 return s1->name == s2->name && s1->evr == s2->evr && s1->arch == s2->arch ? 1 : 0;
2596 if (joinkey == SOLVABLE_CHECKSUM)
2598 const unsigned char *chk1, *chk2;
2600 chk1 = solvable_lookup_bin_checksum(s1, joinkey, &type1);
2603 chk2 = solvable_lookup_bin_checksum(s2, joinkey, &type2);
2604 if (!chk2 || type1 != type2)
2606 return memcmp(chk1, chk2, sat_chksum_len(type1)) ? 0 : 1;
2612 repodata_join(Repodata *data, Id joinkey)
2614 Repo *repo = data->repo;
2615 Pool *pool = repo->pool;
2616 Hashmask hm = mkmask(repo->nsolvables);
2617 Hashtable ht = sat_calloc(hm + 1, sizeof(*ht));
2619 int i, datastart, dataend;
2622 datastart = data->start;
2623 dataend = data->end;
2624 if (datastart == dataend || repo->start == repo->end)
2626 FOR_REPO_SOLVABLES(repo, i, s)
2628 if (i >= datastart && i < dataend)
2630 h = repodata_join_hash(s, joinkey);
2634 hh = HASHCHAIN_START;
2636 h = HASHCHAIN_NEXT(h, hh, hm);
2639 for (i = datastart; i < dataend; i++)
2641 Solvable *s = pool->solvables + i;
2642 if (s->repo != data->repo)
2644 if (!data->attrs[i - data->start])
2646 h = repodata_join_hash(s, joinkey);
2650 hh = HASHCHAIN_START;
2653 Solvable *s2 = pool->solvables + ht[h];
2654 if (repodata_join_match(s, s2, joinkey))
2656 /* a match! move data over */
2657 repodata_extend(data, ht[h]);
2658 repodata_merge_attrs(data, ht[h], i);
2660 h = HASHCHAIN_NEXT(h, hh, hm);
2664 /* all done! now free solvables */
2665 repo_free_solvable_block(repo, datastart, dataend - datastart, 1);
2669 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: