rhughes@241: /* rhughes@241: * Copyright (C) 2008 Kristian Høgsberg rhughes@241: * Copyright (C) 2008 Red Hat, Inc rhughes@241: * rhughes@241: * This program is free software; you can redistribute it and/or modify rhughes@241: * it under the terms of the GNU General Public License as published by rhughes@241: * the Free Software Foundation; either version 2 of the License, or rhughes@241: * (at your option) any later version. rhughes@241: * rhughes@241: * This program is distributed in the hope that it will be useful, rhughes@241: * but WITHOUT ANY WARRANTY; without even the implied warranty of rhughes@241: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the rhughes@241: * GNU General Public License for more details. rhughes@241: * rhughes@241: * You should have received a copy of the GNU General Public License along rhughes@241: * with this program; if not, write to the Free Software Foundation, Inc., rhughes@241: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. rhughes@241: */ rhughes@241: rhughes@241: #define _GNU_SOURCE rhughes@241: rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: rhughes@241: #include "razor.h" rhughes@241: #include "razor-internal.h" rhughes@241: #include "types.h" rhughes@241: rhughes@241: struct razor_set_section { rhughes@241: uint32_t type; rhughes@241: uint32_t offset; rhughes@241: uint32_t size; rhughes@241: }; rhughes@241: rhughes@241: struct razor_set_header { rhughes@241: uint32_t magic; rhughes@241: uint32_t version; rhughes@241: struct razor_set_section sections[0]; rhughes@241: }; rhughes@241: rhughes@241: #define RAZOR_MAGIC 0x7a7a7a7a rhughes@241: #define RAZOR_VERSION 1 rhughes@241: rhughes@241: #define RAZOR_STRING_POOL 0 rhughes@241: #define RAZOR_PACKAGES 1 rhughes@241: #define RAZOR_PROPERTIES 2 rhughes@241: #define RAZOR_FILES 3 rhughes@241: #define RAZOR_PACKAGE_POOL 4 rhughes@241: #define RAZOR_PROPERTY_POOL 5 rhughes@241: #define RAZOR_FILE_POOL 6 rhughes@241: rhughes@241: struct razor_package { rhughes@241: uint name : 24; rhughes@241: uint flags : 8; rhughes@241: uint32_t version; rhughes@241: uint32_t arch; rhughes@241: struct list_head properties; rhughes@241: struct list_head files; rhughes@241: }; rhughes@241: rhughes@241: struct razor_property { rhughes@241: uint name : 24; rhughes@241: uint flags : 6; rhughes@241: enum razor_property_type type : 2; rhughes@241: enum razor_version_relation relation : 32; rhughes@241: uint32_t version; rhughes@241: struct list_head packages; rhughes@241: }; rhughes@241: rhughes@241: struct razor_entry { rhughes@241: uint name : 24; rhughes@241: uint flags : 8; rhughes@241: uint32_t start; rhughes@241: struct list_head packages; rhughes@241: }; rhughes@241: rhughes@241: #define RAZOR_ENTRY_LAST 0x80 rhughes@241: rhughes@241: struct razor_set { rhughes@241: struct array string_pool; rhughes@241: struct array packages; rhughes@241: struct array properties; rhughes@241: struct array files; rhughes@241: struct array package_pool; rhughes@241: struct array property_pool; rhughes@241: struct array file_pool; rhughes@241: struct razor_set_header *header; rhughes@241: }; rhughes@241: rhughes@241: struct import_entry { rhughes@241: uint32_t package; rhughes@241: char *name; rhughes@241: }; rhughes@241: rhughes@241: struct import_directory { rhughes@241: uint32_t name, count; rhughes@241: struct array files; rhughes@241: struct array packages; rhughes@241: struct import_directory *last; rhughes@241: }; rhughes@241: rhughes@241: struct razor_importer { rhughes@241: struct razor_set *set; rhughes@241: struct hashtable table; rhughes@241: struct razor_package *package; rhughes@241: struct array properties; rhughes@241: struct array files; rhughes@241: struct array file_requires; rhughes@241: }; rhughes@241: rhughes@241: static void * rhughes@241: zalloc(size_t size) rhughes@241: { rhughes@241: void *p; rhughes@241: rhughes@241: p = malloc(size); rhughes@241: memset(p, 0, size); rhughes@241: rhughes@241: return p; rhughes@241: } rhughes@241: rhughes@241: struct razor_set_section razor_sections[] = { rhughes@241: { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) }, rhughes@241: { RAZOR_PACKAGES, offsetof(struct razor_set, packages) }, rhughes@241: { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) }, rhughes@241: { RAZOR_FILES, offsetof(struct razor_set, files) }, rhughes@241: { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) }, rhughes@241: { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) }, rhughes@241: { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) }, rhughes@241: }; rhughes@241: rhughes@241: struct razor_set * rhughes@241: razor_set_create(void) rhughes@241: { rhughes@241: struct razor_set *set; rhughes@241: struct razor_entry *e; rhughes@241: char *empty; rhughes@241: rhughes@241: set = zalloc(sizeof *set); rhughes@241: rhughes@241: e = array_add(&set->files, sizeof *e); rhughes@241: empty = array_add(&set->string_pool, 1); rhughes@241: *empty = '\0'; rhughes@241: e->name = 0; rhughes@241: e->flags = RAZOR_ENTRY_LAST; rhughes@241: e->start = 0; rhughes@241: list_set_empty(&e->packages); rhughes@241: rhughes@241: return set; rhughes@241: } rhughes@241: rhughes@241: struct razor_set * rhughes@241: razor_set_open(const char *filename) rhughes@241: { rhughes@241: struct razor_set *set; rhughes@241: struct razor_set_section *s; rhughes@241: struct stat stat; rhughes@241: struct array *array; rhughes@241: int fd; rhughes@241: rhughes@241: set = zalloc(sizeof *set); rhughes@241: fd = open(filename, O_RDONLY); rhughes@241: if (fstat(fd, &stat) < 0) rhughes@241: return NULL; rhughes@241: set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); rhughes@241: if (set->header == MAP_FAILED) { rhughes@241: free(set); rhughes@241: return NULL; rhughes@241: } rhughes@241: rhughes@241: for (s = set->header->sections; ~s->type; s++) { rhughes@241: if (s->type >= ARRAY_SIZE(razor_sections)) rhughes@241: continue; rhughes@241: if (s->type != razor_sections[s->type].type) rhughes@241: continue; rhughes@241: array = (void *) set + razor_sections[s->type].offset; rhughes@241: array->data = (void *) set->header + s->offset; rhughes@241: array->size = s->size; rhughes@241: array->alloc = s->size; rhughes@241: } rhughes@241: close(fd); rhughes@241: rhughes@241: return set; rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_set_destroy(struct razor_set *set) rhughes@241: { rhughes@241: unsigned int size; rhughes@241: struct array *a; rhughes@241: int i; rhughes@241: rhughes@241: if (set->header) { rhughes@241: for (i = 0; set->header->sections[i].type; i++) rhughes@241: ; rhughes@241: size = set->header->sections[i].type; rhughes@241: munmap(set->header, size); rhughes@241: } else { rhughes@241: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { rhughes@241: a = (void *) set + razor_sections[i].offset; rhughes@241: free(a->data); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: free(set); rhughes@241: } rhughes@241: rhughes@241: int rhughes@241: razor_set_write_to_fd(struct razor_set *set, int fd) rhughes@241: { rhughes@241: char data[4096]; rhughes@241: struct razor_set_header *header = (struct razor_set_header *) data; rhughes@241: struct array *a; rhughes@241: uint32_t offset; rhughes@241: int i; rhughes@241: rhughes@241: memset(data, 0, sizeof data); rhughes@241: header->magic = RAZOR_MAGIC; rhughes@241: header->version = RAZOR_VERSION; rhughes@241: offset = sizeof data; rhughes@241: rhughes@241: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { rhughes@241: if (razor_sections[i].type != i) rhughes@241: continue; rhughes@241: a = (void *) set + razor_sections[i].offset; rhughes@241: header->sections[i].type = i; rhughes@241: header->sections[i].offset = offset; rhughes@241: header->sections[i].size = a->size; rhughes@241: offset += ALIGN(a->size, 4096); rhughes@241: } rhughes@241: rhughes@241: header->sections[i].type = ~0; rhughes@241: header->sections[i].offset = 0; rhughes@241: header->sections[i].size = 0; rhughes@241: rhughes@241: razor_write(fd, data, sizeof data); rhughes@241: memset(data, 0, sizeof data); rhughes@241: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { rhughes@241: if (razor_sections[i].type != i) rhughes@241: continue; rhughes@241: a = (void *) set + razor_sections[i].offset; rhughes@241: razor_write(fd, a->data, a->size); rhughes@241: razor_write(fd, data, ALIGN(a->size, 4096) - a->size); rhughes@241: } rhughes@241: rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: int rhughes@241: razor_set_write(struct razor_set *set, const char *filename) rhughes@241: { rhughes@241: int fd, status; rhughes@241: rhughes@241: fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); rhughes@241: if (fd < 0) rhughes@241: return -1; rhughes@241: rhughes@241: status = razor_set_write_to_fd(set, fd); rhughes@241: if (status) { rhughes@241: close(fd); rhughes@241: return status; rhughes@241: } rhughes@241: rhughes@241: return close(fd); rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_build_evr(char *evr_buf, int size, const char *epoch, rhughes@241: const char *version, const char *release) rhughes@241: { rhughes@241: int len; rhughes@241: rhughes@241: if (!version || !*version) { rhughes@241: *evr_buf = '\0'; rhughes@241: return; rhughes@241: } rhughes@241: rhughes@241: if (epoch && *epoch && strcmp(epoch, "0") != 0) { rhughes@241: len = snprintf(evr_buf, size, "%s:", epoch); rhughes@241: evr_buf += len; rhughes@241: size -= len; rhughes@241: } rhughes@241: len = snprintf(evr_buf, size, "%s", version); rhughes@241: evr_buf += len; rhughes@241: size -= len; rhughes@241: if (release && *release) rhughes@241: snprintf(evr_buf, size, "-%s", release); rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_importer_begin_package(struct razor_importer *importer, rhughes@241: const char *name, rhughes@241: const char *version, rhughes@241: const char *arch) rhughes@241: { rhughes@241: struct razor_package *p; rhughes@241: rhughes@241: p = array_add(&importer->set->packages, sizeof *p); rhughes@241: p->name = hashtable_tokenize(&importer->table, name); rhughes@241: p->flags = 0; rhughes@241: p->version = hashtable_tokenize(&importer->table, version); rhughes@241: p->arch = hashtable_tokenize(&importer->table, arch); rhughes@241: rhughes@241: importer->package = p; rhughes@241: array_init(&importer->properties); rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_importer_finish_package(struct razor_importer *importer) rhughes@241: { rhughes@241: list_set_array(&importer->package->properties, rhughes@241: &importer->set->property_pool, rhughes@241: &importer->properties, rhughes@241: 1); rhughes@241: rhughes@241: array_release(&importer->properties); rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_importer_add_property(struct razor_importer *importer, rhughes@241: const char *name, rhughes@241: enum razor_version_relation relation, rhughes@241: const char *version, rhughes@241: enum razor_property_type type) rhughes@241: { rhughes@241: struct razor_property *p; rhughes@241: uint32_t *r; rhughes@241: rhughes@241: p = array_add(&importer->set->properties, sizeof *p); rhughes@241: p->name = hashtable_tokenize(&importer->table, name); rhughes@241: p->flags = 0; rhughes@241: p->type = type; rhughes@241: p->relation = relation; rhughes@241: p->version = hashtable_tokenize(&importer->table, version); rhughes@241: list_set_ptr(&p->packages, importer->package - rhughes@241: (struct razor_package *) importer->set->packages.data); rhughes@241: rhughes@241: r = array_add(&importer->properties, sizeof *r); rhughes@241: *r = p - (struct razor_property *) importer->set->properties.data; rhughes@241: rhughes@241: if (type == RAZOR_PROPERTY_REQUIRES && *name == '/') { rhughes@241: r = array_add(&importer->file_requires, sizeof *r); rhughes@241: *r = p->name; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_importer_add_file(struct razor_importer *importer, const char *name) rhughes@241: { rhughes@241: struct import_entry *e; rhughes@241: rhughes@241: e = array_add(&importer->files, sizeof *e); rhughes@241: rhughes@241: e->package = importer->package - rhughes@241: (struct razor_package *) importer->set->packages.data; rhughes@241: e->name = strdup(name); rhughes@241: } rhughes@241: rhughes@241: struct razor_importer * rhughes@241: razor_importer_new(void) rhughes@241: { rhughes@241: struct razor_importer *importer; rhughes@241: rhughes@241: importer = zalloc(sizeof *importer); rhughes@241: importer->set = razor_set_create(); rhughes@241: hashtable_init(&importer->table, &importer->set->string_pool); rhughes@241: rhughes@241: return importer; rhughes@241: } rhughes@241: rhughes@241: /* Destroy an importer without creating the set. */ rhughes@241: void rhughes@241: razor_importer_destroy(struct razor_importer *importer) rhughes@241: { rhughes@241: /* FIXME: write this */ rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: versioncmp(const char *s1, const char *s2) rhughes@241: { rhughes@241: const char *p1, *p2; rhughes@241: long n1, n2; rhughes@241: int res; rhughes@241: rhughes@241: n1 = strtol(s1, (char **) &p1, 10); rhughes@241: n2 = strtol(s2, (char **) &p2, 10); rhughes@241: rhughes@241: /* Epoch; if one but not the other has an epoch set, default rhughes@241: * the epoch-less version to 0. */ rhughes@241: res = (*p1 == ':') - (*p2 == ':'); rhughes@241: if (res < 0) { rhughes@241: n1 = 0; rhughes@241: p1 = s1; rhughes@241: p2++; rhughes@241: } else if (res > 0) { rhughes@241: p1++; rhughes@241: n2 = 0; rhughes@241: p2 = s2; rhughes@241: } rhughes@241: rhughes@241: if (n1 != n2) rhughes@241: return n1 - n2; rhughes@241: while (*p1 && *p2) { rhughes@241: if (*p1 != *p2) rhughes@241: return *p1 - *p2; rhughes@241: p1++; rhughes@241: p2++; rhughes@241: if (isdigit(*p1) && isdigit(*p2)) rhughes@241: return versioncmp(p1, p2); rhughes@241: } rhughes@241: rhughes@241: return *p1 - *p2; rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: compare_packages(const void *p1, const void *p2, void *data) rhughes@241: { rhughes@241: const struct razor_package *pkg1 = p1, *pkg2 = p2; rhughes@241: struct razor_set *set = data; rhughes@241: char *pool = set->string_pool.data; rhughes@241: rhughes@241: /* FIXME: what if the flags are different? */ rhughes@241: if (pkg1->name == pkg2->name) rhughes@241: return versioncmp(&pool[pkg1->version], &pool[pkg2->version]); rhughes@241: else rhughes@241: return strcmp(&pool[pkg1->name], &pool[pkg2->name]); rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: compare_properties(const void *p1, const void *p2, void *data) rhughes@241: { rhughes@241: const struct razor_property *prop1 = p1, *prop2 = p2; rhughes@241: struct razor_set *set = data; rhughes@241: char *pool = set->string_pool.data; rhughes@241: rhughes@241: if (prop1->name != prop2->name) rhughes@241: return strcmp(&pool[prop1->name], &pool[prop2->name]); rhughes@241: else if (prop1->type != prop2->type) rhughes@241: return prop1->type - prop2->type; rhughes@241: else if (prop1->relation != prop2->relation) rhughes@241: return prop1->relation - prop2->relation; rhughes@241: else rhughes@241: return versioncmp(&pool[prop1->version], &pool[prop2->version]); rhughes@241: } rhughes@241: rhughes@241: static uint32_t * rhughes@241: uniqueify_properties(struct razor_set *set) rhughes@241: { rhughes@241: struct razor_property *rp, *up, *rp_end; rhughes@241: struct array *pkgs, *p; rhughes@241: struct list_head *r; rhughes@241: uint32_t *map, *rmap; rhughes@241: int i, count, unique; rhughes@241: rhughes@241: count = set->properties.size / sizeof(struct razor_property); rhughes@241: map = razor_qsort_with_data(set->properties.data, rhughes@241: count, rhughes@241: sizeof(struct razor_property), rhughes@241: compare_properties, rhughes@241: set); rhughes@241: rhughes@241: rp_end = set->properties.data + set->properties.size; rhughes@241: rmap = malloc(count * sizeof *map); rhughes@241: pkgs = zalloc(count * sizeof *pkgs); rhughes@241: for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) { rhughes@241: if (rp->name != up->name || rp->type != up->type || rhughes@241: rp->relation != up->relation || rp->version != up->version) { rhughes@241: up++; rhughes@241: up->name = rp->name; rhughes@241: up->flags = 0; rhughes@241: up->type = rp->type; rhughes@241: up->relation = rp->relation; rhughes@241: up->version = rp->version; rhughes@241: } rhughes@241: rhughes@241: unique = up - (struct razor_property *) set->properties.data; rhughes@241: rmap[map[i]] = unique; rhughes@241: r = array_add(&pkgs[unique], sizeof *r); rhughes@241: *r = rp->packages; rhughes@241: } rhughes@241: free(map); rhughes@241: rhughes@241: if (up != rp) rhughes@241: up++; rhughes@241: set->properties.size = (void *) up - set->properties.data; rhughes@241: rp_end = up; rhughes@241: for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) { rhughes@241: list_set_array(&rp->packages, &set->package_pool, p, 0); rhughes@241: array_release(p); rhughes@241: } rhughes@241: rhughes@241: free(pkgs); rhughes@241: rhughes@241: return rmap; rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: compare_filenames(const void *p1, const void *p2, void *data) rhughes@241: { rhughes@241: const struct import_entry *e1 = p1; rhughes@241: const struct import_entry *e2 = p2; rhughes@241: const char *n1 = e1->name; rhughes@241: const char *n2 = e2->name; rhughes@241: rhughes@241: /* Need to make sure that the contents of a directory rhughes@241: * are sorted immediately after it. So "foo/bar" has to rhughes@241: * sort before "foo.conf" rhughes@241: * rhughes@241: * FIXME: this is about 60% slower than strcmp rhughes@241: */ rhughes@241: while (*n1 && *n2) { rhughes@241: if (*n1 < *n2) rhughes@241: return *n2 == '/' ? 1 : -1; rhughes@241: else if (*n1 > *n2) rhughes@241: return *n1 == '/' ? -1 : 1; rhughes@241: n1++; rhughes@241: n2++; rhughes@241: } rhughes@241: if (*n1) rhughes@241: return 1; rhughes@241: else if (*n2) rhughes@241: return -1; rhughes@241: else rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: count_entries(struct import_directory *d) rhughes@241: { rhughes@241: struct import_directory *p, *end; rhughes@241: rhughes@241: p = d->files.data; rhughes@241: end = d->files.data + d->files.size; rhughes@241: d->count = 0; rhughes@241: while (p < end) { rhughes@241: count_entries(p); rhughes@241: d->count += p->count + 1; rhughes@241: p++; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: serialize_files(struct razor_set *set, rhughes@241: struct import_directory *d, struct array *array) rhughes@241: { rhughes@241: struct import_directory *p, *end; rhughes@241: struct razor_entry *e = NULL; rhughes@241: uint32_t s; rhughes@241: rhughes@241: p = d->files.data; rhughes@241: end = d->files.data + d->files.size; rhughes@241: s = array->size / sizeof *e + d->files.size / sizeof *p; rhughes@241: while (p < end) { rhughes@241: e = array_add(array, sizeof *e); rhughes@241: e->name = p->name; rhughes@241: e->flags = 0; rhughes@241: e->start = p->count > 0 ? s : 0; rhughes@241: s += p->count; rhughes@241: rhughes@241: list_set_array(&e->packages, &set->package_pool, &p->packages, 0); rhughes@241: array_release(&p->packages); rhughes@241: p++; rhughes@241: } rhughes@241: if (e != NULL) rhughes@241: e->flags |= RAZOR_ENTRY_LAST; rhughes@241: rhughes@241: p = d->files.data; rhughes@241: end = d->files.data + d->files.size; rhughes@241: while (p < end) { rhughes@241: serialize_files(set, p, array); rhughes@241: p++; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: remap_property_package_links(struct array *properties, uint32_t *rmap) rhughes@241: { rhughes@241: struct razor_property *p, *end; rhughes@241: rhughes@241: end = properties->data + properties->size; rhughes@241: for (p = properties->data; p < end; p++) rhughes@241: list_remap_head(&p->packages, rmap); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: build_file_tree(struct razor_importer *importer) rhughes@241: { rhughes@241: int count, i, length; rhughes@241: struct import_entry *filenames; rhughes@241: char *f, *end; rhughes@241: uint32_t name, *r; rhughes@241: char dirname[256]; rhughes@241: struct import_directory *d, root; rhughes@241: struct razor_entry *e; rhughes@241: rhughes@241: count = importer->files.size / sizeof (struct import_entry); rhughes@241: razor_qsort_with_data(importer->files.data, rhughes@241: count, rhughes@241: sizeof (struct import_entry), rhughes@241: compare_filenames, rhughes@241: NULL); rhughes@241: rhughes@241: root.name = hashtable_tokenize(&importer->table, ""); rhughes@241: array_init(&root.files); rhughes@241: array_init(&root.packages); rhughes@241: root.last = NULL; rhughes@241: rhughes@241: filenames = importer->files.data; rhughes@241: for (i = 0; i < count; i++) { rhughes@241: f = filenames[i].name; rhughes@241: if (*f != '/') rhughes@241: continue; rhughes@241: f++; rhughes@241: rhughes@241: d = &root; rhughes@241: while (*f) { rhughes@241: end = strchr(f, '/'); rhughes@241: if (end == NULL) rhughes@241: end = f + strlen(f); rhughes@241: length = end - f; rhughes@241: memcpy(dirname, f, length); rhughes@241: dirname[length] ='\0'; rhughes@241: name = hashtable_tokenize(&importer->table, dirname); rhughes@241: if (d->last == NULL || d->last->name != name) { rhughes@241: d->last = array_add(&d->files, sizeof *d); rhughes@241: d->last->name = name; rhughes@241: d->last->last = NULL; rhughes@241: array_init(&d->last->files); rhughes@241: array_init(&d->last->packages); rhughes@241: } rhughes@241: d = d->last; rhughes@241: f = end + 1; rhughes@241: if (*end == '\0') rhughes@241: break; rhughes@241: } rhughes@241: rhughes@241: r = array_add(&d->packages, sizeof *r); rhughes@241: *r = filenames[i].package; rhughes@241: free(filenames[i].name); rhughes@241: } rhughes@241: rhughes@241: count_entries(&root); rhughes@241: e = importer->set->files.data; rhughes@241: e->name = root.name; rhughes@241: e->flags = RAZOR_ENTRY_LAST; rhughes@241: e->start = importer->files.size ? 1 : 0; rhughes@241: list_set_empty(&e->packages); rhughes@241: rhughes@241: serialize_files(importer->set, &root, &importer->set->files); rhughes@241: rhughes@241: array_release(&importer->files); rhughes@241: } rhughes@241: rhughes@241: static struct razor_entry * rhughes@241: find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern); rhughes@241: rhughes@241: static void rhughes@241: list_to_array(struct list *list, struct array *array) rhughes@241: { rhughes@241: uint32_t *item; rhughes@241: rhughes@241: while (list) { rhughes@241: item = array_add(array, sizeof *item); rhughes@241: *item = list->data; rhughes@241: list = list_next(list); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: compare_file_requires(const void *p1, const void *p2, void *data) rhughes@241: { rhughes@241: uint32_t *f1 = (void *)p1, *f2 = (void *)p2; rhughes@241: const char *pool = data; rhughes@241: rhughes@241: return strcmp(&pool[*f1], &pool[*f2]); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: find_file_provides(struct razor_importer *importer) rhughes@241: { rhughes@241: struct razor_property *prop; rhughes@241: struct razor_entry *top, *entry; rhughes@241: struct razor_package *packages; rhughes@241: struct array pkgprops; rhughes@241: struct list *pkg; rhughes@241: uint32_t *req, *req_start, *req_end; rhughes@241: uint32_t *map, *newprop; rhughes@241: char *pool; rhughes@241: rhughes@241: pool = importer->set->string_pool.data; rhughes@241: packages = importer->set->packages.data; rhughes@241: top = importer->set->files.data; rhughes@241: rhughes@241: req = req_start = importer->file_requires.data; rhughes@241: req_end = importer->file_requires.data + importer->file_requires.size; rhughes@241: map = razor_qsort_with_data(req, req_end - req, sizeof *req, rhughes@241: compare_file_requires, pool); rhughes@241: free(map); rhughes@241: rhughes@241: for (req = req_start; req < req_end; req++) { rhughes@241: if (req > req_start && req[0] == req[-1]) rhughes@241: continue; rhughes@241: entry = find_entry(importer->set, top, &pool[*req]); rhughes@241: if (!entry) rhughes@241: continue; rhughes@241: rhughes@241: for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) { rhughes@241: prop = array_add(&importer->set->properties, sizeof *prop); rhughes@241: prop->name = *req; rhughes@241: prop->type = RAZOR_PROPERTY_PROVIDES; rhughes@241: prop->relation = RAZOR_VERSION_EQUAL; rhughes@241: prop->version = hashtable_tokenize(&importer->table, ""); rhughes@241: list_set_ptr(&prop->packages, pkg->data); rhughes@241: rhughes@241: /* Update property list of pkg */ rhughes@241: array_init(&pkgprops); rhughes@241: list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops); rhughes@241: newprop = array_add(&pkgprops, sizeof *newprop); rhughes@241: *newprop = prop - (struct razor_property *)importer->set->properties.data; rhughes@241: list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1); rhughes@241: array_release(&pkgprops); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: array_release(&importer->file_requires); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: build_package_file_lists(struct razor_set *set, uint32_t *rmap) rhughes@241: { rhughes@241: struct razor_package *p, *packages; rhughes@241: struct array *pkgs; rhughes@241: struct razor_entry *e, *end; rhughes@241: struct list *r; rhughes@241: uint32_t *q; rhughes@241: int i, count; rhughes@241: rhughes@241: count = set->packages.size / sizeof *p; rhughes@241: pkgs = zalloc(count * sizeof *pkgs); rhughes@241: rhughes@241: end = set->files.data + set->files.size; rhughes@241: for (e = set->files.data; e < end; e++) { rhughes@241: list_remap_head(&e->packages, rmap); rhughes@241: r = list_first(&e->packages, &set->package_pool); rhughes@241: while (r) { rhughes@241: q = array_add(&pkgs[r->data], sizeof *q); rhughes@241: *q = e - (struct razor_entry *) set->files.data; rhughes@241: r = list_next(r); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: packages = set->packages.data; rhughes@241: for (i = 0; i < count; i++) { rhughes@241: list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0); rhughes@241: array_release(&pkgs[i]); rhughes@241: } rhughes@241: free(pkgs); rhughes@241: } rhughes@241: rhughes@241: struct razor_set * rhughes@241: razor_importer_finish(struct razor_importer *importer) rhughes@241: { rhughes@241: struct razor_set *set; rhughes@241: uint32_t *map, *rmap; rhughes@241: int i, count; rhughes@241: rhughes@241: build_file_tree(importer); rhughes@241: find_file_provides(importer); rhughes@241: rhughes@241: map = uniqueify_properties(importer->set); rhughes@241: list_remap_pool(&importer->set->property_pool, map); rhughes@241: free(map); rhughes@241: rhughes@241: count = importer->set->packages.size / sizeof(struct razor_package); rhughes@241: map = razor_qsort_with_data(importer->set->packages.data, rhughes@241: count, rhughes@241: sizeof(struct razor_package), rhughes@241: compare_packages, rhughes@241: importer->set); rhughes@241: rhughes@241: rmap = malloc(count * sizeof *rmap); rhughes@241: for (i = 0; i < count; i++) rhughes@241: rmap[map[i]] = i; rhughes@241: free(map); rhughes@241: rhughes@241: list_remap_pool(&importer->set->package_pool, rmap); rhughes@241: build_package_file_lists(importer->set, rmap); rhughes@241: remap_property_package_links(&importer->set->properties, rmap); rhughes@241: free(rmap); rhughes@241: rhughes@241: set = importer->set; rhughes@241: hashtable_release(&importer->table); rhughes@241: free(importer); rhughes@241: rhughes@241: return set; rhughes@241: } rhughes@241: rhughes@241: struct razor_package_iterator { rhughes@241: struct razor_set *set; rhughes@241: struct razor_package *package, *end; rhughes@241: struct list *index; rhughes@241: int free_index; rhughes@241: }; rhughes@241: rhughes@241: static struct razor_package_iterator * rhughes@241: razor_package_iterator_create_with_index(struct razor_set *set, rhughes@241: struct list *index) rhughes@241: { rhughes@241: struct razor_package_iterator *pi; rhughes@241: rhughes@241: pi = zalloc(sizeof *pi); rhughes@241: pi->set = set; rhughes@241: pi->index = index; rhughes@241: rhughes@241: return pi; rhughes@241: } rhughes@241: rhughes@241: struct razor_package_iterator * rhughes@241: razor_package_iterator_create(struct razor_set *set) rhughes@241: { rhughes@241: struct razor_package_iterator *pi; rhughes@241: rhughes@241: pi = zalloc(sizeof *pi); rhughes@241: pi->set = set; rhughes@241: pi->end = set->packages.data + set->packages.size; rhughes@241: pi->package = set->packages.data; rhughes@241: rhughes@241: return pi; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: razor_package_iterator_init_for_property(struct razor_package_iterator *pi, rhughes@241: struct razor_set *set, rhughes@241: struct razor_property *property) rhughes@241: { rhughes@241: memset(pi, 0, sizeof *pi); rhughes@241: pi->set = set; rhughes@241: pi->index = list_first(&property->packages, &set->package_pool); rhughes@241: } rhughes@241: rhughes@241: struct razor_package_iterator * rhughes@241: razor_package_iterator_create_for_property(struct razor_set *set, rhughes@241: struct razor_property *property) rhughes@241: { rhughes@241: struct list *index; rhughes@241: rhughes@241: index = list_first(&property->packages, &set->package_pool); rhughes@241: return razor_package_iterator_create_with_index(set, index); rhughes@241: } rhughes@241: rhughes@241: int rhughes@241: razor_package_iterator_next(struct razor_package_iterator *pi, rhughes@241: struct razor_package **package, rhughes@241: const char **name, rhughes@241: const char **version, rhughes@241: const char **arch) rhughes@241: { rhughes@241: char *pool; rhughes@241: int valid; rhughes@241: struct razor_package *p, *packages; rhughes@241: rhughes@241: if (pi->package) { rhughes@241: p = pi->package++; rhughes@241: valid = p < pi->end; rhughes@241: } else if (pi->index) { rhughes@241: packages = pi->set->packages.data; rhughes@241: p = &packages[pi->index->data]; rhughes@241: pi->index = list_next(pi->index); rhughes@241: valid = 1; rhughes@241: } else rhughes@241: valid = 0; rhughes@241: rhughes@241: if (valid) { rhughes@241: pool = pi->set->string_pool.data; rhughes@241: *package = p; rhughes@241: *name = &pool[p->name]; rhughes@241: *version = &pool[p->version]; rhughes@241: *arch = &pool[p->arch]; rhughes@241: } else { rhughes@241: *package = NULL; rhughes@241: } rhughes@241: rhughes@241: return valid; rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_package_iterator_destroy(struct razor_package_iterator *pi) rhughes@241: { rhughes@241: if (pi->free_index) rhughes@241: free(pi->index); rhughes@241: rhughes@241: free(pi); rhughes@241: } rhughes@241: rhughes@241: struct razor_package * rhughes@241: razor_set_get_package(struct razor_set *set, const char *package) rhughes@241: { rhughes@241: struct razor_package_iterator *pi; rhughes@241: struct razor_package *p; rhughes@241: const char *name, *version, *arch; rhughes@241: rhughes@241: pi = razor_package_iterator_create(set); rhughes@241: while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { rhughes@241: if (strcmp(package, name) == 0) rhughes@241: break; rhughes@241: } rhughes@241: razor_package_iterator_destroy(pi); rhughes@241: rhughes@241: return p; rhughes@241: } rhughes@241: rhughes@241: struct razor_property_iterator { rhughes@241: struct razor_set *set; rhughes@241: struct razor_property *property, *end; rhughes@241: struct list *index; rhughes@241: }; rhughes@241: rhughes@241: struct razor_property_iterator * rhughes@241: razor_property_iterator_create(struct razor_set *set, rhughes@241: struct razor_package *package) rhughes@241: { rhughes@241: struct razor_property_iterator *pi; rhughes@241: rhughes@241: pi = zalloc(sizeof *pi); rhughes@241: pi->set = set; rhughes@241: rhughes@241: if (package) { rhughes@241: pi->index = list_first(&package->properties, rhughes@241: &set->property_pool); rhughes@241: } else { rhughes@241: pi->property = set->properties.data; rhughes@241: pi->end = set->properties.data + set->properties.size; rhughes@241: } rhughes@241: rhughes@241: return pi; rhughes@241: } rhughes@241: rhughes@241: int rhughes@241: razor_property_iterator_next(struct razor_property_iterator *pi, rhughes@241: struct razor_property **property, rhughes@241: const char **name, rhughes@241: enum razor_version_relation *relation, rhughes@241: const char **version, rhughes@241: enum razor_property_type *type) rhughes@241: { rhughes@241: char *pool; rhughes@241: int valid; rhughes@241: struct razor_property *p, *properties; rhughes@241: rhughes@241: if (pi->property) { rhughes@241: p = pi->property++; rhughes@241: valid = p < pi->end; rhughes@241: } else if (pi->index) { rhughes@241: properties = pi->set->properties.data; rhughes@241: p = &properties[pi->index->data]; rhughes@241: pi->index = list_next(pi->index); rhughes@241: valid = 1; rhughes@241: } else rhughes@241: valid = 0; rhughes@241: rhughes@241: if (valid) { rhughes@241: pool = pi->set->string_pool.data; rhughes@241: *property = p; rhughes@241: *name = &pool[p->name]; rhughes@241: *relation = p->relation; rhughes@241: *version = &pool[p->version]; rhughes@241: *type = p->type; rhughes@241: } else { rhughes@241: *property = NULL; rhughes@241: } rhughes@241: rhughes@241: return valid; rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_property_iterator_destroy(struct razor_property_iterator *pi) rhughes@241: { rhughes@241: free(pi); rhughes@241: } rhughes@241: rhughes@241: static struct razor_entry * rhughes@241: find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern) rhughes@241: { rhughes@241: struct razor_entry *e; rhughes@241: const char *n, *pool = set->string_pool.data; rhughes@241: int len; rhughes@241: rhughes@241: e = (struct razor_entry *) set->files.data + dir->start; rhughes@241: do { rhughes@241: n = pool + e->name; rhughes@241: if (strcmp(pattern + 1, n) == 0) rhughes@241: return e; rhughes@241: len = strlen(n); rhughes@241: if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 && rhughes@241: pattern[len + 1] == '/') { rhughes@241: return find_entry(set, e, pattern + len + 1); rhughes@241: } rhughes@241: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); rhughes@241: rhughes@241: return NULL; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: list_dir(struct razor_set *set, struct razor_entry *dir, rhughes@241: char *prefix, const char *pattern) rhughes@241: { rhughes@241: struct razor_entry *e; rhughes@241: const char *n, *pool = set->string_pool.data; rhughes@241: rhughes@241: e = (struct razor_entry *) set->files.data + dir->start; rhughes@241: do { rhughes@241: n = pool + e->name; rhughes@241: if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0) rhughes@241: continue; rhughes@241: printf("%s/%s\n", prefix, n); rhughes@241: if (e->start) { rhughes@241: char *sub = prefix + strlen (prefix); rhughes@241: *sub = '/'; rhughes@241: strcpy (sub + 1, n); rhughes@241: list_dir(set, e, prefix, pattern); rhughes@241: *sub = '\0'; rhughes@241: } rhughes@241: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_set_list_files(struct razor_set *set, const char *pattern) rhughes@241: { rhughes@241: struct razor_entry *e; rhughes@241: char buffer[512], *p, *base; rhughes@241: rhughes@241: if (pattern == NULL || !strcmp (pattern, "/")) { rhughes@241: buffer[0] = '\0'; rhughes@241: list_dir(set, set->files.data, buffer, NULL); rhughes@241: return; rhughes@241: } rhughes@241: rhughes@241: strcpy(buffer, pattern); rhughes@241: e = find_entry(set, set->files.data, buffer); rhughes@241: if (e && e->start > 0) { rhughes@241: base = NULL; rhughes@241: } else { rhughes@241: p = strrchr(buffer, '/'); rhughes@241: if (p) { rhughes@241: *p = '\0'; rhughes@241: base = p + 1; rhughes@241: } else { rhughes@241: base = NULL; rhughes@241: } rhughes@241: } rhughes@241: e = find_entry(set, set->files.data, buffer); rhughes@241: if (e->start != 0) rhughes@241: list_dir(set, e, buffer, base); rhughes@241: } rhughes@241: rhughes@241: struct razor_package_iterator * rhughes@241: razor_package_iterator_create_for_file(struct razor_set *set, rhughes@241: const char *filename) rhughes@241: { rhughes@241: struct razor_entry *entry; rhughes@241: struct list *index; rhughes@241: rhughes@241: entry = find_entry(set, set->files.data, filename); rhughes@241: if (entry == NULL) rhughes@241: return NULL; rhughes@241: rhughes@241: index = list_first(&entry->packages, &set->package_pool); rhughes@241: return razor_package_iterator_create_with_index(set, index); rhughes@241: } rhughes@241: rhughes@241: static struct list * rhughes@241: list_package_files(struct razor_set *set, struct list *r, rhughes@241: struct razor_entry *dir, uint32_t end, rhughes@241: char *prefix) rhughes@241: { rhughes@241: struct razor_entry *e, *f, *entries; rhughes@241: uint32_t next, file; rhughes@241: char *pool; rhughes@241: int len; rhughes@241: rhughes@241: entries = (struct razor_entry *) set->files.data; rhughes@241: pool = set->string_pool.data; rhughes@241: rhughes@241: e = entries + dir->start; rhughes@241: do { rhughes@241: if (entries + r->data == e) { rhughes@241: printf("%s/%s\n", prefix, pool + e->name); rhughes@241: r = list_next(r); rhughes@241: if (!r) rhughes@241: return NULL; rhughes@241: if (r->data >= end) rhughes@241: return r; rhughes@241: } rhughes@241: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); rhughes@241: rhughes@241: e = entries + dir->start; rhughes@241: do { rhughes@241: if (e->start == 0) rhughes@241: continue; rhughes@241: rhughes@241: if (e->flags & RAZOR_ENTRY_LAST) rhughes@241: next = end; rhughes@241: else { rhughes@241: f = e + 1; rhughes@241: while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST)) rhughes@241: f++; rhughes@241: if (f->start == 0) rhughes@241: next = end; rhughes@241: else rhughes@241: next = f->start; rhughes@241: } rhughes@241: rhughes@241: file = r->data; rhughes@241: if (e->start <= file && file < next) { rhughes@241: len = strlen(prefix); rhughes@241: prefix[len] = '/'; rhughes@241: strcpy(prefix + len + 1, pool + e->name); rhughes@241: r = list_package_files(set, r, e, next, prefix); rhughes@241: prefix[len] = '\0'; rhughes@241: } rhughes@241: } while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL); rhughes@241: rhughes@241: return r; rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_set_list_package_files(struct razor_set *set, const char *name) rhughes@241: { rhughes@241: struct razor_package *package; rhughes@241: struct list *r; rhughes@241: uint32_t end; rhughes@241: char buffer[512]; rhughes@241: rhughes@241: package = razor_set_get_package(set, name); rhughes@241: rhughes@241: r = list_first(&package->files, &set->file_pool); rhughes@241: end = set->files.size / sizeof (struct razor_entry); rhughes@241: buffer[0] = '\0'; rhughes@241: list_package_files(set, r, set->files.data, end, buffer); rhughes@241: } rhughes@241: rhughes@241: #define UPSTREAM_SOURCE 0x80 rhughes@241: rhughes@241: struct source { rhughes@241: struct razor_set *set; rhughes@241: uint32_t *property_map; rhughes@241: uint32_t *file_map; rhughes@241: }; rhughes@241: rhughes@241: struct razor_merger { rhughes@241: struct razor_set *set; rhughes@241: struct hashtable table; rhughes@241: struct source source1; rhughes@241: struct source source2; rhughes@241: }; rhughes@241: rhughes@241: static struct razor_merger * rhughes@241: razor_merger_create(struct razor_set *set1, struct razor_set *set2) rhughes@241: { rhughes@241: struct razor_merger *merger; rhughes@241: int count; rhughes@241: size_t size; rhughes@241: rhughes@241: merger = zalloc(sizeof *merger); rhughes@241: merger->set = razor_set_create(); rhughes@241: hashtable_init(&merger->table, &merger->set->string_pool); rhughes@241: rhughes@241: merger->source1.set = set1; rhughes@241: count = set1->properties.size / sizeof (struct razor_property); rhughes@241: size = count * sizeof merger->source1.property_map[0]; rhughes@241: merger->source1.property_map = zalloc(size); rhughes@241: count = set1->files.size / sizeof (struct razor_entry); rhughes@241: size = count * sizeof merger->source1.file_map[0]; rhughes@241: merger->source1.file_map = zalloc(size); rhughes@241: rhughes@241: merger->source2.set = set2; rhughes@241: count = set2->properties.size / sizeof (struct razor_property); rhughes@241: size = count * sizeof merger->source2.property_map[0]; rhughes@241: merger->source2.property_map = zalloc(size); rhughes@241: count = set2->files.size / sizeof (struct razor_entry); rhughes@241: size = count * sizeof merger->source2.file_map[0]; rhughes@241: merger->source2.file_map = zalloc(size); rhughes@241: rhughes@241: return merger; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: razor_merger_add_package(struct razor_merger *merger, rhughes@241: struct razor_package *package) rhughes@241: { rhughes@241: char *pool; rhughes@241: struct list *r; rhughes@241: struct razor_package *p; rhughes@241: struct razor_set *set1; rhughes@241: struct source *source; rhughes@241: uint32_t flags; rhughes@241: rhughes@241: set1 = merger->source1.set; rhughes@241: if (set1->packages.data <= (void *) package && rhughes@241: (void *) package < set1->packages.data + set1->packages.size) { rhughes@241: source = &merger->source1; rhughes@241: flags = 0; rhughes@241: } else { rhughes@241: source = &merger->source2; rhughes@241: flags = UPSTREAM_SOURCE; rhughes@241: } rhughes@241: rhughes@241: pool = source->set->string_pool.data; rhughes@241: p = array_add(&merger->set->packages, sizeof *p); rhughes@241: p->name = hashtable_tokenize(&merger->table, &pool[package->name]); rhughes@241: p->flags = flags; rhughes@241: p->version = hashtable_tokenize(&merger->table, rhughes@241: &pool[package->version]); rhughes@241: p->arch = hashtable_tokenize(&merger->table, rhughes@241: &pool[package->arch]); rhughes@241: rhughes@241: p->properties = package->properties; rhughes@241: r = list_first(&package->properties, &source->set->property_pool); rhughes@241: while (r) { rhughes@241: source->property_map[r->data] = 1; rhughes@241: r = list_next(r); rhughes@241: } rhughes@241: rhughes@241: p->files = package->files; rhughes@241: r = list_first(&package->files, &source->set->file_pool); rhughes@241: while (r) { rhughes@241: source->file_map[r->data] = 1; rhughes@241: r = list_next(r); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static uint32_t rhughes@241: add_property(struct razor_merger *merger, rhughes@241: const char *name, enum razor_version_relation relation, rhughes@241: const char *version, int type) rhughes@241: { rhughes@241: struct razor_property *p; rhughes@241: rhughes@241: p = array_add(&merger->set->properties, sizeof *p); rhughes@241: p->name = hashtable_tokenize(&merger->table, name); rhughes@241: p->flags = 0; rhughes@241: p->type = type; rhughes@241: p->relation = relation; rhughes@241: p->version = hashtable_tokenize(&merger->table, version); rhughes@241: rhughes@241: return p - (struct razor_property *) merger->set->properties.data; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: merge_properties(struct razor_merger *merger) rhughes@241: { rhughes@241: struct razor_property *p1, *p2; rhughes@241: struct razor_set *set1, *set2; rhughes@241: uint32_t *map1, *map2; rhughes@241: int i, j, cmp, count1, count2; rhughes@241: char *pool1, *pool2; rhughes@241: rhughes@241: set1 = merger->source1.set; rhughes@241: set2 = merger->source2.set; rhughes@241: map1 = merger->source1.property_map; rhughes@241: map2 = merger->source2.property_map; rhughes@241: rhughes@241: i = 0; rhughes@241: j = 0; rhughes@241: pool1 = set1->string_pool.data; rhughes@241: pool2 = set2->string_pool.data; rhughes@241: rhughes@241: count1 = set1->properties.size / sizeof *p1; rhughes@241: count2 = set2->properties.size / sizeof *p2; rhughes@241: while (i < count1 || j < count2) { rhughes@241: if (i < count1 && map1[i] == 0) { rhughes@241: i++; rhughes@241: continue; rhughes@241: } rhughes@241: if (j < count2 && map2[j] == 0) { rhughes@241: j++; rhughes@241: continue; rhughes@241: } rhughes@241: p1 = (struct razor_property *) set1->properties.data + i; rhughes@241: p2 = (struct razor_property *) set2->properties.data + j; rhughes@241: if (i < count1 && j < count2) rhughes@241: cmp = strcmp(&pool1[p1->name], &pool2[p2->name]); rhughes@241: else if (i < count1) rhughes@241: cmp = -1; rhughes@241: else rhughes@241: cmp = 1; rhughes@241: if (cmp == 0) rhughes@241: cmp = p1->type - p2->type; rhughes@241: if (cmp == 0) rhughes@241: cmp = p1->relation - p2->relation; rhughes@241: if (cmp == 0) rhughes@241: cmp = versioncmp(&pool1[p1->version], rhughes@241: &pool2[p2->version]); rhughes@241: if (cmp < 0) { rhughes@241: map1[i++] = add_property(merger, rhughes@241: &pool1[p1->name], rhughes@241: p1->relation, rhughes@241: &pool1[p1->version], rhughes@241: p1->type); rhughes@241: } else if (cmp > 0) { rhughes@241: map2[j++] = add_property(merger, rhughes@241: &pool2[p2->name], rhughes@241: p2->relation, rhughes@241: &pool2[p2->version], rhughes@241: p2->type); rhughes@241: } else { rhughes@241: map1[i++] = map2[j++] = add_property(merger, rhughes@241: &pool1[p1->name], rhughes@241: p1->relation, rhughes@241: &pool1[p1->version], rhughes@241: p1->type); rhughes@241: } rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: emit_properties(struct list_head *properties, struct array *source_pool, rhughes@241: uint32_t *map, struct array *pool) rhughes@241: { rhughes@241: uint32_t r; rhughes@241: struct list *p, *q; rhughes@241: rhughes@241: r = pool->size / sizeof *q; rhughes@241: p = list_first(properties, source_pool); rhughes@241: while (p) { rhughes@241: q = array_add(pool, sizeof *q); rhughes@241: q->data = map[p->data]; rhughes@241: q->flags = p->flags; rhughes@241: p = list_next(p); rhughes@241: } rhughes@241: rhughes@241: list_set_ptr(properties, r); rhughes@241: } rhughes@241: rhughes@241: static uint32_t rhughes@241: add_file(struct razor_merger *merger, const char *name) rhughes@241: { rhughes@241: struct razor_entry *e; rhughes@241: rhughes@241: e = array_add(&merger->set->files, sizeof *e); rhughes@241: e->name = hashtable_tokenize(&merger->table, name); rhughes@241: e->flags = 0; rhughes@241: e->start = 0; rhughes@241: rhughes@241: return e - (struct razor_entry *)merger->set->files.data; rhughes@241: } rhughes@241: rhughes@241: /* FIXME. Blah */ rhughes@241: static int rhughes@241: fix_file_map(uint32_t *map, rhughes@241: struct razor_entry *files, rhughes@241: struct razor_entry *top) rhughes@241: { rhughes@241: uint32_t e; rhughes@241: int found_file = 0; rhughes@241: rhughes@241: e = top->start; rhughes@241: do { rhughes@241: if (files[e].start) rhughes@241: fix_file_map(map, files, &files[e]); rhughes@241: if (map[e]) rhughes@241: found_file = 1; rhughes@241: } while (!(files[e++].flags & RAZOR_ENTRY_LAST)); rhughes@241: rhughes@241: if (found_file) rhughes@241: map[top - files] = 1; rhughes@241: return found_file; rhughes@241: } rhughes@241: rhughes@241: struct merge_directory { rhughes@241: uint32_t merged, dir1, dir2; rhughes@241: }; rhughes@241: rhughes@241: static void rhughes@241: merge_one_directory(struct razor_merger *merger, struct merge_directory *md) rhughes@241: { rhughes@241: struct razor_entry *root1, *root2, *mroot, *e1, *e2; rhughes@241: struct razor_set *set1, *set2; rhughes@241: struct array merge_stack; rhughes@241: struct merge_directory *child_md, *end_md; rhughes@241: uint32_t *map1, *map2, start, last; rhughes@241: int cmp; rhughes@241: char *pool1, *pool2; rhughes@241: rhughes@241: set1 = merger->source1.set; rhughes@241: set2 = merger->source2.set; rhughes@241: map1 = merger->source1.file_map; rhughes@241: map2 = merger->source2.file_map; rhughes@241: pool1 = set1->string_pool.data; rhughes@241: pool2 = set2->string_pool.data; rhughes@241: root1 = (struct razor_entry *) set1->files.data; rhughes@241: root2 = (struct razor_entry *) set2->files.data; rhughes@241: rhughes@241: array_init(&merge_stack); rhughes@241: rhughes@241: start = merger->set->files.size / sizeof (struct razor_entry); rhughes@241: last = 0; rhughes@241: e1 = md->dir1 ? root1 + md->dir1 : NULL; rhughes@241: e2 = md->dir2 ? root2 + md->dir2 : NULL; rhughes@241: while (e1 || e2) { rhughes@241: if (!e2 && !map1[e1 - root1]) { rhughes@241: if ((e1++)->flags & RAZOR_ENTRY_LAST) rhughes@241: e1 = NULL; rhughes@241: continue; rhughes@241: } rhughes@241: if (!e1 && !map2[e2 - root2]) { rhughes@241: if ((e2++)->flags & RAZOR_ENTRY_LAST) rhughes@241: e2 = NULL; rhughes@241: continue; rhughes@241: } rhughes@241: if (e1 && !map1[e1 - root1] && rhughes@241: e2 && !map1[e2 - root2]) { rhughes@241: if ((e1++)->flags & RAZOR_ENTRY_LAST) rhughes@241: e1 = NULL; rhughes@241: if ((e2++)->flags & RAZOR_ENTRY_LAST) rhughes@241: e2 = NULL; rhughes@241: continue; rhughes@241: } rhughes@241: rhughes@241: if (!e1) rhughes@241: cmp = 1; rhughes@241: else if (!e2) rhughes@241: cmp = -1; rhughes@241: else { rhughes@241: cmp = strcmp (&pool1[e1->name], rhughes@241: &pool2[e2->name]); rhughes@241: } rhughes@241: rhughes@241: if (cmp < 0) { rhughes@241: if (map1[e1 - root1]) { rhughes@241: map1[e1 - root1] = last = rhughes@241: add_file(merger, &pool1[e1->name]); rhughes@241: if (e1->start) { rhughes@241: child_md = array_add(&merge_stack, sizeof (struct merge_directory)); rhughes@241: child_md->merged = last; rhughes@241: child_md->dir1 = e1->start; rhughes@241: child_md->dir2 = 0; rhughes@241: } rhughes@241: } rhughes@241: if ((e1++)->flags & RAZOR_ENTRY_LAST) rhughes@241: e1 = NULL; rhughes@241: } else if (cmp > 0) { rhughes@241: if (map2[e2 - root2]) { rhughes@241: map2[e2 - root2] = last = rhughes@241: add_file(merger, &pool2[e2->name]); rhughes@241: if (e2->start) { rhughes@241: child_md = array_add(&merge_stack, sizeof (struct merge_directory)); rhughes@241: child_md->merged = last; rhughes@241: child_md->dir1 = 0; rhughes@241: child_md->dir2 = e2->start; rhughes@241: } rhughes@241: } rhughes@241: if ((e2++)->flags & RAZOR_ENTRY_LAST) rhughes@241: e2 = NULL; rhughes@241: } else { rhughes@241: map1[e1 - root1] = map2[e2- root2] = last = rhughes@241: add_file(merger, &pool1[e1->name]); rhughes@241: if (e1->start || e2->start) { rhughes@241: child_md = array_add(&merge_stack, sizeof (struct merge_directory)); rhughes@241: child_md->merged = last; rhughes@241: child_md->dir1 = e1->start; rhughes@241: child_md->dir2 = e2->start; rhughes@241: } rhughes@241: if ((e1++)->flags & RAZOR_ENTRY_LAST) rhughes@241: e1 = NULL; rhughes@241: if ((e2++)->flags & RAZOR_ENTRY_LAST) rhughes@241: e2 = NULL; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: mroot = (struct razor_entry *)merger->set->files.data; rhughes@241: if (last) { rhughes@241: mroot[last].flags = RAZOR_ENTRY_LAST; rhughes@241: mroot[md->merged].start = start; rhughes@241: } else rhughes@241: mroot[md->merged].start = 0; rhughes@241: rhughes@241: end_md = merge_stack.data + merge_stack.size; rhughes@241: for (child_md = merge_stack.data; child_md < end_md; child_md++) rhughes@241: merge_one_directory(merger, child_md); rhughes@241: array_release(&merge_stack); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: merge_files(struct razor_merger *merger) rhughes@241: { rhughes@241: struct razor_entry *root; rhughes@241: struct merge_directory md; rhughes@241: uint32_t *map1, *map2; rhughes@241: rhughes@241: map1 = merger->source1.file_map; rhughes@241: map2 = merger->source2.file_map; rhughes@241: rhughes@241: md.merged = 0; rhughes@241: rhughes@241: if (merger->source1.set->files.size) { rhughes@241: root = (struct razor_entry *) merger->source1.set->files.data; rhughes@241: if (root->start) rhughes@241: fix_file_map(map1, root, root); rhughes@241: md.dir1 = root->start; rhughes@241: } else rhughes@241: md.dir1 = 0; rhughes@241: rhughes@241: if (merger->source2.set->files.size) { rhughes@241: root = (struct razor_entry *) merger->source2.set->files.data; rhughes@241: if (root->start) rhughes@241: fix_file_map(map2, root, root); rhughes@241: md.dir2 = root->start; rhughes@241: } else rhughes@241: md.dir2 = 0; rhughes@241: rhughes@241: merge_one_directory(merger, &md); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: emit_files(struct list_head *files, struct array *source_pool, rhughes@241: uint32_t *map, struct array *pool) rhughes@241: { rhughes@241: uint32_t r; rhughes@241: struct list *p, *q; rhughes@241: rhughes@241: r = pool->size / sizeof *q; rhughes@241: p = list_first(files, source_pool); rhughes@241: while (p) { rhughes@241: q = array_add(pool, sizeof *q); rhughes@241: q->data = map[p->data]; rhughes@241: q->flags = p->flags; rhughes@241: p = list_next(p); rhughes@241: } rhughes@241: rhughes@241: list_set_ptr(files, r); rhughes@241: } rhughes@241: rhughes@241: /* Rebuild property->packages maps. We can't just remap these, as a rhughes@241: * property may have lost or gained a number of packages. Allocate an rhughes@241: * array per property and loop through the packages and add them to rhughes@241: * the arrays for their properties. */ rhughes@241: static void rhughes@241: rebuild_property_package_lists(struct razor_set *set) rhughes@241: { rhughes@241: struct array *pkgs, *a; rhughes@241: struct razor_package *pkg, *pkg_end; rhughes@241: struct razor_property *prop, *prop_end; rhughes@241: struct list *r; rhughes@241: uint32_t *q; rhughes@241: int count; rhughes@241: rhughes@241: count = set->properties.size / sizeof (struct razor_property); rhughes@241: pkgs = zalloc(count * sizeof *pkgs); rhughes@241: pkg_end = set->packages.data + set->packages.size; rhughes@241: rhughes@241: for (pkg = set->packages.data; pkg < pkg_end; pkg++) { rhughes@241: r = list_first(&pkg->properties, &set->property_pool); rhughes@241: while (r) { rhughes@241: q = array_add(&pkgs[r->data], sizeof *q); rhughes@241: *q = pkg - (struct razor_package *) set->packages.data; rhughes@241: r = list_next(r); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: prop_end = set->properties.data + set->properties.size; rhughes@241: a = pkgs; rhughes@241: for (prop = set->properties.data; prop < prop_end; prop++, a++) { rhughes@241: list_set_array(&prop->packages, &set->package_pool, a, 0); rhughes@241: array_release(a); rhughes@241: } rhughes@241: free(pkgs); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: rebuild_file_package_lists(struct razor_set *set) rhughes@241: { rhughes@241: struct array *pkgs, *a; rhughes@241: struct razor_package *pkg, *pkg_end; rhughes@241: struct razor_entry *entry, *entry_end; rhughes@241: struct list *r; rhughes@241: uint32_t *q; rhughes@241: int count; rhughes@241: rhughes@241: count = set->files.size / sizeof (struct razor_entry); rhughes@241: pkgs = zalloc(count * sizeof *pkgs); rhughes@241: pkg_end = set->packages.data + set->packages.size; rhughes@241: rhughes@241: for (pkg = set->packages.data; pkg < pkg_end; pkg++) { rhughes@241: r = list_first(&pkg->files, &set->file_pool); rhughes@241: while (r) { rhughes@241: q = array_add(&pkgs[r->data], sizeof *q); rhughes@241: *q = pkg - (struct razor_package *) set->packages.data; rhughes@241: r = list_next(r); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: entry_end = set->files.data + set->files.size; rhughes@241: a = pkgs; rhughes@241: for (entry = set->files.data; entry < entry_end; entry++, a++) { rhughes@241: list_set_array(&entry->packages, &set->package_pool, a, 0); rhughes@241: array_release(a); rhughes@241: } rhughes@241: free(pkgs); rhughes@241: } rhughes@241: rhughes@241: static struct razor_set * rhughes@241: razor_merger_finish(struct razor_merger *merger) rhughes@241: { rhughes@241: struct razor_set *result; rhughes@241: struct razor_package *p, *pend; rhughes@241: rhughes@241: /* As we built the package list, we filled out a bitvector of rhughes@241: * the properties that are referenced by the packages in the rhughes@241: * new set. Now we do a parallel loop through the properties rhughes@241: * and emit those marked in the bit vector to the new set. In rhughes@241: * the process, we update the bit vector to actually map from rhughes@241: * indices in the old property list to indices in the new rhughes@241: * property list for both sets. */ rhughes@241: rhughes@241: merge_properties(merger); rhughes@241: merge_files(merger); rhughes@241: rhughes@241: /* Now we loop through the packages again and emit the rhughes@241: * property lists, remapped to point to the new properties. */ rhughes@241: rhughes@241: pend = merger->set->packages.data + merger->set->packages.size; rhughes@241: for (p = merger->set->packages.data; p < pend; p++) { rhughes@241: struct source *src; rhughes@241: rhughes@241: if (p->flags & UPSTREAM_SOURCE) rhughes@241: src = &merger->source2; rhughes@241: else rhughes@241: src = &merger->source1; rhughes@241: rhughes@241: emit_properties(&p->properties, rhughes@241: &src->set->property_pool, rhughes@241: src->property_map, rhughes@241: &merger->set->property_pool); rhughes@241: emit_files(&p->files, rhughes@241: &src->set->file_pool, rhughes@241: src->file_map, rhughes@241: &merger->set->file_pool); rhughes@241: p->flags &= ~UPSTREAM_SOURCE; rhughes@241: } rhughes@241: rhughes@241: rebuild_property_package_lists(merger->set); rhughes@241: rebuild_file_package_lists(merger->set); rhughes@241: rhughes@241: result = merger->set; rhughes@241: hashtable_release(&merger->table); rhughes@241: free(merger); rhughes@241: rhughes@241: return result; rhughes@241: } rhughes@241: rhughes@241: /* The diff order matters. We should sort the packages so that a rhughes@241: * REMOVE of a package comes before the INSTALL, and so that all rhughes@241: * requires for a package have been installed before the package. rhughes@241: **/ rhughes@241: rhughes@241: void rhughes@241: razor_set_diff(struct razor_set *set, struct razor_set *upstream, rhughes@241: razor_package_callback_t callback, void *data) rhughes@241: { rhughes@241: struct razor_package_iterator *pi1, *pi2; rhughes@241: struct razor_package *p1, *p2; rhughes@241: const char *name1, *name2, *version1, *version2, *arch1, *arch2; rhughes@241: int res; rhughes@241: rhughes@241: pi1 = razor_package_iterator_create(set); rhughes@241: pi2 = razor_package_iterator_create(upstream); rhughes@241: rhughes@241: razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1); rhughes@241: razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2); rhughes@241: rhughes@241: while (p1 || p2) { rhughes@241: if (p1 && p2) { rhughes@241: res = strcmp(name1, name2); rhughes@241: if (res == 0) rhughes@241: res = versioncmp(version1, version2); rhughes@241: } else { rhughes@241: res = 0; rhughes@241: } rhughes@241: rhughes@241: if (p2 == NULL || res < 0) rhughes@241: callback(name1, version1, NULL, arch1, data); rhughes@241: else if (p1 == NULL || res > 0) rhughes@241: callback(name2, NULL, version2, arch2, data); rhughes@241: rhughes@241: if (p1 != NULL && res <= 0) rhughes@241: razor_package_iterator_next(pi1, &p1, rhughes@241: &name1, &version1, &arch1); rhughes@241: if (p2 != NULL && res >= 0) rhughes@241: razor_package_iterator_next(pi2, &p2, rhughes@241: &name2, &version2, &arch2); rhughes@241: } rhughes@241: rhughes@241: razor_package_iterator_destroy(pi1); rhughes@241: razor_package_iterator_destroy(pi2); rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: provider_satisfies_requirement(struct razor_property *provider, rhughes@241: const char *provider_strings, rhughes@241: enum razor_version_relation relation, rhughes@241: const char *required) rhughes@241: { rhughes@241: int cmp, len; rhughes@241: const char *provided = &provider_strings[provider->version]; rhughes@241: rhughes@241: if (!*required) rhughes@241: return 1; rhughes@241: if (!*provided) { rhughes@241: if (relation >= RAZOR_VERSION_EQUAL) rhughes@241: return 1; rhughes@241: else rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: cmp = versioncmp(provided, required); rhughes@241: rhughes@241: switch (relation) { rhughes@241: case RAZOR_VERSION_LESS: rhughes@241: return cmp < 0; rhughes@241: rhughes@241: case RAZOR_VERSION_LESS_OR_EQUAL: rhughes@241: if (cmp <= 0) rhughes@241: return 1; rhughes@241: /* fall through: FIXME, make sure this is correct */ rhughes@241: rhughes@241: case RAZOR_VERSION_EQUAL: rhughes@241: if (cmp == 0) rhughes@241: return 1; rhughes@241: rhughes@241: /* "foo == 1.1" is satisfied by "foo 1.1-2" */ rhughes@241: len = strlen(required); rhughes@241: if (!strncmp(required, provided, len) && provided[len] == '-') rhughes@241: return 1; rhughes@241: return 0; rhughes@241: rhughes@241: case RAZOR_VERSION_GREATER_OR_EQUAL: rhughes@241: return cmp >= 0; rhughes@241: rhughes@241: case RAZOR_VERSION_GREATER: rhughes@241: return cmp > 0; rhughes@241: } rhughes@241: rhughes@241: /* shouldn't happen */ rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: #define TRANS_PACKAGE_PRESENT 1 rhughes@241: #define TRANS_PACKAGE_UPDATE 2 rhughes@241: #define TRANS_PROPERTY_SATISFIED 0x80000000 rhughes@241: rhughes@241: struct transaction_set { rhughes@241: struct razor_set *set; rhughes@241: uint32_t *packages; rhughes@241: uint32_t *properties; rhughes@241: }; rhughes@241: rhughes@241: struct razor_transaction { rhughes@241: int package_count, errors; rhughes@241: struct transaction_set system, upstream; rhughes@241: int changes; rhughes@241: }; rhughes@241: rhughes@241: static void rhughes@241: transaction_set_init(struct transaction_set *ts, struct razor_set *set) rhughes@241: { rhughes@241: int count; rhughes@241: rhughes@241: ts->set = set; rhughes@241: count = set->packages.size / sizeof (struct razor_package); rhughes@241: ts->packages = zalloc(count * sizeof *ts->packages); rhughes@241: count = set->properties.size / sizeof (struct razor_property); rhughes@241: ts->properties = zalloc(count * sizeof *ts->properties); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: transaction_set_release(struct transaction_set *ts) rhughes@241: { rhughes@241: free(ts->packages); rhughes@241: free(ts->properties); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: transaction_set_install_package(struct transaction_set *ts, rhughes@241: struct razor_package *package) rhughes@241: { rhughes@241: struct razor_package *pkgs; rhughes@241: struct list *prop; rhughes@241: int i; rhughes@241: rhughes@241: pkgs = ts->set->packages.data; rhughes@241: i = package - pkgs; rhughes@241: if (ts->packages[i] == TRANS_PACKAGE_PRESENT) rhughes@241: return; rhughes@241: rhughes@241: ts->packages[i] = TRANS_PACKAGE_PRESENT; rhughes@241: rhughes@241: prop = list_first(&package->properties, &ts->set->property_pool); rhughes@241: while (prop) { rhughes@241: ts->properties[prop->data]++; rhughes@241: prop = list_next(prop); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: transaction_set_remove_package(struct transaction_set *ts, rhughes@241: struct razor_package *package) rhughes@241: { rhughes@241: struct razor_package *pkgs; rhughes@241: struct list *prop; rhughes@241: int i; rhughes@241: rhughes@241: pkgs = ts->set->packages.data; rhughes@241: i = package - pkgs; rhughes@241: if (ts->packages[i] == 0) rhughes@241: return; rhughes@241: rhughes@241: ts->packages[i] = 0; rhughes@241: rhughes@241: prop = list_first(&package->properties, &ts->set->property_pool); rhughes@241: while (prop) { rhughes@241: ts->properties[prop->data]--; rhughes@241: prop = list_next(prop); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: struct razor_transaction * rhughes@241: razor_transaction_create(struct razor_set *system, struct razor_set *upstream) rhughes@241: { rhughes@241: struct razor_transaction *trans; rhughes@241: struct razor_package *p, *spkgs, *pend; rhughes@241: rhughes@241: trans = zalloc(sizeof *trans); rhughes@241: transaction_set_init(&trans->system, system); rhughes@241: transaction_set_init(&trans->upstream, upstream); rhughes@241: rhughes@241: spkgs = trans->system.set->packages.data; rhughes@241: pend = trans->system.set->packages.data + rhughes@241: trans->system.set->packages.size; rhughes@241: for (p = spkgs; p < pend; p++) rhughes@241: transaction_set_install_package(&trans->system, p); rhughes@241: rhughes@241: return trans; rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_transaction_install_package(struct razor_transaction *trans, rhughes@241: struct razor_package *package) rhughes@241: { rhughes@241: transaction_set_install_package(&trans->upstream, package); rhughes@241: trans->changes++; rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_transaction_remove_package(struct razor_transaction *trans, rhughes@241: struct razor_package *package) rhughes@241: { rhughes@241: transaction_set_remove_package(&trans->system, package); rhughes@241: trans->changes++; rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_transaction_update_package(struct razor_transaction *trans, rhughes@241: struct razor_package *package) rhughes@241: { rhughes@241: struct razor_package *spkgs, *upkgs, *end; rhughes@241: rhughes@241: spkgs = trans->system.set->packages.data; rhughes@241: upkgs = trans->upstream.set->packages.data; rhughes@241: end = trans->system.set->packages.data + rhughes@241: trans->system.set->packages.size; rhughes@241: if (spkgs <= package && package < end) rhughes@241: trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE; rhughes@241: else rhughes@241: trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE; rhughes@241: } rhughes@241: rhughes@241: struct prop_iter { rhughes@241: struct razor_property *p, *start, *end; rhughes@241: const char *pool; rhughes@241: uint32_t *present; rhughes@241: }; rhughes@241: rhughes@241: static void rhughes@241: prop_iter_init(struct prop_iter *pi, struct transaction_set *ts) rhughes@241: { rhughes@241: pi->p = ts->set->properties.data; rhughes@241: pi->start = ts->set->properties.data; rhughes@241: pi->end = ts->set->properties.data + ts->set->properties.size; rhughes@241: pi->pool = ts->set->string_pool.data; rhughes@241: pi->present = ts->properties; rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: prop_iter_next(struct prop_iter *pi, rhughes@241: enum razor_property_type type, struct razor_property **p) rhughes@241: { rhughes@241: while (pi->p < pi->end) { rhughes@241: if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) && rhughes@241: pi->p->type == type) { rhughes@241: *p = pi->p++; rhughes@241: return 1; rhughes@241: } rhughes@241: pi->p++; rhughes@241: } rhughes@241: rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: static struct razor_property * rhughes@241: prop_iter_seek_to(struct prop_iter *pi, rhughes@241: enum razor_property_type type, const char *match) rhughes@241: { rhughes@241: uint32_t name; rhughes@241: rhughes@241: while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0) rhughes@241: pi->p++; rhughes@241: rhughes@241: if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0) rhughes@241: return NULL; rhughes@241: rhughes@241: name = pi->p->name; rhughes@241: while (pi->p < pi->end && rhughes@241: pi->p->name == name && rhughes@241: pi->p->type != type) rhughes@241: pi->p++; rhughes@241: rhughes@241: if (pi->p == pi->end || pi->p->name != name) rhughes@241: return NULL; rhughes@241: rhughes@241: return pi->p; rhughes@241: } rhughes@241: rhughes@241: /* Remove packages from set that provide any of the matching (same rhughes@241: * name and type) providers from ppi onwards that match the rhughes@241: * requirement that rpi points to. */ rhughes@241: static void rhughes@241: remove_matching_providers(struct razor_transaction *trans, rhughes@241: struct prop_iter *ppi, rhughes@241: enum razor_version_relation relation, rhughes@241: const char *version) rhughes@241: { rhughes@241: struct razor_property *p; rhughes@241: struct razor_package *pkg, *pkgs; rhughes@241: struct razor_package_iterator pkg_iter; rhughes@241: struct razor_set *set; rhughes@241: const char *n, *v, *a; rhughes@241: rhughes@241: if (ppi->present == trans->system.properties) rhughes@241: set = trans->system.set; rhughes@241: else rhughes@241: set = trans->upstream.set; rhughes@241: rhughes@241: pkgs = (struct razor_package *) set->packages.data; rhughes@241: for (p = ppi->p; rhughes@241: p < ppi->end && rhughes@241: p->name == ppi->p->name && rhughes@241: p->type == ppi->p->type; rhughes@241: p++) { rhughes@241: if (!ppi->present[p - ppi->start]) rhughes@241: continue; rhughes@241: if (!provider_satisfies_requirement(p, ppi->pool, rhughes@241: relation, version)) rhughes@241: continue; rhughes@241: rhughes@241: razor_package_iterator_init_for_property(&pkg_iter, set, p); rhughes@241: while (razor_package_iterator_next(&pkg_iter, rhughes@241: &pkg, &n, &v, &a)) { rhughes@241: fprintf(stderr, "removing %s-%s\n", n, v); rhughes@241: razor_transaction_remove_package(trans, pkg); rhughes@241: } rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: flag_matching_providers(struct razor_transaction *trans, rhughes@241: struct prop_iter *ppi, rhughes@241: struct razor_property *r, rhughes@241: struct prop_iter *rpi, rhughes@241: unsigned int flag) rhughes@241: { rhughes@241: struct razor_property *p; rhughes@241: struct razor_package *pkg, *pkgs; rhughes@241: struct razor_package_iterator pkg_iter; rhughes@241: struct razor_set *set; rhughes@241: const char *name, *version, *arch; rhughes@241: uint32_t *flags; rhughes@241: rhughes@241: if (ppi->present == trans->system.properties) { rhughes@241: set = trans->system.set; rhughes@241: flags = trans->system.packages; rhughes@241: } else { rhughes@241: set = trans->upstream.set; rhughes@241: flags = trans->upstream.packages; rhughes@241: } rhughes@241: rhughes@241: pkgs = (struct razor_package *) set->packages.data; rhughes@241: for (p = ppi->p; rhughes@241: p < ppi->end && rhughes@241: p->name == ppi->p->name && rhughes@241: p->type == ppi->p->type; rhughes@241: p++) { rhughes@241: if (!ppi->present[p - ppi->start]) rhughes@241: continue; rhughes@241: if (!provider_satisfies_requirement(p, ppi->pool, rhughes@241: r->relation, rhughes@241: &rpi->pool[r->version])) rhughes@241: continue; rhughes@241: rhughes@241: razor_package_iterator_init_for_property(&pkg_iter, set, p); rhughes@241: while (razor_package_iterator_next(&pkg_iter, &pkg, rhughes@241: &name, &version, &arch)) { rhughes@241: rhughes@241: fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n", rhughes@241: name, version, rhughes@241: ppi->pool + p->name, rhughes@241: rpi->pool + r->name, rhughes@241: rpi->pool + r->version); rhughes@241: flags[pkg - pkgs] |= flag; rhughes@241: } rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static struct razor_package * rhughes@241: pick_matching_provider(struct razor_set *set, rhughes@241: struct prop_iter *ppi, rhughes@241: enum razor_version_relation relation, rhughes@241: const char *version) rhughes@241: { rhughes@241: struct razor_property *p; rhughes@241: struct razor_package *pkgs; rhughes@241: struct list *i; rhughes@241: rhughes@241: /* This is where we decide which pkgs to pull in to satisfy a rhughes@241: * requirement. There may be several different providers rhughes@241: * (different versions) and each version of a provider may rhughes@241: * come from a number of packages. We pick the first package rhughes@241: * from the first provider that matches. */ rhughes@241: rhughes@241: pkgs = set->packages.data; rhughes@241: for (p = ppi->p; rhughes@241: p < ppi->end && rhughes@241: p->name == ppi->p->name && rhughes@241: p->type == ppi->p->type && rhughes@241: ppi->present[p - ppi->start] == 0; rhughes@241: p++) { rhughes@241: if (!provider_satisfies_requirement(p, ppi->pool, rhughes@241: relation, version)) rhughes@241: continue; rhughes@241: rhughes@241: i = list_first(&p->packages, &set->package_pool); rhughes@241: rhughes@241: return &pkgs[i->data]; rhughes@241: } rhughes@241: rhughes@241: return NULL; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: remove_obsoleted_packages(struct razor_transaction *trans) rhughes@241: { rhughes@241: struct razor_property *up; rhughes@241: struct razor_package *spkgs; rhughes@241: struct prop_iter spi, upi; rhughes@241: rhughes@241: spkgs = trans->system.set->packages.data; rhughes@241: prop_iter_init(&spi, &trans->system); rhughes@241: prop_iter_init(&upi, &trans->upstream); rhughes@241: rhughes@241: while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) { rhughes@241: if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, rhughes@241: &upi.pool[up->name])) rhughes@241: continue; rhughes@241: remove_matching_providers(trans, &spi, up->relation, rhughes@241: &upi.pool[up->version]); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: any_provider_satisfies_requirement(struct prop_iter *ppi, rhughes@241: enum razor_version_relation relation, rhughes@241: const char *version) rhughes@241: { rhughes@241: struct razor_property *p; rhughes@241: rhughes@241: for (p = ppi->p; rhughes@241: p < ppi->end && rhughes@241: p->name == ppi->p->name && rhughes@241: p->type == ppi->p->type; rhughes@241: p++) { rhughes@241: if (ppi->present[p - ppi->start] > 0 && rhughes@241: provider_satisfies_requirement(p, ppi->pool, rhughes@241: relation, version)) rhughes@241: return 1; rhughes@241: } rhughes@241: rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: clear_requires_flags(struct transaction_set *ts) rhughes@241: { rhughes@241: struct razor_property *p; rhughes@241: const char *pool; rhughes@241: int i, count; rhughes@241: rhughes@241: count = ts->set->properties.size / sizeof *p; rhughes@241: p = ts->set->properties.data; rhughes@241: pool = ts->set->string_pool.data; rhughes@241: for (i = 0; i < count; i++) { rhughes@241: ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED; rhughes@241: if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0) rhughes@241: ts->properties[i] |= TRANS_PROPERTY_SATISFIED; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static const char *relation_string[] = { "<", "<=", "=", ">=", ">" }; rhughes@241: rhughes@241: static void rhughes@241: mark_satisfied_requires(struct razor_transaction *trans, rhughes@241: struct transaction_set *rts, rhughes@241: struct transaction_set *pts) rhughes@241: { rhughes@241: struct prop_iter rpi, ppi; rhughes@241: struct razor_property *rp; rhughes@241: rhughes@241: prop_iter_init(&rpi, rts); rhughes@241: prop_iter_init(&ppi, pts); rhughes@241: rhughes@241: while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { rhughes@241: if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, rhughes@241: &rpi.pool[rp->name])) rhughes@241: continue; rhughes@241: rhughes@241: if (any_provider_satisfies_requirement(&ppi, rp->relation, rhughes@241: &rpi.pool[rp->version])) rhughes@241: rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: mark_all_satisfied_requires(struct razor_transaction *trans) rhughes@241: { rhughes@241: clear_requires_flags(&trans->system); rhughes@241: clear_requires_flags(&trans->upstream); rhughes@241: mark_satisfied_requires(trans, &trans->system, &trans->system); rhughes@241: mark_satisfied_requires(trans, &trans->system, &trans->upstream); rhughes@241: mark_satisfied_requires(trans, &trans->upstream, &trans->system); rhughes@241: mark_satisfied_requires(trans, &trans->upstream, &trans->upstream); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: update_unsatisfied_packages(struct razor_transaction *trans) rhughes@241: { rhughes@241: struct razor_package *spkgs, *pkg; rhughes@241: struct razor_property *sp; rhughes@241: struct prop_iter spi; rhughes@241: struct razor_package_iterator pkg_iter; rhughes@241: const char *name, *version, *arch; rhughes@241: rhughes@241: spkgs = trans->system.set->packages.data; rhughes@241: prop_iter_init(&spi, &trans->system); rhughes@241: rhughes@241: while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) { rhughes@241: if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED) rhughes@241: continue; rhughes@241: rhughes@241: razor_package_iterator_init_for_property(&pkg_iter, rhughes@241: trans->system.set, rhughes@241: sp); rhughes@241: while (razor_package_iterator_next(&pkg_iter, &pkg, rhughes@241: &name, &version, &arch)) { rhughes@241: fprintf(stderr, "updating %s because %s %s %s " rhughes@241: "isn't satisfied\n", rhughes@241: name, spi.pool + sp->name, rhughes@241: relation_string[sp->relation], rhughes@241: spi.pool + sp->version); rhughes@241: trans->system.packages[pkg - spkgs] |= rhughes@241: TRANS_PACKAGE_UPDATE; rhughes@241: } rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_transaction_update_all(struct razor_transaction *trans) rhughes@241: { rhughes@241: struct razor_package *p; rhughes@241: int i, count; rhughes@241: rhughes@241: count = trans->system.set->packages.size / sizeof *p; rhughes@241: for (i = 0; i < count; i++) rhughes@241: trans->system.packages[i] |= TRANS_PACKAGE_UPDATE; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: update_conflicted_packages(struct razor_transaction *trans) rhughes@241: { rhughes@241: struct razor_package *pkg, *spkgs; rhughes@241: struct razor_property *up, *sp; rhughes@241: struct prop_iter spi, upi; rhughes@241: struct razor_package_iterator pkg_iter; rhughes@241: const char *name, *version, *arch; rhughes@241: rhughes@241: spkgs = trans->system.set->packages.data; rhughes@241: prop_iter_init(&spi, &trans->system); rhughes@241: prop_iter_init(&upi, &trans->upstream); rhughes@241: rhughes@241: while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) { rhughes@241: if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES, rhughes@241: &spi.pool[sp->name])) rhughes@241: continue; rhughes@241: rhughes@241: if (!any_provider_satisfies_requirement(&upi, sp->relation, rhughes@241: &spi.pool[sp->version])) rhughes@241: continue; rhughes@241: rhughes@241: razor_package_iterator_init_for_property(&pkg_iter, rhughes@241: trans->system.set, rhughes@241: sp); rhughes@241: while (razor_package_iterator_next(&pkg_iter, &pkg, rhughes@241: &name, &version, &arch)) { rhughes@241: fprintf(stderr, "updating %s %s because it conflicts with %s", rhughes@241: name, version, spi.pool + sp->name); rhughes@241: trans->system.packages[pkg - spkgs] |= rhughes@241: TRANS_PACKAGE_UPDATE; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: prop_iter_init(&spi, &trans->system); rhughes@241: prop_iter_init(&upi, &trans->upstream); rhughes@241: rhughes@241: while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) { rhughes@241: sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, rhughes@241: &upi.pool[upi.p->name]); rhughes@241: rhughes@241: if (sp) rhughes@241: flag_matching_providers(trans, &spi, up, &upi, rhughes@241: TRANS_PACKAGE_UPDATE); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: pull_in_requirements(struct razor_transaction *trans, rhughes@241: struct prop_iter *rpi, struct prop_iter *ppi) rhughes@241: { rhughes@241: struct razor_property *rp, *pp; rhughes@241: struct razor_package *pkg, *upkgs; rhughes@241: rhughes@241: upkgs = trans->upstream.set->packages.data; rhughes@241: while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { rhughes@241: if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED) rhughes@241: continue; rhughes@241: rhughes@241: pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES, rhughes@241: &rpi->pool[rp->name]); rhughes@241: if (pp == NULL) rhughes@241: continue; rhughes@241: pkg = pick_matching_provider(trans->upstream.set, rhughes@241: ppi, rp->relation, rhughes@241: &rpi->pool[rp->version]); rhughes@241: if (pkg == NULL) rhughes@241: continue; rhughes@241: rhughes@241: rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED; rhughes@241: rhughes@241: fprintf(stderr, "pulling in %s which provides %s %s %s " rhughes@241: "to satisfy %s %s %s\n", rhughes@241: ppi->pool + pkg->name, rhughes@241: ppi->pool + pp->name, rhughes@241: relation_string[pp->relation], rhughes@241: ppi->pool + pp->version, rhughes@241: &rpi->pool[rp->name], rhughes@241: relation_string[rp->relation], rhughes@241: &rpi->pool[rp->version]); rhughes@241: rhughes@241: trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: pull_in_all_requirements(struct razor_transaction *trans) rhughes@241: { rhughes@241: struct prop_iter rpi, ppi; rhughes@241: rhughes@241: prop_iter_init(&rpi, &trans->system); rhughes@241: prop_iter_init(&ppi, &trans->upstream); rhughes@241: pull_in_requirements(trans, &rpi, &ppi); rhughes@241: rhughes@241: prop_iter_init(&rpi, &trans->upstream); rhughes@241: prop_iter_init(&ppi, &trans->upstream); rhughes@241: pull_in_requirements(trans, &rpi, &ppi); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: flush_scheduled_system_updates(struct razor_transaction *trans) rhughes@241: { rhughes@241: struct razor_package_iterator *pi; rhughes@241: struct razor_package *p, *pkg, *spkgs; rhughes@241: struct prop_iter ppi; rhughes@241: const char *name, *version, *arch; rhughes@241: rhughes@241: spkgs = trans->system.set->packages.data; rhughes@241: pi = razor_package_iterator_create(trans->system.set); rhughes@241: prop_iter_init(&ppi, &trans->upstream); rhughes@241: rhughes@241: while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { rhughes@241: if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE)) rhughes@241: continue; rhughes@241: rhughes@241: if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name)) rhughes@241: continue; rhughes@241: rhughes@241: pkg = pick_matching_provider(trans->upstream.set, &ppi, rhughes@241: RAZOR_VERSION_GREATER, version); rhughes@241: if (pkg == NULL) rhughes@241: continue; rhughes@241: rhughes@241: fprintf(stderr, "updating %s-%s to %s-%s\n", rhughes@241: name, version, rhughes@241: &ppi.pool[pkg->name], &ppi.pool[pkg->version]); rhughes@241: rhughes@241: razor_transaction_remove_package(trans, p); rhughes@241: razor_transaction_install_package(trans, pkg); rhughes@241: } rhughes@241: rhughes@241: razor_package_iterator_destroy(pi); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: flush_scheduled_upstream_updates(struct razor_transaction *trans) rhughes@241: { rhughes@241: struct razor_package_iterator *pi; rhughes@241: struct razor_package *p, *upkgs; rhughes@241: struct prop_iter spi; rhughes@241: const char *name, *version, *arch; rhughes@241: rhughes@241: upkgs = trans->upstream.set->packages.data; rhughes@241: pi = razor_package_iterator_create(trans->upstream.set); rhughes@241: prop_iter_init(&spi, &trans->system); rhughes@241: rhughes@241: while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { rhughes@241: if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE)) rhughes@241: continue; rhughes@241: krh@244: if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name)) krh@244: remove_matching_providers(trans, &spi, krh@244: RAZOR_VERSION_LESS, version); rhughes@241: razor_transaction_install_package(trans, p); rhughes@241: fprintf(stderr, "installing %s-%s\n", name, version); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: int rhughes@241: razor_transaction_resolve(struct razor_transaction *trans) rhughes@241: { rhughes@241: int last = 0; rhughes@241: rhughes@241: flush_scheduled_system_updates(trans); krh@244: flush_scheduled_upstream_updates(trans); rhughes@241: rhughes@241: while (last < trans->changes) { rhughes@241: last = trans->changes; rhughes@241: remove_obsoleted_packages(trans); rhughes@241: mark_all_satisfied_requires(trans); rhughes@241: update_unsatisfied_packages(trans); rhughes@241: update_conflicted_packages(trans); rhughes@241: pull_in_all_requirements(trans); rhughes@241: flush_scheduled_system_updates(trans); rhughes@241: flush_scheduled_upstream_updates(trans); rhughes@241: } rhughes@241: rhughes@241: return trans->changes; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: describe_unsatisfied(struct razor_set *set, struct razor_property *rp) rhughes@241: { rhughes@241: struct razor_package_iterator pi; rhughes@241: struct razor_package *pkg; rhughes@241: const char *name, *version, *arch, *pool; rhughes@241: rhughes@241: pool = set->string_pool.data; rhughes@241: if (pool[rp->version] == '\0') { rhughes@241: razor_package_iterator_init_for_property(&pi, set, rp); rhughes@241: while (razor_package_iterator_next(&pi, &pkg, rhughes@241: &name, &version, &arch)) rhughes@241: fprintf(stderr, "%s is needed by %s-%s.%s\n", rhughes@241: &pool[rp->name], rhughes@241: name, version, arch); rhughes@241: } else { rhughes@241: razor_package_iterator_init_for_property(&pi, set, rp); rhughes@241: while (razor_package_iterator_next(&pi, &pkg, rhughes@241: &name, &version, &arch)) rhughes@241: fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n", rhughes@241: &pool[rp->name], rhughes@241: relation_string[rp->relation], rhughes@241: &pool[rp->version], rhughes@241: name, version, arch); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: int rhughes@241: razor_transaction_describe(struct razor_transaction *trans) rhughes@241: { rhughes@241: struct prop_iter rpi; rhughes@241: struct razor_property *rp; rhughes@241: int unsatisfied; rhughes@241: rhughes@241: flush_scheduled_system_updates(trans); rhughes@241: flush_scheduled_upstream_updates(trans); rhughes@241: mark_all_satisfied_requires(trans); rhughes@241: rhughes@241: unsatisfied = 0; rhughes@241: prop_iter_init(&rpi, &trans->system); rhughes@241: while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { rhughes@241: if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) { rhughes@241: describe_unsatisfied(trans->system.set, rp); rhughes@241: unsatisfied++; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: prop_iter_init(&rpi, &trans->upstream); rhughes@241: while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { rhughes@241: if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) { rhughes@241: describe_unsatisfied(trans->upstream.set, rp); rhughes@241: unsatisfied++; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: return unsatisfied; rhughes@241: } rhughes@241: rhughes@241: int rhughes@241: razor_transaction_unsatisfied_property(struct razor_transaction *trans, rhughes@241: const char *name, rhughes@241: enum razor_version_relation rel, rhughes@241: const char *version, rhughes@241: enum razor_property_type type) rhughes@241: { rhughes@241: struct prop_iter pi; rhughes@241: struct razor_property *p; rhughes@241: rhughes@241: prop_iter_init(&pi, &trans->system); rhughes@241: while (prop_iter_next(&pi, type, &p)) { rhughes@241: if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) && rhughes@241: p->relation == rel && rhughes@241: strcmp(&pi.pool[p->name], name) == 0 && rhughes@241: strcmp(&pi.pool[p->version], version) == 0) rhughes@241: rhughes@241: return 1; rhughes@241: } rhughes@241: rhughes@241: prop_iter_init(&pi, &trans->upstream); rhughes@241: while (prop_iter_next(&pi, type, &p)) { rhughes@241: if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) && rhughes@241: p->relation == rel && rhughes@241: strcmp(&pi.pool[p->name], name) == 0 && rhughes@241: strcmp(&pi.pool[p->version], version) == 0) rhughes@241: rhughes@241: return 1; rhughes@241: } rhughes@241: rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: struct razor_set * rhughes@241: razor_transaction_finish(struct razor_transaction *trans) rhughes@241: { rhughes@241: struct razor_merger *merger; rhughes@241: struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs; rhughes@241: char *upool, *spool; rhughes@241: int cmp; rhughes@241: rhughes@241: s = trans->system.set->packages.data; rhughes@241: spkgs = trans->system.set->packages.data; rhughes@241: send = trans->system.set->packages.data + rhughes@241: trans->system.set->packages.size; rhughes@241: spool = trans->system.set->string_pool.data; rhughes@241: rhughes@241: u = trans->upstream.set->packages.data; rhughes@241: upkgs = trans->upstream.set->packages.data; rhughes@241: uend = trans->upstream.set->packages.data + rhughes@241: trans->upstream.set->packages.size; rhughes@241: upool = trans->upstream.set->string_pool.data; rhughes@241: rhughes@241: merger = razor_merger_create(trans->system.set, trans->upstream.set); rhughes@241: while (s < send || u < uend) { rhughes@241: if (s < send && u < uend) rhughes@241: cmp = strcmp(&spool[s->name], &upool[u->name]); rhughes@241: else if (s < send) rhughes@241: cmp = -1; rhughes@241: else rhughes@241: cmp = 1; rhughes@241: rhughes@241: if (cmp < 0) { rhughes@241: if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT) rhughes@241: razor_merger_add_package(merger, s); rhughes@241: s++; rhughes@241: } else if (cmp == 0) { rhughes@241: if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT) rhughes@241: razor_merger_add_package(merger, s); rhughes@241: if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT) rhughes@241: razor_merger_add_package(merger, u); rhughes@241: rhughes@241: s++; rhughes@241: u++; rhughes@241: } else { rhughes@241: if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT) rhughes@241: razor_merger_add_package(merger, u); rhughes@241: u++; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: razor_transaction_destroy(trans); rhughes@241: rhughes@241: return razor_merger_finish(merger); rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_transaction_destroy(struct razor_transaction *trans) rhughes@241: { rhughes@241: transaction_set_release(&trans->system); rhughes@241: transaction_set_release(&trans->upstream); rhughes@241: free(trans); rhughes@241: } rhughes@241: rhughes@241: struct razor_package_query { rhughes@241: struct razor_set *set; rhughes@241: char *vector; rhughes@241: int count; rhughes@241: }; rhughes@241: rhughes@241: struct razor_package_query * rhughes@241: razor_package_query_create(struct razor_set *set) rhughes@241: { rhughes@241: struct razor_package_query *pq; rhughes@241: int count; rhughes@241: rhughes@241: pq = zalloc(sizeof *pq); rhughes@241: pq->set = set; rhughes@241: count = set->packages.size / sizeof(struct razor_package); rhughes@241: pq->vector = zalloc(count * sizeof(char)); rhughes@241: rhughes@241: return pq; rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_package_query_add_package(struct razor_package_query *pq, rhughes@241: struct razor_package *p) rhughes@241: { rhughes@241: struct razor_package *packages; rhughes@241: rhughes@241: packages = pq->set->packages.data; rhughes@241: pq->count += pq->vector[p - packages] ^ 1; rhughes@241: pq->vector[p - packages] = 1; rhughes@241: } rhughes@241: rhughes@241: void rhughes@241: razor_package_query_add_iterator(struct razor_package_query *pq, rhughes@241: struct razor_package_iterator *pi) rhughes@241: { rhughes@241: struct razor_package *packages, *p; rhughes@241: const char *name, *version, *arch; rhughes@241: rhughes@241: packages = pq->set->packages.data; rhughes@241: while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { rhughes@241: pq->count += pq->vector[p - packages] ^ 1; rhughes@241: pq->vector[p - packages] = 1; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: struct razor_package_iterator * rhughes@241: razor_package_query_finish(struct razor_package_query *pq) rhughes@241: { rhughes@241: struct razor_package_iterator *pi; rhughes@241: struct razor_set *set; rhughes@241: struct list *index; rhughes@241: int i, j, count; rhughes@241: rhughes@241: set = pq->set; rhughes@241: count = set->packages.size / sizeof(struct razor_package); rhughes@241: index = zalloc(pq->count * sizeof *index); rhughes@241: rhughes@241: for (i = 0, j = 0; i < count; i++) { rhughes@241: if (!pq->vector[i]) rhughes@241: continue; rhughes@241: rhughes@241: index[j].data = i; rhughes@241: if (j == pq->count - 1) rhughes@241: index[j].flags = 0x80; rhughes@241: j++; rhughes@241: } rhughes@241: rhughes@241: free(pq); rhughes@241: rhughes@241: pi = razor_package_iterator_create_with_index(set, index); rhughes@241: pi->free_index = 1; rhughes@241: rhughes@241: return pi; rhughes@241: }