#define _GNU_SOURCE
#include <string.h>
+#include <fnmatch.h>
#include <stdio.h>
#include <stdlib.h>
#include "poolid_private.h"
#include "util.h"
-#include "fastlz.c"
+#include "repopack.h"
-unsigned char *
-data_read_id(unsigned char *dp, Id *idp)
-{
- Id x = 0;
- unsigned char c;
- for (;;)
- {
- c = *dp++;
- if (!(c & 0x80))
- {
- *idp = (x << 7) ^ c;
- return dp;
- }
- x = (x << 7) ^ c ^ 128;
- }
-}
+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);
-static unsigned char *
-data_read_ideof(unsigned char *dp, Id *idp, int *eof)
-{
- Id x = 0;
- unsigned char c;
- for (;;)
- {
- c = *dp++;
- if (!(c & 0x80))
- {
- if (c & 0x40)
- {
- c ^= 0x40;
- *eof = 0;
- }
- else
- *eof = 1;
- *idp = (x << 6) ^ c;
- return dp;
- }
- x = (x << 7) ^ c ^ 128;
- }
-}
+#define REPODATA_BLOCK 255
-static unsigned char *
-data_skip(unsigned char *dp, int type)
+
+void
+repodata_init(Repodata *data, Repo *repo, int localpool)
{
- unsigned char x;
- switch (type)
- {
- case TYPE_VOID:
- case TYPE_CONSTANT:
- return dp;
- case TYPE_ID:
- case TYPE_NUM:
- case TYPE_DIR:
- while ((*dp & 0x80) != 0)
- dp++;
- return dp + 1;
- case TYPE_IDARRAY:
- while ((*dp & 0xc0) != 0)
- dp++;
- return dp + 1;
- case TYPE_STR:
- while ((*dp) != 0)
- dp++;
- return dp + 1;
- case TYPE_DIRSTRARRAY:
- for (;;)
- {
- while ((*dp & 0x80) != 0)
- dp++;
- x = *dp++;
- while ((*dp) != 0)
- dp++;
- dp++;
- if (!(x & 0x40))
- return dp;
- }
- case TYPE_DIRNUMNUMARRAY:
- for (;;)
- {
- while ((*dp & 0x80) != 0)
- dp++;
- dp++;
- while ((*dp & 0x80) != 0)
- dp++;
- dp++;
- while ((*dp & 0x80) != 0)
- dp++;
- if (!(*dp & 0x40))
- return dp + 1;
- dp++;
- }
- default:
- fprintf(stderr, "unknown type in data_skip\n");
- exit(1);
- }
+ memset(data, 0, sizeof (*data));
+ data->repo = repo;
+ data->localpool = localpool;
+ if (localpool)
+ stringpool_init_empty(&data->spool);
+ data->keys = sat_calloc(1, sizeof(Repokey));
+ data->nkeys = 1;
+ data->schemata = sat_calloc(1, sizeof(Id));
+ data->schemadata = sat_calloc(1, sizeof(Id));
+ data->nschemata = 1;
+ data->schemadatalen = 1;
+ data->start = repo->start;
+ data->end = repo->end;
+ data->incoreoffset = sat_extend_resize(0, data->end - data->start, sizeof(Id), REPODATA_BLOCK);
+ data->pagefd = -1;
}
-static unsigned char *
-data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
+void
+repodata_free(Repodata *data)
{
- kv->eof = 1;
- if (!dp)
- return 0;
- switch (key->type)
- {
- case TYPE_VOID:
- return dp;
- case TYPE_CONSTANT:
- kv->num = key->size;
- return dp;
- case TYPE_STR:
- kv->str = (const char *)dp;
- return dp + strlen(kv->str) + 1;
- case TYPE_ID:
- return data_read_id(dp, &kv->id);
- case TYPE_NUM:
- return data_read_id(dp, &kv->num);
- case TYPE_IDARRAY:
- return data_read_ideof(dp, &kv->id, &kv->eof);
- case TYPE_DIR:
- return data_read_id(dp, &kv->id);
- case TYPE_DIRSTRARRAY:
- dp = data_read_ideof(dp, &kv->id, &kv->eof);
- kv->str = (const char *)dp;
- return dp + strlen(kv->str) + 1;
- case TYPE_DIRNUMNUMARRAY:
- dp = data_read_id(dp, &kv->id);
- dp = data_read_id(dp, &kv->num);
- return data_read_ideof(dp, &kv->num2, &kv->eof);
- default:
- return 0;
- }
+ sat_free(data->keys);
+ sat_free(data->schemata);
+ sat_free(data->schemadata);
+
+ sat_free(data->spool.strings);
+ sat_free(data->spool.stringspace);
+ sat_free(data->spool.stringhashtbl);
+
+ sat_free(data->dirpool.dirs);
+ sat_free(data->dirpool.dirtraverse);
+
+ sat_free(data->incoredata);
+ sat_free(data->incoreoffset);
+ sat_free(data->verticaloffset);
+
+ sat_free(data->blob_store);
+ sat_free(data->pages);
+ sat_free(data->mapped);
+
+ sat_free(data->vincore);
+
+ sat_free(data->attrs);
+ sat_free(data->attrdata);
+ sat_free(data->attriddata);
+
+ sat_free(data->location);
+
+ if (data->pagefd != -1)
+ close(data->pagefd);
}
static unsigned char *
-forward_to_key(Repodata *data, Id key, Id schemaid, unsigned char *dp)
+forward_to_key(Repodata *data, Id keyid, Id schemaid, unsigned char *dp)
{
Id k, *keyp;
keyp = data->schemadata + data->schemata[schemaid];
while ((k = *keyp++) != 0)
{
- if (k == key)
+ if (k == keyid)
return dp;
if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
{
- dp = data_skip(dp, TYPE_ID); /* skip that offset */
- dp = data_skip(dp, TYPE_ID); /* skip that length */
+ dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip that offset */
+ dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip that length */
continue;
}
if (data->keys[k].storage != KEY_STORAGE_INCORE)
if (i > pend)
return data->blob_store + data->pages[pstart].mapped_at;
+ if (data->pagefd == -1)
+ return 0;
+
/* Ensure that we can map the numbers of pages we need at all. */
if (pend - pstart + 1 > data->ncanmap)
{
#ifdef DEBUG_PAGING
fprintf (stderr, "PAGEIN: %d to %d", i, pnum);
#endif
- /* Not mapped, so read in this page. */
- if (fseek(data->fp, p->file_offset, SEEK_SET) < 0)
- {
- perror ("mapping fseek");
- exit (1);
- }
- if (fread(compressed ? buf : dest, in_len, 1, data->fp) != 1)
+ if (pread(data->pagefd, compressed ? buf : dest, in_len, p->file_offset) != in_len)
{
- perror ("mapping fread");
- exit (1);
+ perror ("mapping pread");
+ return 0;
}
if (compressed)
{
unsigned int out_len;
out_len = unchecked_decompress_buf(buf, in_len,
dest, BLOB_PAGESIZE);
- if (out_len != BLOB_PAGESIZE
- && i < data->num_pages - 1)
+ if (out_len != BLOB_PAGESIZE && i < data->num_pages - 1)
{
- fprintf (stderr, "can't decompress\n");
- exit (1);
+ fprintf(stderr, "can't decompress\n");
+ return 0;
}
#ifdef DEBUG_PAGING
fprintf (stderr, " (expand %d to %d)", in_len, out_len);
make_vertical_available(Repodata *data, Repokey *key, Id off, Id len)
{
unsigned char *dp;
- if (key->type == TYPE_VOID)
+ if (!len)
return 0;
if (off >= data->lastverticaloffset)
{
return 0;
return data->vincore + off;
}
- if (!data->fp)
- return 0;
if (off + len > key->size)
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 = load_page_range(data, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
if (dp)
dp += off % BLOB_PAGESIZE;
}
static inline int
-maybe_load_repodata(Repodata *data)
+maybe_load_repodata(Repodata *data, Id *keyid)
{
if (data->state == REPODATA_STUB)
{
if (data->loadcallback)
- data->loadcallback(data);
+ {
+ if (keyid)
+ {
+ /* key order may change when loading */
+ int i;
+ Id name = data->keys[*keyid].name;
+ Id type = data->keys[*keyid].type;
+ data->loadcallback(data);
+ if (data->state == REPODATA_AVAILABLE)
+ {
+ for (i = 1; i < data->nkeys; i++)
+ if (data->keys[i].name == name && data->keys[i].type == type)
+ break;
+ if (i < data->nkeys)
+ *keyid = i;
+ else
+ return 0;
+ }
+ }
+ else
+ data->loadcallback(data);
+ }
else
data->state = REPODATA_ERROR;
}
Id id, *keyp;
unsigned char *dp;
- if (!maybe_load_repodata (data))
+ if (!maybe_load_repodata(data, &keyid))
return 0;
dp = data->incoredata + data->incoreoffset[entry];
dp = get_data(data, key, &dp);
if (!dp)
return 0;
- if (key->type == TYPE_STR)
+ if (key->type == REPOKEY_TYPE_STR)
return (const char *)dp;
- if (key->type != TYPE_ID)
+ if (key->type == REPOKEY_TYPE_CONSTANTID)
+ return id2str(data->repo->pool, key->size);
+ if (key->type == REPOKEY_TYPE_ID)
+ dp = data_read_id(dp, &id);
+ else
return 0;
- /* id type, must either use global or local string store*/
- dp = data_read_id(dp, &id);
if (data->localpool)
return data->spool.stringspace + data->spool.strings[id];
return id2str(data->repo->pool, id);
}
int
-repodata_lookup_num(Repodata *data, Id entry, Id keyid, unsigned *value)
+repodata_lookup_num(Repodata *data, Id entry, Id keyid, unsigned int *value)
{
Id schema;
Repokey *key;
*value = 0;
- if (!maybe_load_repodata (data))
+ if (!maybe_load_repodata(data, &keyid))
return 0;
dp = data->incoredata + data->incoreoffset[entry];
dp = get_data(data, key, &dp);
if (!dp)
return 0;
- if (key->type == TYPE_NUM
- || key->type == TYPE_U32
- || key->type == TYPE_CONSTANT)
+ if (key->type == REPOKEY_TYPE_NUM
+ || key->type == REPOKEY_TYPE_U32
+ || key->type == REPOKEY_TYPE_CONSTANT)
{
dp = data_fetch(dp, &kv, key);
*value = kv.num;
return 0;
}
+int
+repodata_lookup_void(Repodata *data, Id entry, Id keyid)
+{
+ Id schema;
+ Id *keyp;
+ unsigned char *dp;
+ if (!maybe_load_repodata(data, &keyid))
+ return 0;
+ dp = data->incoredata + data->incoreoffset[entry];
+ dp = data_read_id(dp, &schema);
+ for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
+ if (!*keyp)
+ return 0;
+ return 1;
+}
+
void
repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
{
int stop;
KeyValue kv;
- if (!maybe_load_repodata (data))
+ if (!maybe_load_repodata(data, 0))
return;
dp = data->incoredata + data->incoreoffset[entry];
}
}
+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 + 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, schema, 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)
+ {
+ 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;
+ }
+ else
+ {
+ di->solvid = repo->start - 1;
+ di->data = repo->repodata + repo->nrepodata - 1;
+ di->state = 0;
+ }
+ di->match = match;
+ di->keyname = keyname;
+ static Id zeroid = 0;
+ di->keyp = &zeroid;
+ di->kv.eof = 1;
+ di->repo = repo;
+ di->idp = 0;
+}
+
+/* FIXME factor and merge with repo_matchvalue */
+static int
+dataiterator_match(Dataiterator *di, KeyValue *kv)
+{
+ int flags = di->flags;
+
+ 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;
+ default:
+ return 0;
+ }
+ switch ((flags & SEARCH_STRINGMASK))
+ {
+ case SEARCH_SUBSTRING:
+ if (flags & SEARCH_NOCASE)
+ {
+ if (!strcasestr(kv->str, di->match))
+ return 0;
+ }
+ else
+ {
+ if (!strstr(kv->str, di->match))
+ return 0;
+ }
+ break;
+ case SEARCH_STRING:
+ if (flags & SEARCH_NOCASE)
+ {
+ if (strcasecmp(di->match, kv->str))
+ return 0;
+ }
+ else
+ {
+ if (strcmp(di->match, kv->str))
+ return 0;
+ }
+ break;
+ case SEARCH_GLOB:
+ if (fnmatch(di->match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
+ return 0;
+ break;
+#if 0
+ case SEARCH_REGEX:
+ if (regexec(&di->regexp, kv->str, 0, NULL, 0))
+ return 0;
+#endif
+ default:
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
+ { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_FRESHENS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
+};
+
+int
+dataiterator_step(Dataiterator *di)
+{
+restart:
+ while (1)
+ {
+ if (di->state)
+ {
+ if (di->idp)
+ {
+ 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;
+ break;
+ case SOLVABLE_ARCH:
+ if (!s->arch)
+ continue;
+ di->kv.id = s->arch;
+ break;
+ case SOLVABLE_EVR:
+ if (!s->evr)
+ continue;
+ di->kv.id = s->evr;
+ break;
+ case SOLVABLE_VENDOR:
+ if (!s->vendor)
+ continue;
+ di->kv.id = s->vendor;
+ 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 SOLVABLE_FRESHENS:
+ di->idp = s->freshens
+ ? di->repo->idarraydata + s->freshens : 0;
+ continue;
+ case RPM_RPMDBID:
+ if (!di->repo->rpmdbid)
+ continue;
+ di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
+ break;
+ default:
+ di->data = di->repo->repodata - 1;
+ di->kv.eof = 1;
+ di->state = 0;
+ continue;
+ }
+ }
+ else
+ {
+ 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;
+ while (++di->solvid < repo->end)
+ if (repo->pool->solvables[di->solvid].repo == repo)
+ break;
+ if (di->solvid >= repo->end)
+ return 0;
+ 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 >= 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);
+ }
+ }
+weg2:
+ if (!di->match
+ || dataiterator_match(di, &di->kv))
+ break;
+ }
+ return 1;
+}
/* extend repodata so that it includes solvables p */
void
int new = p - data->end + 1;
if (data->attrs)
{
- data->attrs = sat_realloc2(data->attrs, old + 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_realloc2(data->incoreoffset, old + new, sizeof(Id));
+ data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
memset(data->incoreoffset + old, 0, new * sizeof(Id));
data->end = p + 1;
}
int new = data->start - p;
if (data->attrs)
{
- data->attrs = sat_realloc2(data->attrs, old + 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_realloc2(data->incoreoffset, old + 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));
memset(data->incoreoffset, 0, new * sizeof(Id));
data->start = p;
}
}
+void
+repodata_extend_block(Repodata *data, Id start, Id num)
+{
+ if (!num)
+ return;
+ if (!data->incoreoffset)
+ {
+ data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
+ data->start = start;
+ data->end = start + num;
+ return;
+ }
+ repodata_extend(data, start);
+ if (num > 1)
+ repodata_extend(data, start + num - 1);
+}
+
+/**********************************************************************/
+
+#define REPODATA_ATTRS_BLOCK 63
+#define REPODATA_ATTRDATA_BLOCK 1023
+#define REPODATA_ATTRIDDATA_BLOCK 63
+
static void
repodata_insert_keyid(Repodata *data, Id entry, Id keyid, Id val, int overwrite)
{
Id *pp;
int i;
if (!data->attrs)
- data->attrs = sat_calloc(data->end - data->start + 1, sizeof(Id *));
+ {
+ data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *),
+ REPODATA_BLOCK);
+ }
i = 0;
if (data->attrs[entry])
{
}
i = pp - data->attrs[entry];
}
- data->attrs[entry] = sat_realloc2(data->attrs[entry], i + 3, sizeof(Id));
+ data->attrs[entry] = sat_extend(data->attrs[entry], i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
pp = data->attrs[entry] + i;
*pp++ = keyid;
*pp++ = val;
for (keyid = 1; keyid < data->nkeys; keyid++)
if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
{
- if (key->type == TYPE_CONSTANT && key->size != data->keys[keyid].size)
+ if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
continue;
break;
}
{
Repokey key;
key.name = keyname;
- key.type = TYPE_ID;
+ key.type = REPOKEY_TYPE_ID;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
repodata_set(data, entry, &key, id);
{
Repokey key;
key.name = keyname;
- key.type = TYPE_NUM;
+ key.type = REPOKEY_TYPE_NUM;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
repodata_set(data, entry, &key, num);
else
id = str2id(data->repo->pool, str, 1);
key.name = keyname;
- key.type = TYPE_ID;
+ key.type = REPOKEY_TYPE_ID;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
repodata_set(data, entry, &key, id);
{
Repokey key;
key.name = keyname;
- key.type = TYPE_CONSTANT;
+ key.type = REPOKEY_TYPE_CONSTANT;
key.size = constant;
key.storage = KEY_STORAGE_INCORE;
repodata_set(data, entry, &key, 0);
}
void
+repodata_set_constantid(Repodata *data, Id entry, 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, entry, &key, 0);
+}
+
+void
repodata_set_void(Repodata *data, Id entry, Id keyname)
{
Repokey key;
key.name = keyname;
- key.type = TYPE_VOID;
+ key.type = REPOKEY_TYPE_VOID;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
repodata_set(data, entry, &key, 0);
l = strlen(str) + 1;
key.name = keyname;
- key.type = TYPE_STR;
+ key.type = REPOKEY_TYPE_STR;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
- data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l);
+ data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
memcpy(data->attrdata + data->attrdatalen, str, l);
repodata_set(data, entry, &key, data->attrdatalen);
data->attrdatalen += l;
if (data->attrs && data->attrs[entry])
{
for (pp = data->attrs[entry]; *pp; pp += 2)
- if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRNUMNUMARRAY)
+ if (data->keys[*pp].name == keyname && data->keys[*pp].type == REPOKEY_TYPE_DIRNUMNUMARRAY)
break;
if (*pp)
{
if (ida + 1 == data->attriddata + data->attriddatalen)
{
/* this was the last entry, just append it */
- data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id));
+ data->attriddata = sat_extend(data->attriddata, data->attriddatalen, 3, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
data->attriddatalen--; /* overwrite terminating 0 */
}
else
{
/* too bad. move to back. */
- data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 4, sizeof(Id));
+ data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + 4, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
pp[1] = data->attriddatalen;
data->attriddatalen += oldsize;
}
}
key.name = keyname;
- key.type = TYPE_DIRNUMNUMARRAY;
+ key.type = REPOKEY_TYPE_DIRNUMNUMARRAY;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
- data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 4, sizeof(Id));
+ data->attriddata = sat_extend(data->attriddata, data->attriddatalen, 4, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
repodata_set(data, entry, &key, data->attriddatalen);
data->attriddata[data->attriddatalen++] = dir;
data->attriddata[data->attriddatalen++] = num;
}
void
-repodata_merge_attrs (Repodata *data, Id dest, Id src)
+repodata_add_dirstr(Repodata *data, Id entry, Id keyname, Id dir, const char *str)
+{
+ Id *ida, *pp, stroff;
+ Repokey key;
+ int l;
+
+ l = strlen(str) + 1;
+ data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
+ memcpy(data->attrdata + data->attrdatalen, str, l);
+ stroff = data->attrdatalen;
+ data->attrdatalen += l;
+
+#if 0
+fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", entry, dir, str, data->attriddatalen);
+#endif
+ if (data->attrs && data->attrs[entry])
+ {
+ for (pp = data->attrs[entry]; *pp; pp += 2)
+ if (data->keys[*pp].name == keyname && data->keys[*pp].type == REPOKEY_TYPE_DIRSTRARRAY)
+ break;
+ if (*pp)
+ {
+ int oldsize = 0;
+ for (ida = data->attriddata + pp[1]; *ida; ida += 2)
+ oldsize += 2;
+ if (ida + 1 == data->attriddata + data->attriddatalen)
+ {
+ /* this was the last entry, just append it */
+ data->attriddata = sat_extend(data->attriddata, data->attriddatalen, 2, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+ data->attriddatalen--; /* overwrite terminating 0 */
+ }
+ else
+ {
+ /* too bad. move to back. */
+ data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + 3, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+ memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
+ pp[1] = data->attriddatalen;
+ data->attriddatalen += oldsize;
+ }
+ data->attriddata[data->attriddatalen++] = dir;
+ data->attriddata[data->attriddatalen++] = stroff;
+ data->attriddata[data->attriddatalen++] = 0;
+ return;
+ }
+ }
+ key.name = keyname;
+ key.type = REPOKEY_TYPE_DIRSTRARRAY;
+ key.size = 0;
+ key.storage = KEY_STORAGE_INCORE;
+ data->attriddata = sat_extend(data->attriddata, data->attriddatalen, 3, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+ repodata_set(data, entry, &key, data->attriddatalen);
+ data->attriddata[data->attriddatalen++] = dir;
+ data->attriddata[data->attriddatalen++] = stroff;
+ data->attriddata[data->attriddatalen++] = 0;
+}
+
+void
+repodata_merge_attrs(Repodata *data, Id dest, Id src)
{
Id *keyp;
- for (keyp = data->attrs[src]; *keyp; keyp += 2)
+ if (dest == src || !(keyp = data->attrs[src]))
+ return;
+ for (; *keyp; keyp += 2)
repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
}
/* Skip the data associated with this old key. */
if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
{
- ndp = data_skip(dp, TYPE_ID);
- ndp = data_skip(ndp, TYPE_ID);
+ ndp = data_skip(dp, REPOKEY_TYPE_ID);
+ ndp = data_skip(ndp, REPOKEY_TYPE_ID);
}
else if (key->storage == KEY_STORAGE_INCORE)
ndp = data_skip(dp, key->type);
id = seen[*keyp] - 1;
switch (key->type)
{
- case TYPE_VOID:
- case TYPE_CONSTANT:
+ case REPOKEY_TYPE_VOID:
+ case REPOKEY_TYPE_CONSTANT:
+ case REPOKEY_TYPE_CONSTANTID:
break;
- case TYPE_STR:
+ case REPOKEY_TYPE_STR:
data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
break;
- case TYPE_ID:
- case TYPE_NUM:
- case TYPE_DIR:
+ case REPOKEY_TYPE_ID:
+ case REPOKEY_TYPE_NUM:
+ case REPOKEY_TYPE_DIR:
data_addid(xd, id);
break;
- case TYPE_DIRNUMNUMARRAY:
+ case REPOKEY_TYPE_DIRNUMNUMARRAY:
for (ida = data->attriddata + id; *ida; ida += 3)
{
data_addid(xd, ida[0]);
data_addideof(xd, ida[2], ida[3] ? 0 : 1);
}
break;
+ case REPOKEY_TYPE_DIRSTRARRAY:
+ for (ida = data->attriddata + id; *ida; ida += 2)
+ {
+ data_addideof(xd, ida[0], ida[2] ? 0 : 1);
+ data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
+ }
+ break;
default:
fprintf(stderr, "don't know how to handle type %d\n", key->type);
exit(1);
}
dp = ndp;
}
+ if (data->attrs[entry])
+ sat_free(data->attrs[entry]);
}
+ sat_free(schema);
+ sat_free(seen);
+
+ sat_free(data->incoredata);
data->incoredata = newincore.buf;
data->incoredatalen = newincore.len;
data->incoredatafree = 0;
+ sat_free(data->vincore);
data->vincore = newvincore.buf;
data->vincorelen = newvincore.len;
data->attrs = sat_free(data->attrs);
data->attrdata = sat_free(data->attrdata);
+ data->attriddata = sat_free(data->attriddata);
data->attrdatalen = 0;
+ data->attriddatalen = 0;
}
Id
parent = 0;
while (*dir == '/' && dir[1] == '/')
dir++;
+ if (*dir == '/' && !dir[1])
+ return 1;
while (*dir)
{
dire = strchrnul(dir, '/');
return parent;
}
+const char *
+repodata_dir2str(Repodata *data, Id did, const char *suf)
+{
+ Pool *pool = data->repo->pool;
+ int l = 0;
+ Id parent, comp;
+ const char *comps;
+ char *p;
+
+ if (!did)
+ return suf ? suf : "";
+ parent = did;
+ while (parent)
+ {
+ comp = dirpool_compid(&data->dirpool, parent);
+ comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
+ l += strlen(comps);
+ parent = dirpool_parent(&data->dirpool, parent);
+ if (parent)
+ l++;
+ }
+ if (suf)
+ l += strlen(suf) + 1;
+ p = pool_alloctmpspace(pool, l + 1) + l;
+ *p = 0;
+ if (suf)
+ {
+ p -= strlen(suf);
+ strcpy(p, suf);
+ *--p = '/';
+ }
+ parent = did;
+ while (parent)
+ {
+ comp = dirpool_compid(&data->dirpool, parent);
+ comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
+ l = strlen(comps);
+ p -= l;
+ strncpy(p, comps, l);
+ parent = dirpool_parent(&data->dirpool, parent);
+ if (parent)
+ *--p = '/';
+ }
+ return p;
+}
+
unsigned int
repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
{
return x;
}
+#define SOLV_ERROR_EOF 3
+#define SOLV_ERROR_CORRUPT 6
+
/* Try to either setup on-demand paging (using FP as backing
file), or in case that doesn't work (FP not seekable) slurps in
all pages and deactivates paging. */
-
void
repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
{
unsigned int can_seek;
long cur_file_ofs;
unsigned char buf[BLOB_PAGESIZE];
+
if (pagesz != BLOB_PAGESIZE)
{
/* We could handle this by slurping in everything. */
- fprintf (stderr, "non matching page size\n");
- exit (1);
+ data->error = SOLV_ERROR_CORRUPT;
+ return;
}
can_seek = 1;
if ((cur_file_ofs = ftell(fp)) < 0)
can_seek = 0;
- clearerr (fp);
+ clearerr(fp);
+ if (can_seek)
+ data->pagefd = dup(fileno(fp));
+ if (data->pagefd == -1)
+ can_seek = 0;
+
#ifdef DEBUG_PAGING
fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
#endif
fprintf (stderr, "can't seek after we thought we can\n");
/* We can't fall back to non-seeking behaviour as we already
read over some data pages without storing them away. */
- exit (1);
+ data->error = SOLV_ERROR_EOF;
+ close(data->pagefd);
+ data->pagefd = -1;
+ return;
}
cur_file_ofs += in_len;
}
/* We can't seek, so suck everything in. */
if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
{
- perror ("fread");
- exit (1);
+ perror("fread");
+ data->error = SOLV_ERROR_EOF;
+ return;
}
if (compressed)
{
out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
- if (out_len != BLOB_PAGESIZE
- && i < npages - 1)
+ if (out_len != BLOB_PAGESIZE && i < npages - 1)
{
- fprintf (stderr, "can't decompress\n");
- exit (1);
+ data->error = SOLV_ERROR_CORRUPT;
+ return;
}
}
}
}
+}
- if (can_seek)
- {
- /* If we are here we were able to seek to all page
- positions, so activate paging by copying FP into our structure.
- We dup() the file, so that our callers can fclose() it and we
- still have it open. But this means that we share file positions
- with the input filedesc. So in case our caller reads it after us,
- and calls back into us we might change the file position unexpectedly
- to him. */
- int fd = dup (fileno (fp));
- if (fd < 0)
- {
- /* Jeez! What a bloody system, we can't dup() anymore. */
- perror ("dup");
- exit (1);
- }
- /* XXX we don't close this yet anywhere. */
- data->fp = fdopen (fd, "r");
- if (!data->fp)
- {
- /* My God! What happened now? */
- perror ("fdopen");
- exit (1);
- }
- }
+void
+repodata_disable_paging(Repodata *data)
+{
+ if (maybe_load_repodata(data, 0)
+ && data->num_pages)
+ load_page_range (data, 0, data->num_pages - 1);
}
+/*
+vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
+*/