2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
13 * a repository can contain multiple repodata entries, consisting of
14 * different sets of keys and different sets of solvables
29 #include "poolid_private.h"
37 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
38 unsigned char *out, unsigned int out_len);
39 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
42 unsigned int out_len);
44 #define REPODATA_BLOCK 255
48 repodata_initdata(Repodata *data, Repo *repo, int localpool)
50 memset(data, 0, sizeof (*data));
52 data->localpool = localpool;
54 stringpool_init_empty(&data->spool);
55 data->keys = sat_calloc(1, sizeof(Repokey));
57 data->schemata = sat_calloc(1, sizeof(Id));
58 data->schemadata = sat_calloc(1, sizeof(Id));
60 data->schemadatalen = 1;
61 repopagestore_init(&data->store);
65 repodata_freedata(Repodata *data)
71 sat_free(data->schemata);
72 sat_free(data->schemadata);
73 sat_free(data->schematahash);
75 stringpool_free(&data->spool);
76 dirpool_free(&data->dirpool);
78 sat_free(data->mainschemaoffsets);
79 sat_free(data->incoredata);
80 sat_free(data->incoreoffset);
81 sat_free(data->verticaloffset);
83 repopagestore_free(&data->store);
85 sat_free(data->vincore);
88 for (i = 0; i < data->end - data->start; i++)
89 sat_free(data->attrs[i]);
90 sat_free(data->attrs);
92 for (i = 0; i < data->nxattrs; i++)
93 sat_free(data->xattrs[i]);
94 sat_free(data->xattrs);
96 sat_free(data->attrdata);
97 sat_free(data->attriddata);
101 repodata_create(Repo *repo, int localpool)
106 repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
107 data = repo->repodata + repo->nrepodata - 1;
108 repodata_initdata(data, repo, localpool);
113 repodata_free(Repodata *data)
115 Repo *repo = data->repo;
116 int i = data - repo->repodata;
117 repodata_freedata(data);
118 if (i < repo->nrepodata - 1)
119 memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
124 /***************************************************************
125 * key pool management
128 /* this is not so time critical that we need a hash, so we do a simple
131 repodata_key2id(Repodata *data, Repokey *key, int create)
135 for (keyid = 1; keyid < data->nkeys; keyid++)
136 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
138 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
142 if (keyid == data->nkeys)
146 /* allocate new key */
147 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
148 data->keys[data->nkeys++] = *key;
149 if (data->verticaloffset)
151 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
152 data->verticaloffset[data->nkeys - 1] = 0;
154 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
160 /***************************************************************
161 * schema pool management
164 #define SCHEMATA_BLOCK 31
165 #define SCHEMATADATA_BLOCK 255
168 repodata_schema2id(Repodata *data, Id *schema, int create)
174 if ((schematahash = data->schematahash) == 0)
176 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
177 for (i = 0; i < data->nschemata; i++)
179 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
182 schematahash[h] = i + 1;
184 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
185 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
188 for (sp = schema, len = 0, h = 0; *sp; len++)
193 cid = schematahash[h];
197 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
200 for (cid = 0; cid < data->nschemata; cid++)
201 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
207 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
208 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
210 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
211 data->schemata[data->nschemata] = data->schemadatalen;
212 data->schemadatalen += len;
213 schematahash[h] = data->nschemata + 1;
215 fprintf(stderr, "schema2id: new schema\n");
217 return data->nschemata++;
221 repodata_free_schemahash(Repodata *data)
223 data->schematahash = sat_free(data->schematahash);
225 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
226 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
230 /***************************************************************
231 * dir pool management
235 repodata_str2dir(Repodata *data, const char *dir, int create)
241 while (*dir == '/' && dir[1] == '/')
243 if (*dir == '/' && !dir[1])
247 dire = strchrnul(dir, '/');
249 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
251 id = strn2id(data->repo->pool, dir, dire - dir, create);
254 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
267 repodata_dir2str(Repodata *data, Id did, const char *suf)
269 Pool *pool = data->repo->pool;
276 return suf ? suf : "";
280 comp = dirpool_compid(&data->dirpool, parent);
281 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
283 parent = dirpool_parent(&data->dirpool, parent);
288 l += strlen(suf) + 1;
289 p = pool_alloctmpspace(pool, l + 1) + l;
300 comp = dirpool_compid(&data->dirpool, parent);
301 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
304 strncpy(p, comps, l);
305 parent = dirpool_parent(&data->dirpool, parent);
313 /***************************************************************
317 static inline unsigned char *
318 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
320 Id *keyp = data->schemadata + data->schemata[schema];
321 for (; *keyp; keyp++)
322 dp = data_skip_key(data, dp, data->keys + *keyp);
327 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
329 int nentries, schema;
332 case REPOKEY_TYPE_FIXARRAY:
333 dp = data_read_id(dp, &nentries);
336 dp = data_read_id(dp, &schema);
338 dp = data_skip_schema(data, dp, schema);
340 case REPOKEY_TYPE_FLEXARRAY:
341 dp = data_read_id(dp, &nentries);
344 dp = data_read_id(dp, &schema);
345 dp = data_skip_schema(data, dp, schema);
349 if (key->storage == KEY_STORAGE_INCORE)
350 dp = data_skip(dp, key->type);
351 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
353 dp = data_skip(dp, REPOKEY_TYPE_ID);
354 dp = data_skip(dp, REPOKEY_TYPE_ID);
360 static unsigned char *
361 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
367 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
370 for (i = 0; (k = *keyp++) != 0; i++)
372 return data->incoredata + data->mainschemaoffsets[i];
375 while ((k = *keyp++) != 0)
379 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
381 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
382 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
385 if (data->keys[k].storage != KEY_STORAGE_INCORE)
387 dp = data_skip_key(data, dp, data->keys + k);
392 static unsigned char *
393 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
398 if (off >= data->lastverticaloffset)
400 off -= data->lastverticaloffset;
401 if (off + len > data->vincorelen)
403 return data->vincore + off;
405 if (off + len > key->size)
407 /* we now have the offset, go into vertical */
408 off += data->verticaloffset[key - data->keys];
409 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
410 dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
412 dp += off % BLOB_PAGESIZE;
416 static inline unsigned char *
417 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
419 unsigned char *dp = *dpp;
423 if (key->storage == KEY_STORAGE_INCORE)
426 *dpp = data_skip_key(data, dp, key);
429 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
432 dp = data_read_id(dp, &off);
433 dp = data_read_id(dp, &len);
436 return get_vertical_data(data, key, off, len);
442 load_repodata(Repodata *data)
444 if (data->loadcallback)
446 data->loadcallback(data);
447 if (data->state == REPODATA_AVAILABLE)
450 data->state = REPODATA_ERROR;
455 maybe_load_repodata(Repodata *data, Id keyname)
457 if (keyname && !repodata_precheck_keyname(data, keyname))
458 return 0; /* do not bother... */
465 for (i = 0; i < data->nkeys; i++)
466 if (keyname == data->keys[i].name)
468 if (i == data->nkeys)
471 return load_repodata(data);
474 case REPODATA_AVAILABLE:
475 case REPODATA_LOADING:
478 data->state = REPODATA_ERROR;
483 static inline unsigned char *
484 solvid2data(Repodata *data, Id solvid, Id *schemap)
486 unsigned char *dp = data->incoredata;
489 if (solvid == SOLVID_META) /* META */
491 else if (solvid == SOLVID_POS) /* META */
493 Pool *pool = data->repo->pool;
494 if (data->repo != pool->pos.repo)
496 if (data != data->repo->repodata + pool->pos.repodataid)
498 *schemap = pool->pos.schema;
499 return data->incoredata + pool->pos.dp;
503 if (solvid < data->start || solvid >= data->end)
505 dp += data->incoreoffset[solvid - data->start];
507 return data_read_id(dp, schemap);
510 /************************************************************************
514 static inline unsigned char *
515 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
518 Id schema, *keyp, *kp;
521 if (!maybe_load_repodata(data, keyname))
523 dp = solvid2data(data, solvid, &schema);
526 keyp = data->schemadata + data->schemata[schema];
527 for (kp = keyp; *kp; kp++)
528 if (data->keys[*kp].name == keyname)
532 *keypp = key = data->keys + *kp;
533 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
534 return dp; /* no need to forward... */
535 dp = forward_to_key(data, *kp, keyp, dp);
538 return get_data(data, key, &dp, 0);
543 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
549 dp = find_key_data(data, solvid, keyname, &key);
552 if (key->type == REPOKEY_TYPE_CONSTANTID)
554 if (key->type != REPOKEY_TYPE_ID)
556 dp = data_read_id(dp, &id);
561 repodata_globalize_id(Repodata *data, Id id, int create)
563 if (!id || !data || !data->localpool)
565 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
569 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
575 dp = find_key_data(data, solvid, keyname, &key);
578 if (key->type == REPOKEY_TYPE_STR)
579 return (const char *)dp;
580 if (key->type == REPOKEY_TYPE_CONSTANTID)
581 return id2str(data->repo->pool, key->size);
582 if (key->type == REPOKEY_TYPE_ID)
583 dp = data_read_id(dp, &id);
587 return data->spool.stringspace + data->spool.strings[id];
588 return id2str(data->repo->pool, id);
592 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
599 dp = find_key_data(data, solvid, keyname, &key);
602 if (key->type == REPOKEY_TYPE_NUM
603 || key->type == REPOKEY_TYPE_U32
604 || key->type == REPOKEY_TYPE_CONSTANT)
606 dp = data_fetch(dp, &kv, key);
614 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
620 if (!maybe_load_repodata(data, keyname))
622 dp = solvid2data(data, solvid, &schema);
625 /* can't use find_key_data as we need to test the type */
626 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
627 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
632 const unsigned char *
633 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
638 dp = find_key_data(data, solvid, keyname, &key);
646 repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
654 dp = find_key_data(data, solvid, keyname, &key);
659 dp = data_read_ideof(dp, &id, &eof);
667 /************************************************************************
673 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
677 case REPOKEY_TYPE_ID:
678 case REPOKEY_TYPE_CONSTANTID:
679 case REPOKEY_TYPE_IDARRAY:
680 if (data && data->localpool)
681 kv->str = stringpool_id2str(&data->spool, kv->id);
683 kv->str = id2str(pool, kv->id);
684 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
687 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
689 if (*s == ':' && s > kv->str)
693 case REPOKEY_TYPE_STR:
695 case REPOKEY_TYPE_DIRSTRARRAY:
696 if (!(flags & SEARCH_FILES))
697 return 1; /* match just the basename */
698 /* Put the full filename into kv->str. */
699 kv->str = repodata_dir2str(data, kv->id, kv->str);
700 /* And to compensate for that put the "empty" directory into
701 kv->id, so that later calls to repodata_dir2str on this data
702 come up with the same filename again. */
705 case REPOKEY_TYPE_MD5:
706 case REPOKEY_TYPE_SHA1:
707 case REPOKEY_TYPE_SHA256:
708 if (!(flags & SEARCH_CHECKSUMS))
709 return 0; /* skip em */
710 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
718 struct subschema_data {
724 /* search a specific repodata */
726 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
730 Id keyid, *kp, *keyp;
731 unsigned char *dp, *ddp;
737 if (!maybe_load_repodata(data, keyname))
739 if (solvid == SOLVID_SUBSCHEMA)
741 struct subschema_data *subd = cbdata;
742 cbdata = subd->cbdata;
744 schema = subd->parent->id;
745 dp = (unsigned char *)subd->parent->str;
746 kv.parent = subd->parent;
751 dp = solvid2data(data, solvid, &schema);
754 s = data->repo->pool->solvables + solvid;
757 keyp = data->schemadata + data->schemata[schema];
760 /* search for a specific key */
761 for (kp = keyp; *kp; kp++)
762 if (data->keys[*kp].name == keyname)
766 dp = forward_to_key(data, *kp, keyp, dp);
772 while ((keyid = *keyp++) != 0)
775 key = data->keys + keyid;
776 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
778 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
780 struct subschema_data subd;
784 subd.cbdata = cbdata;
787 ddp = data_read_id(ddp, &nentries);
791 while (ddp && nentries > 0)
795 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
796 ddp = data_read_id(ddp, &schema);
798 kv.str = (char *)ddp;
799 stop = callback(cbdata, s, data, key, &kv);
800 if (stop > SEARCH_NEXT_KEY)
802 if (stop && stop != SEARCH_ENTERSUB)
804 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
805 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
806 ddp = data_skip_schema(data, ddp, schema);
809 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
813 kv.str = (char *)ddp;
814 stop = callback(cbdata, s, data, key, &kv);
815 if (stop > SEARCH_NEXT_KEY)
825 ddp = data_fetch(ddp, &kv, key);
828 stop = callback(cbdata, s, data, key, &kv);
831 while (!kv.eof && !stop);
832 if (onekey || stop > SEARCH_NEXT_KEY)
838 repodata_setpos_kv(Repodata *data, KeyValue *kv)
840 Pool *pool = data->repo->pool;
842 pool_clear_pos(pool);
845 pool->pos.repo = data->repo;
846 pool->pos.repodataid = data - data->repo->repodata;
847 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
848 pool->pos.schema = kv->id;
852 /************************************************************************
853 * data iterator functions
856 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
857 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
858 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
859 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
860 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
861 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
862 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
863 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
864 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
865 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
866 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
867 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
868 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
869 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
873 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
887 case SOLVABLE_VENDOR:
890 case SOLVABLE_PROVIDES:
892 return s->provides ? s->repo->idarraydata + s->provides : 0;
893 case SOLVABLE_OBSOLETES:
895 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
896 case SOLVABLE_CONFLICTS:
898 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
899 case SOLVABLE_REQUIRES:
901 return s->requires ? s->repo->idarraydata + s->requires : 0;
902 case SOLVABLE_RECOMMENDS:
904 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
905 case SOLVABLE_SUPPLEMENTS:
907 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
908 case SOLVABLE_SUGGESTS:
910 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
911 case SOLVABLE_ENHANCES:
913 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
916 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
923 datamatcher_init(Datamatcher *ma, const char *match, int flags)
929 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
931 ma->matchdata = sat_calloc(1, sizeof(regex_t));
932 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
935 sat_free(ma->matchdata);
936 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
943 datamatcher_free(Datamatcher *ma)
945 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
947 regfree(ma->matchdata);
948 ma->matchdata = sat_free(ma->matchdata);
953 datamatcher_match(Datamatcher *ma, const char *str)
956 switch ((ma->flags & SEARCH_STRINGMASK))
958 case SEARCH_SUBSTRING:
959 if (ma->flags & SEARCH_NOCASE)
961 if (!strcasestr(str, ma->match))
966 if (!strstr(str, ma->match))
971 if (ma->flags & SEARCH_NOCASE)
973 if (strcasecmp(ma->match, str))
978 if (strcmp(ma->match, str))
982 case SEARCH_STRINGSTART:
983 if (ma->flags & SEARCH_NOCASE)
985 if (strncasecmp(ma->match, str, strlen(ma->match)))
990 if (strncmp(ma->match, str, strlen(ma->match)))
994 case SEARCH_STRINGEND:
995 l = strlen(str) - strlen(ma->match);
998 if (ma->flags & SEARCH_NOCASE)
1000 if (strcasecmp(ma->match, str + l))
1005 if (strcmp(ma->match, str + l))
1010 if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
1014 if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
1024 repodata_filelistfilter_matches(Repodata *data, const char *str)
1026 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1027 /* for now hardcoded */
1028 if (strstr(str, "bin/"))
1030 if (!strncmp(str, "/etc/", 5))
1032 if (!strcmp(str, "/usr/lib/sendmail"))
1054 di_nextarrayelement,
1059 di_nextsolvableattr,
1064 /* see repo.h for documentation */
1066 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1068 memset(di, 0, sizeof(*di));
1070 di->flags = flags & ~SEARCH_THISSOLVID;
1071 if (!pool || (repo && repo->pool != pool))
1079 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1085 di->keyname = keyname;
1086 di->keynames[0] = keyname;
1087 dataiterator_set_search(di, repo, p);
1092 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1095 memset(&di->matcher, 0, sizeof(di->matcher));
1096 if (from->matcher.match)
1097 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1102 for (i = 1; i < di->nparents; i++)
1103 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1104 di->kv.parent = &di->parents[di->nparents - 1].kv;
1109 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1111 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1112 datamatcher_free(&di->matcher);
1113 memset(&di->matcher, 0, sizeof(di->matcher));
1117 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1127 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1131 di->flags &= ~SEARCH_THISSOLVID;
1135 if (!di->pool->nrepos)
1143 di->repo = di->pool->repos[0];
1145 di->state = di_enterrepo;
1147 dataiterator_jump_to_solvid(di, p);
1151 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1154 di->keyname = keyname;
1155 di->keynames[0] = keyname;
1159 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1163 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1165 di->state = di_bye; /* sorry */
1168 for (i = di->nkeynames + 1; i > 0; i--)
1169 di->keynames[i] = di->keynames[i - 1];
1170 di->keynames[0] = di->keyname = keyname;
1175 dataiterator_free(Dataiterator *di)
1177 if (di->matcher.match)
1178 datamatcher_free(&di->matcher);
1181 static inline unsigned char *
1182 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1184 Id *keyp = di->keyp;
1185 Repokey *keys = di->data->keys;
1188 for (keyp = di->keyp; *keyp; keyp++)
1189 if (keys[*keyp].name == keyname)
1193 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1201 dataiterator_filelistcheck(Dataiterator *di)
1204 int needcomplete = 0;
1205 Repodata *data = di->data;
1207 if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
1208 if (!di->matcher.match || (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING || !repodata_filelistfilter_matches(di->data, di->matcher.match))
1210 if (data->state != REPODATA_AVAILABLE)
1211 return needcomplete ? 1 : 0;
1212 for (j = 1; j < data->nkeys; j++)
1213 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1215 return j == data->nkeys && !needcomplete ? 0 : 1;
1219 dataiterator_step(Dataiterator *di)
1227 case di_enterrepo: di_enterrepo:
1230 if (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS))
1232 if (!(di->flags & SEARCH_THISSOLVID))
1234 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1235 goto di_nextsolvable;
1239 case di_entersolvable: di_entersolvable:
1240 if (di->repodataid >= 0)
1242 di->repodataid = 0; /* reset repodata iterator */
1243 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)
1245 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1247 goto di_entersolvablekey;
1252 case di_enterrepodata: di_enterrepodata:
1253 if (di->repodataid >= 0)
1255 if (di->repodataid >= di->repo->nrepodata)
1256 goto di_nextsolvable;
1257 di->data = di->repo->repodata + di->repodataid;
1259 if (di->repodataid >= 0 && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1260 goto di_nextrepodata;
1261 if (!maybe_load_repodata(di->data, di->keyname))
1262 goto di_nextrepodata;
1263 di->dp = solvid2data(di->data, di->solvid, &schema);
1265 goto di_nextrepodata;
1266 if (di->solvid == SOLVID_POS)
1267 di->solvid = di->pool->pos.solvid;
1268 /* reset key iterator */
1269 di->keyp = di->data->schemadata + di->data->schemata[schema];
1272 case di_enterschema: di_enterschema:
1274 di->dp = dataiterator_find_keyname(di, di->keyname);
1275 if (!di->dp || !*di->keyp)
1279 goto di_nextrepodata;
1283 case di_enterkey: di_enterkey:
1285 di->key = di->data->keys + *di->keyp;
1286 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1289 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1291 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1297 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1299 di->state = di_nextkey;
1301 di->state = di_nextattr;
1304 case di_nextkey: di_nextkey:
1305 if (!di->keyname && *++di->keyp)
1311 case di_nextrepodata: di_nextrepodata:
1312 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1313 goto di_enterrepodata;
1316 case di_nextsolvable: di_nextsolvable:
1317 if (!(di->flags & SEARCH_THISSOLVID))
1320 di->solvid = di->repo->start;
1323 for (; di->solvid < di->repo->end; di->solvid++)
1325 if (di->pool->solvables[di->solvid].repo == di->repo)
1326 goto di_entersolvable;
1331 case di_nextrepo: di_nextrepo:
1332 if (di->repoid >= 0)
1336 if (di->repoid < di->pool->nrepos)
1338 di->repo = di->pool->repos[di->repoid];
1344 case di_bye: di_bye:
1348 case di_enterarray: di_enterarray:
1349 if (di->key->name == REPOSITORY_SOLVABLES)
1351 di->ddp = data_read_id(di->ddp, &di->kv.num);
1356 case di_nextarrayelement: di_nextarrayelement:
1359 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1360 if (di->kv.entry == di->kv.num)
1362 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1364 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1366 di->kv.str = (char *)di->ddp;
1368 di->state = di_nextkey;
1371 if (di->kv.entry == di->kv.num - 1)
1373 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1374 di->ddp = data_read_id(di->ddp, &di->kv.id);
1375 di->kv.str = (char *)di->ddp;
1376 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1378 if ((di->flags & SEARCH_SUB) != 0)
1379 di->state = di_entersub;
1381 di->state = di_nextarrayelement;
1384 case di_entersub: di_entersub:
1385 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1386 goto di_nextarrayelement; /* sorry, full */
1387 di->parents[di->nparents].kv = di->kv;
1388 di->parents[di->nparents].dp = di->dp;
1389 di->parents[di->nparents].keyp = di->keyp;
1390 di->dp = (unsigned char *)di->kv.str;
1391 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1392 memset(&di->kv, 0, sizeof(di->kv));
1393 di->kv.parent = &di->parents[di->nparents].kv;
1395 di->keyname = di->keynames[di->nparents - di->rootlevel];
1396 goto di_enterschema;
1398 case di_leavesub: di_leavesub:
1399 if (di->nparents - 1 < di->rootlevel)
1402 di->dp = di->parents[di->nparents].dp;
1403 di->kv = di->parents[di->nparents].kv;
1404 di->keyp = di->parents[di->nparents].keyp;
1405 di->key = di->data->keys + *di->keyp;
1406 di->ddp = (unsigned char *)di->kv.str;
1407 di->keyname = di->keynames[di->nparents - di->rootlevel];
1408 goto di_nextarrayelement;
1410 /* special solvable attr handling follows */
1412 case di_nextsolvableattr:
1413 di->kv.id = *di->idp++;
1418 di->state = di_nextsolvablekey;
1422 case di_nextsolvablekey: di_nextsolvablekey:
1423 if (di->keyname || di->key->name == RPM_RPMDBID)
1424 goto di_enterrepodata;
1428 case di_entersolvablekey: di_entersolvablekey:
1429 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1430 if (!di->idp || !di->idp[0])
1431 goto di_nextsolvablekey;
1432 di->kv.id = di->idp[0];
1433 di->kv.num = di->idp[0];
1435 if (!di->kv.eof && !di->idp[0])
1439 di->state = di_nextsolvablekey;
1441 di->state = di_nextsolvableattr;
1445 if (di->matcher.match)
1447 /* simple pre-check so that we don't need to stringify */
1448 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))
1450 int l = strlen(di->matcher.match) - strlen(di->kv.str);
1451 if (l < 0 || strcmp(di->matcher.match + l, di->kv.str))
1454 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1456 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1460 if (!datamatcher_match(&di->matcher, di->kv.str))
1463 /* found something! */
1469 dataiterator_entersub(Dataiterator *di)
1471 if (di->state == di_nextarrayelement)
1472 di->state = di_entersub;
1476 dataiterator_setpos(Dataiterator *di)
1478 if (di->kv.eof == 2)
1480 pool_clear_pos(di->pool);
1483 di->pool->pos.solvid = di->solvid;
1484 di->pool->pos.repo = di->repo;
1485 di->pool->pos.repodataid = di->data - di->repo->repodata;
1486 di->pool->pos.schema = di->kv.id;
1487 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1491 dataiterator_setpos_parent(Dataiterator *di)
1493 if (!di->kv.parent || di->kv.parent->eof == 2)
1495 pool_clear_pos(di->pool);
1498 di->pool->pos.solvid = di->solvid;
1499 di->pool->pos.repo = di->repo;
1500 di->pool->pos.repodataid = di->data - di->repo->repodata;
1501 di->pool->pos.schema = di->kv.parent->id;
1502 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1505 /* clones just the position, not the search keys/matcher */
1507 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1509 di->state = from->state;
1510 di->flags &= ~SEARCH_THISSOLVID;
1511 di->flags |= (from->flags & SEARCH_THISSOLVID);
1512 di->repo = from->repo;
1513 di->data = from->data;
1515 di->ddp = from->ddp;
1516 di->idp = from->idp;
1517 di->keyp = from->keyp;
1518 di->key = from->key;
1520 di->repodataid = from->repodataid;
1521 di->solvid = from->solvid;
1522 di->repoid = from->repoid;
1523 di->rootlevel = from->rootlevel;
1524 memcpy(di->parents, from->parents, sizeof(from->parents));
1525 di->nparents = from->nparents;
1529 for (i = 1; i < di->nparents; i++)
1530 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1531 di->kv.parent = &di->parents[di->nparents - 1].kv;
1536 dataiterator_seek(Dataiterator *di, int whence)
1538 if ((whence & DI_SEEK_STAY) != 0)
1539 di->rootlevel = di->nparents;
1540 switch (whence & ~DI_SEEK_STAY)
1543 if (di->state != di_nextarrayelement)
1545 if ((whence & DI_SEEK_STAY) != 0)
1546 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1547 di->state = di_entersub;
1549 case DI_SEEK_PARENT:
1556 if (di->rootlevel > di->nparents)
1557 di->rootlevel = di->nparents;
1558 di->dp = di->parents[di->nparents].dp;
1559 di->kv = di->parents[di->nparents].kv;
1560 di->keyp = di->parents[di->nparents].keyp;
1561 di->key = di->data->keys + *di->keyp;
1562 di->ddp = (unsigned char *)di->kv.str;
1563 di->keyname = di->keynames[di->nparents - di->rootlevel];
1564 di->state = di_nextarrayelement;
1566 case DI_SEEK_REWIND:
1572 di->dp = (unsigned char *)di->kv.parent->str;
1573 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1574 di->state = di_enterschema;
1582 dataiterator_skip_attribute(Dataiterator *di)
1584 if (di->state == di_nextsolvableattr)
1585 di->state = di_nextsolvablekey;
1587 di->state = di_nextkey;
1591 dataiterator_skip_solvable(Dataiterator *di)
1595 di->keyname = di->keynames[0];
1596 di->state = di_nextsolvable;
1600 dataiterator_skip_repo(Dataiterator *di)
1604 di->keyname = di->keynames[0];
1605 di->state = di_nextrepo;
1609 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1613 di->keyname = di->keynames[0];
1614 if (solvid == SOLVID_POS)
1616 di->repo = di->pool->pos.repo;
1623 di->data = di->repo->repodata + di->pool->pos.repodataid;
1624 di->repodataid = -1;
1625 di->solvid = solvid;
1626 di->state = di_enterrepo;
1627 di->flags |= SEARCH_THISSOLVID;
1632 di->repo = di->pool->solvables[solvid].repo;
1635 else if (di->repoid >= 0)
1637 if (!di->pool->nrepos)
1642 di->repo = di->pool->repos[0];
1646 di->solvid = solvid;
1648 di->flags |= SEARCH_THISSOLVID;
1649 di->state = di_enterrepo;
1653 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1661 di->flags &= ~SEARCH_THISSOLVID;
1662 di->state = di_enterrepo;
1666 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1668 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1672 return datamatcher_match(ma, di->kv.str);
1675 /************************************************************************
1676 * data modify functions
1679 /* extend repodata so that it includes solvables p */
1681 repodata_extend(Repodata *data, Id p)
1683 if (data->start == data->end)
1684 data->start = data->end = p;
1687 int old = data->end - data->start;
1688 int new = p - data->end + 1;
1691 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1692 memset(data->attrs + old, 0, new * sizeof(Id *));
1694 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1695 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1698 if (p < data->start)
1700 int old = data->end - data->start;
1701 int new = data->start - p;
1704 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1705 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1706 memset(data->attrs, 0, new * sizeof(Id *));
1708 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1709 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1710 memset(data->incoreoffset, 0, new * sizeof(Id));
1715 /* shrink end of repodata */
1717 repodata_shrink(Repodata *data, int end)
1721 if (data->end <= end)
1723 if (data->start >= end)
1727 for (i = 0; i < data->end - data->start; i++)
1728 sat_free(data->attrs[i]);
1729 data->attrs = sat_free(data->attrs);
1731 data->incoreoffset = sat_free(data->incoreoffset);
1732 data->start = data->end = 0;
1737 for (i = end; i < data->end; i++)
1738 sat_free(data->attrs[i - data->start]);
1739 data->attrs = sat_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1741 if (data->incoreoffset)
1742 data->incoreoffset = sat_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1746 /* extend repodata so that it includes solvables from start to start + num - 1 */
1748 repodata_extend_block(Repodata *data, Id start, Id num)
1752 if (!data->incoreoffset)
1754 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1755 data->start = start;
1756 data->end = start + num;
1759 repodata_extend(data, start);
1761 repodata_extend(data, start + num - 1);
1764 /**********************************************************************/
1767 #define REPODATA_ATTRS_BLOCK 63
1768 #define REPODATA_ATTRDATA_BLOCK 1023
1769 #define REPODATA_ATTRIDDATA_BLOCK 63
1773 repodata_new_handle(Repodata *data)
1777 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1780 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1781 data->xattrs[data->nxattrs] = 0;
1782 return -(data->nxattrs++);
1786 repodata_get_attrp(Repodata *data, Id handle)
1788 if (handle == SOLVID_META)
1792 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1797 return data->xattrs - handle;
1798 if (handle < data->start || handle >= data->end)
1799 repodata_extend(data, handle);
1801 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1802 return data->attrs + (handle - data->start);
1806 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1812 app = repodata_get_attrp(data, handle);
1817 /* Determine equality based on the name only, allows us to change
1818 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1819 for (pp = ap; *pp; pp += 2)
1820 if (data->keys[*pp].name == data->keys[keyid].name)
1833 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1843 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1847 keyid = repodata_key2id(data, key, 1);
1848 repodata_insert_keyid(data, solvid, keyid, val, 1);
1852 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1856 key.type = REPOKEY_TYPE_ID;
1858 key.storage = KEY_STORAGE_INCORE;
1859 repodata_set(data, solvid, &key, id);
1863 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1867 key.type = REPOKEY_TYPE_NUM;
1869 key.storage = KEY_STORAGE_INCORE;
1870 repodata_set(data, solvid, &key, (Id)num);
1874 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1878 if (data->localpool)
1879 id = stringpool_str2id(&data->spool, str, 1);
1881 id = str2id(data->repo->pool, str, 1);
1883 key.type = REPOKEY_TYPE_ID;
1885 key.storage = KEY_STORAGE_INCORE;
1886 repodata_set(data, solvid, &key, id);
1890 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1894 key.type = REPOKEY_TYPE_CONSTANT;
1895 key.size = constant;
1896 key.storage = KEY_STORAGE_INCORE;
1897 repodata_set(data, solvid, &key, 0);
1901 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1905 key.type = REPOKEY_TYPE_CONSTANTID;
1907 key.storage = KEY_STORAGE_INCORE;
1908 repodata_set(data, solvid, &key, 0);
1912 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1916 key.type = REPOKEY_TYPE_VOID;
1918 key.storage = KEY_STORAGE_INCORE;
1919 repodata_set(data, solvid, &key, 0);
1923 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1928 l = strlen(str) + 1;
1930 key.type = REPOKEY_TYPE_STR;
1932 key.storage = KEY_STORAGE_INCORE;
1933 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1934 memcpy(data->attrdata + data->attrdatalen, str, l);
1935 repodata_set(data, solvid, &key, data->attrdatalen);
1936 data->attrdatalen += l;
1939 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1940 * so that the caller can append the new element there */
1942 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1945 Id *ida, *pp, **ppp;
1947 /* check if it is the same as last time, this speeds things up a lot */
1948 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1950 /* great! just append the new data */
1951 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1952 data->attriddatalen--; /* overwrite terminating 0 */
1953 data->lastdatalen += entrysize;
1957 ppp = repodata_get_attrp(data, handle);
1960 for (; *pp; pp += 2)
1961 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1965 /* not found. allocate new key */
1970 key.storage = KEY_STORAGE_INCORE;
1971 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1972 repodata_set(data, handle, &key, data->attriddatalen);
1973 data->lasthandle = 0; /* next time... */
1977 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1978 oldsize += entrysize;
1979 if (ida + 1 == data->attriddata + data->attriddatalen)
1981 /* this was the last entry, just append it */
1982 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1983 data->attriddatalen--; /* overwrite terminating 0 */
1987 /* too bad. move to back. */
1988 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1989 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1990 pp[1] = data->attriddatalen;
1991 data->attriddatalen += oldsize;
1993 data->lasthandle = handle;
1994 data->lastkey = *pp;
1995 data->lastdatalen = data->attriddatalen + entrysize + 1;
1999 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2000 const unsigned char *str)
2005 if (!(l = sat_chksum_len(type)))
2010 key.storage = KEY_STORAGE_INCORE;
2011 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2012 memcpy(data->attrdata + data->attrdatalen, str, l);
2013 repodata_set(data, solvid, &key, data->attrdatalen);
2014 data->attrdatalen += l;
2018 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
2021 for (i = 0; i < buflen; i++)
2023 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
2024 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
2025 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
2036 buf[i] = (buf[i] << 4) | v;
2043 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2046 unsigned char buf[64];
2049 if (!(l = sat_chksum_len(type)))
2051 if (hexstr2bytes(buf, str, l) != l)
2053 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2057 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2062 if (!(l = sat_chksum_len(type)))
2064 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2065 for (i = 0; i < l; i++)
2067 unsigned char v = buf[i];
2068 unsigned char w = v >> 4;
2069 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2071 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2077 /* rpm filenames don't contain the epoch, so strip it */
2078 static inline const char *
2079 evrid2vrstr(Pool *pool, Id evrid)
2081 const char *p, *evr = id2str(pool, evrid);
2084 for (p = evr; *p >= '0' && *p <= '9'; p++)
2086 return p != evr && *p == ':' ? p + 1 : evr;
2090 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2092 Pool *pool = data->repo->pool;
2094 const char *str, *fp;
2098 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2101 if ((dir = strrchr(file, '/')) != 0)
2112 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2117 if (l == 1 && dir[0] == '.')
2119 s = pool->solvables + solvid;
2122 str = id2str(pool, s->arch);
2123 if (!strncmp(dir, str, l) && !str[l])
2124 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2126 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
2129 char *dir2 = strdup(dir);
2131 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
2136 str = id2str(pool, s->name);
2138 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2141 str = evrid2vrstr(pool, s->evr);
2143 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2146 str = id2str(pool, s->arch);
2148 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2150 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2155 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2159 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2163 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2165 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2166 data->attriddata[data->attriddatalen++] = dir;
2167 data->attriddata[data->attriddatalen++] = num;
2168 data->attriddata[data->attriddatalen++] = num2;
2169 data->attriddata[data->attriddatalen++] = 0;
2173 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2179 l = strlen(str) + 1;
2180 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2181 memcpy(data->attrdata + data->attrdatalen, str, l);
2182 stroff = data->attrdatalen;
2183 data->attrdatalen += l;
2186 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2188 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2189 data->attriddata[data->attriddatalen++] = dir;
2190 data->attriddata[data->attriddatalen++] = stroff;
2191 data->attriddata[data->attriddatalen++] = 0;
2195 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2198 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2200 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2201 data->attriddata[data->attriddatalen++] = id;
2202 data->attriddata[data->attriddatalen++] = 0;
2206 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2210 if (data->localpool)
2211 id = stringpool_str2id(&data->spool, str, 1);
2213 id = str2id(data->repo->pool, str, 1);
2214 repodata_add_idarray(data, solvid, keyname, id);
2218 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2220 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2221 data->attriddata[data->attriddatalen++] = ghandle;
2222 data->attriddata[data->attriddatalen++] = 0;
2226 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2228 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2229 data->attriddata[data->attriddatalen++] = ghandle;
2230 data->attriddata[data->attriddatalen++] = 0;
2233 /* add all attrs from src to dest */
2235 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2238 if (dest == src || !(keyp = data->attrs[src - data->start]))
2240 for (; *keyp; keyp += 2)
2241 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2245 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2248 if (dest == src || !(keyp = data->attrs[src - data->start]))
2250 for (; *keyp; keyp += 2)
2251 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2252 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2257 /**********************************************************************/
2259 /* TODO: unify with repo_write! */
2261 #define EXTDATA_BLOCK 1023
2269 data_addid(struct extdata *xd, Id x)
2272 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2273 dp = xd->buf + xd->len;
2278 *dp++ = (x >> 28) | 128;
2280 *dp++ = (x >> 21) | 128;
2281 *dp++ = (x >> 14) | 128;
2284 *dp++ = (x >> 7) | 128;
2286 xd->len = dp - xd->buf;
2290 data_addideof(struct extdata *xd, Id x, int eof)
2293 x = (x & 63) | ((x & ~63) << 1);
2294 data_addid(xd, (eof ? x: x | 64));
2298 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2300 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2301 memcpy(xd->buf + xd->len, blob, len);
2305 /*********************************/
2308 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2309 struct extdata *newvincore,
2311 Repokey *key, Id val)
2313 /* Otherwise we have a new value. Parse it into the internal
2317 unsigned int oldvincorelen = 0;
2321 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2324 oldvincorelen = xd->len;
2328 case REPOKEY_TYPE_VOID:
2329 case REPOKEY_TYPE_CONSTANT:
2330 case REPOKEY_TYPE_CONSTANTID:
2332 case REPOKEY_TYPE_STR:
2333 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2335 case REPOKEY_TYPE_MD5:
2336 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2338 case REPOKEY_TYPE_SHA1:
2339 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2341 case REPOKEY_TYPE_SHA256:
2342 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2344 case REPOKEY_TYPE_ID:
2345 case REPOKEY_TYPE_NUM:
2346 case REPOKEY_TYPE_DIR:
2347 data_addid(xd, val);
2349 case REPOKEY_TYPE_IDARRAY:
2350 for (ida = data->attriddata + val; *ida; ida++)
2351 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2353 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2354 for (ida = data->attriddata + val; *ida; ida += 3)
2356 data_addid(xd, ida[0]);
2357 data_addid(xd, ida[1]);
2358 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2361 case REPOKEY_TYPE_DIRSTRARRAY:
2362 for (ida = data->attriddata + val; *ida; ida += 2)
2364 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2365 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2368 case REPOKEY_TYPE_FIXARRAY:
2372 for (ida = data->attriddata + val; *ida; ida++)
2375 fprintf(stderr, "serialize struct %d\n", *ida);
2378 Id *kp = data->xattrs[-*ida];
2385 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2391 schemaid = repodata_schema2id(data, schema, 1);
2392 else if (schemaid != repodata_schema2id(data, schema, 0))
2394 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2398 fprintf(stderr, " schema %d\n", schemaid);
2403 data_addid(xd, num);
2404 data_addid(xd, schemaid);
2405 for (ida = data->attriddata + val; *ida; ida++)
2407 Id *kp = data->xattrs[-*ida];
2412 repodata_serialize_key(data, newincore, newvincore,
2413 schema, data->keys + *kp, kp[1]);
2418 case REPOKEY_TYPE_FLEXARRAY:
2421 for (ida = data->attriddata + val; *ida; ida++)
2423 data_addid(xd, num);
2424 for (ida = data->attriddata + val; *ida; ida++)
2426 Id *kp = data->xattrs[-*ida];
2429 data_addid(xd, 0); /* XXX */
2436 schemaid = repodata_schema2id(data, schema, 1);
2437 data_addid(xd, schemaid);
2438 kp = data->xattrs[-*ida];
2441 repodata_serialize_key(data, newincore, newvincore,
2442 schema, data->keys + *kp, kp[1]);
2448 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2451 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2453 /* put offset/len in incore */
2454 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2455 oldvincorelen = xd->len - oldvincorelen;
2456 data_addid(newincore, oldvincorelen);
2461 repodata_internalize(Repodata *data)
2463 Repokey *key, solvkey;
2465 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2466 unsigned char *dp, *ndp;
2467 int newschema, oldcount;
2468 struct extdata newincore;
2469 struct extdata newvincore;
2472 if (!data->attrs && !data->xattrs)
2475 newvincore.buf = data->vincore;
2476 newvincore.len = data->vincorelen;
2478 /* find the solvables key, create if needed */
2479 memset(&solvkey, 0, sizeof(solvkey));
2480 solvkey.name = REPOSITORY_SOLVABLES;
2481 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2483 solvkey.storage = KEY_STORAGE_INCORE;
2484 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2486 schema = sat_malloc2(data->nkeys, sizeof(Id));
2487 seen = sat_malloc2(data->nkeys, sizeof(Id));
2489 /* Merge the data already existing (in data->schemata, ->incoredata and
2490 friends) with the new attributes in data->attrs[]. */
2491 nentry = data->end - data->start;
2492 memset(&newincore, 0, sizeof(newincore));
2493 data_addid(&newincore, 0); /* start data at offset 1 */
2495 data->mainschema = 0;
2496 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2498 /* join entry data */
2499 /* we start with the meta data, entry -1 */
2500 for (entry = -1; entry < nentry; entry++)
2502 memset(seen, 0, data->nkeys * sizeof(Id));
2504 dp = data->incoredata;
2507 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2508 dp = data_read_id(dp, &oldschema);
2511 fprintf(stderr, "oldschema %d\n", oldschema);
2512 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2513 fprintf(stderr, "schemadata %p\n", data->schemadata);
2515 /* seen: -1: old data 0: skipped >0: id + 1 */
2519 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2523 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2531 keyp = data->attrs ? data->attrs[entry] : 0;
2534 /* strip solvables key */
2536 for (sp = keyp = schema; *sp; sp++)
2537 if (*sp != solvkeyid)
2542 seen[solvkeyid] = 0;
2543 keyp = data->xattrs ? data->xattrs[1] : 0;
2546 for (; *keyp; keyp += 2)
2553 seen[*keyp] = keyp[1] + 1;
2555 if (entry < 0 && data->end != data->start)
2562 /* Ideally we'd like to sort the new schema here, to ensure
2563 schema equality independend of the ordering. We can't do that
2564 yet. For once see below (old ids need to come before new ids).
2565 An additional difficulty is that we also need to move
2566 the values with the keys. */
2567 schemaid = repodata_schema2id(data, schema, 1);
2569 schemaid = oldschema;
2572 /* Now create data blob. We walk through the (possibly new) schema
2573 and either copy over old data, or insert the new. */
2574 /* XXX Here we rely on the fact that the (new) schema has the form
2575 o1 o2 o3 o4 ... | n1 n2 n3 ...
2576 (oX being the old keyids (possibly overwritten), and nX being
2577 the new keyids). This rules out sorting the keyids in order
2578 to ensure a small schema count. */
2580 data->incoreoffset[entry] = newincore.len;
2581 data_addid(&newincore, schemaid);
2584 data->mainschema = schemaid;
2585 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2587 keypstart = data->schemadata + data->schemata[schemaid];
2588 for (keyp = keypstart; *keyp; keyp++)
2591 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2592 if (*keyp == solvkeyid)
2594 /* add flexarray entry count */
2595 data_addid(&newincore, data->end - data->start);
2598 key = data->keys + *keyp;
2600 fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2605 /* Skip the data associated with this old key. */
2606 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2608 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2609 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2611 else if (key->storage == KEY_STORAGE_INCORE)
2612 ndp = data_skip_key(data, dp, key);
2615 if (seen[*keyp] == -1)
2617 /* If this key was an old one _and_ was not overwritten with
2618 a different value copy over the old value (we skipped it
2621 data_addblob(&newincore, dp, ndp - dp);
2624 else if (seen[*keyp])
2626 /* Otherwise we have a new value. Parse it into the internal
2628 repodata_serialize_key(data, &newincore, &newvincore,
2629 schema, key, seen[*keyp] - 1);
2633 if (entry >= 0 && data->attrs && data->attrs[entry])
2634 data->attrs[entry] = sat_free(data->attrs[entry]);
2636 /* free all xattrs */
2637 for (entry = 0; entry < data->nxattrs; entry++)
2638 if (data->xattrs[entry])
2639 sat_free(data->xattrs[entry]);
2640 data->xattrs = sat_free(data->xattrs);
2643 data->lasthandle = 0;
2645 data->lastdatalen = 0;
2648 repodata_free_schemahash(data);
2650 sat_free(data->incoredata);
2651 data->incoredata = newincore.buf;
2652 data->incoredatalen = newincore.len;
2653 data->incoredatafree = 0;
2655 sat_free(data->vincore);
2656 data->vincore = newvincore.buf;
2657 data->vincorelen = newvincore.len;
2659 data->attrs = sat_free(data->attrs);
2660 data->attrdata = sat_free(data->attrdata);
2661 data->attriddata = sat_free(data->attriddata);
2662 data->attrdatalen = 0;
2663 data->attriddatalen = 0;
2667 repodata_disable_paging(Repodata *data)
2669 if (maybe_load_repodata(data, 0))
2670 repopagestore_disable_paging(&data->store);
2674 repodata_load_stub(Repodata *data)
2676 Repo *repo = data->repo;
2677 Pool *pool = repo->pool;
2680 if (!pool->loadcallback)
2682 data->state = REPODATA_ERROR;
2685 data->state = REPODATA_LOADING;
2686 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
2688 data->state = REPODATA_ERROR;
2692 repodata_create_stubs(Repodata *data)
2694 Repo *repo = data->repo;
2695 Pool *pool = repo->pool;
2702 int datastart, dataend;
2704 repodataid = data - repo->repodata;
2705 datastart = data->start;
2706 dataend = data->end;
2707 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2708 while (dataiterator_step(&di))
2710 if (di.data - repo->repodata != repodataid)
2714 dataiterator_free(&di);
2717 stubdataids = sat_calloc(cnt, sizeof(*stubdataids));
2718 for (i = 0; i < cnt; i++)
2720 sdata = repo_add_repodata(repo, 0);
2721 if (dataend > datastart)
2722 repodata_extend_block(sdata, datastart, dataend - datastart);
2723 stubdataids[i] = sdata - repo->repodata;
2724 sdata->state = REPODATA_STUB;
2725 sdata->loadcallback = repodata_load_stub;
2728 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
2730 while (dataiterator_step(&di))
2732 if (di.data - repo->repodata != repodataid)
2734 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
2736 dataiterator_entersub(&di);
2737 sdata = repo->repodata + stubdataids[i++];
2741 switch (di.key->type)
2743 case REPOKEY_TYPE_ID:
2744 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
2746 case REPOKEY_TYPE_CONSTANTID:
2747 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
2749 case REPOKEY_TYPE_STR:
2750 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
2752 case REPOKEY_TYPE_VOID:
2753 repodata_set_void(sdata, SOLVID_META, di.key->name);
2755 case REPOKEY_TYPE_NUM:
2756 repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
2758 case REPOKEY_TYPE_MD5:
2759 case REPOKEY_TYPE_SHA1:
2760 case REPOKEY_TYPE_SHA256:
2761 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
2763 case REPOKEY_TYPE_IDARRAY:
2764 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
2765 if (di.key->name == REPOSITORY_KEYS)
2772 xkeyname = di.kv.id;
2775 xkey.name = xkeyname;
2776 xkey.type = di.kv.id;
2777 xkey.storage = KEY_STORAGE_INCORE;
2779 repodata_key2id(sdata, &xkey, 1);
2784 dataiterator_free(&di);
2785 for (i = 0; i < cnt; i++)
2786 repodata_internalize(repo->repodata + stubdataids[i]);
2787 sat_free(stubdataids);
2791 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: