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))
1018 di_nextarrayelement,
1023 di_nextsolvableattr,
1028 /* see repo.h for documentation */
1030 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1032 memset(di, 0, sizeof(*di));
1034 di->flags = flags & ~SEARCH_THISSOLVID;
1035 if (!pool || (repo && repo->pool != pool))
1043 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1049 di->keyname = keyname;
1050 di->keynames[0] = keyname;
1051 dataiterator_set_search(di, repo, p);
1056 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1059 memset(&di->matcher, 0, sizeof(di->matcher));
1060 if (from->matcher.match)
1061 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1066 for (i = 1; i < di->nparents; i++)
1067 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1068 di->kv.parent = &di->parents[di->nparents - 1].kv;
1073 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1075 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1076 datamatcher_free(&di->matcher);
1077 memset(&di->matcher, 0, sizeof(di->matcher));
1081 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1091 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1095 di->flags &= ~SEARCH_THISSOLVID;
1099 if (!di->pool->nrepos)
1107 di->repo = di->pool->repos[0];
1109 di->state = di_enterrepo;
1111 dataiterator_jump_to_solvid(di, p);
1115 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1118 di->keyname = keyname;
1119 di->keynames[0] = keyname;
1123 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1127 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1129 di->state = di_bye; /* sorry */
1132 for (i = di->nkeynames + 1; i > 0; i--)
1133 di->keynames[i] = di->keynames[i - 1];
1134 di->keynames[0] = di->keyname = keyname;
1139 dataiterator_free(Dataiterator *di)
1141 if (di->matcher.match)
1142 datamatcher_free(&di->matcher);
1145 static inline unsigned char *
1146 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1148 Id *keyp = di->keyp;
1149 Repokey *keys = di->data->keys;
1152 for (keyp = di->keyp; *keyp; keyp++)
1153 if (keys[*keyp].name == keyname)
1157 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1165 repodata_filelistfilter_matches(Repodata *data, const char *str)
1167 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1168 /* for now hardcoded */
1169 if (strstr(str, "bin/"))
1171 if (!strncmp(str, "/etc/", 5))
1173 if (!strcmp(str, "/usr/bin/sendmail"))
1179 dataiterator_filelistcheck(Dataiterator *di)
1182 Repodata *data = di->data;
1183 if (data->state != REPODATA_AVAILABLE)
1185 if (!repodata_precheck_keyname(data, REPOSITORY_EXTERNAL))
1187 for (i = 0; i < data->nkeys; i++)
1188 if (data->keys[i].name == REPOSITORY_EXTERNAL)
1190 if (i == data->nkeys)
1192 if (!(di->matcher.flags & SEARCH_COMPLETE_FILELIST))
1194 di->repodataid = -1; /* do not look somewhere else */
1197 if (di->matcher.match && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) == SEARCH_STRING && repodata_filelistfilter_matches(di->data, di->matcher.match))
1199 di->repodataid = -1; /* do not look somewhere else */
1206 dataiterator_step(Dataiterator *di)
1214 case di_enterrepo: di_enterrepo:
1217 if (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS))
1219 if (!(di->flags & SEARCH_THISSOLVID))
1221 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1222 goto di_nextsolvable;
1226 case di_entersolvable: di_entersolvable:
1227 if (di->repodataid >= 0)
1229 di->repodataid = 0; /* reset repodata iterator */
1230 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)
1232 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1234 goto di_entersolvablekey;
1239 case di_enterrepodata: di_enterrepodata:
1240 if (di->repodataid >= 0)
1242 if (di->repodataid >= di->repo->nrepodata)
1243 goto di_nextsolvable;
1244 di->data = di->repo->repodata + di->repodataid;
1246 if (di->repodataid >= 0 && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1247 goto di_nextrepodata;
1248 if (!maybe_load_repodata(di->data, di->keyname))
1249 goto di_nextrepodata;
1250 di->dp = solvid2data(di->data, di->solvid, &schema);
1252 goto di_nextrepodata;
1253 if (di->solvid == SOLVID_POS)
1254 di->solvid = di->pool->pos.solvid;
1255 /* reset key iterator */
1256 di->keyp = di->data->schemadata + di->data->schemata[schema];
1259 case di_enterschema: di_enterschema:
1261 di->dp = dataiterator_find_keyname(di, di->keyname);
1262 if (!di->dp || !*di->keyp)
1266 goto di_nextrepodata;
1270 case di_enterkey: di_enterkey:
1272 di->key = di->data->keys + *di->keyp;
1273 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1276 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1278 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1284 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1286 di->state = di_nextkey;
1288 di->state = di_nextattr;
1291 case di_nextkey: di_nextkey:
1292 if (!di->keyname && *++di->keyp)
1298 case di_nextrepodata: di_nextrepodata:
1299 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1300 goto di_enterrepodata;
1303 case di_nextsolvable: di_nextsolvable:
1304 if (!(di->flags & SEARCH_THISSOLVID))
1307 di->solvid = di->repo->start;
1310 for (; di->solvid < di->repo->end; di->solvid++)
1312 if (di->pool->solvables[di->solvid].repo == di->repo)
1313 goto di_entersolvable;
1318 case di_nextrepo: di_nextrepo:
1319 if (di->repoid >= 0)
1323 if (di->repoid < di->pool->nrepos)
1325 di->repo = di->pool->repos[di->repoid];
1331 case di_bye: di_bye:
1335 case di_enterarray: di_enterarray:
1336 if (di->key->name == REPOSITORY_SOLVABLES)
1338 di->ddp = data_read_id(di->ddp, &di->kv.num);
1343 case di_nextarrayelement: di_nextarrayelement:
1346 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1347 if (di->kv.entry == di->kv.num)
1349 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1351 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1353 di->kv.str = (char *)di->ddp;
1355 di->state = di_nextkey;
1358 if (di->kv.entry == di->kv.num - 1)
1360 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1361 di->ddp = data_read_id(di->ddp, &di->kv.id);
1362 di->kv.str = (char *)di->ddp;
1363 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1365 if ((di->flags & SEARCH_SUB) != 0)
1366 di->state = di_entersub;
1368 di->state = di_nextarrayelement;
1371 case di_entersub: di_entersub:
1372 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1373 goto di_nextarrayelement; /* sorry, full */
1374 di->parents[di->nparents].kv = di->kv;
1375 di->parents[di->nparents].dp = di->dp;
1376 di->parents[di->nparents].keyp = di->keyp;
1377 di->dp = (unsigned char *)di->kv.str;
1378 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1379 memset(&di->kv, 0, sizeof(di->kv));
1380 di->kv.parent = &di->parents[di->nparents].kv;
1382 di->keyname = di->keynames[di->nparents - di->rootlevel];
1383 goto di_enterschema;
1385 case di_leavesub: di_leavesub:
1386 if (di->nparents - 1 < di->rootlevel)
1389 di->dp = di->parents[di->nparents].dp;
1390 di->kv = di->parents[di->nparents].kv;
1391 di->keyp = di->parents[di->nparents].keyp;
1392 di->key = di->data->keys + *di->keyp;
1393 di->ddp = (unsigned char *)di->kv.str;
1394 di->keyname = di->keynames[di->nparents - di->rootlevel];
1395 goto di_nextarrayelement;
1397 /* special solvable attr handling follows */
1399 case di_nextsolvableattr:
1400 di->kv.id = *di->idp++;
1405 di->state = di_nextsolvablekey;
1409 case di_nextsolvablekey: di_nextsolvablekey:
1410 if (di->keyname || di->key->name == RPM_RPMDBID)
1411 goto di_enterrepodata;
1415 case di_entersolvablekey: di_entersolvablekey:
1416 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1417 if (!di->idp || !di->idp[0])
1418 goto di_nextsolvablekey;
1419 di->kv.id = di->idp[0];
1420 di->kv.num = di->idp[0];
1422 if (!di->kv.eof && !di->idp[0])
1426 di->state = di_nextsolvablekey;
1428 di->state = di_nextsolvableattr;
1432 if (di->matcher.match)
1434 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1436 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1440 if (!datamatcher_match(&di->matcher, di->kv.str))
1443 /* found something! */
1449 dataiterator_entersub(Dataiterator *di)
1451 if (di->state == di_nextarrayelement)
1452 di->state = di_entersub;
1456 dataiterator_setpos(Dataiterator *di)
1458 if (di->kv.eof == 2)
1460 pool_clear_pos(di->pool);
1463 di->pool->pos.solvid = di->solvid;
1464 di->pool->pos.repo = di->repo;
1465 di->pool->pos.repodataid = di->data - di->repo->repodata;
1466 di->pool->pos.schema = di->kv.id;
1467 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1471 dataiterator_setpos_parent(Dataiterator *di)
1473 if (!di->kv.parent || di->kv.parent->eof == 2)
1475 pool_clear_pos(di->pool);
1478 di->pool->pos.solvid = di->solvid;
1479 di->pool->pos.repo = di->repo;
1480 di->pool->pos.repodataid = di->data - di->repo->repodata;
1481 di->pool->pos.schema = di->kv.parent->id;
1482 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1485 /* clones just the position, not the search keys/matcher */
1487 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1489 di->state = from->state;
1490 di->flags &= ~SEARCH_THISSOLVID;
1491 di->flags |= (from->flags & SEARCH_THISSOLVID);
1492 di->repo = from->repo;
1493 di->data = from->data;
1495 di->ddp = from->ddp;
1496 di->idp = from->idp;
1497 di->keyp = from->keyp;
1498 di->key = from->key;
1500 di->repodataid = from->repodataid;
1501 di->solvid = from->solvid;
1502 di->repoid = from->repoid;
1503 di->rootlevel = from->rootlevel;
1504 memcpy(di->parents, from->parents, sizeof(from->parents));
1505 di->nparents = from->nparents;
1509 for (i = 1; i < di->nparents; i++)
1510 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1511 di->kv.parent = &di->parents[di->nparents - 1].kv;
1516 dataiterator_seek(Dataiterator *di, int whence)
1518 if ((whence & DI_SEEK_STAY) != 0)
1519 di->rootlevel = di->nparents;
1520 switch (whence & ~DI_SEEK_STAY)
1523 if (di->state != di_nextarrayelement)
1525 if ((whence & DI_SEEK_STAY) != 0)
1526 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1527 di->state = di_entersub;
1529 case DI_SEEK_PARENT:
1536 if (di->rootlevel > di->nparents)
1537 di->rootlevel = di->nparents;
1538 di->dp = di->parents[di->nparents].dp;
1539 di->kv = di->parents[di->nparents].kv;
1540 di->keyp = di->parents[di->nparents].keyp;
1541 di->key = di->data->keys + *di->keyp;
1542 di->ddp = (unsigned char *)di->kv.str;
1543 di->keyname = di->keynames[di->nparents - di->rootlevel];
1544 di->state = di_nextarrayelement;
1546 case DI_SEEK_REWIND:
1552 di->dp = (unsigned char *)di->kv.parent->str;
1553 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1554 di->state = di_enterschema;
1562 dataiterator_skip_attribute(Dataiterator *di)
1564 if (di->state == di_nextsolvableattr)
1565 di->state = di_nextsolvablekey;
1567 di->state = di_nextkey;
1571 dataiterator_skip_solvable(Dataiterator *di)
1575 di->keyname = di->keynames[0];
1576 di->state = di_nextsolvable;
1580 dataiterator_skip_repo(Dataiterator *di)
1584 di->keyname = di->keynames[0];
1585 di->state = di_nextrepo;
1589 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1593 di->keyname = di->keynames[0];
1594 if (solvid == SOLVID_POS)
1596 di->repo = di->pool->pos.repo;
1603 di->data = di->repo->repodata + di->pool->pos.repodataid;
1604 di->repodataid = -1;
1605 di->solvid = solvid;
1606 di->state = di_enterrepo;
1607 di->flags |= SEARCH_THISSOLVID;
1612 di->repo = di->pool->solvables[solvid].repo;
1615 else if (di->repoid >= 0)
1617 if (!di->pool->nrepos)
1622 di->repo = di->pool->repos[0];
1626 di->solvid = solvid;
1628 di->flags |= SEARCH_THISSOLVID;
1629 di->state = di_enterrepo;
1633 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1641 di->flags &= ~SEARCH_THISSOLVID;
1642 di->state = di_enterrepo;
1646 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1648 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1652 return datamatcher_match(ma, di->kv.str);
1655 /************************************************************************
1656 * data modify functions
1659 /* extend repodata so that it includes solvables p */
1661 repodata_extend(Repodata *data, Id p)
1663 if (data->start == data->end)
1664 data->start = data->end = p;
1667 int old = data->end - data->start;
1668 int new = p - data->end + 1;
1671 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1672 memset(data->attrs + old, 0, new * sizeof(Id *));
1674 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1675 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1678 if (p < data->start)
1680 int old = data->end - data->start;
1681 int new = data->start - p;
1684 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1685 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1686 memset(data->attrs, 0, new * sizeof(Id *));
1688 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1689 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1690 memset(data->incoreoffset, 0, new * sizeof(Id));
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 /**********************************************************************/
1745 #define REPODATA_ATTRS_BLOCK 63
1746 #define REPODATA_ATTRDATA_BLOCK 1023
1747 #define REPODATA_ATTRIDDATA_BLOCK 63
1751 repodata_new_handle(Repodata *data)
1755 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1758 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1759 data->xattrs[data->nxattrs] = 0;
1760 return -(data->nxattrs++);
1764 repodata_get_attrp(Repodata *data, Id handle)
1766 if (handle == SOLVID_META)
1770 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1775 return data->xattrs - handle;
1776 if (handle < data->start || handle >= data->end)
1777 repodata_extend(data, handle);
1779 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1780 return data->attrs + (handle - data->start);
1784 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1790 app = repodata_get_attrp(data, handle);
1795 for (pp = ap; *pp; pp += 2)
1796 /* Determine equality based on the name only, allows us to change
1797 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1798 if (data->keys[*pp].name == data->keys[keyid].name)
1811 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1821 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1825 keyid = repodata_key2id(data, key, 1);
1826 repodata_insert_keyid(data, solvid, keyid, val, 1);
1830 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1834 key.type = REPOKEY_TYPE_ID;
1836 key.storage = KEY_STORAGE_INCORE;
1837 repodata_set(data, solvid, &key, id);
1841 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1845 key.type = REPOKEY_TYPE_NUM;
1847 key.storage = KEY_STORAGE_INCORE;
1848 repodata_set(data, solvid, &key, (Id)num);
1852 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1856 if (data->localpool)
1857 id = stringpool_str2id(&data->spool, str, 1);
1859 id = str2id(data->repo->pool, str, 1);
1861 key.type = REPOKEY_TYPE_ID;
1863 key.storage = KEY_STORAGE_INCORE;
1864 repodata_set(data, solvid, &key, id);
1868 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1872 key.type = REPOKEY_TYPE_CONSTANT;
1873 key.size = constant;
1874 key.storage = KEY_STORAGE_INCORE;
1875 repodata_set(data, solvid, &key, 0);
1879 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1883 key.type = REPOKEY_TYPE_CONSTANTID;
1885 key.storage = KEY_STORAGE_INCORE;
1886 repodata_set(data, solvid, &key, 0);
1890 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1894 key.type = REPOKEY_TYPE_VOID;
1896 key.storage = KEY_STORAGE_INCORE;
1897 repodata_set(data, solvid, &key, 0);
1901 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1906 l = strlen(str) + 1;
1908 key.type = REPOKEY_TYPE_STR;
1910 key.storage = KEY_STORAGE_INCORE;
1911 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1912 memcpy(data->attrdata + data->attrdatalen, str, l);
1913 repodata_set(data, solvid, &key, data->attrdatalen);
1914 data->attrdatalen += l;
1917 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1918 * so that the caller can append the new element there */
1920 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1923 Id *ida, *pp, **ppp;
1925 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1927 /* great! just append the new data */
1928 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1929 data->attriddatalen--; /* overwrite terminating 0 */
1930 data->lastdatalen += entrysize;
1933 ppp = repodata_get_attrp(data, handle);
1936 for (; *pp; pp += 2)
1937 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1941 /* not found. allocate new key */
1946 key.storage = KEY_STORAGE_INCORE;
1947 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1948 repodata_set(data, handle, &key, data->attriddatalen);
1949 data->lasthandle = 0; /* next time... */
1953 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1954 oldsize += entrysize;
1955 if (ida + 1 == data->attriddata + data->attriddatalen)
1957 /* this was the last entry, just append it */
1958 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1959 data->attriddatalen--; /* overwrite terminating 0 */
1963 /* too bad. move to back. */
1964 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1965 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1966 pp[1] = data->attriddatalen;
1967 data->attriddatalen += oldsize;
1969 data->lasthandle = handle;
1970 data->lastkey = *pp;
1971 data->lastdatalen = data->attriddatalen + entrysize + 1;
1975 checksumtype2len(Id type)
1979 case REPOKEY_TYPE_MD5:
1981 case REPOKEY_TYPE_SHA1:
1983 case REPOKEY_TYPE_SHA256:
1984 return SIZEOF_SHA256;
1991 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1992 const unsigned char *str)
1995 int l = checksumtype2len(type);
2002 key.storage = KEY_STORAGE_INCORE;
2003 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2004 memcpy(data->attrdata + data->attrdatalen, str, l);
2005 repodata_set(data, solvid, &key, data->attrdatalen);
2006 data->attrdatalen += l;
2010 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
2013 for (i = 0; i < buflen; i++)
2015 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
2016 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
2017 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
2028 buf[i] = (buf[i] << 4) | v;
2035 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2038 unsigned char buf[64];
2039 int l = checksumtype2len(type);
2043 if (hexstr2bytes(buf, str, l) != l)
2045 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2049 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2054 l = checksumtype2len(type);
2057 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2058 for (i = 0; i < l; i++)
2060 unsigned char v = buf[i];
2061 unsigned char w = v >> 4;
2062 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2064 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2070 /* rpm filenames don't contain the epoch, so strip it */
2071 static inline const char *
2072 evrid2vrstr(Pool *pool, Id evrid)
2074 const char *p, *evr = id2str(pool, evrid);
2077 for (p = evr; *p >= '0' && *p <= '9'; p++)
2079 return p != evr && *p == ':' ? p + 1 : evr;
2083 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2085 Pool *pool = data->repo->pool;
2087 const char *str, *fp;
2091 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2094 if ((dir = strrchr(file, '/')) != 0)
2105 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2110 if (l == 1 && dir[0] == '.')
2112 s = pool->solvables + solvid;
2115 str = id2str(pool, s->arch);
2116 if (!strncmp(dir, str, l) && !str[l])
2117 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2119 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
2122 char *dir2 = strdup(dir);
2124 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
2129 str = id2str(pool, s->name);
2131 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2134 str = evrid2vrstr(pool, s->evr);
2136 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2139 str = id2str(pool, s->arch);
2141 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2143 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2148 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2152 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2156 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2158 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2159 data->attriddata[data->attriddatalen++] = dir;
2160 data->attriddata[data->attriddatalen++] = num;
2161 data->attriddata[data->attriddatalen++] = num2;
2162 data->attriddata[data->attriddatalen++] = 0;
2166 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2172 l = strlen(str) + 1;
2173 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2174 memcpy(data->attrdata + data->attrdatalen, str, l);
2175 stroff = data->attrdatalen;
2176 data->attrdatalen += l;
2179 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2181 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2182 data->attriddata[data->attriddatalen++] = dir;
2183 data->attriddata[data->attriddatalen++] = stroff;
2184 data->attriddata[data->attriddatalen++] = 0;
2188 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2191 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2193 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2194 data->attriddata[data->attriddatalen++] = id;
2195 data->attriddata[data->attriddatalen++] = 0;
2199 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2203 if (data->localpool)
2204 id = stringpool_str2id(&data->spool, str, 1);
2206 id = str2id(data->repo->pool, str, 1);
2207 repodata_add_idarray(data, solvid, keyname, id);
2211 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2213 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2214 data->attriddata[data->attriddatalen++] = ghandle;
2215 data->attriddata[data->attriddatalen++] = 0;
2219 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2221 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2222 data->attriddata[data->attriddatalen++] = ghandle;
2223 data->attriddata[data->attriddatalen++] = 0;
2226 /* add all attrs from src to dest */
2228 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2231 if (dest == src || !(keyp = data->attrs[src - data->start]))
2233 for (; *keyp; keyp += 2)
2234 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2240 /**********************************************************************/
2242 /* unify with repo_write! */
2244 #define EXTDATA_BLOCK 1023
2252 data_addid(struct extdata *xd, Id x)
2255 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2256 dp = xd->buf + xd->len;
2261 *dp++ = (x >> 28) | 128;
2263 *dp++ = (x >> 21) | 128;
2264 *dp++ = (x >> 14) | 128;
2267 *dp++ = (x >> 7) | 128;
2269 xd->len = dp - xd->buf;
2273 data_addideof(struct extdata *xd, Id x, int eof)
2276 x = (x & 63) | ((x & ~63) << 1);
2277 data_addid(xd, (eof ? x: x | 64));
2281 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2283 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2284 memcpy(xd->buf + xd->len, blob, len);
2288 /*********************************/
2291 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2292 struct extdata *newvincore,
2294 Repokey *key, Id val)
2296 /* Otherwise we have a new value. Parse it into the internal
2300 unsigned int oldvincorelen = 0;
2304 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2307 oldvincorelen = xd->len;
2311 case REPOKEY_TYPE_VOID:
2312 case REPOKEY_TYPE_CONSTANT:
2313 case REPOKEY_TYPE_CONSTANTID:
2315 case REPOKEY_TYPE_STR:
2316 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2318 case REPOKEY_TYPE_MD5:
2319 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2321 case REPOKEY_TYPE_SHA1:
2322 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2324 case REPOKEY_TYPE_SHA256:
2325 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2327 case REPOKEY_TYPE_ID:
2328 case REPOKEY_TYPE_NUM:
2329 case REPOKEY_TYPE_DIR:
2330 data_addid(xd, val);
2332 case REPOKEY_TYPE_IDARRAY:
2333 for (ida = data->attriddata + val; *ida; ida++)
2334 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2336 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2337 for (ida = data->attriddata + val; *ida; ida += 3)
2339 data_addid(xd, ida[0]);
2340 data_addid(xd, ida[1]);
2341 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2344 case REPOKEY_TYPE_DIRSTRARRAY:
2345 for (ida = data->attriddata + val; *ida; ida += 2)
2347 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2348 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2351 case REPOKEY_TYPE_FIXARRAY:
2355 for (ida = data->attriddata + val; *ida; ida++)
2358 fprintf(stderr, "serialize struct %d\n", *ida);
2361 Id *kp = data->xattrs[-*ida];
2368 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2374 schemaid = repodata_schema2id(data, schema, 1);
2375 else if (schemaid != repodata_schema2id(data, schema, 0))
2377 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2381 fprintf(stderr, " schema %d\n", schemaid);
2386 data_addid(xd, num);
2387 data_addid(xd, schemaid);
2388 for (ida = data->attriddata + val; *ida; ida++)
2390 Id *kp = data->xattrs[-*ida];
2395 repodata_serialize_key(data, newincore, newvincore,
2396 schema, data->keys + *kp, kp[1]);
2401 case REPOKEY_TYPE_FLEXARRAY:
2404 for (ida = data->attriddata + val; *ida; ida++)
2406 data_addid(xd, num);
2407 for (ida = data->attriddata + val; *ida; ida++)
2409 Id *kp = data->xattrs[-*ida];
2412 data_addid(xd, 0); /* XXX */
2419 schemaid = repodata_schema2id(data, schema, 1);
2420 data_addid(xd, schemaid);
2421 kp = data->xattrs[-*ida];
2424 repodata_serialize_key(data, newincore, newvincore,
2425 schema, data->keys + *kp, kp[1]);
2431 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2434 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2436 /* put offset/len in incore */
2437 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2438 oldvincorelen = xd->len - oldvincorelen;
2439 data_addid(newincore, oldvincorelen);
2444 repodata_internalize(Repodata *data)
2446 Repokey *key, solvkey;
2448 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2449 unsigned char *dp, *ndp;
2450 int newschema, oldcount;
2451 struct extdata newincore;
2452 struct extdata newvincore;
2455 if (!data->attrs && !data->xattrs)
2458 newvincore.buf = data->vincore;
2459 newvincore.len = data->vincorelen;
2461 /* find the solvables key, create if needed */
2462 memset(&solvkey, 0, sizeof(solvkey));
2463 solvkey.name = REPOSITORY_SOLVABLES;
2464 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2466 solvkey.storage = KEY_STORAGE_INCORE;
2467 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2469 schema = sat_malloc2(data->nkeys, sizeof(Id));
2470 seen = sat_malloc2(data->nkeys, sizeof(Id));
2472 /* Merge the data already existing (in data->schemata, ->incoredata and
2473 friends) with the new attributes in data->attrs[]. */
2474 nentry = data->end - data->start;
2475 memset(&newincore, 0, sizeof(newincore));
2476 data_addid(&newincore, 0); /* start data at offset 1 */
2478 data->mainschema = 0;
2479 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2481 /* join entry data */
2482 /* we start with the meta data, entry -1 */
2483 for (entry = -1; entry < nentry; entry++)
2485 memset(seen, 0, data->nkeys * sizeof(Id));
2487 dp = data->incoredata;
2490 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2491 dp = data_read_id(dp, &oldschema);
2494 fprintf(stderr, "oldschema %d\n", oldschema);
2495 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2496 fprintf(stderr, "schemadata %p\n", data->schemadata);
2498 /* seen: -1: old data 0: skipped >0: id + 1 */
2502 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2506 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2514 keyp = data->attrs ? data->attrs[entry] : 0;
2517 /* strip solvables key */
2519 for (sp = keyp = schema; *sp; sp++)
2520 if (*sp != solvkeyid)
2525 seen[solvkeyid] = 0;
2526 keyp = data->xattrs ? data->xattrs[1] : 0;
2529 for (; *keyp; keyp += 2)
2536 seen[*keyp] = keyp[1] + 1;
2538 if (entry < 0 && data->end != data->start)
2545 /* Ideally we'd like to sort the new schema here, to ensure
2546 schema equality independend of the ordering. We can't do that
2547 yet. For once see below (old ids need to come before new ids).
2548 An additional difficulty is that we also need to move
2549 the values with the keys. */
2550 schemaid = repodata_schema2id(data, schema, 1);
2552 schemaid = oldschema;
2555 /* Now create data blob. We walk through the (possibly new) schema
2556 and either copy over old data, or insert the new. */
2557 /* XXX Here we rely on the fact that the (new) schema has the form
2558 o1 o2 o3 o4 ... | n1 n2 n3 ...
2559 (oX being the old keyids (possibly overwritten), and nX being
2560 the new keyids). This rules out sorting the keyids in order
2561 to ensure a small schema count. */
2563 data->incoreoffset[entry] = newincore.len;
2564 data_addid(&newincore, schemaid);
2567 data->mainschema = schemaid;
2568 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2570 keypstart = data->schemadata + data->schemata[schemaid];
2571 for (keyp = keypstart; *keyp; keyp++)
2574 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2575 if (*keyp == solvkeyid)
2577 /* add flexarray entry count */
2578 data_addid(&newincore, data->end - data->start);
2581 key = data->keys + *keyp;
2583 fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2588 /* Skip the data associated with this old key. */
2589 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2591 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2592 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2594 else if (key->storage == KEY_STORAGE_INCORE)
2595 ndp = data_skip_key(data, dp, key);
2598 if (seen[*keyp] == -1)
2600 /* If this key was an old one _and_ was not overwritten with
2601 a different value copy over the old value (we skipped it
2604 data_addblob(&newincore, dp, ndp - dp);
2607 else if (seen[*keyp])
2609 /* Otherwise we have a new value. Parse it into the internal
2611 repodata_serialize_key(data, &newincore, &newvincore,
2612 schema, key, seen[*keyp] - 1);
2616 if (entry >= 0 && data->attrs && data->attrs[entry])
2617 data->attrs[entry] = sat_free(data->attrs[entry]);
2619 /* free all xattrs */
2620 for (entry = 0; entry < data->nxattrs; entry++)
2621 if (data->xattrs[entry])
2622 sat_free(data->xattrs[entry]);
2623 data->xattrs = sat_free(data->xattrs);
2626 data->lasthandle = 0;
2628 data->lastdatalen = 0;
2631 repodata_free_schemahash(data);
2633 sat_free(data->incoredata);
2634 data->incoredata = newincore.buf;
2635 data->incoredatalen = newincore.len;
2636 data->incoredatafree = 0;
2638 sat_free(data->vincore);
2639 data->vincore = newvincore.buf;
2640 data->vincorelen = newvincore.len;
2642 data->attrs = sat_free(data->attrs);
2643 data->attrdata = sat_free(data->attrdata);
2644 data->attriddata = sat_free(data->attriddata);
2645 data->attrdatalen = 0;
2646 data->attriddatalen = 0;
2650 repodata_disable_paging(Repodata *data)
2652 if (maybe_load_repodata(data, 0))
2653 repopagestore_disable_paging(&data->store);
2657 repodata_load_stub(Repodata *data)
2659 Repo *repo = data->repo;
2660 Pool *pool = repo->pool;
2663 if (!pool->loadcallback)
2665 data->state = REPODATA_ERROR;
2668 data->state = REPODATA_LOADING;
2669 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
2671 data->state = REPODATA_ERROR;
2675 repodata_create_stubs(Repodata *data)
2677 Repo *repo = data->repo;
2678 Pool *pool = repo->pool;
2685 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2686 while (dataiterator_step(&di))
2688 dataiterator_free(&di);
2691 stubdataids = sat_calloc(cnt, sizeof(*stubdataids));
2692 for (i = 0; i < cnt; i++)
2694 sdata = repo_add_repodata(repo, 0);
2695 if (data->end > data->start)
2697 repodata_extend(sdata, data->start);
2698 repodata_extend(sdata, data->end - 1);
2700 stubdataids[i] = sdata - repo->repodata;
2701 sdata->state = REPODATA_STUB;
2702 sdata->loadcallback = repodata_load_stub;
2705 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2707 while (dataiterator_step(&di))
2709 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
2711 dataiterator_entersub(&di);
2712 sdata = repo->repodata + stubdataids[i++];
2716 switch (di.key->type)
2718 case REPOKEY_TYPE_ID:
2719 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
2721 case REPOKEY_TYPE_CONSTANTID:
2722 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
2724 case REPOKEY_TYPE_STR:
2725 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
2727 case REPOKEY_TYPE_VOID:
2728 repodata_set_void(sdata, SOLVID_META, di.key->name);
2730 case REPOKEY_TYPE_NUM:
2731 repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
2733 case REPOKEY_TYPE_MD5:
2734 case REPOKEY_TYPE_SHA1:
2735 case REPOKEY_TYPE_SHA256:
2736 repodata_set_checksum(sdata, SOLVID_META, di.key->name, di.key->type, di.kv.str);
2738 case REPOKEY_TYPE_IDARRAY:
2739 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
2740 if (di.key->name == REPOSITORY_KEYS)
2747 xkeyname = di.kv.id;
2750 xkey.name = xkeyname;
2751 xkey.type = di.kv.id;
2752 xkey.storage = KEY_STORAGE_INCORE;
2754 repodata_key2id(sdata, &xkey, 1);
2759 dataiterator_free(&di);
2760 for (i = 0; i < cnt; i++)
2761 repodata_internalize(repo->repodata + stubdataids[i]);
2762 sat_free(stubdataids);
2766 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: