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"
35 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
36 unsigned char *out, unsigned int out_len);
37 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
40 unsigned int out_len);
42 #define REPODATA_BLOCK 255
46 repodata_initdata(Repodata *data, Repo *repo, int localpool)
48 memset(data, 0, sizeof (*data));
50 data->localpool = localpool;
52 stringpool_init_empty(&data->spool);
53 data->keys = sat_calloc(1, sizeof(Repokey));
55 data->schemata = sat_calloc(1, sizeof(Id));
56 data->schemadata = sat_calloc(1, sizeof(Id));
58 data->schemadatalen = 1;
59 repopagestore_init(&data->store);
63 repodata_freedata(Repodata *data)
69 sat_free(data->schemata);
70 sat_free(data->schemadata);
71 sat_free(data->schematahash);
73 stringpool_free(&data->spool);
74 dirpool_free(&data->dirpool);
76 sat_free(data->mainschemaoffsets);
77 sat_free(data->incoredata);
78 sat_free(data->incoreoffset);
79 sat_free(data->verticaloffset);
81 repopagestore_free(&data->store);
83 sat_free(data->vincore);
86 for (i = 0; i < data->end - data->start; i++)
87 sat_free(data->attrs[i]);
88 sat_free(data->attrs);
90 for (i = 0; i < data->nxattrs; i++)
91 sat_free(data->xattrs[i]);
92 sat_free(data->xattrs);
94 sat_free(data->attrdata);
95 sat_free(data->attriddata);
99 repodata_free(Repodata *data)
101 Repo *repo = data->repo;
102 int i = data - repo->repodata;
103 repodata_freedata(data);
104 if (i < repo->nrepodata - 1)
105 memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
110 /***************************************************************
111 * key pool management
114 /* this is not so time critical that we need a hash, so we do a simple
117 repodata_key2id(Repodata *data, Repokey *key, int create)
121 for (keyid = 1; keyid < data->nkeys; keyid++)
122 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
124 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
128 if (keyid == data->nkeys)
132 /* allocate new key */
133 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
134 data->keys[data->nkeys++] = *key;
135 if (data->verticaloffset)
137 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
138 data->verticaloffset[data->nkeys - 1] = 0;
140 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
146 /***************************************************************
147 * schema pool management
150 #define SCHEMATA_BLOCK 31
151 #define SCHEMATADATA_BLOCK 255
154 repodata_schema2id(Repodata *data, Id *schema, int create)
160 if ((schematahash = data->schematahash) == 0)
162 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
163 for (i = 0; i < data->nschemata; i++)
165 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
168 schematahash[h] = i + 1;
170 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
171 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
174 for (sp = schema, len = 0, h = 0; *sp; len++)
179 cid = schematahash[h];
183 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
186 for (cid = 0; cid < data->nschemata; cid++)
187 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
193 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
194 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
196 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
197 data->schemata[data->nschemata] = data->schemadatalen;
198 data->schemadatalen += len;
199 schematahash[h] = data->nschemata + 1;
201 fprintf(stderr, "schema2id: new schema\n");
203 return data->nschemata++;
207 repodata_free_schemahash(Repodata *data)
209 data->schematahash = sat_free(data->schematahash);
211 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
212 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
216 /***************************************************************
217 * dir pool management
221 repodata_str2dir(Repodata *data, const char *dir, int create)
227 while (*dir == '/' && dir[1] == '/')
229 if (*dir == '/' && !dir[1])
233 dire = strchrnul(dir, '/');
235 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
237 id = strn2id(data->repo->pool, dir, dire - dir, create);
240 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
253 repodata_dir2str(Repodata *data, Id did, const char *suf)
255 Pool *pool = data->repo->pool;
262 return suf ? suf : "";
266 comp = dirpool_compid(&data->dirpool, parent);
267 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
269 parent = dirpool_parent(&data->dirpool, parent);
274 l += strlen(suf) + 1;
275 p = pool_alloctmpspace(pool, l + 1) + l;
286 comp = dirpool_compid(&data->dirpool, parent);
287 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
290 strncpy(p, comps, l);
291 parent = dirpool_parent(&data->dirpool, parent);
299 /***************************************************************
303 static inline unsigned char *
304 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
306 Id *keyp = data->schemadata + data->schemata[schema];
307 for (; *keyp; keyp++)
308 dp = data_skip_key(data, dp, data->keys + *keyp);
313 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
315 int nentries, schema;
318 case REPOKEY_TYPE_FIXARRAY:
319 dp = data_read_id(dp, &nentries);
322 dp = data_read_id(dp, &schema);
324 dp = data_skip_schema(data, dp, schema);
326 case REPOKEY_TYPE_FLEXARRAY:
327 dp = data_read_id(dp, &nentries);
330 dp = data_read_id(dp, &schema);
331 dp = data_skip_schema(data, dp, schema);
335 if (key->storage == KEY_STORAGE_INCORE)
336 dp = data_skip(dp, key->type);
337 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
339 dp = data_skip(dp, REPOKEY_TYPE_ID);
340 dp = data_skip(dp, REPOKEY_TYPE_ID);
346 static unsigned char *
347 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
353 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
356 for (i = 0; (k = *keyp++) != 0; i++)
358 return data->incoredata + data->mainschemaoffsets[i];
361 while ((k = *keyp++) != 0)
365 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
367 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
368 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
371 if (data->keys[k].storage != KEY_STORAGE_INCORE)
373 dp = data_skip_key(data, dp, data->keys + k);
378 static unsigned char *
379 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
384 if (off >= data->lastverticaloffset)
386 off -= data->lastverticaloffset;
387 if (off + len > data->vincorelen)
389 return data->vincore + off;
391 if (off + len > key->size)
393 /* we now have the offset, go into vertical */
394 off += data->verticaloffset[key - data->keys];
395 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
396 dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
398 dp += off % BLOB_PAGESIZE;
402 static inline unsigned char *
403 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
405 unsigned char *dp = *dpp;
409 if (key->storage == KEY_STORAGE_INCORE)
412 *dpp = data_skip_key(data, dp, key);
415 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
418 dp = data_read_id(dp, &off);
419 dp = data_read_id(dp, &len);
422 return get_vertical_data(data, key, off, len);
428 load_repodata(Repodata *data)
430 if (data->loadcallback)
432 data->loadcallback(data);
433 if (data->state == REPODATA_AVAILABLE)
436 data->state = REPODATA_ERROR;
441 maybe_load_repodata(Repodata *data, Id keyname)
443 if (keyname && !repodata_precheck_keyname(data, keyname))
444 return 0; /* do not bother... */
451 for (i = 0; i < data->nkeys; i++)
452 if (keyname == data->keys[i].name)
454 if (i == data->nkeys)
457 return load_repodata(data);
460 case REPODATA_AVAILABLE:
463 data->state = REPODATA_ERROR;
468 static inline unsigned char *
469 solvid2data(Repodata *data, Id solvid, Id *schemap)
471 unsigned char *dp = data->incoredata;
474 if (solvid == SOLVID_META) /* META */
476 else if (solvid == SOLVID_POS) /* META */
478 Pool *pool = data->repo->pool;
479 if (data->repo != pool->pos.repo)
481 if (data != data->repo->repodata + pool->pos.repodataid)
483 *schemap = pool->pos.schema;
484 return data->incoredata + pool->pos.dp;
488 if (solvid < data->start || solvid >= data->end)
490 dp += data->incoreoffset[solvid - data->start];
492 return data_read_id(dp, schemap);
495 /************************************************************************
499 static inline unsigned char *
500 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
503 Id schema, *keyp, *kp;
506 if (!maybe_load_repodata(data, keyname))
508 dp = solvid2data(data, solvid, &schema);
511 keyp = data->schemadata + data->schemata[schema];
512 for (kp = keyp; *kp; kp++)
513 if (data->keys[*kp].name == keyname)
517 *keypp = key = data->keys + *kp;
518 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
519 return dp; /* no need to forward... */
520 dp = forward_to_key(data, *kp, keyp, dp);
523 return get_data(data, key, &dp, 0);
528 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
534 dp = find_key_data(data, solvid, keyname, &key);
537 if (key->type == REPOKEY_TYPE_CONSTANTID)
539 if (key->type != REPOKEY_TYPE_ID)
541 dp = data_read_id(dp, &id);
546 repodata_globalize_id(Repodata *data, Id id, int create)
548 if (!id || !data || !data->localpool)
550 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
554 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
560 dp = find_key_data(data, solvid, keyname, &key);
563 if (key->type == REPOKEY_TYPE_STR)
564 return (const char *)dp;
565 if (key->type == REPOKEY_TYPE_CONSTANTID)
566 return id2str(data->repo->pool, key->size);
567 if (key->type == REPOKEY_TYPE_ID)
568 dp = data_read_id(dp, &id);
572 return data->spool.stringspace + data->spool.strings[id];
573 return id2str(data->repo->pool, id);
577 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
584 dp = find_key_data(data, solvid, keyname, &key);
587 if (key->type == REPOKEY_TYPE_NUM
588 || key->type == REPOKEY_TYPE_U32
589 || key->type == REPOKEY_TYPE_CONSTANT)
591 dp = data_fetch(dp, &kv, key);
599 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
605 if (!maybe_load_repodata(data, keyname))
607 dp = solvid2data(data, solvid, &schema);
610 /* can't use find_key_data as we need to test the type */
611 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
612 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
617 const unsigned char *
618 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
623 dp = find_key_data(data, solvid, keyname, &key);
631 /************************************************************************
637 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
641 case REPOKEY_TYPE_ID:
642 case REPOKEY_TYPE_CONSTANTID:
643 case REPOKEY_TYPE_IDARRAY:
644 if (data && data->localpool)
645 kv->str = stringpool_id2str(&data->spool, kv->id);
647 kv->str = id2str(pool, kv->id);
648 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
651 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
653 if (*s == ':' && s > kv->str)
657 case REPOKEY_TYPE_STR:
659 case REPOKEY_TYPE_DIRSTRARRAY:
660 if (!(flags & SEARCH_FILES))
661 return 1; /* match just the basename */
662 /* Put the full filename into kv->str. */
663 kv->str = repodata_dir2str(data, kv->id, kv->str);
664 /* And to compensate for that put the "empty" directory into
665 kv->id, so that later calls to repodata_dir2str on this data
666 come up with the same filename again. */
669 case REPOKEY_TYPE_MD5:
670 case REPOKEY_TYPE_SHA1:
671 case REPOKEY_TYPE_SHA256:
672 if (!(flags & SEARCH_CHECKSUMS))
673 return 0; /* skip em */
674 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
682 struct subschema_data {
688 /* search a specific repodata */
690 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
694 Id keyid, *kp, *keyp;
695 unsigned char *dp, *ddp;
701 if (!maybe_load_repodata(data, keyname))
703 if (solvid == SOLVID_SUBSCHEMA)
705 struct subschema_data *subd = cbdata;
706 cbdata = subd->cbdata;
708 schema = subd->parent->id;
709 dp = (unsigned char *)subd->parent->str;
710 kv.parent = subd->parent;
715 dp = solvid2data(data, solvid, &schema);
718 s = data->repo->pool->solvables + solvid;
721 keyp = data->schemadata + data->schemata[schema];
724 /* search for a specific key */
725 for (kp = keyp; *kp; kp++)
726 if (data->keys[*kp].name == keyname)
730 dp = forward_to_key(data, *kp, keyp, dp);
736 while ((keyid = *keyp++) != 0)
739 key = data->keys + keyid;
740 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
742 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
744 struct subschema_data subd;
748 subd.cbdata = cbdata;
751 ddp = data_read_id(ddp, &nentries);
755 while (ddp && nentries > 0)
759 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
760 ddp = data_read_id(ddp, &schema);
762 kv.str = (char *)ddp;
763 stop = callback(cbdata, s, data, key, &kv);
764 if (stop > SEARCH_NEXT_KEY)
766 if (stop && stop != SEARCH_ENTERSUB)
768 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
769 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
770 ddp = data_skip_schema(data, ddp, schema);
773 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
777 kv.str = (char *)ddp;
778 stop = callback(cbdata, s, data, key, &kv);
779 if (stop > SEARCH_NEXT_KEY)
789 ddp = data_fetch(ddp, &kv, key);
792 stop = callback(cbdata, s, data, key, &kv);
795 while (!kv.eof && !stop);
796 if (onekey || stop > SEARCH_NEXT_KEY)
802 repodata_setpos_kv(Repodata *data, KeyValue *kv)
804 Pool *pool = data->repo->pool;
806 pool_clear_pos(pool);
809 pool->pos.repo = data->repo;
810 pool->pos.repodataid = data - data->repo->repodata;
811 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
812 pool->pos.schema = kv->id;
816 /************************************************************************
817 * data iterator functions
820 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
821 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
822 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
823 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
824 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
825 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
826 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
827 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
828 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
829 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
830 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
831 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
832 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
833 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
837 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
851 case SOLVABLE_VENDOR:
854 case SOLVABLE_PROVIDES:
856 return s->provides ? s->repo->idarraydata + s->provides : 0;
857 case SOLVABLE_OBSOLETES:
859 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
860 case SOLVABLE_CONFLICTS:
862 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
863 case SOLVABLE_REQUIRES:
865 return s->requires ? s->repo->idarraydata + s->requires : 0;
866 case SOLVABLE_RECOMMENDS:
868 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
869 case SOLVABLE_SUPPLEMENTS:
871 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
872 case SOLVABLE_SUGGESTS:
874 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
875 case SOLVABLE_ENHANCES:
877 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
880 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
887 datamatcher_init(Datamatcher *ma, const char *match, int flags)
893 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
895 ma->matchdata = sat_calloc(1, sizeof(regex_t));
896 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
899 sat_free(ma->matchdata);
900 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
907 datamatcher_free(Datamatcher *ma)
909 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
911 regfree(ma->matchdata);
912 ma->matchdata = sat_free(ma->matchdata);
917 datamatcher_match(Datamatcher *ma, const char *str)
919 switch ((ma->flags & SEARCH_STRINGMASK))
921 case SEARCH_SUBSTRING:
922 if (ma->flags & SEARCH_NOCASE)
924 if (!strcasestr(str, ma->match))
929 if (!strstr(str, ma->match))
934 if (ma->flags & SEARCH_NOCASE)
936 if (strcasecmp(ma->match, str))
941 if (strcmp(ma->match, str))
946 if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
950 if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
985 /* see repo.h for documentation */
987 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
989 memset(di, 0, sizeof(*di));
991 di->flags = flags & ~SEARCH_THISSOLVID;
992 if (!pool || (repo && repo->pool != pool))
1000 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1006 di->keyname = keyname;
1007 di->keynames[0] = keyname;
1008 dataiterator_set_search(di, repo, p);
1013 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1016 memset(&di->matcher, 0, sizeof(di->matcher));
1017 if (from->matcher.match)
1018 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1023 for (i = 1; i < di->nparents; i++)
1024 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1025 di->kv.parent = &di->parents[di->nparents - 1].kv;
1030 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1032 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1033 datamatcher_free(&di->matcher);
1034 memset(&di->matcher, 0, sizeof(di->matcher));
1038 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1048 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1052 di->flags &= ~SEARCH_THISSOLVID;
1056 if (!di->pool->nrepos)
1064 di->repo = di->pool->repos[0];
1066 di->state = di_enterrepo;
1068 dataiterator_jump_to_solvid(di, p);
1072 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1075 di->keyname = keyname;
1076 di->keynames[0] = keyname;
1080 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1084 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1086 di->state = di_bye; /* sorry */
1089 for (i = di->nkeynames + 1; i > 0; i--)
1090 di->keynames[i] = di->keynames[i - 1];
1091 di->keynames[0] = di->keyname = keyname;
1096 dataiterator_free(Dataiterator *di)
1098 if (di->matcher.match)
1099 datamatcher_free(&di->matcher);
1102 static inline unsigned char *
1103 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1105 Id *keyp = di->keyp;
1106 Repokey *keys = di->data->keys;
1109 for (keyp = di->keyp; *keyp; keyp++)
1110 if (keys[*keyp].name == keyname)
1114 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1122 dataiterator_step(Dataiterator *di)
1130 case di_enterrepo: di_enterrepo:
1133 if (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS))
1135 if (!(di->flags & SEARCH_THISSOLVID))
1137 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1138 goto di_nextsolvable;
1142 case di_entersolvable: di_entersolvable:
1143 if (di->repodataid >= 0)
1145 di->repodataid = 0; /* reset repodata iterator */
1146 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)
1148 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1150 goto di_entersolvablekey;
1155 case di_enterrepodata: di_enterrepodata:
1156 if (di->repodataid >= 0)
1158 if (di->repodataid >= di->repo->nrepodata)
1159 goto di_nextsolvable;
1160 di->data = di->repo->repodata + di->repodataid;
1162 if (!maybe_load_repodata(di->data, di->keyname))
1163 goto di_nextrepodata;
1164 di->dp = solvid2data(di->data, di->solvid, &schema);
1166 goto di_nextrepodata;
1167 if (di->solvid == SOLVID_POS)
1168 di->solvid = di->pool->pos.solvid;
1169 /* reset key iterator */
1170 di->keyp = di->data->schemadata + di->data->schemata[schema];
1173 case di_enterschema: di_enterschema:
1175 di->dp = dataiterator_find_keyname(di, di->keyname);
1176 if (!di->dp || !*di->keyp)
1180 goto di_nextrepodata;
1184 case di_enterkey: di_enterkey:
1186 di->key = di->data->keys + *di->keyp;
1187 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1190 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1192 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1198 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1200 di->state = di_nextkey;
1202 di->state = di_nextattr;
1205 case di_nextkey: di_nextkey:
1206 if (!di->keyname && *++di->keyp)
1212 case di_nextrepodata: di_nextrepodata:
1213 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1214 goto di_enterrepodata;
1217 case di_nextsolvable: di_nextsolvable:
1218 if (!(di->flags & SEARCH_THISSOLVID))
1221 di->solvid = di->repo->start;
1224 for (; di->solvid < di->repo->end; di->solvid++)
1226 if (di->pool->solvables[di->solvid].repo == di->repo)
1227 goto di_entersolvable;
1232 case di_nextrepo: di_nextrepo:
1233 if (di->repoid >= 0)
1236 if (di->repoid < di->pool->nrepos)
1238 di->repo = di->pool->repos[di->repoid];
1244 case di_bye: di_bye:
1248 case di_enterarray: di_enterarray:
1249 if (di->key->name == REPOSITORY_SOLVABLES)
1251 di->ddp = data_read_id(di->ddp, &di->kv.num);
1256 case di_nextarrayelement: di_nextarrayelement:
1259 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1260 if (di->kv.entry == di->kv.num)
1262 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1264 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1266 di->kv.str = (char *)di->ddp;
1268 di->state = di_nextkey;
1271 if (di->kv.entry == di->kv.num - 1)
1273 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1274 di->ddp = data_read_id(di->ddp, &di->kv.id);
1275 di->kv.str = (char *)di->ddp;
1276 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1278 if ((di->flags & SEARCH_SUB) != 0)
1279 di->state = di_entersub;
1281 di->state = di_nextarrayelement;
1284 case di_entersub: di_entersub:
1285 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1286 goto di_nextarrayelement; /* sorry, full */
1287 di->parents[di->nparents].kv = di->kv;
1288 di->parents[di->nparents].dp = di->dp;
1289 di->parents[di->nparents].keyp = di->keyp;
1290 di->dp = (unsigned char *)di->kv.str;
1291 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1292 memset(&di->kv, 0, sizeof(di->kv));
1293 di->kv.parent = &di->parents[di->nparents].kv;
1295 di->keyname = di->keynames[di->nparents - di->rootlevel];
1296 goto di_enterschema;
1298 case di_leavesub: di_leavesub:
1299 if (di->nparents - 1 < di->rootlevel)
1302 di->dp = di->parents[di->nparents].dp;
1303 di->kv = di->parents[di->nparents].kv;
1304 di->keyp = di->parents[di->nparents].keyp;
1305 di->key = di->data->keys + *di->keyp;
1306 di->ddp = (unsigned char *)di->kv.str;
1307 di->keyname = di->keynames[di->nparents - di->rootlevel];
1308 goto di_nextarrayelement;
1310 /* special solvable attr handling follows */
1312 case di_nextsolvableattr:
1313 di->kv.id = *di->idp++;
1318 di->state = di_nextsolvablekey;
1322 case di_nextsolvablekey: di_nextsolvablekey:
1323 if (di->keyname || di->key->name == RPM_RPMDBID)
1324 goto di_enterrepodata;
1328 case di_entersolvablekey: di_entersolvablekey:
1329 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1330 if (!di->idp || !di->idp[0])
1331 goto di_nextsolvablekey;
1332 di->kv.id = di->idp[0];
1333 di->kv.num = di->idp[0];
1335 if (!di->kv.eof && !di->idp[0])
1339 di->state = di_nextsolvablekey;
1341 di->state = di_nextsolvableattr;
1345 if (di->matcher.match)
1347 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1349 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1353 if (!datamatcher_match(&di->matcher, di->kv.str))
1356 /* found something! */
1362 dataiterator_entersub(Dataiterator *di)
1364 if (di->state == di_nextarrayelement)
1365 di->state = di_entersub;
1369 dataiterator_setpos(Dataiterator *di)
1371 if (di->kv.eof == 2)
1373 pool_clear_pos(di->pool);
1376 di->pool->pos.solvid = di->solvid;
1377 di->pool->pos.repo = di->repo;
1378 di->pool->pos.repodataid = di->data - di->repo->repodata;
1379 di->pool->pos.schema = di->kv.id;
1380 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1384 dataiterator_setpos_parent(Dataiterator *di)
1386 if (!di->kv.parent || di->kv.parent->eof == 2)
1388 pool_clear_pos(di->pool);
1391 di->pool->pos.solvid = di->solvid;
1392 di->pool->pos.repo = di->repo;
1393 di->pool->pos.repodataid = di->data - di->repo->repodata;
1394 di->pool->pos.schema = di->kv.parent->id;
1395 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1398 /* clones just the position, not the search keys/matcher */
1400 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1402 di->state = from->state;
1403 di->flags &= ~SEARCH_THISSOLVID;
1404 di->flags |= (from->flags & SEARCH_THISSOLVID);
1405 di->repo = from->repo;
1406 di->data = from->data;
1408 di->ddp = from->ddp;
1409 di->idp = from->idp;
1410 di->keyp = from->keyp;
1411 di->key = from->key;
1413 di->repodataid = from->repodataid;
1414 di->solvid = from->solvid;
1415 di->repoid = from->repoid;
1416 di->rootlevel = from->rootlevel;
1417 memcpy(di->parents, from->parents, sizeof(from->parents));
1418 di->nparents = from->nparents;
1422 for (i = 1; i < di->nparents; i++)
1423 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1424 di->kv.parent = &di->parents[di->nparents - 1].kv;
1429 dataiterator_seek(Dataiterator *di, int whence)
1431 if ((whence & DI_SEEK_STAY) != 0)
1432 di->rootlevel = di->nparents;
1433 switch (whence & ~DI_SEEK_STAY)
1436 if (di->state != di_nextarrayelement)
1438 if ((whence & DI_SEEK_STAY) != 0)
1439 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1440 di->state = di_entersub;
1442 case DI_SEEK_PARENT:
1449 if (di->rootlevel > di->nparents)
1450 di->rootlevel = di->nparents;
1451 di->dp = di->parents[di->nparents].dp;
1452 di->kv = di->parents[di->nparents].kv;
1453 di->keyp = di->parents[di->nparents].keyp;
1454 di->key = di->data->keys + *di->keyp;
1455 di->ddp = (unsigned char *)di->kv.str;
1456 di->keyname = di->keynames[di->nparents - di->rootlevel];
1457 di->state = di_nextarrayelement;
1459 case DI_SEEK_REWIND:
1465 di->dp = (unsigned char *)di->kv.parent->str;
1466 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1467 di->state = di_enterschema;
1475 dataiterator_skip_attribute(Dataiterator *di)
1477 if (di->state == di_nextsolvableattr)
1478 di->state = di_nextsolvablekey;
1480 di->state = di_nextkey;
1484 dataiterator_skip_solvable(Dataiterator *di)
1486 di->state = di_nextsolvable;
1490 dataiterator_skip_repo(Dataiterator *di)
1492 di->state = di_nextrepo;
1496 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1500 if (solvid == SOLVID_POS)
1502 di->repo = di->pool->pos.repo;
1509 di->data = di->repo->repodata + di->pool->pos.repodataid;
1510 di->repodataid = -1;
1511 di->solvid = solvid;
1512 di->state = di_enterrepo;
1513 di->flags |= SEARCH_THISSOLVID;
1518 di->repo = di->pool->solvables[solvid].repo;
1521 else if (di->repoid >= 0)
1523 if (!di->pool->nrepos)
1528 di->repo = di->pool->repos[0];
1532 di->solvid = solvid;
1534 di->flags |= SEARCH_THISSOLVID;
1535 di->state = di_enterrepo;
1539 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1547 di->flags &= ~SEARCH_THISSOLVID;
1548 di->state = di_enterrepo;
1552 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1554 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1558 return datamatcher_match(ma, di->kv.str);
1561 /************************************************************************
1562 * data modify functions
1565 /* extend repodata so that it includes solvables p */
1567 repodata_extend(Repodata *data, Id p)
1569 if (data->start == data->end)
1570 data->start = data->end = p;
1573 int old = data->end - data->start;
1574 int new = p - data->end + 1;
1577 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1578 memset(data->attrs + old, 0, new * sizeof(Id *));
1580 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1581 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1584 if (p < data->start)
1586 int old = data->end - data->start;
1587 int new = data->start - p;
1590 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1591 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1592 memset(data->attrs, 0, new * sizeof(Id *));
1594 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1595 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1596 memset(data->incoreoffset, 0, new * sizeof(Id));
1601 /* extend repodata so that it includes solvables from start to start + num - 1 */
1603 repodata_extend_block(Repodata *data, Id start, Id num)
1607 if (!data->incoreoffset)
1609 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1610 data->start = start;
1611 data->end = start + num;
1614 repodata_extend(data, start);
1616 repodata_extend(data, start + num - 1);
1619 /**********************************************************************/
1621 #define REPODATA_ATTRS_BLOCK 63
1622 #define REPODATA_ATTRDATA_BLOCK 1023
1623 #define REPODATA_ATTRIDDATA_BLOCK 63
1627 repodata_new_handle(Repodata *data)
1631 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1634 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1635 data->xattrs[data->nxattrs] = 0;
1636 return -(data->nxattrs++);
1640 repodata_get_attrp(Repodata *data, Id handle)
1642 if (handle == SOLVID_META)
1646 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1651 return data->xattrs - handle;
1652 if (handle < data->start || handle >= data->end)
1653 repodata_extend(data, handle);
1655 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1656 return data->attrs + (handle - data->start);
1660 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1666 app = repodata_get_attrp(data, handle);
1671 for (pp = ap; *pp; pp += 2)
1672 /* Determine equality based on the name only, allows us to change
1673 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1674 if (data->keys[*pp].name == data->keys[keyid].name)
1687 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1697 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1701 keyid = repodata_key2id(data, key, 1);
1702 repodata_insert_keyid(data, solvid, keyid, val, 1);
1706 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1710 key.type = REPOKEY_TYPE_ID;
1712 key.storage = KEY_STORAGE_INCORE;
1713 repodata_set(data, solvid, &key, id);
1717 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1721 key.type = REPOKEY_TYPE_NUM;
1723 key.storage = KEY_STORAGE_INCORE;
1724 repodata_set(data, solvid, &key, (Id)num);
1728 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1732 if (data->localpool)
1733 id = stringpool_str2id(&data->spool, str, 1);
1735 id = str2id(data->repo->pool, str, 1);
1737 key.type = REPOKEY_TYPE_ID;
1739 key.storage = KEY_STORAGE_INCORE;
1740 repodata_set(data, solvid, &key, id);
1744 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1748 key.type = REPOKEY_TYPE_CONSTANT;
1749 key.size = constant;
1750 key.storage = KEY_STORAGE_INCORE;
1751 repodata_set(data, solvid, &key, 0);
1755 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1759 key.type = REPOKEY_TYPE_CONSTANTID;
1761 key.storage = KEY_STORAGE_INCORE;
1762 repodata_set(data, solvid, &key, 0);
1766 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1770 key.type = REPOKEY_TYPE_VOID;
1772 key.storage = KEY_STORAGE_INCORE;
1773 repodata_set(data, solvid, &key, 0);
1777 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1782 l = strlen(str) + 1;
1784 key.type = REPOKEY_TYPE_STR;
1786 key.storage = KEY_STORAGE_INCORE;
1787 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1788 memcpy(data->attrdata + data->attrdatalen, str, l);
1789 repodata_set(data, solvid, &key, data->attrdatalen);
1790 data->attrdatalen += l;
1793 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1794 * so that the caller can append the new element there */
1796 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1799 Id *ida, *pp, **ppp;
1801 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1803 /* great! just append the new data */
1804 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1805 data->attriddatalen--; /* overwrite terminating 0 */
1806 data->lastdatalen += entrysize;
1809 ppp = repodata_get_attrp(data, handle);
1812 for (; *pp; pp += 2)
1813 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1817 /* not found. allocate new key */
1822 key.storage = KEY_STORAGE_INCORE;
1823 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1824 repodata_set(data, handle, &key, data->attriddatalen);
1825 data->lasthandle = 0; /* next time... */
1829 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1830 oldsize += entrysize;
1831 if (ida + 1 == data->attriddata + data->attriddatalen)
1833 /* this was the last entry, just append it */
1834 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1835 data->attriddatalen--; /* overwrite terminating 0 */
1839 /* too bad. move to back. */
1840 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1841 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1842 pp[1] = data->attriddatalen;
1843 data->attriddatalen += oldsize;
1845 data->lasthandle = handle;
1846 data->lastkey = *pp;
1847 data->lastdatalen = data->attriddatalen + entrysize + 1;
1851 checksumtype2len(Id type)
1855 case REPOKEY_TYPE_MD5:
1857 case REPOKEY_TYPE_SHA1:
1859 case REPOKEY_TYPE_SHA256:
1860 return SIZEOF_SHA256;
1867 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1868 const unsigned char *str)
1871 int l = checksumtype2len(type);
1878 key.storage = KEY_STORAGE_INCORE;
1879 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1880 memcpy(data->attrdata + data->attrdatalen, str, l);
1881 repodata_set(data, solvid, &key, data->attrdatalen);
1882 data->attrdatalen += l;
1886 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1889 for (i = 0; i < buflen; i++)
1891 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1892 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
1893 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
1904 buf[i] = (buf[i] << 4) | v;
1911 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1914 unsigned char buf[64];
1915 int l = checksumtype2len(type);
1919 if (hexstr2bytes(buf, str, l) != l)
1921 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
1925 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1930 l = checksumtype2len(type);
1933 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1934 for (i = 0; i < l; i++)
1936 unsigned char v = buf[i];
1937 unsigned char w = v >> 4;
1938 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1940 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1946 /* rpm filenames don't contain the epoch, so strip it */
1947 static inline const char *
1948 evrid2vrstr(Pool *pool, Id evrid)
1950 const char *p, *evr = id2str(pool, evrid);
1953 for (p = evr; *p >= '0' && *p <= '9'; p++)
1955 return p != evr && *p == ':' ? p + 1 : evr;
1959 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
1961 Pool *pool = data->repo->pool;
1963 const char *str, *fp;
1967 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
1970 if ((dir = strrchr(file, '/')) != 0)
1981 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
1986 if (l == 1 && dir[0] == '.')
1988 s = pool->solvables + solvid;
1991 str = id2str(pool, s->arch);
1992 if (!strncmp(dir, str, l) && !str[l])
1993 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
1995 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
1998 char *dir2 = strdup(dir);
2000 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
2005 str = id2str(pool, s->name);
2007 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2010 str = evrid2vrstr(pool, s->evr);
2012 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2015 str = id2str(pool, s->arch);
2017 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2019 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2024 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2028 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2032 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2034 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2035 data->attriddata[data->attriddatalen++] = dir;
2036 data->attriddata[data->attriddatalen++] = num;
2037 data->attriddata[data->attriddatalen++] = num2;
2038 data->attriddata[data->attriddatalen++] = 0;
2042 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2048 l = strlen(str) + 1;
2049 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2050 memcpy(data->attrdata + data->attrdatalen, str, l);
2051 stroff = data->attrdatalen;
2052 data->attrdatalen += l;
2055 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2057 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2058 data->attriddata[data->attriddatalen++] = dir;
2059 data->attriddata[data->attriddatalen++] = stroff;
2060 data->attriddata[data->attriddatalen++] = 0;
2064 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2067 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2069 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2070 data->attriddata[data->attriddatalen++] = id;
2071 data->attriddata[data->attriddatalen++] = 0;
2075 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2079 if (data->localpool)
2080 id = stringpool_str2id(&data->spool, str, 1);
2082 id = str2id(data->repo->pool, str, 1);
2083 repodata_add_idarray(data, solvid, keyname, id);
2087 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2089 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2090 data->attriddata[data->attriddatalen++] = ghandle;
2091 data->attriddata[data->attriddatalen++] = 0;
2095 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2097 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2098 data->attriddata[data->attriddatalen++] = ghandle;
2099 data->attriddata[data->attriddatalen++] = 0;
2102 /* add all attrs from src to dest */
2104 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2107 if (dest == src || !(keyp = data->attrs[src - data->start]))
2109 for (; *keyp; keyp += 2)
2110 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2116 /**********************************************************************/
2118 /* unify with repo_write! */
2120 #define EXTDATA_BLOCK 1023
2128 data_addid(struct extdata *xd, Id x)
2131 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2132 dp = xd->buf + xd->len;
2137 *dp++ = (x >> 28) | 128;
2139 *dp++ = (x >> 21) | 128;
2140 *dp++ = (x >> 14) | 128;
2143 *dp++ = (x >> 7) | 128;
2145 xd->len = dp - xd->buf;
2149 data_addideof(struct extdata *xd, Id x, int eof)
2152 x = (x & 63) | ((x & ~63) << 1);
2153 data_addid(xd, (eof ? x: x | 64));
2157 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2159 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2160 memcpy(xd->buf + xd->len, blob, len);
2164 /*********************************/
2167 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2168 struct extdata *newvincore,
2170 Repokey *key, Id val)
2172 /* Otherwise we have a new value. Parse it into the internal
2176 unsigned int oldvincorelen = 0;
2180 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2183 oldvincorelen = xd->len;
2187 case REPOKEY_TYPE_VOID:
2188 case REPOKEY_TYPE_CONSTANT:
2189 case REPOKEY_TYPE_CONSTANTID:
2191 case REPOKEY_TYPE_STR:
2192 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2194 case REPOKEY_TYPE_MD5:
2195 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2197 case REPOKEY_TYPE_SHA1:
2198 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2200 case REPOKEY_TYPE_SHA256:
2201 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2203 case REPOKEY_TYPE_ID:
2204 case REPOKEY_TYPE_NUM:
2205 case REPOKEY_TYPE_DIR:
2206 data_addid(xd, val);
2208 case REPOKEY_TYPE_IDARRAY:
2209 for (ida = data->attriddata + val; *ida; ida++)
2210 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2212 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2213 for (ida = data->attriddata + val; *ida; ida += 3)
2215 data_addid(xd, ida[0]);
2216 data_addid(xd, ida[1]);
2217 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2220 case REPOKEY_TYPE_DIRSTRARRAY:
2221 for (ida = data->attriddata + val; *ida; ida += 2)
2223 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2224 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2227 case REPOKEY_TYPE_FIXARRAY:
2231 for (ida = data->attriddata + val; *ida; ida++)
2234 fprintf(stderr, "serialize struct %d\n", *ida);
2237 Id *kp = data->xattrs[-*ida];
2244 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2250 schemaid = repodata_schema2id(data, schema, 1);
2251 else if (schemaid != repodata_schema2id(data, schema, 0))
2253 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2257 fprintf(stderr, " schema %d\n", schemaid);
2262 data_addid(xd, num);
2263 data_addid(xd, schemaid);
2264 for (ida = data->attriddata + val; *ida; ida++)
2266 Id *kp = data->xattrs[-*ida];
2271 repodata_serialize_key(data, newincore, newvincore,
2272 schema, data->keys + *kp, kp[1]);
2277 case REPOKEY_TYPE_FLEXARRAY:
2280 for (ida = data->attriddata + val; *ida; ida++)
2282 data_addid(xd, num);
2283 for (ida = data->attriddata + val; *ida; ida++)
2285 Id *kp = data->xattrs[-*ida];
2288 data_addid(xd, 0); /* XXX */
2295 schemaid = repodata_schema2id(data, schema, 1);
2296 data_addid(xd, schemaid);
2297 kp = data->xattrs[-*ida];
2300 repodata_serialize_key(data, newincore, newvincore,
2301 schema, data->keys + *kp, kp[1]);
2307 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2310 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2312 /* put offset/len in incore */
2313 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2314 oldvincorelen = xd->len - oldvincorelen;
2315 data_addid(newincore, oldvincorelen);
2320 repodata_internalize(Repodata *data)
2322 Repokey *key, solvkey;
2324 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2325 unsigned char *dp, *ndp;
2326 int newschema, oldcount;
2327 struct extdata newincore;
2328 struct extdata newvincore;
2331 if (!data->attrs && !data->xattrs)
2334 newvincore.buf = data->vincore;
2335 newvincore.len = data->vincorelen;
2337 /* find the solvables key, create if needed */
2338 memset(&solvkey, 0, sizeof(solvkey));
2339 solvkey.name = REPOSITORY_SOLVABLES;
2340 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2342 solvkey.storage = KEY_STORAGE_INCORE;
2343 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2345 schema = sat_malloc2(data->nkeys, sizeof(Id));
2346 seen = sat_malloc2(data->nkeys, sizeof(Id));
2348 /* Merge the data already existing (in data->schemata, ->incoredata and
2349 friends) with the new attributes in data->attrs[]. */
2350 nentry = data->end - data->start;
2351 memset(&newincore, 0, sizeof(newincore));
2352 data_addid(&newincore, 0); /* start data at offset 1 */
2354 data->mainschema = 0;
2355 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2357 /* join entry data */
2358 /* we start with the meta data, entry -1 */
2359 for (entry = -1; entry < nentry; entry++)
2361 memset(seen, 0, data->nkeys * sizeof(Id));
2363 dp = data->incoredata;
2366 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2367 dp = data_read_id(dp, &oldschema);
2370 fprintf(stderr, "oldschema %d\n", oldschema);
2371 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2372 fprintf(stderr, "schemadata %p\n", data->schemadata);
2374 /* seen: -1: old data 0: skipped >0: id + 1 */
2378 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2382 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2390 keyp = data->attrs ? data->attrs[entry] : 0;
2393 /* strip solvables key */
2395 for (sp = keyp = schema; *sp; sp++)
2396 if (*sp != solvkeyid)
2401 seen[solvkeyid] = 0;
2402 keyp = data->xattrs ? data->xattrs[1] : 0;
2405 for (; *keyp; keyp += 2)
2412 seen[*keyp] = keyp[1] + 1;
2414 if (entry < 0 && data->end != data->start)
2421 /* Ideally we'd like to sort the new schema here, to ensure
2422 schema equality independend of the ordering. We can't do that
2423 yet. For once see below (old ids need to come before new ids).
2424 An additional difficulty is that we also need to move
2425 the values with the keys. */
2426 schemaid = repodata_schema2id(data, schema, 1);
2428 schemaid = oldschema;
2431 /* Now create data blob. We walk through the (possibly new) schema
2432 and either copy over old data, or insert the new. */
2433 /* XXX Here we rely on the fact that the (new) schema has the form
2434 o1 o2 o3 o4 ... | n1 n2 n3 ...
2435 (oX being the old keyids (possibly overwritten), and nX being
2436 the new keyids). This rules out sorting the keyids in order
2437 to ensure a small schema count. */
2439 data->incoreoffset[entry] = newincore.len;
2440 data_addid(&newincore, schemaid);
2443 data->mainschema = schemaid;
2444 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2446 keypstart = data->schemadata + data->schemata[schemaid];
2447 for (keyp = keypstart; *keyp; keyp++)
2450 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2451 if (*keyp == solvkeyid)
2453 /* add flexarray entry count */
2454 data_addid(&newincore, data->end - data->start);
2457 key = data->keys + *keyp;
2459 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2464 /* Skip the data associated with this old key. */
2465 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2467 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2468 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2470 else if (key->storage == KEY_STORAGE_INCORE)
2471 ndp = data_skip_key(data, dp, key);
2474 if (seen[*keyp] == -1)
2476 /* If this key was an old one _and_ was not overwritten with
2477 a different value copy over the old value (we skipped it
2480 data_addblob(&newincore, dp, ndp - dp);
2483 else if (seen[*keyp])
2485 /* Otherwise we have a new value. Parse it into the internal
2487 repodata_serialize_key(data, &newincore, &newvincore,
2488 schema, key, seen[*keyp] - 1);
2492 if (entry >= 0 && data->attrs && data->attrs[entry])
2493 data->attrs[entry] = sat_free(data->attrs[entry]);
2495 /* free all xattrs */
2496 for (entry = 0; entry < data->nxattrs; entry++)
2497 if (data->xattrs[entry])
2498 sat_free(data->xattrs[entry]);
2499 data->xattrs = sat_free(data->xattrs);
2502 data->lasthandle = 0;
2504 data->lastdatalen = 0;
2507 repodata_free_schemahash(data);
2509 sat_free(data->incoredata);
2510 data->incoredata = newincore.buf;
2511 data->incoredatalen = newincore.len;
2512 data->incoredatafree = 0;
2514 sat_free(data->vincore);
2515 data->vincore = newvincore.buf;
2516 data->vincorelen = newvincore.len;
2518 data->attrs = sat_free(data->attrs);
2519 data->attrdata = sat_free(data->attrdata);
2520 data->attriddata = sat_free(data->attriddata);
2521 data->attrdatalen = 0;
2522 data->attriddatalen = 0;
2526 repodata_disable_paging(Repodata *data)
2528 if (maybe_load_repodata(data, 0))
2529 repopagestore_disable_paging(&data->store);
2533 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: