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)
935 switch ((ma->flags & SEARCH_STRINGMASK))
937 case SEARCH_SUBSTRING:
938 if (ma->flags & SEARCH_NOCASE)
940 if (!strcasestr(str, ma->match))
945 if (!strstr(str, ma->match))
950 if (ma->flags & SEARCH_NOCASE)
952 if (strcasecmp(ma->match, str))
957 if (strcmp(ma->match, str))
961 case SEARCH_STRINGSTART:
962 if (ma->flags & SEARCH_NOCASE)
964 if (strncasecmp(ma->match, str, strlen(ma->match)))
969 if (strncmp(ma->match, str, strlen(ma->match)))
973 case SEARCH_STRINGEND:
974 l = strlen(str) - strlen(ma->match);
977 if (ma->flags & SEARCH_NOCASE)
979 if (strcasecmp(ma->match, str + l))
984 if (strcmp(ma->match, str + l))
989 if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
993 if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
1003 repodata_filelistfilter_matches(Repodata *data, const char *str)
1005 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1006 /* for now hardcoded */
1007 if (strstr(str, "bin/"))
1009 if (!strncmp(str, "/etc/", 5))
1011 if (!strcmp(str, "/usr/lib/sendmail"))
1033 di_nextarrayelement,
1038 di_nextsolvableattr,
1043 /* see repo.h for documentation */
1045 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1047 memset(di, 0, sizeof(*di));
1049 di->flags = flags & ~SEARCH_THISSOLVID;
1050 if (!pool || (repo && repo->pool != pool))
1058 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1064 di->keyname = keyname;
1065 di->keynames[0] = keyname;
1066 dataiterator_set_search(di, repo, p);
1071 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1074 memset(&di->matcher, 0, sizeof(di->matcher));
1075 if (from->matcher.match)
1076 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1081 for (i = 1; i < di->nparents; i++)
1082 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1083 di->kv.parent = &di->parents[di->nparents - 1].kv;
1088 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1090 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1091 datamatcher_free(&di->matcher);
1092 memset(&di->matcher, 0, sizeof(di->matcher));
1096 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1106 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1110 di->flags &= ~SEARCH_THISSOLVID;
1114 if (!di->pool->nrepos)
1122 di->repo = di->pool->repos[0];
1124 di->state = di_enterrepo;
1126 dataiterator_jump_to_solvid(di, p);
1130 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1133 di->keyname = keyname;
1134 di->keynames[0] = keyname;
1138 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1142 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1144 di->state = di_bye; /* sorry */
1147 for (i = di->nkeynames + 1; i > 0; i--)
1148 di->keynames[i] = di->keynames[i - 1];
1149 di->keynames[0] = di->keyname = keyname;
1154 dataiterator_free(Dataiterator *di)
1156 if (di->matcher.match)
1157 datamatcher_free(&di->matcher);
1160 static inline unsigned char *
1161 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1163 Id *keyp = di->keyp;
1164 Repokey *keys = di->data->keys;
1167 for (keyp = di->keyp; *keyp; keyp++)
1168 if (keys[*keyp].name == keyname)
1172 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1180 dataiterator_filelistcheck(Dataiterator *di)
1183 Repodata *data = di->data;
1184 if (data->state != REPODATA_AVAILABLE)
1186 if (!repodata_precheck_keyname(data, REPOSITORY_EXTERNAL))
1188 for (i = 0; i < data->nkeys; i++)
1189 if (data->keys[i].name == REPOSITORY_EXTERNAL)
1191 if (i == data->nkeys)
1193 if (!(di->matcher.flags & SEARCH_COMPLETE_FILELIST))
1195 di->repodataid = -1; /* do not look somewhere else */
1198 if (di->matcher.match && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) == SEARCH_STRING && repodata_filelistfilter_matches(di->data, di->matcher.match))
1200 di->repodataid = -1; /* do not look somewhere else */
1207 dataiterator_step(Dataiterator *di)
1215 case di_enterrepo: di_enterrepo:
1218 if (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS))
1220 if (!(di->flags & SEARCH_THISSOLVID))
1222 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1223 goto di_nextsolvable;
1227 case di_entersolvable: di_entersolvable:
1228 if (di->repodataid >= 0)
1230 di->repodataid = 0; /* reset repodata iterator */
1231 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)
1233 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1235 goto di_entersolvablekey;
1240 case di_enterrepodata: di_enterrepodata:
1241 if (di->repodataid >= 0)
1243 if (di->repodataid >= di->repo->nrepodata)
1244 goto di_nextsolvable;
1245 di->data = di->repo->repodata + di->repodataid;
1247 if (di->repodataid >= 0 && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1248 goto di_nextrepodata;
1249 if (!maybe_load_repodata(di->data, di->keyname))
1250 goto di_nextrepodata;
1251 di->dp = solvid2data(di->data, di->solvid, &schema);
1253 goto di_nextrepodata;
1254 if (di->solvid == SOLVID_POS)
1255 di->solvid = di->pool->pos.solvid;
1256 /* reset key iterator */
1257 di->keyp = di->data->schemadata + di->data->schemata[schema];
1260 case di_enterschema: di_enterschema:
1262 di->dp = dataiterator_find_keyname(di, di->keyname);
1263 if (!di->dp || !*di->keyp)
1267 goto di_nextrepodata;
1271 case di_enterkey: di_enterkey:
1273 di->key = di->data->keys + *di->keyp;
1274 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1277 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1279 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1285 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1287 di->state = di_nextkey;
1289 di->state = di_nextattr;
1292 case di_nextkey: di_nextkey:
1293 if (!di->keyname && *++di->keyp)
1299 case di_nextrepodata: di_nextrepodata:
1300 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1301 goto di_enterrepodata;
1304 case di_nextsolvable: di_nextsolvable:
1305 if (!(di->flags & SEARCH_THISSOLVID))
1308 di->solvid = di->repo->start;
1311 for (; di->solvid < di->repo->end; di->solvid++)
1313 if (di->pool->solvables[di->solvid].repo == di->repo)
1314 goto di_entersolvable;
1319 case di_nextrepo: di_nextrepo:
1320 if (di->repoid >= 0)
1324 if (di->repoid < di->pool->nrepos)
1326 di->repo = di->pool->repos[di->repoid];
1332 case di_bye: di_bye:
1336 case di_enterarray: di_enterarray:
1337 if (di->key->name == REPOSITORY_SOLVABLES)
1339 di->ddp = data_read_id(di->ddp, &di->kv.num);
1344 case di_nextarrayelement: di_nextarrayelement:
1347 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1348 if (di->kv.entry == di->kv.num)
1350 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1352 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1354 di->kv.str = (char *)di->ddp;
1356 di->state = di_nextkey;
1359 if (di->kv.entry == di->kv.num - 1)
1361 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1362 di->ddp = data_read_id(di->ddp, &di->kv.id);
1363 di->kv.str = (char *)di->ddp;
1364 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1366 if ((di->flags & SEARCH_SUB) != 0)
1367 di->state = di_entersub;
1369 di->state = di_nextarrayelement;
1372 case di_entersub: di_entersub:
1373 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1374 goto di_nextarrayelement; /* sorry, full */
1375 di->parents[di->nparents].kv = di->kv;
1376 di->parents[di->nparents].dp = di->dp;
1377 di->parents[di->nparents].keyp = di->keyp;
1378 di->dp = (unsigned char *)di->kv.str;
1379 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1380 memset(&di->kv, 0, sizeof(di->kv));
1381 di->kv.parent = &di->parents[di->nparents].kv;
1383 di->keyname = di->keynames[di->nparents - di->rootlevel];
1384 goto di_enterschema;
1386 case di_leavesub: di_leavesub:
1387 if (di->nparents - 1 < di->rootlevel)
1390 di->dp = di->parents[di->nparents].dp;
1391 di->kv = di->parents[di->nparents].kv;
1392 di->keyp = di->parents[di->nparents].keyp;
1393 di->key = di->data->keys + *di->keyp;
1394 di->ddp = (unsigned char *)di->kv.str;
1395 di->keyname = di->keynames[di->nparents - di->rootlevel];
1396 goto di_nextarrayelement;
1398 /* special solvable attr handling follows */
1400 case di_nextsolvableattr:
1401 di->kv.id = *di->idp++;
1406 di->state = di_nextsolvablekey;
1410 case di_nextsolvablekey: di_nextsolvablekey:
1411 if (di->keyname || di->key->name == RPM_RPMDBID)
1412 goto di_enterrepodata;
1416 case di_entersolvablekey: di_entersolvablekey:
1417 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1418 if (!di->idp || !di->idp[0])
1419 goto di_nextsolvablekey;
1420 di->kv.id = di->idp[0];
1421 di->kv.num = di->idp[0];
1423 if (!di->kv.eof && !di->idp[0])
1427 di->state = di_nextsolvablekey;
1429 di->state = di_nextsolvableattr;
1433 if (di->matcher.match)
1435 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1437 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1441 if (!datamatcher_match(&di->matcher, di->kv.str))
1444 /* found something! */
1450 dataiterator_entersub(Dataiterator *di)
1452 if (di->state == di_nextarrayelement)
1453 di->state = di_entersub;
1457 dataiterator_setpos(Dataiterator *di)
1459 if (di->kv.eof == 2)
1461 pool_clear_pos(di->pool);
1464 di->pool->pos.solvid = di->solvid;
1465 di->pool->pos.repo = di->repo;
1466 di->pool->pos.repodataid = di->data - di->repo->repodata;
1467 di->pool->pos.schema = di->kv.id;
1468 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1472 dataiterator_setpos_parent(Dataiterator *di)
1474 if (!di->kv.parent || di->kv.parent->eof == 2)
1476 pool_clear_pos(di->pool);
1479 di->pool->pos.solvid = di->solvid;
1480 di->pool->pos.repo = di->repo;
1481 di->pool->pos.repodataid = di->data - di->repo->repodata;
1482 di->pool->pos.schema = di->kv.parent->id;
1483 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1486 /* clones just the position, not the search keys/matcher */
1488 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1490 di->state = from->state;
1491 di->flags &= ~SEARCH_THISSOLVID;
1492 di->flags |= (from->flags & SEARCH_THISSOLVID);
1493 di->repo = from->repo;
1494 di->data = from->data;
1496 di->ddp = from->ddp;
1497 di->idp = from->idp;
1498 di->keyp = from->keyp;
1499 di->key = from->key;
1501 di->repodataid = from->repodataid;
1502 di->solvid = from->solvid;
1503 di->repoid = from->repoid;
1504 di->rootlevel = from->rootlevel;
1505 memcpy(di->parents, from->parents, sizeof(from->parents));
1506 di->nparents = from->nparents;
1510 for (i = 1; i < di->nparents; i++)
1511 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1512 di->kv.parent = &di->parents[di->nparents - 1].kv;
1517 dataiterator_seek(Dataiterator *di, int whence)
1519 if ((whence & DI_SEEK_STAY) != 0)
1520 di->rootlevel = di->nparents;
1521 switch (whence & ~DI_SEEK_STAY)
1524 if (di->state != di_nextarrayelement)
1526 if ((whence & DI_SEEK_STAY) != 0)
1527 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1528 di->state = di_entersub;
1530 case DI_SEEK_PARENT:
1537 if (di->rootlevel > di->nparents)
1538 di->rootlevel = di->nparents;
1539 di->dp = di->parents[di->nparents].dp;
1540 di->kv = di->parents[di->nparents].kv;
1541 di->keyp = di->parents[di->nparents].keyp;
1542 di->key = di->data->keys + *di->keyp;
1543 di->ddp = (unsigned char *)di->kv.str;
1544 di->keyname = di->keynames[di->nparents - di->rootlevel];
1545 di->state = di_nextarrayelement;
1547 case DI_SEEK_REWIND:
1553 di->dp = (unsigned char *)di->kv.parent->str;
1554 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1555 di->state = di_enterschema;
1563 dataiterator_skip_attribute(Dataiterator *di)
1565 if (di->state == di_nextsolvableattr)
1566 di->state = di_nextsolvablekey;
1568 di->state = di_nextkey;
1572 dataiterator_skip_solvable(Dataiterator *di)
1576 di->keyname = di->keynames[0];
1577 di->state = di_nextsolvable;
1581 dataiterator_skip_repo(Dataiterator *di)
1585 di->keyname = di->keynames[0];
1586 di->state = di_nextrepo;
1590 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1594 di->keyname = di->keynames[0];
1595 if (solvid == SOLVID_POS)
1597 di->repo = di->pool->pos.repo;
1604 di->data = di->repo->repodata + di->pool->pos.repodataid;
1605 di->repodataid = -1;
1606 di->solvid = solvid;
1607 di->state = di_enterrepo;
1608 di->flags |= SEARCH_THISSOLVID;
1613 di->repo = di->pool->solvables[solvid].repo;
1616 else if (di->repoid >= 0)
1618 if (!di->pool->nrepos)
1623 di->repo = di->pool->repos[0];
1627 di->solvid = solvid;
1629 di->flags |= SEARCH_THISSOLVID;
1630 di->state = di_enterrepo;
1634 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1642 di->flags &= ~SEARCH_THISSOLVID;
1643 di->state = di_enterrepo;
1647 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1649 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1653 return datamatcher_match(ma, di->kv.str);
1656 /************************************************************************
1657 * data modify functions
1660 /* extend repodata so that it includes solvables p */
1662 repodata_extend(Repodata *data, Id p)
1664 if (data->start == data->end)
1665 data->start = data->end = p;
1668 int old = data->end - data->start;
1669 int new = p - data->end + 1;
1672 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1673 memset(data->attrs + old, 0, new * sizeof(Id *));
1675 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1676 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1679 if (p < data->start)
1681 int old = data->end - data->start;
1682 int new = data->start - p;
1685 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1686 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1687 memset(data->attrs, 0, new * sizeof(Id *));
1689 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1690 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1691 memset(data->incoreoffset, 0, new * sizeof(Id));
1696 /* shrink end of repodata */
1698 repodata_shrink(Repodata *data, int end)
1702 if (data->end <= end)
1704 if (data->start >= end)
1708 for (i = 0; i < data->end - data->start; i++)
1709 sat_free(data->attrs[i]);
1710 data->attrs = sat_free(data->attrs);
1712 data->incoreoffset = sat_free(data->incoreoffset);
1713 data->start = data->end = 0;
1718 for (i = end; i < data->end; i++)
1719 sat_free(data->attrs[i - data->start]);
1720 data->attrs = sat_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1722 if (data->incoreoffset)
1723 data->incoreoffset = sat_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1727 /* extend repodata so that it includes solvables from start to start + num - 1 */
1729 repodata_extend_block(Repodata *data, Id start, Id num)
1733 if (!data->incoreoffset)
1735 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1736 data->start = start;
1737 data->end = start + num;
1740 repodata_extend(data, start);
1742 repodata_extend(data, start + num - 1);
1745 /**********************************************************************/
1748 #define REPODATA_ATTRS_BLOCK 63
1749 #define REPODATA_ATTRDATA_BLOCK 1023
1750 #define REPODATA_ATTRIDDATA_BLOCK 63
1754 repodata_new_handle(Repodata *data)
1758 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1761 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1762 data->xattrs[data->nxattrs] = 0;
1763 return -(data->nxattrs++);
1767 repodata_get_attrp(Repodata *data, Id handle)
1769 if (handle == SOLVID_META)
1773 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1778 return data->xattrs - handle;
1779 if (handle < data->start || handle >= data->end)
1780 repodata_extend(data, handle);
1782 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1783 return data->attrs + (handle - data->start);
1787 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1793 app = repodata_get_attrp(data, handle);
1798 /* Determine equality based on the name only, allows us to change
1799 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1800 for (pp = ap; *pp; pp += 2)
1801 if (data->keys[*pp].name == data->keys[keyid].name)
1814 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1824 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1828 keyid = repodata_key2id(data, key, 1);
1829 repodata_insert_keyid(data, solvid, keyid, val, 1);
1833 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1837 key.type = REPOKEY_TYPE_ID;
1839 key.storage = KEY_STORAGE_INCORE;
1840 repodata_set(data, solvid, &key, id);
1844 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1848 key.type = REPOKEY_TYPE_NUM;
1850 key.storage = KEY_STORAGE_INCORE;
1851 repodata_set(data, solvid, &key, (Id)num);
1855 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1859 if (data->localpool)
1860 id = stringpool_str2id(&data->spool, str, 1);
1862 id = str2id(data->repo->pool, str, 1);
1864 key.type = REPOKEY_TYPE_ID;
1866 key.storage = KEY_STORAGE_INCORE;
1867 repodata_set(data, solvid, &key, id);
1871 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1875 key.type = REPOKEY_TYPE_CONSTANT;
1876 key.size = constant;
1877 key.storage = KEY_STORAGE_INCORE;
1878 repodata_set(data, solvid, &key, 0);
1882 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1886 key.type = REPOKEY_TYPE_CONSTANTID;
1888 key.storage = KEY_STORAGE_INCORE;
1889 repodata_set(data, solvid, &key, 0);
1893 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1897 key.type = REPOKEY_TYPE_VOID;
1899 key.storage = KEY_STORAGE_INCORE;
1900 repodata_set(data, solvid, &key, 0);
1904 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1909 l = strlen(str) + 1;
1911 key.type = REPOKEY_TYPE_STR;
1913 key.storage = KEY_STORAGE_INCORE;
1914 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1915 memcpy(data->attrdata + data->attrdatalen, str, l);
1916 repodata_set(data, solvid, &key, data->attrdatalen);
1917 data->attrdatalen += l;
1920 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1921 * so that the caller can append the new element there */
1923 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1926 Id *ida, *pp, **ppp;
1928 /* check if it is the same as last time, this speeds things up a lot */
1929 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1931 /* great! just append the new data */
1932 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1933 data->attriddatalen--; /* overwrite terminating 0 */
1934 data->lastdatalen += entrysize;
1938 ppp = repodata_get_attrp(data, handle);
1941 for (; *pp; pp += 2)
1942 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1946 /* not found. allocate new key */
1951 key.storage = KEY_STORAGE_INCORE;
1952 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1953 repodata_set(data, handle, &key, data->attriddatalen);
1954 data->lasthandle = 0; /* next time... */
1958 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1959 oldsize += entrysize;
1960 if (ida + 1 == data->attriddata + data->attriddatalen)
1962 /* this was the last entry, just append it */
1963 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1964 data->attriddatalen--; /* overwrite terminating 0 */
1968 /* too bad. move to back. */
1969 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1970 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1971 pp[1] = data->attriddatalen;
1972 data->attriddatalen += oldsize;
1974 data->lasthandle = handle;
1975 data->lastkey = *pp;
1976 data->lastdatalen = data->attriddatalen + entrysize + 1;
1980 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1981 const unsigned char *str)
1986 if (!(l = sat_chksum_len(type)))
1991 key.storage = KEY_STORAGE_INCORE;
1992 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1993 memcpy(data->attrdata + data->attrdatalen, str, l);
1994 repodata_set(data, solvid, &key, data->attrdatalen);
1995 data->attrdatalen += l;
1999 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
2002 for (i = 0; i < buflen; i++)
2004 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
2005 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
2006 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
2017 buf[i] = (buf[i] << 4) | v;
2024 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2027 unsigned char buf[64];
2030 if (!(l = sat_chksum_len(type)))
2032 if (hexstr2bytes(buf, str, l) != l)
2034 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2038 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2043 if (!(l = sat_chksum_len(type)))
2045 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2046 for (i = 0; i < l; i++)
2048 unsigned char v = buf[i];
2049 unsigned char w = v >> 4;
2050 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2052 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2058 /* rpm filenames don't contain the epoch, so strip it */
2059 static inline const char *
2060 evrid2vrstr(Pool *pool, Id evrid)
2062 const char *p, *evr = id2str(pool, evrid);
2065 for (p = evr; *p >= '0' && *p <= '9'; p++)
2067 return p != evr && *p == ':' ? p + 1 : evr;
2071 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2073 Pool *pool = data->repo->pool;
2075 const char *str, *fp;
2079 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2082 if ((dir = strrchr(file, '/')) != 0)
2093 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2098 if (l == 1 && dir[0] == '.')
2100 s = pool->solvables + solvid;
2103 str = id2str(pool, s->arch);
2104 if (!strncmp(dir, str, l) && !str[l])
2105 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2107 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
2110 char *dir2 = strdup(dir);
2112 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
2117 str = id2str(pool, s->name);
2119 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2122 str = evrid2vrstr(pool, s->evr);
2124 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2127 str = id2str(pool, s->arch);
2129 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2131 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2136 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2140 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2144 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2146 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2147 data->attriddata[data->attriddatalen++] = dir;
2148 data->attriddata[data->attriddatalen++] = num;
2149 data->attriddata[data->attriddatalen++] = num2;
2150 data->attriddata[data->attriddatalen++] = 0;
2154 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2160 l = strlen(str) + 1;
2161 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2162 memcpy(data->attrdata + data->attrdatalen, str, l);
2163 stroff = data->attrdatalen;
2164 data->attrdatalen += l;
2167 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2169 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2170 data->attriddata[data->attriddatalen++] = dir;
2171 data->attriddata[data->attriddatalen++] = stroff;
2172 data->attriddata[data->attriddatalen++] = 0;
2176 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2179 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2181 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2182 data->attriddata[data->attriddatalen++] = id;
2183 data->attriddata[data->attriddatalen++] = 0;
2187 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2191 if (data->localpool)
2192 id = stringpool_str2id(&data->spool, str, 1);
2194 id = str2id(data->repo->pool, str, 1);
2195 repodata_add_idarray(data, solvid, keyname, id);
2199 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2201 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2202 data->attriddata[data->attriddatalen++] = ghandle;
2203 data->attriddata[data->attriddatalen++] = 0;
2207 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2209 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2210 data->attriddata[data->attriddatalen++] = ghandle;
2211 data->attriddata[data->attriddatalen++] = 0;
2214 /* add all attrs from src to dest */
2216 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2219 if (dest == src || !(keyp = data->attrs[src - data->start]))
2221 for (; *keyp; keyp += 2)
2222 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2226 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2229 if (dest == src || !(keyp = data->attrs[src - data->start]))
2231 for (; *keyp; keyp += 2)
2232 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2233 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2238 /**********************************************************************/
2240 /* TODO: unify with repo_write! */
2242 #define EXTDATA_BLOCK 1023
2250 data_addid(struct extdata *xd, Id x)
2253 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2254 dp = xd->buf + xd->len;
2259 *dp++ = (x >> 28) | 128;
2261 *dp++ = (x >> 21) | 128;
2262 *dp++ = (x >> 14) | 128;
2265 *dp++ = (x >> 7) | 128;
2267 xd->len = dp - xd->buf;
2271 data_addideof(struct extdata *xd, Id x, int eof)
2274 x = (x & 63) | ((x & ~63) << 1);
2275 data_addid(xd, (eof ? x: x | 64));
2279 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2281 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2282 memcpy(xd->buf + xd->len, blob, len);
2286 /*********************************/
2289 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2290 struct extdata *newvincore,
2292 Repokey *key, Id val)
2294 /* Otherwise we have a new value. Parse it into the internal
2298 unsigned int oldvincorelen = 0;
2302 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2305 oldvincorelen = xd->len;
2309 case REPOKEY_TYPE_VOID:
2310 case REPOKEY_TYPE_CONSTANT:
2311 case REPOKEY_TYPE_CONSTANTID:
2313 case REPOKEY_TYPE_STR:
2314 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2316 case REPOKEY_TYPE_MD5:
2317 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2319 case REPOKEY_TYPE_SHA1:
2320 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2322 case REPOKEY_TYPE_SHA256:
2323 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2325 case REPOKEY_TYPE_ID:
2326 case REPOKEY_TYPE_NUM:
2327 case REPOKEY_TYPE_DIR:
2328 data_addid(xd, val);
2330 case REPOKEY_TYPE_IDARRAY:
2331 for (ida = data->attriddata + val; *ida; ida++)
2332 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2334 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2335 for (ida = data->attriddata + val; *ida; ida += 3)
2337 data_addid(xd, ida[0]);
2338 data_addid(xd, ida[1]);
2339 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2342 case REPOKEY_TYPE_DIRSTRARRAY:
2343 for (ida = data->attriddata + val; *ida; ida += 2)
2345 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2346 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2349 case REPOKEY_TYPE_FIXARRAY:
2353 for (ida = data->attriddata + val; *ida; ida++)
2356 fprintf(stderr, "serialize struct %d\n", *ida);
2359 Id *kp = data->xattrs[-*ida];
2366 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2372 schemaid = repodata_schema2id(data, schema, 1);
2373 else if (schemaid != repodata_schema2id(data, schema, 0))
2375 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2379 fprintf(stderr, " schema %d\n", schemaid);
2384 data_addid(xd, num);
2385 data_addid(xd, schemaid);
2386 for (ida = data->attriddata + val; *ida; ida++)
2388 Id *kp = data->xattrs[-*ida];
2393 repodata_serialize_key(data, newincore, newvincore,
2394 schema, data->keys + *kp, kp[1]);
2399 case REPOKEY_TYPE_FLEXARRAY:
2402 for (ida = data->attriddata + val; *ida; ida++)
2404 data_addid(xd, num);
2405 for (ida = data->attriddata + val; *ida; ida++)
2407 Id *kp = data->xattrs[-*ida];
2410 data_addid(xd, 0); /* XXX */
2417 schemaid = repodata_schema2id(data, schema, 1);
2418 data_addid(xd, schemaid);
2419 kp = data->xattrs[-*ida];
2422 repodata_serialize_key(data, newincore, newvincore,
2423 schema, data->keys + *kp, kp[1]);
2429 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2432 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2434 /* put offset/len in incore */
2435 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2436 oldvincorelen = xd->len - oldvincorelen;
2437 data_addid(newincore, oldvincorelen);
2442 repodata_internalize(Repodata *data)
2444 Repokey *key, solvkey;
2446 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2447 unsigned char *dp, *ndp;
2448 int newschema, oldcount;
2449 struct extdata newincore;
2450 struct extdata newvincore;
2453 if (!data->attrs && !data->xattrs)
2456 newvincore.buf = data->vincore;
2457 newvincore.len = data->vincorelen;
2459 /* find the solvables key, create if needed */
2460 memset(&solvkey, 0, sizeof(solvkey));
2461 solvkey.name = REPOSITORY_SOLVABLES;
2462 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2464 solvkey.storage = KEY_STORAGE_INCORE;
2465 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2467 schema = sat_malloc2(data->nkeys, sizeof(Id));
2468 seen = sat_malloc2(data->nkeys, sizeof(Id));
2470 /* Merge the data already existing (in data->schemata, ->incoredata and
2471 friends) with the new attributes in data->attrs[]. */
2472 nentry = data->end - data->start;
2473 memset(&newincore, 0, sizeof(newincore));
2474 data_addid(&newincore, 0); /* start data at offset 1 */
2476 data->mainschema = 0;
2477 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2479 /* join entry data */
2480 /* we start with the meta data, entry -1 */
2481 for (entry = -1; entry < nentry; entry++)
2483 memset(seen, 0, data->nkeys * sizeof(Id));
2485 dp = data->incoredata;
2488 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2489 dp = data_read_id(dp, &oldschema);
2492 fprintf(stderr, "oldschema %d\n", oldschema);
2493 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2494 fprintf(stderr, "schemadata %p\n", data->schemadata);
2496 /* seen: -1: old data 0: skipped >0: id + 1 */
2500 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2504 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2512 keyp = data->attrs ? data->attrs[entry] : 0;
2515 /* strip solvables key */
2517 for (sp = keyp = schema; *sp; sp++)
2518 if (*sp != solvkeyid)
2523 seen[solvkeyid] = 0;
2524 keyp = data->xattrs ? data->xattrs[1] : 0;
2527 for (; *keyp; keyp += 2)
2534 seen[*keyp] = keyp[1] + 1;
2536 if (entry < 0 && data->end != data->start)
2543 /* Ideally we'd like to sort the new schema here, to ensure
2544 schema equality independend of the ordering. We can't do that
2545 yet. For once see below (old ids need to come before new ids).
2546 An additional difficulty is that we also need to move
2547 the values with the keys. */
2548 schemaid = repodata_schema2id(data, schema, 1);
2550 schemaid = oldschema;
2553 /* Now create data blob. We walk through the (possibly new) schema
2554 and either copy over old data, or insert the new. */
2555 /* XXX Here we rely on the fact that the (new) schema has the form
2556 o1 o2 o3 o4 ... | n1 n2 n3 ...
2557 (oX being the old keyids (possibly overwritten), and nX being
2558 the new keyids). This rules out sorting the keyids in order
2559 to ensure a small schema count. */
2561 data->incoreoffset[entry] = newincore.len;
2562 data_addid(&newincore, schemaid);
2565 data->mainschema = schemaid;
2566 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2568 keypstart = data->schemadata + data->schemata[schemaid];
2569 for (keyp = keypstart; *keyp; keyp++)
2572 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2573 if (*keyp == solvkeyid)
2575 /* add flexarray entry count */
2576 data_addid(&newincore, data->end - data->start);
2579 key = data->keys + *keyp;
2581 fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2586 /* Skip the data associated with this old key. */
2587 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2589 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2590 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2592 else if (key->storage == KEY_STORAGE_INCORE)
2593 ndp = data_skip_key(data, dp, key);
2596 if (seen[*keyp] == -1)
2598 /* If this key was an old one _and_ was not overwritten with
2599 a different value copy over the old value (we skipped it
2602 data_addblob(&newincore, dp, ndp - dp);
2605 else if (seen[*keyp])
2607 /* Otherwise we have a new value. Parse it into the internal
2609 repodata_serialize_key(data, &newincore, &newvincore,
2610 schema, key, seen[*keyp] - 1);
2614 if (entry >= 0 && data->attrs && data->attrs[entry])
2615 data->attrs[entry] = sat_free(data->attrs[entry]);
2617 /* free all xattrs */
2618 for (entry = 0; entry < data->nxattrs; entry++)
2619 if (data->xattrs[entry])
2620 sat_free(data->xattrs[entry]);
2621 data->xattrs = sat_free(data->xattrs);
2624 data->lasthandle = 0;
2626 data->lastdatalen = 0;
2629 repodata_free_schemahash(data);
2631 sat_free(data->incoredata);
2632 data->incoredata = newincore.buf;
2633 data->incoredatalen = newincore.len;
2634 data->incoredatafree = 0;
2636 sat_free(data->vincore);
2637 data->vincore = newvincore.buf;
2638 data->vincorelen = newvincore.len;
2640 data->attrs = sat_free(data->attrs);
2641 data->attrdata = sat_free(data->attrdata);
2642 data->attriddata = sat_free(data->attriddata);
2643 data->attrdatalen = 0;
2644 data->attriddatalen = 0;
2648 repodata_disable_paging(Repodata *data)
2650 if (maybe_load_repodata(data, 0))
2651 repopagestore_disable_paging(&data->store);
2655 repodata_load_stub(Repodata *data)
2657 Repo *repo = data->repo;
2658 Pool *pool = repo->pool;
2661 if (!pool->loadcallback)
2663 data->state = REPODATA_ERROR;
2666 data->state = REPODATA_LOADING;
2667 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
2669 data->state = REPODATA_ERROR;
2673 repodata_create_stubs(Repodata *data)
2675 Repo *repo = data->repo;
2676 Pool *pool = repo->pool;
2683 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2684 while (dataiterator_step(&di))
2686 dataiterator_free(&di);
2689 stubdataids = sat_calloc(cnt, sizeof(*stubdataids));
2690 for (i = 0; i < cnt; i++)
2692 sdata = repo_add_repodata(repo, 0);
2693 if (data->end > data->start)
2695 repodata_extend(sdata, data->start);
2696 repodata_extend(sdata, data->end - 1);
2698 stubdataids[i] = sdata - repo->repodata;
2699 sdata->state = REPODATA_STUB;
2700 sdata->loadcallback = repodata_load_stub;
2703 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2705 while (dataiterator_step(&di))
2707 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
2709 dataiterator_entersub(&di);
2710 sdata = repo->repodata + stubdataids[i++];
2714 switch (di.key->type)
2716 case REPOKEY_TYPE_ID:
2717 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
2719 case REPOKEY_TYPE_CONSTANTID:
2720 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
2722 case REPOKEY_TYPE_STR:
2723 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
2725 case REPOKEY_TYPE_VOID:
2726 repodata_set_void(sdata, SOLVID_META, di.key->name);
2728 case REPOKEY_TYPE_NUM:
2729 repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
2731 case REPOKEY_TYPE_MD5:
2732 case REPOKEY_TYPE_SHA1:
2733 case REPOKEY_TYPE_SHA256:
2734 repodata_set_checksum(sdata, SOLVID_META, di.key->name, di.key->type, di.kv.str);
2736 case REPOKEY_TYPE_IDARRAY:
2737 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
2738 if (di.key->name == REPOSITORY_KEYS)
2745 xkeyname = di.kv.id;
2748 xkey.name = xkeyname;
2749 xkey.type = di.kv.id;
2750 xkey.storage = KEY_STORAGE_INCORE;
2752 repodata_key2id(sdata, &xkey, 1);
2757 dataiterator_free(&di);
2758 for (i = 0; i < cnt; i++)
2759 repodata_internalize(repo->repodata + stubdataids[i]);
2760 sat_free(stubdataids);
2764 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: