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:
475 case REPODATA_LOADING:
478 data->state = REPODATA_ERROR;
483 static inline unsigned char *
484 solvid2data(Repodata *data, Id solvid, Id *schemap)
486 unsigned char *dp = data->incoredata;
489 if (solvid == SOLVID_META) /* META */
491 else if (solvid == SOLVID_POS) /* META */
493 Pool *pool = data->repo->pool;
494 if (data->repo != pool->pos.repo)
496 if (data != data->repo->repodata + pool->pos.repodataid)
498 *schemap = pool->pos.schema;
499 return data->incoredata + pool->pos.dp;
503 if (solvid < data->start || solvid >= data->end)
505 dp += data->incoreoffset[solvid - data->start];
507 return data_read_id(dp, schemap);
510 /************************************************************************
514 static inline unsigned char *
515 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
518 Id schema, *keyp, *kp;
521 if (!maybe_load_repodata(data, keyname))
523 dp = solvid2data(data, solvid, &schema);
526 keyp = data->schemadata + data->schemata[schema];
527 for (kp = keyp; *kp; kp++)
528 if (data->keys[*kp].name == keyname)
532 *keypp = key = data->keys + *kp;
533 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
534 return dp; /* no need to forward... */
535 dp = forward_to_key(data, *kp, keyp, dp);
538 return get_data(data, key, &dp, 0);
543 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
549 dp = find_key_data(data, solvid, keyname, &key);
552 if (key->type == REPOKEY_TYPE_CONSTANTID)
554 if (key->type != REPOKEY_TYPE_ID)
556 dp = data_read_id(dp, &id);
561 repodata_globalize_id(Repodata *data, Id id, int create)
563 if (!id || !data || !data->localpool)
565 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
569 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
575 dp = find_key_data(data, solvid, keyname, &key);
578 if (key->type == REPOKEY_TYPE_STR)
579 return (const char *)dp;
580 if (key->type == REPOKEY_TYPE_CONSTANTID)
581 return id2str(data->repo->pool, key->size);
582 if (key->type == REPOKEY_TYPE_ID)
583 dp = data_read_id(dp, &id);
587 return data->spool.stringspace + data->spool.strings[id];
588 return id2str(data->repo->pool, id);
592 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
599 dp = find_key_data(data, solvid, keyname, &key);
602 if (key->type == REPOKEY_TYPE_NUM
603 || key->type == REPOKEY_TYPE_U32
604 || key->type == REPOKEY_TYPE_CONSTANT)
606 dp = data_fetch(dp, &kv, key);
614 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
620 if (!maybe_load_repodata(data, keyname))
622 dp = solvid2data(data, solvid, &schema);
625 /* can't use find_key_data as we need to test the type */
626 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
627 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
632 const unsigned char *
633 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
638 dp = find_key_data(data, solvid, keyname, &key);
646 /************************************************************************
652 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
656 case REPOKEY_TYPE_ID:
657 case REPOKEY_TYPE_CONSTANTID:
658 case REPOKEY_TYPE_IDARRAY:
659 if (data && data->localpool)
660 kv->str = stringpool_id2str(&data->spool, kv->id);
662 kv->str = id2str(pool, kv->id);
663 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
666 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
668 if (*s == ':' && s > kv->str)
672 case REPOKEY_TYPE_STR:
674 case REPOKEY_TYPE_DIRSTRARRAY:
675 if (!(flags & SEARCH_FILES))
676 return 1; /* match just the basename */
677 /* Put the full filename into kv->str. */
678 kv->str = repodata_dir2str(data, kv->id, kv->str);
679 /* And to compensate for that put the "empty" directory into
680 kv->id, so that later calls to repodata_dir2str on this data
681 come up with the same filename again. */
684 case REPOKEY_TYPE_MD5:
685 case REPOKEY_TYPE_SHA1:
686 case REPOKEY_TYPE_SHA256:
687 if (!(flags & SEARCH_CHECKSUMS))
688 return 0; /* skip em */
689 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
697 struct subschema_data {
703 /* search a specific repodata */
705 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
709 Id keyid, *kp, *keyp;
710 unsigned char *dp, *ddp;
716 if (!maybe_load_repodata(data, keyname))
718 if (solvid == SOLVID_SUBSCHEMA)
720 struct subschema_data *subd = cbdata;
721 cbdata = subd->cbdata;
723 schema = subd->parent->id;
724 dp = (unsigned char *)subd->parent->str;
725 kv.parent = subd->parent;
730 dp = solvid2data(data, solvid, &schema);
733 s = data->repo->pool->solvables + solvid;
736 keyp = data->schemadata + data->schemata[schema];
739 /* search for a specific key */
740 for (kp = keyp; *kp; kp++)
741 if (data->keys[*kp].name == keyname)
745 dp = forward_to_key(data, *kp, keyp, dp);
751 while ((keyid = *keyp++) != 0)
754 key = data->keys + keyid;
755 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
757 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
759 struct subschema_data subd;
763 subd.cbdata = cbdata;
766 ddp = data_read_id(ddp, &nentries);
770 while (ddp && nentries > 0)
774 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
775 ddp = data_read_id(ddp, &schema);
777 kv.str = (char *)ddp;
778 stop = callback(cbdata, s, data, key, &kv);
779 if (stop > SEARCH_NEXT_KEY)
781 if (stop && stop != SEARCH_ENTERSUB)
783 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
784 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
785 ddp = data_skip_schema(data, ddp, schema);
788 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
792 kv.str = (char *)ddp;
793 stop = callback(cbdata, s, data, key, &kv);
794 if (stop > SEARCH_NEXT_KEY)
804 ddp = data_fetch(ddp, &kv, key);
807 stop = callback(cbdata, s, data, key, &kv);
810 while (!kv.eof && !stop);
811 if (onekey || stop > SEARCH_NEXT_KEY)
817 repodata_setpos_kv(Repodata *data, KeyValue *kv)
819 Pool *pool = data->repo->pool;
821 pool_clear_pos(pool);
824 pool->pos.repo = data->repo;
825 pool->pos.repodataid = data - data->repo->repodata;
826 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
827 pool->pos.schema = kv->id;
831 /************************************************************************
832 * data iterator functions
835 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
836 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
837 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
838 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
839 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
840 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
841 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
842 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
843 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
844 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
845 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
846 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
847 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
848 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
852 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
866 case SOLVABLE_VENDOR:
869 case SOLVABLE_PROVIDES:
871 return s->provides ? s->repo->idarraydata + s->provides : 0;
872 case SOLVABLE_OBSOLETES:
874 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
875 case SOLVABLE_CONFLICTS:
877 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
878 case SOLVABLE_REQUIRES:
880 return s->requires ? s->repo->idarraydata + s->requires : 0;
881 case SOLVABLE_RECOMMENDS:
883 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
884 case SOLVABLE_SUPPLEMENTS:
886 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
887 case SOLVABLE_SUGGESTS:
889 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
890 case SOLVABLE_ENHANCES:
892 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
895 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
902 datamatcher_init(Datamatcher *ma, const char *match, int flags)
908 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
910 ma->matchdata = sat_calloc(1, sizeof(regex_t));
911 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
914 sat_free(ma->matchdata);
915 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
922 datamatcher_free(Datamatcher *ma)
924 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
926 regfree(ma->matchdata);
927 ma->matchdata = sat_free(ma->matchdata);
932 datamatcher_match(Datamatcher *ma, const char *str)
934 switch ((ma->flags & SEARCH_STRINGMASK))
936 case SEARCH_SUBSTRING:
937 if (ma->flags & SEARCH_NOCASE)
939 if (!strcasestr(str, ma->match))
944 if (!strstr(str, ma->match))
949 if (ma->flags & SEARCH_NOCASE)
951 if (strcasecmp(ma->match, str))
956 if (strcmp(ma->match, str))
961 if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
965 if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
1000 /* see repo.h for documentation */
1002 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1004 memset(di, 0, sizeof(*di));
1006 di->flags = flags & ~SEARCH_THISSOLVID;
1007 if (!pool || (repo && repo->pool != pool))
1015 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1021 di->keyname = keyname;
1022 di->keynames[0] = keyname;
1023 dataiterator_set_search(di, repo, p);
1028 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1031 memset(&di->matcher, 0, sizeof(di->matcher));
1032 if (from->matcher.match)
1033 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1038 for (i = 1; i < di->nparents; i++)
1039 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1040 di->kv.parent = &di->parents[di->nparents - 1].kv;
1045 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1047 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1048 datamatcher_free(&di->matcher);
1049 memset(&di->matcher, 0, sizeof(di->matcher));
1053 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1063 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1067 di->flags &= ~SEARCH_THISSOLVID;
1071 if (!di->pool->nrepos)
1079 di->repo = di->pool->repos[0];
1081 di->state = di_enterrepo;
1083 dataiterator_jump_to_solvid(di, p);
1087 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1090 di->keyname = keyname;
1091 di->keynames[0] = keyname;
1095 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1099 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1101 di->state = di_bye; /* sorry */
1104 for (i = di->nkeynames + 1; i > 0; i--)
1105 di->keynames[i] = di->keynames[i - 1];
1106 di->keynames[0] = di->keyname = keyname;
1111 dataiterator_free(Dataiterator *di)
1113 if (di->matcher.match)
1114 datamatcher_free(&di->matcher);
1117 static inline unsigned char *
1118 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1120 Id *keyp = di->keyp;
1121 Repokey *keys = di->data->keys;
1124 for (keyp = di->keyp; *keyp; keyp++)
1125 if (keys[*keyp].name == keyname)
1129 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1137 repodata_filelistfilter_matches(Repodata *data, const char *str)
1139 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1140 /* for now hardcoded */
1141 if (strstr(str, "bin/"))
1143 if (!strncmp(str, "/etc/", 5))
1145 if (!strcmp(str, "/usr/bin/sendmail"))
1151 dataiterator_filelistcheck(Dataiterator *di)
1154 Repodata *data = di->data;
1155 if (data->state != REPODATA_AVAILABLE)
1157 if (!repodata_precheck_keyname(data, REPOSITORY_EXTERNAL))
1159 for (i = 0; i < data->nkeys; i++)
1160 if (data->keys[i].name == REPOSITORY_EXTERNAL)
1162 if (i == data->nkeys)
1164 if (!(di->matcher.flags & SEARCH_COMPLETE_FILELIST))
1166 di->repodataid = -1; /* do not look somewhere else */
1169 if (di->matcher.match && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) == SEARCH_STRING && repodata_filelistfilter_matches(di->data, di->matcher.match))
1171 di->repodataid = -1; /* do not look somewhere else */
1178 dataiterator_step(Dataiterator *di)
1186 case di_enterrepo: di_enterrepo:
1189 if (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS))
1191 if (!(di->flags & SEARCH_THISSOLVID))
1193 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1194 goto di_nextsolvable;
1198 case di_entersolvable: di_entersolvable:
1199 if (di->repodataid >= 0)
1201 di->repodataid = 0; /* reset repodata iterator */
1202 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)
1204 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1206 goto di_entersolvablekey;
1211 case di_enterrepodata: di_enterrepodata:
1212 if (di->repodataid >= 0)
1214 if (di->repodataid >= di->repo->nrepodata)
1215 goto di_nextsolvable;
1216 di->data = di->repo->repodata + di->repodataid;
1218 if (di->repodataid >= 0 && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1219 goto di_nextrepodata;
1220 if (!maybe_load_repodata(di->data, di->keyname))
1221 goto di_nextrepodata;
1222 di->dp = solvid2data(di->data, di->solvid, &schema);
1224 goto di_nextrepodata;
1225 if (di->solvid == SOLVID_POS)
1226 di->solvid = di->pool->pos.solvid;
1227 /* reset key iterator */
1228 di->keyp = di->data->schemadata + di->data->schemata[schema];
1231 case di_enterschema: di_enterschema:
1233 di->dp = dataiterator_find_keyname(di, di->keyname);
1234 if (!di->dp || !*di->keyp)
1238 goto di_nextrepodata;
1242 case di_enterkey: di_enterkey:
1244 di->key = di->data->keys + *di->keyp;
1245 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1248 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1250 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1256 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1258 di->state = di_nextkey;
1260 di->state = di_nextattr;
1263 case di_nextkey: di_nextkey:
1264 if (!di->keyname && *++di->keyp)
1270 case di_nextrepodata: di_nextrepodata:
1271 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1272 goto di_enterrepodata;
1275 case di_nextsolvable: di_nextsolvable:
1276 if (!(di->flags & SEARCH_THISSOLVID))
1279 di->solvid = di->repo->start;
1282 for (; di->solvid < di->repo->end; di->solvid++)
1284 if (di->pool->solvables[di->solvid].repo == di->repo)
1285 goto di_entersolvable;
1290 case di_nextrepo: di_nextrepo:
1291 if (di->repoid >= 0)
1295 if (di->repoid < di->pool->nrepos)
1297 di->repo = di->pool->repos[di->repoid];
1303 case di_bye: di_bye:
1307 case di_enterarray: di_enterarray:
1308 if (di->key->name == REPOSITORY_SOLVABLES)
1310 di->ddp = data_read_id(di->ddp, &di->kv.num);
1315 case di_nextarrayelement: di_nextarrayelement:
1318 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1319 if (di->kv.entry == di->kv.num)
1321 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1323 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1325 di->kv.str = (char *)di->ddp;
1327 di->state = di_nextkey;
1330 if (di->kv.entry == di->kv.num - 1)
1332 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1333 di->ddp = data_read_id(di->ddp, &di->kv.id);
1334 di->kv.str = (char *)di->ddp;
1335 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1337 if ((di->flags & SEARCH_SUB) != 0)
1338 di->state = di_entersub;
1340 di->state = di_nextarrayelement;
1343 case di_entersub: di_entersub:
1344 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1345 goto di_nextarrayelement; /* sorry, full */
1346 di->parents[di->nparents].kv = di->kv;
1347 di->parents[di->nparents].dp = di->dp;
1348 di->parents[di->nparents].keyp = di->keyp;
1349 di->dp = (unsigned char *)di->kv.str;
1350 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1351 memset(&di->kv, 0, sizeof(di->kv));
1352 di->kv.parent = &di->parents[di->nparents].kv;
1354 di->keyname = di->keynames[di->nparents - di->rootlevel];
1355 goto di_enterschema;
1357 case di_leavesub: di_leavesub:
1358 if (di->nparents - 1 < di->rootlevel)
1361 di->dp = di->parents[di->nparents].dp;
1362 di->kv = di->parents[di->nparents].kv;
1363 di->keyp = di->parents[di->nparents].keyp;
1364 di->key = di->data->keys + *di->keyp;
1365 di->ddp = (unsigned char *)di->kv.str;
1366 di->keyname = di->keynames[di->nparents - di->rootlevel];
1367 goto di_nextarrayelement;
1369 /* special solvable attr handling follows */
1371 case di_nextsolvableattr:
1372 di->kv.id = *di->idp++;
1377 di->state = di_nextsolvablekey;
1381 case di_nextsolvablekey: di_nextsolvablekey:
1382 if (di->keyname || di->key->name == RPM_RPMDBID)
1383 goto di_enterrepodata;
1387 case di_entersolvablekey: di_entersolvablekey:
1388 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1389 if (!di->idp || !di->idp[0])
1390 goto di_nextsolvablekey;
1391 di->kv.id = di->idp[0];
1392 di->kv.num = di->idp[0];
1394 if (!di->kv.eof && !di->idp[0])
1398 di->state = di_nextsolvablekey;
1400 di->state = di_nextsolvableattr;
1404 if (di->matcher.match)
1406 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1408 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1412 if (!datamatcher_match(&di->matcher, di->kv.str))
1415 /* found something! */
1421 dataiterator_entersub(Dataiterator *di)
1423 if (di->state == di_nextarrayelement)
1424 di->state = di_entersub;
1428 dataiterator_setpos(Dataiterator *di)
1430 if (di->kv.eof == 2)
1432 pool_clear_pos(di->pool);
1435 di->pool->pos.solvid = di->solvid;
1436 di->pool->pos.repo = di->repo;
1437 di->pool->pos.repodataid = di->data - di->repo->repodata;
1438 di->pool->pos.schema = di->kv.id;
1439 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1443 dataiterator_setpos_parent(Dataiterator *di)
1445 if (!di->kv.parent || di->kv.parent->eof == 2)
1447 pool_clear_pos(di->pool);
1450 di->pool->pos.solvid = di->solvid;
1451 di->pool->pos.repo = di->repo;
1452 di->pool->pos.repodataid = di->data - di->repo->repodata;
1453 di->pool->pos.schema = di->kv.parent->id;
1454 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1457 /* clones just the position, not the search keys/matcher */
1459 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1461 di->state = from->state;
1462 di->flags &= ~SEARCH_THISSOLVID;
1463 di->flags |= (from->flags & SEARCH_THISSOLVID);
1464 di->repo = from->repo;
1465 di->data = from->data;
1467 di->ddp = from->ddp;
1468 di->idp = from->idp;
1469 di->keyp = from->keyp;
1470 di->key = from->key;
1472 di->repodataid = from->repodataid;
1473 di->solvid = from->solvid;
1474 di->repoid = from->repoid;
1475 di->rootlevel = from->rootlevel;
1476 memcpy(di->parents, from->parents, sizeof(from->parents));
1477 di->nparents = from->nparents;
1481 for (i = 1; i < di->nparents; i++)
1482 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1483 di->kv.parent = &di->parents[di->nparents - 1].kv;
1488 dataiterator_seek(Dataiterator *di, int whence)
1490 if ((whence & DI_SEEK_STAY) != 0)
1491 di->rootlevel = di->nparents;
1492 switch (whence & ~DI_SEEK_STAY)
1495 if (di->state != di_nextarrayelement)
1497 if ((whence & DI_SEEK_STAY) != 0)
1498 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1499 di->state = di_entersub;
1501 case DI_SEEK_PARENT:
1508 if (di->rootlevel > di->nparents)
1509 di->rootlevel = di->nparents;
1510 di->dp = di->parents[di->nparents].dp;
1511 di->kv = di->parents[di->nparents].kv;
1512 di->keyp = di->parents[di->nparents].keyp;
1513 di->key = di->data->keys + *di->keyp;
1514 di->ddp = (unsigned char *)di->kv.str;
1515 di->keyname = di->keynames[di->nparents - di->rootlevel];
1516 di->state = di_nextarrayelement;
1518 case DI_SEEK_REWIND:
1524 di->dp = (unsigned char *)di->kv.parent->str;
1525 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1526 di->state = di_enterschema;
1534 dataiterator_skip_attribute(Dataiterator *di)
1536 if (di->state == di_nextsolvableattr)
1537 di->state = di_nextsolvablekey;
1539 di->state = di_nextkey;
1543 dataiterator_skip_solvable(Dataiterator *di)
1547 di->keyname = di->keynames[0];
1548 di->state = di_nextsolvable;
1552 dataiterator_skip_repo(Dataiterator *di)
1556 di->keyname = di->keynames[0];
1557 di->state = di_nextrepo;
1561 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1565 di->keyname = di->keynames[0];
1566 if (solvid == SOLVID_POS)
1568 di->repo = di->pool->pos.repo;
1575 di->data = di->repo->repodata + di->pool->pos.repodataid;
1576 di->repodataid = -1;
1577 di->solvid = solvid;
1578 di->state = di_enterrepo;
1579 di->flags |= SEARCH_THISSOLVID;
1584 di->repo = di->pool->solvables[solvid].repo;
1587 else if (di->repoid >= 0)
1589 if (!di->pool->nrepos)
1594 di->repo = di->pool->repos[0];
1598 di->solvid = solvid;
1600 di->flags |= SEARCH_THISSOLVID;
1601 di->state = di_enterrepo;
1605 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1613 di->flags &= ~SEARCH_THISSOLVID;
1614 di->state = di_enterrepo;
1618 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1620 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1624 return datamatcher_match(ma, di->kv.str);
1627 /************************************************************************
1628 * data modify functions
1631 /* extend repodata so that it includes solvables p */
1633 repodata_extend(Repodata *data, Id p)
1635 if (data->start == data->end)
1636 data->start = data->end = p;
1639 int old = data->end - data->start;
1640 int new = p - data->end + 1;
1643 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1644 memset(data->attrs + old, 0, new * sizeof(Id *));
1646 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1647 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1650 if (p < data->start)
1652 int old = data->end - data->start;
1653 int new = data->start - p;
1656 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1657 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1658 memset(data->attrs, 0, new * sizeof(Id *));
1660 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1661 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1662 memset(data->incoreoffset, 0, new * sizeof(Id));
1668 repodata_shrink(Repodata *data, int end)
1672 if (data->end <= end)
1674 if (data->start >= end)
1678 for (i = 0; i < data->end - data->start; i++)
1679 sat_free(data->attrs[i]);
1680 data->attrs = sat_free(data->attrs);
1682 data->incoreoffset = sat_free(data->incoreoffset);
1683 data->start = data->end = 0;
1688 for (i = end; i < data->end; i++)
1689 sat_free(data->attrs[i - data->start]);
1690 data->attrs = sat_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1692 if (data->incoreoffset)
1693 data->incoreoffset = sat_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1697 /* extend repodata so that it includes solvables from start to start + num - 1 */
1699 repodata_extend_block(Repodata *data, Id start, Id num)
1703 if (!data->incoreoffset)
1705 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1706 data->start = start;
1707 data->end = start + num;
1710 repodata_extend(data, start);
1712 repodata_extend(data, start + num - 1);
1715 /**********************************************************************/
1717 #define REPODATA_ATTRS_BLOCK 63
1718 #define REPODATA_ATTRDATA_BLOCK 1023
1719 #define REPODATA_ATTRIDDATA_BLOCK 63
1723 repodata_new_handle(Repodata *data)
1727 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1730 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1731 data->xattrs[data->nxattrs] = 0;
1732 return -(data->nxattrs++);
1736 repodata_get_attrp(Repodata *data, Id handle)
1738 if (handle == SOLVID_META)
1742 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1747 return data->xattrs - handle;
1748 if (handle < data->start || handle >= data->end)
1749 repodata_extend(data, handle);
1751 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1752 return data->attrs + (handle - data->start);
1756 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1762 app = repodata_get_attrp(data, handle);
1767 for (pp = ap; *pp; pp += 2)
1768 /* Determine equality based on the name only, allows us to change
1769 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1770 if (data->keys[*pp].name == data->keys[keyid].name)
1783 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1793 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1797 keyid = repodata_key2id(data, key, 1);
1798 repodata_insert_keyid(data, solvid, keyid, val, 1);
1802 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1806 key.type = REPOKEY_TYPE_ID;
1808 key.storage = KEY_STORAGE_INCORE;
1809 repodata_set(data, solvid, &key, id);
1813 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1817 key.type = REPOKEY_TYPE_NUM;
1819 key.storage = KEY_STORAGE_INCORE;
1820 repodata_set(data, solvid, &key, (Id)num);
1824 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1828 if (data->localpool)
1829 id = stringpool_str2id(&data->spool, str, 1);
1831 id = str2id(data->repo->pool, str, 1);
1833 key.type = REPOKEY_TYPE_ID;
1835 key.storage = KEY_STORAGE_INCORE;
1836 repodata_set(data, solvid, &key, id);
1840 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1844 key.type = REPOKEY_TYPE_CONSTANT;
1845 key.size = constant;
1846 key.storage = KEY_STORAGE_INCORE;
1847 repodata_set(data, solvid, &key, 0);
1851 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1855 key.type = REPOKEY_TYPE_CONSTANTID;
1857 key.storage = KEY_STORAGE_INCORE;
1858 repodata_set(data, solvid, &key, 0);
1862 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1866 key.type = REPOKEY_TYPE_VOID;
1868 key.storage = KEY_STORAGE_INCORE;
1869 repodata_set(data, solvid, &key, 0);
1873 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1878 l = strlen(str) + 1;
1880 key.type = REPOKEY_TYPE_STR;
1882 key.storage = KEY_STORAGE_INCORE;
1883 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1884 memcpy(data->attrdata + data->attrdatalen, str, l);
1885 repodata_set(data, solvid, &key, data->attrdatalen);
1886 data->attrdatalen += l;
1889 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1890 * so that the caller can append the new element there */
1892 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1895 Id *ida, *pp, **ppp;
1897 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1899 /* great! just append the new data */
1900 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1901 data->attriddatalen--; /* overwrite terminating 0 */
1902 data->lastdatalen += entrysize;
1905 ppp = repodata_get_attrp(data, handle);
1908 for (; *pp; pp += 2)
1909 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1913 /* not found. allocate new key */
1918 key.storage = KEY_STORAGE_INCORE;
1919 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1920 repodata_set(data, handle, &key, data->attriddatalen);
1921 data->lasthandle = 0; /* next time... */
1925 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1926 oldsize += entrysize;
1927 if (ida + 1 == data->attriddata + data->attriddatalen)
1929 /* this was the last entry, just append it */
1930 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1931 data->attriddatalen--; /* overwrite terminating 0 */
1935 /* too bad. move to back. */
1936 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1937 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1938 pp[1] = data->attriddatalen;
1939 data->attriddatalen += oldsize;
1941 data->lasthandle = handle;
1942 data->lastkey = *pp;
1943 data->lastdatalen = data->attriddatalen + entrysize + 1;
1947 checksumtype2len(Id type)
1951 case REPOKEY_TYPE_MD5:
1953 case REPOKEY_TYPE_SHA1:
1955 case REPOKEY_TYPE_SHA256:
1956 return SIZEOF_SHA256;
1963 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1964 const unsigned char *str)
1967 int l = checksumtype2len(type);
1974 key.storage = KEY_STORAGE_INCORE;
1975 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1976 memcpy(data->attrdata + data->attrdatalen, str, l);
1977 repodata_set(data, solvid, &key, data->attrdatalen);
1978 data->attrdatalen += l;
1982 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1985 for (i = 0; i < buflen; i++)
1987 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1988 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
1989 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
2000 buf[i] = (buf[i] << 4) | v;
2007 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2010 unsigned char buf[64];
2011 int l = checksumtype2len(type);
2015 if (hexstr2bytes(buf, str, l) != l)
2017 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2021 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2026 l = checksumtype2len(type);
2029 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2030 for (i = 0; i < l; i++)
2032 unsigned char v = buf[i];
2033 unsigned char w = v >> 4;
2034 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2036 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2042 /* rpm filenames don't contain the epoch, so strip it */
2043 static inline const char *
2044 evrid2vrstr(Pool *pool, Id evrid)
2046 const char *p, *evr = id2str(pool, evrid);
2049 for (p = evr; *p >= '0' && *p <= '9'; p++)
2051 return p != evr && *p == ':' ? p + 1 : evr;
2055 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2057 Pool *pool = data->repo->pool;
2059 const char *str, *fp;
2063 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2066 if ((dir = strrchr(file, '/')) != 0)
2077 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2082 if (l == 1 && dir[0] == '.')
2084 s = pool->solvables + solvid;
2087 str = id2str(pool, s->arch);
2088 if (!strncmp(dir, str, l) && !str[l])
2089 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2091 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
2094 char *dir2 = strdup(dir);
2096 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
2101 str = id2str(pool, s->name);
2103 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2106 str = evrid2vrstr(pool, s->evr);
2108 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2111 str = id2str(pool, s->arch);
2113 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2115 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2120 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2124 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2128 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2130 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2131 data->attriddata[data->attriddatalen++] = dir;
2132 data->attriddata[data->attriddatalen++] = num;
2133 data->attriddata[data->attriddatalen++] = num2;
2134 data->attriddata[data->attriddatalen++] = 0;
2138 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2144 l = strlen(str) + 1;
2145 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2146 memcpy(data->attrdata + data->attrdatalen, str, l);
2147 stroff = data->attrdatalen;
2148 data->attrdatalen += l;
2151 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2153 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2154 data->attriddata[data->attriddatalen++] = dir;
2155 data->attriddata[data->attriddatalen++] = stroff;
2156 data->attriddata[data->attriddatalen++] = 0;
2160 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2163 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2165 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2166 data->attriddata[data->attriddatalen++] = id;
2167 data->attriddata[data->attriddatalen++] = 0;
2171 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2175 if (data->localpool)
2176 id = stringpool_str2id(&data->spool, str, 1);
2178 id = str2id(data->repo->pool, str, 1);
2179 repodata_add_idarray(data, solvid, keyname, id);
2183 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2185 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2186 data->attriddata[data->attriddatalen++] = ghandle;
2187 data->attriddata[data->attriddatalen++] = 0;
2191 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2193 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2194 data->attriddata[data->attriddatalen++] = ghandle;
2195 data->attriddata[data->attriddatalen++] = 0;
2198 /* add all attrs from src to dest */
2200 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2203 if (dest == src || !(keyp = data->attrs[src - data->start]))
2205 for (; *keyp; keyp += 2)
2206 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2212 /**********************************************************************/
2214 /* unify with repo_write! */
2216 #define EXTDATA_BLOCK 1023
2224 data_addid(struct extdata *xd, Id x)
2227 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2228 dp = xd->buf + xd->len;
2233 *dp++ = (x >> 28) | 128;
2235 *dp++ = (x >> 21) | 128;
2236 *dp++ = (x >> 14) | 128;
2239 *dp++ = (x >> 7) | 128;
2241 xd->len = dp - xd->buf;
2245 data_addideof(struct extdata *xd, Id x, int eof)
2248 x = (x & 63) | ((x & ~63) << 1);
2249 data_addid(xd, (eof ? x: x | 64));
2253 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2255 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2256 memcpy(xd->buf + xd->len, blob, len);
2260 /*********************************/
2263 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2264 struct extdata *newvincore,
2266 Repokey *key, Id val)
2268 /* Otherwise we have a new value. Parse it into the internal
2272 unsigned int oldvincorelen = 0;
2276 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2279 oldvincorelen = xd->len;
2283 case REPOKEY_TYPE_VOID:
2284 case REPOKEY_TYPE_CONSTANT:
2285 case REPOKEY_TYPE_CONSTANTID:
2287 case REPOKEY_TYPE_STR:
2288 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2290 case REPOKEY_TYPE_MD5:
2291 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2293 case REPOKEY_TYPE_SHA1:
2294 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2296 case REPOKEY_TYPE_SHA256:
2297 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2299 case REPOKEY_TYPE_ID:
2300 case REPOKEY_TYPE_NUM:
2301 case REPOKEY_TYPE_DIR:
2302 data_addid(xd, val);
2304 case REPOKEY_TYPE_IDARRAY:
2305 for (ida = data->attriddata + val; *ida; ida++)
2306 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2308 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2309 for (ida = data->attriddata + val; *ida; ida += 3)
2311 data_addid(xd, ida[0]);
2312 data_addid(xd, ida[1]);
2313 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2316 case REPOKEY_TYPE_DIRSTRARRAY:
2317 for (ida = data->attriddata + val; *ida; ida += 2)
2319 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2320 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2323 case REPOKEY_TYPE_FIXARRAY:
2327 for (ida = data->attriddata + val; *ida; ida++)
2330 fprintf(stderr, "serialize struct %d\n", *ida);
2333 Id *kp = data->xattrs[-*ida];
2340 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2346 schemaid = repodata_schema2id(data, schema, 1);
2347 else if (schemaid != repodata_schema2id(data, schema, 0))
2349 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2353 fprintf(stderr, " schema %d\n", schemaid);
2358 data_addid(xd, num);
2359 data_addid(xd, schemaid);
2360 for (ida = data->attriddata + val; *ida; ida++)
2362 Id *kp = data->xattrs[-*ida];
2367 repodata_serialize_key(data, newincore, newvincore,
2368 schema, data->keys + *kp, kp[1]);
2373 case REPOKEY_TYPE_FLEXARRAY:
2376 for (ida = data->attriddata + val; *ida; ida++)
2378 data_addid(xd, num);
2379 for (ida = data->attriddata + val; *ida; ida++)
2381 Id *kp = data->xattrs[-*ida];
2384 data_addid(xd, 0); /* XXX */
2391 schemaid = repodata_schema2id(data, schema, 1);
2392 data_addid(xd, schemaid);
2393 kp = data->xattrs[-*ida];
2396 repodata_serialize_key(data, newincore, newvincore,
2397 schema, data->keys + *kp, kp[1]);
2403 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2406 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2408 /* put offset/len in incore */
2409 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2410 oldvincorelen = xd->len - oldvincorelen;
2411 data_addid(newincore, oldvincorelen);
2416 repodata_internalize(Repodata *data)
2418 Repokey *key, solvkey;
2420 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2421 unsigned char *dp, *ndp;
2422 int newschema, oldcount;
2423 struct extdata newincore;
2424 struct extdata newvincore;
2427 if (!data->attrs && !data->xattrs)
2430 newvincore.buf = data->vincore;
2431 newvincore.len = data->vincorelen;
2433 /* find the solvables key, create if needed */
2434 memset(&solvkey, 0, sizeof(solvkey));
2435 solvkey.name = REPOSITORY_SOLVABLES;
2436 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2438 solvkey.storage = KEY_STORAGE_INCORE;
2439 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2441 schema = sat_malloc2(data->nkeys, sizeof(Id));
2442 seen = sat_malloc2(data->nkeys, sizeof(Id));
2444 /* Merge the data already existing (in data->schemata, ->incoredata and
2445 friends) with the new attributes in data->attrs[]. */
2446 nentry = data->end - data->start;
2447 memset(&newincore, 0, sizeof(newincore));
2448 data_addid(&newincore, 0); /* start data at offset 1 */
2450 data->mainschema = 0;
2451 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2453 /* join entry data */
2454 /* we start with the meta data, entry -1 */
2455 for (entry = -1; entry < nentry; entry++)
2457 memset(seen, 0, data->nkeys * sizeof(Id));
2459 dp = data->incoredata;
2462 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2463 dp = data_read_id(dp, &oldschema);
2466 fprintf(stderr, "oldschema %d\n", oldschema);
2467 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2468 fprintf(stderr, "schemadata %p\n", data->schemadata);
2470 /* seen: -1: old data 0: skipped >0: id + 1 */
2474 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2478 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2486 keyp = data->attrs ? data->attrs[entry] : 0;
2489 /* strip solvables key */
2491 for (sp = keyp = schema; *sp; sp++)
2492 if (*sp != solvkeyid)
2497 seen[solvkeyid] = 0;
2498 keyp = data->xattrs ? data->xattrs[1] : 0;
2501 for (; *keyp; keyp += 2)
2508 seen[*keyp] = keyp[1] + 1;
2510 if (entry < 0 && data->end != data->start)
2517 /* Ideally we'd like to sort the new schema here, to ensure
2518 schema equality independend of the ordering. We can't do that
2519 yet. For once see below (old ids need to come before new ids).
2520 An additional difficulty is that we also need to move
2521 the values with the keys. */
2522 schemaid = repodata_schema2id(data, schema, 1);
2524 schemaid = oldschema;
2527 /* Now create data blob. We walk through the (possibly new) schema
2528 and either copy over old data, or insert the new. */
2529 /* XXX Here we rely on the fact that the (new) schema has the form
2530 o1 o2 o3 o4 ... | n1 n2 n3 ...
2531 (oX being the old keyids (possibly overwritten), and nX being
2532 the new keyids). This rules out sorting the keyids in order
2533 to ensure a small schema count. */
2535 data->incoreoffset[entry] = newincore.len;
2536 data_addid(&newincore, schemaid);
2539 data->mainschema = schemaid;
2540 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2542 keypstart = data->schemadata + data->schemata[schemaid];
2543 for (keyp = keypstart; *keyp; keyp++)
2546 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2547 if (*keyp == solvkeyid)
2549 /* add flexarray entry count */
2550 data_addid(&newincore, data->end - data->start);
2553 key = data->keys + *keyp;
2555 fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2560 /* Skip the data associated with this old key. */
2561 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2563 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2564 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2566 else if (key->storage == KEY_STORAGE_INCORE)
2567 ndp = data_skip_key(data, dp, key);
2570 if (seen[*keyp] == -1)
2572 /* If this key was an old one _and_ was not overwritten with
2573 a different value copy over the old value (we skipped it
2576 data_addblob(&newincore, dp, ndp - dp);
2579 else if (seen[*keyp])
2581 /* Otherwise we have a new value. Parse it into the internal
2583 repodata_serialize_key(data, &newincore, &newvincore,
2584 schema, key, seen[*keyp] - 1);
2588 if (entry >= 0 && data->attrs && data->attrs[entry])
2589 data->attrs[entry] = sat_free(data->attrs[entry]);
2591 /* free all xattrs */
2592 for (entry = 0; entry < data->nxattrs; entry++)
2593 if (data->xattrs[entry])
2594 sat_free(data->xattrs[entry]);
2595 data->xattrs = sat_free(data->xattrs);
2598 data->lasthandle = 0;
2600 data->lastdatalen = 0;
2603 repodata_free_schemahash(data);
2605 sat_free(data->incoredata);
2606 data->incoredata = newincore.buf;
2607 data->incoredatalen = newincore.len;
2608 data->incoredatafree = 0;
2610 sat_free(data->vincore);
2611 data->vincore = newvincore.buf;
2612 data->vincorelen = newvincore.len;
2614 data->attrs = sat_free(data->attrs);
2615 data->attrdata = sat_free(data->attrdata);
2616 data->attriddata = sat_free(data->attriddata);
2617 data->attrdatalen = 0;
2618 data->attriddatalen = 0;
2622 repodata_disable_paging(Repodata *data)
2624 if (maybe_load_repodata(data, 0))
2625 repopagestore_disable_paging(&data->store);
2629 repodata_load_stub(Repodata *data)
2631 Repo *repo = data->repo;
2632 Pool *pool = repo->pool;
2635 if (!pool->loadcallback)
2637 data->state = REPODATA_ERROR;
2640 data->state = REPODATA_LOADING;
2641 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
2643 data->state = REPODATA_ERROR;
2647 repodata_create_stubs(Repodata *data)
2649 Repo *repo = data->repo;
2650 Pool *pool = repo->pool;
2657 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2658 while (dataiterator_step(&di))
2660 dataiterator_free(&di);
2663 stubdataids = sat_calloc(cnt, sizeof(*stubdataids));
2664 for (i = 0; i < cnt; i++)
2666 sdata = repo_add_repodata(repo, 0);
2667 if (data->end > data->start)
2669 repodata_extend(sdata, data->start);
2670 repodata_extend(sdata, data->end - 1);
2672 stubdataids[i] = sdata - repo->repodata;
2673 sdata->state = REPODATA_STUB;
2674 sdata->loadcallback = repodata_load_stub;
2677 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2679 while (dataiterator_step(&di))
2681 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
2683 dataiterator_entersub(&di);
2684 sdata = repo->repodata + stubdataids[i++];
2688 switch (di.key->type)
2690 case REPOKEY_TYPE_ID:
2691 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
2693 case REPOKEY_TYPE_CONSTANTID:
2694 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
2696 case REPOKEY_TYPE_STR:
2697 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
2699 case REPOKEY_TYPE_VOID:
2700 repodata_set_void(sdata, SOLVID_META, di.key->name);
2702 case REPOKEY_TYPE_NUM:
2703 repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
2705 case REPOKEY_TYPE_MD5:
2706 case REPOKEY_TYPE_SHA1:
2707 case REPOKEY_TYPE_SHA256:
2708 repodata_set_checksum(sdata, SOLVID_META, di.key->name, di.key->type, di.kv.str);
2710 case REPOKEY_TYPE_IDARRAY:
2711 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
2712 if (di.key->name == REPOSITORY_KEYS)
2719 xkeyname = di.kv.id;
2722 xkey.name = xkeyname;
2723 xkey.type = di.kv.id;
2724 xkey.storage = KEY_STORAGE_INCORE;
2726 repodata_key2id(sdata, &xkey, 1);
2731 dataiterator_free(&di);
2732 for (i = 0; i < cnt; i++)
2733 repodata_internalize(repo->repodata + stubdataids[i]);
2734 sat_free(stubdataids);
2738 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: