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)
1545 di->state = di_nextsolvable;
1549 dataiterator_skip_repo(Dataiterator *di)
1551 di->state = di_nextrepo;
1555 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1559 if (solvid == SOLVID_POS)
1561 di->repo = di->pool->pos.repo;
1568 di->data = di->repo->repodata + di->pool->pos.repodataid;
1569 di->repodataid = -1;
1570 di->solvid = solvid;
1571 di->state = di_enterrepo;
1572 di->flags |= SEARCH_THISSOLVID;
1577 di->repo = di->pool->solvables[solvid].repo;
1580 else if (di->repoid >= 0)
1582 if (!di->pool->nrepos)
1587 di->repo = di->pool->repos[0];
1591 di->solvid = solvid;
1593 di->flags |= SEARCH_THISSOLVID;
1594 di->state = di_enterrepo;
1598 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1606 di->flags &= ~SEARCH_THISSOLVID;
1607 di->state = di_enterrepo;
1611 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1613 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1617 return datamatcher_match(ma, di->kv.str);
1620 /************************************************************************
1621 * data modify functions
1624 /* extend repodata so that it includes solvables p */
1626 repodata_extend(Repodata *data, Id p)
1628 if (data->start == data->end)
1629 data->start = data->end = p;
1632 int old = data->end - data->start;
1633 int new = p - data->end + 1;
1636 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1637 memset(data->attrs + old, 0, new * sizeof(Id *));
1639 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1640 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1643 if (p < data->start)
1645 int old = data->end - data->start;
1646 int new = data->start - p;
1649 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1650 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1651 memset(data->attrs, 0, new * sizeof(Id *));
1653 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1654 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1655 memset(data->incoreoffset, 0, new * sizeof(Id));
1661 repodata_shrink(Repodata *data, int end)
1665 if (data->end <= end)
1667 if (data->start >= end)
1671 for (i = 0; i < data->end - data->start; i++)
1672 sat_free(data->attrs[i]);
1673 data->attrs = sat_free(data->attrs);
1675 data->incoreoffset = sat_free(data->incoreoffset);
1676 data->start = data->end = 0;
1681 for (i = end; i < data->end; i++)
1682 sat_free(data->attrs[i - data->start]);
1683 data->attrs = sat_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1685 if (data->incoreoffset)
1686 data->incoreoffset = sat_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1690 /* extend repodata so that it includes solvables from start to start + num - 1 */
1692 repodata_extend_block(Repodata *data, Id start, Id num)
1696 if (!data->incoreoffset)
1698 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1699 data->start = start;
1700 data->end = start + num;
1703 repodata_extend(data, start);
1705 repodata_extend(data, start + num - 1);
1708 /**********************************************************************/
1710 #define REPODATA_ATTRS_BLOCK 63
1711 #define REPODATA_ATTRDATA_BLOCK 1023
1712 #define REPODATA_ATTRIDDATA_BLOCK 63
1716 repodata_new_handle(Repodata *data)
1720 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1723 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1724 data->xattrs[data->nxattrs] = 0;
1725 return -(data->nxattrs++);
1729 repodata_get_attrp(Repodata *data, Id handle)
1731 if (handle == SOLVID_META)
1735 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1740 return data->xattrs - handle;
1741 if (handle < data->start || handle >= data->end)
1742 repodata_extend(data, handle);
1744 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1745 return data->attrs + (handle - data->start);
1749 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1755 app = repodata_get_attrp(data, handle);
1760 for (pp = ap; *pp; pp += 2)
1761 /* Determine equality based on the name only, allows us to change
1762 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1763 if (data->keys[*pp].name == data->keys[keyid].name)
1776 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1786 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1790 keyid = repodata_key2id(data, key, 1);
1791 repodata_insert_keyid(data, solvid, keyid, val, 1);
1795 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1799 key.type = REPOKEY_TYPE_ID;
1801 key.storage = KEY_STORAGE_INCORE;
1802 repodata_set(data, solvid, &key, id);
1806 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1810 key.type = REPOKEY_TYPE_NUM;
1812 key.storage = KEY_STORAGE_INCORE;
1813 repodata_set(data, solvid, &key, (Id)num);
1817 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1821 if (data->localpool)
1822 id = stringpool_str2id(&data->spool, str, 1);
1824 id = str2id(data->repo->pool, str, 1);
1826 key.type = REPOKEY_TYPE_ID;
1828 key.storage = KEY_STORAGE_INCORE;
1829 repodata_set(data, solvid, &key, id);
1833 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1837 key.type = REPOKEY_TYPE_CONSTANT;
1838 key.size = constant;
1839 key.storage = KEY_STORAGE_INCORE;
1840 repodata_set(data, solvid, &key, 0);
1844 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1848 key.type = REPOKEY_TYPE_CONSTANTID;
1850 key.storage = KEY_STORAGE_INCORE;
1851 repodata_set(data, solvid, &key, 0);
1855 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1859 key.type = REPOKEY_TYPE_VOID;
1861 key.storage = KEY_STORAGE_INCORE;
1862 repodata_set(data, solvid, &key, 0);
1866 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1871 l = strlen(str) + 1;
1873 key.type = REPOKEY_TYPE_STR;
1875 key.storage = KEY_STORAGE_INCORE;
1876 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1877 memcpy(data->attrdata + data->attrdatalen, str, l);
1878 repodata_set(data, solvid, &key, data->attrdatalen);
1879 data->attrdatalen += l;
1882 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1883 * so that the caller can append the new element there */
1885 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1888 Id *ida, *pp, **ppp;
1890 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1892 /* great! just append the new data */
1893 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1894 data->attriddatalen--; /* overwrite terminating 0 */
1895 data->lastdatalen += entrysize;
1898 ppp = repodata_get_attrp(data, handle);
1901 for (; *pp; pp += 2)
1902 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1906 /* not found. allocate new key */
1911 key.storage = KEY_STORAGE_INCORE;
1912 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1913 repodata_set(data, handle, &key, data->attriddatalen);
1914 data->lasthandle = 0; /* next time... */
1918 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1919 oldsize += entrysize;
1920 if (ida + 1 == data->attriddata + data->attriddatalen)
1922 /* this was the last entry, just append it */
1923 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1924 data->attriddatalen--; /* overwrite terminating 0 */
1928 /* too bad. move to back. */
1929 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1930 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1931 pp[1] = data->attriddatalen;
1932 data->attriddatalen += oldsize;
1934 data->lasthandle = handle;
1935 data->lastkey = *pp;
1936 data->lastdatalen = data->attriddatalen + entrysize + 1;
1940 checksumtype2len(Id type)
1944 case REPOKEY_TYPE_MD5:
1946 case REPOKEY_TYPE_SHA1:
1948 case REPOKEY_TYPE_SHA256:
1949 return SIZEOF_SHA256;
1956 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1957 const unsigned char *str)
1960 int l = checksumtype2len(type);
1967 key.storage = KEY_STORAGE_INCORE;
1968 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1969 memcpy(data->attrdata + data->attrdatalen, str, l);
1970 repodata_set(data, solvid, &key, data->attrdatalen);
1971 data->attrdatalen += l;
1975 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1978 for (i = 0; i < buflen; i++)
1980 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1981 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
1982 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
1993 buf[i] = (buf[i] << 4) | v;
2000 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2003 unsigned char buf[64];
2004 int l = checksumtype2len(type);
2008 if (hexstr2bytes(buf, str, l) != l)
2010 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2014 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2019 l = checksumtype2len(type);
2022 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2023 for (i = 0; i < l; i++)
2025 unsigned char v = buf[i];
2026 unsigned char w = v >> 4;
2027 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2029 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2035 /* rpm filenames don't contain the epoch, so strip it */
2036 static inline const char *
2037 evrid2vrstr(Pool *pool, Id evrid)
2039 const char *p, *evr = id2str(pool, evrid);
2042 for (p = evr; *p >= '0' && *p <= '9'; p++)
2044 return p != evr && *p == ':' ? p + 1 : evr;
2048 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2050 Pool *pool = data->repo->pool;
2052 const char *str, *fp;
2056 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2059 if ((dir = strrchr(file, '/')) != 0)
2070 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2075 if (l == 1 && dir[0] == '.')
2077 s = pool->solvables + solvid;
2080 str = id2str(pool, s->arch);
2081 if (!strncmp(dir, str, l) && !str[l])
2082 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2084 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
2087 char *dir2 = strdup(dir);
2089 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
2094 str = id2str(pool, s->name);
2096 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2099 str = evrid2vrstr(pool, s->evr);
2101 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2104 str = id2str(pool, s->arch);
2106 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2108 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2113 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2117 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2121 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2123 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2124 data->attriddata[data->attriddatalen++] = dir;
2125 data->attriddata[data->attriddatalen++] = num;
2126 data->attriddata[data->attriddatalen++] = num2;
2127 data->attriddata[data->attriddatalen++] = 0;
2131 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2137 l = strlen(str) + 1;
2138 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2139 memcpy(data->attrdata + data->attrdatalen, str, l);
2140 stroff = data->attrdatalen;
2141 data->attrdatalen += l;
2144 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2146 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2147 data->attriddata[data->attriddatalen++] = dir;
2148 data->attriddata[data->attriddatalen++] = stroff;
2149 data->attriddata[data->attriddatalen++] = 0;
2153 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2156 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2158 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2159 data->attriddata[data->attriddatalen++] = id;
2160 data->attriddata[data->attriddatalen++] = 0;
2164 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2168 if (data->localpool)
2169 id = stringpool_str2id(&data->spool, str, 1);
2171 id = str2id(data->repo->pool, str, 1);
2172 repodata_add_idarray(data, solvid, keyname, id);
2176 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2178 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2179 data->attriddata[data->attriddatalen++] = ghandle;
2180 data->attriddata[data->attriddatalen++] = 0;
2184 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2186 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2187 data->attriddata[data->attriddatalen++] = ghandle;
2188 data->attriddata[data->attriddatalen++] = 0;
2191 /* add all attrs from src to dest */
2193 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2196 if (dest == src || !(keyp = data->attrs[src - data->start]))
2198 for (; *keyp; keyp += 2)
2199 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2205 /**********************************************************************/
2207 /* unify with repo_write! */
2209 #define EXTDATA_BLOCK 1023
2217 data_addid(struct extdata *xd, Id x)
2220 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2221 dp = xd->buf + xd->len;
2226 *dp++ = (x >> 28) | 128;
2228 *dp++ = (x >> 21) | 128;
2229 *dp++ = (x >> 14) | 128;
2232 *dp++ = (x >> 7) | 128;
2234 xd->len = dp - xd->buf;
2238 data_addideof(struct extdata *xd, Id x, int eof)
2241 x = (x & 63) | ((x & ~63) << 1);
2242 data_addid(xd, (eof ? x: x | 64));
2246 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2248 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2249 memcpy(xd->buf + xd->len, blob, len);
2253 /*********************************/
2256 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2257 struct extdata *newvincore,
2259 Repokey *key, Id val)
2261 /* Otherwise we have a new value. Parse it into the internal
2265 unsigned int oldvincorelen = 0;
2269 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2272 oldvincorelen = xd->len;
2276 case REPOKEY_TYPE_VOID:
2277 case REPOKEY_TYPE_CONSTANT:
2278 case REPOKEY_TYPE_CONSTANTID:
2280 case REPOKEY_TYPE_STR:
2281 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2283 case REPOKEY_TYPE_MD5:
2284 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2286 case REPOKEY_TYPE_SHA1:
2287 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2289 case REPOKEY_TYPE_SHA256:
2290 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2292 case REPOKEY_TYPE_ID:
2293 case REPOKEY_TYPE_NUM:
2294 case REPOKEY_TYPE_DIR:
2295 data_addid(xd, val);
2297 case REPOKEY_TYPE_IDARRAY:
2298 for (ida = data->attriddata + val; *ida; ida++)
2299 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2301 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2302 for (ida = data->attriddata + val; *ida; ida += 3)
2304 data_addid(xd, ida[0]);
2305 data_addid(xd, ida[1]);
2306 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2309 case REPOKEY_TYPE_DIRSTRARRAY:
2310 for (ida = data->attriddata + val; *ida; ida += 2)
2312 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2313 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2316 case REPOKEY_TYPE_FIXARRAY:
2320 for (ida = data->attriddata + val; *ida; ida++)
2323 fprintf(stderr, "serialize struct %d\n", *ida);
2326 Id *kp = data->xattrs[-*ida];
2333 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2339 schemaid = repodata_schema2id(data, schema, 1);
2340 else if (schemaid != repodata_schema2id(data, schema, 0))
2342 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2346 fprintf(stderr, " schema %d\n", schemaid);
2351 data_addid(xd, num);
2352 data_addid(xd, schemaid);
2353 for (ida = data->attriddata + val; *ida; ida++)
2355 Id *kp = data->xattrs[-*ida];
2360 repodata_serialize_key(data, newincore, newvincore,
2361 schema, data->keys + *kp, kp[1]);
2366 case REPOKEY_TYPE_FLEXARRAY:
2369 for (ida = data->attriddata + val; *ida; ida++)
2371 data_addid(xd, num);
2372 for (ida = data->attriddata + val; *ida; ida++)
2374 Id *kp = data->xattrs[-*ida];
2377 data_addid(xd, 0); /* XXX */
2384 schemaid = repodata_schema2id(data, schema, 1);
2385 data_addid(xd, schemaid);
2386 kp = data->xattrs[-*ida];
2389 repodata_serialize_key(data, newincore, newvincore,
2390 schema, data->keys + *kp, kp[1]);
2396 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2399 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2401 /* put offset/len in incore */
2402 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2403 oldvincorelen = xd->len - oldvincorelen;
2404 data_addid(newincore, oldvincorelen);
2409 repodata_internalize(Repodata *data)
2411 Repokey *key, solvkey;
2413 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2414 unsigned char *dp, *ndp;
2415 int newschema, oldcount;
2416 struct extdata newincore;
2417 struct extdata newvincore;
2420 if (!data->attrs && !data->xattrs)
2423 newvincore.buf = data->vincore;
2424 newvincore.len = data->vincorelen;
2426 /* find the solvables key, create if needed */
2427 memset(&solvkey, 0, sizeof(solvkey));
2428 solvkey.name = REPOSITORY_SOLVABLES;
2429 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2431 solvkey.storage = KEY_STORAGE_INCORE;
2432 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2434 schema = sat_malloc2(data->nkeys, sizeof(Id));
2435 seen = sat_malloc2(data->nkeys, sizeof(Id));
2437 /* Merge the data already existing (in data->schemata, ->incoredata and
2438 friends) with the new attributes in data->attrs[]. */
2439 nentry = data->end - data->start;
2440 memset(&newincore, 0, sizeof(newincore));
2441 data_addid(&newincore, 0); /* start data at offset 1 */
2443 data->mainschema = 0;
2444 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2446 /* join entry data */
2447 /* we start with the meta data, entry -1 */
2448 for (entry = -1; entry < nentry; entry++)
2450 memset(seen, 0, data->nkeys * sizeof(Id));
2452 dp = data->incoredata;
2455 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2456 dp = data_read_id(dp, &oldschema);
2459 fprintf(stderr, "oldschema %d\n", oldschema);
2460 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2461 fprintf(stderr, "schemadata %p\n", data->schemadata);
2463 /* seen: -1: old data 0: skipped >0: id + 1 */
2467 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2471 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2479 keyp = data->attrs ? data->attrs[entry] : 0;
2482 /* strip solvables key */
2484 for (sp = keyp = schema; *sp; sp++)
2485 if (*sp != solvkeyid)
2490 seen[solvkeyid] = 0;
2491 keyp = data->xattrs ? data->xattrs[1] : 0;
2494 for (; *keyp; keyp += 2)
2501 seen[*keyp] = keyp[1] + 1;
2503 if (entry < 0 && data->end != data->start)
2510 /* Ideally we'd like to sort the new schema here, to ensure
2511 schema equality independend of the ordering. We can't do that
2512 yet. For once see below (old ids need to come before new ids).
2513 An additional difficulty is that we also need to move
2514 the values with the keys. */
2515 schemaid = repodata_schema2id(data, schema, 1);
2517 schemaid = oldschema;
2520 /* Now create data blob. We walk through the (possibly new) schema
2521 and either copy over old data, or insert the new. */
2522 /* XXX Here we rely on the fact that the (new) schema has the form
2523 o1 o2 o3 o4 ... | n1 n2 n3 ...
2524 (oX being the old keyids (possibly overwritten), and nX being
2525 the new keyids). This rules out sorting the keyids in order
2526 to ensure a small schema count. */
2528 data->incoreoffset[entry] = newincore.len;
2529 data_addid(&newincore, schemaid);
2532 data->mainschema = schemaid;
2533 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2535 keypstart = data->schemadata + data->schemata[schemaid];
2536 for (keyp = keypstart; *keyp; keyp++)
2539 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2540 if (*keyp == solvkeyid)
2542 /* add flexarray entry count */
2543 data_addid(&newincore, data->end - data->start);
2546 key = data->keys + *keyp;
2548 fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2553 /* Skip the data associated with this old key. */
2554 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2556 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2557 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2559 else if (key->storage == KEY_STORAGE_INCORE)
2560 ndp = data_skip_key(data, dp, key);
2563 if (seen[*keyp] == -1)
2565 /* If this key was an old one _and_ was not overwritten with
2566 a different value copy over the old value (we skipped it
2569 data_addblob(&newincore, dp, ndp - dp);
2572 else if (seen[*keyp])
2574 /* Otherwise we have a new value. Parse it into the internal
2576 repodata_serialize_key(data, &newincore, &newvincore,
2577 schema, key, seen[*keyp] - 1);
2581 if (entry >= 0 && data->attrs && data->attrs[entry])
2582 data->attrs[entry] = sat_free(data->attrs[entry]);
2584 /* free all xattrs */
2585 for (entry = 0; entry < data->nxattrs; entry++)
2586 if (data->xattrs[entry])
2587 sat_free(data->xattrs[entry]);
2588 data->xattrs = sat_free(data->xattrs);
2591 data->lasthandle = 0;
2593 data->lastdatalen = 0;
2596 repodata_free_schemahash(data);
2598 sat_free(data->incoredata);
2599 data->incoredata = newincore.buf;
2600 data->incoredatalen = newincore.len;
2601 data->incoredatafree = 0;
2603 sat_free(data->vincore);
2604 data->vincore = newvincore.buf;
2605 data->vincorelen = newvincore.len;
2607 data->attrs = sat_free(data->attrs);
2608 data->attrdata = sat_free(data->attrdata);
2609 data->attriddata = sat_free(data->attriddata);
2610 data->attrdatalen = 0;
2611 data->attriddatalen = 0;
2615 repodata_disable_paging(Repodata *data)
2617 if (maybe_load_repodata(data, 0))
2618 repopagestore_disable_paging(&data->store);
2622 repodata_load_stub(Repodata *data)
2624 Repo *repo = data->repo;
2625 Pool *pool = repo->pool;
2628 if (!pool->loadcallback)
2630 data->state = REPODATA_ERROR;
2633 data->state = REPODATA_LOADING;
2634 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
2636 data->state = REPODATA_ERROR;
2640 repodata_create_stubs(Repodata *data)
2642 Repo *repo = data->repo;
2643 Pool *pool = repo->pool;
2650 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2651 while (dataiterator_step(&di))
2653 dataiterator_free(&di);
2656 stubdataids = sat_calloc(cnt, sizeof(*stubdataids));
2657 for (i = 0; i < cnt; i++)
2659 sdata = repo_add_repodata(repo, 0);
2660 if (data->end > data->start)
2662 repodata_extend(sdata, data->start);
2663 repodata_extend(sdata, data->end - 1);
2665 stubdataids[i] = sdata - repo->repodata;
2666 sdata->state = REPODATA_STUB;
2667 sdata->loadcallback = repodata_load_stub;
2670 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2672 while (dataiterator_step(&di))
2674 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
2676 dataiterator_entersub(&di);
2677 sdata = repo->repodata + stubdataids[i++];
2681 switch (di.key->type)
2683 case REPOKEY_TYPE_ID:
2684 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
2686 case REPOKEY_TYPE_CONSTANTID:
2687 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
2689 case REPOKEY_TYPE_STR:
2690 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
2692 case REPOKEY_TYPE_VOID:
2693 repodata_set_void(sdata, SOLVID_META, di.key->name);
2695 case REPOKEY_TYPE_NUM:
2696 repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
2698 case REPOKEY_TYPE_MD5:
2699 case REPOKEY_TYPE_SHA1:
2700 case REPOKEY_TYPE_SHA256:
2701 repodata_set_checksum(sdata, SOLVID_META, di.key->name, di.key->type, di.kv.str);
2703 case REPOKEY_TYPE_IDARRAY:
2704 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
2705 if (di.key->name == REPOSITORY_KEYS)
2712 xkeyname = di.kv.id;
2715 xkey.name = xkeyname;
2716 xkey.type = di.kv.id;
2717 xkey.storage = KEY_STORAGE_INCORE;
2719 repodata_key2id(sdata, &xkey, 1);
2724 dataiterator_free(&di);
2725 for (i = 0; i < cnt; i++)
2726 repodata_internalize(repo->repodata + stubdataids[i]);
2727 sat_free(stubdataids);
2731 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: