*
* Manage data coming from one repository
*
+ * a repository can contain multiple repodata entries, consisting of
+ * different sets of keys and different sets of solvables
*/
#define _GNU_SOURCE
#include "pool.h"
#include "poolid_private.h"
#include "util.h"
+#include "hash.h"
+#include "chksum.h"
#include "repopack.h"
#include "repopage.h"
-extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
- unsigned char *out, unsigned int out_len);
-extern unsigned int unchecked_decompress_buf (const unsigned char *in,
- unsigned int in_len,
- unsigned char *out,
- unsigned int out_len);
-
#define REPODATA_BLOCK 255
+static unsigned char *data_skip_key(Repodata *data, unsigned char *dp, Repokey *key);
void
-repodata_init(Repodata *data, Repo *repo, int localpool)
+repodata_initdata(Repodata *data, Repo *repo, int localpool)
{
memset(data, 0, sizeof (*data));
data->repo = repo;
data->localpool = localpool;
if (localpool)
stringpool_init_empty(&data->spool);
+ /* dirpool_init(&data->dirpool); just zeros out again */
data->keys = sat_calloc(1, sizeof(Repokey));
data->nkeys = 1;
data->schemata = sat_calloc(1, sizeof(Id));
}
void
-repodata_free(Repodata *data)
+repodata_freedata(Repodata *data)
{
int i;
sat_free(data->attriddata);
}
+Repodata *
+repodata_create(Repo *repo, int localpool)
+{
+ Repodata *data;
+
+ repo->nrepodata++;
+ repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
+ data = repo->repodata + repo->nrepodata - 1;
+ repodata_initdata(data, repo, localpool);
+ return data;
+}
+
+void
+repodata_free(Repodata *data)
+{
+ Repo *repo = data->repo;
+ int i = data - repo->repodata;
+ repodata_freedata(data);
+ if (i < repo->nrepodata - 1)
+ memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
+ repo->nrepodata--;
+}
+
+void
+repodata_empty(Repodata *data, int localpool)
+{
+ void (*loadcallback)(Repodata *) = data->loadcallback;
+ int state = data->state;
+ repodata_freedata(data);
+ repodata_initdata(data, data->repo, localpool);
+ data->state = state;
+ data->loadcallback = loadcallback;
+}
+
/***************************************************************
* key pool management
Id *sp, cid;
Id *schematahash;
+ if (!*schema)
+ return 0; /* XXX: allow empty schema? */
if ((schematahash = data->schematahash) == 0)
{
data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
- for (i = 0; i < data->nschemata; i++)
+ for (i = 1; i < data->nschemata; i++)
{
for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
h = h * 7 + *sp++;
h &= 255;
- schematahash[h] = i + 1;
+ schematahash[h] = i;
}
data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
cid = schematahash[h];
if (cid)
{
- cid--;
if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
return cid;
- /* cache conflict */
- for (cid = 0; cid < data->nschemata; cid++)
+ /* cache conflict, do a slow search */
+ for (cid = 1; cid < data->nschemata; cid++)
if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
return cid;
}
memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
data->schemata[data->nschemata] = data->schemadatalen;
data->schemadatalen += len;
- schematahash[h] = data->nschemata + 1;
+ schematahash[h] = data->nschemata;
#if 0
fprintf(stderr, "schema2id: new schema\n");
#endif
* dir pool management
*/
+#ifndef HAVE_STRCHRNUL
+static inline const char *strchrnul(const char *str, char x)
+{
+ const char *p = strchr(str, x);
+ return p ? p : str + strlen(str);
+}
+#endif
+
Id
repodata_str2dir(Repodata *data, const char *dir, int create)
{
while (*dir == '/' && dir[1] == '/')
dir++;
if (*dir == '/' && !dir[1])
- return 1;
+ {
+ if (data->dirpool.ndirs)
+ return 1;
+ return dirpool_add_dir(&data->dirpool, 0, 1, create);
+ }
while (*dir)
{
dire = strchrnul(dir, '/');
if (data->localpool)
id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
else
- id = strn2id(data->repo->pool, dir, dire - dir, create);
+ id = pool_strn2id(data->repo->pool, dir, dire - dir, create);
if (!id)
return 0;
parent = dirpool_add_dir(&data->dirpool, parent, id, create);
return dp;
}
-unsigned char *
+static unsigned char *
data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
{
int nentries, schema;
if (!keyid)
return 0;
+ if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
+ {
+ int i;
+ for (i = 0; (k = *keyp++) != 0; i++)
+ if (k == keyid)
+ return data->incoredata + data->mainschemaoffsets[i];
+ return 0;
+ }
while ((k = *keyp++) != 0)
{
if (k == keyid)
return 0;
/* we now have the offset, go into vertical */
off += data->verticaloffset[key - data->keys];
- /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
- dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
+ /* fprintf(stderr, "key %d page %d\n", key->name, off / REPOPAGE_BLOBSIZE); */
+ dp = repopagestore_load_page_range(&data->store, off / REPOPAGE_BLOBSIZE, (off + len - 1) / REPOPAGE_BLOBSIZE);
if (dp)
- dp += off % BLOB_PAGESIZE;
+ dp += off % REPOPAGE_BLOBSIZE;
return dp;
}
static inline unsigned char *
-get_data(Repodata *data, Repokey *key, unsigned char **dpp)
+get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
{
unsigned char *dp = *dpp;
return 0;
if (key->storage == KEY_STORAGE_INCORE)
{
- /* hmm, this is a bit expensive */
- *dpp = data_skip_key(data, dp, key);
+ if (advance)
+ *dpp = data_skip_key(data, dp, key);
return dp;
}
else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
Id off, len;
dp = data_read_id(dp, &off);
dp = data_read_id(dp, &len);
- *dpp = dp;
+ if (advance)
+ *dpp = dp;
return get_vertical_data(data, key, off, len);
}
return 0;
case REPODATA_ERROR:
return 0;
case REPODATA_AVAILABLE:
+ case REPODATA_LOADING:
return 1;
default:
data->state = REPODATA_ERROR;
}
}
-static inline unsigned char*
-entry2data(Repodata *data, Id entry, Id *schemap)
+static inline unsigned char *
+solvid2data(Repodata *data, Id solvid, Id *schemap)
{
unsigned char *dp = data->incoredata;
if (!dp)
return 0;
- if (entry == SOLVID_META) /* META */
+ if (solvid == SOLVID_META) /* META */
dp += 1;
- else if (entry == SOLVID_POS) /* META */
+ else if (solvid == SOLVID_POS) /* META */
{
Pool *pool = data->repo->pool;
if (data->repo != pool->pos.repo)
}
else
{
- if (entry < data->start || entry >= data->end)
+ if (solvid < data->start || solvid >= data->end)
return 0;
- dp += data->incoreoffset[entry - data->start];
+ dp += data->incoreoffset[solvid - data->start];
}
return data_read_id(dp, schemap);
}
* data lookup
*/
-static inline Id
-find_schema_key(Repodata *data, Id schema, Id keyname)
-{
- Id *keyp;
- for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
- if (data->keys[*keyp].name == keyname)
- return *keyp;
- return 0;
-}
-
static inline unsigned char *
-find_key_data(Repodata *data, Id entry, Id keyname, Repokey **keyp)
+find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
{
- unsigned char *dp, *ddp;
- Id keyid, schema;
+ unsigned char *dp;
+ Id schema, *keyp, *kp;
Repokey *key;
if (!maybe_load_repodata(data, keyname))
return 0;
- dp = entry2data(data, entry, &schema);
+ dp = solvid2data(data, solvid, &schema);
if (!dp)
return 0;
- keyid = find_schema_key(data, schema, keyname);
- if (!keyid)
+ keyp = data->schemadata + data->schemata[schema];
+ for (kp = keyp; *kp; kp++)
+ if (data->keys[*kp].name == keyname)
+ break;
+ if (!*kp)
+ return 0;
+ *keypp = key = data->keys + *kp;
+ if (key->type == REPOKEY_TYPE_DELETED)
return 0;
- key = data->keys + keyid;
- *keyp = key;
if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
- return dp;
- dp = forward_to_key(data, keyid, data->schemadata + data->schemata[schema], dp);
+ return dp; /* no need to forward... */
+ dp = forward_to_key(data, *kp, keyp, dp);
if (!dp)
return 0;
- ddp = get_data(data, key, &dp);
- return ddp;
+ return get_data(data, key, &dp, 0);
}
+Id
+repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
+{
+ Id schema, *keyp, *kp;
+ if (!maybe_load_repodata(data, keyname))
+ return 0;
+ if (!solvid2data(data, solvid, &schema))
+ return 0;
+ keyp = data->schemadata + data->schemata[schema];
+ for (kp = keyp; *kp; kp++)
+ if (data->keys[*kp].name == keyname)
+ return data->keys[*kp].type;
+ return 0;
+}
Id
-repodata_lookup_id(Repodata *data, Id entry, Id keyname)
+repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
{
unsigned char *dp;
Repokey *key;
Id id;
- dp = find_key_data(data, entry, keyname, &key);
+ dp = find_key_data(data, solvid, keyname, &key);
if (!dp)
return 0;
if (key->type == REPOKEY_TYPE_CONSTANTID)
}
const char *
-repodata_lookup_str(Repodata *data, Id entry, Id keyname)
+repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
{
unsigned char *dp;
Repokey *key;
Id id;
- dp = find_key_data(data, entry, keyname, &key);
+ dp = find_key_data(data, solvid, keyname, &key);
if (!dp)
return 0;
if (key->type == REPOKEY_TYPE_STR)
return (const char *)dp;
if (key->type == REPOKEY_TYPE_CONSTANTID)
- return id2str(data->repo->pool, key->size);
- if (key->type == REPOKEY_TYPE_ID)
+ id = key->size;
+ else if (key->type == REPOKEY_TYPE_ID)
dp = data_read_id(dp, &id);
else
return 0;
if (data->localpool)
- return data->spool.stringspace + data->spool.strings[id];
- return id2str(data->repo->pool, id);
+ return stringpool_id2str(&data->spool, id);
+ return pool_id2str(data->repo->pool, id);
}
int
-repodata_lookup_num(Repodata *data, Id entry, Id keyname, unsigned int *value)
+repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
{
unsigned char *dp;
Repokey *key;
KeyValue kv;
*value = 0;
- dp = find_key_data(data, entry, keyname, &key);
+ dp = find_key_data(data, solvid, keyname, &key);
if (!dp)
return 0;
if (key->type == REPOKEY_TYPE_NUM
|| key->type == REPOKEY_TYPE_U32
|| key->type == REPOKEY_TYPE_CONSTANT)
{
+ kv.num = 0;
dp = data_fetch(dp, &kv, key);
*value = kv.num;
return 1;
}
int
-repodata_lookup_void(Repodata *data, Id entry, Id keyname)
+repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
{
Id schema;
Id *keyp;
if (!maybe_load_repodata(data, keyname))
return 0;
- dp = entry2data(data, entry, &schema);
+ dp = solvid2data(data, solvid, &schema);
if (!dp)
return 0;
- /* can't use find_schema_key as we need to test the type */
+ /* can't use find_key_data as we need to test the type */
for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
return 1;
}
const unsigned char *
-repodata_lookup_bin_checksum(Repodata *data, Id entry, Id keyname, Id *typep)
+repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
{
unsigned char *dp;
Repokey *key;
- dp = find_key_data(data, entry, keyname, &key);
+ dp = find_key_data(data, solvid, keyname, &key);
if (!dp)
return 0;
*typep = key->type;
return dp;
}
+int
+repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
+{
+ unsigned char *dp;
+ Repokey *key;
+ Id id;
+ int eof = 0;
+
+ queue_empty(q);
+ dp = find_key_data(data, solvid, keyname, &key);
+ if (!dp)
+ return 0;
+ if (key->type != REPOKEY_TYPE_IDARRAY && key->type != REPOKEY_TYPE_REL_IDARRAY)
+ return 0;
+ for (;;)
+ {
+ dp = data_read_ideof(dp, &id, &eof);
+ queue_push(q, id);
+ if (eof)
+ break;
+ }
+ return 1;
+}
+
+Id
+repodata_globalize_id(Repodata *data, Id id, int create)
+{
+ if (!id || !data || !data->localpool)
+ return id;
+ return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
+}
+
+Id
+repodata_localize_id(Repodata *data, Id id, int create)
+{
+ if (!id || !data || !data->localpool)
+ return id;
+ return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
+}
+
/************************************************************************
* data search
*/
+
+int
+repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
+{
+ switch (key->type)
+ {
+ case REPOKEY_TYPE_ID:
+ case REPOKEY_TYPE_CONSTANTID:
+ case REPOKEY_TYPE_IDARRAY:
+ if (data && data->localpool)
+ kv->str = stringpool_id2str(&data->spool, kv->id);
+ else
+ kv->str = pool_id2str(pool, kv->id);
+ if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
+ {
+ const char *s;
+ for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
+ ;
+ if (*s == ':' && s > kv->str)
+ kv->str = s + 1;
+ }
+ return 1;
+ case REPOKEY_TYPE_STR:
+ return 1;
+ case REPOKEY_TYPE_DIRSTRARRAY:
+ if (!(flags & SEARCH_FILES))
+ return 1; /* match just the basename */
+ /* Put the full filename into kv->str. */
+ kv->str = repodata_dir2str(data, kv->id, kv->str);
+ /* And to compensate for that put the "empty" directory into
+ kv->id, so that later calls to repodata_dir2str on this data
+ come up with the same filename again. */
+ kv->id = 0;
+ return 1;
+ case REPOKEY_TYPE_MD5:
+ case REPOKEY_TYPE_SHA1:
+ case REPOKEY_TYPE_SHA256:
+ if (!(flags & SEARCH_CHECKSUMS))
+ return 0; /* skip em */
+ kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
struct subschema_data {
Solvable *s;
void *cbdata;
KeyValue *parent;
};
-/* search in a specific entry */
+/* search a specific repodata */
void
-repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
{
Id schema;
Repokey *key;
- Id k, keyid, *kp, *keyp;
+ Id keyid, *kp, *keyp;
unsigned char *dp, *ddp;
int onekey = 0;
int stop;
if (!maybe_load_repodata(data, keyname))
return;
- if (entry == SOLVID_SUBSCHEMA)
+ if (solvid == SOLVID_SUBSCHEMA)
{
struct subschema_data *subd = cbdata;
cbdata = subd->cbdata;
else
{
schema = 0;
- dp = entry2data(data, entry, &schema);
+ dp = solvid2data(data, solvid, &schema);
if (!dp)
return;
- s = data->repo->pool->solvables + entry;
+ s = data->repo->pool->solvables + solvid;
kv.parent = 0;
}
keyp = data->schemadata + data->schemata[schema];
if (keyname)
{
/* search for a specific key */
- for (kp = keyp; (k = *kp++) != 0; )
- if (data->keys[k].name == keyname)
+ for (kp = keyp; *kp; kp++)
+ if (data->keys[*kp].name == keyname)
break;
- if (k == 0)
+ if (!*kp)
return;
- dp = forward_to_key(data, k, data->schemadata + data->schemata[schema], dp);
+ dp = forward_to_key(data, *kp, keyp, dp);
if (!dp)
return;
- keyp = kp - 1;
+ keyp = kp;
onekey = 1;
}
while ((keyid = *keyp++) != 0)
{
stop = 0;
key = data->keys + keyid;
- ddp = get_data(data, key, &dp);
+ ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
+ if (key->type == REPOKEY_TYPE_DELETED)
+ continue;
if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
{
struct subschema_data subd;
kv.eof = 0;
while (ddp && nentries > 0)
{
+ if (!--nentries)
+ kv.eof = 1;
if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
ddp = data_read_id(ddp, &schema);
kv.id = schema;
stop = callback(cbdata, s, data, key, &kv);
if (stop > SEARCH_NEXT_KEY)
return;
- if (stop)
+ if (stop && stop != SEARCH_ENTERSUB)
break;
- if (!keyname)
- repodata_search(data, SOLVID_SUBSCHEMA, 0, callback, &subd);
+ if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
+ repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
ddp = data_skip_schema(data, ddp, schema);
- nentries--;
kv.entry++;
}
- if (!nentries)
+ if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
{
/* sentinel */
- kv.eof = 1;
+ kv.eof = 2;
kv.str = (char *)ddp;
stop = callback(cbdata, s, data, key, &kv);
if (stop > SEARCH_NEXT_KEY)
{
Pool *pool = data->repo->pool;
if (!kv)
- {
- pool->pos.repo = 0;
- pool->pos.repodataid = 0;
- pool->pos.dp = 0;
- pool->pos.schema = 0;
- }
+ pool_clear_pos(pool);
else
{
- pool->pos.repo = 0;
+ pool->pos.repo = data->repo;
pool->pos.repodataid = data - data->repo->repodata;
pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
pool->pos.schema = kv->id;
}
}
-/************************************************************************/
+/************************************************************************
+ * data iterator functions
+ */
static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
{ SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
{ RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
};
-#if 1
static inline Id *
solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
{
}
}
-void
-datamatcher_init(Datamatcher *ma, Pool *pool, const char *match, int flags)
+int
+datamatcher_init(Datamatcher *ma, const char *match, int flags)
{
- ma->pool = pool;
- ma->match = (void *)match;
+ ma->match = match;
ma->flags = flags;
ma->error = 0;
+ ma->matchdata = 0;
if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
{
- ma->match = sat_calloc(1, sizeof(regex_t));
- ma->error = regcomp((regex_t *)ma->match, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
+ ma->matchdata = sat_calloc(1, sizeof(regex_t));
+ ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
if (ma->error)
{
- sat_free(ma->match);
- ma->match = (void *)match;
+ sat_free(ma->matchdata);
ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
}
}
+ return ma->error;
}
void
datamatcher_free(Datamatcher *ma)
{
- if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->match)
+ if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
{
- regfree(ma->match);
- ma->match = sat_free(ma->match);
+ regfree(ma->matchdata);
+ ma->matchdata = sat_free(ma->matchdata);
}
}
int
-datamatcher_match(Datamatcher *ma, Repodata *data, Repokey *key, KeyValue *kv)
+datamatcher_match(Datamatcher *ma, const char *str)
{
- switch (key->type)
- {
- case REPOKEY_TYPE_ID:
- case REPOKEY_TYPE_IDARRAY:
- if (data && data->localpool)
- kv->str = stringpool_id2str(&data->spool, kv->id);
- else
- kv->str = id2str(ma->pool, kv->id);
- break;
- case REPOKEY_TYPE_STR:
- break;
- case REPOKEY_TYPE_DIRSTRARRAY:
- if (!(ma->flags & SEARCH_FILES))
- return 0;
- /* Put the full filename into kv->str. */
- kv->str = repodata_dir2str(data, kv->id, kv->str);
- /* And to compensate for that put the "empty" directory into
- kv->id, so that later calls to repodata_dir2str on this data
- come up with the same filename again. */
- kv->id = 0;
- break;
- default:
- return 0;
- }
- /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
- for the others we can't know if a colon separates a kind or not. */
- if ((ma->flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
- {
- const char *s = strchr(kv->str, ':');
- if (s)
- kv->str = s + 1;
- }
+ int l;
switch ((ma->flags & SEARCH_STRINGMASK))
{
case SEARCH_SUBSTRING:
if (ma->flags & SEARCH_NOCASE)
{
- if (!strcasestr(kv->str, (const char *)ma->match))
+ if (!strcasestr(str, ma->match))
return 0;
}
else
{
- if (!strstr(kv->str, (const char *)ma->match))
+ if (!strstr(str, ma->match))
return 0;
}
break;
case SEARCH_STRING:
if (ma->flags & SEARCH_NOCASE)
{
- if (strcasecmp((const char *)ma->match, kv->str))
+ if (strcasecmp(ma->match, str))
+ return 0;
+ }
+ else
+ {
+ if (strcmp(ma->match, str))
+ return 0;
+ }
+ break;
+ case SEARCH_STRINGSTART:
+ if (ma->flags & SEARCH_NOCASE)
+ {
+ if (strncasecmp(ma->match, str, strlen(ma->match)))
+ return 0;
+ }
+ else
+ {
+ if (strncmp(ma->match, str, strlen(ma->match)))
+ return 0;
+ }
+ break;
+ case SEARCH_STRINGEND:
+ l = strlen(str) - strlen(ma->match);
+ if (l < 0)
+ return 0;
+ if (ma->flags & SEARCH_NOCASE)
+ {
+ if (strcasecmp(ma->match, str + l))
return 0;
}
else
{
- if (strcmp((const char *)ma->match, kv->str))
+ if (strcmp(ma->match, str + l))
return 0;
}
break;
case SEARCH_GLOB:
- if (fnmatch((const char *)ma->match, kv->str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
+ if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
return 0;
break;
case SEARCH_REGEX:
- if (regexec((const regex_t *)ma->match, kv->str, 0, NULL, 0))
+ if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
return 0;
break;
default:
return 1;
}
+int
+repodata_filelistfilter_matches(Repodata *data, const char *str)
+{
+ /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
+ /* for now hardcoded */
+ if (strstr(str, "bin/"))
+ return 1;
+ if (!strncmp(str, "/etc/", 5))
+ return 1;
+ if (!strcmp(str, "/usr/lib/sendmail"))
+ return 1;
+ return 0;
+}
+
+
enum {
di_bye,
+ di_enterrepo,
+ di_entersolvable,
+ di_enterrepodata,
+ di_enterschema,
+ di_enterkey,
+
di_nextattr,
di_nextkey,
di_nextrepodata,
di_nextsolvable,
di_nextrepo,
- di_enterrepo,
- di_entersolvable,
- di_enterrepodata,
- di_enterkey,
-
+ di_enterarray,
di_nextarrayelement,
+
di_entersub,
di_leavesub,
di_entersolvablekey
};
-void
-dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname, const char *match, int flags)
+/* see repo.h for documentation */
+int
+dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
{
memset(di, 0, sizeof(*di));
- di->repo = repo;
+ di->pool = pool;
+ di->flags = flags & ~SEARCH_THISSOLVID;
+ if (!pool || (repo && repo->pool != pool))
+ {
+ di->state = di_bye;
+ return -1;
+ }
+ if (match)
+ {
+ int error;
+ if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
+ {
+ di->state = di_bye;
+ return error;
+ }
+ }
di->keyname = keyname;
- di->solvid = p;
- di->pool = repo->pool;
- if (p)
- flags |= SEARCH_THISSOLVID;
- di->flags = flags;
- if (repo)
- di->repoid = -1;
+ di->keynames[0] = keyname;
+ dataiterator_set_search(di, repo, p);
+ return 0;
+}
+
+void
+dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
+{
+ *di = *from;
+ memset(&di->matcher, 0, sizeof(di->matcher));
+ if (from->matcher.match)
+ datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
+ if (di->nparents)
+ {
+ /* fix pointers */
+ int i;
+ for (i = 1; i < di->nparents; i++)
+ di->parents[i].kv.parent = &di->parents[i - 1].kv;
+ di->kv.parent = &di->parents[di->nparents - 1].kv;
+ }
+}
+
+int
+dataiterator_set_match(Dataiterator *di, const char *match, int flags)
+{
+ di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
+ datamatcher_free(&di->matcher);
+ memset(&di->matcher, 0, sizeof(di->matcher));
if (match)
- datamatcher_init(&di->matcher, di->pool, match, flags);
- if (p == SOLVID_POS)
{
- di->repo = di->pool->pos.repo;
- if (!di->repo)
+ int error;
+ if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
{
di->state = di_bye;
- return;
+ return error;
}
- di->data = di->repo->repodata + di->pool->pos.repodataid;
- di->repoid = -1;
- di->repodataid = -1;
+ }
+ return 0;
+}
+
+void
+dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
+{
+ di->repo = repo;
+ di->repoid = 0;
+ di->flags &= ~SEARCH_THISSOLVID;
+ di->nparents = 0;
+ di->rootlevel = 0;
+ di->repodataid = 0;
+ if (!di->pool->nrepos)
+ {
+ di->state = di_bye;
+ return;
+ }
+ if (!repo)
+ {
+ di->repoid = 1;
+ di->repo = di->pool->repos[0];
}
di->state = di_enterrepo;
+ if (p)
+ dataiterator_jump_to_solvid(di, p);
+}
+
+void
+dataiterator_set_keyname(Dataiterator *di, Id keyname)
+{
+ di->nkeynames = 0;
+ di->keyname = keyname;
+ di->keynames[0] = keyname;
+}
+
+void
+dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
+{
+ int i;
+
+ if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
+ {
+ di->state = di_bye; /* sorry */
+ return;
+ }
+ for (i = di->nkeynames + 1; i > 0; i--)
+ di->keynames[i] = di->keynames[i - 1];
+ di->keynames[0] = di->keyname = keyname;
+ di->nkeynames++;
}
void
datamatcher_free(&di->matcher);
}
+static inline unsigned char *
+dataiterator_find_keyname(Dataiterator *di, Id keyname)
+{
+ Id *keyp = di->keyp;
+ Repokey *keys = di->data->keys;
+ unsigned char *dp;
+
+ for (keyp = di->keyp; *keyp; keyp++)
+ if (keys[*keyp].name == keyname)
+ break;
+ if (!*keyp)
+ return 0;
+ dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
+ if (!dp)
+ return 0;
+ di->keyp = keyp;
+ return dp;
+}
+
+static int
+dataiterator_filelistcheck(Dataiterator *di)
+{
+ int j;
+ int needcomplete = 0;
+ Repodata *data = di->data;
+
+ if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
+ if (!di->matcher.match
+ || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
+ && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
+ || !repodata_filelistfilter_matches(di->data, di->matcher.match))
+ needcomplete = 1;
+ if (data->state != REPODATA_AVAILABLE)
+ return needcomplete ? 1 : 0;
+ for (j = 1; j < data->nkeys; j++)
+ if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
+ break;
+ return j == data->nkeys && !needcomplete ? 0 : 1;
+}
+
int
dataiterator_step(Dataiterator *di)
{
{
switch (di->state)
{
- case di_nextattr: di_nextattr:
- di->kv.entry++;
- di->ddp = data_fetch(di->ddp, &di->kv, di->key);
- if (di->kv.eof)
- di->state = di_nextkey;
- else
- di->state = di_nextattr;
- break;
-
- case di_nextkey: di_nextkey:
- if (!di->keyname)
+ case di_enterrepo: di_enterrepo:
+ if (!di->repo)
+ goto di_bye;
+ if (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS))
+ goto di_nextrepo;
+ if (!(di->flags & SEARCH_THISSOLVID))
{
- if (*++di->keyp)
- goto di_enterkey;
+ di->solvid = di->repo->start - 1; /* reset solvid iterator */
+ goto di_nextsolvable;
}
- else if ((di->flags & SEARCH_SUB) != 0)
+ /* FALLTHROUGH */
+
+ case di_entersolvable: di_entersolvable:
+ if (di->repodataid >= 0)
{
- Id *keyp = di->keyp;
- for (keyp++; *keyp; keyp++)
- if (di->data->keys[*keyp].name == di->keyname ||
- di->data->keys[*keyp].type == REPOKEY_TYPE_FIXARRAY ||
- di->data->keys[*keyp].type == REPOKEY_TYPE_FLEXARRAY)
- break;
- if (*keyp && (di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp)) != 0)
+ di->repodataid = 0; /* reset repodata iterator */
+ 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)
{
- di->keyp = keyp;
- goto di_enterkey;
+ di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
+ di->data = 0;
+ goto di_entersolvablekey;
}
}
+ /* FALLTHROUGH */
+
+ case di_enterrepodata: di_enterrepodata:
+ if (di->repodataid >= 0)
+ {
+ if (di->repodataid >= di->repo->nrepodata)
+ goto di_nextsolvable;
+ di->data = di->repo->repodata + di->repodataid;
+ }
+ if (di->repodataid >= 0 && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
+ goto di_nextrepodata;
+ if (!maybe_load_repodata(di->data, di->keyname))
+ goto di_nextrepodata;
+ di->dp = solvid2data(di->data, di->solvid, &schema);
+ if (!di->dp)
+ goto di_nextrepodata;
+ if (di->solvid == SOLVID_POS)
+ di->solvid = di->pool->pos.solvid;
+ /* reset key iterator */
+ di->keyp = di->data->schemadata + di->data->schemata[schema];
+ /* FALLTHROUGH */
+ case di_enterschema: di_enterschema:
+ if (di->keyname)
+ di->dp = dataiterator_find_keyname(di, di->keyname);
+ if (!di->dp || !*di->keyp)
+ {
+ if (di->kv.parent)
+ goto di_leavesub;
+ goto di_nextrepodata;
+ }
+ /* FALLTHROUGH */
+
+ case di_enterkey: di_enterkey:
+ di->kv.entry = -1;
+ di->key = di->data->keys + *di->keyp;
+ di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
+ if (!di->ddp)
+ goto di_nextkey;
+ if (di->key->type == REPOKEY_TYPE_DELETED)
+ goto di_nextkey;
+ if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
+ goto di_enterarray;
+ if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
+ goto di_nextkey;
+ /* FALLTHROUGH */
+
+ case di_nextattr:
+ di->kv.entry++;
+ di->ddp = data_fetch(di->ddp, &di->kv, di->key);
+ if (di->kv.eof)
+ di->state = di_nextkey;
+ else
+ di->state = di_nextattr;
+ break;
+
+ case di_nextkey: di_nextkey:
+ if (!di->keyname && *++di->keyp)
+ goto di_enterkey;
if (di->kv.parent)
goto di_leavesub;
/* FALLTHROUGH */
goto di_enterrepodata;
/* FALLTHROUGH */
- case di_nextsolvable:
+ case di_nextsolvable: di_nextsolvable:
if (!(di->flags & SEARCH_THISSOLVID))
{
if (di->solvid < 0)
}
/* FALLTHROUGH */
- case di_nextrepo:
- if (di->repoid >= 0)
+ case di_nextrepo: di_nextrepo:
+ if (di->repoid > 0)
{
di->repoid++;
- if (di->repoid < di->pool->nrepos)
+ di->repodataid = 0;
+ if (di->repoid - 1 < di->pool->nrepos)
{
- di->repo = di->pool->repos[di->repoid];
+ di->repo = di->pool->repos[di->repoid - 1];
goto di_enterrepo;
}
}
-
/* FALLTHROUGH */
- case di_bye:
+
+ case di_bye: di_bye:
di->state = di_bye;
return 0;
- case di_enterrepo: di_enterrepo:
- if (!(di->flags & SEARCH_THISSOLVID))
- di->solvid = di->repo->start;
- /* FALLTHROUGH */
-
- case di_entersolvable: di_entersolvable:
- if (di->repodataid >= 0)
- {
- di->repodataid = 0;
- if (di->solvid > 0 && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)))
- {
- di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
- di->data = 0;
- goto di_entersolvablekey;
- }
- }
-
- case di_enterrepodata: di_enterrepodata:
- if (di->repodataid >= 0)
- di->data = di->repo->repodata + di->repodataid;
- if (!maybe_load_repodata(di->data, di->keyname))
- goto di_nextrepodata;
- di->dp = entry2data(di->data, di->solvid, &schema);
- if (!di->dp)
- goto di_nextrepodata;
- di->keyp = di->data->schemadata + di->data->schemata[schema];
- if (di->keyname)
- {
- Id *keyp;
- if ((di->flags & SEARCH_SUB) != 0)
- {
- di->keyp--;
- goto di_nextkey;
- }
- for (keyp = di->keyp; *keyp; keyp++)
- if (di->data->keys[*keyp].name == di->keyname)
- break;
- if (!*keyp)
- goto di_nextrepodata;
- di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
- di->keyp = keyp;
- if (!di->dp)
- goto di_nextrepodata;
- }
-
- case di_enterkey: di_enterkey:
- di->kv.entry = -1;
- di->key = di->data->keys + *di->keyp;
- di->ddp = get_data(di->data, di->key, &di->dp);
- if (!di->ddp)
+ case di_enterarray: di_enterarray:
+ if (di->key->name == REPOSITORY_SOLVABLES)
goto di_nextkey;
- if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
- {
- di->ddp = data_read_id(di->ddp, &di->kv.num);
- di->kv.entry = -1;
- di->kv.eof = 0;
- goto di_nextarrayelement;
- }
- goto di_nextattr;
+ di->ddp = data_read_id(di->ddp, &di->kv.num);
+ di->kv.eof = 0;
+ di->kv.entry = -1;
+ /* FALLTHROUGH */
case di_nextarrayelement: di_nextarrayelement:
di->kv.entry++;
di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
if (di->kv.entry == di->kv.num)
{
- if (di->keyname && di->key->name != di->keyname)
+ if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
+ goto di_nextkey;
+ if (!(di->flags & SEARCH_ARRAYSENTINEL))
goto di_nextkey;
di->kv.str = (char *)di->ddp;
- di->kv.eof = 1;
+ di->kv.eof = 2;
di->state = di_nextkey;
break;
}
+ if (di->kv.entry == di->kv.num - 1)
+ di->kv.eof = 1;
if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
di->ddp = data_read_id(di->ddp, &di->kv.id);
di->kv.str = (char *)di->ddp;
- if (di->keyname && di->key->name != di->keyname)
+ if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
goto di_entersub;
if ((di->flags & SEARCH_SUB) != 0)
di->state = di_entersub;
memset(&di->kv, 0, sizeof(di->kv));
di->kv.parent = &di->parents[di->nparents].kv;
di->nparents++;
- di->keyp--;
- goto di_nextkey;
+ di->keyname = di->keynames[di->nparents - di->rootlevel];
+ goto di_enterschema;
case di_leavesub: di_leavesub:
+ if (di->nparents - 1 < di->rootlevel)
+ goto di_bye;
di->nparents--;
di->dp = di->parents[di->nparents].dp;
di->kv = di->parents[di->nparents].kv;
di->keyp = di->parents[di->nparents].keyp;
di->key = di->data->keys + *di->keyp;
di->ddp = (unsigned char *)di->kv.str;
+ di->keyname = di->keynames[di->nparents - di->rootlevel];
goto di_nextarrayelement;
/* special solvable attr handling follows */
goto di_nextsolvablekey;
di->kv.id = di->idp[0];
di->kv.num = di->idp[0];
- if (!di->kv.eof && !di->idp[1])
+ di->idp++;
+ if (!di->kv.eof && !di->idp[0])
di->kv.eof = 1;
di->kv.entry = 0;
if (di->kv.eof)
}
if (di->matcher.match)
- if (!datamatcher_match(&di->matcher, di->data, di->key, &di->kv))
- continue;
+ {
+ /* simple pre-check so that we don't need to stringify */
+ 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))
+ {
+ int l = strlen(di->matcher.match) - strlen(di->kv.str);
+ if (l < 0 || strcmp(di->matcher.match + l, di->kv.str))
+ continue;
+ }
+ if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
+ {
+ if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
+ return 1;
+ continue;
+ }
+ if (!datamatcher_match(&di->matcher, di->kv.str))
+ continue;
+ }
/* found something! */
return 1;
}
}
void
+dataiterator_entersub(Dataiterator *di)
+{
+ if (di->state == di_nextarrayelement)
+ di->state = di_entersub;
+}
+
+void
dataiterator_setpos(Dataiterator *di)
{
- if (di->kv.eof)
+ if (di->kv.eof == 2)
{
- memset(&di->pool->pos, 0, sizeof(di->pool->pos));
+ pool_clear_pos(di->pool);
return;
}
+ di->pool->pos.solvid = di->solvid;
di->pool->pos.repo = di->repo;
di->pool->pos.repodataid = di->data - di->repo->repodata;
di->pool->pos.schema = di->kv.id;
void
dataiterator_setpos_parent(Dataiterator *di)
{
- if (!di->kv.parent)
+ if (!di->kv.parent || di->kv.parent->eof == 2)
{
- memset(&di->pool->pos, 0, sizeof(di->pool->pos));
+ pool_clear_pos(di->pool);
return;
}
+ di->pool->pos.solvid = di->solvid;
di->pool->pos.repo = di->repo;
di->pool->pos.repodataid = di->data - di->repo->repodata;
di->pool->pos.schema = di->kv.parent->id;
di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
}
+/* clones just the position, not the search keys/matcher */
void
-dataiterator_skip_attribute(Dataiterator *di)
-{
- if (di->state == di_nextsolvableattr)
- di->state = di_nextsolvablekey;
- else
- di->state = di_nextkey;
-}
-
-void
-dataiterator_skip_solvable(Dataiterator *di)
-{
- di->state = di_nextsolvable;
-}
-
-void
-dataiterator_skip_repo(Dataiterator *di)
-{
- di->state = di_nextrepo;
-}
-
-void
-dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
-{
- di->repo = s->repo;
- di->repoid = -1;
- di->solvid = s - di->pool->solvables;
- di->state = di_entersolvable;
-}
-
-void
-dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
-{
- di->repo = repo;
- di->repoid = -1;
- di->state = di_enterrepo;
-}
-
-int
-dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
-{
- Datamatcher matcher = di->matcher;
- matcher.flags = flags;
- matcher.match = (void *)vmatch;
- matcher.pool = di->pool;
- return datamatcher_match(&matcher, di->data, di->key, &di->kv);
-}
-
-#else
-
-/************************************************************************
- * data search iterator
- */
-
-static void
-dataiterator_newdata(Dataiterator *di)
-{
- Id keyname = di->keyname;
- Repodata *data = di->data;
- di->nextkeydp = 0;
-
- if (data->state == REPODATA_STUB)
- {
- if (keyname)
- {
- int j;
- for (j = 1; j < data->nkeys; j++)
- if (keyname == data->keys[j].name)
- break;
- if (j == data->nkeys)
- return;
- }
- /* load it */
- if (data->loadcallback)
- data->loadcallback(data);
- else
- data->state = REPODATA_ERROR;
- }
- if (data->state == REPODATA_ERROR)
- return;
-
- Id schema;
- unsigned char *dp = data->incoredata;
- if (!dp)
- return;
- if (di->solvid >= 0)
- dp += data->incoreoffset[di->solvid - data->start];
- dp = data_read_id(dp, &schema);
- Id *keyp = data->schemadata + data->schemata[schema];
- if (keyname)
- {
- Id k, *kp;
- /* search in a specific key */
- for (kp = keyp; (k = *kp++) != 0; )
- if (data->keys[k].name == keyname)
- break;
- if (k == 0)
- return;
- dp = forward_to_key(data, k, keyp, dp);
- if (!dp)
- return;
- keyp = kp - 1;
- }
- Id keyid = *keyp++;
- if (!keyid)
- return;
-
- di->data = data;
- di->key = di->data->keys + keyid;
- di->keyp = keyp;
- di->dp = 0;
-
- di->nextkeydp = dp;
- di->dp = get_data(di->data, di->key, &di->nextkeydp);
- di->kv.eof = 0;
-}
-
-void
-dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname,
- const char *match, int flags)
-{
- di->flags = flags;
- if (p > 0)
+dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
+{
+ di->state = from->state;
+ di->flags &= ~SEARCH_THISSOLVID;
+ di->flags |= (from->flags & SEARCH_THISSOLVID);
+ di->repo = from->repo;
+ di->data = from->data;
+ di->dp = from->dp;
+ di->ddp = from->ddp;
+ di->idp = from->idp;
+ di->keyp = from->keyp;
+ di->key = from->key;
+ di->kv = from->kv;
+ di->repodataid = from->repodataid;
+ di->solvid = from->solvid;
+ di->repoid = from->repoid;
+ di->rootlevel = from->rootlevel;
+ memcpy(di->parents, from->parents, sizeof(from->parents));
+ di->nparents = from->nparents;
+ if (di->nparents)
{
- di->solvid = p;
- di->flags |= __SEARCH_ONESOLVABLE;
- di->data = repo->repodata - 1;
- if (flags & SEARCH_NO_STORAGE_SOLVABLE)
- di->state = 0;
- else
- di->state = 1;
+ int i;
+ for (i = 1; i < di->nparents; i++)
+ di->parents[i].kv.parent = &di->parents[i - 1].kv;
+ di->kv.parent = &di->parents[di->nparents - 1].kv;
}
- else
- {
- di->solvid = repo->start - 1;
- if (di->solvid < 0)
- {
- fprintf(stderr, "A repo contains the NULL solvable!\n");
- exit(1);
- }
- di->data = repo->repodata + repo->nrepodata - 1;
- di->state = 0;
- }
-
- di->match = match;
- if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
- {
- if (di->match)
- {
- /* We feed multiple lines eventually (e.g. authors or descriptions),
- so set REG_NEWLINE. */
- di->regex_err =
- regcomp(&di->regex, di->match,
- REG_EXTENDED | REG_NOSUB | REG_NEWLINE
- | ((di->flags & SEARCH_NOCASE) ? REG_ICASE : 0));
-#if 0
- if (di->regex_err != 0)
- {
- fprintf(stderr, "Given regex failed to compile: %s\n", di->match);
- fprintf(stderr, "regcomp error code: %d\n", di->regex_err);
- exit(1);
- }
-#else
- }
- else
- {
- di->flags |= (di->flags & SEARCH_STRINGMASK) | SEARCH_STRING;
- di->regex_err = 0;
-#endif
- }
- }
-
- di->keyname = keyname;
- static Id zeroid = 0;
- di->keyp = &zeroid;
- di->kv.eof = 1;
- di->repo = repo;
- di->idp = 0;
- di->subkeyp = 0;
}
-/* FIXME factor and merge with repo_matchvalue */
-static int
-dataiterator_match_int_real(Dataiterator *di, int flags, const void *vmatch)
-{
- KeyValue *kv = &di->kv;
- const char *match = vmatch;
- if ((flags & SEARCH_STRINGMASK) != 0)
- {
- switch (di->key->type)
- {
- case REPOKEY_TYPE_ID:
- case REPOKEY_TYPE_IDARRAY:
- if (di->data && di->data->localpool)
- kv->str = stringpool_id2str(&di->data->spool, kv->id);
- else
- kv->str = id2str(di->repo->pool, kv->id);
- break;
- case REPOKEY_TYPE_STR:
- break;
- case REPOKEY_TYPE_DIRSTRARRAY:
- if (!(flags & SEARCH_FILES))
- return 0;
- /* Put the full filename into kv->str. */
- kv->str = repodata_dir2str(di->data, kv->id, kv->str);
- /* And to compensate for that put the "empty" directory into
- kv->id, so that later calls to repodata_dir2str on this data
- come up with the same filename again. */
- kv->id = 0;
- break;
- default:
- return 0;
- }
- /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
- for the others we can't know if a colon separates a kind or not. */
- if ((flags & SEARCH_SKIP_KIND)
- && di->key->storage == KEY_STORAGE_SOLVABLE)
- {
- const char *s = strchr(kv->str, ':');
- if (s)
- kv->str = s + 1;
- }
- switch ((flags & SEARCH_STRINGMASK))
- {
- case SEARCH_SUBSTRING:
- if (flags & SEARCH_NOCASE)
- {
- if (!strcasestr(kv->str, match))
- return 0;
- }
- else
- {
- if (!strstr(kv->str, match))
- return 0;
- }
- break;
- case SEARCH_STRING:
- if (flags & SEARCH_NOCASE)
- {
- if (strcasecmp(match, kv->str))
- return 0;
- }
- else
- {
- if (strcmp(match, kv->str))
- return 0;
- }
- break;
- case SEARCH_GLOB:
- if (fnmatch(match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
- return 0;
- break;
- case SEARCH_REGEX:
- if (regexec((const regex_t *)vmatch, kv->str, 0, NULL, 0))
- return 0;
- break;
- default:
- return 0;
- }
- }
- return 1;
-}
-
-static int
-dataiterator_match_int(Dataiterator *di)
-{
- if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
- return dataiterator_match_int_real(di, di->flags, &di->regex);
- else
- return dataiterator_match_int_real(di, di->flags, di->match);
-}
-
-int
-dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
-{
- return dataiterator_match_int_real(di, flags, vmatch);
-}
-
-int
-dataiterator_step(Dataiterator *di)
-{
-restart:
- while (1)
- {
- if (di->state)
- {
- /* we're stepping through solvable data, 1 -> SOLVABLE_NAME... */
- if (di->idp)
- {
- /* we're stepping through an id array */
- Id *idp = di->idp;
- if (*idp)
- {
- di->kv.id = *idp;
- di->idp++;
- di->kv.eof = idp[1] ? 0 : 1;
- goto weg2;
- }
- else
- di->idp = 0;
- }
- Solvable *s = di->repo->pool->solvables + di->solvid;
- int state = di->state;
- di->key = solvablekeys + state - 1;
- if (di->keyname)
- di->state = RPM_RPMDBID;
- else
- di->state++;
- if (state == 1)
- {
- di->data = 0;
- if (di->keyname)
- state = di->keyname - 1;
- }
- switch (state + 1)
- {
- case SOLVABLE_NAME:
- if (!s->name)
- continue;
- di->kv.id = s->name;
- di->kv.eof = 1;
- break;
- case SOLVABLE_ARCH:
- if (!s->arch)
- continue;
- di->kv.id = s->arch;
- di->kv.eof = 1;
- break;
- case SOLVABLE_EVR:
- if (!s->evr)
- continue;
- di->kv.id = s->evr;
- di->kv.eof = 1;
- break;
- case SOLVABLE_VENDOR:
- if (!s->vendor)
- continue;
- di->kv.id = s->vendor;
- di->kv.eof = 1;
- break;
- case SOLVABLE_PROVIDES:
- di->idp = s->provides
- ? di->repo->idarraydata + s->provides : 0;
- continue;
- case SOLVABLE_OBSOLETES:
- di->idp = s->obsoletes
- ? di->repo->idarraydata + s->obsoletes : 0;
- continue;
- case SOLVABLE_CONFLICTS:
- di->idp = s->conflicts
- ? di->repo->idarraydata + s->conflicts : 0;
- continue;
- case SOLVABLE_REQUIRES:
- di->idp = s->requires
- ? di->repo->idarraydata + s->requires : 0;
- continue;
- case SOLVABLE_RECOMMENDS:
- di->idp = s->recommends
- ? di->repo->idarraydata + s->recommends : 0;
- continue;
- case SOLVABLE_SUPPLEMENTS:
- di->idp = s->supplements
- ? di->repo->idarraydata + s->supplements : 0;
- continue;
- case SOLVABLE_SUGGESTS:
- di->idp = s->suggests
- ? di->repo->idarraydata + s->suggests : 0;
- continue;
- case SOLVABLE_ENHANCES:
- di->idp = s->enhances
- ? di->repo->idarraydata + s->enhances : 0;
- continue;
- case RPM_RPMDBID:
- if (!di->repo->rpmdbid)
- continue;
- di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
- di->kv.eof = 1;
- break;
- default:
- di->data = di->repo->repodata - 1;
- di->kv.eof = 1;
- di->state = 0;
- continue;
- }
- }
- else if (di->subkeyp)
- {
- Id keyid;
- if (!di->subnum)
- {
- /* Send end-of-substruct. We are here only when we saw a
- _COUNTED key one level up. Since then we didn't increment
- ->keyp, so it still can be found at keyp[-1]. */
- di->kv.eof = 2;
- di->key = di->data->keys + di->keyp[-1];
- di->subkeyp = 0;
- }
- else if (!(keyid = *di->subkeyp++))
- {
- /* Send end-of-element. See above for keyp[-1]. */
- di->kv.eof = 1;
- di->key = di->data->keys + di->keyp[-1];
- if (di->subschema)
- di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
- else
- {
- di->dp = data_read_id(di->dp, &di->subschema);
- di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
- di->subschema = 0;
- }
- di->subnum--;
- }
- else
- {
- di->key = di->data->keys + keyid;
- di->dp = data_fetch(di->dp, &di->kv, di->key);
- if (!di->dp)
- exit(1);
- }
+void
+dataiterator_seek(Dataiterator *di, int whence)
+{
+ if ((whence & DI_SEEK_STAY) != 0)
+ di->rootlevel = di->nparents;
+ switch (whence & ~DI_SEEK_STAY)
+ {
+ case DI_SEEK_CHILD:
+ if (di->state != di_nextarrayelement)
+ break;
+ if ((whence & DI_SEEK_STAY) != 0)
+ di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
+ di->state = di_entersub;
+ break;
+ case DI_SEEK_PARENT:
+ if (!di->nparents)
+ {
+ di->state = di_bye;
+ break;
}
- else
+ di->nparents--;
+ if (di->rootlevel > di->nparents)
+ di->rootlevel = di->nparents;
+ di->dp = di->parents[di->nparents].dp;
+ di->kv = di->parents[di->nparents].kv;
+ di->keyp = di->parents[di->nparents].keyp;
+ di->key = di->data->keys + *di->keyp;
+ di->ddp = (unsigned char *)di->kv.str;
+ di->keyname = di->keynames[di->nparents - di->rootlevel];
+ di->state = di_nextarrayelement;
+ break;
+ case DI_SEEK_REWIND:
+ if (!di->nparents)
{
- if (di->kv.eof)
- di->dp = 0;
- else
- di->dp = data_fetch(di->dp, &di->kv, di->key);
-
- while (!di->dp)
- {
- Id keyid;
- if (di->keyname || !(keyid = *di->keyp++))
- {
- while (1)
- {
- Repo *repo = di->repo;
- Repodata *data = ++di->data;
- if (data >= repo->repodata + repo->nrepodata)
- {
- if (di->flags & __SEARCH_ONESOLVABLE)
- return 0;
- if (di->solvid >= 0)
- {
- while (++di->solvid < repo->end)
- if (repo->pool->solvables[di->solvid].repo == repo)
- break;
- if (di->solvid >= repo->end)
- {
- if (!(di->flags & SEARCH_EXTRA))
- goto skiprepo;
- goto skiprepo;
- }
- }
- else
- {
- {
-skiprepo:;
- Pool *pool = di->repo->pool;
- if (!(di->flags & SEARCH_ALL_REPOS)
- || di->repo == pool->repos[pool->nrepos - 1])
- return 0;
- int i;
- for (i = 0; i < pool->nrepos; i++)
- if (di->repo == pool->repos[i])
- break;
- di->repo = pool->repos[i + 1];
- dataiterator_init(di, di->repo, 0, di->keyname, di->match, di->flags);
- continue;
- }
- }
- di->data = repo->repodata - 1;
- if ((di->flags & SEARCH_NO_STORAGE_SOLVABLE))
- continue;
- static Id zeroid = 0;
- di->keyp = &zeroid;
- di->state = 1;
- goto restart;
- }
- if ((di->solvid >= 0 && di->solvid >= data->start && di->solvid < data->end))
- {
- dataiterator_newdata(di);
- if (di->nextkeydp)
- break;
- }
- }
- }
- else
- {
- di->key = di->data->keys + keyid;
- di->dp = get_data(di->data, di->key, &di->nextkeydp);
- }
- di->dp = data_fetch(di->dp, &di->kv, di->key);
- }
- if (di->key->type == REPOKEY_TYPE_FIXARRAY)
- {
- di->subnum = di->kv.num;
- di->subschema = di->kv.id;
- di->kv.eof = 0;
- di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
- }
- if (di->key->type == REPOKEY_TYPE_FLEXARRAY)
- {
- di->subnum = di->kv.num;
- di->kv.eof = 0;
- di->dp = data_read_id(di->dp, &di->subschema);
- di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
- di->subschema = 0;
- }
+ di->state = di_bye;
+ break;
}
-weg2:
- if (!di->match
- || dataiterator_match_int(di))
- break;
+ di->dp = (unsigned char *)di->kv.parent->str;
+ di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
+ di->state = di_enterschema;
+ break;
+ default:
+ break;
}
- return 1;
}
void
dataiterator_skip_attribute(Dataiterator *di)
{
- if (di->state)
- di->idp = 0;
- /* This will make the next _step call to retrieve the next field. */
- di->kv.eof = 1;
+ if (di->state == di_nextsolvableattr)
+ di->state = di_nextsolvablekey;
+ else
+ di->state = di_nextkey;
}
void
dataiterator_skip_solvable(Dataiterator *di)
{
- /* We're done with this field. */
- di->kv.eof = 1;
- /* And with solvable data. */
- di->state = 0;
- /* And with all keys for this repodata and thing. */
- static Id zeroid = 0;
- di->keyp = &zeroid;
- /* And with all repodatas for this thing. */
- di->data = di->repo->repodata + di->repo->nrepodata - 1;
- /* Hence the next call to _step will retrieve the next thing. */
+ di->nparents = 0;
+ di->kv.parent = 0;
+ di->rootlevel = 0;
+ di->keyname = di->keynames[0];
+ di->state = di_nextsolvable;
}
void
dataiterator_skip_repo(Dataiterator *di)
{
- dataiterator_skip_solvable(di);
- /* We're done with all solvables and all extra things for this repo. */
- di->solvid = -1;
+ di->nparents = 0;
+ di->kv.parent = 0;
+ di->rootlevel = 0;
+ di->keyname = di->keynames[0];
+ di->state = di_nextrepo;
}
void
-dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
+dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
{
- di->repo = s->repo;
- /* Simulate us being done with the solvable before the requested one. */
- dataiterator_skip_solvable(di);
- di->solvid = s - s->repo->pool->solvables;
- di->solvid--;
+ di->nparents = 0;
+ di->kv.parent = 0;
+ di->rootlevel = 0;
+ di->keyname = di->keynames[0];
+ if (solvid == SOLVID_POS)
+ {
+ di->repo = di->pool->pos.repo;
+ if (!di->repo)
+ {
+ di->state = di_bye;
+ return;
+ }
+ di->repoid = 0;
+ di->data = di->repo->repodata + di->pool->pos.repodataid;
+ di->repodataid = -1;
+ di->solvid = solvid;
+ di->state = di_enterrepo;
+ di->flags |= SEARCH_THISSOLVID;
+ return;
+ }
+ if (solvid > 0)
+ {
+ di->repo = di->pool->solvables[solvid].repo;
+ di->repoid = 0;
+ }
+ else if (di->repoid > 0)
+ {
+ if (!di->pool->nrepos)
+ {
+ di->state = di_bye;
+ return;
+ }
+ di->repoid = 1;
+ di->repo = di->pool->repos[0];
+ }
+ di->repodataid = 0;
+ di->solvid = solvid;
+ if (solvid)
+ di->flags |= SEARCH_THISSOLVID;
+ di->state = di_enterrepo;
}
void
dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
{
+ di->nparents = 0;
+ di->kv.parent = 0;
+ di->rootlevel = 0;
di->repo = repo;
- dataiterator_skip_solvable(di);
- di->solvid = repo->start - 1;
+ di->repoid = 0; /* 0 means stay at repo */
+ di->repodataid = 0;
+ di->solvid = 0;
+ di->flags &= ~SEARCH_THISSOLVID;
+ di->state = di_enterrepo;
}
-#endif
+int
+dataiterator_match(Dataiterator *di, Datamatcher *ma)
+{
+ if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
+ return 0;
+ if (!ma)
+ return 1;
+ return datamatcher_match(ma, di->kv.str);
+}
/************************************************************************
* data modify functions
int new = p - data->end + 1;
if (data->attrs)
{
- data->attrs = sat_extend(data->attrs, old, new, sizeof(Id), REPODATA_BLOCK);
- memset(data->attrs + old, 0, new * sizeof(Id));
+ data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
+ memset(data->attrs + old, 0, new * sizeof(Id *));
}
data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
memset(data->incoreoffset + old, 0, new * sizeof(Id));
int new = data->start - p;
if (data->attrs)
{
- data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id), REPODATA_BLOCK);
- memmove(data->attrs + new, data->attrs, old * sizeof(Id));
- memset(data->attrs, 0, new * sizeof(Id));
+ data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
+ memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
+ memset(data->attrs, 0, new * sizeof(Id *));
}
data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
}
}
+/* shrink end of repodata */
+void
+repodata_shrink(Repodata *data, int end)
+{
+ int i;
+
+ if (data->end <= end)
+ return;
+ if (data->start >= end)
+ {
+ if (data->attrs)
+ {
+ for (i = 0; i < data->end - data->start; i++)
+ sat_free(data->attrs[i]);
+ data->attrs = sat_free(data->attrs);
+ }
+ data->incoreoffset = sat_free(data->incoreoffset);
+ data->start = data->end = 0;
+ return;
+ }
+ if (data->attrs)
+ {
+ for (i = end; i < data->end; i++)
+ sat_free(data->attrs[i - data->start]);
+ data->attrs = sat_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
+ }
+ if (data->incoreoffset)
+ data->incoreoffset = sat_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
+ data->end = end;
+}
+
+/* extend repodata so that it includes solvables from start to start + num - 1 */
void
repodata_extend_block(Repodata *data, Id start, Id num)
{
/**********************************************************************/
-#define REPODATA_ATTRS_BLOCK 63
+
+#define REPODATA_ATTRS_BLOCK 31
#define REPODATA_ATTRDATA_BLOCK 1023
#define REPODATA_ATTRIDDATA_BLOCK 63
if (!data->nxattrs)
{
data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
- data->nxattrs = 2;
+ data->nxattrs = 2; /* -1: SOLVID_META */
}
data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
data->xattrs[data->nxattrs] = 0;
static inline Id **
repodata_get_attrp(Repodata *data, Id handle)
{
- if (handle == SOLVID_META)
+ if (handle < 0)
{
- if (!data->xattrs)
+ if (handle == SOLVID_META && !data->xattrs)
{
data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
data->nxattrs = 2;
}
+ return data->xattrs - handle;
}
- if (handle < 0)
- return data->xattrs - handle;
if (handle < data->start || handle >= data->end)
repodata_extend(data, handle);
if (!data->attrs)
i = 0;
if (ap)
{
+ /* Determine equality based on the name only, allows us to change
+ type (when overwrite is set), and makes TYPE_CONSTANT work. */
for (pp = ap; *pp; pp += 2)
- /* Determine equality based on the name only, allows us to change
- type (when overwrite is set), and makes TYPE_CONSTANT work. */
if (data->keys[*pp].name == data->keys[keyid].name)
break;
if (*pp)
{
- if (overwrite)
+ if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
{
pp[0] = keyid;
pp[1] = val;
}
-void
-repodata_set(Repodata *data, Id handle, Repokey *key, Id val)
+static void
+repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
{
Id keyid;
keyid = repodata_key2id(data, key, 1);
- repodata_insert_keyid(data, handle, keyid, val, 1);
+ repodata_insert_keyid(data, solvid, keyid, val, 1);
}
void
-repodata_set_id(Repodata *data, Id handle, Id keyname, Id id)
+repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
{
Repokey key;
key.name = keyname;
key.type = REPOKEY_TYPE_ID;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
- repodata_set(data, handle, &key, id);
+ repodata_set(data, solvid, &key, id);
}
void
-repodata_set_num(Repodata *data, Id handle, Id keyname, unsigned int num)
+repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
{
Repokey key;
key.name = keyname;
key.type = REPOKEY_TYPE_NUM;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
- repodata_set(data, handle, &key, (Id)num);
+ repodata_set(data, solvid, &key, (Id)num);
}
void
-repodata_set_poolstr(Repodata *data, Id handle, Id keyname, const char *str)
+repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
{
Repokey key;
Id id;
if (data->localpool)
id = stringpool_str2id(&data->spool, str, 1);
else
- id = str2id(data->repo->pool, str, 1);
+ id = pool_str2id(data->repo->pool, str, 1);
key.name = keyname;
key.type = REPOKEY_TYPE_ID;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
- repodata_set(data, handle, &key, id);
+ repodata_set(data, solvid, &key, id);
}
void
-repodata_set_constant(Repodata *data, Id handle, Id keyname, unsigned int constant)
+repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
{
Repokey key;
key.name = keyname;
key.type = REPOKEY_TYPE_CONSTANT;
key.size = constant;
key.storage = KEY_STORAGE_INCORE;
- repodata_set(data, handle, &key, 0);
+ repodata_set(data, solvid, &key, 0);
}
void
-repodata_set_constantid(Repodata *data, Id handle, Id keyname, Id id)
+repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
{
Repokey key;
key.name = keyname;
key.type = REPOKEY_TYPE_CONSTANTID;
key.size = id;
key.storage = KEY_STORAGE_INCORE;
- repodata_set(data, handle, &key, 0);
+ repodata_set(data, solvid, &key, 0);
}
void
-repodata_set_void(Repodata *data, Id handle, Id keyname)
+repodata_set_void(Repodata *data, Id solvid, Id keyname)
{
Repokey key;
key.name = keyname;
key.type = REPOKEY_TYPE_VOID;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
- repodata_set(data, handle, &key, 0);
+ repodata_set(data, solvid, &key, 0);
}
void
-repodata_set_str(Repodata *data, Id handle, Id keyname, const char *str)
+repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
{
Repokey key;
int l;
key.storage = KEY_STORAGE_INCORE;
data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
memcpy(data->attrdata + data->attrdatalen, str, l);
- repodata_set(data, handle, &key, data->attrdatalen);
+ repodata_set(data, solvid, &key, data->attrdatalen);
data->attrdatalen += l;
}
+void
+repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
+{
+ Repokey key;
+ unsigned char *dp;
+
+ key.name = keyname;
+ key.type = REPOKEY_TYPE_BINARY;
+ key.size = 0;
+ key.storage = KEY_STORAGE_INCORE;
+ data->attrdata = sat_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
+ dp = data->attrdata + data->attrdatalen;
+ if (len >= (1 << 14))
+ {
+ if (len >= (1 << 28))
+ *dp++ = (len >> 28) | 128;
+ if (len >= (1 << 21))
+ *dp++ = (len >> 21) | 128;
+ *dp++ = (len >> 14) | 128;
+ }
+ if (len >= (1 << 7))
+ *dp++ = (len >> 7) | 128;
+ *dp++ = len & 127;
+ if (len)
+ memcpy(dp, buf, len);
+ repodata_set(data, solvid, &key, data->attrdatalen);
+ data->attrdatalen = dp + len - data->attrdata;
+}
+
+/* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
+ * so that the caller can append entrysize new elements plus the termination zero there */
static void
repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
{
int oldsize;
Id *ida, *pp, **ppp;
+ /* check if it is the same as last time, this speeds things up a lot */
if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
{
/* great! just append the new data */
data->lastdatalen += entrysize;
return;
}
+
ppp = repodata_get_attrp(data, handle);
pp = *ppp;
if (pp)
- for (; *pp; pp += 2)
- if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
- break;
- if (!pp || !*pp)
+ {
+ for (; *pp; pp += 2)
+ if (data->keys[*pp].name == keyname)
+ break;
+ }
+ if (!pp || !*pp || data->keys[*pp].type != keytype)
{
/* not found. allocate new key */
Repokey key;
+ Id keyid;
key.name = keyname;
key.type = keytype;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
- repodata_set(data, handle, &key, data->attriddatalen);
- data->lasthandle = 0; /* next time... */
+ keyid = repodata_key2id(data, &key, 1);
+ repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
+ data->lasthandle = handle;
+ data->lastkey = keyid;
+ data->lastdatalen = data->attriddatalen + entrysize + 1;
return;
}
oldsize = 0;
data->lastdatalen = data->attriddatalen + entrysize + 1;
}
-static inline int
-checksumtype2len(Id type)
-{
- switch (type)
- {
- case REPOKEY_TYPE_MD5:
- return SIZEOF_MD5;
- case REPOKEY_TYPE_SHA1:
- return SIZEOF_SHA1;
- case REPOKEY_TYPE_SHA256:
- return SIZEOF_SHA256;
- default:
- return 0;
- }
-}
-
void
-repodata_set_bin_checksum(Repodata *data, Id handle, Id keyname, Id type,
+repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
const unsigned char *str)
{
Repokey key;
- int l = checksumtype2len(type);
+ int l;
- if (!l)
+ if (!(l = sat_chksum_len(type)))
return;
key.name = keyname;
key.type = type;
key.storage = KEY_STORAGE_INCORE;
data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
memcpy(data->attrdata + data->attrdatalen, str, l);
- repodata_set(data, handle, &key, data->attrdatalen);
+ repodata_set(data, solvid, &key, data->attrdatalen);
data->attrdatalen += l;
}
-static int
-hexstr2bytes(unsigned char *buf, const char *str, int buflen)
-{
- int i;
- for (i = 0; i < buflen; i++)
- {
-#define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
- : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
- : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
- : -1)
- int v = c2h(*str);
- str++;
- if (v < 0)
- return 0;
- buf[i] = v;
- v = c2h(*str);
- str++;
- if (v < 0)
- return 0;
- buf[i] = (buf[i] << 4) | v;
-#undef c2h
- }
- return buflen;
-}
-
void
-repodata_set_checksum(Repodata *data, Id handle, Id keyname, Id type,
+repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
const char *str)
{
unsigned char buf[64];
- int l = checksumtype2len(type);
+ int l;
- if (!l)
+ if (!(l = sat_chksum_len(type)))
return;
- if (hexstr2bytes(buf, str, l) != l)
- {
- fprintf(stderr, "Invalid hex character in '%s'\n", str);
- return;
- }
- repodata_set_bin_checksum(data, handle, keyname, type, buf);
+ if (l > sizeof(buf) || sat_hex2bin(&str, buf, l) != l)
+ return;
+ repodata_set_bin_checksum(data, solvid, keyname, type, buf);
}
const char *
repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
{
- int i, l;
- char *str, *s;
+ int l;
- l = checksumtype2len(type);
- if (!l)
+ if (!(l = sat_chksum_len(type)))
return "";
- s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
- for (i = 0; i < l; i++)
+ return pool_bin2hex(data->repo->pool, buf, l);
+}
+
+/* rpm filenames don't contain the epoch, so strip it */
+static inline const char *
+evrid2vrstr(Pool *pool, Id evrid)
+{
+ const char *p, *evr = pool_id2str(pool, evrid);
+ if (!evr)
+ return evr;
+ for (p = evr; *p >= '0' && *p <= '9'; p++)
+ ;
+ return p != evr && *p == ':' ? p + 1 : evr;
+}
+
+void
+repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
+{
+ Pool *pool = data->repo->pool;
+ Solvable *s;
+ const char *str, *fp;
+ int l = 0;
+
+ if (medianr)
+ repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
+ if (!dir)
+ {
+ if ((dir = strrchr(file, '/')) != 0)
+ {
+ l = dir - file;
+ dir = file;
+ file = dir + l + 1;
+ if (!l)
+ l++;
+ }
+ }
+ else
+ l = strlen(dir);
+ if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
{
- unsigned char v = buf[i];
- unsigned char w = v >> 4;
- *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
- w = v & 15;
- *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
+ dir += 2;
+ l -= 2;
}
- *s = 0;
- return str;
+ if (l == 1 && dir[0] == '.')
+ l = 0;
+ s = pool->solvables + solvid;
+ if (dir && l)
+ {
+ str = pool_id2str(pool, s->arch);
+ if (!strncmp(dir, str, l) && !str[l])
+ repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
+ else if (!dir[l])
+ repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
+ else
+ {
+ char *dir2 = strdup(dir);
+ dir2[l] = 0;
+ repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
+ free(dir2);
+ }
+ }
+ fp = file;
+ str = pool_id2str(pool, s->name);
+ l = strlen(str);
+ if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
+ {
+ fp += l + 1;
+ str = evrid2vrstr(pool, s->evr);
+ l = strlen(str);
+ if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
+ {
+ fp += l + 1;
+ str = pool_id2str(pool, s->arch);
+ l = strlen(str);
+ if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
+ {
+ repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
+ return;
+ }
+ }
+ }
+ repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
}
-Id
-repodata_globalize_id(Repodata *data, Id id)
+void
+repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
{
- if (!data || !data->localpool)
- return id;
- return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
+ Repokey key;
+ int i;
+
+ key.name = keyname;
+ key.type = REPOKEY_TYPE_IDARRAY;
+ key.size = 0;
+ key.storage = KEY_STORAGE_INCORE;
+ repodata_set(data, solvid, &key, data->attriddatalen);
+ data->attriddata = sat_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+ for (i = 0; i < q->count; i++)
+ data->attriddata[data->attriddatalen++] = q->elements[i];
+ data->attriddata[data->attriddatalen++] = 0;
}
void
-repodata_add_dirnumnum(Repodata *data, Id handle, Id keyname, Id dir, Id num, Id num2)
+repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
{
assert(dir);
#if 0
-fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", handle, dir, num, num2, data->attriddatalen);
+fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
#endif
- repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
+ repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
data->attriddata[data->attriddatalen++] = dir;
data->attriddata[data->attriddatalen++] = num;
data->attriddata[data->attriddatalen++] = num2;
}
void
-repodata_add_dirstr(Repodata *data, Id handle, Id keyname, Id dir, const char *str)
+repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
{
Id stroff;
int l;
data->attrdatalen += l;
#if 0
-fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", handle, dir, str, data->attriddatalen);
+fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
#endif
- repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
+ repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
data->attriddata[data->attriddatalen++] = dir;
data->attriddata[data->attriddatalen++] = stroff;
data->attriddata[data->attriddatalen++] = 0;
}
void
-repodata_add_idarray(Repodata *data, Id handle, Id keyname, Id id)
+repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
{
#if 0
-fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", handle, id, data->attriddatalen);
+fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
#endif
- repodata_add_array(data, handle, keyname, REPOKEY_TYPE_IDARRAY, 1);
+ repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
data->attriddata[data->attriddatalen++] = id;
data->attriddata[data->attriddatalen++] = 0;
}
void
-repodata_add_poolstr_array(Repodata *data, Id handle, Id keyname,
+repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
const char *str)
{
Id id;
if (data->localpool)
id = stringpool_str2id(&data->spool, str, 1);
else
- id = str2id(data->repo->pool, str, 1);
- repodata_add_idarray(data, handle, keyname, id);
+ id = pool_str2id(data->repo->pool, str, 1);
+ repodata_add_idarray(data, solvid, keyname, id);
}
void
-repodata_add_fixarray(Repodata *data, Id handle, Id keyname, Id ghandle)
+repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
{
- repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FIXARRAY, 1);
+ repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
data->attriddata[data->attriddatalen++] = ghandle;
data->attriddata[data->attriddatalen++] = 0;
}
void
-repodata_add_flexarray(Repodata *data, Id handle, Id keyname, Id ghandle)
+repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
{
- repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
+ repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
data->attriddata[data->attriddatalen++] = ghandle;
data->attriddata[data->attriddatalen++] = 0;
}
void
+repodata_delete_uninternalized(Repodata *data, Id solvid, Id keyname)
+{
+ Id *pp, *ap, **app;
+ app = repodata_get_attrp(data, solvid);
+ ap = *app;
+ if (!ap)
+ return;
+ for (; *ap; ap += 2)
+ if (data->keys[*ap].name == keyname)
+ break;
+ if (!*ap)
+ return;
+ pp = ap;
+ ap += 2;
+ for (; *ap; ap += 2)
+ {
+ if (data->keys[*ap].name == keyname)
+ continue;
+ *pp++ = ap[0];
+ *pp++ = ap[1];
+ }
+ *pp = 0;
+}
+
+/* XXX: does not work correctly, needs fix in iterators! */
+void
+repodata_delete(Repodata *data, Id solvid, Id keyname)
+{
+ Repokey key;
+ key.name = keyname;
+ key.type = REPOKEY_TYPE_DELETED;
+ key.size = 0;
+ key.storage = KEY_STORAGE_INCORE;
+ repodata_set(data, solvid, &key, 0);
+}
+
+/* add all (uninternalized) attrs from src to dest */
+void
repodata_merge_attrs(Repodata *data, Id dest, Id src)
{
Id *keyp;
- if (dest == src || !(keyp = data->attrs[src]))
+ if (dest == src || !(keyp = data->attrs[src - data->start]))
return;
for (; *keyp; keyp += 2)
repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
}
+/* add some (uninternalized) attrs from src to dest */
+void
+repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
+{
+ Id *keyp;
+ if (dest == src || !(keyp = data->attrs[src - data->start]))
+ return;
+ for (; *keyp; keyp += 2)
+ if (!keyidmap || MAPTST(keyidmap, keyp[0]))
+ repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
+}
/**********************************************************************/
-/* unify with repo_write! */
+/* TODO: unify with repo_write and repo_solv! */
#define EXTDATA_BLOCK 1023
data_addid(struct extdata *xd, Id x)
{
unsigned char *dp;
+
xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
dp = xd->buf + xd->len;
{
if (x >= 64)
x = (x & 63) | ((x & ~63) << 1);
- data_addid(xd, (eof ? x: x | 64));
+ data_addid(xd, (eof ? x : x | 64));
}
static void
/*********************************/
+/* internalalize some key into incore/vincore data */
+
static void
repodata_serialize_key(Repodata *data, struct extdata *newincore,
struct extdata *newvincore,
Id *schema,
Repokey *key, Id val)
{
- /* Otherwise we have a new value. Parse it into the internal
- form. */
Id *ida;
struct extdata *xd;
unsigned int oldvincorelen = 0;
case REPOKEY_TYPE_DIR:
data_addid(xd, val);
break;
+ case REPOKEY_TYPE_BINARY:
+ {
+ Id len;
+ unsigned char *dp = data_read_id(data->attrdata + val, &len);
+ dp += len;
+ data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
+ }
+ break;
case REPOKEY_TYPE_IDARRAY:
for (ida = data->attriddata + val; *ida; ida++)
data_addideof(xd, ida[0], ida[1] ? 0 : 1);
schemaid = 0;
for (ida = data->attriddata + val; *ida; ida++)
{
-#if 0
- fprintf(stderr, "serialize struct %d\n", *ida);
-#endif
sp = schema;
Id *kp = data->xattrs[-*ida];
if (!kp)
continue;
num++;
for (;*kp; kp += 2)
- {
-#if 0
- fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
-#endif
- *sp++ = *kp;
- }
+ *sp++ = *kp;
*sp = 0;
if (!schemaid)
schemaid = repodata_schema2id(data, schema, 1);
else if (schemaid != repodata_schema2id(data, schema, 0))
{
- fprintf(stderr, " not yet implemented: substructs with different schemas\n");
+ pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
exit(1);
}
-#if 0
- fprintf(stderr, " schema %d\n", schemaid);
-#endif
}
if (!num)
break;
if (!kp)
continue;
for (;*kp; kp += 2)
- {
- repodata_serialize_key(data, newincore, newvincore,
- schema, data->keys + *kp, kp[1]);
- }
+ repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
}
break;
}
data_addid(xd, schemaid);
kp = data->xattrs[-*ida];
for (;*kp; kp += 2)
- {
- repodata_serialize_key(data, newincore, newvincore,
- schema, data->keys + *kp, kp[1]);
- }
+ repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
}
break;
}
default:
- fprintf(stderr, "don't know how to handle type %d\n", key->type);
+ pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
exit(1);
}
if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
{
if (seen[*keyp])
{
- fprintf(stderr, "Inconsistent old data (key occured twice).\n");
+ pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
exit(1);
}
seen[*keyp] = -1;
}
key = data->keys + *keyp;
#if 0
- fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
+ fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, pool_id2str(data->repo->pool, key->name), pool_id2str(data->repo->pool, key->type));
#endif
ndp = dp;
if (oldcount)
repopagestore_disable_paging(&data->store);
}
+static void
+repodata_load_stub(Repodata *data)
+{
+ Repo *repo = data->repo;
+ Pool *pool = repo->pool;
+ int r, i;
+ struct _Pool_tmpspace oldtmpspace;
+
+ if (!pool->loadcallback)
+ {
+ data->state = REPODATA_ERROR;
+ return;
+ }
+ data->state = REPODATA_LOADING;
+
+ /* save tmp space */
+ oldtmpspace = pool->tmpspace;
+ memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
+
+ r = pool->loadcallback(pool, data, pool->loadcallbackdata);
+
+ /* restore tmp space */
+ for (i = 0; i < POOL_TMPSPACEBUF; i++)
+ sat_free(pool->tmpspace.buf[i]);
+ pool->tmpspace = oldtmpspace;
+
+ data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
+}
+
+void
+repodata_create_stubs(Repodata *data)
+{
+ Repo *repo = data->repo;
+ Pool *pool = repo->pool;
+ Repodata *sdata;
+ int *stubdataids;
+ Dataiterator di;
+ Id xkeyname = 0;
+ int i, cnt = 0;
+ int repodataid;
+ int datastart, dataend;
+
+ repodataid = data - repo->repodata;
+ datastart = data->start;
+ dataend = data->end;
+ dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
+ while (dataiterator_step(&di))
+ {
+ if (di.data - repo->repodata != repodataid)
+ continue;
+ cnt++;
+ }
+ dataiterator_free(&di);
+ if (!cnt)
+ return;
+ stubdataids = sat_calloc(cnt, sizeof(*stubdataids));
+ for (i = 0; i < cnt; i++)
+ {
+ sdata = repo_add_repodata(repo, 0);
+ if (dataend > datastart)
+ repodata_extend_block(sdata, datastart, dataend - datastart);
+ stubdataids[i] = sdata - repo->repodata;
+ sdata->state = REPODATA_STUB;
+ sdata->loadcallback = repodata_load_stub;
+ }
+ i = 0;
+ dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
+ sdata = 0;
+ while (dataiterator_step(&di))
+ {
+ if (di.data - repo->repodata != repodataid)
+ continue;
+ if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
+ {
+ dataiterator_entersub(&di);
+ sdata = repo->repodata + stubdataids[i++];
+ xkeyname = 0;
+ continue;
+ }
+ switch (di.key->type)
+ {
+ case REPOKEY_TYPE_ID:
+ repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
+ break;
+ case REPOKEY_TYPE_CONSTANTID:
+ repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
+ break;
+ case REPOKEY_TYPE_STR:
+ repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
+ break;
+ case REPOKEY_TYPE_VOID:
+ repodata_set_void(sdata, SOLVID_META, di.key->name);
+ break;
+ case REPOKEY_TYPE_NUM:
+ repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
+ break;
+ case REPOKEY_TYPE_MD5:
+ case REPOKEY_TYPE_SHA1:
+ case REPOKEY_TYPE_SHA256:
+ repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
+ break;
+ case REPOKEY_TYPE_IDARRAY:
+ repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
+ if (di.key->name == REPOSITORY_KEYS)
+ {
+ Repokey xkey;
+
+ if (!xkeyname)
+ {
+ if (!di.kv.eof)
+ xkeyname = di.kv.id;
+ continue;
+ }
+ xkey.name = xkeyname;
+ xkey.type = di.kv.id;
+ xkey.storage = KEY_STORAGE_INCORE;
+ xkey.size = 0;
+ repodata_key2id(sdata, &xkey, 1);
+ xkeyname = 0;
+ }
+ default:
+ break;
+ }
+ }
+ dataiterator_free(&di);
+ for (i = 0; i < cnt; i++)
+ repodata_internalize(repo->repodata + stubdataids[i]);
+ sat_free(stubdataids);
+}
+
/*
vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
*/