X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Frepodata.c;h=456b0551fbda7026ea74f5547f103ae67b977181;hb=eb7916da1418f09af7504f34dc1e379eb8e6b2ee;hp=5bf576ca0af7235de9bffc0ce3891b42e0d05a8a;hpb=30d99ea461ff631b7a7f6231d1ee8c66a1ab0474;p=platform%2Fupstream%2Flibsolv.git diff --git a/src/repodata.c b/src/repodata.c index 5bf576c..456b055 100644 --- a/src/repodata.c +++ b/src/repodata.c @@ -14,6 +14,7 @@ #define _GNU_SOURCE #include +#include #include #include @@ -25,156 +26,87 @@ #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) @@ -205,6 +137,9 @@ load_page_range(Repodata *data, unsigned int pstart, unsigned int pend) 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) { @@ -314,27 +249,20 @@ load_page_range(Repodata *data, unsigned int pstart, unsigned int pend) #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); @@ -354,7 +282,7 @@ static unsigned char * 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) { @@ -363,12 +291,11 @@ make_vertical_available(Repodata *data, Repokey *key, Id off, Id len) 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; @@ -399,6 +326,42 @@ get_data(Repodata *data, Repokey *key, unsigned char **dpp) 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) @@ -408,6 +371,9 @@ repodata_lookup_str(Repodata *data, Id entry, Id keyid) Id 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); /* make sure the schema of this solvable contains the key */ @@ -419,17 +385,71 @@ repodata_lookup_str(Repodata *data, Id entry, Id 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) { @@ -441,6 +461,9 @@ repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbda int stop; KeyValue kv; + 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]; @@ -476,6 +499,336 @@ repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbda } } +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 @@ -489,10 +842,10 @@ repodata_extend(Repodata *data, Id p) 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; } @@ -502,39 +855,70 @@ repodata_extend(Repodata *data, Id p) 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]) { for (pp = data->attrs[entry]; *pp; pp += 2) - if (*pp == keyid) + /* 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[1] = val; + { + pp[0] = keyid; + pp[1] = val; + } return; } 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; @@ -550,7 +934,7 @@ repodata_set(Repodata *data, Id entry, Repokey *key, Id 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; } @@ -573,7 +957,7 @@ repodata_set_id(Repodata *data, Id entry, Id keyname, Id id) { 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); @@ -584,7 +968,7 @@ repodata_set_num(Repodata *data, Id entry, Id keyname, Id num) { 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); @@ -600,7 +984,7 @@ repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str) 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); @@ -611,18 +995,29 @@ repodata_set_constant(Repodata *data, Id entry, Id keyname, Id constant) { 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); @@ -636,61 +1031,156 @@ repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str) 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 + 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; @@ -698,10 +1188,56 @@ fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, nu } 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 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; - 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); } @@ -838,6 +1374,7 @@ repodata_internalize(Repodata *data) 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)); @@ -906,8 +1443,8 @@ fprintf(stderr, "schemadata %p\n", data->schemadata); /* 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); @@ -938,18 +1475,29 @@ fprintf(stderr, "schemadata %p\n", data->schemadata); 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: + 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]); @@ -957,6 +1505,13 @@ fprintf(stderr, "schemadata %p\n", data->schemadata); 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); @@ -971,17 +1526,26 @@ fprintf(stderr, "schemadata %p\n", data->schemadata); } 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 @@ -993,6 +1557,8 @@ repodata_str2dir(Repodata *data, const char *dir, int create) parent = 0; while (*dir == '/' && dir[1] == '/') dir++; + if (*dir == '/' && !dir[1]) + return 1; while (*dir) { dire = strchrnul(dir, '/'); @@ -1014,6 +1580,52 @@ repodata_str2dir(Repodata *data, const char *dir, int create) 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) { @@ -1038,10 +1650,12 @@ read_u32(FILE *fp) 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) { @@ -1051,16 +1665,22 @@ repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int b 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 @@ -1094,7 +1714,10 @@ repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int b 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; } @@ -1108,45 +1731,30 @@ repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int b /* 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: +*/