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 ? 0 : 1;
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 /* simple pre-check so that we don't need to stringify */
1427 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && di->matcher.match && (di->matcher.flags & (SEARCH_FILES|SEARCH_NOCASE|SEARCH_STRINGMASK)) == (SEARCH_FILES|SEARCH_STRING))
1429 int l = strlen(di->matcher.match) - strlen(di->kv.str);
1430 if (l < 0 || strcmp(di->matcher.match + l, di->kv.str))
1433 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1435 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1439 if (!datamatcher_match(&di->matcher, di->kv.str))
1442 /* found something! */
1448 dataiterator_entersub(Dataiterator *di)
1450 if (di->state == di_nextarrayelement)
1451 di->state = di_entersub;
1455 dataiterator_setpos(Dataiterator *di)
1457 if (di->kv.eof == 2)
1459 pool_clear_pos(di->pool);
1462 di->pool->pos.solvid = di->solvid;
1463 di->pool->pos.repo = di->repo;
1464 di->pool->pos.repodataid = di->data - di->repo->repodata;
1465 di->pool->pos.schema = di->kv.id;
1466 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1470 dataiterator_setpos_parent(Dataiterator *di)
1472 if (!di->kv.parent || di->kv.parent->eof == 2)
1474 pool_clear_pos(di->pool);
1477 di->pool->pos.solvid = di->solvid;
1478 di->pool->pos.repo = di->repo;
1479 di->pool->pos.repodataid = di->data - di->repo->repodata;
1480 di->pool->pos.schema = di->kv.parent->id;
1481 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1484 /* clones just the position, not the search keys/matcher */
1486 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1488 di->state = from->state;
1489 di->flags &= ~SEARCH_THISSOLVID;
1490 di->flags |= (from->flags & SEARCH_THISSOLVID);
1491 di->repo = from->repo;
1492 di->data = from->data;
1494 di->ddp = from->ddp;
1495 di->idp = from->idp;
1496 di->keyp = from->keyp;
1497 di->key = from->key;
1499 di->repodataid = from->repodataid;
1500 di->solvid = from->solvid;
1501 di->repoid = from->repoid;
1502 di->rootlevel = from->rootlevel;
1503 memcpy(di->parents, from->parents, sizeof(from->parents));
1504 di->nparents = from->nparents;
1508 for (i = 1; i < di->nparents; i++)
1509 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1510 di->kv.parent = &di->parents[di->nparents - 1].kv;
1515 dataiterator_seek(Dataiterator *di, int whence)
1517 if ((whence & DI_SEEK_STAY) != 0)
1518 di->rootlevel = di->nparents;
1519 switch (whence & ~DI_SEEK_STAY)
1522 if (di->state != di_nextarrayelement)
1524 if ((whence & DI_SEEK_STAY) != 0)
1525 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1526 di->state = di_entersub;
1528 case DI_SEEK_PARENT:
1535 if (di->rootlevel > di->nparents)
1536 di->rootlevel = di->nparents;
1537 di->dp = di->parents[di->nparents].dp;
1538 di->kv = di->parents[di->nparents].kv;
1539 di->keyp = di->parents[di->nparents].keyp;
1540 di->key = di->data->keys + *di->keyp;
1541 di->ddp = (unsigned char *)di->kv.str;
1542 di->keyname = di->keynames[di->nparents - di->rootlevel];
1543 di->state = di_nextarrayelement;
1545 case DI_SEEK_REWIND:
1551 di->dp = (unsigned char *)di->kv.parent->str;
1552 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1553 di->state = di_enterschema;
1561 dataiterator_skip_attribute(Dataiterator *di)
1563 if (di->state == di_nextsolvableattr)
1564 di->state = di_nextsolvablekey;
1566 di->state = di_nextkey;
1570 dataiterator_skip_solvable(Dataiterator *di)
1574 di->keyname = di->keynames[0];
1575 di->state = di_nextsolvable;
1579 dataiterator_skip_repo(Dataiterator *di)
1583 di->keyname = di->keynames[0];
1584 di->state = di_nextrepo;
1588 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1592 di->keyname = di->keynames[0];
1593 if (solvid == SOLVID_POS)
1595 di->repo = di->pool->pos.repo;
1602 di->data = di->repo->repodata + di->pool->pos.repodataid;
1603 di->repodataid = -1;
1604 di->solvid = solvid;
1605 di->state = di_enterrepo;
1606 di->flags |= SEARCH_THISSOLVID;
1611 di->repo = di->pool->solvables[solvid].repo;
1614 else if (di->repoid >= 0)
1616 if (!di->pool->nrepos)
1621 di->repo = di->pool->repos[0];
1625 di->solvid = solvid;
1627 di->flags |= SEARCH_THISSOLVID;
1628 di->state = di_enterrepo;
1632 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1640 di->flags &= ~SEARCH_THISSOLVID;
1641 di->state = di_enterrepo;
1645 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1647 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1651 return datamatcher_match(ma, di->kv.str);
1654 /************************************************************************
1655 * data modify functions
1658 /* extend repodata so that it includes solvables p */
1660 repodata_extend(Repodata *data, Id p)
1662 if (data->start == data->end)
1663 data->start = data->end = p;
1666 int old = data->end - data->start;
1667 int new = p - data->end + 1;
1670 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1671 memset(data->attrs + old, 0, new * sizeof(Id *));
1673 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1674 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1677 if (p < data->start)
1679 int old = data->end - data->start;
1680 int new = data->start - p;
1683 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1684 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1685 memset(data->attrs, 0, new * sizeof(Id *));
1687 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1688 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1689 memset(data->incoreoffset, 0, new * sizeof(Id));
1694 /* shrink end of repodata */
1696 repodata_shrink(Repodata *data, int end)
1700 if (data->end <= end)
1702 if (data->start >= end)
1706 for (i = 0; i < data->end - data->start; i++)
1707 sat_free(data->attrs[i]);
1708 data->attrs = sat_free(data->attrs);
1710 data->incoreoffset = sat_free(data->incoreoffset);
1711 data->start = data->end = 0;
1716 for (i = end; i < data->end; i++)
1717 sat_free(data->attrs[i - data->start]);
1718 data->attrs = sat_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1720 if (data->incoreoffset)
1721 data->incoreoffset = sat_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1725 /* extend repodata so that it includes solvables from start to start + num - 1 */
1727 repodata_extend_block(Repodata *data, Id start, Id num)
1731 if (!data->incoreoffset)
1733 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1734 data->start = start;
1735 data->end = start + num;
1738 repodata_extend(data, start);
1740 repodata_extend(data, start + num - 1);
1743 /**********************************************************************/
1746 #define REPODATA_ATTRS_BLOCK 63
1747 #define REPODATA_ATTRDATA_BLOCK 1023
1748 #define REPODATA_ATTRIDDATA_BLOCK 63
1752 repodata_new_handle(Repodata *data)
1756 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1759 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1760 data->xattrs[data->nxattrs] = 0;
1761 return -(data->nxattrs++);
1765 repodata_get_attrp(Repodata *data, Id handle)
1767 if (handle == SOLVID_META)
1771 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1776 return data->xattrs - handle;
1777 if (handle < data->start || handle >= data->end)
1778 repodata_extend(data, handle);
1780 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1781 return data->attrs + (handle - data->start);
1785 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1791 app = repodata_get_attrp(data, handle);
1796 /* Determine equality based on the name only, allows us to change
1797 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1798 for (pp = ap; *pp; pp += 2)
1799 if (data->keys[*pp].name == data->keys[keyid].name)
1812 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1822 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1826 keyid = repodata_key2id(data, key, 1);
1827 repodata_insert_keyid(data, solvid, keyid, val, 1);
1831 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1835 key.type = REPOKEY_TYPE_ID;
1837 key.storage = KEY_STORAGE_INCORE;
1838 repodata_set(data, solvid, &key, id);
1842 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1846 key.type = REPOKEY_TYPE_NUM;
1848 key.storage = KEY_STORAGE_INCORE;
1849 repodata_set(data, solvid, &key, (Id)num);
1853 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1857 if (data->localpool)
1858 id = stringpool_str2id(&data->spool, str, 1);
1860 id = str2id(data->repo->pool, str, 1);
1862 key.type = REPOKEY_TYPE_ID;
1864 key.storage = KEY_STORAGE_INCORE;
1865 repodata_set(data, solvid, &key, id);
1869 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1873 key.type = REPOKEY_TYPE_CONSTANT;
1874 key.size = constant;
1875 key.storage = KEY_STORAGE_INCORE;
1876 repodata_set(data, solvid, &key, 0);
1880 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1884 key.type = REPOKEY_TYPE_CONSTANTID;
1886 key.storage = KEY_STORAGE_INCORE;
1887 repodata_set(data, solvid, &key, 0);
1891 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1895 key.type = REPOKEY_TYPE_VOID;
1897 key.storage = KEY_STORAGE_INCORE;
1898 repodata_set(data, solvid, &key, 0);
1902 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1907 l = strlen(str) + 1;
1909 key.type = REPOKEY_TYPE_STR;
1911 key.storage = KEY_STORAGE_INCORE;
1912 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1913 memcpy(data->attrdata + data->attrdatalen, str, l);
1914 repodata_set(data, solvid, &key, data->attrdatalen);
1915 data->attrdatalen += l;
1918 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1919 * so that the caller can append the new element there */
1921 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1924 Id *ida, *pp, **ppp;
1926 /* check if it is the same as last time, this speeds things up a lot */
1927 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1929 /* great! just append the new data */
1930 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1931 data->attriddatalen--; /* overwrite terminating 0 */
1932 data->lastdatalen += entrysize;
1936 ppp = repodata_get_attrp(data, handle);
1939 for (; *pp; pp += 2)
1940 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1944 /* not found. allocate new key */
1949 key.storage = KEY_STORAGE_INCORE;
1950 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1951 repodata_set(data, handle, &key, data->attriddatalen);
1952 data->lasthandle = 0; /* next time... */
1956 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1957 oldsize += entrysize;
1958 if (ida + 1 == data->attriddata + data->attriddatalen)
1960 /* this was the last entry, just append it */
1961 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1962 data->attriddatalen--; /* overwrite terminating 0 */
1966 /* too bad. move to back. */
1967 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1968 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1969 pp[1] = data->attriddatalen;
1970 data->attriddatalen += oldsize;
1972 data->lasthandle = handle;
1973 data->lastkey = *pp;
1974 data->lastdatalen = data->attriddatalen + entrysize + 1;
1978 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1979 const unsigned char *str)
1984 if (!(l = sat_chksum_len(type)))
1989 key.storage = KEY_STORAGE_INCORE;
1990 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1991 memcpy(data->attrdata + data->attrdatalen, str, l);
1992 repodata_set(data, solvid, &key, data->attrdatalen);
1993 data->attrdatalen += l;
1997 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
2000 for (i = 0; i < buflen; i++)
2002 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
2003 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
2004 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
2015 buf[i] = (buf[i] << 4) | v;
2022 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2025 unsigned char buf[64];
2028 if (!(l = sat_chksum_len(type)))
2030 if (hexstr2bytes(buf, str, l) != l)
2032 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2036 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2041 if (!(l = sat_chksum_len(type)))
2043 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2044 for (i = 0; i < l; i++)
2046 unsigned char v = buf[i];
2047 unsigned char w = v >> 4;
2048 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2050 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2056 /* rpm filenames don't contain the epoch, so strip it */
2057 static inline const char *
2058 evrid2vrstr(Pool *pool, Id evrid)
2060 const char *p, *evr = id2str(pool, evrid);
2063 for (p = evr; *p >= '0' && *p <= '9'; p++)
2065 return p != evr && *p == ':' ? p + 1 : evr;
2069 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2071 Pool *pool = data->repo->pool;
2073 const char *str, *fp;
2077 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2080 if ((dir = strrchr(file, '/')) != 0)
2091 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2096 if (l == 1 && dir[0] == '.')
2098 s = pool->solvables + solvid;
2101 str = id2str(pool, s->arch);
2102 if (!strncmp(dir, str, l) && !str[l])
2103 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2105 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
2108 char *dir2 = strdup(dir);
2110 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
2115 str = id2str(pool, s->name);
2117 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2120 str = evrid2vrstr(pool, s->evr);
2122 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2125 str = id2str(pool, s->arch);
2127 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2129 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2134 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2138 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2142 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2144 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2145 data->attriddata[data->attriddatalen++] = dir;
2146 data->attriddata[data->attriddatalen++] = num;
2147 data->attriddata[data->attriddatalen++] = num2;
2148 data->attriddata[data->attriddatalen++] = 0;
2152 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2158 l = strlen(str) + 1;
2159 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2160 memcpy(data->attrdata + data->attrdatalen, str, l);
2161 stroff = data->attrdatalen;
2162 data->attrdatalen += l;
2165 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2167 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2168 data->attriddata[data->attriddatalen++] = dir;
2169 data->attriddata[data->attriddatalen++] = stroff;
2170 data->attriddata[data->attriddatalen++] = 0;
2174 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2177 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2179 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2180 data->attriddata[data->attriddatalen++] = id;
2181 data->attriddata[data->attriddatalen++] = 0;
2185 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2189 if (data->localpool)
2190 id = stringpool_str2id(&data->spool, str, 1);
2192 id = str2id(data->repo->pool, str, 1);
2193 repodata_add_idarray(data, solvid, keyname, id);
2197 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2199 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2200 data->attriddata[data->attriddatalen++] = ghandle;
2201 data->attriddata[data->attriddatalen++] = 0;
2205 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2207 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2208 data->attriddata[data->attriddatalen++] = ghandle;
2209 data->attriddata[data->attriddatalen++] = 0;
2212 /* add all attrs from src to dest */
2214 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2217 if (dest == src || !(keyp = data->attrs[src - data->start]))
2219 for (; *keyp; keyp += 2)
2220 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2224 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2227 if (dest == src || !(keyp = data->attrs[src - data->start]))
2229 for (; *keyp; keyp += 2)
2230 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2231 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2236 /**********************************************************************/
2238 /* TODO: unify with repo_write! */
2240 #define EXTDATA_BLOCK 1023
2248 data_addid(struct extdata *xd, Id x)
2251 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2252 dp = xd->buf + xd->len;
2257 *dp++ = (x >> 28) | 128;
2259 *dp++ = (x >> 21) | 128;
2260 *dp++ = (x >> 14) | 128;
2263 *dp++ = (x >> 7) | 128;
2265 xd->len = dp - xd->buf;
2269 data_addideof(struct extdata *xd, Id x, int eof)
2272 x = (x & 63) | ((x & ~63) << 1);
2273 data_addid(xd, (eof ? x: x | 64));
2277 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2279 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2280 memcpy(xd->buf + xd->len, blob, len);
2284 /*********************************/
2287 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2288 struct extdata *newvincore,
2290 Repokey *key, Id val)
2292 /* Otherwise we have a new value. Parse it into the internal
2296 unsigned int oldvincorelen = 0;
2300 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2303 oldvincorelen = xd->len;
2307 case REPOKEY_TYPE_VOID:
2308 case REPOKEY_TYPE_CONSTANT:
2309 case REPOKEY_TYPE_CONSTANTID:
2311 case REPOKEY_TYPE_STR:
2312 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2314 case REPOKEY_TYPE_MD5:
2315 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2317 case REPOKEY_TYPE_SHA1:
2318 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2320 case REPOKEY_TYPE_SHA256:
2321 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2323 case REPOKEY_TYPE_ID:
2324 case REPOKEY_TYPE_NUM:
2325 case REPOKEY_TYPE_DIR:
2326 data_addid(xd, val);
2328 case REPOKEY_TYPE_IDARRAY:
2329 for (ida = data->attriddata + val; *ida; ida++)
2330 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2332 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2333 for (ida = data->attriddata + val; *ida; ida += 3)
2335 data_addid(xd, ida[0]);
2336 data_addid(xd, ida[1]);
2337 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2340 case REPOKEY_TYPE_DIRSTRARRAY:
2341 for (ida = data->attriddata + val; *ida; ida += 2)
2343 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2344 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2347 case REPOKEY_TYPE_FIXARRAY:
2351 for (ida = data->attriddata + val; *ida; ida++)
2354 fprintf(stderr, "serialize struct %d\n", *ida);
2357 Id *kp = data->xattrs[-*ida];
2364 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2370 schemaid = repodata_schema2id(data, schema, 1);
2371 else if (schemaid != repodata_schema2id(data, schema, 0))
2373 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2377 fprintf(stderr, " schema %d\n", schemaid);
2382 data_addid(xd, num);
2383 data_addid(xd, schemaid);
2384 for (ida = data->attriddata + val; *ida; ida++)
2386 Id *kp = data->xattrs[-*ida];
2391 repodata_serialize_key(data, newincore, newvincore,
2392 schema, data->keys + *kp, kp[1]);
2397 case REPOKEY_TYPE_FLEXARRAY:
2400 for (ida = data->attriddata + val; *ida; ida++)
2402 data_addid(xd, num);
2403 for (ida = data->attriddata + val; *ida; ida++)
2405 Id *kp = data->xattrs[-*ida];
2408 data_addid(xd, 0); /* XXX */
2415 schemaid = repodata_schema2id(data, schema, 1);
2416 data_addid(xd, schemaid);
2417 kp = data->xattrs[-*ida];
2420 repodata_serialize_key(data, newincore, newvincore,
2421 schema, data->keys + *kp, kp[1]);
2427 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2430 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2432 /* put offset/len in incore */
2433 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2434 oldvincorelen = xd->len - oldvincorelen;
2435 data_addid(newincore, oldvincorelen);
2440 repodata_internalize(Repodata *data)
2442 Repokey *key, solvkey;
2444 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2445 unsigned char *dp, *ndp;
2446 int newschema, oldcount;
2447 struct extdata newincore;
2448 struct extdata newvincore;
2451 if (!data->attrs && !data->xattrs)
2454 newvincore.buf = data->vincore;
2455 newvincore.len = data->vincorelen;
2457 /* find the solvables key, create if needed */
2458 memset(&solvkey, 0, sizeof(solvkey));
2459 solvkey.name = REPOSITORY_SOLVABLES;
2460 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2462 solvkey.storage = KEY_STORAGE_INCORE;
2463 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2465 schema = sat_malloc2(data->nkeys, sizeof(Id));
2466 seen = sat_malloc2(data->nkeys, sizeof(Id));
2468 /* Merge the data already existing (in data->schemata, ->incoredata and
2469 friends) with the new attributes in data->attrs[]. */
2470 nentry = data->end - data->start;
2471 memset(&newincore, 0, sizeof(newincore));
2472 data_addid(&newincore, 0); /* start data at offset 1 */
2474 data->mainschema = 0;
2475 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2477 /* join entry data */
2478 /* we start with the meta data, entry -1 */
2479 for (entry = -1; entry < nentry; entry++)
2481 memset(seen, 0, data->nkeys * sizeof(Id));
2483 dp = data->incoredata;
2486 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2487 dp = data_read_id(dp, &oldschema);
2490 fprintf(stderr, "oldschema %d\n", oldschema);
2491 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2492 fprintf(stderr, "schemadata %p\n", data->schemadata);
2494 /* seen: -1: old data 0: skipped >0: id + 1 */
2498 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2502 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2510 keyp = data->attrs ? data->attrs[entry] : 0;
2513 /* strip solvables key */
2515 for (sp = keyp = schema; *sp; sp++)
2516 if (*sp != solvkeyid)
2521 seen[solvkeyid] = 0;
2522 keyp = data->xattrs ? data->xattrs[1] : 0;
2525 for (; *keyp; keyp += 2)
2532 seen[*keyp] = keyp[1] + 1;
2534 if (entry < 0 && data->end != data->start)
2541 /* Ideally we'd like to sort the new schema here, to ensure
2542 schema equality independend of the ordering. We can't do that
2543 yet. For once see below (old ids need to come before new ids).
2544 An additional difficulty is that we also need to move
2545 the values with the keys. */
2546 schemaid = repodata_schema2id(data, schema, 1);
2548 schemaid = oldschema;
2551 /* Now create data blob. We walk through the (possibly new) schema
2552 and either copy over old data, or insert the new. */
2553 /* XXX Here we rely on the fact that the (new) schema has the form
2554 o1 o2 o3 o4 ... | n1 n2 n3 ...
2555 (oX being the old keyids (possibly overwritten), and nX being
2556 the new keyids). This rules out sorting the keyids in order
2557 to ensure a small schema count. */
2559 data->incoreoffset[entry] = newincore.len;
2560 data_addid(&newincore, schemaid);
2563 data->mainschema = schemaid;
2564 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2566 keypstart = data->schemadata + data->schemata[schemaid];
2567 for (keyp = keypstart; *keyp; keyp++)
2570 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2571 if (*keyp == solvkeyid)
2573 /* add flexarray entry count */
2574 data_addid(&newincore, data->end - data->start);
2577 key = data->keys + *keyp;
2579 fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2584 /* Skip the data associated with this old key. */
2585 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2587 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2588 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2590 else if (key->storage == KEY_STORAGE_INCORE)
2591 ndp = data_skip_key(data, dp, key);
2594 if (seen[*keyp] == -1)
2596 /* If this key was an old one _and_ was not overwritten with
2597 a different value copy over the old value (we skipped it
2600 data_addblob(&newincore, dp, ndp - dp);
2603 else if (seen[*keyp])
2605 /* Otherwise we have a new value. Parse it into the internal
2607 repodata_serialize_key(data, &newincore, &newvincore,
2608 schema, key, seen[*keyp] - 1);
2612 if (entry >= 0 && data->attrs && data->attrs[entry])
2613 data->attrs[entry] = sat_free(data->attrs[entry]);
2615 /* free all xattrs */
2616 for (entry = 0; entry < data->nxattrs; entry++)
2617 if (data->xattrs[entry])
2618 sat_free(data->xattrs[entry]);
2619 data->xattrs = sat_free(data->xattrs);
2622 data->lasthandle = 0;
2624 data->lastdatalen = 0;
2627 repodata_free_schemahash(data);
2629 sat_free(data->incoredata);
2630 data->incoredata = newincore.buf;
2631 data->incoredatalen = newincore.len;
2632 data->incoredatafree = 0;
2634 sat_free(data->vincore);
2635 data->vincore = newvincore.buf;
2636 data->vincorelen = newvincore.len;
2638 data->attrs = sat_free(data->attrs);
2639 data->attrdata = sat_free(data->attrdata);
2640 data->attriddata = sat_free(data->attriddata);
2641 data->attrdatalen = 0;
2642 data->attriddatalen = 0;
2646 repodata_disable_paging(Repodata *data)
2648 if (maybe_load_repodata(data, 0))
2649 repopagestore_disable_paging(&data->store);
2653 repodata_load_stub(Repodata *data)
2655 Repo *repo = data->repo;
2656 Pool *pool = repo->pool;
2659 if (!pool->loadcallback)
2661 data->state = REPODATA_ERROR;
2664 data->state = REPODATA_LOADING;
2665 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
2667 data->state = REPODATA_ERROR;
2671 repodata_create_stubs(Repodata *data)
2673 Repo *repo = data->repo;
2674 Pool *pool = repo->pool;
2681 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2682 while (dataiterator_step(&di))
2684 dataiterator_free(&di);
2687 stubdataids = sat_calloc(cnt, sizeof(*stubdataids));
2688 for (i = 0; i < cnt; i++)
2690 sdata = repo_add_repodata(repo, 0);
2691 if (data->end > data->start)
2693 repodata_extend(sdata, data->start);
2694 repodata_extend(sdata, data->end - 1);
2696 stubdataids[i] = sdata - repo->repodata;
2697 sdata->state = REPODATA_STUB;
2698 sdata->loadcallback = repodata_load_stub;
2701 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2703 while (dataiterator_step(&di))
2705 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
2707 dataiterator_entersub(&di);
2708 sdata = repo->repodata + stubdataids[i++];
2712 switch (di.key->type)
2714 case REPOKEY_TYPE_ID:
2715 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
2717 case REPOKEY_TYPE_CONSTANTID:
2718 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
2720 case REPOKEY_TYPE_STR:
2721 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
2723 case REPOKEY_TYPE_VOID:
2724 repodata_set_void(sdata, SOLVID_META, di.key->name);
2726 case REPOKEY_TYPE_NUM:
2727 repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
2729 case REPOKEY_TYPE_MD5:
2730 case REPOKEY_TYPE_SHA1:
2731 case REPOKEY_TYPE_SHA256:
2732 repodata_set_checksum(sdata, SOLVID_META, di.key->name, di.key->type, di.kv.str);
2734 case REPOKEY_TYPE_IDARRAY:
2735 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
2736 if (di.key->name == REPOSITORY_KEYS)
2743 xkeyname = di.kv.id;
2746 xkey.name = xkeyname;
2747 xkey.type = di.kv.id;
2748 xkey.storage = KEY_STORAGE_INCORE;
2750 repodata_key2id(sdata, &xkey, 1);
2755 dataiterator_free(&di);
2756 for (i = 0; i < cnt; i++)
2757 repodata_internalize(repo->repodata + stubdataids[i]);
2758 sat_free(stubdataids);
2762 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: