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 int needcomplete = 0;
1184 Repodata *data = di->data;
1186 if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
1187 if (!di->matcher.match || (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING || !repodata_filelistfilter_matches(di->data, di->matcher.match))
1189 if (data->state != REPODATA_AVAILABLE)
1190 return needcomplete ? 1 : 0;
1191 for (j = 1; j < data->nkeys; j++)
1192 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1194 return j == data->nkeys && needcomplete ? 1 : 0;
1198 dataiterator_step(Dataiterator *di)
1206 case di_enterrepo: di_enterrepo:
1209 if (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS))
1211 if (!(di->flags & SEARCH_THISSOLVID))
1213 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1214 goto di_nextsolvable;
1218 case di_entersolvable: di_entersolvable:
1219 if (di->repodataid >= 0)
1221 di->repodataid = 0; /* reset repodata iterator */
1222 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)
1224 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1226 goto di_entersolvablekey;
1231 case di_enterrepodata: di_enterrepodata:
1232 if (di->repodataid >= 0)
1234 if (di->repodataid >= di->repo->nrepodata)
1235 goto di_nextsolvable;
1236 di->data = di->repo->repodata + di->repodataid;
1238 if (di->repodataid >= 0 && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1239 goto di_nextrepodata;
1240 if (!maybe_load_repodata(di->data, di->keyname))
1241 goto di_nextrepodata;
1242 di->dp = solvid2data(di->data, di->solvid, &schema);
1244 goto di_nextrepodata;
1245 if (di->solvid == SOLVID_POS)
1246 di->solvid = di->pool->pos.solvid;
1247 /* reset key iterator */
1248 di->keyp = di->data->schemadata + di->data->schemata[schema];
1251 case di_enterschema: di_enterschema:
1253 di->dp = dataiterator_find_keyname(di, di->keyname);
1254 if (!di->dp || !*di->keyp)
1258 goto di_nextrepodata;
1262 case di_enterkey: di_enterkey:
1264 di->key = di->data->keys + *di->keyp;
1265 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1268 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1270 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1276 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1278 di->state = di_nextkey;
1280 di->state = di_nextattr;
1283 case di_nextkey: di_nextkey:
1284 if (!di->keyname && *++di->keyp)
1290 case di_nextrepodata: di_nextrepodata:
1291 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1292 goto di_enterrepodata;
1295 case di_nextsolvable: di_nextsolvable:
1296 if (!(di->flags & SEARCH_THISSOLVID))
1299 di->solvid = di->repo->start;
1302 for (; di->solvid < di->repo->end; di->solvid++)
1304 if (di->pool->solvables[di->solvid].repo == di->repo)
1305 goto di_entersolvable;
1310 case di_nextrepo: di_nextrepo:
1311 if (di->repoid >= 0)
1315 if (di->repoid < di->pool->nrepos)
1317 di->repo = di->pool->repos[di->repoid];
1323 case di_bye: di_bye:
1327 case di_enterarray: di_enterarray:
1328 if (di->key->name == REPOSITORY_SOLVABLES)
1330 di->ddp = data_read_id(di->ddp, &di->kv.num);
1335 case di_nextarrayelement: di_nextarrayelement:
1338 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1339 if (di->kv.entry == di->kv.num)
1341 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1343 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1345 di->kv.str = (char *)di->ddp;
1347 di->state = di_nextkey;
1350 if (di->kv.entry == di->kv.num - 1)
1352 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1353 di->ddp = data_read_id(di->ddp, &di->kv.id);
1354 di->kv.str = (char *)di->ddp;
1355 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1357 if ((di->flags & SEARCH_SUB) != 0)
1358 di->state = di_entersub;
1360 di->state = di_nextarrayelement;
1363 case di_entersub: di_entersub:
1364 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1365 goto di_nextarrayelement; /* sorry, full */
1366 di->parents[di->nparents].kv = di->kv;
1367 di->parents[di->nparents].dp = di->dp;
1368 di->parents[di->nparents].keyp = di->keyp;
1369 di->dp = (unsigned char *)di->kv.str;
1370 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1371 memset(&di->kv, 0, sizeof(di->kv));
1372 di->kv.parent = &di->parents[di->nparents].kv;
1374 di->keyname = di->keynames[di->nparents - di->rootlevel];
1375 goto di_enterschema;
1377 case di_leavesub: di_leavesub:
1378 if (di->nparents - 1 < di->rootlevel)
1381 di->dp = di->parents[di->nparents].dp;
1382 di->kv = di->parents[di->nparents].kv;
1383 di->keyp = di->parents[di->nparents].keyp;
1384 di->key = di->data->keys + *di->keyp;
1385 di->ddp = (unsigned char *)di->kv.str;
1386 di->keyname = di->keynames[di->nparents - di->rootlevel];
1387 goto di_nextarrayelement;
1389 /* special solvable attr handling follows */
1391 case di_nextsolvableattr:
1392 di->kv.id = *di->idp++;
1397 di->state = di_nextsolvablekey;
1401 case di_nextsolvablekey: di_nextsolvablekey:
1402 if (di->keyname || di->key->name == RPM_RPMDBID)
1403 goto di_enterrepodata;
1407 case di_entersolvablekey: di_entersolvablekey:
1408 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1409 if (!di->idp || !di->idp[0])
1410 goto di_nextsolvablekey;
1411 di->kv.id = di->idp[0];
1412 di->kv.num = di->idp[0];
1414 if (!di->kv.eof && !di->idp[0])
1418 di->state = di_nextsolvablekey;
1420 di->state = di_nextsolvableattr;
1424 if (di->matcher.match)
1426 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1428 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1432 if (!datamatcher_match(&di->matcher, di->kv.str))
1435 /* found something! */
1441 dataiterator_entersub(Dataiterator *di)
1443 if (di->state == di_nextarrayelement)
1444 di->state = di_entersub;
1448 dataiterator_setpos(Dataiterator *di)
1450 if (di->kv.eof == 2)
1452 pool_clear_pos(di->pool);
1455 di->pool->pos.solvid = di->solvid;
1456 di->pool->pos.repo = di->repo;
1457 di->pool->pos.repodataid = di->data - di->repo->repodata;
1458 di->pool->pos.schema = di->kv.id;
1459 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1463 dataiterator_setpos_parent(Dataiterator *di)
1465 if (!di->kv.parent || di->kv.parent->eof == 2)
1467 pool_clear_pos(di->pool);
1470 di->pool->pos.solvid = di->solvid;
1471 di->pool->pos.repo = di->repo;
1472 di->pool->pos.repodataid = di->data - di->repo->repodata;
1473 di->pool->pos.schema = di->kv.parent->id;
1474 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1477 /* clones just the position, not the search keys/matcher */
1479 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1481 di->state = from->state;
1482 di->flags &= ~SEARCH_THISSOLVID;
1483 di->flags |= (from->flags & SEARCH_THISSOLVID);
1484 di->repo = from->repo;
1485 di->data = from->data;
1487 di->ddp = from->ddp;
1488 di->idp = from->idp;
1489 di->keyp = from->keyp;
1490 di->key = from->key;
1492 di->repodataid = from->repodataid;
1493 di->solvid = from->solvid;
1494 di->repoid = from->repoid;
1495 di->rootlevel = from->rootlevel;
1496 memcpy(di->parents, from->parents, sizeof(from->parents));
1497 di->nparents = from->nparents;
1501 for (i = 1; i < di->nparents; i++)
1502 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1503 di->kv.parent = &di->parents[di->nparents - 1].kv;
1508 dataiterator_seek(Dataiterator *di, int whence)
1510 if ((whence & DI_SEEK_STAY) != 0)
1511 di->rootlevel = di->nparents;
1512 switch (whence & ~DI_SEEK_STAY)
1515 if (di->state != di_nextarrayelement)
1517 if ((whence & DI_SEEK_STAY) != 0)
1518 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1519 di->state = di_entersub;
1521 case DI_SEEK_PARENT:
1528 if (di->rootlevel > di->nparents)
1529 di->rootlevel = di->nparents;
1530 di->dp = di->parents[di->nparents].dp;
1531 di->kv = di->parents[di->nparents].kv;
1532 di->keyp = di->parents[di->nparents].keyp;
1533 di->key = di->data->keys + *di->keyp;
1534 di->ddp = (unsigned char *)di->kv.str;
1535 di->keyname = di->keynames[di->nparents - di->rootlevel];
1536 di->state = di_nextarrayelement;
1538 case DI_SEEK_REWIND:
1544 di->dp = (unsigned char *)di->kv.parent->str;
1545 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1546 di->state = di_enterschema;
1554 dataiterator_skip_attribute(Dataiterator *di)
1556 if (di->state == di_nextsolvableattr)
1557 di->state = di_nextsolvablekey;
1559 di->state = di_nextkey;
1563 dataiterator_skip_solvable(Dataiterator *di)
1567 di->keyname = di->keynames[0];
1568 di->state = di_nextsolvable;
1572 dataiterator_skip_repo(Dataiterator *di)
1576 di->keyname = di->keynames[0];
1577 di->state = di_nextrepo;
1581 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1585 di->keyname = di->keynames[0];
1586 if (solvid == SOLVID_POS)
1588 di->repo = di->pool->pos.repo;
1595 di->data = di->repo->repodata + di->pool->pos.repodataid;
1596 di->repodataid = -1;
1597 di->solvid = solvid;
1598 di->state = di_enterrepo;
1599 di->flags |= SEARCH_THISSOLVID;
1604 di->repo = di->pool->solvables[solvid].repo;
1607 else if (di->repoid >= 0)
1609 if (!di->pool->nrepos)
1614 di->repo = di->pool->repos[0];
1618 di->solvid = solvid;
1620 di->flags |= SEARCH_THISSOLVID;
1621 di->state = di_enterrepo;
1625 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1633 di->flags &= ~SEARCH_THISSOLVID;
1634 di->state = di_enterrepo;
1638 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1640 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1644 return datamatcher_match(ma, di->kv.str);
1647 /************************************************************************
1648 * data modify functions
1651 /* extend repodata so that it includes solvables p */
1653 repodata_extend(Repodata *data, Id p)
1655 if (data->start == data->end)
1656 data->start = data->end = p;
1659 int old = data->end - data->start;
1660 int new = p - data->end + 1;
1663 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1664 memset(data->attrs + old, 0, new * sizeof(Id *));
1666 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1667 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1670 if (p < data->start)
1672 int old = data->end - data->start;
1673 int new = data->start - p;
1676 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1677 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1678 memset(data->attrs, 0, new * sizeof(Id *));
1680 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1681 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1682 memset(data->incoreoffset, 0, new * sizeof(Id));
1687 /* shrink end of repodata */
1689 repodata_shrink(Repodata *data, int end)
1693 if (data->end <= end)
1695 if (data->start >= end)
1699 for (i = 0; i < data->end - data->start; i++)
1700 sat_free(data->attrs[i]);
1701 data->attrs = sat_free(data->attrs);
1703 data->incoreoffset = sat_free(data->incoreoffset);
1704 data->start = data->end = 0;
1709 for (i = end; i < data->end; i++)
1710 sat_free(data->attrs[i - data->start]);
1711 data->attrs = sat_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1713 if (data->incoreoffset)
1714 data->incoreoffset = sat_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1718 /* extend repodata so that it includes solvables from start to start + num - 1 */
1720 repodata_extend_block(Repodata *data, Id start, Id num)
1724 if (!data->incoreoffset)
1726 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1727 data->start = start;
1728 data->end = start + num;
1731 repodata_extend(data, start);
1733 repodata_extend(data, start + num - 1);
1736 /**********************************************************************/
1739 #define REPODATA_ATTRS_BLOCK 63
1740 #define REPODATA_ATTRDATA_BLOCK 1023
1741 #define REPODATA_ATTRIDDATA_BLOCK 63
1745 repodata_new_handle(Repodata *data)
1749 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1752 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1753 data->xattrs[data->nxattrs] = 0;
1754 return -(data->nxattrs++);
1758 repodata_get_attrp(Repodata *data, Id handle)
1760 if (handle == SOLVID_META)
1764 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1769 return data->xattrs - handle;
1770 if (handle < data->start || handle >= data->end)
1771 repodata_extend(data, handle);
1773 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1774 return data->attrs + (handle - data->start);
1778 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1784 app = repodata_get_attrp(data, handle);
1789 /* Determine equality based on the name only, allows us to change
1790 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1791 for (pp = ap; *pp; pp += 2)
1792 if (data->keys[*pp].name == data->keys[keyid].name)
1805 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1815 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1819 keyid = repodata_key2id(data, key, 1);
1820 repodata_insert_keyid(data, solvid, keyid, val, 1);
1824 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1828 key.type = REPOKEY_TYPE_ID;
1830 key.storage = KEY_STORAGE_INCORE;
1831 repodata_set(data, solvid, &key, id);
1835 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1839 key.type = REPOKEY_TYPE_NUM;
1841 key.storage = KEY_STORAGE_INCORE;
1842 repodata_set(data, solvid, &key, (Id)num);
1846 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1850 if (data->localpool)
1851 id = stringpool_str2id(&data->spool, str, 1);
1853 id = str2id(data->repo->pool, str, 1);
1855 key.type = REPOKEY_TYPE_ID;
1857 key.storage = KEY_STORAGE_INCORE;
1858 repodata_set(data, solvid, &key, id);
1862 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1866 key.type = REPOKEY_TYPE_CONSTANT;
1867 key.size = constant;
1868 key.storage = KEY_STORAGE_INCORE;
1869 repodata_set(data, solvid, &key, 0);
1873 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1877 key.type = REPOKEY_TYPE_CONSTANTID;
1879 key.storage = KEY_STORAGE_INCORE;
1880 repodata_set(data, solvid, &key, 0);
1884 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1888 key.type = REPOKEY_TYPE_VOID;
1890 key.storage = KEY_STORAGE_INCORE;
1891 repodata_set(data, solvid, &key, 0);
1895 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1900 l = strlen(str) + 1;
1902 key.type = REPOKEY_TYPE_STR;
1904 key.storage = KEY_STORAGE_INCORE;
1905 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1906 memcpy(data->attrdata + data->attrdatalen, str, l);
1907 repodata_set(data, solvid, &key, data->attrdatalen);
1908 data->attrdatalen += l;
1911 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1912 * so that the caller can append the new element there */
1914 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1917 Id *ida, *pp, **ppp;
1919 /* check if it is the same as last time, this speeds things up a lot */
1920 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1922 /* great! just append the new data */
1923 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1924 data->attriddatalen--; /* overwrite terminating 0 */
1925 data->lastdatalen += entrysize;
1929 ppp = repodata_get_attrp(data, handle);
1932 for (; *pp; pp += 2)
1933 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1937 /* not found. allocate new key */
1942 key.storage = KEY_STORAGE_INCORE;
1943 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1944 repodata_set(data, handle, &key, data->attriddatalen);
1945 data->lasthandle = 0; /* next time... */
1949 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1950 oldsize += entrysize;
1951 if (ida + 1 == data->attriddata + data->attriddatalen)
1953 /* this was the last entry, just append it */
1954 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1955 data->attriddatalen--; /* overwrite terminating 0 */
1959 /* too bad. move to back. */
1960 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1961 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1962 pp[1] = data->attriddatalen;
1963 data->attriddatalen += oldsize;
1965 data->lasthandle = handle;
1966 data->lastkey = *pp;
1967 data->lastdatalen = data->attriddatalen + entrysize + 1;
1971 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1972 const unsigned char *str)
1977 if (!(l = sat_chksum_len(type)))
1982 key.storage = KEY_STORAGE_INCORE;
1983 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1984 memcpy(data->attrdata + data->attrdatalen, str, l);
1985 repodata_set(data, solvid, &key, data->attrdatalen);
1986 data->attrdatalen += l;
1990 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1993 for (i = 0; i < buflen; i++)
1995 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1996 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
1997 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
2008 buf[i] = (buf[i] << 4) | v;
2015 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2018 unsigned char buf[64];
2021 if (!(l = sat_chksum_len(type)))
2023 if (hexstr2bytes(buf, str, l) != l)
2025 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2029 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2034 if (!(l = sat_chksum_len(type)))
2036 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2037 for (i = 0; i < l; i++)
2039 unsigned char v = buf[i];
2040 unsigned char w = v >> 4;
2041 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2043 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2049 /* rpm filenames don't contain the epoch, so strip it */
2050 static inline const char *
2051 evrid2vrstr(Pool *pool, Id evrid)
2053 const char *p, *evr = id2str(pool, evrid);
2056 for (p = evr; *p >= '0' && *p <= '9'; p++)
2058 return p != evr && *p == ':' ? p + 1 : evr;
2062 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2064 Pool *pool = data->repo->pool;
2066 const char *str, *fp;
2070 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2073 if ((dir = strrchr(file, '/')) != 0)
2084 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2089 if (l == 1 && dir[0] == '.')
2091 s = pool->solvables + solvid;
2094 str = id2str(pool, s->arch);
2095 if (!strncmp(dir, str, l) && !str[l])
2096 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2098 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
2101 char *dir2 = strdup(dir);
2103 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
2108 str = id2str(pool, s->name);
2110 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2113 str = evrid2vrstr(pool, s->evr);
2115 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2118 str = id2str(pool, s->arch);
2120 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2122 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2127 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2131 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2135 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2137 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2138 data->attriddata[data->attriddatalen++] = dir;
2139 data->attriddata[data->attriddatalen++] = num;
2140 data->attriddata[data->attriddatalen++] = num2;
2141 data->attriddata[data->attriddatalen++] = 0;
2145 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2151 l = strlen(str) + 1;
2152 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2153 memcpy(data->attrdata + data->attrdatalen, str, l);
2154 stroff = data->attrdatalen;
2155 data->attrdatalen += l;
2158 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2160 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2161 data->attriddata[data->attriddatalen++] = dir;
2162 data->attriddata[data->attriddatalen++] = stroff;
2163 data->attriddata[data->attriddatalen++] = 0;
2167 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2170 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2172 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2173 data->attriddata[data->attriddatalen++] = id;
2174 data->attriddata[data->attriddatalen++] = 0;
2178 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2182 if (data->localpool)
2183 id = stringpool_str2id(&data->spool, str, 1);
2185 id = str2id(data->repo->pool, str, 1);
2186 repodata_add_idarray(data, solvid, keyname, id);
2190 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2192 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2193 data->attriddata[data->attriddatalen++] = ghandle;
2194 data->attriddata[data->attriddatalen++] = 0;
2198 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2200 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2201 data->attriddata[data->attriddatalen++] = ghandle;
2202 data->attriddata[data->attriddatalen++] = 0;
2205 /* add all attrs from src to dest */
2207 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2210 if (dest == src || !(keyp = data->attrs[src - data->start]))
2212 for (; *keyp; keyp += 2)
2213 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2217 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2220 if (dest == src || !(keyp = data->attrs[src - data->start]))
2222 for (; *keyp; keyp += 2)
2223 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2224 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2229 /**********************************************************************/
2231 /* TODO: unify with repo_write! */
2233 #define EXTDATA_BLOCK 1023
2241 data_addid(struct extdata *xd, Id x)
2244 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2245 dp = xd->buf + xd->len;
2250 *dp++ = (x >> 28) | 128;
2252 *dp++ = (x >> 21) | 128;
2253 *dp++ = (x >> 14) | 128;
2256 *dp++ = (x >> 7) | 128;
2258 xd->len = dp - xd->buf;
2262 data_addideof(struct extdata *xd, Id x, int eof)
2265 x = (x & 63) | ((x & ~63) << 1);
2266 data_addid(xd, (eof ? x: x | 64));
2270 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2272 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2273 memcpy(xd->buf + xd->len, blob, len);
2277 /*********************************/
2280 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2281 struct extdata *newvincore,
2283 Repokey *key, Id val)
2285 /* Otherwise we have a new value. Parse it into the internal
2289 unsigned int oldvincorelen = 0;
2293 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2296 oldvincorelen = xd->len;
2300 case REPOKEY_TYPE_VOID:
2301 case REPOKEY_TYPE_CONSTANT:
2302 case REPOKEY_TYPE_CONSTANTID:
2304 case REPOKEY_TYPE_STR:
2305 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2307 case REPOKEY_TYPE_MD5:
2308 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2310 case REPOKEY_TYPE_SHA1:
2311 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2313 case REPOKEY_TYPE_SHA256:
2314 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2316 case REPOKEY_TYPE_ID:
2317 case REPOKEY_TYPE_NUM:
2318 case REPOKEY_TYPE_DIR:
2319 data_addid(xd, val);
2321 case REPOKEY_TYPE_IDARRAY:
2322 for (ida = data->attriddata + val; *ida; ida++)
2323 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2325 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2326 for (ida = data->attriddata + val; *ida; ida += 3)
2328 data_addid(xd, ida[0]);
2329 data_addid(xd, ida[1]);
2330 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2333 case REPOKEY_TYPE_DIRSTRARRAY:
2334 for (ida = data->attriddata + val; *ida; ida += 2)
2336 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2337 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2340 case REPOKEY_TYPE_FIXARRAY:
2344 for (ida = data->attriddata + val; *ida; ida++)
2347 fprintf(stderr, "serialize struct %d\n", *ida);
2350 Id *kp = data->xattrs[-*ida];
2357 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2363 schemaid = repodata_schema2id(data, schema, 1);
2364 else if (schemaid != repodata_schema2id(data, schema, 0))
2366 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2370 fprintf(stderr, " schema %d\n", schemaid);
2375 data_addid(xd, num);
2376 data_addid(xd, schemaid);
2377 for (ida = data->attriddata + val; *ida; ida++)
2379 Id *kp = data->xattrs[-*ida];
2384 repodata_serialize_key(data, newincore, newvincore,
2385 schema, data->keys + *kp, kp[1]);
2390 case REPOKEY_TYPE_FLEXARRAY:
2393 for (ida = data->attriddata + val; *ida; ida++)
2395 data_addid(xd, num);
2396 for (ida = data->attriddata + val; *ida; ida++)
2398 Id *kp = data->xattrs[-*ida];
2401 data_addid(xd, 0); /* XXX */
2408 schemaid = repodata_schema2id(data, schema, 1);
2409 data_addid(xd, schemaid);
2410 kp = data->xattrs[-*ida];
2413 repodata_serialize_key(data, newincore, newvincore,
2414 schema, data->keys + *kp, kp[1]);
2420 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2423 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2425 /* put offset/len in incore */
2426 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2427 oldvincorelen = xd->len - oldvincorelen;
2428 data_addid(newincore, oldvincorelen);
2433 repodata_internalize(Repodata *data)
2435 Repokey *key, solvkey;
2437 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2438 unsigned char *dp, *ndp;
2439 int newschema, oldcount;
2440 struct extdata newincore;
2441 struct extdata newvincore;
2444 if (!data->attrs && !data->xattrs)
2447 newvincore.buf = data->vincore;
2448 newvincore.len = data->vincorelen;
2450 /* find the solvables key, create if needed */
2451 memset(&solvkey, 0, sizeof(solvkey));
2452 solvkey.name = REPOSITORY_SOLVABLES;
2453 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2455 solvkey.storage = KEY_STORAGE_INCORE;
2456 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2458 schema = sat_malloc2(data->nkeys, sizeof(Id));
2459 seen = sat_malloc2(data->nkeys, sizeof(Id));
2461 /* Merge the data already existing (in data->schemata, ->incoredata and
2462 friends) with the new attributes in data->attrs[]. */
2463 nentry = data->end - data->start;
2464 memset(&newincore, 0, sizeof(newincore));
2465 data_addid(&newincore, 0); /* start data at offset 1 */
2467 data->mainschema = 0;
2468 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2470 /* join entry data */
2471 /* we start with the meta data, entry -1 */
2472 for (entry = -1; entry < nentry; entry++)
2474 memset(seen, 0, data->nkeys * sizeof(Id));
2476 dp = data->incoredata;
2479 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2480 dp = data_read_id(dp, &oldschema);
2483 fprintf(stderr, "oldschema %d\n", oldschema);
2484 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2485 fprintf(stderr, "schemadata %p\n", data->schemadata);
2487 /* seen: -1: old data 0: skipped >0: id + 1 */
2491 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2495 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2503 keyp = data->attrs ? data->attrs[entry] : 0;
2506 /* strip solvables key */
2508 for (sp = keyp = schema; *sp; sp++)
2509 if (*sp != solvkeyid)
2514 seen[solvkeyid] = 0;
2515 keyp = data->xattrs ? data->xattrs[1] : 0;
2518 for (; *keyp; keyp += 2)
2525 seen[*keyp] = keyp[1] + 1;
2527 if (entry < 0 && data->end != data->start)
2534 /* Ideally we'd like to sort the new schema here, to ensure
2535 schema equality independend of the ordering. We can't do that
2536 yet. For once see below (old ids need to come before new ids).
2537 An additional difficulty is that we also need to move
2538 the values with the keys. */
2539 schemaid = repodata_schema2id(data, schema, 1);
2541 schemaid = oldschema;
2544 /* Now create data blob. We walk through the (possibly new) schema
2545 and either copy over old data, or insert the new. */
2546 /* XXX Here we rely on the fact that the (new) schema has the form
2547 o1 o2 o3 o4 ... | n1 n2 n3 ...
2548 (oX being the old keyids (possibly overwritten), and nX being
2549 the new keyids). This rules out sorting the keyids in order
2550 to ensure a small schema count. */
2552 data->incoreoffset[entry] = newincore.len;
2553 data_addid(&newincore, schemaid);
2556 data->mainschema = schemaid;
2557 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2559 keypstart = data->schemadata + data->schemata[schemaid];
2560 for (keyp = keypstart; *keyp; keyp++)
2563 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2564 if (*keyp == solvkeyid)
2566 /* add flexarray entry count */
2567 data_addid(&newincore, data->end - data->start);
2570 key = data->keys + *keyp;
2572 fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2577 /* Skip the data associated with this old key. */
2578 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2580 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2581 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2583 else if (key->storage == KEY_STORAGE_INCORE)
2584 ndp = data_skip_key(data, dp, key);
2587 if (seen[*keyp] == -1)
2589 /* If this key was an old one _and_ was not overwritten with
2590 a different value copy over the old value (we skipped it
2593 data_addblob(&newincore, dp, ndp - dp);
2596 else if (seen[*keyp])
2598 /* Otherwise we have a new value. Parse it into the internal
2600 repodata_serialize_key(data, &newincore, &newvincore,
2601 schema, key, seen[*keyp] - 1);
2605 if (entry >= 0 && data->attrs && data->attrs[entry])
2606 data->attrs[entry] = sat_free(data->attrs[entry]);
2608 /* free all xattrs */
2609 for (entry = 0; entry < data->nxattrs; entry++)
2610 if (data->xattrs[entry])
2611 sat_free(data->xattrs[entry]);
2612 data->xattrs = sat_free(data->xattrs);
2615 data->lasthandle = 0;
2617 data->lastdatalen = 0;
2620 repodata_free_schemahash(data);
2622 sat_free(data->incoredata);
2623 data->incoredata = newincore.buf;
2624 data->incoredatalen = newincore.len;
2625 data->incoredatafree = 0;
2627 sat_free(data->vincore);
2628 data->vincore = newvincore.buf;
2629 data->vincorelen = newvincore.len;
2631 data->attrs = sat_free(data->attrs);
2632 data->attrdata = sat_free(data->attrdata);
2633 data->attriddata = sat_free(data->attriddata);
2634 data->attrdatalen = 0;
2635 data->attriddatalen = 0;
2639 repodata_disable_paging(Repodata *data)
2641 if (maybe_load_repodata(data, 0))
2642 repopagestore_disable_paging(&data->store);
2646 repodata_load_stub(Repodata *data)
2648 Repo *repo = data->repo;
2649 Pool *pool = repo->pool;
2652 if (!pool->loadcallback)
2654 data->state = REPODATA_ERROR;
2657 data->state = REPODATA_LOADING;
2658 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
2660 data->state = REPODATA_ERROR;
2664 repodata_create_stubs(Repodata *data)
2666 Repo *repo = data->repo;
2667 Pool *pool = repo->pool;
2674 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2675 while (dataiterator_step(&di))
2677 dataiterator_free(&di);
2680 stubdataids = sat_calloc(cnt, sizeof(*stubdataids));
2681 for (i = 0; i < cnt; i++)
2683 sdata = repo_add_repodata(repo, 0);
2684 if (data->end > data->start)
2686 repodata_extend(sdata, data->start);
2687 repodata_extend(sdata, data->end - 1);
2689 stubdataids[i] = sdata - repo->repodata;
2690 sdata->state = REPODATA_STUB;
2691 sdata->loadcallback = repodata_load_stub;
2694 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2696 while (dataiterator_step(&di))
2698 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
2700 dataiterator_entersub(&di);
2701 sdata = repo->repodata + stubdataids[i++];
2705 switch (di.key->type)
2707 case REPOKEY_TYPE_ID:
2708 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
2710 case REPOKEY_TYPE_CONSTANTID:
2711 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
2713 case REPOKEY_TYPE_STR:
2714 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
2716 case REPOKEY_TYPE_VOID:
2717 repodata_set_void(sdata, SOLVID_META, di.key->name);
2719 case REPOKEY_TYPE_NUM:
2720 repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
2722 case REPOKEY_TYPE_MD5:
2723 case REPOKEY_TYPE_SHA1:
2724 case REPOKEY_TYPE_SHA256:
2725 repodata_set_checksum(sdata, SOLVID_META, di.key->name, di.key->type, di.kv.str);
2727 case REPOKEY_TYPE_IDARRAY:
2728 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
2729 if (di.key->name == REPOSITORY_KEYS)
2736 xkeyname = di.kv.id;
2739 xkey.name = xkeyname;
2740 xkey.type = di.kv.id;
2741 xkey.storage = KEY_STORAGE_INCORE;
2743 repodata_key2id(sdata, &xkey, 1);
2748 dataiterator_free(&di);
2749 for (i = 0; i < cnt; i++)
2750 repodata_internalize(repo->repodata + stubdataids[i]);
2751 sat_free(stubdataids);
2755 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: