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 #define REPODATA_BLOCK 255
39 static unsigned char *data_skip_key(Repodata *data, unsigned char *dp, Repokey *key);
42 repodata_initdata(Repodata *data, Repo *repo, int localpool)
44 memset(data, 0, sizeof (*data));
45 data->repodataid = data - repo->repodata;
47 data->localpool = localpool;
49 stringpool_init_empty(&data->spool);
50 /* dirpool_init(&data->dirpool); just zeros out again */
51 data->keys = solv_calloc(1, sizeof(Repokey));
53 data->schemata = solv_calloc(1, sizeof(Id));
54 data->schemadata = solv_calloc(1, sizeof(Id));
56 data->schemadatalen = 1;
57 repopagestore_init(&data->store);
61 repodata_freedata(Repodata *data)
65 solv_free(data->keys);
67 solv_free(data->schemata);
68 solv_free(data->schemadata);
69 solv_free(data->schematahash);
71 stringpool_free(&data->spool);
72 dirpool_free(&data->dirpool);
74 solv_free(data->mainschemaoffsets);
75 solv_free(data->incoredata);
76 solv_free(data->incoreoffset);
77 solv_free(data->verticaloffset);
79 repopagestore_free(&data->store);
81 solv_free(data->vincore);
84 for (i = 0; i < data->end - data->start; i++)
85 solv_free(data->attrs[i]);
86 solv_free(data->attrs);
88 for (i = 0; i < data->nxattrs; i++)
89 solv_free(data->xattrs[i]);
90 solv_free(data->xattrs);
92 solv_free(data->attrdata);
93 solv_free(data->attriddata);
94 solv_free(data->attrnum64data);
96 solv_free(data->dircache);
100 repodata_free(Repodata *data)
102 Repo *repo = data->repo;
103 int i = data - repo->repodata;
106 repodata_freedata(data);
107 if (i < repo->nrepodata - 1)
109 /* whoa! this changes the repodataids! */
110 memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
111 for (; i < repo->nrepodata - 1; i++)
112 repo->repodata[i].repodataid = i;
115 if (repo->nrepodata == 1)
117 repo->repodata = solv_free(repo->repodata);
123 repodata_empty(Repodata *data, int localpool)
125 void (*loadcallback)(Repodata *) = data->loadcallback;
126 int state = data->state;
127 repodata_freedata(data);
128 repodata_initdata(data, data->repo, localpool);
130 data->loadcallback = loadcallback;
134 /***************************************************************
135 * key pool management
138 /* this is not so time critical that we need a hash, so we do a simple
141 repodata_key2id(Repodata *data, Repokey *key, int create)
145 for (keyid = 1; keyid < data->nkeys; keyid++)
146 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
148 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
152 if (keyid == data->nkeys)
156 /* allocate new key */
157 data->keys = solv_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
158 data->keys[data->nkeys++] = *key;
159 if (data->verticaloffset)
161 data->verticaloffset = solv_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
162 data->verticaloffset[data->nkeys - 1] = 0;
164 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
170 /***************************************************************
171 * schema pool management
174 #define SCHEMATA_BLOCK 31
175 #define SCHEMATADATA_BLOCK 255
178 repodata_schema2id(Repodata *data, Id *schema, int create)
185 return 0; /* XXX: allow empty schema? */
186 if ((schematahash = data->schematahash) == 0)
188 data->schematahash = schematahash = solv_calloc(256, sizeof(Id));
189 for (i = 1; i < data->nschemata; i++)
191 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
196 data->schemadata = solv_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
197 data->schemata = solv_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
200 for (sp = schema, len = 0, h = 0; *sp; len++)
205 cid = schematahash[h];
208 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
210 /* cache conflict, do a slow search */
211 for (cid = 1; cid < data->nschemata; cid++)
212 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
218 data->schemadata = solv_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
219 data->schemata = solv_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
221 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
222 data->schemata[data->nschemata] = data->schemadatalen;
223 data->schemadatalen += len;
224 schematahash[h] = data->nschemata;
226 fprintf(stderr, "schema2id: new schema\n");
228 return data->nschemata++;
232 repodata_free_schemahash(Repodata *data)
234 data->schematahash = solv_free(data->schematahash);
236 data->schemata = solv_realloc2(data->schemata, data->nschemata, sizeof(Id));
237 data->schemadata = solv_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
241 /***************************************************************
242 * dir pool management
245 #ifndef HAVE_STRCHRNUL
246 static inline const char *strchrnul(const char *str, char x)
248 const char *p = strchr(str, x);
249 return p ? p : str + strlen(str);
253 #define DIRCACHE_SIZE 41 /* < 1k */
257 Id ids[DIRCACHE_SIZE];
258 char str[(DIRCACHE_SIZE * (DIRCACHE_SIZE - 1)) / 2];
263 repodata_str2dir(Repodata *data, const char *dir, int create)
274 while (*dir == '/' && dir[1] == '/')
276 if (*dir == '/' && !dir[1])
278 if (data->dirpool.ndirs)
280 return dirpool_add_dir(&data->dirpool, 0, 1, create);
287 struct dircache *dircache = data->dircache;
291 if (l < DIRCACHE_SIZE && dircache->ids[l] && !memcmp(dircache->str + l * (l - 1) / 2, dir, l))
293 parent = dircache->ids[l];
309 dire = strchrnul(dir, '/');
311 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
313 id = pool_strn2id(data->repo->pool, dir, dire - dir, create);
316 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
321 data->dircache = solv_calloc(1, sizeof(struct dircache));
325 if (l < DIRCACHE_SIZE)
327 data->dircache->ids[l] = parent;
328 memcpy(data->dircache->str + l * (l - 1) / 2, dirs, l);
342 repodata_free_dircache(Repodata *data)
344 data->dircache = solv_free(data->dircache);
348 repodata_dir2str(Repodata *data, Id did, const char *suf)
350 Pool *pool = data->repo->pool;
357 return suf ? suf : "";
361 comp = dirpool_compid(&data->dirpool, parent);
362 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
364 parent = dirpool_parent(&data->dirpool, parent);
369 l += strlen(suf) + 1;
370 p = pool_alloctmpspace(pool, l + 1) + l;
381 comp = dirpool_compid(&data->dirpool, parent);
382 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
385 strncpy(p, comps, l);
386 parent = dirpool_parent(&data->dirpool, parent);
394 /***************************************************************
398 static inline unsigned char *
399 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
401 Id *keyp = data->schemadata + data->schemata[schema];
402 for (; *keyp; keyp++)
403 dp = data_skip_key(data, dp, data->keys + *keyp);
407 static unsigned char *
408 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
410 int nentries, schema;
413 case REPOKEY_TYPE_FIXARRAY:
414 dp = data_read_id(dp, &nentries);
417 dp = data_read_id(dp, &schema);
419 dp = data_skip_schema(data, dp, schema);
421 case REPOKEY_TYPE_FLEXARRAY:
422 dp = data_read_id(dp, &nentries);
425 dp = data_read_id(dp, &schema);
426 dp = data_skip_schema(data, dp, schema);
430 if (key->storage == KEY_STORAGE_INCORE)
431 dp = data_skip(dp, key->type);
432 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
434 dp = data_skip(dp, REPOKEY_TYPE_ID);
435 dp = data_skip(dp, REPOKEY_TYPE_ID);
441 static unsigned char *
442 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
448 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
451 for (i = 0; (k = *keyp++) != 0; i++)
453 return data->incoredata + data->mainschemaoffsets[i];
456 while ((k = *keyp++) != 0)
460 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
462 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
463 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
466 if (data->keys[k].storage != KEY_STORAGE_INCORE)
468 dp = data_skip_key(data, dp, data->keys + k);
473 static unsigned char *
474 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
479 if (off >= data->lastverticaloffset)
481 off -= data->lastverticaloffset;
482 if (off + len > data->vincorelen)
484 return data->vincore + off;
486 if (off + len > key->size)
488 /* we now have the offset, go into vertical */
489 off += data->verticaloffset[key - data->keys];
490 /* fprintf(stderr, "key %d page %d\n", key->name, off / REPOPAGE_BLOBSIZE); */
491 dp = repopagestore_load_page_range(&data->store, off / REPOPAGE_BLOBSIZE, (off + len - 1) / REPOPAGE_BLOBSIZE);
493 dp += off % REPOPAGE_BLOBSIZE;
497 static inline unsigned char *
498 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
500 unsigned char *dp = *dpp;
504 if (key->storage == KEY_STORAGE_INCORE)
507 *dpp = data_skip_key(data, dp, key);
510 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
513 dp = data_read_id(dp, &off);
514 dp = data_read_id(dp, &len);
517 return get_vertical_data(data, key, off, len);
523 load_repodata(Repodata *data)
525 if (data->loadcallback)
527 data->loadcallback(data);
528 if (data->state == REPODATA_AVAILABLE)
531 data->state = REPODATA_ERROR;
536 maybe_load_repodata(Repodata *data, Id keyname)
538 if (keyname && !repodata_precheck_keyname(data, keyname))
539 return 0; /* do not bother... */
546 for (i = 1; i < data->nkeys; i++)
547 if (keyname == data->keys[i].name)
549 if (i == data->nkeys)
552 return load_repodata(data);
555 case REPODATA_AVAILABLE:
556 case REPODATA_LOADING:
559 data->state = REPODATA_ERROR;
564 static inline unsigned char *
565 solvid2data(Repodata *data, Id solvid, Id *schemap)
567 unsigned char *dp = data->incoredata;
570 if (solvid == SOLVID_META) /* META */
572 else if (solvid == SOLVID_POS) /* META */
574 Pool *pool = data->repo->pool;
575 if (data->repo != pool->pos.repo)
577 if (data != data->repo->repodata + pool->pos.repodataid)
579 *schemap = pool->pos.schema;
580 return data->incoredata + pool->pos.dp;
584 if (solvid < data->start || solvid >= data->end)
586 dp += data->incoreoffset[solvid - data->start];
588 return data_read_id(dp, schemap);
591 /************************************************************************
595 static inline unsigned char *
596 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
599 Id schema, *keyp, *kp;
602 if (!maybe_load_repodata(data, keyname))
604 dp = solvid2data(data, solvid, &schema);
607 keyp = data->schemadata + data->schemata[schema];
608 for (kp = keyp; *kp; kp++)
609 if (data->keys[*kp].name == keyname)
613 *keypp = key = data->keys + *kp;
614 if (key->type == REPOKEY_TYPE_DELETED)
616 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
617 return dp; /* no need to forward... */
618 dp = forward_to_key(data, *kp, keyp, dp);
621 return get_data(data, key, &dp, 0);
625 repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
627 Id schema, *keyp, *kp;
628 if (!maybe_load_repodata(data, keyname))
630 if (!solvid2data(data, solvid, &schema))
632 keyp = data->schemadata + data->schemata[schema];
633 for (kp = keyp; *kp; kp++)
634 if (data->keys[*kp].name == keyname)
635 return data->keys[*kp].type;
640 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
646 dp = find_key_data(data, solvid, keyname, &key);
649 if (key->type == REPOKEY_TYPE_CONSTANTID)
651 if (key->type != REPOKEY_TYPE_ID)
653 dp = data_read_id(dp, &id);
658 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
664 dp = find_key_data(data, solvid, keyname, &key);
667 if (key->type == REPOKEY_TYPE_STR)
668 return (const char *)dp;
669 if (key->type == REPOKEY_TYPE_CONSTANTID)
671 else if (key->type == REPOKEY_TYPE_ID)
672 dp = data_read_id(dp, &id);
676 return stringpool_id2str(&data->spool, id);
677 return pool_id2str(data->repo->pool, id);
681 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value)
685 unsigned int high, low;
688 dp = find_key_data(data, solvid, keyname, &key);
693 case REPOKEY_TYPE_NUM:
694 data_read_num64(dp, &low, &high);
695 *value = (unsigned long long)high << 32 | low;
697 case REPOKEY_TYPE_U32:
698 data_read_u32(dp, &low);
701 case REPOKEY_TYPE_CONSTANT:
710 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
716 if (!maybe_load_repodata(data, keyname))
718 dp = solvid2data(data, solvid, &schema);
721 /* can't use find_key_data as we need to test the type */
722 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
723 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
728 const unsigned char *
729 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
734 dp = find_key_data(data, solvid, keyname, &key);
737 if (!(key->type == REPOKEY_TYPE_MD5 || key->type == REPOKEY_TYPE_SHA1 || key->type == REPOKEY_TYPE_SHA256))
744 repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
752 dp = find_key_data(data, solvid, keyname, &key);
755 if (key->type != REPOKEY_TYPE_IDARRAY && key->type != REPOKEY_TYPE_REL_IDARRAY)
759 dp = data_read_ideof(dp, &id, &eof);
768 repodata_globalize_id(Repodata *data, Id id, int create)
770 if (!id || !data || !data->localpool)
772 return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
776 repodata_localize_id(Repodata *data, Id id, int create)
778 if (!id || !data || !data->localpool)
780 return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
784 repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
789 ap = data->attrs[solvid - data->start];
794 if (data->keys[*ap].name != keyname)
796 if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
798 if (data->keys[*ap].type == REPOKEY_TYPE_ID)
806 /************************************************************************
812 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
816 case REPOKEY_TYPE_ID:
817 case REPOKEY_TYPE_CONSTANTID:
818 case REPOKEY_TYPE_IDARRAY:
819 if (data && data->localpool)
820 kv->str = stringpool_id2str(&data->spool, kv->id);
822 kv->str = pool_id2str(pool, kv->id);
823 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
826 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
828 if (*s == ':' && s > kv->str)
832 case REPOKEY_TYPE_STR:
834 case REPOKEY_TYPE_DIRSTRARRAY:
835 if (!(flags & SEARCH_FILES))
836 return 1; /* match just the basename */
837 /* Put the full filename into kv->str. */
838 kv->str = repodata_dir2str(data, kv->id, kv->str);
839 /* And to compensate for that put the "empty" directory into
840 kv->id, so that later calls to repodata_dir2str on this data
841 come up with the same filename again. */
844 case REPOKEY_TYPE_MD5:
845 case REPOKEY_TYPE_SHA1:
846 case REPOKEY_TYPE_SHA256:
847 if (!(flags & SEARCH_CHECKSUMS))
848 return 0; /* skip em */
849 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
857 struct subschema_data {
863 /* search a specific repodata */
865 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
869 Id keyid, *kp, *keyp;
870 unsigned char *dp, *ddp;
876 if (!maybe_load_repodata(data, keyname))
878 if (solvid == SOLVID_SUBSCHEMA)
880 struct subschema_data *subd = cbdata;
881 cbdata = subd->cbdata;
883 schema = subd->parent->id;
884 dp = (unsigned char *)subd->parent->str;
885 kv.parent = subd->parent;
890 dp = solvid2data(data, solvid, &schema);
893 s = data->repo->pool->solvables + solvid;
896 keyp = data->schemadata + data->schemata[schema];
899 /* search for a specific key */
900 for (kp = keyp; *kp; kp++)
901 if (data->keys[*kp].name == keyname)
905 dp = forward_to_key(data, *kp, keyp, dp);
911 while ((keyid = *keyp++) != 0)
914 key = data->keys + keyid;
915 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
917 if (key->type == REPOKEY_TYPE_DELETED)
919 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
921 struct subschema_data subd;
925 subd.cbdata = cbdata;
928 ddp = data_read_id(ddp, &nentries);
932 while (ddp && nentries > 0)
936 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
937 ddp = data_read_id(ddp, &schema);
939 kv.str = (char *)ddp;
940 stop = callback(cbdata, s, data, key, &kv);
941 if (stop > SEARCH_NEXT_KEY)
943 if (stop && stop != SEARCH_ENTERSUB)
945 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
946 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
947 ddp = data_skip_schema(data, ddp, schema);
950 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
954 kv.str = (char *)ddp;
955 stop = callback(cbdata, s, data, key, &kv);
956 if (stop > SEARCH_NEXT_KEY)
966 ddp = data_fetch(ddp, &kv, key);
969 stop = callback(cbdata, s, data, key, &kv);
972 while (!kv.eof && !stop);
973 if (onekey || stop > SEARCH_NEXT_KEY)
979 repodata_setpos_kv(Repodata *data, KeyValue *kv)
981 Pool *pool = data->repo->pool;
983 pool_clear_pos(pool);
986 pool->pos.repo = data->repo;
987 pool->pos.repodataid = data - data->repo->repodata;
988 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
989 pool->pos.schema = kv->id;
993 /************************************************************************
994 * data iterator functions
998 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
1012 case SOLVABLE_VENDOR:
1015 case SOLVABLE_PROVIDES:
1017 return s->provides ? s->repo->idarraydata + s->provides : 0;
1018 case SOLVABLE_OBSOLETES:
1020 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
1021 case SOLVABLE_CONFLICTS:
1023 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
1024 case SOLVABLE_REQUIRES:
1026 return s->requires ? s->repo->idarraydata + s->requires : 0;
1027 case SOLVABLE_RECOMMENDS:
1029 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
1030 case SOLVABLE_SUPPLEMENTS:
1032 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
1033 case SOLVABLE_SUGGESTS:
1035 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
1036 case SOLVABLE_ENHANCES:
1038 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
1041 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
1048 datamatcher_init(Datamatcher *ma, const char *match, int flags)
1054 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1056 ma->matchdata = solv_calloc(1, sizeof(regex_t));
1057 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1060 solv_free(ma->matchdata);
1061 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
1068 datamatcher_free(Datamatcher *ma)
1070 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1072 regfree(ma->matchdata);
1073 ma->matchdata = solv_free(ma->matchdata);
1078 datamatcher_match(Datamatcher *ma, const char *str)
1081 switch ((ma->flags & SEARCH_STRINGMASK))
1083 case SEARCH_SUBSTRING:
1084 if (ma->flags & SEARCH_NOCASE)
1086 if (!strcasestr(str, ma->match))
1091 if (!strstr(str, ma->match))
1096 if (ma->flags & SEARCH_NOCASE)
1098 if (strcasecmp(ma->match, str))
1103 if (strcmp(ma->match, str))
1107 case SEARCH_STRINGSTART:
1108 if (ma->flags & SEARCH_NOCASE)
1110 if (strncasecmp(ma->match, str, strlen(ma->match)))
1115 if (strncmp(ma->match, str, strlen(ma->match)))
1119 case SEARCH_STRINGEND:
1120 l = strlen(str) - strlen(ma->match);
1123 if (ma->flags & SEARCH_NOCASE)
1125 if (strcasecmp(ma->match, str + l))
1130 if (strcmp(ma->match, str + l))
1135 if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
1139 if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
1149 repodata_filelistfilter_matches(Repodata *data, const char *str)
1151 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1152 /* for now hardcoded */
1153 if (strstr(str, "bin/"))
1155 if (!strncmp(str, "/etc/", 5))
1157 if (!strcmp(str, "/usr/lib/sendmail"))
1179 di_nextarrayelement,
1185 di_entersolvablekey,
1189 /* see dataiterator.h for documentation */
1191 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1193 memset(di, 0, sizeof(*di));
1195 di->flags = flags & ~SEARCH_THISSOLVID;
1196 if (!pool || (repo && repo->pool != pool))
1204 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1210 di->keyname = keyname;
1211 di->keynames[0] = keyname;
1212 dataiterator_set_search(di, repo, p);
1217 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1220 memset(&di->matcher, 0, sizeof(di->matcher));
1221 if (from->matcher.match)
1222 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1227 for (i = 1; i < di->nparents; i++)
1228 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1229 di->kv.parent = &di->parents[di->nparents - 1].kv;
1234 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1236 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1237 datamatcher_free(&di->matcher);
1238 memset(&di->matcher, 0, sizeof(di->matcher));
1242 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1252 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1256 di->flags &= ~SEARCH_THISSOLVID;
1260 if (!di->pool->urepos)
1268 di->repo = di->pool->repos[di->repoid];
1270 di->state = di_enterrepo;
1272 dataiterator_jump_to_solvid(di, p);
1276 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1279 di->keyname = keyname;
1280 di->keynames[0] = keyname;
1284 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1288 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1290 di->state = di_bye; /* sorry */
1293 for (i = di->nkeynames + 1; i > 0; i--)
1294 di->keynames[i] = di->keynames[i - 1];
1295 di->keynames[0] = di->keyname = keyname;
1300 dataiterator_free(Dataiterator *di)
1302 if (di->matcher.match)
1303 datamatcher_free(&di->matcher);
1306 static inline unsigned char *
1307 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1309 Id *keyp = di->keyp;
1310 Repokey *keys = di->data->keys;
1313 for (keyp = di->keyp; *keyp; keyp++)
1314 if (keys[*keyp].name == keyname)
1318 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1326 dataiterator_filelistcheck(Dataiterator *di)
1329 int needcomplete = 0;
1330 Repodata *data = di->data;
1332 if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
1333 if (!di->matcher.match
1334 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1335 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1336 || !repodata_filelistfilter_matches(di->data, di->matcher.match))
1338 if (data->state != REPODATA_AVAILABLE)
1339 return needcomplete ? 1 : 0;
1340 for (j = 1; j < data->nkeys; j++)
1341 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1343 return j == data->nkeys && !needcomplete ? 0 : 1;
1347 dataiterator_step(Dataiterator *di)
1355 case di_enterrepo: di_enterrepo:
1356 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1358 if (!(di->flags & SEARCH_THISSOLVID))
1360 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1361 goto di_nextsolvable;
1365 case di_entersolvable: di_entersolvable:
1368 di->repodataid = 1; /* reset repodata iterator */
1369 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)
1371 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1373 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1375 goto di_entersolvablekey;
1380 case di_enterrepodata: di_enterrepodata:
1383 if (di->repodataid >= di->repo->nrepodata)
1384 goto di_nextsolvable;
1385 di->data = di->repo->repodata + di->repodataid;
1387 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1388 goto di_nextrepodata;
1389 if (!maybe_load_repodata(di->data, di->keyname))
1390 goto di_nextrepodata;
1391 di->dp = solvid2data(di->data, di->solvid, &schema);
1393 goto di_nextrepodata;
1394 if (di->solvid == SOLVID_POS)
1395 di->solvid = di->pool->pos.solvid;
1396 /* reset key iterator */
1397 di->keyp = di->data->schemadata + di->data->schemata[schema];
1400 case di_enterschema: di_enterschema:
1402 di->dp = dataiterator_find_keyname(di, di->keyname);
1403 if (!di->dp || !*di->keyp)
1407 goto di_nextrepodata;
1411 case di_enterkey: di_enterkey:
1413 di->key = di->data->keys + *di->keyp;
1414 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1417 if (di->key->type == REPOKEY_TYPE_DELETED)
1419 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1421 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1427 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1429 di->state = di_nextkey;
1431 di->state = di_nextattr;
1434 case di_nextkey: di_nextkey:
1435 if (!di->keyname && *++di->keyp)
1441 case di_nextrepodata: di_nextrepodata:
1442 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1443 goto di_enterrepodata;
1446 case di_nextsolvable: di_nextsolvable:
1447 if (!(di->flags & SEARCH_THISSOLVID))
1450 di->solvid = di->repo->start;
1453 for (; di->solvid < di->repo->end; di->solvid++)
1455 if (di->pool->solvables[di->solvid].repo == di->repo)
1456 goto di_entersolvable;
1461 case di_nextrepo: di_nextrepo:
1466 if (di->repoid < di->pool->nrepos)
1468 di->repo = di->pool->repos[di->repoid];
1474 case di_bye: di_bye:
1478 case di_enterarray: di_enterarray:
1479 if (di->key->name == REPOSITORY_SOLVABLES)
1481 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1486 case di_nextarrayelement: di_nextarrayelement:
1489 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1490 if (di->kv.entry == di->kv.num)
1492 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1494 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1496 di->kv.str = (char *)di->ddp;
1498 di->state = di_nextkey;
1501 if (di->kv.entry == di->kv.num - 1)
1503 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1504 di->ddp = data_read_id(di->ddp, &di->kv.id);
1505 di->kv.str = (char *)di->ddp;
1506 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1508 if ((di->flags & SEARCH_SUB) != 0)
1509 di->state = di_entersub;
1511 di->state = di_nextarrayelement;
1514 case di_entersub: di_entersub:
1515 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1516 goto di_nextarrayelement; /* sorry, full */
1517 di->parents[di->nparents].kv = di->kv;
1518 di->parents[di->nparents].dp = di->dp;
1519 di->parents[di->nparents].keyp = di->keyp;
1520 di->dp = (unsigned char *)di->kv.str;
1521 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1522 memset(&di->kv, 0, sizeof(di->kv));
1523 di->kv.parent = &di->parents[di->nparents].kv;
1525 di->keyname = di->keynames[di->nparents - di->rootlevel];
1526 goto di_enterschema;
1528 case di_leavesub: di_leavesub:
1529 if (di->nparents - 1 < di->rootlevel)
1532 di->dp = di->parents[di->nparents].dp;
1533 di->kv = di->parents[di->nparents].kv;
1534 di->keyp = di->parents[di->nparents].keyp;
1535 di->key = di->data->keys + *di->keyp;
1536 di->ddp = (unsigned char *)di->kv.str;
1537 di->keyname = di->keynames[di->nparents - di->rootlevel];
1538 goto di_nextarrayelement;
1540 /* special solvable attr handling follows */
1542 case di_nextsolvablekey: di_nextsolvablekey:
1543 if (di->keyname || di->key->name == RPM_RPMDBID)
1544 goto di_enterrepodata;
1548 case di_entersolvablekey: di_entersolvablekey:
1549 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1550 if (!di->idp || !*di->idp)
1551 goto di_nextsolvablekey;
1555 di->kv.id = *di->idp;
1556 di->kv.num = *di->idp; /* for rpmdbid */
1557 di->kv.num2 = 0; /* for rpmdbid */
1559 di->state = di_nextsolvablekey;
1565 case di_nextsolvableattr:
1566 di->state = di_nextsolvableattr;
1567 di->kv.id = *di->idp++;
1572 di->state = di_nextsolvablekey;
1578 if (di->matcher.match)
1580 /* simple pre-check so that we don't need to stringify */
1581 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && di->matcher.match && (di->matcher.flags & (SEARCH_FILES|SEARCH_NOCASE|SEARCH_STRINGMASK)) == (SEARCH_FILES|SEARCH_STRING))
1583 int l = strlen(di->matcher.match) - strlen(di->kv.str);
1584 if (l < 0 || strcmp(di->matcher.match + l, di->kv.str))
1587 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1589 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1593 if (!datamatcher_match(&di->matcher, di->kv.str))
1596 /* found something! */
1602 dataiterator_entersub(Dataiterator *di)
1604 if (di->state == di_nextarrayelement)
1605 di->state = di_entersub;
1609 dataiterator_setpos(Dataiterator *di)
1611 if (di->kv.eof == 2)
1613 pool_clear_pos(di->pool);
1616 di->pool->pos.solvid = di->solvid;
1617 di->pool->pos.repo = di->repo;
1618 di->pool->pos.repodataid = di->data - di->repo->repodata;
1619 di->pool->pos.schema = di->kv.id;
1620 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1624 dataiterator_setpos_parent(Dataiterator *di)
1626 if (!di->kv.parent || di->kv.parent->eof == 2)
1628 pool_clear_pos(di->pool);
1631 di->pool->pos.solvid = di->solvid;
1632 di->pool->pos.repo = di->repo;
1633 di->pool->pos.repodataid = di->data - di->repo->repodata;
1634 di->pool->pos.schema = di->kv.parent->id;
1635 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1638 /* clones just the position, not the search keys/matcher */
1640 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1642 di->state = from->state;
1643 di->flags &= ~SEARCH_THISSOLVID;
1644 di->flags |= (from->flags & SEARCH_THISSOLVID);
1645 di->repo = from->repo;
1646 di->data = from->data;
1648 di->ddp = from->ddp;
1649 di->idp = from->idp;
1650 di->keyp = from->keyp;
1651 di->key = from->key;
1653 di->repodataid = from->repodataid;
1654 di->solvid = from->solvid;
1655 di->repoid = from->repoid;
1656 di->rootlevel = from->rootlevel;
1657 memcpy(di->parents, from->parents, sizeof(from->parents));
1658 di->nparents = from->nparents;
1662 for (i = 1; i < di->nparents; i++)
1663 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1664 di->kv.parent = &di->parents[di->nparents - 1].kv;
1669 dataiterator_seek(Dataiterator *di, int whence)
1671 if ((whence & DI_SEEK_STAY) != 0)
1672 di->rootlevel = di->nparents;
1673 switch (whence & ~DI_SEEK_STAY)
1676 if (di->state != di_nextarrayelement)
1678 if ((whence & DI_SEEK_STAY) != 0)
1679 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1680 di->state = di_entersub;
1682 case DI_SEEK_PARENT:
1689 if (di->rootlevel > di->nparents)
1690 di->rootlevel = di->nparents;
1691 di->dp = di->parents[di->nparents].dp;
1692 di->kv = di->parents[di->nparents].kv;
1693 di->keyp = di->parents[di->nparents].keyp;
1694 di->key = di->data->keys + *di->keyp;
1695 di->ddp = (unsigned char *)di->kv.str;
1696 di->keyname = di->keynames[di->nparents - di->rootlevel];
1697 di->state = di_nextarrayelement;
1699 case DI_SEEK_REWIND:
1705 di->dp = (unsigned char *)di->kv.parent->str;
1706 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1707 di->state = di_enterschema;
1715 dataiterator_skip_attribute(Dataiterator *di)
1717 if (di->state == di_nextsolvableattr)
1718 di->state = di_nextsolvablekey;
1720 di->state = di_nextkey;
1724 dataiterator_skip_solvable(Dataiterator *di)
1729 di->keyname = di->keynames[0];
1730 di->state = di_nextsolvable;
1734 dataiterator_skip_repo(Dataiterator *di)
1739 di->keyname = di->keynames[0];
1740 di->state = di_nextrepo;
1744 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1749 di->keyname = di->keynames[0];
1750 if (solvid == SOLVID_POS)
1752 di->repo = di->pool->pos.repo;
1759 di->data = di->repo->repodata + di->pool->pos.repodataid;
1761 di->solvid = solvid;
1762 di->state = di_enterrepo;
1763 di->flags |= SEARCH_THISSOLVID;
1768 di->repo = di->pool->solvables[solvid].repo;
1771 else if (di->repoid > 0)
1773 if (!di->pool->urepos)
1779 di->repo = di->pool->repos[di->repoid];
1782 di->solvid = solvid;
1784 di->flags |= SEARCH_THISSOLVID;
1785 di->state = di_enterrepo;
1789 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1795 di->repoid = 0; /* 0 means stay at repo */
1798 di->flags &= ~SEARCH_THISSOLVID;
1799 di->state = di_enterrepo;
1803 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1805 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1809 return datamatcher_match(ma, di->kv.str);
1812 /************************************************************************
1813 * data modify functions
1816 /* extend repodata so that it includes solvables p */
1818 repodata_extend(Repodata *data, Id p)
1820 if (data->start == data->end)
1821 data->start = data->end = p;
1824 int old = data->end - data->start;
1825 int new = p - data->end + 1;
1828 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1829 memset(data->attrs + old, 0, new * sizeof(Id *));
1831 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1832 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1835 if (p < data->start)
1837 int old = data->end - data->start;
1838 int new = data->start - p;
1841 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1842 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1843 memset(data->attrs, 0, new * sizeof(Id *));
1845 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1846 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1847 memset(data->incoreoffset, 0, new * sizeof(Id));
1852 /* shrink end of repodata */
1854 repodata_shrink(Repodata *data, int end)
1858 if (data->end <= end)
1860 if (data->start >= end)
1864 for (i = 0; i < data->end - data->start; i++)
1865 solv_free(data->attrs[i]);
1866 data->attrs = solv_free(data->attrs);
1868 data->incoreoffset = solv_free(data->incoreoffset);
1869 data->start = data->end = 0;
1874 for (i = end; i < data->end; i++)
1875 solv_free(data->attrs[i - data->start]);
1876 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1878 if (data->incoreoffset)
1879 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1883 /* extend repodata so that it includes solvables from start to start + num - 1 */
1885 repodata_extend_block(Repodata *data, Id start, Id num)
1889 if (!data->incoreoffset)
1891 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1892 data->start = start;
1893 data->end = start + num;
1896 repodata_extend(data, start);
1898 repodata_extend(data, start + num - 1);
1901 /**********************************************************************/
1904 #define REPODATA_ATTRS_BLOCK 31
1905 #define REPODATA_ATTRDATA_BLOCK 1023
1906 #define REPODATA_ATTRIDDATA_BLOCK 63
1907 #define REPODATA_ATTRNUM64DATA_BLOCK 15
1911 repodata_new_handle(Repodata *data)
1915 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1916 data->nxattrs = 2; /* -1: SOLVID_META */
1918 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1919 data->xattrs[data->nxattrs] = 0;
1920 return -(data->nxattrs++);
1924 repodata_get_attrp(Repodata *data, Id handle)
1928 if (handle == SOLVID_META && !data->xattrs)
1930 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1933 return data->xattrs - handle;
1935 if (handle < data->start || handle >= data->end)
1936 repodata_extend(data, handle);
1938 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1939 return data->attrs + (handle - data->start);
1943 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1949 app = repodata_get_attrp(data, handle);
1954 /* Determine equality based on the name only, allows us to change
1955 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1956 for (pp = ap; *pp; pp += 2)
1957 if (data->keys[*pp].name == data->keys[keyid].name)
1961 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
1970 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1980 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1984 keyid = repodata_key2id(data, key, 1);
1985 repodata_insert_keyid(data, solvid, keyid, val, 1);
1989 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1993 key.type = REPOKEY_TYPE_ID;
1995 key.storage = KEY_STORAGE_INCORE;
1996 repodata_set(data, solvid, &key, id);
2000 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2004 key.type = REPOKEY_TYPE_NUM;
2006 key.storage = KEY_STORAGE_INCORE;
2007 if (num >= 0x80000000)
2009 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2010 data->attrnum64data[data->attrnum64datalen] = num;
2011 num = 0x80000000 | data->attrnum64datalen++;
2013 repodata_set(data, solvid, &key, (Id)num);
2017 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2021 if (data->localpool)
2022 id = stringpool_str2id(&data->spool, str, 1);
2024 id = pool_str2id(data->repo->pool, str, 1);
2026 key.type = REPOKEY_TYPE_ID;
2028 key.storage = KEY_STORAGE_INCORE;
2029 repodata_set(data, solvid, &key, id);
2033 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2037 key.type = REPOKEY_TYPE_CONSTANT;
2038 key.size = constant;
2039 key.storage = KEY_STORAGE_INCORE;
2040 repodata_set(data, solvid, &key, 0);
2044 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2048 key.type = REPOKEY_TYPE_CONSTANTID;
2050 key.storage = KEY_STORAGE_INCORE;
2051 repodata_set(data, solvid, &key, 0);
2055 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2059 key.type = REPOKEY_TYPE_VOID;
2061 key.storage = KEY_STORAGE_INCORE;
2062 repodata_set(data, solvid, &key, 0);
2066 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2071 l = strlen(str) + 1;
2073 key.type = REPOKEY_TYPE_STR;
2075 key.storage = KEY_STORAGE_INCORE;
2076 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2077 memcpy(data->attrdata + data->attrdatalen, str, l);
2078 repodata_set(data, solvid, &key, data->attrdatalen);
2079 data->attrdatalen += l;
2083 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2091 key.type = REPOKEY_TYPE_BINARY;
2093 key.storage = KEY_STORAGE_INCORE;
2094 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2095 dp = data->attrdata + data->attrdatalen;
2096 if (len >= (1 << 14))
2098 if (len >= (1 << 28))
2099 *dp++ = (len >> 28) | 128;
2100 if (len >= (1 << 21))
2101 *dp++ = (len >> 21) | 128;
2102 *dp++ = (len >> 14) | 128;
2104 if (len >= (1 << 7))
2105 *dp++ = (len >> 7) | 128;
2108 memcpy(dp, buf, len);
2109 repodata_set(data, solvid, &key, data->attrdatalen);
2110 data->attrdatalen = dp + len - data->attrdata;
2113 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2114 * so that the caller can append entrysize new elements plus the termination zero there */
2116 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2119 Id *ida, *pp, **ppp;
2121 /* check if it is the same as last time, this speeds things up a lot */
2122 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2124 /* great! just append the new data */
2125 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2126 data->attriddatalen--; /* overwrite terminating 0 */
2127 data->lastdatalen += entrysize;
2131 ppp = repodata_get_attrp(data, handle);
2135 for (; *pp; pp += 2)
2136 if (data->keys[*pp].name == keyname)
2139 if (!pp || !*pp || data->keys[*pp].type != keytype)
2141 /* not found. allocate new key */
2147 key.storage = KEY_STORAGE_INCORE;
2148 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2149 keyid = repodata_key2id(data, &key, 1);
2150 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2151 data->lasthandle = handle;
2152 data->lastkey = keyid;
2153 data->lastdatalen = data->attriddatalen + entrysize + 1;
2157 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2158 oldsize += entrysize;
2159 if (ida + 1 == data->attriddata + data->attriddatalen)
2161 /* this was the last entry, just append it */
2162 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2163 data->attriddatalen--; /* overwrite terminating 0 */
2167 /* too bad. move to back. */
2168 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2169 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2170 pp[1] = data->attriddatalen;
2171 data->attriddatalen += oldsize;
2173 data->lasthandle = handle;
2174 data->lastkey = *pp;
2175 data->lastdatalen = data->attriddatalen + entrysize + 1;
2179 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2180 const unsigned char *str)
2185 if (!(l = solv_chksum_len(type)))
2190 key.storage = KEY_STORAGE_INCORE;
2191 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2192 memcpy(data->attrdata + data->attrdatalen, str, l);
2193 repodata_set(data, solvid, &key, data->attrdatalen);
2194 data->attrdatalen += l;
2198 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2201 unsigned char buf[64];
2204 if (!(l = solv_chksum_len(type)))
2206 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2208 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2212 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2216 if (!(l = solv_chksum_len(type)))
2218 return pool_bin2hex(data->repo->pool, buf, l);
2221 /* rpm filenames don't contain the epoch, so strip it */
2222 static inline const char *
2223 evrid2vrstr(Pool *pool, Id evrid)
2225 const char *p, *evr = pool_id2str(pool, evrid);
2228 for (p = evr; *p >= '0' && *p <= '9'; p++)
2230 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2234 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2236 Pool *pool = data->repo->pool;
2238 const char *str, *fp;
2242 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2245 if ((dir = strrchr(file, '/')) != 0)
2256 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2261 if (l == 1 && dir[0] == '.')
2263 s = pool->solvables + solvid;
2266 str = pool_id2str(pool, s->arch);
2267 if (!strncmp(dir, str, l) && !str[l])
2268 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2270 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
2273 char *dir2 = solv_strdup(dir);
2275 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
2280 str = pool_id2str(pool, s->name);
2282 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2285 str = evrid2vrstr(pool, s->evr);
2287 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2290 str = pool_id2str(pool, s->arch);
2292 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2294 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2299 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2303 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2305 Pool *pool = data->repo->pool;
2306 Solvable *s = pool->solvables + solvid;
2307 const char *p, *sevr, *sarch, *name, *evr;
2309 p = strrchr(sourcepkg, '.');
2310 if (!p || strcmp(p, ".rpm") != 0)
2313 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2317 while (p > sourcepkg && *p != '.')
2319 if (*p != '.' || p == sourcepkg)
2322 while (p > sourcepkg && *p != '-')
2324 if (*p != '-' || p == sourcepkg)
2327 while (p > sourcepkg && *p != '-')
2329 if (*p != '-' || p == sourcepkg)
2332 pool = s->repo->pool;
2334 name = pool_id2str(pool, s->name);
2335 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2336 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2338 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2340 evr = evrid2vrstr(pool, s->evr);
2341 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2342 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2344 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2346 if (!strcmp(sarch, "src.rpm"))
2347 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2348 else if (!strcmp(sarch, "nosrc.rpm"))
2349 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2351 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2355 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2361 key.type = REPOKEY_TYPE_IDARRAY;
2363 key.storage = KEY_STORAGE_INCORE;
2364 repodata_set(data, solvid, &key, data->attriddatalen);
2365 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2366 for (i = 0; i < q->count; i++)
2367 data->attriddata[data->attriddatalen++] = q->elements[i];
2368 data->attriddata[data->attriddatalen++] = 0;
2372 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2376 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2378 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2379 data->attriddata[data->attriddatalen++] = dir;
2380 data->attriddata[data->attriddatalen++] = num;
2381 data->attriddata[data->attriddatalen++] = num2;
2382 data->attriddata[data->attriddatalen++] = 0;
2386 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2392 l = strlen(str) + 1;
2393 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2394 memcpy(data->attrdata + data->attrdatalen, str, l);
2395 stroff = data->attrdatalen;
2396 data->attrdatalen += l;
2399 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2401 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2402 data->attriddata[data->attriddatalen++] = dir;
2403 data->attriddata[data->attriddatalen++] = stroff;
2404 data->attriddata[data->attriddatalen++] = 0;
2408 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2411 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2413 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2414 data->attriddata[data->attriddatalen++] = id;
2415 data->attriddata[data->attriddatalen++] = 0;
2419 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2423 if (data->localpool)
2424 id = stringpool_str2id(&data->spool, str, 1);
2426 id = pool_str2id(data->repo->pool, str, 1);
2427 repodata_add_idarray(data, solvid, keyname, id);
2431 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2433 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2434 data->attriddata[data->attriddatalen++] = ghandle;
2435 data->attriddata[data->attriddatalen++] = 0;
2439 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2441 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2442 data->attriddata[data->attriddatalen++] = ghandle;
2443 data->attriddata[data->attriddatalen++] = 0;
2447 repodata_delete_uninternalized(Repodata *data, Id solvid, Id keyname)
2450 app = repodata_get_attrp(data, solvid);
2454 for (; *ap; ap += 2)
2455 if (data->keys[*ap].name == keyname)
2461 for (; *ap; ap += 2)
2463 if (data->keys[*ap].name == keyname)
2471 /* XXX: does not work correctly, needs fix in iterators! */
2473 repodata_delete(Repodata *data, Id solvid, Id keyname)
2477 key.type = REPOKEY_TYPE_DELETED;
2479 key.storage = KEY_STORAGE_INCORE;
2480 repodata_set(data, solvid, &key, 0);
2483 /* add all (uninternalized) attrs from src to dest */
2485 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2488 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2490 for (; *keyp; keyp += 2)
2491 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2494 /* add some (uninternalized) attrs from src to dest */
2496 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2499 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2501 for (; *keyp; keyp += 2)
2502 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2503 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2506 /* swap (uninternalized) attrs from src and dest */
2508 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2511 if (!data->attrs || dest == src)
2513 tmpattrs = data->attrs[dest - data->start];
2514 data->attrs[dest - data->start] = data->attrs[src - data->start];
2515 data->attrs[src - data->start] = tmpattrs;
2519 /**********************************************************************/
2521 /* TODO: unify with repo_write and repo_solv! */
2523 #define EXTDATA_BLOCK 1023
2531 data_addid(struct extdata *xd, Id sx)
2533 unsigned int x = (unsigned int)sx;
2536 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2537 dp = xd->buf + xd->len;
2542 *dp++ = (x >> 28) | 128;
2544 *dp++ = (x >> 21) | 128;
2545 *dp++ = (x >> 14) | 128;
2548 *dp++ = (x >> 7) | 128;
2550 xd->len = dp - xd->buf;
2554 data_addid64(struct extdata *xd, unsigned long long x)
2556 if (x >= 0x100000000)
2560 data_addid(xd, (Id)(x >> 35));
2561 xd->buf[xd->len - 1] |= 128;
2563 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2564 xd->buf[xd->len - 5] = (x >> 28) | 128;
2567 data_addid(xd, (Id)x);
2571 data_addideof(struct extdata *xd, Id sx, int eof)
2573 unsigned int x = (unsigned int)sx;
2576 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2577 dp = xd->buf + xd->len;
2582 *dp++ = (x >> 27) | 128;
2584 *dp++ = (x >> 20) | 128;
2585 *dp++ = (x >> 13) | 128;
2588 *dp++ = (x >> 6) | 128;
2589 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2590 xd->len = dp - xd->buf;
2594 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2596 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2597 memcpy(xd->buf + xd->len, blob, len);
2601 /*********************************/
2603 /* internalalize some key into incore/vincore data */
2606 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2607 struct extdata *newvincore,
2609 Repokey *key, Id val)
2613 unsigned int oldvincorelen = 0;
2617 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2620 oldvincorelen = xd->len;
2624 case REPOKEY_TYPE_VOID:
2625 case REPOKEY_TYPE_CONSTANT:
2626 case REPOKEY_TYPE_CONSTANTID:
2628 case REPOKEY_TYPE_STR:
2629 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2631 case REPOKEY_TYPE_MD5:
2632 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2634 case REPOKEY_TYPE_SHA1:
2635 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2637 case REPOKEY_TYPE_SHA256:
2638 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2640 case REPOKEY_TYPE_NUM:
2641 if (val & 0x80000000)
2643 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2647 case REPOKEY_TYPE_ID:
2648 case REPOKEY_TYPE_DIR:
2649 data_addid(xd, val);
2651 case REPOKEY_TYPE_BINARY:
2654 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2655 dp += (unsigned int)len;
2656 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2659 case REPOKEY_TYPE_IDARRAY:
2660 for (ida = data->attriddata + val; *ida; ida++)
2661 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2663 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2664 for (ida = data->attriddata + val; *ida; ida += 3)
2666 data_addid(xd, ida[0]);
2667 data_addid(xd, ida[1]);
2668 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2671 case REPOKEY_TYPE_DIRSTRARRAY:
2672 for (ida = data->attriddata + val; *ida; ida += 2)
2674 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2675 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2678 case REPOKEY_TYPE_FIXARRAY:
2682 for (ida = data->attriddata + val; *ida; ida++)
2686 kp = data->xattrs[-*ida];
2694 schemaid = repodata_schema2id(data, schema, 1);
2695 else if (schemaid != repodata_schema2id(data, schema, 0))
2697 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
2703 data_addid(xd, num);
2704 data_addid(xd, schemaid);
2705 for (ida = data->attriddata + val; *ida; ida++)
2707 Id *kp = data->xattrs[-*ida];
2711 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2715 case REPOKEY_TYPE_FLEXARRAY:
2718 for (ida = data->attriddata + val; *ida; ida++)
2720 data_addid(xd, num);
2721 for (ida = data->attriddata + val; *ida; ida++)
2723 Id *kp = data->xattrs[-*ida];
2726 data_addid(xd, 0); /* XXX */
2733 schemaid = repodata_schema2id(data, schema, 1);
2734 data_addid(xd, schemaid);
2735 kp = data->xattrs[-*ida];
2737 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2742 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
2745 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2747 /* put offset/len in incore */
2748 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2749 oldvincorelen = xd->len - oldvincorelen;
2750 data_addid(newincore, oldvincorelen);
2755 repodata_internalize(Repodata *data)
2757 Repokey *key, solvkey;
2759 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2760 unsigned char *dp, *ndp;
2761 int newschema, oldcount;
2762 struct extdata newincore;
2763 struct extdata newvincore;
2766 if (!data->attrs && !data->xattrs)
2769 newvincore.buf = data->vincore;
2770 newvincore.len = data->vincorelen;
2772 /* find the solvables key, create if needed */
2773 memset(&solvkey, 0, sizeof(solvkey));
2774 solvkey.name = REPOSITORY_SOLVABLES;
2775 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2777 solvkey.storage = KEY_STORAGE_INCORE;
2778 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2780 schema = solv_malloc2(data->nkeys, sizeof(Id));
2781 seen = solv_malloc2(data->nkeys, sizeof(Id));
2783 /* Merge the data already existing (in data->schemata, ->incoredata and
2784 friends) with the new attributes in data->attrs[]. */
2785 nentry = data->end - data->start;
2786 memset(&newincore, 0, sizeof(newincore));
2787 data_addid(&newincore, 0); /* start data at offset 1 */
2789 data->mainschema = 0;
2790 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
2792 /* join entry data */
2793 /* we start with the meta data, entry -1 */
2794 for (entry = -1; entry < nentry; entry++)
2796 memset(seen, 0, data->nkeys * sizeof(Id));
2798 dp = data->incoredata;
2801 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2802 dp = data_read_id(dp, &oldschema);
2805 fprintf(stderr, "oldschema %d\n", oldschema);
2806 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2807 fprintf(stderr, "schemadata %p\n", data->schemadata);
2809 /* seen: -1: old data 0: skipped >0: id + 1 */
2813 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2817 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
2825 keyp = data->attrs ? data->attrs[entry] : 0;
2828 /* strip solvables key */
2830 for (sp = keyp = schema; *sp; sp++)
2831 if (*sp != solvkeyid)
2836 seen[solvkeyid] = 0;
2837 keyp = data->xattrs ? data->xattrs[1] : 0;
2840 for (; *keyp; keyp += 2)
2847 seen[*keyp] = keyp[1] + 1;
2849 if (entry < 0 && data->end != data->start)
2856 /* Ideally we'd like to sort the new schema here, to ensure
2857 schema equality independend of the ordering. We can't do that
2858 yet. For once see below (old ids need to come before new ids).
2859 An additional difficulty is that we also need to move
2860 the values with the keys. */
2861 schemaid = repodata_schema2id(data, schema, 1);
2863 schemaid = oldschema;
2866 /* Now create data blob. We walk through the (possibly new) schema
2867 and either copy over old data, or insert the new. */
2868 /* XXX Here we rely on the fact that the (new) schema has the form
2869 o1 o2 o3 o4 ... | n1 n2 n3 ...
2870 (oX being the old keyids (possibly overwritten), and nX being
2871 the new keyids). This rules out sorting the keyids in order
2872 to ensure a small schema count. */
2874 data->incoreoffset[entry] = newincore.len;
2875 data_addid(&newincore, schemaid);
2878 data->mainschema = schemaid;
2879 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
2881 keypstart = data->schemadata + data->schemata[schemaid];
2882 for (keyp = keypstart; *keyp; keyp++)
2885 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2886 if (*keyp == solvkeyid)
2888 /* add flexarray entry count */
2889 data_addid(&newincore, data->end - data->start);
2892 key = data->keys + *keyp;
2894 fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, pool_id2str(data->repo->pool, key->name), pool_id2str(data->repo->pool, key->type));
2899 /* Skip the data associated with this old key. */
2900 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2902 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2903 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2905 else if (key->storage == KEY_STORAGE_INCORE)
2906 ndp = data_skip_key(data, dp, key);
2909 if (seen[*keyp] == -1)
2911 /* If this key was an old one _and_ was not overwritten with
2912 a different value copy over the old value (we skipped it
2915 data_addblob(&newincore, dp, ndp - dp);
2918 else if (seen[*keyp])
2920 /* Otherwise we have a new value. Parse it into the internal
2922 repodata_serialize_key(data, &newincore, &newvincore,
2923 schema, key, seen[*keyp] - 1);
2927 if (entry >= 0 && data->attrs && data->attrs[entry])
2928 data->attrs[entry] = solv_free(data->attrs[entry]);
2930 /* free all xattrs */
2931 for (entry = 0; entry < data->nxattrs; entry++)
2932 if (data->xattrs[entry])
2933 solv_free(data->xattrs[entry]);
2934 data->xattrs = solv_free(data->xattrs);
2937 data->lasthandle = 0;
2939 data->lastdatalen = 0;
2942 repodata_free_schemahash(data);
2944 solv_free(data->incoredata);
2945 data->incoredata = newincore.buf;
2946 data->incoredatalen = newincore.len;
2947 data->incoredatafree = 0;
2949 solv_free(data->vincore);
2950 data->vincore = newvincore.buf;
2951 data->vincorelen = newvincore.len;
2953 data->attrs = solv_free(data->attrs);
2954 data->attrdata = solv_free(data->attrdata);
2955 data->attriddata = solv_free(data->attriddata);
2956 data->attrnum64data = solv_free(data->attrnum64data);
2957 data->attrdatalen = 0;
2958 data->attriddatalen = 0;
2959 data->attrnum64datalen = 0;
2963 repodata_disable_paging(Repodata *data)
2965 if (maybe_load_repodata(data, 0))
2966 repopagestore_disable_paging(&data->store);
2970 repodata_load_stub(Repodata *data)
2972 Repo *repo = data->repo;
2973 Pool *pool = repo->pool;
2975 struct _Pool_tmpspace oldtmpspace;
2977 if (!pool->loadcallback)
2979 data->state = REPODATA_ERROR;
2982 data->state = REPODATA_LOADING;
2984 /* save tmp space */
2985 oldtmpspace = pool->tmpspace;
2986 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
2988 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
2990 /* restore tmp space */
2991 for (i = 0; i < POOL_TMPSPACEBUF; i++)
2992 solv_free(pool->tmpspace.buf[i]);
2993 pool->tmpspace = oldtmpspace;
2995 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
2999 repodata_create_stubs(Repodata *data)
3001 Repo *repo = data->repo;
3002 Pool *pool = repo->pool;
3009 int datastart, dataend;
3011 repodataid = data - repo->repodata;
3012 datastart = data->start;
3013 dataend = data->end;
3014 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3015 while (dataiterator_step(&di))
3017 if (di.data - repo->repodata != repodataid)
3021 dataiterator_free(&di);
3024 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3025 for (i = 0; i < cnt; i++)
3027 sdata = repo_add_repodata(repo, 0);
3028 if (dataend > datastart)
3029 repodata_extend_block(sdata, datastart, dataend - datastart);
3030 stubdataids[i] = sdata - repo->repodata;
3031 sdata->state = REPODATA_STUB;
3032 sdata->loadcallback = repodata_load_stub;
3035 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3037 while (dataiterator_step(&di))
3039 if (di.data - repo->repodata != repodataid)
3041 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3043 dataiterator_entersub(&di);
3044 sdata = repo->repodata + stubdataids[i++];
3048 switch (di.key->type)
3050 case REPOKEY_TYPE_ID:
3051 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3053 case REPOKEY_TYPE_CONSTANTID:
3054 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3056 case REPOKEY_TYPE_STR:
3057 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3059 case REPOKEY_TYPE_VOID:
3060 repodata_set_void(sdata, SOLVID_META, di.key->name);
3062 case REPOKEY_TYPE_NUM:
3063 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3065 case REPOKEY_TYPE_MD5:
3066 case REPOKEY_TYPE_SHA1:
3067 case REPOKEY_TYPE_SHA256:
3068 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3070 case REPOKEY_TYPE_IDARRAY:
3071 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3072 if (di.key->name == REPOSITORY_KEYS)
3079 xkeyname = di.kv.id;
3082 xkey.name = xkeyname;
3083 xkey.type = di.kv.id;
3084 xkey.storage = KEY_STORAGE_INCORE;
3086 repodata_key2id(sdata, &xkey, 1);
3093 dataiterator_free(&di);
3094 for (i = 0; i < cnt; i++)
3095 repodata_internalize(repo->repodata + stubdataids[i]);
3096 solv_free(stubdataids);
3100 repodata_memused(Repodata *data)
3102 return data->incoredatalen + data->vincorelen;
3106 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: