diff options
author | Kristian Høgsberg <krh@redhat.com> | 2008-06-20 15:10:34 -0400 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2008-06-20 15:10:34 -0400 |
commit | e557f97da15b1682b2e9854672b019485bc48362 (patch) | |
tree | 65abdad4fc67068862eedb5af4e17a94c6be1bf4 /librazor | |
parent | 17138ad12dda6da15358726f19ba8f94993ddfc1 (diff) |
Break up the monolithic razor.c.
Diffstat (limited to 'librazor')
-rw-r--r-- | librazor/Makefile.am | 9 | ||||
-rw-r--r-- | librazor/importer.c | 488 | ||||
-rw-r--r-- | librazor/iterator.c | 265 | ||||
-rw-r--r-- | librazor/merger.c | 525 | ||||
-rw-r--r-- | librazor/razor-internal.h | 158 | ||||
-rw-r--r-- | librazor/razor.c | 2201 | ||||
-rw-r--r-- | librazor/razor.h | 1 | ||||
-rw-r--r-- | librazor/root.c (renamed from librazor/razor-root.c) | 0 | ||||
-rw-r--r-- | librazor/transaction.c | 912 | ||||
-rw-r--r-- | librazor/types.c | 2 | ||||
-rw-r--r-- | librazor/types.h | 59 |
11 files changed, 2367 insertions, 2253 deletions
diff --git a/librazor/Makefile.am b/librazor/Makefile.am index 0231424..a858968 100644 --- a/librazor/Makefile.am +++ b/librazor/Makefile.am @@ -21,11 +21,14 @@ librazor_la_SOURCES = \ razor-internal.h \ razor.h \ razor.c \ - razor-root.c \ - types.h \ + root.c \ types.c \ util.c \ - rpm.c + rpm.c \ + iterator.c \ + importer.c \ + merger.c \ + transaction.c librazor_la_LIBADD = $(ZLIB_LIBS) diff --git a/librazor/importer.c b/librazor/importer.c new file mode 100644 index 0000000..10d87c2 --- /dev/null +++ b/librazor/importer.c @@ -0,0 +1,488 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com> + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE + +#include <string.h> +#include "razor-internal.h" +#include "razor.h" + +void +razor_importer_begin_package(struct razor_importer *importer, + const char *name, + const char *version, + const char *arch) +{ + struct razor_package *p; + + p = array_add(&importer->set->packages, sizeof *p); + p->name = hashtable_tokenize(&importer->table, name); + p->flags = 0; + p->version = hashtable_tokenize(&importer->table, version); + p->arch = hashtable_tokenize(&importer->table, arch); + + importer->package = p; + array_init(&importer->properties); +} + + +void +razor_importer_finish_package(struct razor_importer *importer) +{ + list_set_array(&importer->package->properties, + &importer->set->property_pool, + &importer->properties, + 1); + + array_release(&importer->properties); +} + +void +razor_importer_add_property(struct razor_importer *importer, + const char *name, + uint32_t flags, + const char *version) +{ + struct razor_property *p; + uint32_t *r; + + p = array_add(&importer->set->properties, sizeof *p); + p->name = hashtable_tokenize(&importer->table, name); + p->flags = flags; + p->version = hashtable_tokenize(&importer->table, version); + list_set_ptr(&p->packages, importer->package - + (struct razor_package *) importer->set->packages.data); + + r = array_add(&importer->properties, sizeof *r); + *r = p - (struct razor_property *) importer->set->properties.data; + + if (((flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES) && + *name == '/') { + r = array_add(&importer->file_requires, sizeof *r); + *r = p->name; + } +} + +void +razor_importer_add_file(struct razor_importer *importer, const char *name) +{ + struct import_entry *e; + + e = array_add(&importer->files, sizeof *e); + + e->package = importer->package - + (struct razor_package *) importer->set->packages.data; + e->name = strdup(name); +} + +struct razor_importer * +razor_importer_new(void) +{ + struct razor_importer *importer; + + importer = zalloc(sizeof *importer); + importer->set = razor_set_create(); + hashtable_init(&importer->table, &importer->set->string_pool); + + return importer; +} + +/* Destroy an importer without creating the set. */ +void +razor_importer_destroy(struct razor_importer *importer) +{ + /* FIXME: write this */ +} + +static int +compare_packages(const void *p1, const void *p2, void *data) +{ + const struct razor_package *pkg1 = p1, *pkg2 = p2; + struct razor_set *set = data; + char *pool = set->string_pool.data; + + /* FIXME: what if the flags are different? */ + if (pkg1->name == pkg2->name) + return razor_versioncmp(&pool[pkg1->version], &pool[pkg2->version]); + else + return strcmp(&pool[pkg1->name], &pool[pkg2->name]); +} + +static int +compare_properties(const void *p1, const void *p2, void *data) +{ + const struct razor_property *prop1 = p1, *prop2 = p2; + struct razor_set *set = data; + char *pool = set->string_pool.data; + + if (prop1->name != prop2->name) + return strcmp(&pool[prop1->name], &pool[prop2->name]); + else if (prop1->flags != prop2->flags) + return prop1->flags - prop2->flags; + else + return razor_versioncmp(&pool[prop1->version], &pool[prop2->version]); +} + +static uint32_t * +uniqueify_properties(struct razor_set *set) +{ + struct razor_property *rp, *up, *rp_end; + struct array *pkgs, *p; + struct list_head *r; + uint32_t *map, *rmap; + int i, count, unique; + + count = set->properties.size / sizeof(struct razor_property); + map = razor_qsort_with_data(set->properties.data, + count, + sizeof(struct razor_property), + compare_properties, + set); + + rp_end = set->properties.data + set->properties.size; + rmap = malloc(count * sizeof *map); + pkgs = zalloc(count * sizeof *pkgs); + for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) { + if (rp->name != up->name || + rp->flags != up->flags || + rp->version != up->version) { + up++; + up->name = rp->name; + up->flags = rp->flags; + up->version = rp->version; + } + + unique = up - (struct razor_property *) set->properties.data; + rmap[map[i]] = unique; + r = array_add(&pkgs[unique], sizeof *r); + *r = rp->packages; + } + free(map); + + if (up != rp) + up++; + set->properties.size = (void *) up - set->properties.data; + rp_end = up; + for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) { + list_set_array(&rp->packages, &set->package_pool, p, 0); + array_release(p); + } + + free(pkgs); + + return rmap; +} + +static int +compare_filenames(const void *p1, const void *p2, void *data) +{ + const struct import_entry *e1 = p1; + const struct import_entry *e2 = p2; + const char *n1 = e1->name; + const char *n2 = e2->name; + + /* Need to make sure that the contents of a directory + * are sorted immediately after it. So "foo/bar" has to + * sort before "foo.conf" + * + * FIXME: this is about 60% slower than strcmp + */ + while (*n1 && *n2) { + if (*n1 < *n2) + return *n2 == '/' ? 1 : -1; + else if (*n1 > *n2) + return *n1 == '/' ? -1 : 1; + n1++; + n2++; + } + if (*n1) + return 1; + else if (*n2) + return -1; + else + return 0; +} + +static void +count_entries(struct import_directory *d) +{ + struct import_directory *p, *end; + + p = d->files.data; + end = d->files.data + d->files.size; + d->count = 0; + while (p < end) { + count_entries(p); + d->count += p->count + 1; + p++; + } +} + +static void +serialize_files(struct razor_set *set, + struct import_directory *d, struct array *array) +{ + struct import_directory *p, *end; + struct razor_entry *e = NULL; + uint32_t s; + + p = d->files.data; + end = d->files.data + d->files.size; + s = array->size / sizeof *e + d->files.size / sizeof *p; + while (p < end) { + e = array_add(array, sizeof *e); + e->name = p->name; + e->flags = 0; + e->start = p->count > 0 ? s : 0; + s += p->count; + + list_set_array(&e->packages, &set->package_pool, &p->packages, 0); + array_release(&p->packages); + p++; + } + if (e != NULL) + e->flags |= RAZOR_ENTRY_LAST; + + p = d->files.data; + end = d->files.data + d->files.size; + while (p < end) { + serialize_files(set, p, array); + p++; + } +} + +static void +remap_property_package_links(struct array *properties, uint32_t *rmap) +{ + struct razor_property *p, *end; + + end = properties->data + properties->size; + for (p = properties->data; p < end; p++) + list_remap_head(&p->packages, rmap); +} + +static void +build_file_tree(struct razor_importer *importer) +{ + int count, i, length; + struct import_entry *filenames; + char *f, *end; + uint32_t name, *r; + char dirname[256]; + struct import_directory *d, root; + struct razor_entry *e; + + count = importer->files.size / sizeof (struct import_entry); + razor_qsort_with_data(importer->files.data, + count, + sizeof (struct import_entry), + compare_filenames, + NULL); + + root.name = hashtable_tokenize(&importer->table, ""); + array_init(&root.files); + array_init(&root.packages); + root.last = NULL; + + filenames = importer->files.data; + for (i = 0; i < count; i++) { + f = filenames[i].name; + if (*f != '/') + continue; + f++; + + d = &root; + while (*f) { + end = strchr(f, '/'); + if (end == NULL) + end = f + strlen(f); + length = end - f; + memcpy(dirname, f, length); + dirname[length] ='\0'; + name = hashtable_tokenize(&importer->table, dirname); + if (d->last == NULL || d->last->name != name) { + d->last = array_add(&d->files, sizeof *d); + d->last->name = name; + d->last->last = NULL; + array_init(&d->last->files); + array_init(&d->last->packages); + } + d = d->last; + f = end + 1; + if (*end == '\0') + break; + } + + r = array_add(&d->packages, sizeof *r); + *r = filenames[i].package; + free(filenames[i].name); + } + + count_entries(&root); + e = importer->set->files.data; + e->name = root.name; + e->flags = RAZOR_ENTRY_LAST; + e->start = importer->files.size ? 1 : 0; + list_set_empty(&e->packages); + + serialize_files(importer->set, &root, &importer->set->files); + + array_release(&importer->files); +} + +static void +list_to_array(struct list *list, struct array *array) +{ + uint32_t *item; + + while (list) { + item = array_add(array, sizeof *item); + *item = list->data; + list = list_next(list); + } +} + +static int +compare_file_requires(const void *p1, const void *p2, void *data) +{ + uint32_t *f1 = (void *)p1, *f2 = (void *)p2; + const char *pool = data; + + return strcmp(&pool[*f1], &pool[*f2]); +} + +static void +find_file_provides(struct razor_importer *importer) +{ + struct razor_property *prop; + struct razor_entry *top, *entry; + struct razor_package *packages; + struct array pkgprops; + struct list *pkg; + uint32_t *req, *req_start, *req_end; + uint32_t *map, *newprop; + char *pool; + + pool = importer->set->string_pool.data; + packages = importer->set->packages.data; + top = importer->set->files.data; + + req = req_start = importer->file_requires.data; + req_end = importer->file_requires.data + importer->file_requires.size; + map = razor_qsort_with_data(req, req_end - req, sizeof *req, + compare_file_requires, pool); + free(map); + + for (req = req_start; req < req_end; req++) { + if (req > req_start && req[0] == req[-1]) + continue; + entry = razor_set_find_entry(importer->set, top, &pool[*req]); + if (!entry) + continue; + + for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) { + prop = array_add(&importer->set->properties, sizeof *prop); + prop->name = *req; + prop->flags = + RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL; + prop->version = hashtable_tokenize(&importer->table, ""); + list_set_ptr(&prop->packages, pkg->data); + + /* Update property list of pkg */ + array_init(&pkgprops); + list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops); + newprop = array_add(&pkgprops, sizeof *newprop); + *newprop = prop - (struct razor_property *)importer->set->properties.data; + list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1); + array_release(&pkgprops); + } + } + + array_release(&importer->file_requires); +} + +static void +build_package_file_lists(struct razor_set *set, uint32_t *rmap) +{ + struct razor_package *p, *packages; + struct array *pkgs; + struct razor_entry *e, *end; + struct list *r; + uint32_t *q; + int i, count; + + count = set->packages.size / sizeof *p; + pkgs = zalloc(count * sizeof *pkgs); + + end = set->files.data + set->files.size; + for (e = set->files.data; e < end; e++) { + list_remap_head(&e->packages, rmap); + r = list_first(&e->packages, &set->package_pool); + while (r) { + q = array_add(&pkgs[r->data], sizeof *q); + *q = e - (struct razor_entry *) set->files.data; + r = list_next(r); + } + } + + packages = set->packages.data; + for (i = 0; i < count; i++) { + list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0); + array_release(&pkgs[i]); + } + free(pkgs); +} + +struct razor_set * +razor_importer_finish(struct razor_importer *importer) +{ + struct razor_set *set; + uint32_t *map, *rmap; + int i, count; + + build_file_tree(importer); + find_file_provides(importer); + + map = uniqueify_properties(importer->set); + list_remap_pool(&importer->set->property_pool, map); + free(map); + + count = importer->set->packages.size / sizeof(struct razor_package); + map = razor_qsort_with_data(importer->set->packages.data, + count, + sizeof(struct razor_package), + compare_packages, + importer->set); + + rmap = malloc(count * sizeof *rmap); + for (i = 0; i < count; i++) + rmap[map[i]] = i; + free(map); + + list_remap_pool(&importer->set->package_pool, rmap); + build_package_file_lists(importer->set, rmap); + remap_property_package_links(&importer->set->properties, rmap); + free(rmap); + + set = importer->set; + hashtable_release(&importer->table); + free(importer); + + return set; +} diff --git a/librazor/iterator.c b/librazor/iterator.c new file mode 100644 index 0000000..909b954 --- /dev/null +++ b/librazor/iterator.c @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com> + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE + +#include <string.h> +#include "razor-internal.h" +#include "razor.h" + +static struct razor_package_iterator * +razor_package_iterator_create_with_index(struct razor_set *set, + struct list *index) +{ + struct razor_package_iterator *pi; + + pi = zalloc(sizeof *pi); + pi->set = set; + pi->index = index; + + return pi; +} + +struct razor_package_iterator * +razor_package_iterator_create(struct razor_set *set) +{ + struct razor_package_iterator *pi; + + pi = zalloc(sizeof *pi); + pi->set = set; + pi->end = set->packages.data + set->packages.size; + pi->package = set->packages.data; + + return pi; +} + +void +razor_package_iterator_init_for_property(struct razor_package_iterator *pi, + struct razor_set *set, + struct razor_property *property) +{ + memset(pi, 0, sizeof *pi); + pi->set = set; + pi->index = list_first(&property->packages, &set->package_pool); +} + +struct razor_package_iterator * +razor_package_iterator_create_for_property(struct razor_set *set, + struct razor_property *property) +{ + struct list *index; + + index = list_first(&property->packages, &set->package_pool); + return razor_package_iterator_create_with_index(set, index); +} + +struct razor_package_iterator * +razor_package_iterator_create_for_file(struct razor_set *set, + const char *filename) +{ + struct razor_entry *entry; + struct list *index; + + entry = razor_set_find_entry(set, set->files.data, filename); + if (entry == NULL) + return NULL; + + index = list_first(&entry->packages, &set->package_pool); + return razor_package_iterator_create_with_index(set, index); +} + +int +razor_package_iterator_next(struct razor_package_iterator *pi, + struct razor_package **package, + const char **name, + const char **version, + const char **arch) +{ + char *pool; + int valid; + struct razor_package *p, *packages; + + if (pi->package) { + p = pi->package++; + valid = p < pi->end; + } else if (pi->index) { + packages = pi->set->packages.data; + p = &packages[pi->index->data]; + pi->index = list_next(pi->index); + valid = 1; + } else + valid = 0; + + if (valid) { + pool = pi->set->string_pool.data; + *package = p; + *name = &pool[p->name]; + *version = &pool[p->version]; + *arch = &pool[p->arch]; + } else { + *package = NULL; + } + + return valid; +} + +void +razor_package_iterator_destroy(struct razor_package_iterator *pi) +{ + if (pi->free_index) + free(pi->index); + + free(pi); +} + +struct razor_property_iterator * +razor_property_iterator_create(struct razor_set *set, + struct razor_package *package) +{ + struct razor_property_iterator *pi; + + pi = zalloc(sizeof *pi); + pi->set = set; + + if (package) { + pi->index = list_first(&package->properties, + &set->property_pool); + } else { + pi->property = set->properties.data; + pi->end = set->properties.data + set->properties.size; + } + + return pi; +} + +int +razor_property_iterator_next(struct razor_property_iterator *pi, + struct razor_property **property, + const char **name, + uint32_t *flags, + const char **version) +{ + char *pool; + int valid; + struct razor_property *p, *properties; + + if (pi->property) { + p = pi->property++; + valid = p < pi->end; + } else if (pi->index) { + properties = pi->set->properties.data; + p = &properties[pi->index->data]; + pi->index = list_next(pi->index); + valid = 1; + } else + valid = 0; + + if (valid) { + pool = pi->set->string_pool.data; + *property = p; + *name = &pool[p->name]; + *flags = p->flags; + *version = &pool[p->version]; + } else { + *property = NULL; + } + + return valid; +} + +void +razor_property_iterator_destroy(struct razor_property_iterator *pi) +{ + free(pi); +} + +struct razor_package_query { + struct razor_set *set; + char *vector; + int count; +}; + +struct razor_package_query * +razor_package_query_create(struct razor_set *set) +{ + struct razor_package_query *pq; + int count; + + pq = zalloc(sizeof *pq); + pq->set = set; + count = set->packages.size / sizeof(struct razor_package); + pq->vector = zalloc(count * sizeof(char)); + + return pq; +} + +void +razor_package_query_add_package(struct razor_package_query *pq, + struct razor_package *p) +{ + struct razor_package *packages; + + packages = pq->set->packages.data; + pq->count += pq->vector[p - packages] ^ 1; + pq->vector[p - packages] = 1; +} + +void +razor_package_query_add_iterator(struct razor_package_query *pq, + struct razor_package_iterator *pi) +{ + struct razor_package *packages, *p; + const char *name, *version, *arch; + + packages = pq->set->packages.data; + while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { + pq->count += pq->vector[p - packages] ^ 1; + pq->vector[p - packages] = 1; + } +} + +struct razor_package_iterator * +razor_package_query_finish(struct razor_package_query *pq) +{ + struct razor_package_iterator *pi; + struct razor_set *set; + struct list *index; + int i, j, count; + + set = pq->set; + count = set->packages.size / sizeof(struct razor_package); + index = zalloc(pq->count * sizeof *index); + + for (i = 0, j = 0; i < count; i++) { + if (!pq->vector[i]) + continue; + + index[j].data = i; + if (j == pq->count - 1) + index[j].flags = 0x80; + j++; + } + + free(pq); + + pi = razor_package_iterator_create_with_index(set, index); + pi->free_index = 1; + + return pi; +} diff --git a/librazor/merger.c b/librazor/merger.c new file mode 100644 index 0000000..636903a --- /dev/null +++ b/librazor/merger.c @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com> + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <string.h> +#include "razor-internal.h" +#include "razor.h" + +#define UPSTREAM_SOURCE 0x80 + +struct source { + struct razor_set *set; + uint32_t *property_map; + uint32_t *file_map; +}; + +struct razor_merger { + struct razor_set *set; + struct hashtable table; + struct source source1; + struct source source2; +}; + +struct razor_merger * +razor_merger_create(struct razor_set *set1, struct razor_set *set2) +{ + struct razor_merger *merger; + int count; + size_t size; + + merger = zalloc(sizeof *merger); + merger->set = razor_set_create(); + hashtable_init(&merger->table, &merger->set->string_pool); + + merger->source1.set = set1; + count = set1->properties.size / sizeof (struct razor_property); + size = count * sizeof merger->source1.property_map[0]; + merger->source1.property_map = zalloc(size); + count = set1->files.size / sizeof (struct razor_entry); + size = count * sizeof merger->source1.file_map[0]; + merger->source1.file_map = zalloc(size); + + merger->source2.set = set2; + count = set2->properties.size / sizeof (struct razor_property); + size = count * sizeof merger->source2.property_map[0]; + merger->source2.property_map = zalloc(size); + count = set2->files.size / sizeof (struct razor_entry); + size = count * sizeof merger->source2.file_map[0]; + merger->source2.file_map = zalloc(size); + + return merger; +} + +void +razor_merger_add_package(struct razor_merger *merger, + struct razor_package *package) +{ + char *pool; + struct list *r; + struct razor_package *p; + struct razor_set *set1; + struct source *source; + uint32_t flags; + + set1 = merger->source1.set; + if (set1->packages.data <= (void *) package && + (void *) package < set1->packages.data + set1->packages.size) { + source = &merger->source1; + flags = 0; + } else { + source = &merger->source2; + flags = UPSTREAM_SOURCE; + } + + pool = source->set->string_pool.data; + p = array_add(&merger->set->packages, sizeof *p); + p->name = hashtable_tokenize(&merger->table, &pool[package->name]); + p->flags = flags; + p->version = hashtable_tokenize(&merger->table, + &pool[package->version]); + p->arch = hashtable_tokenize(&merger->table, + &pool[package->arch]); + + p->properties = package->properties; + r = list_first(&package->properties, &source->set->property_pool); + while (r) { + source->property_map[r->data] = 1; + r = list_next(r); + } + + p->files = package->files; + r = list_first(&package->files, &source->set->file_pool); + while (r) { + source->file_map[r->data] = 1; + r = list_next(r); + } +} + +static uint32_t +add_property(struct razor_merger *merger, + const char *name, uint32_t flags, const char *version) +{ + struct razor_property *p; + + p = array_add(&merger->set->properties, sizeof *p); + p->name = hashtable_tokenize(&merger->table, name); + p->flags = flags; + p->version = hashtable_tokenize(&merger->table, version); + + return p - (struct razor_property *) merger->set->properties.data; +} + +static void +merge_properties(struct razor_merger *merger) +{ + struct razor_property *p1, *p2; + struct razor_set *set1, *set2; + uint32_t *map1, *map2; + int i, j, cmp, count1, count2; + char *pool1, *pool2; + + set1 = merger->source1.set; + set2 = merger->source2.set; + map1 = merger->source1.property_map; + map2 = merger->source2.property_map; + + i = 0; + j = 0; + pool1 = set1->string_pool.data; + pool2 = set2->string_pool.data; + + count1 = set1->properties.size / sizeof *p1; + count2 = set2->properties.size / sizeof *p2; + while (i < count1 || j < count2) { + if (i < count1 && map1[i] == 0) { + i++; + continue; + } + if (j < count2 && map2[j] == 0) { + j++; + continue; + } + p1 = (struct razor_property *) set1->properties.data + i; + p2 = (struct razor_property *) set2->properties.data + j; + if (i < count1 && j < count2) + cmp = strcmp(&pool1[p1->name], &pool2[p2->name]); + else if (i < count1) + cmp = -1; + else + cmp = 1; + if (cmp == 0) + cmp = p1->flags - p2->flags; + if (cmp == 0) + cmp = razor_versioncmp(&pool1[p1->version], + &pool2[p2->version]); + if (cmp < 0) { + map1[i++] = add_property(merger, + &pool1[p1->name], + p1->flags, + &pool1[p1->version]); + } else if (cmp > 0) { + map2[j++] = add_property(merger, + &pool2[p2->name], + p2->flags, + &pool2[p2->version]); + } else { + map1[i++] = map2[j++] = + add_property(merger, + &pool1[p1->name], + p1->flags, + &pool1[p1->version]); + } + } +} + +static void +emit_properties(struct list_head *properties, struct array *source_pool, + uint32_t *map, struct array *pool) +{ + uint32_t r; + struct list *p, *q; + + r = pool->size / sizeof *q; + p = list_first(properties, source_pool); + while (p) { + q = array_add(pool, sizeof *q); + q->data = map[p->data]; + q->flags = p->flags; + p = list_next(p); + } + + list_set_ptr(properties, r); +} + +static uint32_t +add_file(struct razor_merger *merger, const char *name) +{ + struct razor_entry *e; + + e = array_add(&merger->set->files, sizeof *e); + e->name = hashtable_tokenize(&merger->table, name); + e->flags = 0; + e->start = 0; + + return e - (struct razor_entry *)merger->set->files.data; +} + +/* FIXME. Blah */ +static int +fix_file_map(uint32_t *map, + struct razor_entry *files, + struct razor_entry *top) +{ + uint32_t e; + int found_file = 0; + + e = top->start; + do { + if (files[e].start) + fix_file_map(map, files, &files[e]); + if (map[e]) + found_file = 1; + } while (!(files[e++].flags & RAZOR_ENTRY_LAST)); + + if (found_file) + map[top - files] = 1; + return found_file; +} + +struct merge_directory { + uint32_t merged, dir1, dir2; +}; + +static void +merge_one_directory(struct razor_merger *merger, struct merge_directory *md) +{ + struct razor_entry *root1, *root2, *mroot, *e1, *e2; + struct razor_set *set1, *set2; + struct array merge_stack; + struct merge_directory *child_md, *end_md; + uint32_t *map1, *map2, start, last; + int cmp; + char *pool1, *pool2; + + set1 = merger->source1.set; + set2 = merger->source2.set; + map1 = merger->source1.file_map; + map2 = merger->source2.file_map; + pool1 = set1->string_pool.data; + pool2 = set2->string_pool.data; + root1 = (struct razor_entry *) set1->files.data; + root2 = (struct razor_entry *) set2->files.data; + + array_init(&merge_stack); + + start = merger->set->files.size / sizeof (struct razor_entry); + last = 0; + e1 = md->dir1 ? root1 + md->dir1 : NULL; + e2 = md->dir2 ? root2 + md->dir2 : NULL; + while (e1 || e2) { + if (!e2 && !map1[e1 - root1]) { + if ((e1++)->flags & RAZOR_ENTRY_LAST) + e1 = NULL; + continue; + } + if (!e1 && !map2[e2 - root2]) { + if ((e2++)->flags & RAZOR_ENTRY_LAST) + e2 = NULL; + continue; + } + if (e1 && !map1[e1 - root1] && + e2 && !map1[e2 - root2]) { + if ((e1++)->flags & RAZOR_ENTRY_LAST) + e1 = NULL; + if ((e2++)->flags & RAZOR_ENTRY_LAST) + e2 = NULL; + continue; + } + + if (!e1) + cmp = 1; + else if (!e2) + cmp = -1; + else { + cmp = strcmp (&pool1[e1->name], + &pool2[e2->name]); + } + + if (cmp < 0) { + if (map1[e1 - root1]) { + map1[e1 - root1] = last = + add_file(merger, &pool1[e1->name]); + if (e1->start) { + child_md = array_add(&merge_stack, sizeof (struct merge_directory)); + child_md->merged = last; + child_md->dir1 = e1->start; + child_md->dir2 = 0; + } + } + if ((e1++)->flags & RAZOR_ENTRY_LAST) + e1 = NULL; + } else if (cmp > 0) { + if (map2[e2 - root2]) { + map2[e2 - root2] = last = + add_file(merger, &pool2[e2->name]); + if (e2->start) { + child_md = array_add(&merge_stack, sizeof (struct merge_directory)); + child_md->merged = last; + child_md->dir1 = 0; + child_md->dir2 = e2->start; + } + } + if ((e2++)->flags & RAZOR_ENTRY_LAST) + e2 = NULL; + } else { + map1[e1 - root1] = map2[e2- root2] = last = + add_file(merger, &pool1[e1->name]); + if (e1->start || e2->start) { + child_md = array_add(&merge_stack, sizeof (struct merge_directory)); + child_md->merged = last; + child_md->dir1 = e1->start; + child_md->dir2 = e2->start; + } + if ((e1++)->flags & RAZOR_ENTRY_LAST) + e1 = NULL; + if ((e2++)->flags & RAZOR_ENTRY_LAST) + e2 = NULL; + } + } + + mroot = (struct razor_entry *)merger->set->files.data; + if (last) { + mroot[last].flags = RAZOR_ENTRY_LAST; + mroot[md->merged].start = start; + } else + mroot[md->merged].start = 0; + + end_md = merge_stack.data + merge_stack.size; + for (child_md = merge_stack.data; child_md < end_md; child_md++) + merge_one_directory(merger, child_md); + array_release(&merge_stack); +} + +static void +merge_files(struct razor_merger *merger) +{ + struct razor_entry *root; + struct merge_directory md; + uint32_t *map1, *map2; + + map1 = merger->source1.file_map; + map2 = merger->source2.file_map; + + md.merged = 0; + + if (merger->source1.set->files.size) { + root = (struct razor_entry *) merger->source1.set->files.data; + if (root->start) + fix_file_map(map1, root, root); + md.dir1 = root->start; + } else + md.dir1 = 0; + + if (merger->source2.set->files.size) { + root = (struct razor_entry *) merger->source2.set->files.data; + if (root->start) + fix_file_map(map2, root, root); + md.dir2 = root->start; + } else + md.dir2 = 0; + + merge_one_directory(merger, &md); +} + +static void +emit_files(struct list_head *files, struct array *source_pool, + uint32_t *map, struct array *pool) +{ + uint32_t r; + struct list *p, *q; + + r = pool->size / sizeof *q; + p = list_first(files, source_pool); + while (p) { + q = array_add(pool, sizeof *q); + q->data = map[p->data]; + q->flags = p->flags; + p = list_next(p); + } + + list_set_ptr(files, r); +} + +/* Rebuild property->packages maps. We can't just remap these, as a + * property may have lost or gained a number of packages. Allocate an + * array per property and loop through the packages and add them to + * the arrays for their properties. */ +static void +rebuild_property_package_lists(struct razor_set *set) +{ + struct array *pkgs, *a; + struct razor_package *pkg, *pkg_end; + struct razor_property *prop, *prop_end; + struct list *r; + uint32_t *q; + int count; + + count = set->properties.size / sizeof (struct razor_property); + pkgs = zalloc(count * sizeof *pkgs); + pkg_end = set->packages.data + set->packages.size; + + for (pkg = set->packages.data; pkg < pkg_end; pkg++) { + r = list_first(&pkg->properties, &set->property_pool); + while (r) { + q = array_add(&pkgs[r->data], sizeof *q); + *q = pkg - (struct razor_package *) set->packages.data; + r = list_next(r); + } + } + + prop_end = set->properties.data + set->properties.size; + a = pkgs; + for (prop = set->properties.data; prop < prop_end; prop++, a++) { + list_set_array(&prop->packages, &set->package_pool, a, 0); + array_release(a); + } + free(pkgs); +} + +static void +rebuild_file_package_lists(struct razor_set *set) +{ + struct array *pkgs, *a; + struct razor_package *pkg, *pkg_end; + struct razor_entry *entry, *entry_end; + struct list *r; + uint32_t *q; + int count; + + count = set->files.size / sizeof (struct razor_entry); + pkgs = zalloc(count * sizeof *pkgs); + pkg_end = set->packages.data + set->packages.size; + + for (pkg = set->packages.data; pkg < pkg_end; pkg++) { + r = list_first(&pkg->files, &set->file_pool); + while (r) { + q = array_add(&pkgs[r->data], sizeof *q); + *q = pkg - (struct razor_package *) set->packages.data; + r = list_next(r); + } + } + + entry_end = set->files.data + set->files.size; + a = pkgs; + for (entry = set->files.data; entry < entry_end; entry++, a++) { + list_set_array(&entry->packages, &set->package_pool, a, 0); + array_release(a); + } + free(pkgs); +} + +struct razor_set * +razor_merger_finish(struct razor_merger *merger) +{ + struct razor_set *result; + struct razor_package *p, *pend; + + /* As we built the package list, we filled out a bitvector of + * the properties that are referenced by the packages in the + * new set. Now we do a parallel loop through the properties + * and emit those marked in the bit vector to the new set. In + * the process, we update the bit vector to actually map from + * indices in the old property list to indices in the new + * property list for both sets. */ + + merge_properties(merger); + merge_files(merger); + + /* Now we loop through the packages again and emit the + * property lists, remapped to point to the new properties. */ + + pend = merger->set->packages.data + merger->set->packages.size; + for (p = merger->set->packages.data; p < pend; p++) { + struct source *src; + + if (p->flags & UPSTREAM_SOURCE) + src = &merger->source2; + else + src = &merger->source1; + + emit_properties(&p->properties, + &src->set->property_pool, + src->property_map, + &merger->set->property_pool); + emit_files(&p->files, + &src->set->file_pool, + src->file_map, + &merger->set->file_pool); + p->flags &= ~UPSTREAM_SOURCE; + } + + rebuild_property_package_lists(merger->set); + rebuild_file_package_lists(merger->set); + + result = merger->set; + hashtable_release(&merger->table); + free(merger); + + return result; +} diff --git a/librazor/razor-internal.h b/librazor/razor-internal.h index f2a922f..bcc5e11 100644 --- a/librazor/razor-internal.h +++ b/librazor/razor-internal.h @@ -1,8 +1,166 @@ #ifndef _RAZOR_INTERNAL_H_ #define _RAZOR_INTERNAL_H_ +#include <stdlib.h> +#include <stdint.h> + +void *zalloc(size_t size); + +struct array { + void *data; + int size, alloc; +}; + +void array_init(struct array *array); +void array_release(struct array *array); +void *array_add(struct array *array, int size); + + +struct list_head { + uint32_t list_ptr : 24; + uint32_t flags : 8; +}; + +struct list { + uint32_t data : 24; + uint32_t flags : 8; +}; + +void list_set_empty(struct list_head *head); +void list_set_ptr(struct list_head *head, uint32_t ptr); +void list_set_array(struct list_head *head, struct array *pool, struct array *items, int force_indirect); + +struct list *list_first(struct list_head *head, struct array *pool); +struct list *list_next(struct list *list); + +void list_remap_pool(struct array *pool, uint32_t *map); +void list_remap_head(struct list_head *list, uint32_t *map); + + +struct hashtable { + struct array buckets; + struct array *pool; +}; + +void hashtable_init(struct hashtable *table, struct array *pool); +void hashtable_release(struct hashtable *table); +uint32_t hashtable_insert(struct hashtable *table, const char *key); +uint32_t hashtable_lookup(struct hashtable *table, const char *key); +uint32_t hashtable_tokenize(struct hashtable *table, const char *string); + + +struct razor_set_section { + uint32_t type; + uint32_t offset; + uint32_t size; +}; + +struct razor_set_header { + uint32_t magic; + uint32_t version; + struct razor_set_section sections[0]; +}; + +#define RAZOR_MAGIC 0x7a7a7a7a +#define RAZOR_VERSION 1 + +#define RAZOR_STRING_POOL 0 +#define RAZOR_PACKAGES 1 +#define RAZOR_PROPERTIES 2 +#define RAZOR_FILES 3 +#define RAZOR_PACKAGE_POOL 4 +#define RAZOR_PROPERTY_POOL 5 +#define RAZOR_FILE_POOL 6 + +struct razor_package { + uint32_t name : 24; + uint32_t flags : 8; + uint32_t version; + uint32_t arch; + struct list_head properties; + struct list_head files; +}; + +struct razor_property { + uint32_t name; + uint32_t flags; + uint32_t version; + struct list_head packages; +}; + +struct razor_entry { + uint32_t name : 24; + uint32_t flags : 8; + uint32_t start; + struct list_head packages; +}; + +#define RAZOR_ENTRY_LAST 0x80 + +struct razor_set { + struct array string_pool; + struct array packages; + struct array properties; + struct array files; + struct array package_pool; + struct array property_pool; + struct array file_pool; + struct razor_set_header *header; +}; + +struct import_entry { + uint32_t package; + char *name; +}; + +struct import_directory { + uint32_t name, count; + struct array files; + struct array packages; + struct import_directory *last; +}; + +struct razor_importer { + struct razor_set *set; + struct hashtable table; + struct razor_package *package; + struct array properties; + struct array files; + struct array file_requires; +}; + +struct razor_package_iterator { + struct razor_set *set; + struct razor_package *package, *end; + struct list *index; + int free_index; +}; + +void +razor_package_iterator_init_for_property(struct razor_package_iterator *pi, + struct razor_set *set, + struct razor_property *property); + +struct razor_property_iterator { + struct razor_set *set; + struct razor_property *property, *end; + struct list *index; +}; + #define ALIGN(value, base) (((value) + (base - 1)) & ~((base) - 1)) +struct razor_entry * +razor_set_find_entry(struct razor_set *set, + struct razor_entry *dir, const char *pattern); + +struct razor_merger * +razor_merger_create(struct razor_set *set1, struct razor_set *set2); +void +razor_merger_add_package(struct razor_merger *merger, + struct razor_package *package); +struct razor_set * +razor_merger_finish(struct razor_merger *merger); + /* Utility functions */ int razor_create_dir(const char *root, const char *path); diff --git a/librazor/razor.c b/librazor/razor.c index 67a2df2..210da4c 100644 --- a/librazor/razor.c +++ b/librazor/razor.c @@ -35,89 +35,8 @@ #include "razor.h" #include "razor-internal.h" -#include "types.h" -struct razor_set_section { - uint32_t type; - uint32_t offset; - uint32_t size; -}; - -struct razor_set_header { - uint32_t magic; - uint32_t version; - struct razor_set_section sections[0]; -}; - -#define RAZOR_MAGIC 0x7a7a7a7a -#define RAZOR_VERSION 1 - -#define RAZOR_STRING_POOL 0 -#define RAZOR_PACKAGES 1 -#define RAZOR_PROPERTIES 2 -#define RAZOR_FILES 3 -#define RAZOR_PACKAGE_POOL 4 -#define RAZOR_PROPERTY_POOL 5 -#define RAZOR_FILE_POOL 6 - -struct razor_package { - uint name : 24; - uint flags : 8; - uint32_t version; - uint32_t arch; - struct list_head properties; - struct list_head files; -}; - -struct razor_property { - uint32_t name; - uint32_t flags; - uint32_t version; - struct list_head packages; -}; - -struct razor_entry { - uint name : 24; - uint flags : 8; - uint32_t start; - struct list_head packages; -}; - -#define RAZOR_ENTRY_LAST 0x80 - -struct razor_set { - struct array string_pool; - struct array packages; - struct array properties; - struct array files; - struct array package_pool; - struct array property_pool; - struct array file_pool; - struct razor_set_header *header; -}; - -struct import_entry { - uint32_t package; - char *name; -}; - -struct import_directory { - uint32_t name, count; - struct array files; - struct array packages; - struct import_directory *last; -}; - -struct razor_importer { - struct razor_set *set; - struct hashtable table; - struct razor_package *package; - struct array properties; - struct array files; - struct array file_requires; -}; - -static void * +void * zalloc(size_t size) { void *p; @@ -296,95 +215,8 @@ razor_build_evr(char *evr_buf, int size, const char *epoch, snprintf(evr_buf, size, "-%s", release); } -void -razor_importer_begin_package(struct razor_importer *importer, - const char *name, - const char *version, - const char *arch) -{ - struct razor_package *p; - - p = array_add(&importer->set->packages, sizeof *p); - p->name = hashtable_tokenize(&importer->table, name); - p->flags = 0; - p->version = hashtable_tokenize(&importer->table, version); - p->arch = hashtable_tokenize(&importer->table, arch); - - importer->package = p; - array_init(&importer->properties); -} - - -void -razor_importer_finish_package(struct razor_importer *importer) -{ - list_set_array(&importer->package->properties, - &importer->set->property_pool, - &importer->properties, - 1); - - array_release(&importer->properties); -} - -void -razor_importer_add_property(struct razor_importer *importer, - const char *name, - uint32_t flags, - const char *version) -{ - struct razor_property *p; - uint32_t *r; - - p = array_add(&importer->set->properties, sizeof *p); - p->name = hashtable_tokenize(&importer->table, name); - p->flags = flags; - p->version = hashtable_tokenize(&importer->table, version); - list_set_ptr(&p->packages, importer->package - - (struct razor_package *) importer->set->packages.data); - - r = array_add(&importer->properties, sizeof *r); - *r = p - (struct razor_property *) importer->set->properties.data; - - if (((flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES) && - *name == '/') { - r = array_add(&importer->file_requires, sizeof *r); - *r = p->name; - } -} - -void -razor_importer_add_file(struct razor_importer *importer, const char *name) -{ - struct import_entry *e; - - e = array_add(&importer->files, sizeof *e); - - e->package = importer->package - - (struct razor_package *) importer->set->packages.data; - e->name = strdup(name); -} - -struct razor_importer * -razor_importer_new(void) -{ - struct razor_importer *importer; - - importer = zalloc(sizeof *importer); - importer->set = razor_set_create(); - hashtable_init(&importer->table, &importer->set->string_pool); - - return importer; -} - -/* Destroy an importer without creating the set. */ -void -razor_importer_destroy(struct razor_importer *importer) -{ - /* FIXME: write this */ -} - -static int -versioncmp(const char *s1, const char *s2) +int +razor_versioncmp(const char *s1, const char *s2) { const char *p1, *p2; long n1, n2; @@ -414,489 +246,12 @@ versioncmp(const char *s1, const char *s2) p1++; p2++; if (isdigit(*p1) && isdigit(*p2)) - return versioncmp(p1, p2); + return razor_versioncmp(p1, p2); } return *p1 - *p2; } -static int -compare_packages(const void *p1, const void *p2, void *data) -{ - const struct razor_package *pkg1 = p1, *pkg2 = p2; - struct razor_set *set = data; - char *pool = set->string_pool.data; - - /* FIXME: what if the flags are different? */ - if (pkg1->name == pkg2->name) - return versioncmp(&pool[pkg1->version], &pool[pkg2->version]); - else - return strcmp(&pool[pkg1->name], &pool[pkg2->name]); -} - -static int -compare_properties(const void *p1, const void *p2, void *data) -{ - const struct razor_property *prop1 = p1, *prop2 = p2; - struct razor_set *set = data; - char *pool = set->string_pool.data; - - if (prop1->name != prop2->name) - return strcmp(&pool[prop1->name], &pool[prop2->name]); - else if (prop1->flags != prop2->flags) - return prop1->flags - prop2->flags; - else - return versioncmp(&pool[prop1->version], &pool[prop2->version]); -} - -static uint32_t * -uniqueify_properties(struct razor_set *set) -{ - struct razor_property *rp, *up, *rp_end; - struct array *pkgs, *p; - struct list_head *r; - uint32_t *map, *rmap; - int i, count, unique; - - count = set->properties.size / sizeof(struct razor_property); - map = razor_qsort_with_data(set->properties.data, - count, - sizeof(struct razor_property), - compare_properties, - set); - - rp_end = set->properties.data + set->properties.size; - rmap = malloc(count * sizeof *map); - pkgs = zalloc(count * sizeof *pkgs); - for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) { - if (rp->name != up->name || - rp->flags != up->flags || - rp->version != up->version) { - up++; - up->name = rp->name; - up->flags = rp->flags; - up->version = rp->version; - } - - unique = up - (struct razor_property *) set->properties.data; - rmap[map[i]] = unique; - r = array_add(&pkgs[unique], sizeof *r); - *r = rp->packages; - } - free(map); - - if (up != rp) - up++; - set->properties.size = (void *) up - set->properties.data; - rp_end = up; - for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) { - list_set_array(&rp->packages, &set->package_pool, p, 0); - array_release(p); - } - - free(pkgs); - - return rmap; -} - -static int -compare_filenames(const void *p1, const void *p2, void *data) -{ - const struct import_entry *e1 = p1; - const struct import_entry *e2 = p2; - const char *n1 = e1->name; - const char *n2 = e2->name; - - /* Need to make sure that the contents of a directory - * are sorted immediately after it. So "foo/bar" has to - * sort before "foo.conf" - * - * FIXME: this is about 60% slower than strcmp - */ - while (*n1 && *n2) { - if (*n1 < *n2) - return *n2 == '/' ? 1 : -1; - else if (*n1 > *n2) - return *n1 == '/' ? -1 : 1; - n1++; - n2++; - } - if (*n1) - return 1; - else if (*n2) - return -1; - else - return 0; -} - -static void -count_entries(struct import_directory *d) -{ - struct import_directory *p, *end; - - p = d->files.data; - end = d->files.data + d->files.size; - d->count = 0; - while (p < end) { - count_entries(p); - d->count += p->count + 1; - p++; - } -} - -static void -serialize_files(struct razor_set *set, - struct import_directory *d, struct array *array) -{ - struct import_directory *p, *end; - struct razor_entry *e = NULL; - uint32_t s; - - p = d->files.data; - end = d->files.data + d->files.size; - s = array->size / sizeof *e + d->files.size / sizeof *p; - while (p < end) { - e = array_add(array, sizeof *e); - e->name = p->name; - e->flags = 0; - e->start = p->count > 0 ? s : 0; - s += p->count; - - list_set_array(&e->packages, &set->package_pool, &p->packages, 0); - array_release(&p->packages); - p++; - } - if (e != NULL) - e->flags |= RAZOR_ENTRY_LAST; - - p = d->files.data; - end = d->files.data + d->files.size; - while (p < end) { - serialize_files(set, p, array); - p++; - } -} - -static void -remap_property_package_links(struct array *properties, uint32_t *rmap) -{ - struct razor_property *p, *end; - - end = properties->data + properties->size; - for (p = properties->data; p < end; p++) - list_remap_head(&p->packages, rmap); -} - -static void -build_file_tree(struct razor_importer *importer) -{ - int count, i, length; - struct import_entry *filenames; - char *f, *end; - uint32_t name, *r; - char dirname[256]; - struct import_directory *d, root; - struct razor_entry *e; - - count = importer->files.size / sizeof (struct import_entry); - razor_qsort_with_data(importer->files.data, - count, - sizeof (struct import_entry), - compare_filenames, - NULL); - - root.name = hashtable_tokenize(&importer->table, ""); - array_init(&root.files); - array_init(&root.packages); - root.last = NULL; - - filenames = importer->files.data; - for (i = 0; i < count; i++) { - f = filenames[i].name; - if (*f != '/') - continue; - f++; - - d = &root; - while (*f) { - end = strchr(f, '/'); - if (end == NULL) - end = f + strlen(f); - length = end - f; - memcpy(dirname, f, length); - dirname[length] ='\0'; - name = hashtable_tokenize(&importer->table, dirname); - if (d->last == NULL || d->last->name != name) { - d->last = array_add(&d->files, sizeof *d); - d->last->name = name; - d->last->last = NULL; - array_init(&d->last->files); - array_init(&d->last->packages); - } - d = d->last; - f = end + 1; - if (*end == '\0') - break; - } - - r = array_add(&d->packages, sizeof *r); - *r = filenames[i].package; - free(filenames[i].name); - } - - count_entries(&root); - e = importer->set->files.data; - e->name = root.name; - e->flags = RAZOR_ENTRY_LAST; - e->start = importer->files.size ? 1 : 0; - list_set_empty(&e->packages); - - serialize_files(importer->set, &root, &importer->set->files); - - array_release(&importer->files); -} - -static struct razor_entry * -find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern); - -static void -list_to_array(struct list *list, struct array *array) -{ - uint32_t *item; - - while (list) { - item = array_add(array, sizeof *item); - *item = list->data; - list = list_next(list); - } -} - -static int -compare_file_requires(const void *p1, const void *p2, void *data) -{ - uint32_t *f1 = (void *)p1, *f2 = (void *)p2; - const char *pool = data; - - return strcmp(&pool[*f1], &pool[*f2]); -} - -static void -find_file_provides(struct razor_importer *importer) -{ - struct razor_property *prop; - struct razor_entry *top, *entry; - struct razor_package *packages; - struct array pkgprops; - struct list *pkg; - uint32_t *req, *req_start, *req_end; - uint32_t *map, *newprop; - char *pool; - - pool = importer->set->string_pool.data; - packages = importer->set->packages.data; - top = importer->set->files.data; - - req = req_start = importer->file_requires.data; - req_end = importer->file_requires.data + importer->file_requires.size; - map = razor_qsort_with_data(req, req_end - req, sizeof *req, - compare_file_requires, pool); - free(map); - - for (req = req_start; req < req_end; req++) { - if (req > req_start && req[0] == req[-1]) - continue; - entry = find_entry(importer->set, top, &pool[*req]); - if (!entry) - continue; - - for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) { - prop = array_add(&importer->set->properties, sizeof *prop); - prop->name = *req; - prop->flags = - RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL; - prop->version = hashtable_tokenize(&importer->table, ""); - list_set_ptr(&prop->packages, pkg->data); - - /* Update property list of pkg */ - array_init(&pkgprops); - list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops); - newprop = array_add(&pkgprops, sizeof *newprop); - *newprop = prop - (struct razor_property *)importer->set->properties.data; - list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1); - array_release(&pkgprops); - } - } - - array_release(&importer->file_requires); -} - -static void -build_package_file_lists(struct razor_set *set, uint32_t *rmap) -{ - struct razor_package *p, *packages; - struct array *pkgs; - struct razor_entry *e, *end; - struct list *r; - uint32_t *q; - int i, count; - - count = set->packages.size / sizeof *p; - pkgs = zalloc(count * sizeof *pkgs); - - end = set->files.data + set->files.size; - for (e = set->files.data; e < end; e++) { - list_remap_head(&e->packages, rmap); - r = list_first(&e->packages, &set->package_pool); - while (r) { - q = array_add(&pkgs[r->data], sizeof *q); - *q = e - (struct razor_entry *) set->files.data; - r = list_next(r); - } - } - - packages = set->packages.data; - for (i = 0; i < count; i++) { - list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0); - array_release(&pkgs[i]); - } - free(pkgs); -} - -struct razor_set * -razor_importer_finish(struct razor_importer *importer) -{ - struct razor_set *set; - uint32_t *map, *rmap; - int i, count; - - build_file_tree(importer); - find_file_provides(importer); - - map = uniqueify_properties(importer->set); - list_remap_pool(&importer->set->property_pool, map); - free(map); - - count = importer->set->packages.size / sizeof(struct razor_package); - map = razor_qsort_with_data(importer->set->packages.data, - count, - sizeof(struct razor_package), - compare_packages, - importer->set); - - rmap = malloc(count * sizeof *rmap); - for (i = 0; i < count; i++) - rmap[map[i]] = i; - free(map); - - list_remap_pool(&importer->set->package_pool, rmap); - build_package_file_lists(importer->set, rmap); - remap_property_package_links(&importer->set->properties, rmap); - free(rmap); - - set = importer->set; - hashtable_release(&importer->table); - free(importer); - - return set; -} - -struct razor_package_iterator { - struct razor_set *set; - struct razor_package *package, *end; - struct list *index; - int free_index; -}; - -static struct razor_package_iterator * -razor_package_iterator_create_with_index(struct razor_set *set, - struct list *index) -{ - struct razor_package_iterator *pi; - - pi = zalloc(sizeof *pi); - pi->set = set; - pi->index = index; - - return pi; -} - -struct razor_package_iterator * -razor_package_iterator_create(struct razor_set *set) -{ - struct razor_package_iterator *pi; - - pi = zalloc(sizeof *pi); - pi->set = set; - pi->end = set->packages.data + set->packages.size; - pi->package = set->packages.data; - - return pi; -} - -static void -razor_package_iterator_init_for_property(struct razor_package_iterator *pi, - struct razor_set *set, - struct razor_property *property) -{ - memset(pi, 0, sizeof *pi); - pi->set = set; - pi->index = list_first(&property->packages, &set->package_pool); -} - -struct razor_package_iterator * -razor_package_iterator_create_for_property(struct razor_set *set, - struct razor_property *property) -{ - struct list *index; - - index = list_first(&property->packages, &set->package_pool); - return razor_package_iterator_create_with_index(set, index); -} - -int -razor_package_iterator_next(struct razor_package_iterator *pi, - struct razor_package **package, - const char **name, - const char **version, - const char **arch) -{ - char *pool; - int valid; - struct razor_package *p, *packages; - - if (pi->package) { - p = pi->package++; - valid = p < pi->end; - } else if (pi->index) { - packages = pi->set->packages.data; - p = &packages[pi->index->data]; - pi->index = list_next(pi->index); - valid = 1; - } else - valid = 0; - - if (valid) { - pool = pi->set->string_pool.data; - *package = p; - *name = &pool[p->name]; - *version = &pool[p->version]; - *arch = &pool[p->arch]; - } else { - *package = NULL; - } - - return valid; -} - -void -razor_package_iterator_destroy(struct razor_package_iterator *pi) -{ - if (pi->free_index) - free(pi->index); - - free(pi); -} - struct razor_package * razor_set_get_package(struct razor_set *set, const char *package) { @@ -914,75 +269,9 @@ razor_set_get_package(struct razor_set *set, const char *package) return p; } -struct razor_property_iterator { - struct razor_set *set; - struct razor_property *property, *end; - struct list *index; -}; - -struct razor_property_iterator * -razor_property_iterator_create(struct razor_set *set, - struct razor_package *package) -{ - struct razor_property_iterator *pi; - - pi = zalloc(sizeof *pi); - pi->set = set; - - if (package) { - pi->index = list_first(&package->properties, - &set->property_pool); - } else { - pi->property = set->properties.data; - pi->end = set->properties.data + set->properties.size; - } - - return pi; -} - -int -razor_property_iterator_next(struct razor_property_iterator *pi, - struct razor_property **property, - const char **name, - uint32_t *flags, - const char **version) -{ - char *pool; - int valid; - struct razor_property *p, *properties; - - if (pi->property) { - p = pi->property++; - valid = p < pi->end; - } else if (pi->index) { - properties = pi->set->properties.data; - p = &properties[pi->index->data]; - pi->index = list_next(pi->index); - valid = 1; - } else - valid = 0; - - if (valid) { - pool = pi->set->string_pool.data; - *property = p; - *name = &pool[p->name]; - *flags = p->flags; - *version = &pool[p->version]; - } else { - *property = NULL; - } - - return valid; -} - -void -razor_property_iterator_destroy(struct razor_property_iterator *pi) -{ - free(pi); -} - -static struct razor_entry * -find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern) +struct razor_entry * +razor_set_find_entry(struct razor_set *set, + struct razor_entry *dir, const char *pattern) { struct razor_entry *e; const char *n, *pool = set->string_pool.data; @@ -996,7 +285,7 @@ find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern) len = strlen(n); if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 && pattern[len + 1] == '/') { - return find_entry(set, e, pattern + len + 1); + return razor_set_find_entry(set, e, pattern + len + 1); } } while (!((e++)->flags & RAZOR_ENTRY_LAST)); @@ -1039,7 +328,7 @@ razor_set_list_files(struct razor_set *set, const char *pattern) } strcpy(buffer, pattern); - e = find_entry(set, set->files.data, buffer); + e = razor_set_find_entry(set, set->files.data, buffer); if (e && e->start > 0) { base = NULL; } else { @@ -1051,26 +340,11 @@ razor_set_list_files(struct razor_set *set, const char *pattern) base = NULL; } } - e = find_entry(set, set->files.data, buffer); + e = razor_set_find_entry(set, set->files.data, buffer); if (e->start != 0) list_dir(set, e, buffer, base); } -struct razor_package_iterator * -razor_package_iterator_create_for_file(struct razor_set *set, - const char *filename) -{ - struct razor_entry *entry; - struct list *index; - - entry = find_entry(set, set->files.data, filename); - if (entry == NULL) - return NULL; - - index = list_first(&entry->packages, &set->package_pool); - return razor_package_iterator_create_with_index(set, index); -} - static struct list * list_package_files(struct razor_set *set, struct list *r, struct razor_entry *dir, uint32_t end, @@ -1142,509 +416,6 @@ razor_set_list_package_files(struct razor_set *set, const char *name) list_package_files(set, r, set->files.data, end, buffer); } -#define UPSTREAM_SOURCE 0x80 - -struct source { - struct razor_set *set; - uint32_t *property_map; - uint32_t *file_map; -}; - -struct razor_merger { - struct razor_set *set; - struct hashtable table; - struct source source1; - struct source source2; -}; - -static struct razor_merger * -razor_merger_create(struct razor_set *set1, struct razor_set *set2) -{ - struct razor_merger *merger; - int count; - size_t size; - - merger = zalloc(sizeof *merger); - merger->set = razor_set_create(); - hashtable_init(&merger->table, &merger->set->string_pool); - - merger->source1.set = set1; - count = set1->properties.size / sizeof (struct razor_property); - size = count * sizeof merger->source1.property_map[0]; - merger->source1.property_map = zalloc(size); - count = set1->files.size / sizeof (struct razor_entry); - size = count * sizeof merger->source1.file_map[0]; - merger->source1.file_map = zalloc(size); - - merger->source2.set = set2; - count = set2->properties.size / sizeof (struct razor_property); - size = count * sizeof merger->source2.property_map[0]; - merger->source2.property_map = zalloc(size); - count = set2->files.size / sizeof (struct razor_entry); - size = count * sizeof merger->source2.file_map[0]; - merger->source2.file_map = zalloc(size); - - return merger; -} - -static void -razor_merger_add_package(struct razor_merger *merger, - struct razor_package *package) -{ - char *pool; - struct list *r; - struct razor_package *p; - struct razor_set *set1; - struct source *source; - uint32_t flags; - - set1 = merger->source1.set; - if (set1->packages.data <= (void *) package && - (void *) package < set1->packages.data + set1->packages.size) { - source = &merger->source1; - flags = 0; - } else { - source = &merger->source2; - flags = UPSTREAM_SOURCE; - } - - pool = source->set->string_pool.data; - p = array_add(&merger->set->packages, sizeof *p); - p->name = hashtable_tokenize(&merger->table, &pool[package->name]); - p->flags = flags; - p->version = hashtable_tokenize(&merger->table, - &pool[package->version]); - p->arch = hashtable_tokenize(&merger->table, - &pool[package->arch]); - - p->properties = package->properties; - r = list_first(&package->properties, &source->set->property_pool); - while (r) { - source->property_map[r->data] = 1; - r = list_next(r); - } - - p->files = package->files; - r = list_first(&package->files, &source->set->file_pool); - while (r) { - source->file_map[r->data] = 1; - r = list_next(r); - } -} - -static uint32_t -add_property(struct razor_merger *merger, - const char *name, uint32_t flags, const char *version) -{ - struct razor_property *p; - - p = array_add(&merger->set->properties, sizeof *p); - p->name = hashtable_tokenize(&merger->table, name); - p->flags = flags; - p->version = hashtable_tokenize(&merger->table, version); - - return p - (struct razor_property *) merger->set->properties.data; -} - -static void -merge_properties(struct razor_merger *merger) -{ - struct razor_property *p1, *p2; - struct razor_set *set1, *set2; - uint32_t *map1, *map2; - int i, j, cmp, count1, count2; - char *pool1, *pool2; - - set1 = merger->source1.set; - set2 = merger->source2.set; - map1 = merger->source1.property_map; - map2 = merger->source2.property_map; - - i = 0; - j = 0; - pool1 = set1->string_pool.data; - pool2 = set2->string_pool.data; - - count1 = set1->properties.size / sizeof *p1; - count2 = set2->properties.size / sizeof *p2; - while (i < count1 || j < count2) { - if (i < count1 && map1[i] == 0) { - i++; - continue; - } - if (j < count2 && map2[j] == 0) { - j++; - continue; - } - p1 = (struct razor_property *) set1->properties.data + i; - p2 = (struct razor_property *) set2->properties.data + j; - if (i < count1 && j < count2) - cmp = strcmp(&pool1[p1->name], &pool2[p2->name]); - else if (i < count1) - cmp = -1; - else - cmp = 1; - if (cmp == 0) - cmp = p1->flags - p2->flags; - if (cmp == 0) - cmp = versioncmp(&pool1[p1->version], - &pool2[p2->version]); - if (cmp < 0) { - map1[i++] = add_property(merger, - &pool1[p1->name], - p1->flags, - &pool1[p1->version]); - } else if (cmp > 0) { - map2[j++] = add_property(merger, - &pool2[p2->name], - p2->flags, - &pool2[p2->version]); - } else { - map1[i++] = map2[j++] = - add_property(merger, - &pool1[p1->name], - p1->flags, - &pool1[p1->version]); - } - } -} - -static void -emit_properties(struct list_head *properties, struct array *source_pool, - uint32_t *map, struct array *pool) -{ - uint32_t r; - struct list *p, *q; - - r = pool->size / sizeof *q; - p = list_first(properties, source_pool); - while (p) { - q = array_add(pool, sizeof *q); - q->data = map[p->data]; - q->flags = p->flags; - p = list_next(p); - } - - list_set_ptr(properties, r); -} - -static uint32_t -add_file(struct razor_merger *merger, const char *name) -{ - struct razor_entry *e; - - e = array_add(&merger->set->files, sizeof *e); - e->name = hashtable_tokenize(&merger->table, name); - e->flags = 0; - e->start = 0; - - return e - (struct razor_entry *)merger->set->files.data; -} - -/* FIXME. Blah */ -static int -fix_file_map(uint32_t *map, - struct razor_entry *files, - struct razor_entry *top) -{ - uint32_t e; - int found_file = 0; - - e = top->start; - do { - if (files[e].start) - fix_file_map(map, files, &files[e]); - if (map[e]) - found_file = 1; - } while (!(files[e++].flags & RAZOR_ENTRY_LAST)); - - if (found_file) - map[top - files] = 1; - return found_file; -} - -struct merge_directory { - uint32_t merged, dir1, dir2; -}; - -static void -merge_one_directory(struct razor_merger *merger, struct merge_directory *md) -{ - struct razor_entry *root1, *root2, *mroot, *e1, *e2; - struct razor_set *set1, *set2; - struct array merge_stack; - struct merge_directory *child_md, *end_md; - uint32_t *map1, *map2, start, last; - int cmp; - char *pool1, *pool2; - - set1 = merger->source1.set; - set2 = merger->source2.set; - map1 = merger->source1.file_map; - map2 = merger->source2.file_map; - pool1 = set1->string_pool.data; - pool2 = set2->string_pool.data; - root1 = (struct razor_entry *) set1->files.data; - root2 = (struct razor_entry *) set2->files.data; - - array_init(&merge_stack); - - start = merger->set->files.size / sizeof (struct razor_entry); - last = 0; - e1 = md->dir1 ? root1 + md->dir1 : NULL; - e2 = md->dir2 ? root2 + md->dir2 : NULL; - while (e1 || e2) { - if (!e2 && !map1[e1 - root1]) { - if ((e1++)->flags & RAZOR_ENTRY_LAST) - e1 = NULL; - continue; - } - if (!e1 && !map2[e2 - root2]) { - if ((e2++)->flags & RAZOR_ENTRY_LAST) - e2 = NULL; - continue; - } - if (e1 && !map1[e1 - root1] && - e2 && !map1[e2 - root2]) { - if ((e1++)->flags & RAZOR_ENTRY_LAST) - e1 = NULL; - if ((e2++)->flags & RAZOR_ENTRY_LAST) - e2 = NULL; - continue; - } - - if (!e1) - cmp = 1; - else if (!e2) - cmp = -1; - else { - cmp = strcmp (&pool1[e1->name], - &pool2[e2->name]); - } - - if (cmp < 0) { - if (map1[e1 - root1]) { - map1[e1 - root1] = last = - add_file(merger, &pool1[e1->name]); - if (e1->start) { - child_md = array_add(&merge_stack, sizeof (struct merge_directory)); - child_md->merged = last; - child_md->dir1 = e1->start; - child_md->dir2 = 0; - } - } - if ((e1++)->flags & RAZOR_ENTRY_LAST) - e1 = NULL; - } else if (cmp > 0) { - if (map2[e2 - root2]) { - map2[e2 - root2] = last = - add_file(merger, &pool2[e2->name]); - if (e2->start) { - child_md = array_add(&merge_stack, sizeof (struct merge_directory)); - child_md->merged = last; - child_md->dir1 = 0; - child_md->dir2 = e2->start; - } - } - if ((e2++)->flags & RAZOR_ENTRY_LAST) - e2 = NULL; - } else { - map1[e1 - root1] = map2[e2- root2] = last = - add_file(merger, &pool1[e1->name]); - if (e1->start || e2->start) { - child_md = array_add(&merge_stack, sizeof (struct merge_directory)); - child_md->merged = last; - child_md->dir1 = e1->start; - child_md->dir2 = e2->start; - } - if ((e1++)->flags & RAZOR_ENTRY_LAST) - e1 = NULL; - if ((e2++)->flags & RAZOR_ENTRY_LAST) - e2 = NULL; - } - } - - mroot = (struct razor_entry *)merger->set->files.data; - if (last) { - mroot[last].flags = RAZOR_ENTRY_LAST; - mroot[md->merged].start = start; - } else - mroot[md->merged].start = 0; - - end_md = merge_stack.data + merge_stack.size; - for (child_md = merge_stack.data; child_md < end_md; child_md++) - merge_one_directory(merger, child_md); - array_release(&merge_stack); -} - -static void -merge_files(struct razor_merger *merger) -{ - struct razor_entry *root; - struct merge_directory md; - uint32_t *map1, *map2; - - map1 = merger->source1.file_map; - map2 = merger->source2.file_map; - - md.merged = 0; - - if (merger->source1.set->files.size) { - root = (struct razor_entry *) merger->source1.set->files.data; - if (root->start) - fix_file_map(map1, root, root); - md.dir1 = root->start; - } else - md.dir1 = 0; - - if (merger->source2.set->files.size) { - root = (struct razor_entry *) merger->source2.set->files.data; - if (root->start) - fix_file_map(map2, root, root); - md.dir2 = root->start; - } else - md.dir2 = 0; - - merge_one_directory(merger, &md); -} - -static void -emit_files(struct list_head *files, struct array *source_pool, - uint32_t *map, struct array *pool) -{ - uint32_t r; - struct list *p, *q; - - r = pool->size / sizeof *q; - p = list_first(files, source_pool); - while (p) { - q = array_add(pool, sizeof *q); - q->data = map[p->data]; - q->flags = p->flags; - p = list_next(p); - } - - list_set_ptr(files, r); -} - -/* Rebuild property->packages maps. We can't just remap these, as a - * property may have lost or gained a number of packages. Allocate an - * array per property and loop through the packages and add them to - * the arrays for their properties. */ -static void -rebuild_property_package_lists(struct razor_set *set) -{ - struct array *pkgs, *a; - struct razor_package *pkg, *pkg_end; - struct razor_property *prop, *prop_end; - struct list *r; - uint32_t *q; - int count; - - count = set->properties.size / sizeof (struct razor_property); - pkgs = zalloc(count * sizeof *pkgs); - pkg_end = set->packages.data + set->packages.size; - - for (pkg = set->packages.data; pkg < pkg_end; pkg++) { - r = list_first(&pkg->properties, &set->property_pool); - while (r) { - q = array_add(&pkgs[r->data], sizeof *q); - *q = pkg - (struct razor_package *) set->packages.data; - r = list_next(r); - } - } - - prop_end = set->properties.data + set->properties.size; - a = pkgs; - for (prop = set->properties.data; prop < prop_end; prop++, a++) { - list_set_array(&prop->packages, &set->package_pool, a, 0); - array_release(a); - } - free(pkgs); -} - -static void -rebuild_file_package_lists(struct razor_set *set) -{ - struct array *pkgs, *a; - struct razor_package *pkg, *pkg_end; - struct razor_entry *entry, *entry_end; - struct list *r; - uint32_t *q; - int count; - - count = set->files.size / sizeof (struct razor_entry); - pkgs = zalloc(count * sizeof *pkgs); - pkg_end = set->packages.data + set->packages.size; - - for (pkg = set->packages.data; pkg < pkg_end; pkg++) { - r = list_first(&pkg->files, &set->file_pool); - while (r) { - q = array_add(&pkgs[r->data], sizeof *q); - *q = pkg - (struct razor_package *) set->packages.data; - r = list_next(r); - } - } - - entry_end = set->files.data + set->files.size; - a = pkgs; - for (entry = set->files.data; entry < entry_end; entry++, a++) { - list_set_array(&entry->packages, &set->package_pool, a, 0); - array_release(a); - } - free(pkgs); -} - -static struct razor_set * -razor_merger_finish(struct razor_merger *merger) -{ - struct razor_set *result; - struct razor_package *p, *pend; - - /* As we built the package list, we filled out a bitvector of - * the properties that are referenced by the packages in the - * new set. Now we do a parallel loop through the properties - * and emit those marked in the bit vector to the new set. In - * the process, we update the bit vector to actually map from - * indices in the old property list to indices in the new - * property list for both sets. */ - - merge_properties(merger); - merge_files(merger); - - /* Now we loop through the packages again and emit the - * property lists, remapped to point to the new properties. */ - - pend = merger->set->packages.data + merger->set->packages.size; - for (p = merger->set->packages.data; p < pend; p++) { - struct source *src; - - if (p->flags & UPSTREAM_SOURCE) - src = &merger->source2; - else - src = &merger->source1; - - emit_properties(&p->properties, - &src->set->property_pool, - src->property_map, - &merger->set->property_pool); - emit_files(&p->files, - &src->set->file_pool, - src->file_map, - &merger->set->file_pool); - p->flags &= ~UPSTREAM_SOURCE; - } - - rebuild_property_package_lists(merger->set); - rebuild_file_package_lists(merger->set); - - result = merger->set; - hashtable_release(&merger->table); - free(merger); - - return result; -} - /* The diff order matters. We should sort the packages so that a * REMOVE of a package comes before the INSTALL, and so that all * requires for a package have been installed before the package. @@ -1669,7 +440,7 @@ razor_set_diff(struct razor_set *set, struct razor_set *upstream, if (p1 && p2) { res = strcmp(name1, name2); if (res == 0) - res = versioncmp(version1, version2); + res = razor_versioncmp(version1, version2); } else { res = 0; } @@ -1690,953 +461,3 @@ razor_set_diff(struct razor_set *set, struct razor_set *upstream, razor_package_iterator_destroy(pi1); razor_package_iterator_destroy(pi2); } - -static int -provider_satisfies_requirement(struct razor_property *provider, - const char *provider_strings, - uint32_t flags, - const char *required) -{ - int cmp, len; - const char *provided = &provider_strings[provider->version]; - - if (!*required) - return 1; - if (!*provided) { - if (flags & RAZOR_PROPERTY_LESS) - return 0; - else - return 1; - } - - cmp = versioncmp(provided, required); - - switch (flags & RAZOR_PROPERTY_RELATION_MASK) { - case RAZOR_PROPERTY_LESS: - return cmp < 0; - - case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL: - if (cmp <= 0) - return 1; - /* fall through: FIXME, make sure this is correct */ - - case RAZOR_PROPERTY_EQUAL: - if (cmp == 0) - return 1; - - /* "foo == 1.1" is satisfied by "foo 1.1-2" */ - len = strlen(required); - if (!strncmp(required, provided, len) && provided[len] == '-') - return 1; - return 0; - - case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL: - return cmp >= 0; - - case RAZOR_PROPERTY_GREATER: - return cmp > 0; - } - - /* shouldn't happen */ - return 0; -} - -#define TRANS_PACKAGE_PRESENT 1 -#define TRANS_PACKAGE_UPDATE 2 -#define TRANS_PROPERTY_SATISFIED 0x80000000 - -struct transaction_set { - struct razor_set *set; - uint32_t *packages; - uint32_t *properties; -}; - -struct razor_transaction { - int package_count, errors; - struct transaction_set system, upstream; - int changes; -}; - -static void -transaction_set_init(struct transaction_set *ts, struct razor_set *set) -{ - int count; - - ts->set = set; - count = set->packages.size / sizeof (struct razor_package); - ts->packages = zalloc(count * sizeof *ts->packages); - count = set->properties.size / sizeof (struct razor_property); - ts->properties = zalloc(count * sizeof *ts->properties); -} - -static void -transaction_set_release(struct transaction_set *ts) -{ - free(ts->packages); - free(ts->properties); -} - -static void -transaction_set_install_package(struct transaction_set *ts, - struct razor_package *package) -{ - struct razor_package *pkgs; - struct list *prop; - int i; - - pkgs = ts->set->packages.data; - i = package - pkgs; - if (ts->packages[i] == TRANS_PACKAGE_PRESENT) - return; - - ts->packages[i] = TRANS_PACKAGE_PRESENT; - - prop = list_first(&package->properties, &ts->set->property_pool); - while (prop) { - ts->properties[prop->data]++; - prop = list_next(prop); - } -} - -static void -transaction_set_remove_package(struct transaction_set *ts, - struct razor_package *package) -{ - struct razor_package *pkgs; - struct list *prop; - int i; - - pkgs = ts->set->packages.data; - i = package - pkgs; - if (ts->packages[i] == 0) - return; - - ts->packages[i] = 0; - - prop = list_first(&package->properties, &ts->set->property_pool); - while (prop) { - ts->properties[prop->data]--; - prop = list_next(prop); - } -} - -struct razor_transaction * -razor_transaction_create(struct razor_set *system, struct razor_set *upstream) -{ - struct razor_transaction *trans; - struct razor_package *p, *spkgs, *pend; - - trans = zalloc(sizeof *trans); - transaction_set_init(&trans->system, system); - transaction_set_init(&trans->upstream, upstream); - - spkgs = trans->system.set->packages.data; - pend = trans->system.set->packages.data + - trans->system.set->packages.size; - for (p = spkgs; p < pend; p++) - transaction_set_install_package(&trans->system, p); - - return trans; -} - -void -razor_transaction_install_package(struct razor_transaction *trans, - struct razor_package *package) -{ - transaction_set_install_package(&trans->upstream, package); - trans->changes++; -} - -void -razor_transaction_remove_package(struct razor_transaction *trans, - struct razor_package *package) -{ - transaction_set_remove_package(&trans->system, package); - trans->changes++; -} - -void -razor_transaction_update_package(struct razor_transaction *trans, - struct razor_package *package) -{ - struct razor_package *spkgs, *upkgs, *end; - - spkgs = trans->system.set->packages.data; - upkgs = trans->upstream.set->packages.data; - end = trans->system.set->packages.data + - trans->system.set->packages.size; - if (spkgs <= package && package < end) - trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE; - else - trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE; -} - -struct prop_iter { - struct razor_property *p, *start, *end; - const char *pool; - uint32_t *present; -}; - -static void -prop_iter_init(struct prop_iter *pi, struct transaction_set *ts) -{ - pi->p = ts->set->properties.data; - pi->start = ts->set->properties.data; - pi->end = ts->set->properties.data + ts->set->properties.size; - pi->pool = ts->set->string_pool.data; - pi->present = ts->properties; -} - -static int -prop_iter_next(struct prop_iter *pi, uint32_t flags, struct razor_property **p) -{ - while (pi->p < pi->end) { - if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) && - (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) == flags) { - *p = pi->p++; - return 1; - } - pi->p++; - } - - return 0; -} - -static struct razor_property * -prop_iter_seek_to(struct prop_iter *pi, - uint32_t flags, const char *match) -{ - uint32_t name; - - while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0) - pi->p++; - - if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0) - return NULL; - - name = pi->p->name; - while (pi->p < pi->end && - pi->p->name == name && - (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) != flags) - pi->p++; - - if (pi->p == pi->end || pi->p->name != name) - return NULL; - - return pi->p; -} - -/* Remove packages from set that provide any of the matching (same - * name and type) providers from ppi onwards that match the - * requirement that rpi points to. */ -static void -remove_matching_providers(struct razor_transaction *trans, - struct prop_iter *ppi, - uint32_t flags, - const char *version) -{ - struct razor_property *p; - struct razor_package *pkg, *pkgs; - struct razor_package_iterator pkg_iter; - struct razor_set *set; - const char *n, *v, *a; - uint32_t type; - - if (ppi->present == trans->system.properties) - set = trans->system.set; - else - set = trans->upstream.set; - - pkgs = (struct razor_package *) set->packages.data; - type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; - for (p = ppi->p; - p < ppi->end && - p->name == ppi->p->name && - (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type; - p++) { - if (!ppi->present[p - ppi->start]) - continue; - if (!provider_satisfies_requirement(p, ppi->pool, - flags, version)) - continue; - - razor_package_iterator_init_for_property(&pkg_iter, set, p); - while (razor_package_iterator_next(&pkg_iter, - &pkg, &n, &v, &a)) { - fprintf(stderr, "removing %s-%s\n", n, v); - razor_transaction_remove_package(trans, pkg); - } - } -} - -static void -flag_matching_providers(struct razor_transaction *trans, - struct prop_iter *ppi, - struct razor_property *r, - struct prop_iter *rpi, - unsigned int flag) -{ - struct razor_property *p; - struct razor_package *pkg, *pkgs; - struct razor_package_iterator pkg_iter; - struct razor_set *set; - const char *name, *version, *arch; - uint32_t *flags, type; - - if (ppi->present == trans->system.properties) { - set = trans->system.set; - flags = trans->system.packages; - } else { - set = trans->upstream.set; - flags = trans->upstream.packages; - } - - pkgs = (struct razor_package *) set->packages.data; - type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; - for (p = ppi->p; - p < ppi->end && - p->name == ppi->p->name && - (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type; - p++) { - if (!ppi->present[p - ppi->start]) - continue; - if (!provider_satisfies_requirement(p, ppi->pool, - r->flags, - &rpi->pool[r->version])) - continue; - - razor_package_iterator_init_for_property(&pkg_iter, set, p); - while (razor_package_iterator_next(&pkg_iter, &pkg, - &name, &version, &arch)) { - - fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n", - name, version, - ppi->pool + p->name, - rpi->pool + r->name, - rpi->pool + r->version); - flags[pkg - pkgs] |= flag; - } - } -} - -static struct razor_package * -pick_matching_provider(struct razor_set *set, - struct prop_iter *ppi, - uint32_t flags, - const char *version) -{ - struct razor_property *p; - struct razor_package *pkgs; - struct list *i; - uint32_t type; - - /* This is where we decide which pkgs to pull in to satisfy a - * requirement. There may be several different providers - * (different versions) and each version of a provider may - * come from a number of packages. We pick the first package - * from the first provider that matches. */ - - pkgs = set->packages.data; - type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; - for (p = ppi->p; - p < ppi->end && - p->name == ppi->p->name && - (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type && - ppi->present[p - ppi->start] == 0; - p++) { - if (!provider_satisfies_requirement(p, ppi->pool, - flags, version)) - continue; - - i = list_first(&p->packages, &set->package_pool); - - return &pkgs[i->data]; - } - - return NULL; -} - -static void -remove_obsoleted_packages(struct razor_transaction *trans) -{ - struct razor_property *up; - struct razor_package *spkgs; - struct prop_iter spi, upi; - - spkgs = trans->system.set->packages.data; - prop_iter_init(&spi, &trans->system); - prop_iter_init(&upi, &trans->upstream); - - while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) { - if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, - &upi.pool[up->name])) - continue; - remove_matching_providers(trans, &spi, up->flags, - &upi.pool[up->version]); - } -} - -static int -any_provider_satisfies_requirement(struct prop_iter *ppi, - uint32_t flags, - const char *version) -{ - struct razor_property *p; - uint32_t type; - - type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; - for (p = ppi->p; - p < ppi->end && - p->name == ppi->p->name && - (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type; - p++) { - if (ppi->present[p - ppi->start] > 0 && - provider_satisfies_requirement(p, ppi->pool, - flags, version)) - return 1; - } - - return 0; -} - -static void -clear_requires_flags(struct transaction_set *ts) -{ - struct razor_property *p; - const char *pool; - int i, count; - - count = ts->set->properties.size / sizeof *p; - p = ts->set->properties.data; - pool = ts->set->string_pool.data; - for (i = 0; i < count; i++) { - ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED; - if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0) - ts->properties[i] |= TRANS_PROPERTY_SATISFIED; - } -} - -const char * -razor_property_relation_to_string(struct razor_property *p) -{ - switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) { - case RAZOR_PROPERTY_LESS: - return "<"; - - case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL: - return "<="; - - case RAZOR_PROPERTY_EQUAL: - return "="; - - case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL: - return ">="; - - case RAZOR_PROPERTY_GREATER: - return ">"; - - default: - return "?"; - } -} - -const char * -razor_property_type_to_string(struct razor_property *p) -{ - switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) { - case RAZOR_PROPERTY_REQUIRES: - return "requires"; - case RAZOR_PROPERTY_PROVIDES: - return "provides"; - case RAZOR_PROPERTY_CONFLICTS: - return "conflicts"; - case RAZOR_PROPERTY_OBSOLETES: - return "obsoletes"; - default: - return NULL; - } -} - -static void -mark_satisfied_requires(struct razor_transaction *trans, - struct transaction_set *rts, - struct transaction_set *pts) -{ - struct prop_iter rpi, ppi; - struct razor_property *rp; - - prop_iter_init(&rpi, rts); - prop_iter_init(&ppi, pts); - - while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { - if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, - &rpi.pool[rp->name])) - continue; - - if (any_provider_satisfies_requirement(&ppi, rp->flags, - &rpi.pool[rp->version])) - rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED; - } -} - -static void -mark_all_satisfied_requires(struct razor_transaction *trans) -{ - clear_requires_flags(&trans->system); - clear_requires_flags(&trans->upstream); - mark_satisfied_requires(trans, &trans->system, &trans->system); - mark_satisfied_requires(trans, &trans->system, &trans->upstream); - mark_satisfied_requires(trans, &trans->upstream, &trans->system); - mark_satisfied_requires(trans, &trans->upstream, &trans->upstream); -} - -static void -update_unsatisfied_packages(struct razor_transaction *trans) -{ - struct razor_package *spkgs, *pkg; - struct razor_property *sp; - struct prop_iter spi; - struct razor_package_iterator pkg_iter; - const char *name, *version, *arch; - - spkgs = trans->system.set->packages.data; - prop_iter_init(&spi, &trans->system); - - while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) { - if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED) - continue; - - razor_package_iterator_init_for_property(&pkg_iter, - trans->system.set, - sp); - while (razor_package_iterator_next(&pkg_iter, &pkg, - &name, &version, &arch)) { - fprintf(stderr, "updating %s because %s %s %s " - "isn't satisfied\n", - name, spi.pool + sp->name, - razor_property_relation_to_string(sp), - spi.pool + sp->version); - trans->system.packages[pkg - spkgs] |= - TRANS_PACKAGE_UPDATE; - } - } -} - -void -razor_transaction_update_all(struct razor_transaction *trans) -{ - struct razor_package *p; - int i, count; - - count = trans->system.set->packages.size / sizeof *p; - for (i = 0; i < count; i++) - trans->system.packages[i] |= TRANS_PACKAGE_UPDATE; -} - -static void -update_conflicted_packages(struct razor_transaction *trans) -{ - struct razor_package *pkg, *spkgs; - struct razor_property *up, *sp; - struct prop_iter spi, upi; - struct razor_package_iterator pkg_iter; - const char *name, *version, *arch; - - spkgs = trans->system.set->packages.data; - prop_iter_init(&spi, &trans->system); - prop_iter_init(&upi, &trans->upstream); - - while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) { - if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES, - &spi.pool[sp->name])) - continue; - - if (!any_provider_satisfies_requirement(&upi, sp->flags, - &spi.pool[sp->version])) - continue; - - razor_package_iterator_init_for_property(&pkg_iter, - trans->system.set, - sp); - while (razor_package_iterator_next(&pkg_iter, &pkg, - &name, &version, &arch)) { - fprintf(stderr, "updating %s %s because it conflicts with %s", - name, version, spi.pool + sp->name); - trans->system.packages[pkg - spkgs] |= - TRANS_PACKAGE_UPDATE; - } - } - - prop_iter_init(&spi, &trans->system); - prop_iter_init(&upi, &trans->upstream); - - while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) { - sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, - &upi.pool[upi.p->name]); - - if (sp) - flag_matching_providers(trans, &spi, up, &upi, - TRANS_PACKAGE_UPDATE); - } -} - -static void -pull_in_requirements(struct razor_transaction *trans, - struct prop_iter *rpi, struct prop_iter *ppi) -{ - struct razor_property *rp, *pp; - struct razor_package *pkg, *upkgs; - - upkgs = trans->upstream.set->packages.data; - while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { - if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED) - continue; - - pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES, - &rpi->pool[rp->name]); - if (pp == NULL) - continue; - pkg = pick_matching_provider(trans->upstream.set, - ppi, rp->flags, - &rpi->pool[rp->version]); - if (pkg == NULL) - continue; - - rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED; - - fprintf(stderr, "pulling in %s which provides %s %s %s " - "to satisfy %s %s %s\n", - ppi->pool + pkg->name, - ppi->pool + pp->name, - razor_property_relation_to_string(pp), - ppi->pool + pp->version, - &rpi->pool[rp->name], - razor_property_relation_to_string(rp), - &rpi->pool[rp->version]); - - trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE; - } -} - -static void -pull_in_all_requirements(struct razor_transaction *trans) -{ - struct prop_iter rpi, ppi; - - prop_iter_init(&rpi, &trans->system); - prop_iter_init(&ppi, &trans->upstream); - pull_in_requirements(trans, &rpi, &ppi); - - prop_iter_init(&rpi, &trans->upstream); - prop_iter_init(&ppi, &trans->upstream); - pull_in_requirements(trans, &rpi, &ppi); -} - -static void -flush_scheduled_system_updates(struct razor_transaction *trans) -{ - struct razor_package_iterator *pi; - struct razor_package *p, *pkg, *spkgs; - struct prop_iter ppi; - const char *name, *version, *arch; - - spkgs = trans->system.set->packages.data; - pi = razor_package_iterator_create(trans->system.set); - prop_iter_init(&ppi, &trans->upstream); - - while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { - if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE)) - continue; - - if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name)) - continue; - - pkg = pick_matching_provider(trans->upstream.set, &ppi, - RAZOR_PROPERTY_GREATER, version); - if (pkg == NULL) - continue; - - fprintf(stderr, "updating %s-%s to %s-%s\n", - name, version, - &ppi.pool[pkg->name], &ppi.pool[pkg->version]); - - razor_transaction_remove_package(trans, p); - razor_transaction_install_package(trans, pkg); - } - - razor_package_iterator_destroy(pi); -} - -static void -flush_scheduled_upstream_updates(struct razor_transaction *trans) -{ - struct razor_package_iterator *pi; - struct razor_package *p, *upkgs; - struct prop_iter spi; - const char *name, *version, *arch; - - upkgs = trans->upstream.set->packages.data; - pi = razor_package_iterator_create(trans->upstream.set); - prop_iter_init(&spi, &trans->system); - - while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { - if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE)) - continue; - - if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name)) - remove_matching_providers(trans, - &spi, - RAZOR_PROPERTY_LESS, - version); - razor_transaction_install_package(trans, p); - fprintf(stderr, "installing %s-%s\n", name, version); - } -} - -int -razor_transaction_resolve(struct razor_transaction *trans) -{ - int last = 0; - - flush_scheduled_system_updates(trans); - flush_scheduled_upstream_updates(trans); - - while (last < trans->changes) { - last = trans->changes; - remove_obsoleted_packages(trans); - mark_all_satisfied_requires(trans); - update_unsatisfied_packages(trans); - update_conflicted_packages(trans); - pull_in_all_requirements(trans); - flush_scheduled_system_updates(trans); - flush_scheduled_upstream_updates(trans); - } - - return trans->changes; -} - -static void -describe_unsatisfied(struct razor_set *set, struct razor_property *rp) -{ - struct razor_package_iterator pi; - struct razor_package *pkg; - const char *name, *version, *arch, *pool; - - pool = set->string_pool.data; - if (pool[rp->version] == '\0') { - razor_package_iterator_init_for_property(&pi, set, rp); - while (razor_package_iterator_next(&pi, &pkg, - &name, &version, &arch)) - fprintf(stderr, "%s is needed by %s-%s.%s\n", - &pool[rp->name], - name, version, arch); - } else { - razor_package_iterator_init_for_property(&pi, set, rp); - while (razor_package_iterator_next(&pi, &pkg, - &name, &version, &arch)) - fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n", - &pool[rp->name], - razor_property_relation_to_string(rp), - &pool[rp->version], - name, version, arch); - } -} - -int -razor_transaction_describe(struct razor_transaction *trans) -{ - struct prop_iter rpi; - struct razor_property *rp; - int unsatisfied; - - flush_scheduled_system_updates(trans); - flush_scheduled_upstream_updates(trans); - mark_all_satisfied_requires(trans); - - unsatisfied = 0; - prop_iter_init(&rpi, &trans->system); - while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { - if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) { - describe_unsatisfied(trans->system.set, rp); - unsatisfied++; - } - } - - prop_iter_init(&rpi, &trans->upstream); - while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { - if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) { - describe_unsatisfied(trans->upstream.set, rp); - unsatisfied++; - } - } - - return unsatisfied; -} - -int -razor_transaction_unsatisfied_property(struct razor_transaction *trans, - const char *name, - uint32_t flags, - const char *version) -{ - struct prop_iter pi; - struct razor_property *p; - - prop_iter_init(&pi, &trans->system); - while (prop_iter_next(&pi, flags, &p)) { - if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) && - p->flags == flags && - strcmp(&pi.pool[p->name], name) == 0 && - strcmp(&pi.pool[p->version], version) == 0) - - return 1; - } - - prop_iter_init(&pi, &trans->upstream); - while (prop_iter_next(&pi, flags, &p)) { - if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) && - p->flags == flags && - strcmp(&pi.pool[p->name], name) == 0 && - strcmp(&pi.pool[p->version], version) == 0) - - return 1; - } - - return 0; -} - -struct razor_set * -razor_transaction_finish(struct razor_transaction *trans) -{ - struct razor_merger *merger; - struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs; - char *upool, *spool; - int cmp; - - s = trans->system.set->packages.data; - spkgs = trans->system.set->packages.data; - send = trans->system.set->packages.data + - trans->system.set->packages.size; - spool = trans->system.set->string_pool.data; - - u = trans->upstream.set->packages.data; - upkgs = trans->upstream.set->packages.data; - uend = trans->upstream.set->packages.data + - trans->upstream.set->packages.size; - upool = trans->upstream.set->string_pool.data; - - merger = razor_merger_create(trans->system.set, trans->upstream.set); - while (s < send || u < uend) { - if (s < send && u < uend) - cmp = strcmp(&spool[s->name], &upool[u->name]); - else if (s < send) - cmp = -1; - else - cmp = 1; - - if (cmp < 0) { - if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT) - razor_merger_add_package(merger, s); - s++; - } else if (cmp == 0) { - if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT) - razor_merger_add_package(merger, s); - if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT) - razor_merger_add_package(merger, u); - - s++; - u++; - } else { - if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT) - razor_merger_add_package(merger, u); - u++; - } - } - - razor_transaction_destroy(trans); - - return razor_merger_finish(merger); -} - -void -razor_transaction_destroy(struct razor_transaction *trans) -{ - transaction_set_release(&trans->system); - transaction_set_release(&trans->upstream); - free(trans); -} - -struct razor_package_query { - struct razor_set *set; - char *vector; - int count; -}; - -struct razor_package_query * -razor_package_query_create(struct razor_set *set) -{ - struct razor_package_query *pq; - int count; - - pq = zalloc(sizeof *pq); - pq->set = set; - count = set->packages.size / sizeof(struct razor_package); - pq->vector = zalloc(count * sizeof(char)); - - return pq; -} - -void -razor_package_query_add_package(struct razor_package_query *pq, - struct razor_package *p) -{ - struct razor_package *packages; - - packages = pq->set->packages.data; - pq->count += pq->vector[p - packages] ^ 1; - pq->vector[p - packages] = 1; -} - -void -razor_package_query_add_iterator(struct razor_package_query *pq, - struct razor_package_iterator *pi) -{ - struct razor_package *packages, *p; - const char *name, *version, *arch; - - packages = pq->set->packages.data; - while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { - pq->count += pq->vector[p - packages] ^ 1; - pq->vector[p - packages] = 1; - } -} - -struct razor_package_iterator * -razor_package_query_finish(struct razor_package_query *pq) -{ - struct razor_package_iterator *pi; - struct razor_set *set; - struct list *index; - int i, j, count; - - set = pq->set; - count = set->packages.size / sizeof(struct razor_package); - index = zalloc(pq->count * sizeof *index); - - for (i = 0, j = 0; i < count; i++) { - if (!pq->vector[i]) - continue; - - index[j].data = i; - if (j == pq->count - 1) - index[j].flags = 0x80; - j++; - } - - free(pq); - - pi = razor_package_iterator_create_with_index(set, index); - pi->free_index = 1; - - return pi; -} diff --git a/librazor/razor.h b/librazor/razor.h index 77a5870..d073ebb 100644 --- a/librazor/razor.h +++ b/librazor/razor.h @@ -164,6 +164,7 @@ struct razor_set *razor_importer_finish(struct razor_importer *importer); void razor_build_evr(char *evr_buf, int size, const char *epoch, const char *version, const char *release); +int razor_versioncmp(const char *s1, const char *s2); struct razor_set *razor_set_create_from_yum(void); struct razor_set *razor_set_create_from_rpmdb(void); diff --git a/librazor/razor-root.c b/librazor/root.c index 8c032ef..8c032ef 100644 --- a/librazor/razor-root.c +++ b/librazor/root.c diff --git a/librazor/transaction.c b/librazor/transaction.c new file mode 100644 index 0000000..93b1bf2 --- /dev/null +++ b/librazor/transaction.c @@ -0,0 +1,912 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com> + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> +#include <fnmatch.h> + +#include "razor-internal.h" +#include "razor.h" + +static int +provider_satisfies_requirement(struct razor_property *provider, + const char *provider_strings, + uint32_t flags, + const char *required) +{ + int cmp, len; + const char *provided = &provider_strings[provider->version]; + + if (!*required) + return 1; + if (!*provided) { + if (flags & RAZOR_PROPERTY_LESS) + return 0; + else + return 1; + } + + cmp = razor_versioncmp(provided, required); + + switch (flags & RAZOR_PROPERTY_RELATION_MASK) { + case RAZOR_PROPERTY_LESS: + return cmp < 0; + + case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL: + if (cmp <= 0) + return 1; + /* fall through: FIXME, make sure this is correct */ + + case RAZOR_PROPERTY_EQUAL: + if (cmp == 0) + return 1; + + /* "foo == 1.1" is satisfied by "foo 1.1-2" */ + len = strlen(required); + if (!strncmp(required, provided, len) && provided[len] == '-') + return 1; + return 0; + + case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL: + return cmp >= 0; + + case RAZOR_PROPERTY_GREATER: + return cmp > 0; + } + + /* shouldn't happen */ + return 0; +} + +#define TRANS_PACKAGE_PRESENT 1 +#define TRANS_PACKAGE_UPDATE 2 +#define TRANS_PROPERTY_SATISFIED 0x80000000 + +struct transaction_set { + struct razor_set *set; + uint32_t *packages; + uint32_t *properties; +}; + +struct razor_transaction { + int package_count, errors; + struct transaction_set system, upstream; + int changes; +}; + +static void +transaction_set_init(struct transaction_set *ts, struct razor_set *set) +{ + int count; + + ts->set = set; + count = set->packages.size / sizeof (struct razor_package); + ts->packages = zalloc(count * sizeof *ts->packages); + count = set->properties.size / sizeof (struct razor_property); + ts->properties = zalloc(count * sizeof *ts->properties); +} + +static void +transaction_set_release(struct transaction_set *ts) +{ + free(ts->packages); + free(ts->properties); +} + +static void +transaction_set_install_package(struct transaction_set *ts, + struct razor_package *package) +{ + struct razor_package *pkgs; + struct list *prop; + int i; + + pkgs = ts->set->packages.data; + i = package - pkgs; + if (ts->packages[i] == TRANS_PACKAGE_PRESENT) + return; + + ts->packages[i] = TRANS_PACKAGE_PRESENT; + + prop = list_first(&package->properties, &ts->set->property_pool); + while (prop) { + ts->properties[prop->data]++; + prop = list_next(prop); + } +} + +static void +transaction_set_remove_package(struct transaction_set *ts, + struct razor_package *package) +{ + struct razor_package *pkgs; + struct list *prop; + int i; + + pkgs = ts->set->packages.data; + i = package - pkgs; + if (ts->packages[i] == 0) + return; + + ts->packages[i] = 0; + + prop = list_first(&package->properties, &ts->set->property_pool); + while (prop) { + ts->properties[prop->data]--; + prop = list_next(prop); + } +} + +struct razor_transaction * +razor_transaction_create(struct razor_set *system, struct razor_set *upstream) +{ + struct razor_transaction *trans; + struct razor_package *p, *spkgs, *pend; + + trans = zalloc(sizeof *trans); + transaction_set_init(&trans->system, system); + transaction_set_init(&trans->upstream, upstream); + + spkgs = trans->system.set->packages.data; + pend = trans->system.set->packages.data + + trans->system.set->packages.size; + for (p = spkgs; p < pend; p++) + transaction_set_install_package(&trans->system, p); + + return trans; +} + +void +razor_transaction_install_package(struct razor_transaction *trans, + struct razor_package *package) +{ + transaction_set_install_package(&trans->upstream, package); + trans->changes++; +} + +void +razor_transaction_remove_package(struct razor_transaction *trans, + struct razor_package *package) +{ + transaction_set_remove_package(&trans->system, package); + trans->changes++; +} + +void +razor_transaction_update_package(struct razor_transaction *trans, + struct razor_package *package) +{ + struct razor_package *spkgs, *upkgs, *end; + + spkgs = trans->system.set->packages.data; + upkgs = trans->upstream.set->packages.data; + end = trans->system.set->packages.data + + trans->system.set->packages.size; + if (spkgs <= package && package < end) + trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE; + else + trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE; +} + +struct prop_iter { + struct razor_property *p, *start, *end; + const char *pool; + uint32_t *present; +}; + +static void +prop_iter_init(struct prop_iter *pi, struct transaction_set *ts) +{ + pi->p = ts->set->properties.data; + pi->start = ts->set->properties.data; + pi->end = ts->set->properties.data + ts->set->properties.size; + pi->pool = ts->set->string_pool.data; + pi->present = ts->properties; +} + +static int +prop_iter_next(struct prop_iter *pi, uint32_t flags, struct razor_property **p) +{ + while (pi->p < pi->end) { + if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) && + (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) == flags) { + *p = pi->p++; + return 1; + } + pi->p++; + } + + return 0; +} + +static struct razor_property * +prop_iter_seek_to(struct prop_iter *pi, + uint32_t flags, const char *match) +{ + uint32_t name; + + while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0) + pi->p++; + + if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0) + return NULL; + + name = pi->p->name; + while (pi->p < pi->end && + pi->p->name == name && + (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) != flags) + pi->p++; + + if (pi->p == pi->end || pi->p->name != name) + return NULL; + + return pi->p; +} + +/* Remove packages from set that provide any of the matching (same + * name and type) providers from ppi onwards that match the + * requirement that rpi points to. */ +static void +remove_matching_providers(struct razor_transaction *trans, + struct prop_iter *ppi, + uint32_t flags, + const char *version) +{ + struct razor_property *p; + struct razor_package *pkg, *pkgs; + struct razor_package_iterator pkg_iter; + struct razor_set *set; + const char *n, *v, *a; + uint32_t type; + + if (ppi->present == trans->system.properties) + set = trans->system.set; + else + set = trans->upstream.set; + + pkgs = (struct razor_package *) set->packages.data; + type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; + for (p = ppi->p; + p < ppi->end && + p->name == ppi->p->name && + (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type; + p++) { + if (!ppi->present[p - ppi->start]) + continue; + if (!provider_satisfies_requirement(p, ppi->pool, + flags, version)) + continue; + + razor_package_iterator_init_for_property(&pkg_iter, set, p); + while (razor_package_iterator_next(&pkg_iter, + &pkg, &n, &v, &a)) { + fprintf(stderr, "removing %s-%s\n", n, v); + razor_transaction_remove_package(trans, pkg); + } + } +} + +static void +flag_matching_providers(struct razor_transaction *trans, + struct prop_iter *ppi, + struct razor_property *r, + struct prop_iter *rpi, + unsigned int flag) +{ + struct razor_property *p; + struct razor_package *pkg, *pkgs; + struct razor_package_iterator pkg_iter; + struct razor_set *set; + const char *name, *version, *arch; + uint32_t *flags, type; + + if (ppi->present == trans->system.properties) { + set = trans->system.set; + flags = trans->system.packages; + } else { + set = trans->upstream.set; + flags = trans->upstream.packages; + } + + pkgs = (struct razor_package *) set->packages.data; + type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; + for (p = ppi->p; + p < ppi->end && + p->name == ppi->p->name && + (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type; + p++) { + if (!ppi->present[p - ppi->start]) + continue; + if (!provider_satisfies_requirement(p, ppi->pool, + r->flags, + &rpi->pool[r->version])) + continue; + + razor_package_iterator_init_for_property(&pkg_iter, set, p); + while (razor_package_iterator_next(&pkg_iter, &pkg, + &name, &version, &arch)) { + + fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n", + name, version, + ppi->pool + p->name, + rpi->pool + r->name, + rpi->pool + r->version); + flags[pkg - pkgs] |= flag; + } + } +} + +static struct razor_package * +pick_matching_provider(struct razor_set *set, + struct prop_iter *ppi, + uint32_t flags, + const char *version) +{ + struct razor_property *p; + struct razor_package *pkgs; + struct list *i; + uint32_t type; + + /* This is where we decide which pkgs to pull in to satisfy a + * requirement. There may be several different providers + * (different versions) and each version of a provider may + * come from a number of packages. We pick the first package + * from the first provider that matches. */ + + pkgs = set->packages.data; + type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; + for (p = ppi->p; + p < ppi->end && + p->name == ppi->p->name && + (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type && + ppi->present[p - ppi->start] == 0; + p++) { + if (!provider_satisfies_requirement(p, ppi->pool, + flags, version)) + continue; + + i = list_first(&p->packages, &set->package_pool); + + return &pkgs[i->data]; + } + + return NULL; +} + +static void +remove_obsoleted_packages(struct razor_transaction *trans) +{ + struct razor_property *up; + struct razor_package *spkgs; + struct prop_iter spi, upi; + + spkgs = trans->system.set->packages.data; + prop_iter_init(&spi, &trans->system); + prop_iter_init(&upi, &trans->upstream); + + while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) { + if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, + &upi.pool[up->name])) + continue; + remove_matching_providers(trans, &spi, up->flags, + &upi.pool[up->version]); + } +} + +static int +any_provider_satisfies_requirement(struct prop_iter *ppi, + uint32_t flags, + const char *version) +{ + struct razor_property *p; + uint32_t type; + + type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; + for (p = ppi->p; + p < ppi->end && + p->name == ppi->p->name && + (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type; + p++) { + if (ppi->present[p - ppi->start] > 0 && + provider_satisfies_requirement(p, ppi->pool, + flags, version)) + return 1; + } + + return 0; +} + +static void +clear_requires_flags(struct transaction_set *ts) +{ + struct razor_property *p; + const char *pool; + int i, count; + + count = ts->set->properties.size / sizeof *p; + p = ts->set->properties.data; + pool = ts->set->string_pool.data; + for (i = 0; i < count; i++) { + ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED; + if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0) + ts->properties[i] |= TRANS_PROPERTY_SATISFIED; + } +} + +const char * +razor_property_relation_to_string(struct razor_property *p) +{ + switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) { + case RAZOR_PROPERTY_LESS: + return "<"; + + case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL: + return "<="; + + case RAZOR_PROPERTY_EQUAL: + return "="; + + case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL: + return ">="; + + case RAZOR_PROPERTY_GREATER: + return ">"; + + default: + return "?"; + } +} + +const char * +razor_property_type_to_string(struct razor_property *p) +{ + switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) { + case RAZOR_PROPERTY_REQUIRES: + return "requires"; + case RAZOR_PROPERTY_PROVIDES: + return "provides"; + case RAZOR_PROPERTY_CONFLICTS: + return "conflicts"; + case RAZOR_PROPERTY_OBSOLETES: + return "obsoletes"; + default: + return NULL; + } +} + +static void +mark_satisfied_requires(struct razor_transaction *trans, + struct transaction_set *rts, + struct transaction_set *pts) +{ + struct prop_iter rpi, ppi; + struct razor_property *rp; + + prop_iter_init(&rpi, rts); + prop_iter_init(&ppi, pts); + + while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { + if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, + &rpi.pool[rp->name])) + continue; + + if (any_provider_satisfies_requirement(&ppi, rp->flags, + &rpi.pool[rp->version])) + rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED; + } +} + +static void +mark_all_satisfied_requires(struct razor_transaction *trans) +{ + clear_requires_flags(&trans->system); + clear_requires_flags(&trans->upstream); + mark_satisfied_requires(trans, &trans->system, &trans->system); + mark_satisfied_requires(trans, &trans->system, &trans->upstream); + mark_satisfied_requires(trans, &trans->upstream, &trans->system); + mark_satisfied_requires(trans, &trans->upstream, &trans->upstream); +} + +static void +update_unsatisfied_packages(struct razor_transaction *trans) +{ + struct razor_package *spkgs, *pkg; + struct razor_property *sp; + struct prop_iter spi; + struct razor_package_iterator pkg_iter; + const char *name, *version, *arch; + + spkgs = trans->system.set->packages.data; + prop_iter_init(&spi, &trans->system); + + while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) { + if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED) + continue; + + razor_package_iterator_init_for_property(&pkg_iter, + trans->system.set, + sp); + while (razor_package_iterator_next(&pkg_iter, &pkg, + &name, &version, &arch)) { + fprintf(stderr, "updating %s because %s %s %s " + "isn't satisfied\n", + name, spi.pool + sp->name, + razor_property_relation_to_string(sp), + spi.pool + sp->version); + trans->system.packages[pkg - spkgs] |= + TRANS_PACKAGE_UPDATE; + } + } +} + +void +razor_transaction_update_all(struct razor_transaction *trans) +{ + struct razor_package *p; + int i, count; + + count = trans->system.set->packages.size / sizeof *p; + for (i = 0; i < count; i++) + trans->system.packages[i] |= TRANS_PACKAGE_UPDATE; +} + +static void +update_conflicted_packages(struct razor_transaction *trans) +{ + struct razor_package *pkg, *spkgs; + struct razor_property *up, *sp; + struct prop_iter spi, upi; + struct razor_package_iterator pkg_iter; + const char *name, *version, *arch; + + spkgs = trans->system.set->packages.data; + prop_iter_init(&spi, &trans->system); + prop_iter_init(&upi, &trans->upstream); + + while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) { + if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES, + &spi.pool[sp->name])) + continue; + + if (!any_provider_satisfies_requirement(&upi, sp->flags, + &spi.pool[sp->version])) + continue; + + razor_package_iterator_init_for_property(&pkg_iter, + trans->system.set, + sp); + while (razor_package_iterator_next(&pkg_iter, &pkg, + &name, &version, &arch)) { + fprintf(stderr, "updating %s %s because it conflicts with %s", + name, version, spi.pool + sp->name); + trans->system.packages[pkg - spkgs] |= + TRANS_PACKAGE_UPDATE; + } + } + + prop_iter_init(&spi, &trans->system); + prop_iter_init(&upi, &trans->upstream); + + while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) { + sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, + &upi.pool[upi.p->name]); + + if (sp) + flag_matching_providers(trans, &spi, up, &upi, + TRANS_PACKAGE_UPDATE); + } +} + +static void +pull_in_requirements(struct razor_transaction *trans, + struct prop_iter *rpi, struct prop_iter *ppi) +{ + struct razor_property *rp, *pp; + struct razor_package *pkg, *upkgs; + + upkgs = trans->upstream.set->packages.data; + while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { + if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED) + continue; + + pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES, + &rpi->pool[rp->name]); + if (pp == NULL) + continue; + pkg = pick_matching_provider(trans->upstream.set, + ppi, rp->flags, + &rpi->pool[rp->version]); + if (pkg == NULL) + continue; + + rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED; + + fprintf(stderr, "pulling in %s which provides %s %s %s " + "to satisfy %s %s %s\n", + ppi->pool + pkg->name, + ppi->pool + pp->name, + razor_property_relation_to_string(pp), + ppi->pool + pp->version, + &rpi->pool[rp->name], + razor_property_relation_to_string(rp), + &rpi->pool[rp->version]); + + trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE; + } +} + +static void +pull_in_all_requirements(struct razor_transaction *trans) +{ + struct prop_iter rpi, ppi; + + prop_iter_init(&rpi, &trans->system); + prop_iter_init(&ppi, &trans->upstream); + pull_in_requirements(trans, &rpi, &ppi); + + prop_iter_init(&rpi, &trans->upstream); + prop_iter_init(&ppi, &trans->upstream); + pull_in_requirements(trans, &rpi, &ppi); +} + +static void +flush_scheduled_system_updates(struct razor_transaction *trans) +{ + struct razor_package_iterator *pi; + struct razor_package *p, *pkg, *spkgs; + struct prop_iter ppi; + const char *name, *version, *arch; + + spkgs = trans->system.set->packages.data; + pi = razor_package_iterator_create(trans->system.set); + prop_iter_init(&ppi, &trans->upstream); + + while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { + if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE)) + continue; + + if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name)) + continue; + + pkg = pick_matching_provider(trans->upstream.set, &ppi, + RAZOR_PROPERTY_GREATER, version); + if (pkg == NULL) + continue; + + fprintf(stderr, "updating %s-%s to %s-%s\n", + name, version, + &ppi.pool[pkg->name], &ppi.pool[pkg->version]); + + razor_transaction_remove_package(trans, p); + razor_transaction_install_package(trans, pkg); + } + + razor_package_iterator_destroy(pi); +} + +static void +flush_scheduled_upstream_updates(struct razor_transaction *trans) +{ + struct razor_package_iterator *pi; + struct razor_package *p, *upkgs; + struct prop_iter spi; + const char *name, *version, *arch; + + upkgs = trans->upstream.set->packages.data; + pi = razor_package_iterator_create(trans->upstream.set); + prop_iter_init(&spi, &trans->system); + + while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { + if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE)) + continue; + + if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name)) + remove_matching_providers(trans, + &spi, + RAZOR_PROPERTY_LESS, + version); + razor_transaction_install_package(trans, p); + fprintf(stderr, "installing %s-%s\n", name, version); + } +} + +int +razor_transaction_resolve(struct razor_transaction *trans) +{ + int last = 0; + + flush_scheduled_system_updates(trans); + flush_scheduled_upstream_updates(trans); + + while (last < trans->changes) { + last = trans->changes; + remove_obsoleted_packages(trans); + mark_all_satisfied_requires(trans); + update_unsatisfied_packages(trans); + update_conflicted_packages(trans); + pull_in_all_requirements(trans); + flush_scheduled_system_updates(trans); + flush_scheduled_upstream_updates(trans); + } + + return trans->changes; +} + +static void +describe_unsatisfied(struct razor_set *set, struct razor_property *rp) +{ + struct razor_package_iterator pi; + struct razor_package *pkg; + const char *name, *version, *arch, *pool; + + pool = set->string_pool.data; + if (pool[rp->version] == '\0') { + razor_package_iterator_init_for_property(&pi, set, rp); + while (razor_package_iterator_next(&pi, &pkg, + &name, &version, &arch)) + fprintf(stderr, "%s is needed by %s-%s.%s\n", + &pool[rp->name], + name, version, arch); + } else { + razor_package_iterator_init_for_property(&pi, set, rp); + while (razor_package_iterator_next(&pi, &pkg, + &name, &version, &arch)) + fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n", + &pool[rp->name], + razor_property_relation_to_string(rp), + &pool[rp->version], + name, version, arch); + } +} + +int +razor_transaction_describe(struct razor_transaction *trans) +{ + struct prop_iter rpi; + struct razor_property *rp; + int unsatisfied; + + flush_scheduled_system_updates(trans); + flush_scheduled_upstream_updates(trans); + mark_all_satisfied_requires(trans); + + unsatisfied = 0; + prop_iter_init(&rpi, &trans->system); + while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { + if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) { + describe_unsatisfied(trans->system.set, rp); + unsatisfied++; + } + } + + prop_iter_init(&rpi, &trans->upstream); + while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { + if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) { + describe_unsatisfied(trans->upstream.set, rp); + unsatisfied++; + } + } + + return unsatisfied; +} + +int +razor_transaction_unsatisfied_property(struct razor_transaction *trans, + const char *name, + uint32_t flags, + const char *version) +{ + struct prop_iter pi; + struct razor_property *p; + + prop_iter_init(&pi, &trans->system); + while (prop_iter_next(&pi, flags, &p)) { + if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) && + p->flags == flags && + strcmp(&pi.pool[p->name], name) == 0 && + strcmp(&pi.pool[p->version], version) == 0) + + return 1; + } + + prop_iter_init(&pi, &trans->upstream); + while (prop_iter_next(&pi, flags, &p)) { + if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) && + p->flags == flags && + strcmp(&pi.pool[p->name], name) == 0 && + strcmp(&pi.pool[p->version], version) == 0) + + return 1; + } + + return 0; +} + +struct razor_set * +razor_transaction_finish(struct razor_transaction *trans) +{ + struct razor_merger *merger; + struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs; + char *upool, *spool; + int cmp; + + s = trans->system.set->packages.data; + spkgs = trans->system.set->packages.data; + send = trans->system.set->packages.data + + trans->system.set->packages.size; + spool = trans->system.set->string_pool.data; + + u = trans->upstream.set->packages.data; + upkgs = trans->upstream.set->packages.data; + uend = trans->upstream.set->packages.data + + trans->upstream.set->packages.size; + upool = trans->upstream.set->string_pool.data; + + merger = razor_merger_create(trans->system.set, trans->upstream.set); + while (s < send || u < uend) { + if (s < send && u < uend) + cmp = strcmp(&spool[s->name], &upool[u->name]); + else if (s < send) + cmp = -1; + else + cmp = 1; + + if (cmp < 0) { + if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT) + razor_merger_add_package(merger, s); + s++; + } else if (cmp == 0) { + if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT) + razor_merger_add_package(merger, s); + if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT) + razor_merger_add_package(merger, u); + + s++; + u++; + } else { + if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT) + razor_merger_add_package(merger, u); + u++; + } + } + + razor_transaction_destroy(trans); + + return razor_merger_finish(merger); +} + +void +razor_transaction_destroy(struct razor_transaction *trans) +{ + transaction_set_release(&trans->system); + transaction_set_release(&trans->upstream); + free(trans); +} diff --git a/librazor/types.c b/librazor/types.c index adb5b89..1dc9aef 100644 --- a/librazor/types.c +++ b/librazor/types.c @@ -1,7 +1,7 @@ #include <stdlib.h> #include <string.h> -#include "types.h" +#include "razor-internal.h" void array_init(struct array *array) diff --git a/librazor/types.h b/librazor/types.h deleted file mode 100644 index 6e36754..0000000 --- a/librazor/types.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _RAZOR_TYPES_H_ -#define _RAZOR_TYPES_H_ - -#include <stdint.h> - -struct array { - void *data; - int size, alloc; -}; - -void array_init(struct array *array); -void array_release(struct array *array); -void *array_add(struct array *array, int size); - - -struct list_head { - uint list_ptr : 24; - uint flags : 8; -}; - -struct list { - uint data : 24; - uint flags : 8; -}; - -void list_set_empty(struct list_head *head); -void list_set_ptr(struct list_head *head, uint32_t ptr); -void list_set_array(struct list_head *head, struct array *pool, struct array *items, int force_indirect); - -struct list *list_first(struct list_head *head, struct array *pool); -struct list *list_next(struct list *list); - -void list_remap_pool(struct array *pool, uint32_t *map); -void list_remap_head(struct list_head *list, uint32_t *map); - - -struct hashtable { - struct array buckets; - struct array *pool; -}; - -void hashtable_init(struct hashtable *table, struct array *pool); -void hashtable_release(struct hashtable *table); -uint32_t hashtable_insert(struct hashtable *table, const char *key); -uint32_t hashtable_lookup(struct hashtable *table, const char *key); -uint32_t hashtable_tokenize(struct hashtable *table, const char *string); - - -struct bitarray { - uint32_t *bits; -}; - -void bitarray_init(struct bitarray *bitarray, int size, int intial_value); -void bitarray_release(struct bitarray *bitarray); -void bitarray_set(struct bitarray *bitarray, int bit, int value); -int bitarray_get(struct bitarray *bitarray, int bit); - - -#endif /* _RAZOR_TYPES_H_ */ |