2 * Copyright (c) 2018, SUSE LLC.
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"
41 #define REPODATA_BLOCK 255
43 static unsigned char *data_skip_key(Repodata *data, unsigned char *dp, Repokey *key);
46 repodata_initdata(Repodata *data, Repo *repo, int localpool)
48 memset(data, 0, sizeof (*data));
49 data->repodataid = data - repo->repodata;
51 data->localpool = localpool;
53 stringpool_init_empty(&data->spool);
54 /* dirpool_init(&data->dirpool); just zeros out again */
55 data->keys = solv_calloc(1, sizeof(Repokey));
57 data->schemata = solv_calloc(1, sizeof(Id));
58 data->schemadata = solv_calloc(1, sizeof(Id));
60 data->schemadatalen = 1;
61 repopagestore_init(&data->store);
65 repodata_freedata(Repodata *data)
69 solv_free(data->keys);
71 solv_free(data->schemata);
72 solv_free(data->schemadata);
73 solv_free(data->schematahash);
75 stringpool_free(&data->spool);
76 dirpool_free(&data->dirpool);
78 solv_free(data->mainschemaoffsets);
79 solv_free(data->incoredata);
80 solv_free(data->incoreoffset);
81 solv_free(data->verticaloffset);
83 repopagestore_free(&data->store);
85 solv_free(data->vincore);
88 for (i = 0; i < data->end - data->start; i++)
89 solv_free(data->attrs[i]);
90 solv_free(data->attrs);
92 for (i = 0; i < data->nxattrs; i++)
93 solv_free(data->xattrs[i]);
94 solv_free(data->xattrs);
96 solv_free(data->attrdata);
97 solv_free(data->attriddata);
98 solv_free(data->attrnum64data);
100 solv_free(data->dircache);
102 repodata_free_filelistfilter(data);
106 repodata_free(Repodata *data)
108 Repo *repo = data->repo;
109 int i = data - repo->repodata;
112 repodata_freedata(data);
113 if (i < repo->nrepodata - 1)
115 /* whoa! this changes the repodataids! */
116 memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
117 for (; i < repo->nrepodata - 1; i++)
118 repo->repodata[i].repodataid = i;
121 if (repo->nrepodata == 1)
123 repo->repodata = solv_free(repo->repodata);
129 repodata_empty(Repodata *data, int localpool)
131 void (*loadcallback)(Repodata *) = data->loadcallback;
132 int state = data->state;
133 repodata_freedata(data);
134 repodata_initdata(data, data->repo, localpool);
136 data->loadcallback = loadcallback;
140 /***************************************************************
141 * key pool management
144 /* this is not so time critical that we need a hash, so we do a simple
147 repodata_key2id(Repodata *data, Repokey *key, int create)
151 for (keyid = 1; keyid < data->nkeys; keyid++)
152 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
154 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
158 if (keyid == data->nkeys)
162 /* allocate new key */
163 data->keys = solv_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
164 data->keys[data->nkeys++] = *key;
165 if (data->verticaloffset)
167 data->verticaloffset = solv_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
168 data->verticaloffset[data->nkeys - 1] = 0;
170 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
176 /***************************************************************
177 * schema pool management
180 #define SCHEMATA_BLOCK 31
181 #define SCHEMATADATA_BLOCK 255
184 repodata_schema2id(Repodata *data, Id *schema, int create)
191 return 0; /* XXX: allow empty schema? */
192 if ((schematahash = data->schematahash) == 0)
194 data->schematahash = schematahash = solv_calloc(256, sizeof(Id));
195 for (i = 1; i < data->nschemata; i++)
197 for (sp = data->schemadata + data->schemata[i], h = 0; *sp;)
202 data->schemadata = solv_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
203 data->schemata = solv_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
206 for (sp = schema, len = 0, h = 0; *sp; len++)
211 cid = schematahash[h];
214 if ((data->schemata[cid] + len <= data->schemadatalen) &&
215 !memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
217 /* cache conflict, do a slow search */
218 for (cid = 1; cid < data->nschemata; cid++)
219 if ((data->schemata[cid] + len <= data->schemadatalen) &&
220 !memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
226 data->schemadata = solv_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
227 data->schemata = solv_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
229 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
230 data->schemata[data->nschemata] = data->schemadatalen;
231 data->schemadatalen += len;
232 schematahash[h] = data->nschemata;
234 fprintf(stderr, "schema2id: new schema\n");
236 return data->nschemata++;
240 repodata_free_schemahash(Repodata *data)
242 data->schematahash = solv_free(data->schematahash);
244 data->schemata = solv_realloc2(data->schemata, data->nschemata, sizeof(Id));
245 data->schemadata = solv_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
249 /***************************************************************
250 * dir pool management
253 #ifndef HAVE_STRCHRNUL
254 static inline const char *strchrnul(const char *str, char x)
256 const char *p = strchr(str, x);
257 return p ? p : str + strlen(str);
261 #define DIRCACHE_SIZE 41 /* < 1k */
265 Id ids[DIRCACHE_SIZE];
266 char str[(DIRCACHE_SIZE * (DIRCACHE_SIZE - 1)) / 2];
271 repodata_str2dir(Repodata *data, const char *dir, int create)
280 return data->dirpool.ndirs ? 0 : dirpool_add_dir(&data->dirpool, 0, 0, create);
281 while (*dir == '/' && dir[1] == '/')
283 if (*dir == '/' && !dir[1])
284 return data->dirpool.ndirs ? 1 : dirpool_add_dir(&data->dirpool, 0, 1, create);
291 struct dircache *dircache = data->dircache;
295 if (l < DIRCACHE_SIZE && dircache->ids[l] && !memcmp(dircache->str + l * (l - 1) / 2, dir, l))
297 parent = dircache->ids[l];
313 dire = strchrnul(dir, '/');
315 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
317 id = pool_strn2id(data->repo->pool, dir, dire - dir, create);
320 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
325 data->dircache = solv_calloc(1, sizeof(struct dircache));
329 if (l < DIRCACHE_SIZE)
331 data->dircache->ids[l] = parent;
332 memcpy(data->dircache->str + l * (l - 1) / 2, dirs, l);
346 repodata_free_dircache(Repodata *data)
348 data->dircache = solv_free(data->dircache);
352 repodata_dir2str(Repodata *data, Id did, const char *suf)
354 Pool *pool = data->repo->pool;
361 return suf ? suf : "";
362 if (did == 1 && !suf)
367 comp = dirpool_compid(&data->dirpool, parent);
368 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
370 parent = dirpool_parent(&data->dirpool, parent);
375 l += strlen(suf) + 1;
376 p = pool_alloctmpspace(pool, l + 1) + l;
387 comp = dirpool_compid(&data->dirpool, parent);
388 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
391 strncpy(p, comps, l);
392 parent = dirpool_parent(&data->dirpool, parent);
400 /***************************************************************
404 static inline unsigned char *
405 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
407 Id *keyp = data->schemadata + data->schemata[schema];
408 for (; *keyp; keyp++)
409 dp = data_skip_key(data, dp, data->keys + *keyp);
413 static unsigned char *
414 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
416 int nentries, schema;
419 case REPOKEY_TYPE_FIXARRAY:
420 dp = data_read_id(dp, &nentries);
423 dp = data_read_id(dp, &schema);
425 dp = data_skip_schema(data, dp, schema);
427 case REPOKEY_TYPE_FLEXARRAY:
428 dp = data_read_id(dp, &nentries);
431 dp = data_read_id(dp, &schema);
432 dp = data_skip_schema(data, dp, schema);
436 if (key->storage == KEY_STORAGE_INCORE)
437 dp = data_skip(dp, key->type);
438 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
440 dp = data_skip(dp, REPOKEY_TYPE_ID);
441 dp = data_skip(dp, REPOKEY_TYPE_ID);
447 static unsigned char *
448 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
454 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
457 for (i = 0; (k = *keyp++) != 0; i++)
459 return data->incoredata + data->mainschemaoffsets[i];
462 while ((k = *keyp++) != 0)
466 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
468 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
469 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
472 if (data->keys[k].storage != KEY_STORAGE_INCORE)
474 dp = data_skip_key(data, dp, data->keys + k);
479 static unsigned char *
480 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
485 if (off >= data->lastverticaloffset)
487 off -= data->lastverticaloffset;
488 if ((unsigned int)off + len > data->vincorelen)
490 return data->vincore + off;
492 if ((unsigned int)off + len > key->size)
494 /* we now have the offset, go into vertical */
495 off += data->verticaloffset[key - data->keys];
496 /* fprintf(stderr, "key %d page %d\n", key->name, off / REPOPAGE_BLOBSIZE); */
497 dp = repopagestore_load_page_range(&data->store, off / REPOPAGE_BLOBSIZE, (off + len - 1) / REPOPAGE_BLOBSIZE);
500 dp += off % REPOPAGE_BLOBSIZE;
504 static inline unsigned char *
505 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
507 unsigned char *dp = *dpp;
511 if (key->storage == KEY_STORAGE_INCORE)
514 *dpp = data_skip_key(data, dp, key);
517 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
520 dp = data_read_id(dp, &off);
521 dp = data_read_id(dp, &len);
524 return get_vertical_data(data, key, off, len);
530 repodata_load(Repodata *data)
532 if (data->state != REPODATA_STUB)
534 if (data->loadcallback)
535 data->loadcallback(data);
537 data->state = REPODATA_ERROR;
541 maybe_load_repodata_stub(Repodata *data, Id keyname)
543 if (data->state != REPODATA_STUB)
545 data->state = REPODATA_ERROR;
551 for (i = 1; i < data->nkeys; i++)
552 if (keyname == data->keys[i].name)
554 if (i == data->nkeys)
558 return data->state == REPODATA_AVAILABLE ? 1 : 0;
562 maybe_load_repodata(Repodata *data, Id keyname)
564 if (keyname && !repodata_precheck_keyname(data, keyname))
565 return 0; /* do not bother... */
566 if (data->state == REPODATA_AVAILABLE || data->state == REPODATA_LOADING)
568 if (data->state == REPODATA_ERROR)
570 return maybe_load_repodata_stub(data, keyname);
573 static inline unsigned char *
574 solvid2data(Repodata *data, Id solvid, Id *schemap)
576 unsigned char *dp = data->incoredata;
579 if (solvid == SOLVID_META)
580 dp += 1; /* offset of "meta" solvable */
581 else if (solvid == SOLVID_POS)
583 Pool *pool = data->repo->pool;
584 if (data->repo != pool->pos.repo)
586 if (data != data->repo->repodata + pool->pos.repodataid)
589 if (pool->pos.dp != 1)
591 *schemap = pool->pos.schema;
597 if (solvid < data->start || solvid >= data->end)
599 dp += data->incoreoffset[solvid - data->start];
601 return data_read_id(dp, schemap);
604 /************************************************************************
608 static unsigned char *
609 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
612 Id schema, *keyp, *kp;
615 if (!maybe_load_repodata(data, keyname))
617 dp = solvid2data(data, solvid, &schema);
620 keyp = data->schemadata + data->schemata[schema];
621 for (kp = keyp; *kp; kp++)
622 if (data->keys[*kp].name == keyname)
626 *keypp = key = data->keys + *kp;
627 if (key->type == REPOKEY_TYPE_DELETED)
629 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
630 return dp; /* no need to forward... */
631 if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
632 return 0; /* get_data will not work, no need to forward */
633 dp = forward_to_key(data, *kp, keyp, dp);
636 return get_data(data, key, &dp, 0);
640 repodata_lookup_schemakeys(Repodata *data, Id solvid)
643 if (!maybe_load_repodata(data, 0))
645 if (!solvid2data(data, solvid, &schema))
647 return data->schemadata + data->schemata[schema];
653 Id *keyskip = solv_calloc(3 + 256, sizeof(Id));
655 keyskip[1] = keyskip[2] = 1;
660 repodata_fill_keyskip(Repodata *data, Id solvid, Id *keyskip)
663 Id maxkeyname, value;
664 keyp = repodata_lookup_schemakeys(data, solvid);
666 return keyskip; /* no keys for this solvid */
668 keyskip = alloc_keyskip();
669 maxkeyname = keyskip[0];
670 value = keyskip[1] + data->repodataid;
671 for (; *keyp; keyp++)
673 Id keyname = data->keys[*keyp].name;
674 if (keyname >= maxkeyname)
676 int newmax = (keyname | 255) + 1;
677 keyskip = solv_realloc2(keyskip, 3 + newmax, sizeof(Id));
678 memset(keyskip + (3 + maxkeyname), 0, (newmax - maxkeyname) * sizeof(Id));
679 keyskip[0] = maxkeyname = newmax;
681 keyskip[3 + keyname] = value;
687 repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
689 Id schema, *keyp, *kp;
690 if (!maybe_load_repodata(data, keyname))
692 if (!solvid2data(data, solvid, &schema))
694 keyp = data->schemadata + data->schemata[schema];
695 for (kp = keyp; *kp; kp++)
696 if (data->keys[*kp].name == keyname)
697 return data->keys[*kp].type;
702 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
708 dp = find_key_data(data, solvid, keyname, &key);
711 if (key->type == REPOKEY_TYPE_CONSTANTID)
713 if (key->type != REPOKEY_TYPE_ID)
715 dp = data_read_id(dp, &id);
720 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
726 dp = find_key_data(data, solvid, keyname, &key);
729 if (key->type == REPOKEY_TYPE_STR)
730 return (const char *)dp;
731 if (key->type == REPOKEY_TYPE_CONSTANTID)
733 else if (key->type == REPOKEY_TYPE_ID)
734 dp = data_read_id(dp, &id);
738 return stringpool_id2str(&data->spool, id);
739 return pool_id2str(data->repo->pool, id);
743 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long notfound)
747 unsigned int high, low;
749 dp = find_key_data(data, solvid, keyname, &key);
754 case REPOKEY_TYPE_NUM:
755 data_read_num64(dp, &low, &high);
756 return (unsigned long long)high << 32 | low;
757 case REPOKEY_TYPE_CONSTANT:
765 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
767 return repodata_lookup_type(data, solvid, keyname) == REPOKEY_TYPE_VOID ? 1 : 0;
770 const unsigned char *
771 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
776 dp = find_key_data(data, solvid, keyname, &key);
791 repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
799 dp = find_key_data(data, solvid, keyname, &key);
804 case REPOKEY_TYPE_CONSTANTID:
805 queue_push(q, key->size);
807 case REPOKEY_TYPE_ID:
808 dp = data_read_id(dp, &id);
811 case REPOKEY_TYPE_IDARRAY:
814 dp = data_read_ideof(dp, &id, &eof);
827 repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp)
833 dp = find_key_data(data, solvid, keyname, &key);
834 if (!dp || key->type != REPOKEY_TYPE_BINARY)
839 dp = data_read_id(dp, &len);
844 /* highly specialized function to speed up fileprovides adding.
845 * - repodata must be available
846 * - solvid must be >= data->start and < data->end
847 * - returns NULL is not found, a "" entry if wrong type
848 * - also returns wrong type for REPOKEY_TYPE_DELETED
850 const unsigned char *
851 repodata_lookup_packed_dirstrarray(Repodata *data, Id solvid, Id keyname)
853 static unsigned char wrongtype[2] = { 0x00 /* dir id 0 */, 0 /* "" */ };
855 Id schema, *keyp, *kp;
858 if (!data->incoredata || !data->incoreoffset[solvid - data->start])
860 dp = data->incoredata + data->incoreoffset[solvid - data->start];
861 dp = data_read_id(dp, &schema);
862 keyp = data->schemadata + data->schemata[schema];
863 for (kp = keyp; *kp; kp++)
864 if (data->keys[*kp].name == keyname)
868 key = data->keys + *kp;
869 if (key->type != REPOKEY_TYPE_DIRSTRARRAY)
871 dp = forward_to_key(data, *kp, keyp, dp);
872 if (key->storage == KEY_STORAGE_INCORE)
874 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET && dp)
877 dp = data_read_id(dp, &off);
878 data_read_id(dp, &len);
879 return get_vertical_data(data, key, off, len);
884 /* id translation functions */
887 repodata_globalize_id(Repodata *data, Id id, int create)
889 if (!id || !data || !data->localpool)
891 return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
895 repodata_localize_id(Repodata *data, Id id, int create)
897 if (!id || !data || !data->localpool)
899 return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
903 repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create)
906 if (!id || !data || !fromdata)
908 if (data == fromdata || (!data->localpool && !fromdata->localpool))
910 if (fromdata->localpool)
911 s = stringpool_id2str(&fromdata->spool, id);
913 s = pool_id2str(data->repo->pool, id);
915 return stringpool_str2id(&data->spool, s, create);
917 return pool_str2id(data->repo->pool, s, create);
921 repodata_translate_dir_slow(Repodata *data, Repodata *fromdata, Id dir, int create, Id *cache)
926 /* make sure that the dirpool has an entry */
927 if (create && !data->dirpool.ndirs)
928 dirpool_add_dir(&data->dirpool, 0, 0, create);
931 parent = dirpool_parent(&fromdata->dirpool, dir);
934 if (!(parent = repodata_translate_dir(data, fromdata, parent, create, cache)))
937 compid = dirpool_compid(&fromdata->dirpool, dir);
938 if (compid > 1 && (data->localpool || fromdata->localpool))
940 if (!(compid = repodata_translate_id(data, fromdata, compid, create)))
943 if (!(compid = dirpool_add_dir(&data->dirpool, parent, compid, create)))
947 cache[(dir & 255) * 2] = dir;
948 cache[(dir & 255) * 2 + 1] = compid;
953 /************************************************************************
954 * uninternalized lookup / search
958 data_fetch_uninternalized(Repodata *data, Repokey *key, Id value, KeyValue *kv)
964 case REPOKEY_TYPE_STR:
965 kv->str = (const char *)data->attrdata + value;
967 case REPOKEY_TYPE_CONSTANT:
971 case REPOKEY_TYPE_CONSTANTID:
974 case REPOKEY_TYPE_NUM:
977 if (value & 0x80000000)
979 kv->num = (unsigned int)data->attrnum64data[value ^ 0x80000000];
980 kv->num2 = (unsigned int)(data->attrnum64data[value ^ 0x80000000] >> 32);
984 kv->num = 0; /* not stringified */
985 kv->str = (const char *)data->attrdata + value;
987 case REPOKEY_TYPE_BINARY:
988 kv->str = (const char *)data_read_id(data->attrdata + value, (Id *)&kv->num);
990 case REPOKEY_TYPE_IDARRAY:
991 array = data->attriddata + (value + kv->entry);
993 kv->eof = array[1] ? 0 : 1;
995 case REPOKEY_TYPE_DIRSTRARRAY:
996 kv->num = 0; /* not stringified */
997 array = data->attriddata + (value + kv->entry * 2);
999 kv->str = (const char *)data->attrdata + array[1];
1000 kv->eof = array[2] ? 0 : 1;
1002 case REPOKEY_TYPE_DIRNUMNUMARRAY:
1003 array = data->attriddata + (value + kv->entry * 3);
1006 kv->num2 = array[2];
1007 kv->eof = array[3] ? 0 : 1;
1009 case REPOKEY_TYPE_FIXARRAY:
1010 case REPOKEY_TYPE_FLEXARRAY:
1011 array = data->attriddata + (value + kv->entry);
1012 kv->id = array[0]; /* the handle */
1013 kv->eof = array[1] ? 0 : 1;
1022 repodata_lookup_kv_uninternalized(Repodata *data, Id solvid, Id keyname, KeyValue *kv)
1025 if (!data->attrs || solvid < data->start || solvid >= data->end)
1027 ap = data->attrs[solvid - data->start];
1030 for (; *ap; ap += 2)
1032 Repokey *key = data->keys + *ap;
1033 if (key->name != keyname)
1035 data_fetch_uninternalized(data, key, ap[1], kv);
1042 repodata_search_uninternalized(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
1049 if (!data->attrs || solvid < data->start || solvid >= data->end)
1051 ap = data->attrs[solvid - data->start];
1054 for (; *ap; ap += 2)
1056 Repokey *key = data->keys + *ap;
1057 if (keyname && key->name != keyname)
1059 s = solvid > 0 ? data->repo->pool->solvables + solvid : 0;
1063 data_fetch_uninternalized(data, key, ap[1], &kv);
1064 stop = callback(cbdata, s, data, key, &kv);
1067 while (!kv.eof && !stop);
1068 if (keyname || stop > SEARCH_NEXT_KEY)
1073 /************************************************************************
1079 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
1083 case REPOKEY_TYPE_ID:
1084 case REPOKEY_TYPE_CONSTANTID:
1085 case REPOKEY_TYPE_IDARRAY:
1086 if (data && data->localpool)
1087 kv->str = stringpool_id2str(&data->spool, kv->id);
1089 kv->str = pool_id2str(pool, kv->id);
1090 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE && (key->name == SOLVABLE_NAME || key->type == REPOKEY_TYPE_IDARRAY))
1093 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
1095 if (*s == ':' && s > kv->str)
1099 case REPOKEY_TYPE_STR:
1101 case REPOKEY_TYPE_DIRSTRARRAY:
1102 if (!(flags & SEARCH_FILES))
1103 return kv->str; /* match just the basename */
1105 return kv->str; /* already stringified */
1106 /* Put the full filename into kv->str. */
1107 kv->str = repodata_dir2str(data, kv->id, kv->str);
1108 kv->num = 1; /* mark stringification */
1111 if (!(flags & SEARCH_CHECKSUMS))
1112 return 0; /* skip em */
1114 return kv->str; /* already stringified */
1115 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
1116 kv->num = 1; /* mark stringification */
1124 /* this is an internal hack to pass the parent kv to repodata_search_keyskip */
1125 struct subschema_data {
1132 repodata_search_arrayelement(Repodata *data, Id solvid, Id keyname, int flags, KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
1134 repodata_search_keyskip(data, solvid, keyname, flags | SEARCH_SUBSCHEMA, (Id *)kv, callback, cbdata);
1138 repodata_search_array(Repodata *data, Id solvid, Id keyname, int flags, Repokey *key, KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
1140 Solvable *s = solvid > 0 ? data->repo->pool->solvables + solvid : 0;
1141 unsigned char *dp = (unsigned char *)kv->str;
1145 if (!dp || kv->entry != -1)
1147 while (++kv->entry < (int)kv->num)
1150 dp = data_skip_schema(data, dp, schema);
1151 if (kv->entry == 0 || key->type == REPOKEY_TYPE_FLEXARRAY)
1152 dp = data_read_id(dp, &schema);
1154 kv->str = (const char *)dp;
1155 kv->eof = kv->entry == kv->num - 1 ? 1 : 0;
1156 stop = callback(cbdata, s, data, key, kv);
1157 if (stop && stop != SEARCH_ENTERSUB)
1159 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
1160 repodata_search_keyskip(data, solvid, keyname, flags | SEARCH_SUBSCHEMA, (Id *)kv, callback, cbdata);
1162 if ((flags & SEARCH_ARRAYSENTINEL) != 0)
1165 dp = data_skip_schema(data, dp, schema);
1167 kv->str = (const char *)dp;
1169 return callback(cbdata, s, data, key, kv);
1174 /* search a specific repodata */
1176 repodata_search_keyskip(Repodata *data, Id solvid, Id keyname, int flags, Id *keyskip, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
1180 Id keyid, *kp, *keyp;
1181 unsigned char *dp, *ddp;
1187 if (!maybe_load_repodata(data, keyname))
1189 if ((flags & SEARCH_SUBSCHEMA) != 0)
1191 flags ^= SEARCH_SUBSCHEMA;
1192 kv.parent = (KeyValue *)keyskip;
1194 schema = kv.parent->id;
1195 dp = (unsigned char *)kv.parent->str;
1200 dp = solvid2data(data, solvid, &schema);
1205 s = solvid > 0 ? data->repo->pool->solvables + solvid : 0;
1206 keyp = data->schemadata + data->schemata[schema];
1209 /* search for a specific key */
1210 for (kp = keyp; *kp; kp++)
1211 if (data->keys[*kp].name == keyname)
1215 dp = forward_to_key(data, *kp, keyp, dp);
1221 while ((keyid = *keyp++) != 0)
1224 key = data->keys + keyid;
1225 ddp = get_data(data, key, &dp, *keyp && !onekey ? 1 : 0);
1227 if (keyskip && (key->name >= keyskip[0] || keyskip[3 + key->name] != keyskip[1] + data->repodataid))
1233 if (key->type == REPOKEY_TYPE_DELETED && !(flags & SEARCH_KEEP_TYPE_DELETED))
1239 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
1242 ddp = data_read_id(ddp, (Id *)&kv.num);
1243 kv.str = (const char *)ddp;
1244 stop = repodata_search_array(data, solvid, 0, flags, key, &kv, callback, cbdata);
1245 if (onekey || stop > SEARCH_NEXT_KEY)
1252 ddp = data_fetch(ddp, &kv, key);
1255 stop = callback(cbdata, s, data, key, &kv);
1258 while (!kv.eof && !stop);
1259 if (onekey || stop > SEARCH_NEXT_KEY)
1265 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
1267 repodata_search_keyskip(data, solvid, keyname, flags, 0, callback, cbdata);
1271 repodata_setpos_kv(Repodata *data, KeyValue *kv)
1273 Pool *pool = data->repo->pool;
1275 pool_clear_pos(pool);
1278 pool->pos.repo = data->repo;
1279 pool->pos.repodataid = data - data->repo->repodata;
1280 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
1281 pool->pos.schema = kv->id;
1285 /************************************************************************
1286 * data iterator functions
1290 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
1304 case SOLVABLE_VENDOR:
1307 case SOLVABLE_PROVIDES:
1309 return s->provides ? s->repo->idarraydata + s->provides : 0;
1310 case SOLVABLE_OBSOLETES:
1312 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
1313 case SOLVABLE_CONFLICTS:
1315 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
1316 case SOLVABLE_REQUIRES:
1318 return s->requires ? s->repo->idarraydata + s->requires : 0;
1319 case SOLVABLE_RECOMMENDS:
1321 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
1322 case SOLVABLE_SUPPLEMENTS:
1324 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
1325 case SOLVABLE_SUGGESTS:
1327 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
1328 case SOLVABLE_ENHANCES:
1330 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
1333 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
1340 datamatcher_init(Datamatcher *ma, const char *match, int flags)
1342 match = match ? solv_strdup(match) : 0;
1347 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1349 ma->matchdata = solv_calloc(1, sizeof(regex_t));
1350 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1353 solv_free(ma->matchdata);
1354 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
1357 if ((flags & SEARCH_FILES) != 0 && match)
1359 /* prepare basename check */
1360 if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
1362 const char *p = strrchr(match, '/');
1363 ma->matchdata = (void *)(p ? p + 1 : match);
1365 else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
1368 for (p = match + strlen(match) - 1; p >= match; p--)
1369 if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
1371 ma->matchdata = (void *)(p + 1);
1378 datamatcher_free(Datamatcher *ma)
1381 ma->match = solv_free((char *)ma->match);
1382 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1384 regfree(ma->matchdata);
1385 solv_free(ma->matchdata);
1391 datamatcher_match(Datamatcher *ma, const char *str)
1394 switch ((ma->flags & SEARCH_STRINGMASK))
1396 case SEARCH_SUBSTRING:
1397 if (ma->flags & SEARCH_NOCASE)
1398 return strcasestr(str, ma->match) != 0;
1400 return strstr(str, ma->match) != 0;
1402 if (ma->flags & SEARCH_NOCASE)
1403 return !strcasecmp(ma->match, str);
1405 return !strcmp(ma->match, str);
1406 case SEARCH_STRINGSTART:
1407 if (ma->flags & SEARCH_NOCASE)
1408 return !strncasecmp(ma->match, str, strlen(ma->match));
1410 return !strncmp(ma->match, str, strlen(ma->match));
1411 case SEARCH_STRINGEND:
1412 l = strlen(str) - strlen(ma->match);
1415 if (ma->flags & SEARCH_NOCASE)
1416 return !strcasecmp(ma->match, str + l);
1418 return !strcmp(ma->match, str + l);
1420 return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
1422 return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
1428 /* check if the matcher can match the provides basename */
1431 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1434 const char *match = ma->matchdata;
1437 switch (ma->flags & SEARCH_STRINGMASK)
1441 case SEARCH_STRINGEND:
1442 if (match != ma->match)
1443 break; /* had slash, do exact match on basename */
1446 /* check if the basename ends with match */
1447 l = strlen(basename) - strlen(match);
1453 return 1; /* maybe matches */
1455 if ((ma->flags & SEARCH_NOCASE) != 0)
1456 return !strcasecmp(match, basename);
1458 return !strcmp(match, basename);
1477 di_nextarrayelement,
1483 di_entersolvablekey,
1487 /* see dataiterator.h for documentation */
1489 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1491 memset(di, 0, sizeof(*di));
1493 di->flags = flags & ~SEARCH_THISSOLVID;
1494 if (!pool || (repo && repo->pool != pool))
1502 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1508 di->keyname = keyname;
1509 di->keynames[0] = keyname;
1510 dataiterator_set_search(di, repo, p);
1515 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1520 if (di->dupstr == di->kv.str)
1521 di->dupstr = solv_memdup(di->dupstr, di->dupstrn);
1528 memset(&di->matcher, 0, sizeof(di->matcher));
1529 if (from->matcher.match)
1530 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1535 for (i = 1; i < di->nparents; i++)
1536 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1537 di->kv.parent = &di->parents[di->nparents - 1].kv;
1540 di->oldkeyskip = solv_memdup2(di->oldkeyskip, 3 + di->oldkeyskip[0], sizeof(Id));
1542 di->keyskip = di->oldkeyskip;
1546 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1548 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1549 datamatcher_free(&di->matcher);
1550 memset(&di->matcher, 0, sizeof(di->matcher));
1554 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1564 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1568 di->flags &= ~SEARCH_THISSOLVID;
1572 if (!di->pool->urepos)
1580 di->repo = di->pool->repos[di->repoid];
1582 di->state = di_enterrepo;
1584 dataiterator_jump_to_solvid(di, p);
1588 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1591 di->keyname = keyname;
1592 di->keynames[0] = keyname;
1596 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1600 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1602 di->state = di_bye; /* sorry */
1605 for (i = di->nkeynames + 1; i > 0; i--)
1606 di->keynames[i] = di->keynames[i - 1];
1607 di->keynames[0] = di->keyname = keyname;
1612 dataiterator_free(Dataiterator *di)
1614 if (di->matcher.match)
1615 datamatcher_free(&di->matcher);
1617 solv_free(di->dupstr);
1619 solv_free(di->oldkeyskip);
1622 static unsigned char *
1623 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1626 Repokey *keys = di->data->keys, *key;
1629 for (keyp = di->keyp; *keyp; keyp++)
1630 if (keys[*keyp].name == keyname)
1635 if (key->type == REPOKEY_TYPE_DELETED)
1637 if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
1638 return 0; /* get_data will not work, no need to forward */
1639 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1647 dataiterator_step(Dataiterator *di)
1651 if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate)
1653 unsigned int ddpoff = di->ddp - di->vert_ddp;
1654 di->vert_off += ddpoff;
1655 di->vert_len -= ddpoff;
1656 di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
1657 di->vert_storestate = di->data->storestate;
1659 di->state = di_nextkey;
1665 case di_enterrepo: di_enterrepo:
1666 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1668 if (!(di->flags & SEARCH_THISSOLVID))
1670 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1671 goto di_nextsolvable;
1675 case di_entersolvable: di_entersolvable:
1676 if (!di->repodataid)
1677 goto di_enterrepodata; /* POS case, repodata is set */
1678 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)
1680 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1681 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1683 goto di_entersolvablekey;
1688 di->data = di->keyname == SOLVABLE_FILELIST ? repo_lookup_filelist_repodata(di->repo, di->solvid, &di->matcher) : repo_lookup_repodata_opt(di->repo, di->solvid, di->keyname);
1690 goto di_nextsolvable;
1691 di->repodataid = di->data - di->repo->repodata;
1693 goto di_enterrepodata;
1695 di_leavesolvablekey:
1696 di->repodataid = 1; /* reset repodata iterator */
1697 di->keyskip = repo_create_keyskip(di->repo, di->solvid, &di->oldkeyskip);
1700 case di_enterrepodata: di_enterrepodata:
1703 if (di->repodataid >= di->repo->nrepodata)
1704 goto di_nextsolvable;
1705 di->data = di->repo->repodata + di->repodataid;
1707 if (!maybe_load_repodata(di->data, di->keyname))
1708 goto di_nextrepodata;
1709 di->dp = solvid2data(di->data, di->solvid, &schema);
1711 goto di_nextrepodata;
1712 if (di->solvid == SOLVID_POS)
1713 di->solvid = di->pool->pos.solvid;
1714 /* reset key iterator */
1715 di->keyp = di->data->schemadata + di->data->schemata[schema];
1718 case di_enterschema: di_enterschema:
1720 di->dp = dataiterator_find_keyname(di, di->keyname);
1721 if (!di->dp || !*di->keyp)
1725 goto di_nextrepodata;
1729 case di_enterkey: di_enterkey:
1731 di->key = di->data->keys + *di->keyp;
1734 /* this is get_data() modified to store vert_ data */
1735 if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1738 di->dp = data_read_id(di->dp, &off);
1739 di->dp = data_read_id(di->dp, &len);
1740 di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
1743 di->vert_storestate = di->data->storestate;
1745 else if (di->key->storage == KEY_STORAGE_INCORE)
1747 di->ddp = di->dp; /* start of data */
1748 if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
1749 di->dp = data_skip_key(di->data, di->dp, di->key); /* advance to next key */
1755 if (di->keyskip && (di->key->name >= di->keyskip[0] || di->keyskip[3 + di->key->name] != di->keyskip[1] + di->data->repodataid))
1757 if (di->key->type == REPOKEY_TYPE_DELETED && !(di->flags & SEARCH_KEEP_TYPE_DELETED))
1759 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1761 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1767 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1768 di->state = di->kv.eof ? di_nextkey : di_nextattr;
1771 case di_nextkey: di_nextkey:
1772 if (!di->keyname && *++di->keyp)
1778 case di_nextrepodata: di_nextrepodata:
1779 if (!di->keyname && di->repodataid && ++di->repodataid < di->repo->nrepodata)
1780 goto di_enterrepodata;
1783 case di_nextsolvable: di_nextsolvable:
1784 if (!(di->flags & SEARCH_THISSOLVID))
1787 di->solvid = di->repo->start;
1790 for (; di->solvid < di->repo->end; di->solvid++)
1792 if (di->pool->solvables[di->solvid].repo == di->repo)
1793 goto di_entersolvable;
1798 case di_nextrepo: di_nextrepo:
1803 if (di->repoid < di->pool->nrepos)
1805 di->repo = di->pool->repos[di->repoid];
1811 case di_bye: di_bye:
1815 case di_enterarray: di_enterarray:
1816 if (di->key->name == REPOSITORY_SOLVABLES)
1818 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1823 case di_nextarrayelement: di_nextarrayelement:
1826 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1827 if (di->kv.entry == di->kv.num)
1829 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1831 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1833 di->kv.str = (char *)di->ddp;
1835 di->state = di_nextkey;
1838 if (di->kv.entry == di->kv.num - 1)
1840 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1841 di->ddp = data_read_id(di->ddp, &di->kv.id);
1842 di->kv.str = (char *)di->ddp;
1843 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1845 if ((di->flags & SEARCH_SUB) != 0)
1846 di->state = di_entersub;
1848 di->state = di_nextarrayelement;
1851 case di_entersub: di_entersub:
1852 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1853 goto di_nextarrayelement; /* sorry, full */
1854 di->parents[di->nparents].kv = di->kv;
1855 di->parents[di->nparents].dp = di->dp;
1856 di->parents[di->nparents].keyp = di->keyp;
1857 di->dp = (unsigned char *)di->kv.str;
1858 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1859 memset(&di->kv, 0, sizeof(di->kv));
1860 di->kv.parent = &di->parents[di->nparents].kv;
1862 di->keyname = di->keynames[di->nparents - di->rootlevel];
1863 goto di_enterschema;
1865 case di_leavesub: di_leavesub:
1866 if (di->nparents - 1 < di->rootlevel)
1869 di->dp = di->parents[di->nparents].dp;
1870 di->kv = di->parents[di->nparents].kv;
1871 di->keyp = di->parents[di->nparents].keyp;
1872 di->key = di->data->keys + *di->keyp;
1873 di->ddp = (unsigned char *)di->kv.str;
1874 di->keyname = di->keynames[di->nparents - di->rootlevel];
1875 goto di_nextarrayelement;
1877 /* special solvable attr handling follows */
1879 case di_nextsolvablekey: di_nextsolvablekey:
1881 goto di_nextsolvable;
1882 if (di->key->name == RPM_RPMDBID) /* reached end of list? */
1883 goto di_leavesolvablekey;
1887 case di_entersolvablekey: di_entersolvablekey:
1888 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1889 if (!di->idp || !*di->idp)
1890 goto di_nextsolvablekey;
1894 di->kv.id = *di->idp;
1895 di->kv.num = *di->idp; /* for rpmdbid */
1896 di->kv.num2 = 0; /* for rpmdbid */
1898 di->state = di_nextsolvablekey;
1904 case di_nextsolvableattr:
1905 di->state = di_nextsolvableattr;
1906 di->kv.id = *di->idp++;
1911 di->state = di_nextsolvablekey;
1917 /* we have a potential match */
1918 if (di->matcher.match)
1921 /* simple pre-check so that we don't need to stringify */
1922 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1923 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1925 /* now stringify so that we can do the matching */
1926 if (!(str = repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags)))
1928 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1932 if (!datamatcher_match(&di->matcher, str))
1937 /* stringify filelist if requested */
1938 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1939 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1941 /* found something! */
1947 dataiterator_entersub(Dataiterator *di)
1949 if (di->state == di_nextarrayelement)
1950 di->state = di_entersub;
1954 dataiterator_setpos(Dataiterator *di)
1956 if (di->kv.eof == 2)
1958 pool_clear_pos(di->pool);
1961 di->pool->pos.solvid = di->solvid;
1962 di->pool->pos.repo = di->repo;
1963 di->pool->pos.repodataid = di->data - di->repo->repodata;
1964 di->pool->pos.schema = di->kv.id;
1965 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1969 dataiterator_setpos_parent(Dataiterator *di)
1971 if (!di->kv.parent || di->kv.parent->eof == 2)
1973 pool_clear_pos(di->pool);
1976 di->pool->pos.solvid = di->solvid;
1977 di->pool->pos.repo = di->repo;
1978 di->pool->pos.repodataid = di->data - di->repo->repodata;
1979 di->pool->pos.schema = di->kv.parent->id;
1980 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1983 /* clones just the position, not the search keys/matcher */
1985 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1987 di->state = from->state;
1988 di->flags &= ~SEARCH_THISSOLVID;
1989 di->flags |= (from->flags & SEARCH_THISSOLVID);
1990 di->repo = from->repo;
1991 di->data = from->data;
1993 di->ddp = from->ddp;
1994 di->idp = from->idp;
1995 di->keyp = from->keyp;
1996 di->key = from->key;
1998 di->repodataid = from->repodataid;
1999 di->solvid = from->solvid;
2000 di->repoid = from->repoid;
2001 di->rootlevel = from->rootlevel;
2002 memcpy(di->parents, from->parents, sizeof(from->parents));
2003 di->nparents = from->nparents;
2007 for (i = 1; i < di->nparents; i++)
2008 di->parents[i].kv.parent = &di->parents[i - 1].kv;
2009 di->kv.parent = &di->parents[di->nparents - 1].kv;
2013 if (from->dupstr && from->dupstr == from->kv.str)
2015 di->dupstrn = from->dupstrn;
2016 di->dupstr = solv_memdup(from->dupstr, from->dupstrn);
2021 dataiterator_seek(Dataiterator *di, int whence)
2023 if ((whence & DI_SEEK_STAY) != 0)
2024 di->rootlevel = di->nparents;
2025 switch (whence & ~DI_SEEK_STAY)
2028 if (di->state != di_nextarrayelement)
2030 if ((whence & DI_SEEK_STAY) != 0)
2031 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
2032 di->state = di_entersub;
2034 case DI_SEEK_PARENT:
2041 if (di->rootlevel > di->nparents)
2042 di->rootlevel = di->nparents;
2043 di->dp = di->parents[di->nparents].dp;
2044 di->kv = di->parents[di->nparents].kv;
2045 di->keyp = di->parents[di->nparents].keyp;
2046 di->key = di->data->keys + *di->keyp;
2047 di->ddp = (unsigned char *)di->kv.str;
2048 di->keyname = di->keynames[di->nparents - di->rootlevel];
2049 di->state = di_nextarrayelement;
2051 case DI_SEEK_REWIND:
2057 di->dp = (unsigned char *)di->kv.parent->str;
2058 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
2059 di->state = di_enterschema;
2067 dataiterator_skip_attribute(Dataiterator *di)
2069 if (di->state == di_nextsolvableattr)
2070 di->state = di_nextsolvablekey;
2072 di->state = di_nextkey;
2076 dataiterator_skip_solvable(Dataiterator *di)
2081 di->keyname = di->keynames[0];
2082 di->state = di_nextsolvable;
2086 dataiterator_skip_repo(Dataiterator *di)
2091 di->keyname = di->keynames[0];
2092 di->state = di_nextrepo;
2096 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
2101 di->keyname = di->keynames[0];
2102 if (solvid == SOLVID_POS)
2104 di->repo = di->pool->pos.repo;
2111 if (!di->pool->pos.repodataid && di->pool->pos.solvid == SOLVID_META) {
2112 solvid = SOLVID_META; /* META pos hack */
2114 di->data = di->repo->repodata + di->pool->pos.repodataid;
2118 else if (solvid > 0)
2120 di->repo = di->pool->solvables[solvid].repo;
2125 if (!di->pool->urepos)
2131 di->repo = di->pool->repos[di->repoid];
2133 if (solvid != SOLVID_POS)
2135 di->solvid = solvid;
2137 di->flags |= SEARCH_THISSOLVID;
2138 di->state = di_enterrepo;
2142 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
2148 di->repoid = 0; /* 0 means stay at repo */
2151 di->flags &= ~SEARCH_THISSOLVID;
2152 di->state = di_enterrepo;
2156 dataiterator_match(Dataiterator *di, Datamatcher *ma)
2159 if (!(str = repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags)))
2161 return ma ? datamatcher_match(ma, str) : 1;
2165 dataiterator_strdup(Dataiterator *di)
2169 if (!di->kv.str || di->kv.str == di->dupstr)
2171 switch (di->key->type)
2174 case REPOKEY_TYPE_DIRSTRARRAY:
2175 if (di->kv.num) /* was it stringified into tmp space? */
2176 l = strlen(di->kv.str) + 1;
2181 if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2183 switch (di->key->type)
2185 case REPOKEY_TYPE_STR:
2186 case REPOKEY_TYPE_DIRSTRARRAY:
2187 l = strlen(di->kv.str) + 1;
2190 l = solv_chksum_len(di->key->type);
2192 case REPOKEY_TYPE_BINARY:
2199 if (!di->dupstrn || di->dupstrn < l)
2201 di->dupstrn = l + 16;
2202 di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
2205 memcpy(di->dupstr, di->kv.str, l);
2206 di->kv.str = di->dupstr;
2210 /************************************************************************
2211 * data modify functions
2214 /* extend repodata so that it includes solvables p */
2216 repodata_extend(Repodata *data, Id p)
2218 if (data->start == data->end)
2219 data->start = data->end = p;
2222 int old = data->end - data->start;
2223 int new = p - data->end + 1;
2226 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
2227 memset(data->attrs + old, 0, new * sizeof(Id *));
2229 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
2230 memset(data->incoreoffset + old, 0, new * sizeof(Id));
2233 if (p < data->start)
2235 int old = data->end - data->start;
2236 int new = data->start - p;
2239 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
2240 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
2241 memset(data->attrs, 0, new * sizeof(Id *));
2243 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
2244 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
2245 memset(data->incoreoffset, 0, new * sizeof(Id));
2250 /* shrink end of repodata */
2252 repodata_shrink(Repodata *data, int end)
2256 if (data->end <= end)
2258 if (data->start >= end)
2262 for (i = 0; i < data->end - data->start; i++)
2263 solv_free(data->attrs[i]);
2264 data->attrs = solv_free(data->attrs);
2266 data->incoreoffset = solv_free(data->incoreoffset);
2267 data->start = data->end = 0;
2272 for (i = end; i < data->end; i++)
2273 solv_free(data->attrs[i - data->start]);
2274 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
2276 if (data->incoreoffset)
2277 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
2281 /* extend repodata so that it includes solvables from start to start + num - 1 */
2283 repodata_extend_block(Repodata *data, Id start, Id num)
2287 if (!data->incoreoffset)
2289 /* this also means that data->attrs is NULL */
2290 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
2291 data->start = start;
2292 data->end = start + num;
2295 repodata_extend(data, start);
2297 repodata_extend(data, start + num - 1);
2300 /**********************************************************************/
2303 #define REPODATA_ATTRS_BLOCK 31
2304 #define REPODATA_ATTRDATA_BLOCK 1023
2305 #define REPODATA_ATTRIDDATA_BLOCK 63
2306 #define REPODATA_ATTRNUM64DATA_BLOCK 15
2310 repodata_new_handle(Repodata *data)
2314 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2315 data->nxattrs = 2; /* -1: SOLVID_META */
2317 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
2318 data->xattrs[data->nxattrs] = 0;
2319 return -(data->nxattrs++);
2323 repodata_get_attrp(Repodata *data, Id handle)
2327 if (handle == SOLVID_META && !data->xattrs)
2329 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2332 return data->xattrs - handle;
2334 if (handle < data->start || handle >= data->end)
2335 repodata_extend(data, handle);
2337 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2338 return data->attrs + (handle - data->start);
2342 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2348 app = repodata_get_attrp(data, handle);
2353 /* Determine equality based on the name only, allows us to change
2354 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2355 for (pp = ap; *pp; pp += 2)
2356 if (data->keys[*pp].name == data->keys[keyid].name)
2360 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2369 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2379 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2383 keyid = repodata_key2id(data, key, 1);
2384 repodata_insert_keyid(data, solvid, keyid, val, 1);
2388 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2392 key.type = REPOKEY_TYPE_ID;
2394 key.storage = KEY_STORAGE_INCORE;
2395 repodata_set(data, solvid, &key, id);
2399 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2403 key.type = REPOKEY_TYPE_NUM;
2405 key.storage = KEY_STORAGE_INCORE;
2406 if (num >= 0x80000000)
2408 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2409 data->attrnum64data[data->attrnum64datalen] = num;
2410 num = 0x80000000 | data->attrnum64datalen++;
2412 repodata_set(data, solvid, &key, (Id)num);
2416 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2420 if (data->localpool)
2421 id = stringpool_str2id(&data->spool, str, 1);
2423 id = pool_str2id(data->repo->pool, str, 1);
2425 key.type = REPOKEY_TYPE_ID;
2427 key.storage = KEY_STORAGE_INCORE;
2428 repodata_set(data, solvid, &key, id);
2432 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2436 key.type = REPOKEY_TYPE_CONSTANT;
2437 key.size = constant;
2438 key.storage = KEY_STORAGE_INCORE;
2439 repodata_set(data, solvid, &key, 0);
2443 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2447 key.type = REPOKEY_TYPE_CONSTANTID;
2449 key.storage = KEY_STORAGE_INCORE;
2450 repodata_set(data, solvid, &key, 0);
2454 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2458 key.type = REPOKEY_TYPE_VOID;
2460 key.storage = KEY_STORAGE_INCORE;
2461 repodata_set(data, solvid, &key, 0);
2465 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2470 l = strlen(str) + 1;
2472 key.type = REPOKEY_TYPE_STR;
2474 key.storage = KEY_STORAGE_INCORE;
2475 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2476 memcpy(data->attrdata + data->attrdatalen, str, l);
2477 repodata_set(data, solvid, &key, data->attrdatalen);
2478 data->attrdatalen += l;
2482 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2490 key.type = REPOKEY_TYPE_BINARY;
2492 key.storage = KEY_STORAGE_INCORE;
2493 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2494 dp = data->attrdata + data->attrdatalen;
2495 if (len >= (1 << 14))
2497 if (len >= (1 << 28))
2498 *dp++ = (len >> 28) | 128;
2499 if (len >= (1 << 21))
2500 *dp++ = (len >> 21) | 128;
2501 *dp++ = (len >> 14) | 128;
2503 if (len >= (1 << 7))
2504 *dp++ = (len >> 7) | 128;
2507 memcpy(dp, buf, len);
2508 repodata_set(data, solvid, &key, data->attrdatalen);
2509 data->attrdatalen = dp + len - data->attrdata;
2512 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2513 * so that the caller can append entrysize new elements plus the termination zero there */
2515 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2518 Id *ida, *pp, **ppp;
2520 /* check if it is the same as last time, this speeds things up a lot */
2521 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2523 /* great! just append the new data */
2524 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2525 data->attriddatalen--; /* overwrite terminating 0 */
2526 data->lastdatalen += entrysize;
2530 ppp = repodata_get_attrp(data, handle);
2534 for (; *pp; pp += 2)
2535 if (data->keys[*pp].name == keyname)
2538 if (!pp || !*pp || data->keys[*pp].type != keytype)
2540 /* not found. allocate new key */
2546 key.storage = KEY_STORAGE_INCORE;
2547 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2548 keyid = repodata_key2id(data, &key, 1);
2549 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2550 data->lasthandle = handle;
2551 data->lastkey = keyid;
2552 data->lastdatalen = data->attriddatalen + entrysize + 1;
2556 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2557 oldsize += entrysize;
2558 if (ida + 1 == data->attriddata + data->attriddatalen)
2560 /* this was the last entry, just append it */
2561 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2562 data->attriddatalen--; /* overwrite terminating 0 */
2566 /* too bad. move to back. */
2567 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2568 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2569 pp[1] = data->attriddatalen;
2570 data->attriddatalen += oldsize;
2572 data->lasthandle = handle;
2573 data->lastkey = *pp;
2574 data->lastdatalen = data->attriddatalen + entrysize + 1;
2578 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2579 const unsigned char *str)
2584 if (!(l = solv_chksum_len(type)))
2589 key.storage = KEY_STORAGE_INCORE;
2590 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2591 memcpy(data->attrdata + data->attrdatalen, str, l);
2592 repodata_set(data, solvid, &key, data->attrdatalen);
2593 data->attrdatalen += l;
2597 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2600 unsigned char buf[64];
2603 if (!(l = solv_chksum_len(type)))
2605 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2607 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2611 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2615 if (!(l = solv_chksum_len(type)))
2617 return pool_bin2hex(data->repo->pool, buf, l);
2620 /* rpm filenames don't contain the epoch, so strip it */
2621 static inline const char *
2622 evrid2vrstr(Pool *pool, Id evrid)
2624 const char *p, *evr = pool_id2str(pool, evrid);
2627 for (p = evr; *p >= '0' && *p <= '9'; p++)
2629 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2633 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2636 if (data->localpool)
2637 id = stringpool_strn2id(&data->spool, str, l, 1);
2639 id = pool_strn2id(data->repo->pool, str, l, 1);
2640 repodata_set_id(data, solvid, keyname, id);
2644 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2647 repodata_set_str(data, solvid, keyname, str);
2650 char *s = solv_strdup(str);
2652 repodata_set_str(data, solvid, keyname, s);
2658 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2660 Pool *pool = data->repo->pool;
2662 const char *str, *fp;
2666 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2669 if ((dir = strrchr(file, '/')) != 0)
2680 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2685 if (l == 1 && dir[0] == '.')
2687 s = pool->solvables + solvid;
2690 str = pool_id2str(pool, s->arch);
2691 if (!strncmp(dir, str, l) && !str[l])
2692 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2694 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2697 str = pool_id2str(pool, s->name);
2699 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2702 str = evrid2vrstr(pool, s->evr);
2704 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2707 str = pool_id2str(pool, s->arch);
2709 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2711 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2716 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2719 /* XXX: medianr is currently not stored */
2721 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2724 const char *evr, *suf, *s;
2728 if ((dir = strrchr(file, '/')) != 0)
2739 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2744 if (l == 1 && dir[0] == '.')
2747 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2748 evr = strchr(file, '-');
2751 for (s = evr - 1; s > file; s--)
2758 suf = strrchr(file, '.');
2761 for (s = suf - 1; s > file; s--)
2767 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2769 /* We accept one more item as suffix. */
2770 for (s = suf - 1; s > file; s--)
2780 if (suf && evr && suf < evr)
2782 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2784 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2786 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2790 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2792 Pool *pool = data->repo->pool;
2793 Solvable *s = pool->solvables + solvid;
2794 const char *p, *sevr, *sarch, *name, *evr;
2796 p = strrchr(sourcepkg, '.');
2797 if (!p || strcmp(p, ".rpm") != 0)
2800 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2804 while (p > sourcepkg && *p != '.')
2806 if (*p != '.' || p == sourcepkg)
2809 while (p > sourcepkg && *p != '-')
2811 if (*p != '-' || p == sourcepkg)
2814 while (p > sourcepkg && *p != '-')
2816 if (*p != '-' || p == sourcepkg)
2819 pool = s->repo->pool;
2821 name = pool_id2str(pool, s->name);
2822 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2823 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2825 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2827 evr = evrid2vrstr(pool, s->evr);
2828 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2829 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2831 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2833 if (!strcmp(sarch, "src.rpm"))
2834 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2835 else if (!strcmp(sarch, "nosrc.rpm"))
2836 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2838 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2842 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2848 key.type = REPOKEY_TYPE_IDARRAY;
2850 key.storage = KEY_STORAGE_INCORE;
2851 repodata_set(data, solvid, &key, data->attriddatalen);
2852 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2853 for (i = 0; i < q->count; i++)
2854 data->attriddata[data->attriddatalen++] = q->elements[i];
2855 data->attriddata[data->attriddatalen++] = 0;
2859 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2863 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2865 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2866 data->attriddata[data->attriddatalen++] = dir;
2867 data->attriddata[data->attriddatalen++] = num;
2868 data->attriddata[data->attriddatalen++] = num2;
2869 data->attriddata[data->attriddatalen++] = 0;
2873 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2879 l = strlen(str) + 1;
2880 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2881 memcpy(data->attrdata + data->attrdatalen, str, l);
2882 stroff = data->attrdatalen;
2883 data->attrdatalen += l;
2886 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2888 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2889 data->attriddata[data->attriddatalen++] = dir;
2890 data->attriddata[data->attriddatalen++] = stroff;
2891 data->attriddata[data->attriddatalen++] = 0;
2895 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2898 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2900 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2901 data->attriddata[data->attriddatalen++] = id;
2902 data->attriddata[data->attriddatalen++] = 0;
2906 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2910 if (data->localpool)
2911 id = stringpool_str2id(&data->spool, str, 1);
2913 id = pool_str2id(data->repo->pool, str, 1);
2914 repodata_add_idarray(data, solvid, keyname, id);
2918 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id handle)
2920 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2921 data->attriddata[data->attriddatalen++] = handle;
2922 data->attriddata[data->attriddatalen++] = 0;
2926 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id handle)
2928 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2929 data->attriddata[data->attriddatalen++] = handle;
2930 data->attriddata[data->attriddatalen++] = 0;
2934 repodata_set_kv(Repodata *data, Id solvid, Id keyname, Id keytype, KeyValue *kv)
2938 case REPOKEY_TYPE_ID:
2939 repodata_set_id(data, solvid, keyname, kv->id);
2941 case REPOKEY_TYPE_CONSTANTID:
2942 repodata_set_constantid(data, solvid, keyname, kv->id);
2944 case REPOKEY_TYPE_IDARRAY:
2945 repodata_add_idarray(data, solvid, keyname, kv->id);
2947 case REPOKEY_TYPE_STR:
2948 repodata_set_str(data, solvid, keyname, kv->str);
2950 case REPOKEY_TYPE_VOID:
2951 repodata_set_void(data, solvid, keyname);
2953 case REPOKEY_TYPE_NUM:
2954 repodata_set_num(data, solvid, keyname, SOLV_KV_NUM64(kv));
2956 case REPOKEY_TYPE_CONSTANT:
2957 repodata_set_constant(data, solvid, keyname, kv->num);
2959 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2961 repodata_add_dirnumnum(data, solvid, keyname, kv->id, kv->num, kv->num2);
2963 case REPOKEY_TYPE_DIRSTRARRAY:
2964 repodata_add_dirstr(data, solvid, keyname, kv->id, kv->str);
2967 repodata_set_bin_checksum(data, solvid, keyname, keytype, (const unsigned char *)kv->str);
2975 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2978 app = repodata_get_attrp(data, solvid);
2984 *app = 0; /* delete all attributes */
2987 for (; *ap; ap += 2)
2988 if (data->keys[*ap].name == keyname)
2994 for (; *ap; ap += 2)
2996 if (data->keys[*ap].name == keyname)
3005 repodata_unset(Repodata *data, Id solvid, Id keyname)
3009 key.type = REPOKEY_TYPE_DELETED;
3011 key.storage = KEY_STORAGE_INCORE;
3012 repodata_set(data, solvid, &key, 0);
3015 /* add all (uninternalized) attrs from src to dest */
3017 repodata_merge_attrs(Repodata *data, Id dest, Id src)
3020 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
3022 for (; *keyp; keyp += 2)
3023 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
3026 /* add some (uninternalized) attrs from src to dest */
3028 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
3031 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
3033 for (; *keyp; keyp += 2)
3034 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
3035 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
3038 /* swap (uninternalized) attrs from src and dest */
3040 repodata_swap_attrs(Repodata *data, Id dest, Id src)
3043 if (!data->attrs || dest == src)
3045 if (dest < data->start || dest >= data->end)
3046 repodata_extend(data, dest);
3047 if (src < data->start || src >= data->end)
3048 repodata_extend(data, src);
3049 tmpattrs = data->attrs[dest - data->start];
3050 data->attrs[dest - data->start] = data->attrs[src - data->start];
3051 data->attrs[src - data->start] = tmpattrs;
3055 /**********************************************************************/
3057 /* TODO: unify with repo_write and repo_solv! */
3059 #define EXTDATA_BLOCK 1023
3067 data_addid(struct extdata *xd, Id sx)
3069 unsigned int x = (unsigned int)sx;
3072 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
3073 dp = xd->buf + xd->len;
3078 *dp++ = (x >> 28) | 128;
3080 *dp++ = (x >> 21) | 128;
3081 *dp++ = (x >> 14) | 128;
3084 *dp++ = (x >> 7) | 128;
3086 xd->len = dp - xd->buf;
3090 data_addid64(struct extdata *xd, unsigned long long x)
3092 if (x >= 0x100000000)
3096 data_addid(xd, (Id)(x >> 35));
3097 xd->buf[xd->len - 1] |= 128;
3099 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
3100 xd->buf[xd->len - 5] = (x >> 28) | 128;
3103 data_addid(xd, (Id)x);
3107 data_addideof(struct extdata *xd, Id sx, int eof)
3109 unsigned int x = (unsigned int)sx;
3112 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
3113 dp = xd->buf + xd->len;
3118 *dp++ = (x >> 27) | 128;
3120 *dp++ = (x >> 20) | 128;
3121 *dp++ = (x >> 13) | 128;
3124 *dp++ = (x >> 6) | 128;
3125 *dp++ = eof ? (x & 63) : (x & 63) | 64;
3126 xd->len = dp - xd->buf;
3130 data_addblob(struct extdata *xd, unsigned char *blob, int len)
3132 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
3133 memcpy(xd->buf + xd->len, blob, len);
3137 /*********************************/
3139 /* this is to reduct memory usage when internalizing oversized repos */
3141 compact_attrdata(Repodata *data, int entry, int nentry)
3144 unsigned int attrdatastart = data->attrdatalen;
3145 unsigned int attriddatastart = data->attriddatalen;
3146 if (attrdatastart < 1024 * 1024 * 4 && attriddatastart < 1024 * 1024)
3148 for (i = entry; i < nentry; i++)
3150 Id v, *attrs = data->attrs[i];
3153 for (; *attrs; attrs += 2)
3155 switch (data->keys[*attrs].type)
3157 case REPOKEY_TYPE_STR:
3158 case REPOKEY_TYPE_BINARY:
3160 if ((unsigned int)attrs[1] < attrdatastart)
3161 attrdatastart = attrs[1];
3163 case REPOKEY_TYPE_DIRSTRARRAY:
3164 for (v = attrs[1]; data->attriddata[v] ; v += 2)
3165 if ((unsigned int)data->attriddata[v + 1] < attrdatastart)
3166 attrdatastart = data->attriddata[v + 1];
3168 case REPOKEY_TYPE_IDARRAY:
3169 case REPOKEY_TYPE_DIRNUMNUMARRAY:
3170 if ((unsigned int)attrs[1] < attriddatastart)
3171 attriddatastart = attrs[1];
3173 case REPOKEY_TYPE_FIXARRAY:
3174 case REPOKEY_TYPE_FLEXARRAY:
3182 printf("compact_attrdata %d %d\n", entry, nentry);
3183 printf("attrdatastart: %d\n", attrdatastart);
3184 printf("attriddatastart: %d\n", attriddatastart);
3186 if (attrdatastart < 1024 * 1024 * 4 && attriddatastart < 1024 * 1024)
3188 for (i = entry; i < nentry; i++)
3190 Id v, *attrs = data->attrs[i];
3193 for (; *attrs; attrs += 2)
3195 switch (data->keys[*attrs].type)
3197 case REPOKEY_TYPE_STR:
3198 case REPOKEY_TYPE_BINARY:
3200 attrs[1] -= attrdatastart;
3202 case REPOKEY_TYPE_DIRSTRARRAY:
3203 for (v = attrs[1]; data->attriddata[v] ; v += 2)
3204 data->attriddata[v + 1] -= attrdatastart;
3206 case REPOKEY_TYPE_IDARRAY:
3207 case REPOKEY_TYPE_DIRNUMNUMARRAY:
3208 attrs[1] -= attriddatastart;
3217 data->attrdatalen -= attrdatastart;
3218 memmove(data->attrdata, data->attrdata + attrdatastart, data->attrdatalen);
3219 data->attrdata = solv_extend_resize(data->attrdata, data->attrdatalen, 1, REPODATA_ATTRDATA_BLOCK);
3221 if (attriddatastart)
3223 data->attriddatalen -= attriddatastart;
3224 memmove(data->attriddata, data->attriddata + attriddatastart, data->attriddatalen * sizeof(Id));
3225 data->attriddata = solv_extend_resize(data->attriddata, data->attriddatalen, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
3229 /* internalalize some key into incore/vincore data */
3232 repodata_serialize_key(Repodata *data, struct extdata *newincore,
3233 struct extdata *newvincore,
3235 Repokey *key, Id val)
3239 unsigned int oldvincorelen = 0;
3243 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3246 oldvincorelen = xd->len;
3250 case REPOKEY_TYPE_VOID:
3251 case REPOKEY_TYPE_CONSTANT:
3252 case REPOKEY_TYPE_CONSTANTID:
3253 case REPOKEY_TYPE_DELETED:
3255 case REPOKEY_TYPE_STR:
3256 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
3258 case REPOKEY_TYPE_MD5:
3259 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
3261 case REPOKEY_TYPE_SHA1:
3262 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
3264 case REPOKEY_TYPE_SHA224:
3265 data_addblob(xd, data->attrdata + val, SIZEOF_SHA224);
3267 case REPOKEY_TYPE_SHA256:
3268 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
3270 case REPOKEY_TYPE_SHA384:
3271 data_addblob(xd, data->attrdata + val, SIZEOF_SHA384);
3273 case REPOKEY_TYPE_SHA512:
3274 data_addblob(xd, data->attrdata + val, SIZEOF_SHA512);
3276 case REPOKEY_TYPE_NUM:
3277 if (val & 0x80000000)
3279 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
3283 case REPOKEY_TYPE_ID:
3284 case REPOKEY_TYPE_DIR:
3285 data_addid(xd, val);
3287 case REPOKEY_TYPE_BINARY:
3290 unsigned char *dp = data_read_id(data->attrdata + val, &len);
3291 dp += (unsigned int)len;
3292 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
3295 case REPOKEY_TYPE_IDARRAY:
3296 for (ida = data->attriddata + val; *ida; ida++)
3297 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
3299 case REPOKEY_TYPE_DIRNUMNUMARRAY:
3300 for (ida = data->attriddata + val; *ida; ida += 3)
3302 data_addid(xd, ida[0]);
3303 data_addid(xd, ida[1]);
3304 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
3307 case REPOKEY_TYPE_DIRSTRARRAY:
3308 for (ida = data->attriddata + val; *ida; ida += 2)
3310 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
3311 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
3314 case REPOKEY_TYPE_FIXARRAY:
3318 for (ida = data->attriddata + val; *ida; ida++)
3322 kp = data->xattrs[-*ida];
3324 continue; /* ignore empty elements */
3326 for (; *kp; kp += 2)
3330 schemaid = repodata_schema2id(data, schema, 1);
3331 else if (schemaid != repodata_schema2id(data, schema, 0))
3333 pool_debug(data->repo->pool, SOLV_ERROR, "repodata_serialize_key: fixarray substructs with different schemas\n");
3338 data_addid(xd, num);
3341 data_addid(xd, schemaid);
3342 for (ida = data->attriddata + val; *ida; ida++)
3344 Id *kp = data->xattrs[-*ida];
3347 for (; *kp; kp += 2)
3348 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3352 case REPOKEY_TYPE_FLEXARRAY:
3355 for (ida = data->attriddata + val; *ida; ida++)
3357 data_addid(xd, num);
3358 for (ida = data->attriddata + val; *ida; ida++)
3360 Id *kp = data->xattrs[-*ida];
3363 data_addid(xd, 0); /* XXX */
3370 schemaid = repodata_schema2id(data, schema, 1);
3371 data_addid(xd, schemaid);
3372 kp = data->xattrs[-*ida];
3374 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3379 pool_debug(data->repo->pool, SOLV_FATAL, "repodata_serialize_key: don't know how to handle type %d\n", key->type);
3382 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3384 /* put offset/len in incore */
3385 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
3386 oldvincorelen = xd->len - oldvincorelen;
3387 data_addid(newincore, oldvincorelen);
3391 /* create a circular linked list of all keys that share
3392 * the same keyname */
3394 calculate_keylink(Repodata *data)
3398 Id maxkeyname = 0, *keytable = 0;
3399 link = solv_calloc(data->nkeys, sizeof(Id));
3400 if (data->nkeys <= 2)
3402 for (i = 1; i < data->nkeys; i++)
3404 Id n = data->keys[i].name;
3405 if (n >= maxkeyname)
3407 keytable = solv_realloc2(keytable, n + 128, sizeof(Id));
3408 memset(keytable + maxkeyname, 0, (n + 128 - maxkeyname) * sizeof(Id));
3409 maxkeyname = n + 128;
3419 /* remove links that just point to themselfs */
3420 for (i = 1; i < data->nkeys; i++)
3423 solv_free(keytable);
3428 repodata_internalize(Repodata *data)
3430 Repokey *key, solvkey;
3432 Id schemaid, keyid, *schema, *sp, oldschemaid, *keyp, *seen;
3433 Offset *oldincoreoffs = 0;
3435 unsigned char *dp, *ndp;
3437 struct extdata newincore;
3438 struct extdata newvincore;
3443 if (!data->attrs && !data->xattrs)
3447 printf("repodata_internalize %d\n", data->repodataid);
3448 printf(" attr data: %d K\n", data->attrdatalen / 1024);
3449 printf(" attrid data: %d K\n", data->attriddatalen / (1024 / 4));
3451 newvincore.buf = data->vincore;
3452 newvincore.len = data->vincorelen;
3454 /* find the solvables key, create if needed */
3455 memset(&solvkey, 0, sizeof(solvkey));
3456 solvkey.name = REPOSITORY_SOLVABLES;
3457 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
3459 solvkey.storage = KEY_STORAGE_INCORE;
3460 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
3462 schema = solv_malloc2(data->nkeys, sizeof(Id));
3463 seen = solv_malloc2(data->nkeys, sizeof(Id));
3465 /* Merge the data already existing (in data->schemata, ->incoredata and
3466 friends) with the new attributes in data->attrs[]. */
3467 nentry = data->end - data->start;
3468 memset(&newincore, 0, sizeof(newincore));
3469 data_addid(&newincore, 0); /* start data at offset 1 */
3471 data->mainschema = 0;
3472 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
3474 keylink = calculate_keylink(data);
3475 /* join entry data */
3476 /* we start with the meta data, entry -1 */
3477 for (entry = -1; entry < nentry; entry++)
3480 dp = data->incoredata;
3483 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
3484 dp = data_read_id(dp, &oldschemaid);
3486 memset(seen, 0, data->nkeys * sizeof(Id));
3488 fprintf(stderr, "oldschemaid %d\n", oldschemaid);
3489 fprintf(stderr, "schemata %d\n", data->schemata[oldschemaid]);
3490 fprintf(stderr, "schemadata %p\n", data->schemadata);
3493 /* seen: -1: old data, 0: skipped, >0: id + 1 */
3497 for (keyp = data->schemadata + data->schemata[oldschemaid]; *keyp; keyp++)
3501 /* oops, should not happen */
3505 seen[*keyp] = -1; /* use old marker */
3508 haveoldkl = 1; /* potential keylink conflict */
3511 /* strip solvables key */
3512 if (entry < 0 && solvkeyid && seen[solvkeyid])
3515 for (sp = keyp = schema; *sp; sp++)
3516 if (*sp != solvkeyid)
3519 seen[solvkeyid] = 0;
3523 /* add new entries */
3525 keyp = data->attrs ? data->attrs[entry] : 0;
3527 keyp = data->xattrs ? data->xattrs[1] : 0;
3529 for (; *keyp; keyp += 2)
3535 if (haveoldkl && keylink[*keyp]) /* this should be pretty rare */
3538 for (kl = keylink[*keyp]; kl != *keyp; kl = keylink[kl])
3541 /* replacing old key kl, remove from schema and seen */
3543 for (osp = schema; osp < sp; osp++)
3546 memmove(osp, osp + 1, (sp - osp) * sizeof(Id));
3554 seen[*keyp] = keyp[1] + 1;
3557 /* add solvables key if needed */
3558 if (entry < 0 && data->end != data->start)
3560 *sp++ = solvkeyid; /* always last in schema */
3567 /* Ideally we'd like to sort the new schema here, to ensure
3568 schema equality independend of the ordering. */
3569 schemaid = repodata_schema2id(data, schema, 1);
3571 schemaid = oldschemaid;
3575 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3576 data->mainschema = schemaid;
3579 /* find offsets in old incore data */
3583 for (sp = data->schemadata + data->schemata[oldschemaid]; *sp; sp++)
3584 if (seen[*sp] == -1)
3585 lastneeded = sp + 1;
3589 oldincoreoffs = solv_malloc2(data->nkeys, 2 * sizeof(Offset));
3590 for (sp = data->schemadata + data->schemata[oldschemaid]; sp != lastneeded; sp++)
3592 /* Skip the data associated with this old key. */
3593 key = data->keys + *sp;
3595 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3597 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3598 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3600 else if (key->storage == KEY_STORAGE_INCORE)
3601 ndp = data_skip_key(data, ndp, key);
3602 oldincoreoffs[*sp * 2] = dp - data->incoredata;
3603 oldincoreoffs[*sp * 2 + 1] = ndp - dp;
3609 /* just copy over the complete old entry (including the schemaid) if there was no new data */
3610 if (entry >= 0 && !neednewschema && oldschemaid && (!data->attrs || !data->attrs[entry]) && dp)
3612 ndp = data->incoredata + data->incoreoffset[entry];
3613 data->incoreoffset[entry] = newincore.len;
3614 data_addblob(&newincore, ndp, dp - ndp);
3618 /* Now create data blob. We walk through the (possibly new) schema
3619 and either copy over old data, or insert the new. */
3621 data->incoreoffset[entry] = newincore.len;
3622 data_addid(&newincore, schemaid);
3624 /* we don't use a pointer to the schemadata here as repodata_serialize_key
3625 * may call repodata_schema2id() which might realloc our schemadata */
3626 for (schemaidx = data->schemata[schemaid]; (keyid = data->schemadata[schemaidx]) != 0; schemaidx++)
3630 data->mainschemaoffsets[schemaidx - data->schemata[schemaid]] = newincore.len;
3631 if (keyid == solvkeyid)
3633 /* add flexarray entry count */
3634 data_addid(&newincore, data->end - data->start);
3635 break; /* always the last entry */
3638 if (seen[keyid] == -1)
3640 if (oldincoreoffs[keyid * 2 + 1])
3641 data_addblob(&newincore, data->incoredata + oldincoreoffs[keyid * 2], oldincoreoffs[keyid * 2 + 1]);
3643 else if (seen[keyid])
3644 repodata_serialize_key(data, &newincore, &newvincore, schema, data->keys + keyid, seen[keyid] - 1);
3649 if (entry >= 0 && data->attrs)
3651 if (data->attrs[entry])
3652 data->attrs[entry] = solv_free(data->attrs[entry]);
3653 if (entry && entry % 4096 == 0 && data->nxattrs <= 2 && entry + 64 < nentry)
3655 compact_attrdata(data, entry + 1, nentry); /* try to free some memory */
3657 printf(" attr data: %d K\n", data->attrdatalen / 1024);
3658 printf(" attrid data: %d K\n", data->attriddatalen / (1024 / 4));
3659 printf(" incore data: %d K\n", newincore.len / 1024);
3660 printf(" sum: %d K\n", (newincore.len + data->attrdatalen + data->attriddatalen * 4) / 1024);
3661 /* malloc_stats(); */
3666 /* free all xattrs */
3667 for (entry = 0; entry < data->nxattrs; entry++)
3668 if (data->xattrs[entry])
3669 solv_free(data->xattrs[entry]);
3670 data->xattrs = solv_free(data->xattrs);
3673 data->lasthandle = 0;
3675 data->lastdatalen = 0;
3679 solv_free(oldincoreoffs);
3680 repodata_free_schemahash(data);
3682 solv_free(data->incoredata);
3683 data->incoredata = newincore.buf;
3684 data->incoredatalen = newincore.len;
3685 data->incoredatafree = 0;
3687 data->vincore = newvincore.buf;
3688 data->vincorelen = newvincore.len;
3690 data->attrs = solv_free(data->attrs);
3691 data->attrdata = solv_free(data->attrdata);
3692 data->attriddata = solv_free(data->attriddata);
3693 data->attrnum64data = solv_free(data->attrnum64data);
3694 data->attrdatalen = 0;
3695 data->attriddatalen = 0;
3696 data->attrnum64datalen = 0;
3698 printf("repodata_internalize %d done\n", data->repodataid);
3699 printf(" incore data: %d K\n", data->incoredatalen / 1024);
3704 repodata_disable_paging(Repodata *data)
3706 if (maybe_load_repodata(data, 0))
3708 repopagestore_disable_paging(&data->store);
3713 /* call the pool's loadcallback to load a stub repodata */
3715 repodata_stub_loader(Repodata *data)
3717 Repo *repo = data->repo;
3718 Pool *pool = repo->pool;
3720 struct s_Pool_tmpspace oldtmpspace;
3723 if (!pool->loadcallback)
3725 data->state = REPODATA_ERROR;
3728 data->state = REPODATA_LOADING;
3730 /* save tmp space and pos */
3731 oldtmpspace = pool->tmpspace;
3732 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3735 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3737 /* restore tmp space and pos */
3738 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3739 solv_free(pool->tmpspace.buf[i]);
3740 pool->tmpspace = oldtmpspace;
3741 if (r && oldpos.repo == repo && oldpos.repodataid == data->repodataid)
3742 memset(&oldpos, 0, sizeof(oldpos));
3745 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3749 repodata_add_stubkey(Repodata *data, Id keyname, Id keytype)
3753 xkey.name = keyname;
3754 xkey.type = keytype;
3755 xkey.storage = KEY_STORAGE_INCORE;
3757 repodata_key2id(data, &xkey, 1);
3761 repodata_add_stub(Repodata **datap)
3763 Repodata *data = *datap;
3764 Repo *repo = data->repo;
3765 Id repodataid = data - repo->repodata;
3766 Repodata *sdata = repo_add_repodata(repo, 0);
3767 data = repo->repodata + repodataid;
3768 if (data->end > data->start)
3769 repodata_extend_block(sdata, data->start, data->end - data->start);
3770 sdata->state = REPODATA_STUB;
3771 sdata->loadcallback = repodata_stub_loader;
3777 repodata_create_stubs(Repodata *data)
3779 Repo *repo = data->repo;
3780 Pool *pool = repo->pool;
3787 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3788 while (dataiterator_step(&di))
3789 if (di.data == data)
3791 dataiterator_free(&di);
3794 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3795 for (i = 0; i < cnt; i++)
3797 sdata = repodata_add_stub(&data);
3798 stubdataids[i] = sdata - repo->repodata;
3801 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3803 while (dataiterator_step(&di))
3805 if (di.data != data)
3807 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3809 dataiterator_entersub(&di);
3810 sdata = repo->repodata + stubdataids[i++];
3814 repodata_set_kv(sdata, SOLVID_META, di.key->name, di.key->type, &di.kv);
3815 if (di.key->name == REPOSITORY_KEYS && di.key->type == REPOKEY_TYPE_IDARRAY)
3820 xkeyname = di.kv.id;
3824 repodata_add_stubkey(sdata, xkeyname, di.kv.id);
3825 if (xkeyname == SOLVABLE_FILELIST)
3826 repodata_set_filelisttype(sdata, REPODATA_FILELIST_EXTENSION);
3831 dataiterator_free(&di);
3832 for (i = 0; i < cnt; i++)
3833 repodata_internalize(repo->repodata + stubdataids[i]);
3834 solv_free(stubdataids);
3839 repodata_set_filelisttype(Repodata *data, int type)
3841 data->filelisttype = type;
3845 repodata_memused(Repodata *data)
3847 return data->incoredatalen + data->vincorelen;