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);
2238 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2241 if (dest == src || !(keyp = data->attrs[src - data->start]))
2243 for (; *keyp; keyp += 2)
2244 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2245 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2250 /**********************************************************************/
2252 /* unify with repo_write! */
2254 #define EXTDATA_BLOCK 1023
2262 data_addid(struct extdata *xd, Id x)
2265 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2266 dp = xd->buf + xd->len;
2271 *dp++ = (x >> 28) | 128;
2273 *dp++ = (x >> 21) | 128;
2274 *dp++ = (x >> 14) | 128;
2277 *dp++ = (x >> 7) | 128;
2279 xd->len = dp - xd->buf;
2283 data_addideof(struct extdata *xd, Id x, int eof)
2286 x = (x & 63) | ((x & ~63) << 1);
2287 data_addid(xd, (eof ? x: x | 64));
2291 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2293 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2294 memcpy(xd->buf + xd->len, blob, len);
2298 /*********************************/
2301 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2302 struct extdata *newvincore,
2304 Repokey *key, Id val)
2306 /* Otherwise we have a new value. Parse it into the internal
2310 unsigned int oldvincorelen = 0;
2314 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2317 oldvincorelen = xd->len;
2321 case REPOKEY_TYPE_VOID:
2322 case REPOKEY_TYPE_CONSTANT:
2323 case REPOKEY_TYPE_CONSTANTID:
2325 case REPOKEY_TYPE_STR:
2326 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2328 case REPOKEY_TYPE_MD5:
2329 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2331 case REPOKEY_TYPE_SHA1:
2332 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2334 case REPOKEY_TYPE_SHA256:
2335 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2337 case REPOKEY_TYPE_ID:
2338 case REPOKEY_TYPE_NUM:
2339 case REPOKEY_TYPE_DIR:
2340 data_addid(xd, val);
2342 case REPOKEY_TYPE_IDARRAY:
2343 for (ida = data->attriddata + val; *ida; ida++)
2344 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2346 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2347 for (ida = data->attriddata + val; *ida; ida += 3)
2349 data_addid(xd, ida[0]);
2350 data_addid(xd, ida[1]);
2351 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2354 case REPOKEY_TYPE_DIRSTRARRAY:
2355 for (ida = data->attriddata + val; *ida; ida += 2)
2357 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2358 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2361 case REPOKEY_TYPE_FIXARRAY:
2365 for (ida = data->attriddata + val; *ida; ida++)
2368 fprintf(stderr, "serialize struct %d\n", *ida);
2371 Id *kp = data->xattrs[-*ida];
2378 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2384 schemaid = repodata_schema2id(data, schema, 1);
2385 else if (schemaid != repodata_schema2id(data, schema, 0))
2387 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2391 fprintf(stderr, " schema %d\n", schemaid);
2396 data_addid(xd, num);
2397 data_addid(xd, schemaid);
2398 for (ida = data->attriddata + val; *ida; ida++)
2400 Id *kp = data->xattrs[-*ida];
2405 repodata_serialize_key(data, newincore, newvincore,
2406 schema, data->keys + *kp, kp[1]);
2411 case REPOKEY_TYPE_FLEXARRAY:
2414 for (ida = data->attriddata + val; *ida; ida++)
2416 data_addid(xd, num);
2417 for (ida = data->attriddata + val; *ida; ida++)
2419 Id *kp = data->xattrs[-*ida];
2422 data_addid(xd, 0); /* XXX */
2429 schemaid = repodata_schema2id(data, schema, 1);
2430 data_addid(xd, schemaid);
2431 kp = data->xattrs[-*ida];
2434 repodata_serialize_key(data, newincore, newvincore,
2435 schema, data->keys + *kp, kp[1]);
2441 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2444 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2446 /* put offset/len in incore */
2447 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2448 oldvincorelen = xd->len - oldvincorelen;
2449 data_addid(newincore, oldvincorelen);
2454 repodata_internalize(Repodata *data)
2456 Repokey *key, solvkey;
2458 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2459 unsigned char *dp, *ndp;
2460 int newschema, oldcount;
2461 struct extdata newincore;
2462 struct extdata newvincore;
2465 if (!data->attrs && !data->xattrs)
2468 newvincore.buf = data->vincore;
2469 newvincore.len = data->vincorelen;
2471 /* find the solvables key, create if needed */
2472 memset(&solvkey, 0, sizeof(solvkey));
2473 solvkey.name = REPOSITORY_SOLVABLES;
2474 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2476 solvkey.storage = KEY_STORAGE_INCORE;
2477 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2479 schema = sat_malloc2(data->nkeys, sizeof(Id));
2480 seen = sat_malloc2(data->nkeys, sizeof(Id));
2482 /* Merge the data already existing (in data->schemata, ->incoredata and
2483 friends) with the new attributes in data->attrs[]. */
2484 nentry = data->end - data->start;
2485 memset(&newincore, 0, sizeof(newincore));
2486 data_addid(&newincore, 0); /* start data at offset 1 */
2488 data->mainschema = 0;
2489 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2491 /* join entry data */
2492 /* we start with the meta data, entry -1 */
2493 for (entry = -1; entry < nentry; entry++)
2495 memset(seen, 0, data->nkeys * sizeof(Id));
2497 dp = data->incoredata;
2500 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2501 dp = data_read_id(dp, &oldschema);
2504 fprintf(stderr, "oldschema %d\n", oldschema);
2505 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2506 fprintf(stderr, "schemadata %p\n", data->schemadata);
2508 /* seen: -1: old data 0: skipped >0: id + 1 */
2512 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2516 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2524 keyp = data->attrs ? data->attrs[entry] : 0;
2527 /* strip solvables key */
2529 for (sp = keyp = schema; *sp; sp++)
2530 if (*sp != solvkeyid)
2535 seen[solvkeyid] = 0;
2536 keyp = data->xattrs ? data->xattrs[1] : 0;
2539 for (; *keyp; keyp += 2)
2546 seen[*keyp] = keyp[1] + 1;
2548 if (entry < 0 && data->end != data->start)
2555 /* Ideally we'd like to sort the new schema here, to ensure
2556 schema equality independend of the ordering. We can't do that
2557 yet. For once see below (old ids need to come before new ids).
2558 An additional difficulty is that we also need to move
2559 the values with the keys. */
2560 schemaid = repodata_schema2id(data, schema, 1);
2562 schemaid = oldschema;
2565 /* Now create data blob. We walk through the (possibly new) schema
2566 and either copy over old data, or insert the new. */
2567 /* XXX Here we rely on the fact that the (new) schema has the form
2568 o1 o2 o3 o4 ... | n1 n2 n3 ...
2569 (oX being the old keyids (possibly overwritten), and nX being
2570 the new keyids). This rules out sorting the keyids in order
2571 to ensure a small schema count. */
2573 data->incoreoffset[entry] = newincore.len;
2574 data_addid(&newincore, schemaid);
2577 data->mainschema = schemaid;
2578 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2580 keypstart = data->schemadata + data->schemata[schemaid];
2581 for (keyp = keypstart; *keyp; keyp++)
2584 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2585 if (*keyp == solvkeyid)
2587 /* add flexarray entry count */
2588 data_addid(&newincore, data->end - data->start);
2591 key = data->keys + *keyp;
2593 fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2598 /* Skip the data associated with this old key. */
2599 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2601 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2602 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2604 else if (key->storage == KEY_STORAGE_INCORE)
2605 ndp = data_skip_key(data, dp, key);
2608 if (seen[*keyp] == -1)
2610 /* If this key was an old one _and_ was not overwritten with
2611 a different value copy over the old value (we skipped it
2614 data_addblob(&newincore, dp, ndp - dp);
2617 else if (seen[*keyp])
2619 /* Otherwise we have a new value. Parse it into the internal
2621 repodata_serialize_key(data, &newincore, &newvincore,
2622 schema, key, seen[*keyp] - 1);
2626 if (entry >= 0 && data->attrs && data->attrs[entry])
2627 data->attrs[entry] = sat_free(data->attrs[entry]);
2629 /* free all xattrs */
2630 for (entry = 0; entry < data->nxattrs; entry++)
2631 if (data->xattrs[entry])
2632 sat_free(data->xattrs[entry]);
2633 data->xattrs = sat_free(data->xattrs);
2636 data->lasthandle = 0;
2638 data->lastdatalen = 0;
2641 repodata_free_schemahash(data);
2643 sat_free(data->incoredata);
2644 data->incoredata = newincore.buf;
2645 data->incoredatalen = newincore.len;
2646 data->incoredatafree = 0;
2648 sat_free(data->vincore);
2649 data->vincore = newvincore.buf;
2650 data->vincorelen = newvincore.len;
2652 data->attrs = sat_free(data->attrs);
2653 data->attrdata = sat_free(data->attrdata);
2654 data->attriddata = sat_free(data->attriddata);
2655 data->attrdatalen = 0;
2656 data->attriddatalen = 0;
2660 repodata_disable_paging(Repodata *data)
2662 if (maybe_load_repodata(data, 0))
2663 repopagestore_disable_paging(&data->store);
2667 repodata_load_stub(Repodata *data)
2669 Repo *repo = data->repo;
2670 Pool *pool = repo->pool;
2673 if (!pool->loadcallback)
2675 data->state = REPODATA_ERROR;
2678 data->state = REPODATA_LOADING;
2679 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
2681 data->state = REPODATA_ERROR;
2685 repodata_create_stubs(Repodata *data)
2687 Repo *repo = data->repo;
2688 Pool *pool = repo->pool;
2695 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2696 while (dataiterator_step(&di))
2698 dataiterator_free(&di);
2701 stubdataids = sat_calloc(cnt, sizeof(*stubdataids));
2702 for (i = 0; i < cnt; i++)
2704 sdata = repo_add_repodata(repo, 0);
2705 if (data->end > data->start)
2707 repodata_extend(sdata, data->start);
2708 repodata_extend(sdata, data->end - 1);
2710 stubdataids[i] = sdata - repo->repodata;
2711 sdata->state = REPODATA_STUB;
2712 sdata->loadcallback = repodata_load_stub;
2715 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2717 while (dataiterator_step(&di))
2719 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
2721 dataiterator_entersub(&di);
2722 sdata = repo->repodata + stubdataids[i++];
2726 switch (di.key->type)
2728 case REPOKEY_TYPE_ID:
2729 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
2731 case REPOKEY_TYPE_CONSTANTID:
2732 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
2734 case REPOKEY_TYPE_STR:
2735 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
2737 case REPOKEY_TYPE_VOID:
2738 repodata_set_void(sdata, SOLVID_META, di.key->name);
2740 case REPOKEY_TYPE_NUM:
2741 repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
2743 case REPOKEY_TYPE_MD5:
2744 case REPOKEY_TYPE_SHA1:
2745 case REPOKEY_TYPE_SHA256:
2746 repodata_set_checksum(sdata, SOLVID_META, di.key->name, di.key->type, di.kv.str);
2748 case REPOKEY_TYPE_IDARRAY:
2749 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
2750 if (di.key->name == REPOSITORY_KEYS)
2757 xkeyname = di.kv.id;
2760 xkey.name = xkeyname;
2761 xkey.type = di.kv.id;
2762 xkey.storage = KEY_STORAGE_INCORE;
2764 repodata_key2id(sdata, &xkey, 1);
2769 dataiterator_free(&di);
2770 for (i = 0; i < cnt; i++)
2771 repodata_internalize(repo->repodata + stubdataids[i]);
2772 sat_free(stubdataids);
2776 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: