#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);
+ sat_free(data->addedfileprovides);
+
+ 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)
+ if (pread(data->pagefd, compressed ? buf : dest, in_len, p->file_offset) != in_len)
{
- perror ("mapping fseek");
- exit (1);
- }
- if (fread(compressed ? buf : dest, in_len, 1, data->fp) != 1)
- {
- 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;
return 0;
}
+static inline int
+maybe_load_repodata(Repodata *data, Id *keyid)
+{
+ if (data->state == REPODATA_STUB)
+ {
+ if (data->loadcallback)
+ {
+ 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;
+ }
+ if (data->state == REPODATA_AVAILABLE)
+ return 1;
+ data->state = REPODATA_ERROR;
+ return 0;
+}
const char *
repodata_lookup_str(Repodata *data, Id entry, Id keyid)
Id id, *keyp;
unsigned char *dp;
- if (data->entryschemau8)
- schema = data->entryschemau8[entry];
- else
- schema = data->entryschema[entry];
+ if (!maybe_load_repodata(data, &keyid))
+ return 0;
+
+ dp = data->incoredata + data->incoreoffset[entry];
+ dp = data_read_id(dp, &schema);
/* make sure the schema of this solvable contains the key */
for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
if (!*keyp)
return 0;
- dp = forward_to_key(data, keyid, schema, data->incoredata + data->incoreoffset[entry]);
+ dp = forward_to_key(data, keyid, schema, dp);
key = data->keys + keyid;
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 strore*/
- 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 int *value)
+{
+ Id schema;
+ Repokey *key;
+ Id *keyp;
+ KeyValue kv;
+ unsigned char *dp;
+
+ *value = 0;
+
+ if (!maybe_load_repodata(data, &keyid))
+ return 0;
+
+ dp = data->incoredata + data->incoreoffset[entry];
+ dp = data_read_id(dp, &schema);
+ /* make sure the schema of this solvable contains the key */
+ for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
+ if (!*keyp)
+ return 0;
+ dp = forward_to_key(data, keyid, schema, dp);
+ key = data->keys + keyid;
+ dp = get_data(data, key, &dp);
+ if (!dp)
+ return 0;
+ 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 1;
+ }
+ 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 (data->entryschemau8)
- schema = data->entryschemau8[entry];
- else
- schema = data->entryschema[entry];
- keyp = data->schemadata + data->schemata[schema];
+ if (!maybe_load_repodata(data, 0))
+ return;
+
dp = data->incoredata + data->incoreoffset[entry];
+ dp = data_read_id(dp, &schema);
+ keyp = data->schemadata + data->schemata[schema];
if (keyname)
{
/* search in a specific key */
}
}
+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 old = data->end - data->start;
int new = p - data->end + 1;
- if (data->entryschemau8)
- {
- data->entryschemau8 = sat_realloc(data->entryschemau8, old + new);
- memset(data->entryschemau8 + old, 0, new);
- }
- if (data->entryschema)
- {
- data->entryschema = sat_realloc2(data->entryschema, old + new, sizeof(Id));
- memset(data->entryschema + old, 0, new * sizeof(Id));
- }
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 old = data->end - data->start;
int new = data->start - p;
- if (data->entryschemau8)
- {
- data->entryschemau8 = sat_realloc(data->entryschemau8, old + new);
- memmove(data->entryschemau8 + new, data->entryschemau8, old);
- memset(data->entryschemau8, 0, new);
- }
- if (data->entryschema)
- {
- data->entryschema = sat_realloc2(data->entryschema, old + new, sizeof(Id));
- memmove(data->entryschema + new, data->entryschema, old * sizeof(Id));
- memset(data->entryschema, 0, new * sizeof(Id));
- }
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_set(Repodata *data, Id entry, Repokey *key, Id val)
+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 keyid, *pp;
+ Id *pp;
int i;
+ if (!data->attrs)
+ {
+ data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *),
+ REPODATA_BLOCK);
+ }
+ i = 0;
+ if (data->attrs[entry])
+ {
+ for (pp = data->attrs[entry]; *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)
+ {
+ pp[0] = keyid;
+ pp[1] = val;
+ }
+ return;
+ }
+ i = pp - data->attrs[entry];
+ }
+ data->attrs[entry] = sat_extend(data->attrs[entry], i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
+ pp = data->attrs[entry] + i;
+ *pp++ = keyid;
+ *pp++ = val;
+ *pp = 0;
+}
+
+void
+repodata_set(Repodata *data, Id entry, Repokey *key, Id val)
+{
+ Id keyid;
/* find key in keys */
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;
}
data->verticaloffset[data->nkeys - 1] = 0;
}
}
- key = data->keys + keyid;
- if (!data->attrs)
- data->attrs = sat_calloc(data->end - data->start + 1, sizeof(Id *));
- i = 0;
- if (data->attrs[entry])
- {
- for (pp = data->attrs[entry]; *pp; pp += 2)
- if (*pp == keyid)
- break;
- if (*pp)
- {
- pp[1] = val;
- return;
- }
- i = pp - data->attrs[entry];
- }
- data->attrs[entry] = sat_realloc2(data->attrs[entry], i + 3, sizeof(Id));
- pp = data->attrs[entry] + i;
- *pp++ = keyid;
- *pp++ = val;
- *pp = 0;
+ repodata_insert_keyid(data, entry, keyid, val, 1);
}
void
{
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;
}
-void
-repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
+static void
+repoadata_add_array(Repodata *data, Id entry, Id keyname, Id keytype, int entrysize)
{
+ int oldsize;
Id *ida, *pp;
- Repokey key;
-#if 0
-fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
-#endif
- if (data->attrs[entry])
+ pp = 0;
+ if (data->attrs && data->attrs[entry])
+ for (pp = data->attrs[entry]; *pp; pp += 2)
+ if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
+ break;
+ if (!pp || !*pp)
{
- for (pp = data->attrs[entry]; *pp; pp += 2)
- if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRNUMNUMARRAY)
- break;
- if (*pp)
- {
- int oldsize = 0;
- for (ida = data->attriddata + pp[1]; *ida; ida += 3)
- oldsize += 3;
- 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->attriddatalen--; /* overwrite terminating 0 */
- }
- else
- {
- /* too bad. move to back. */
- data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 4, sizeof(Id));
- 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++] = num;
- data->attriddata[data->attriddatalen++] = num2;
- data->attriddata[data->attriddatalen++] = 0;
- return;
- }
+ /* not found. allocate new key */
+ Repokey key;
+ 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, entry, &key, data->attriddatalen);
+ return;
+ }
+ oldsize = 0;
+ for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
+ oldsize += entrysize;
+ if (ida + 1 == data->attriddata + data->attriddatalen)
+ {
+ /* this was the last entry, just append it */
+ data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, 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 + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+ memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
+ pp[1] = data->attriddatalen;
+ data->attriddatalen += oldsize;
+ }
+}
+
+void
+repodata_set_bin_checksum(Repodata *data, Id entry, Id keyname, Id type,
+ const unsigned char *str)
+{
+ Repokey key;
+ int l;
+ switch (type)
+ {
+ case REPOKEY_TYPE_MD5: l = SIZEOF_MD5; break;
+ case REPOKEY_TYPE_SHA1: l = SIZEOF_SHA1; break;
+ default: return;
}
key.name = keyname;
- key.type = TYPE_DIRNUMNUMARRAY;
+ key.type = type;
key.size = 0;
key.storage = KEY_STORAGE_INCORE;
- data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 4, sizeof(Id));
- repodata_set(data, entry, &key, data->attriddatalen);
+ 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;
+}
+
+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 entry, Id keyname, Id type,
+ const char *str)
+{
+ int l;
+ switch (type)
+ {
+ case REPOKEY_TYPE_MD5: l = SIZEOF_MD5; break;
+ case REPOKEY_TYPE_SHA1: l = SIZEOF_SHA1; break;
+ default: return;
+ }
+ unsigned char buf[l];
+ if (hexstr2bytes(buf, str, l) != l)
+ {
+ fprintf(stderr, "Invalid hex character in %s\n", str);
+ return;
+ }
+ repodata_set_bin_checksum(data, entry, keyname, type, buf);
+}
+
+const char *
+repodata_chk2str(Repodata *data, Id type, const char *buf)
+{
+ int i, l;
+ char *str, *s;
+ switch (type)
+ {
+ case REPOKEY_TYPE_MD5: l = SIZEOF_MD5; break;
+ case REPOKEY_TYPE_SHA1: l = SIZEOF_SHA1; break;
+ default: return id2str(data->repo->pool, ID_EMPTY);
+ }
+ s = str = pool_alloctmpspace(data->repo->pool, 2*l + 1);
+ for (i = 0; i < l; i++, s+=2)
+ {
+ unsigned char v = buf[i];
+ unsigned char w = v >> 4;
+ s[0] = w >= 10 ? (w-10)+'a' : w + '0';
+ w = v & 15;
+ s[1] = w >= 10 ? (w-10)+'a' : w + '0';
+ }
+ *s = 0;
+ return str;
+}
+
+void
+repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
+{
+
+#if 0
+fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
+#endif
+ repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
data->attriddata[data->attriddatalen++] = dir;
data->attriddata[data->attriddatalen++] = num;
data->attriddata[data->attriddatalen++] = num2;
data->attriddata[data->attriddatalen++] = 0;
}
+void
+repodata_add_dirstr(Repodata *data, Id entry, Id keyname, Id dir, const char *str)
+{
+ Id stroff;
+ 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
+ repoadata_add_array(data, entry, 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 entry, Id keyname, Id id)
+{
+#if 0
+fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", entry, id, data->attriddatalen);
+#endif
+ repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_IDARRAY, 1);
+ data->attriddata[data->attriddatalen++] = id;
+ data->attriddata[data->attriddatalen++] = 0;
+}
+
+void
+repodata_add_poolstr_array(Repodata *data, Id entry, 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, entry, keyname, id);
+}
+
+void
+repodata_merge_attrs(Repodata *data, Id dest, Id src)
+{
+ Id *keyp;
+ if (dest == src || !(keyp = data->attrs[src]))
+ return;
+ for (; *keyp; keyp += 2)
+ repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
+}
+
/*********************************/
/* unify with repo_write! */
void
repodata_internalize(Repodata *data)
{
- int i;
Repokey *key;
Id id, entry, nentry, *ida;
Id schematacache[256];
schema = sat_malloc2(data->nkeys, sizeof(Id));
seen = sat_malloc2(data->nkeys, sizeof(Id));
+ /* Merge the data already existing (in data->schemata, ->incoredata and
+ friends) with the new attributes in data->attrs[]. */
nentry = data->end - data->start;
addschema_prepare(data, schematacache);
memset(&newincore, 0, sizeof(newincore));
+ data_addid(&newincore, 0);
for (entry = 0; entry < nentry; entry++)
{
memset(seen, 0, data->nkeys * sizeof(Id));
sp = schema;
- if (data->entryschemau8)
- oldschema = data->entryschemau8[entry];
+ dp = data->incoredata + data->incoreoffset[entry];
+ if (data->incoredata)
+ dp = data_read_id(dp, &oldschema);
else
- oldschema = data->entryschema[entry];
+ oldschema = 0;
#if 0
fprintf(stderr, "oldschema %d\n", oldschema);
fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
{
if (seen[*keyp])
{
- newschema = 1;
- continue;
+ fprintf(stderr, "Inconsistent old data (key occured twice).\n");
+ exit(1);
}
seen[*keyp] = -1;
*sp++ = *keyp;
oldcount++;
}
- for (keyp = data->attrs[entry]; *keyp; keyp += 2)
- {
- if (!seen[*keyp])
- {
- newschema = 1;
- *sp++ = *keyp;
- }
- seen[*keyp] = keyp[1] + 1;
- }
+ if (data->attrs[entry])
+ for (keyp = data->attrs[entry]; *keyp; keyp += 2)
+ {
+ if (!seen[*keyp])
+ {
+ newschema = 1;
+ *sp++ = *keyp;
+ }
+ seen[*keyp] = keyp[1] + 1;
+ }
*sp++ = 0;
if (newschema)
- {
- schemaid = addschema(data, schema, schematacache);
- if (schemaid > 255 && data->entryschemau8)
- {
- data->entryschema = sat_malloc2(nentry, sizeof(Id));
- for (i = 0; i < nentry; i++)
- data->entryschema[i] = data->entryschemau8[i];
- data->entryschemau8 = sat_free(data->entryschemau8);
- }
- if (data->entryschemau8)
- data->entryschemau8[entry] = schemaid;
- else
- data->entryschema[entry] = schemaid;
- }
+ /* Ideally we'd like to sort the new schema here, to ensure
+ schema equality independend of the ordering. We can't do that
+ yet. For once see below (old ids need to come before new ids).
+ An additional difficulty is that we also need to move
+ the values with the keys. */
+ schemaid = addschema(data, schema, schematacache);
else
schemaid = oldschema;
- /* now create data blob */
- dp = data->incoredata + data->incoreoffset[entry];
+ /* Now create data blob. We walk through the (possibly new) schema
+ and either copy over old data, or insert the new. */
+ /* XXX Here we rely on the fact that the (new) schema has the form
+ o1 o2 o3 o4 ... | n1 n2 n3 ...
+ (oX being the old keyids (possibly overwritten), and nX being
+ the new keyids). This rules out sorting the keyids in order
+ to ensure a small schema count. */
data->incoreoffset[entry] = newincore.len;
+ data_addid(&newincore, schemaid);
for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
{
key = data->keys + *keyp;
ndp = dp;
if (oldcount)
{
+ /* Skip the data associated with this old key. */
if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
{
- ndp = data_skip(dp, TYPE_ID);
- ndp = data_skip(dp, 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);
}
if (seen[*keyp] == -1)
{
+ /* If this key was an old one _and_ was not overwritten with
+ a different value copy over the old value (we skipped it
+ above). */
if (dp != ndp)
data_addblob(&newincore, dp, ndp - dp);
seen[*keyp] = 0;
}
else if (seen[*keyp])
{
+ /* Otherwise we have a new value. Parse it into the internal
+ form. */
struct extdata *xd;
unsigned int oldvincorelen = 0;
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_MD5:
+ data_addblob(xd, data->attrdata + id, SIZEOF_MD5);
+ break;
+ case REPOKEY_TYPE_SHA1:
+ data_addblob(xd, data->attrdata + id, SIZEOF_SHA1);
+ break;
+ case REPOKEY_TYPE_ID:
+ case REPOKEY_TYPE_NUM:
+ case REPOKEY_TYPE_DIR:
data_addid(xd, id);
break;
- case TYPE_DIRNUMNUMARRAY:
- ida = data->attriddata + id;
+ case REPOKEY_TYPE_IDARRAY:
+ for (ida = data->attriddata + id; *ida; ida++)
+ data_addideof(xd, ida[0], ida[1] ? 0 : 1);
+ break;
+ 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 compress_buf(page, len, cpage, max);
}
-/* 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. */
-
#define SOLV_ERROR_EOF 3
static inline unsigned int
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:
+*/