krh@212: /* krh@212: * Copyright (C) 2008 Kristian Høgsberg krh@212: * Copyright (C) 2008 Red Hat, Inc krh@212: * krh@212: * This program is free software; you can redistribute it and/or modify krh@212: * it under the terms of the GNU General Public License as published by krh@212: * the Free Software Foundation; either version 2 of the License, or krh@212: * (at your option) any later version. krh@212: * krh@212: * This program is distributed in the hope that it will be useful, krh@212: * but WITHOUT ANY WARRANTY; without even the implied warranty of krh@212: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the krh@212: * GNU General Public License for more details. krh@212: * krh@212: * You should have received a copy of the GNU General Public License along krh@212: * with this program; if not, write to the Free Software Foundation, Inc., krh@212: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. krh@212: */ krh@212: krh@15: #define _GNU_SOURCE krh@15: krh@0: #include krh@19: #include danw@108: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@15: #include krh@35: #include krh@54: #include krh@0: krh@27: #include "razor.h" krh@91: #include "razor-internal.h" danw@115: #include "types.h" krh@30: krh@30: struct razor_set_section { danw@108: uint32_t type; danw@108: uint32_t offset; danw@108: uint32_t size; krh@30: }; krh@30: krh@30: struct razor_set_header { danw@108: uint32_t magic; danw@108: uint32_t version; krh@30: struct razor_set_section sections[0]; krh@30: }; krh@30: krh@30: #define RAZOR_MAGIC 0x7a7a7a7a krh@30: #define RAZOR_VERSION 1 krh@30: jbowes@228: #define RAZOR_STRING_POOL 0 jbowes@228: #define RAZOR_PACKAGES 1 jbowes@228: #define RAZOR_PROPERTIES 2 jbowes@228: #define RAZOR_FILES 3 jbowes@228: #define RAZOR_PACKAGE_POOL 4 jbowes@228: #define RAZOR_PROPERTY_POOL 5 jbowes@228: #define RAZOR_FILE_POOL 6 jbowes@228: #define RAZOR_FILE_STRING_POOL 7 jbowes@228: #define RAZOR_DETAILS_STRING_POOL 8 krh@30: krh@30: struct razor_package { danw@120: uint name : 24; danw@120: uint flags : 8; jbowes@225: uint32_t version; jbowes@225: uint32_t arch; jbowes@224: uint32_t summary; jbowes@224: uint32_t description; jbowes@225: uint32_t url; jbowes@225: uint32_t license; danw@117: struct list_head properties; danw@117: struct list_head files; krh@30: }; krh@30: krh@30: struct razor_property { danw@119: uint name : 24; danw@119: uint flags : 6; danw@162: enum razor_property_type type : 2; danw@162: enum razor_version_relation relation : 32; danw@108: uint32_t version; danw@117: struct list_head packages; krh@30: }; krh@30: krh@48: struct razor_entry { danw@120: uint name : 24; danw@120: uint flags : 8; danw@108: uint32_t start; danw@117: struct list_head packages; krh@48: }; krh@48: danw@120: #define RAZOR_ENTRY_LAST 0x80 danw@120: krh@30: struct razor_set { krh@30: struct array string_pool; krh@30: struct array packages; krh@66: struct array properties; krh@56: struct array files; krh@56: struct array package_pool; krh@66: struct array property_pool; krh@56: struct array file_pool; jbowes@227: struct array file_string_pool; jbowes@228: struct array details_string_pool; krh@30: struct razor_set_header *header; krh@30: }; krh@30: krh@52: struct import_entry { danw@108: uint32_t package; krh@52: char *name; krh@52: }; krh@52: krh@52: struct import_directory { danw@108: uint32_t name, count; krh@52: struct array files; krh@52: struct array packages; krh@52: struct import_directory *last; krh@52: }; krh@52: krh@30: struct razor_importer { krh@30: struct razor_set *set; krh@78: struct hashtable table; jbowes@227: struct hashtable file_table; jbowes@228: struct hashtable details_table; krh@30: struct razor_package *package; krh@66: struct array properties; krh@48: struct array files; danw@159: struct array file_requires; krh@30: }; krh@30: krh@0: static void * krh@0: zalloc(size_t size) krh@0: { krh@0: void *p; krh@0: krh@0: p = malloc(size); krh@0: memset(p, 0, size); krh@0: krh@0: return p; krh@0: } krh@0: krh@19: struct razor_set_section razor_sections[] = { jbowes@227: { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) }, jbowes@227: { RAZOR_PACKAGES, offsetof(struct razor_set, packages) }, jbowes@227: { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) }, jbowes@227: { RAZOR_FILES, offsetof(struct razor_set, files) }, jbowes@227: { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) }, jbowes@227: { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) }, jbowes@227: { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) }, jbowes@227: { RAZOR_FILE_STRING_POOL, offsetof(struct razor_set, file_string_pool) }, jbowes@228: { RAZOR_DETAILS_STRING_POOL, offsetof(struct razor_set, details_string_pool) }, krh@19: }; krh@19: krh@4: struct razor_set * krh@4: razor_set_create(void) krh@0: { krh@150: struct razor_set *set; krh@150: struct razor_entry *e; danw@167: char *empty; krh@150: krh@150: set = zalloc(sizeof *set); krh@150: krh@150: e = array_add(&set->files, sizeof *e); danw@167: empty = array_add(&set->string_pool, 1); danw@167: *empty = '\0'; jbowes@227: empty = array_add(&set->file_string_pool, 1); jbowes@227: *empty = '\0'; jbowes@228: empty = array_add(&set->details_string_pool, 1); jbowes@228: *empty = '\0'; krh@150: e->name = 0; krh@150: e->flags = RAZOR_ENTRY_LAST; krh@150: e->start = 0; krh@150: list_set_empty(&e->packages); krh@150: krh@150: return set; krh@0: } krh@0: krh@4: struct razor_set * krh@4: razor_set_open(const char *filename) krh@0: { krh@4: struct razor_set *set; krh@19: struct razor_set_section *s; krh@0: struct stat stat; krh@19: struct array *array; krh@19: int fd; krh@0: krh@4: set = zalloc(sizeof *set); krh@0: fd = open(filename, O_RDONLY); krh@0: if (fstat(fd, &stat) < 0) krh@0: return NULL; krh@4: set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); krh@4: if (set->header == MAP_FAILED) { krh@4: free(set); krh@0: return NULL; krh@0: } krh@0: krh@19: for (s = set->header->sections; ~s->type; s++) { krh@19: if (s->type >= ARRAY_SIZE(razor_sections)) krh@19: continue; krh@19: if (s->type != razor_sections[s->type].type) krh@19: continue; krh@19: array = (void *) set + razor_sections[s->type].offset; krh@19: array->data = (void *) set->header + s->offset; krh@19: array->size = s->size; krh@19: array->alloc = s->size; krh@0: } krh@0: close(fd); krh@0: krh@4: return set; krh@0: } krh@0: krh@0: void krh@4: razor_set_destroy(struct razor_set *set) krh@0: { krh@0: unsigned int size; krh@19: struct array *a; krh@0: int i; krh@0: krh@4: if (set->header) { krh@4: for (i = 0; set->header->sections[i].type; i++) krh@0: ; krh@4: size = set->header->sections[i].type; krh@4: munmap(set->header, size); krh@0: } else { krh@19: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@19: a = (void *) set + razor_sections[i].offset; krh@19: free(a->data); krh@19: } krh@0: } krh@0: krh@4: free(set); krh@0: } krh@0: krh@43: int krh@197: razor_set_write_to_fd(struct razor_set *set, int fd) krh@0: { krh@0: char data[4096]; krh@4: struct razor_set_header *header = (struct razor_set_header *) data; krh@19: struct array *a; danw@108: uint32_t offset; krh@197: int i; krh@0: krh@0: memset(data, 0, sizeof data); krh@4: header->magic = RAZOR_MAGIC; krh@4: header->version = RAZOR_VERSION; krh@17: offset = sizeof data; krh@0: krh@19: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@19: if (razor_sections[i].type != i) krh@19: continue; krh@19: a = (void *) set + razor_sections[i].offset; krh@19: header->sections[i].type = i; krh@17: header->sections[i].offset = offset; krh@19: header->sections[i].size = a->size; krh@91: offset += ALIGN(a->size, 4096); krh@17: } krh@0: krh@19: header->sections[i].type = ~0; krh@17: header->sections[i].offset = 0; krh@17: header->sections[i].size = 0; krh@10: krh@91: razor_write(fd, data, sizeof data); danw@113: memset(data, 0, sizeof data); krh@19: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@19: if (razor_sections[i].type != i) krh@19: continue; krh@19: a = (void *) set + razor_sections[i].offset; danw@113: razor_write(fd, a->data, a->size); danw@113: razor_write(fd, data, ALIGN(a->size, 4096) - a->size); krh@19: } krh@17: krh@0: return 0; krh@0: } krh@0: krh@197: int krh@197: razor_set_write(struct razor_set *set, const char *filename) krh@197: { krh@197: int fd, status; krh@197: krh@197: fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); krh@197: if (fd < 0) krh@197: return -1; krh@197: krh@197: status = razor_set_write_to_fd(set, fd); krh@197: if (status) { krh@197: close(fd); krh@197: return status; krh@197: } krh@197: krh@197: return close(fd); krh@197: } krh@197: krh@27: void danw@143: razor_build_evr(char *evr_buf, int size, const char *epoch, danw@143: const char *version, const char *release) danw@143: { danw@143: int len; danw@143: danw@143: if (!version || !*version) { danw@143: *evr_buf = '\0'; danw@143: return; danw@143: } danw@143: danw@143: if (epoch && *epoch && strcmp(epoch, "0") != 0) { danw@143: len = snprintf(evr_buf, size, "%s:", epoch); danw@143: evr_buf += len; danw@143: size -= len; danw@143: } danw@143: len = snprintf(evr_buf, size, "%s", version); danw@143: evr_buf += len; danw@143: size -= len; danw@143: if (release && *release) danw@143: snprintf(evr_buf, size, "-%s", release); danw@143: } danw@143: danw@143: void krh@30: razor_importer_begin_package(struct razor_importer *importer, krh@192: const char *name, krh@192: const char *version, krh@192: const char *arch) krh@13: { krh@25: struct razor_package *p; krh@13: krh@30: p = array_add(&importer->set->packages, sizeof *p); krh@95: p->name = hashtable_tokenize(&importer->table, name); danw@120: p->flags = 0; krh@95: p->version = hashtable_tokenize(&importer->table, version); krh@192: p->arch = hashtable_tokenize(&importer->table, arch); krh@13: krh@30: importer->package = p; krh@66: array_init(&importer->properties); krh@13: } krh@13: krh@13: void krh@30: razor_importer_finish_package(struct razor_importer *importer) krh@13: { danw@117: list_set_array(&importer->package->properties, danw@117: &importer->set->property_pool, danw@124: &importer->properties, danw@124: 1); krh@13: krh@66: array_release(&importer->properties); krh@13: } krh@13: krh@66: void jbowes@224: razor_importer_add_details(struct razor_importer *importer, jbowes@224: const char *summary, jbowes@225: const char *description, jbowes@225: const char *url, jbowes@225: const char *license) jbowes@224: { jbowes@228: importer->package->summary = hashtable_tokenize(&importer->details_table, summary); jbowes@228: importer->package->description = hashtable_tokenize(&importer->details_table, description); jbowes@228: importer->package->url = hashtable_tokenize(&importer->details_table, url); jbowes@228: importer->package->license = hashtable_tokenize(&importer->details_table, license); jbowes@224: } jbowes@224: jbowes@224: void krh@30: razor_importer_add_property(struct razor_importer *importer, danw@109: const char *name, danw@109: enum razor_version_relation relation, danw@109: const char *version, krh@66: enum razor_property_type type) krh@13: { krh@25: struct razor_property *p; danw@108: uint32_t *r; krh@13: krh@66: p = array_add(&importer->set->properties, sizeof *p); danw@119: p->name = hashtable_tokenize(&importer->table, name); danw@119: p->flags = 0; danw@119: p->type = type; danw@109: p->relation = relation; krh@95: p->version = hashtable_tokenize(&importer->table, version); danw@117: list_set_ptr(&p->packages, importer->package - danw@117: (struct razor_package *) importer->set->packages.data); krh@13: krh@66: r = array_add(&importer->properties, sizeof *r); krh@66: *r = p - (struct razor_property *) importer->set->properties.data; danw@159: danw@159: if (type == RAZOR_PROPERTY_REQUIRES && *name == '/') { danw@159: r = array_add(&importer->file_requires, sizeof *r); danw@159: *r = p->name; danw@159: } krh@30: } krh@30: krh@46: void krh@46: razor_importer_add_file(struct razor_importer *importer, const char *name) krh@46: { krh@52: struct import_entry *e; krh@48: krh@52: e = array_add(&importer->files, sizeof *e); krh@52: krh@52: e->package = importer->package - krh@52: (struct razor_package *) importer->set->packages.data; krh@52: e->name = strdup(name); krh@46: } krh@46: krh@30: struct razor_importer * krh@30: razor_importer_new(void) krh@30: { krh@30: struct razor_importer *importer; krh@30: krh@30: importer = zalloc(sizeof *importer); krh@30: importer->set = razor_set_create(); krh@78: hashtable_init(&importer->table, &importer->set->string_pool); jbowes@227: hashtable_init(&importer->file_table, &importer->set->file_string_pool); jbowes@228: hashtable_init(&importer->details_table, &importer->set->details_string_pool); krh@30: krh@30: return importer; krh@9: } krh@9: krh@75: /* Destroy an importer without creating the set. */ krh@75: void krh@75: razor_importer_destroy(struct razor_importer *importer) krh@75: { krh@75: /* FIXME: write this */ krh@75: } krh@75: krh@9: static int krh@35: versioncmp(const char *s1, const char *s2) krh@35: { krh@35: const char *p1, *p2; krh@35: long n1, n2; krh@35: int res; krh@35: danw@153: n1 = strtol(s1, (char **) &p1, 10); danw@153: n2 = strtol(s2, (char **) &p2, 10); krh@35: krh@35: /* Epoch; if one but not the other has an epoch set, default krh@35: * the epoch-less version to 0. */ krh@35: res = (*p1 == ':') - (*p2 == ':'); krh@35: if (res < 0) { krh@35: n1 = 0; krh@35: p1 = s1; krh@35: p2++; krh@35: } else if (res > 0) { krh@35: p1++; krh@35: n2 = 0; krh@35: p2 = s2; krh@35: } krh@35: krh@35: if (n1 != n2) krh@35: return n1 - n2; krh@35: while (*p1 && *p2) { krh@35: if (*p1 != *p2) krh@35: return *p1 - *p2; krh@35: p1++; krh@35: p2++; krh@35: if (isdigit(*p1) && isdigit(*p2)) krh@35: return versioncmp(p1, p2); krh@35: } krh@35: krh@35: return *p1 - *p2; krh@35: } krh@35: krh@35: static int krh@22: compare_packages(const void *p1, const void *p2, void *data) krh@9: { krh@25: const struct razor_package *pkg1 = p1, *pkg2 = p2; krh@22: struct razor_set *set = data; krh@22: char *pool = set->string_pool.data; krh@9: danw@120: /* FIXME: what if the flags are different? */ krh@23: if (pkg1->name == pkg2->name) krh@35: return versioncmp(&pool[pkg1->version], &pool[pkg2->version]); krh@23: else krh@23: return strcmp(&pool[pkg1->name], &pool[pkg2->name]); krh@9: } krh@9: krh@9: static int krh@22: compare_properties(const void *p1, const void *p2, void *data) krh@9: { krh@25: const struct razor_property *prop1 = p1, *prop2 = p2; krh@22: struct razor_set *set = data; krh@22: char *pool = set->string_pool.data; krh@9: danw@119: if (prop1->name != prop2->name) danw@119: return strcmp(&pool[prop1->name], &pool[prop2->name]); danw@119: else if (prop1->type != prop2->type) danw@119: return prop1->type - prop2->type; danw@119: else if (prop1->relation != prop2->relation) danw@119: return prop1->relation - prop2->relation; krh@12: else danw@119: return versioncmp(&pool[prop1->version], &pool[prop2->version]); krh@9: } krh@9: danw@108: static uint32_t * krh@66: uniqueify_properties(struct razor_set *set) krh@9: { krh@25: struct razor_property *rp, *up, *rp_end; krh@18: struct array *pkgs, *p; danw@117: struct list_head *r; danw@117: uint32_t *map, *rmap; krh@18: int i, count, unique; krh@9: krh@66: count = set->properties.size / sizeof(struct razor_property); krh@186: map = razor_qsort_with_data(set->properties.data, krh@186: count, krh@186: sizeof(struct razor_property), krh@186: compare_properties, krh@186: set); krh@9: krh@66: rp_end = set->properties.data + set->properties.size; krh@25: rmap = malloc(count * sizeof *map); krh@25: pkgs = zalloc(count * sizeof *pkgs); krh@66: for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) { danw@119: if (rp->name != up->name || rp->type != up->type || danw@119: rp->relation != up->relation || rp->version != up->version) { krh@25: up++; krh@25: up->name = rp->name; danw@119: up->flags = 0; danw@119: up->type = rp->type; danw@109: up->relation = rp->relation; krh@25: up->version = rp->version; krh@10: } krh@25: krh@66: unique = up - (struct razor_property *) set->properties.data; krh@25: rmap[map[i]] = unique; krh@25: r = array_add(&pkgs[unique], sizeof *r); krh@25: *r = rp->packages; krh@10: } krh@25: free(map); krh@9: danw@124: if (up != rp) danw@124: up++; krh@66: set->properties.size = (void *) up - set->properties.data; krh@25: rp_end = up; krh@66: for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) { danw@124: list_set_array(&rp->packages, &set->package_pool, p, 0); krh@25: array_release(p); krh@18: } krh@18: krh@18: free(pkgs); krh@18: krh@25: return rmap; krh@10: } krh@10: krh@48: static int krh@48: compare_filenames(const void *p1, const void *p2, void *data) krh@48: { krh@52: const struct import_entry *e1 = p1; krh@52: const struct import_entry *e2 = p2; danw@126: const char *n1 = e1->name; danw@126: const char *n2 = e2->name; krh@48: danw@126: /* Need to make sure that the contents of a directory danw@126: * are sorted immediately after it. So "foo/bar" has to danw@126: * sort before "foo.conf" danw@126: * danw@126: * FIXME: this is about 60% slower than strcmp danw@126: */ danw@126: while (*n1 && *n2) { danw@126: if (*n1 < *n2) danw@126: return *n2 == '/' ? 1 : -1; danw@126: else if (*n1 > *n2) danw@126: return *n1 == '/' ? -1 : 1; danw@126: n1++; danw@126: n2++; danw@126: } danw@126: if (*n1) danw@126: return 1; danw@126: else if (*n2) danw@126: return -1; danw@126: else danw@126: return 0; krh@48: } krh@48: krh@48: static void krh@52: count_entries(struct import_directory *d) krh@48: { krh@52: struct import_directory *p, *end; krh@48: krh@48: p = d->files.data; krh@48: end = d->files.data + d->files.size; krh@48: d->count = 0; krh@48: while (p < end) { krh@48: count_entries(p); krh@48: d->count += p->count + 1; krh@48: p++; krh@48: } krh@48: } krh@48: krh@48: static void krh@52: serialize_files(struct razor_set *set, krh@52: struct import_directory *d, struct array *array) krh@48: { krh@52: struct import_directory *p, *end; krh@56: struct razor_entry *e = NULL; danw@114: uint32_t s; krh@48: krh@48: p = d->files.data; krh@48: end = d->files.data + d->files.size; krh@48: s = array->size / sizeof *e + d->files.size / sizeof *p; krh@48: while (p < end) { krh@48: e = array_add(array, sizeof *e); krh@48: e->name = p->name; danw@120: e->flags = 0; krh@56: e->start = p->count > 0 ? s : 0; krh@48: s += p->count; krh@60: danw@124: list_set_array(&e->packages, &set->package_pool, &p->packages, 0); krh@52: array_release(&p->packages); krh@48: p++; krh@48: } krh@56: if (e != NULL) danw@120: e->flags |= RAZOR_ENTRY_LAST; krh@48: krh@48: p = d->files.data; krh@48: end = d->files.data + d->files.size; krh@48: while (p < end) { krh@52: serialize_files(set, p, array); krh@48: p++; krh@48: } krh@48: } krh@48: krh@48: static void danw@108: remap_property_package_links(struct array *properties, uint32_t *rmap) krh@61: { krh@61: struct razor_property *p, *end; krh@61: krh@61: end = properties->data + properties->size; krh@61: for (p = properties->data; p < end; p++) danw@117: list_remap_head(&p->packages, rmap); krh@61: } krh@61: krh@61: static void krh@48: build_file_tree(struct razor_importer *importer) krh@48: { krh@48: int count, i, length; krh@52: struct import_entry *filenames; krh@52: char *f, *end; danw@108: uint32_t name, *r; krh@48: char dirname[256]; krh@52: struct import_directory *d, root; krh@48: struct razor_entry *e; krh@48: krh@52: count = importer->files.size / sizeof (struct import_entry); krh@186: razor_qsort_with_data(importer->files.data, krh@186: count, krh@186: sizeof (struct import_entry), krh@186: compare_filenames, krh@186: NULL); krh@48: jbowes@227: root.name = hashtable_tokenize(&importer->file_table, ""); krh@48: array_init(&root.files); krh@52: array_init(&root.packages); krh@48: root.last = NULL; krh@48: krh@48: filenames = importer->files.data; krh@48: for (i = 0; i < count; i++) { krh@52: f = filenames[i].name; krh@48: if (*f != '/') krh@48: continue; krh@57: f++; krh@48: krh@48: d = &root; krh@48: while (*f) { krh@57: end = strchr(f, '/'); krh@48: if (end == NULL) krh@48: end = f + strlen(f); krh@57: length = end - f; krh@57: memcpy(dirname, f, length); krh@48: dirname[length] ='\0'; jbowes@227: name = hashtable_tokenize(&importer->file_table, dirname); krh@48: if (d->last == NULL || d->last->name != name) { krh@48: d->last = array_add(&d->files, sizeof *d); krh@48: d->last->name = name; krh@48: d->last->last = NULL; krh@48: array_init(&d->last->files); krh@52: array_init(&d->last->packages); krh@48: } krh@48: d = d->last; krh@57: f = end + 1; krh@57: if (*end == '\0') krh@57: break; krh@48: } krh@48: krh@52: r = array_add(&d->packages, sizeof *r); krh@52: *r = filenames[i].package; krh@52: free(filenames[i].name); krh@48: } krh@48: krh@48: count_entries(&root); krh@150: e = importer->set->files.data; danw@120: e->name = root.name; danw@120: e->flags = RAZOR_ENTRY_LAST; danw@129: e->start = importer->files.size ? 1 : 0; danw@117: list_set_empty(&e->packages); krh@48: krh@56: serialize_files(importer->set, &root, &importer->set->files); krh@48: krh@48: array_release(&importer->files); krh@48: } krh@48: danw@159: static struct razor_entry * danw@159: find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern); danw@159: danw@159: static void danw@159: list_to_array(struct list *list, struct array *array) danw@159: { danw@159: uint32_t *item; danw@159: danw@159: while (list) { danw@159: item = array_add(array, sizeof *item); danw@159: *item = list->data; danw@159: list = list_next(list); danw@159: } danw@159: } danw@159: danw@159: static int danw@159: compare_file_requires(const void *p1, const void *p2, void *data) danw@159: { danw@159: uint32_t *f1 = (void *)p1, *f2 = (void *)p2; danw@159: const char *pool = data; danw@159: danw@159: return strcmp(&pool[*f1], &pool[*f2]); danw@159: } danw@159: danw@159: static void danw@159: find_file_provides(struct razor_importer *importer) danw@159: { danw@159: struct razor_property *prop; danw@159: struct razor_entry *top, *entry; danw@159: struct razor_package *packages; danw@163: struct array pkgprops; danw@163: struct list *pkg; danw@163: uint32_t *req, *req_start, *req_end; danw@163: uint32_t *map, *newprop; danw@159: char *pool; danw@159: danw@159: pool = importer->set->string_pool.data; danw@159: packages = importer->set->packages.data; danw@159: top = importer->set->files.data; danw@159: danw@159: req = req_start = importer->file_requires.data; danw@159: req_end = importer->file_requires.data + importer->file_requires.size; krh@186: map = razor_qsort_with_data(req, req_end - req, sizeof *req, krh@186: compare_file_requires, pool); danw@159: free(map); danw@159: danw@159: for (req = req_start; req < req_end; req++) { danw@159: if (req > req_start && req[0] == req[-1]) danw@159: continue; danw@159: entry = find_entry(importer->set, top, &pool[*req]); danw@163: if (!entry) danw@163: continue; danw@163: danw@163: for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) { danw@159: prop = array_add(&importer->set->properties, sizeof *prop); danw@159: prop->name = *req; danw@159: prop->type = RAZOR_PROPERTY_PROVIDES; danw@159: prop->relation = RAZOR_VERSION_EQUAL; danw@159: prop->version = hashtable_tokenize(&importer->table, ""); danw@163: list_set_ptr(&prop->packages, pkg->data); danw@163: danw@163: /* Update property list of pkg */ danw@163: array_init(&pkgprops); danw@163: list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops); danw@163: newprop = array_add(&pkgprops, sizeof *newprop); danw@163: *newprop = prop - (struct razor_property *)importer->set->properties.data; danw@163: list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1); danw@163: array_release(&pkgprops); danw@159: } danw@159: } danw@159: danw@159: array_release(&importer->file_requires); danw@159: } danw@159: krh@56: static void danw@108: build_package_file_lists(struct razor_set *set, uint32_t *rmap) krh@54: { krh@56: struct razor_package *p, *packages; krh@56: struct array *pkgs; krh@54: struct razor_entry *e, *end; danw@117: struct list *r; danw@117: uint32_t *q; krh@56: int i, count; krh@54: krh@56: count = set->packages.size / sizeof *p; krh@56: pkgs = zalloc(count * sizeof *pkgs); krh@54: krh@56: end = set->files.data + set->files.size; krh@92: for (e = set->files.data; e < end; e++) { danw@117: list_remap_head(&e->packages, rmap); danw@116: r = list_first(&e->packages, &set->package_pool); danw@116: while (r) { danw@117: q = array_add(&pkgs[r->data], sizeof *q); krh@56: *q = e - (struct razor_entry *) set->files.data; danw@116: r = list_next(r); krh@54: } krh@54: } krh@54: krh@56: packages = set->packages.data; krh@56: for (i = 0; i < count; i++) { danw@124: list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0); krh@56: array_release(&pkgs[i]); krh@48: } krh@56: free(pkgs); krh@52: } krh@52: krh@27: struct razor_set * krh@30: razor_importer_finish(struct razor_importer *importer) krh@9: { krh@30: struct razor_set *set; danw@108: uint32_t *map, *rmap; krh@39: int i, count; krh@18: danw@159: build_file_tree(importer); danw@159: find_file_provides(importer); danw@159: krh@66: map = uniqueify_properties(importer->set); danw@116: list_remap_pool(&importer->set->property_pool, map); krh@39: free(map); krh@25: krh@30: count = importer->set->packages.size / sizeof(struct razor_package); krh@186: map = razor_qsort_with_data(importer->set->packages.data, krh@186: count, krh@186: sizeof(struct razor_package), krh@186: compare_packages, krh@186: importer->set); krh@39: krh@39: rmap = malloc(count * sizeof *rmap); krh@39: for (i = 0; i < count; i++) krh@39: rmap[map[i]] = i; krh@25: free(map); krh@13: danw@116: list_remap_pool(&importer->set->package_pool, rmap); krh@60: build_package_file_lists(importer->set, rmap); krh@66: remap_property_package_links(&importer->set->properties, rmap); krh@52: free(rmap); krh@48: krh@30: set = importer->set; krh@78: hashtable_release(&importer->table); jbowes@227: hashtable_release(&importer->file_table); jbowes@228: hashtable_release(&importer->details_table); krh@30: free(importer); krh@30: krh@30: return set; krh@9: } krh@9: krh@92: struct razor_package_iterator { krh@92: struct razor_set *set; krh@92: struct razor_package *package, *end; danw@117: struct list *index; krh@216: int free_index; krh@92: }; krh@92: danw@137: static struct razor_package_iterator * krh@101: razor_package_iterator_create_with_index(struct razor_set *set, danw@117: struct list *index) krh@3: { krh@92: struct razor_package_iterator *pi; krh@92: krh@92: pi = zalloc(sizeof *pi); krh@92: pi->set = set; krh@101: pi->index = index; krh@92: krh@92: return pi; krh@92: } krh@92: krh@101: struct razor_package_iterator * krh@101: razor_package_iterator_create(struct razor_set *set) krh@101: { danw@116: struct razor_package_iterator *pi; danw@116: danw@116: pi = zalloc(sizeof *pi); danw@116: pi->set = set; danw@116: pi->end = set->packages.data + set->packages.size; danw@116: pi->package = set->packages.data; danw@116: danw@116: return pi; krh@101: } krh@101: krh@101: struct razor_package_iterator * krh@101: razor_package_iterator_create_for_property(struct razor_set *set, krh@101: struct razor_property *property) krh@101: { danw@117: struct list *index; krh@101: danw@116: index = list_first(&property->packages, &set->package_pool); krh@101: return razor_package_iterator_create_with_index(set, index); krh@101: } krh@101: krh@92: int krh@92: razor_package_iterator_next(struct razor_package_iterator *pi, krh@92: struct razor_package **package, krh@192: const char **name, krh@192: const char **version, krh@192: const char **arch) krh@92: { krh@6: char *pool; krh@101: int valid; krh@101: struct razor_package *p, *packages; krh@3: danw@116: if (pi->package) { krh@101: p = pi->package++; krh@101: valid = p < pi->end; danw@116: } else if (pi->index) { danw@116: packages = pi->set->packages.data; danw@117: p = &packages[pi->index->data]; danw@116: pi->index = list_next(pi->index); danw@116: valid = 1; danw@116: } else danw@116: valid = 0; krh@92: krh@101: if (valid) { krh@101: pool = pi->set->string_pool.data; krh@101: *package = p; danw@120: *name = &pool[p->name]; krh@101: *version = &pool[p->version]; krh@192: *arch = &pool[p->arch]; krh@101: } else { krh@101: *package = NULL; krh@101: } krh@101: krh@101: return valid; krh@92: } krh@92: krh@92: void krh@92: razor_package_iterator_destroy(struct razor_package_iterator *pi) krh@92: { krh@216: if (pi->free_index) krh@216: free(pi->index); krh@216: krh@92: free(pi); krh@3: } krh@3: krh@10: struct razor_package * krh@10: razor_set_get_package(struct razor_set *set, const char *package) krh@10: { krh@97: struct razor_package_iterator *pi; krh@97: struct razor_package *p; krh@192: const char *name, *version, *arch; krh@97: krh@97: pi = razor_package_iterator_create(set); krh@192: while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { krh@97: if (strcmp(package, name) == 0) krh@97: break; krh@97: } krh@97: razor_package_iterator_destroy(pi); krh@97: krh@97: return p; krh@10: } krh@10: jbowes@225: void jbowes@225: razor_package_get_details(struct razor_set *set, struct razor_package *package, jbowes@225: const char **summary, const char **description, jbowes@225: const char **url, const char **license) jbowes@224: { jbowes@228: const char *pool = set->details_string_pool.data; jbowes@225: jbowes@225: *summary = &pool[package->summary]; jbowes@225: *description = &pool[package->description]; jbowes@225: *url = &pool[package->url]; jbowes@225: *license = &pool[package->license]; jbowes@224: } jbowes@224: krh@92: struct razor_property_iterator { krh@92: struct razor_set *set; krh@92: struct razor_property *property, *end; danw@117: struct list *index; krh@92: }; krh@92: krh@92: struct razor_property_iterator * krh@92: razor_property_iterator_create(struct razor_set *set, krh@92: struct razor_package *package) krh@92: { krh@92: struct razor_property_iterator *pi; krh@92: krh@92: pi = zalloc(sizeof *pi); krh@92: pi->set = set; krh@98: danw@116: if (package) { danw@117: pi->index = list_first(&package->properties, danw@117: &set->property_pool); danw@116: } else { danw@116: pi->property = set->properties.data; danw@116: pi->end = set->properties.data + set->properties.size; danw@116: } krh@92: krh@92: return pi; krh@92: } krh@92: krh@92: int krh@92: razor_property_iterator_next(struct razor_property_iterator *pi, krh@92: struct razor_property **property, danw@109: const char **name, danw@109: enum razor_version_relation *relation, danw@109: const char **version, krh@92: enum razor_property_type *type) krh@92: { krh@92: char *pool; krh@92: int valid; krh@92: struct razor_property *p, *properties; krh@92: danw@116: if (pi->property) { krh@92: p = pi->property++; krh@92: valid = p < pi->end; danw@116: } else if (pi->index) { danw@116: properties = pi->set->properties.data; danw@117: p = &properties[pi->index->data]; danw@116: pi->index = list_next(pi->index); danw@116: valid = 1; danw@116: } else danw@116: valid = 0; krh@92: krh@96: if (valid) { krh@96: pool = pi->set->string_pool.data; krh@96: *property = p; danw@119: *name = &pool[p->name]; danw@109: *relation = p->relation; krh@96: *version = &pool[p->version]; danw@119: *type = p->type; krh@96: } else { krh@96: *property = NULL; krh@96: } krh@92: krh@92: return valid; krh@92: } krh@92: krh@66: void krh@92: razor_property_iterator_destroy(struct razor_property_iterator *pi) krh@8: { krh@92: free(pi); krh@10: } krh@10: krh@56: static struct razor_entry * krh@56: find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern) krh@56: { krh@56: struct razor_entry *e; jbowes@227: const char *n, *pool = set->file_string_pool.data; krh@56: int len; krh@56: krh@56: e = (struct razor_entry *) set->files.data + dir->start; krh@56: do { danw@120: n = pool + e->name; krh@56: if (strcmp(pattern + 1, n) == 0) krh@56: return e; krh@57: len = strlen(n); krh@56: if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 && krh@56: pattern[len + 1] == '/') { krh@56: return find_entry(set, e, pattern + len + 1); krh@56: } danw@120: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); krh@56: krh@56: return NULL; krh@56: } krh@56: krh@56: static void krh@56: list_dir(struct razor_set *set, struct razor_entry *dir, danw@127: char *prefix, const char *pattern) krh@56: { krh@56: struct razor_entry *e; jbowes@227: const char *n, *pool = set->file_string_pool.data; krh@56: krh@56: e = (struct razor_entry *) set->files.data + dir->start; krh@56: do { danw@120: n = pool + e->name; krh@56: if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0) krh@56: continue; danw@127: printf("%s/%s\n", prefix, n); danw@127: if (e->start) { danw@127: char *sub = prefix + strlen (prefix); danw@127: *sub = '/'; danw@127: strcpy (sub + 1, n); danw@127: list_dir(set, e, prefix, pattern); danw@127: *sub = '\0'; danw@127: } danw@120: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); krh@56: } krh@56: krh@56: void krh@56: razor_set_list_files(struct razor_set *set, const char *pattern) krh@56: { krh@56: struct razor_entry *e; krh@56: char buffer[512], *p, *base; krh@56: danw@127: if (pattern == NULL || !strcmp (pattern, "/")) { danw@127: buffer[0] = '\0'; danw@127: list_dir(set, set->files.data, buffer, NULL); danw@127: return; danw@127: } krh@56: krh@56: strcpy(buffer, pattern); krh@56: e = find_entry(set, set->files.data, buffer); krh@56: if (e && e->start > 0) { krh@56: base = NULL; krh@56: } else { krh@56: p = strrchr(buffer, '/'); krh@56: if (p) { krh@56: *p = '\0'; krh@56: base = p + 1; krh@56: } else { krh@56: base = NULL; krh@56: } krh@56: } krh@56: e = find_entry(set, set->files.data, buffer); krh@56: if (e->start != 0) krh@56: list_dir(set, e, buffer, base); krh@56: } krh@56: krh@102: struct razor_package_iterator * krh@102: razor_package_iterator_create_for_file(struct razor_set *set, krh@102: const char *filename) krh@56: { krh@102: struct razor_entry *entry; danw@117: struct list *index; krh@56: krh@102: entry = find_entry(set, set->files.data, filename); krh@102: if (entry == NULL) krh@102: return NULL; krh@56: danw@116: index = list_first(&entry->packages, &set->package_pool); krh@102: return razor_package_iterator_create_with_index(set, index); krh@56: } krh@56: danw@117: static struct list * danw@117: list_package_files(struct razor_set *set, struct list *r, danw@108: struct razor_entry *dir, uint32_t end, krh@56: char *prefix) krh@56: { krh@56: struct razor_entry *e, *f, *entries; danw@108: uint32_t next, file; krh@56: char *pool; krh@56: int len; krh@56: krh@56: entries = (struct razor_entry *) set->files.data; jbowes@227: pool = set->file_string_pool.data; krh@56: krh@56: e = entries + dir->start; krh@56: do { danw@117: if (entries + r->data == e) { danw@120: printf("%s/%s\n", prefix, pool + e->name); danw@116: r = list_next(r); danw@116: if (!r) krh@83: return NULL; danw@117: if (r->data >= end) krh@83: return r; krh@56: } danw@120: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); krh@56: krh@56: e = entries + dir->start; krh@56: do { krh@56: if (e->start == 0) krh@56: continue; krh@56: danw@120: if (e->flags & RAZOR_ENTRY_LAST) krh@56: next = end; krh@56: else { krh@56: f = e + 1; danw@120: while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST)) krh@56: f++; krh@56: if (f->start == 0) krh@56: next = end; krh@56: else krh@56: next = f->start; krh@56: } krh@56: danw@117: file = r->data; krh@83: if (e->start <= file && file < next) { krh@56: len = strlen(prefix); krh@56: prefix[len] = '/'; danw@120: strcpy(prefix + len + 1, pool + e->name); krh@56: r = list_package_files(set, r, e, next, prefix); krh@56: prefix[len] = '\0'; krh@56: } danw@120: } while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL); krh@56: krh@56: return r; krh@56: } krh@56: krh@56: void krh@56: razor_set_list_package_files(struct razor_set *set, const char *name) krh@56: { krh@56: struct razor_package *package; danw@117: struct list *r; danw@117: uint32_t end; krh@56: char buffer[512]; krh@56: krh@56: package = razor_set_get_package(set, name); krh@56: danw@116: r = list_first(&package->files, &set->file_pool); krh@56: end = set->files.size / sizeof (struct razor_entry); krh@56: buffer[0] = '\0'; krh@56: list_package_files(set, r, set->files.data, end, buffer); krh@56: } krh@56: krh@43: static void krh@21: razor_set_validate(struct razor_set *set, struct array *unsatisfied) krh@21: { krh@66: struct razor_property *r, *p, *end; danw@108: uint32_t *u; krh@21: char *pool; krh@21: krh@66: end = set->properties.data + set->properties.size; krh@21: pool = set->string_pool.data; krh@21: krh@66: for (r = set->properties.data, p = r; r < end; r++) { danw@119: if (r->type != RAZOR_PROPERTY_REQUIRES) krh@66: continue; krh@66: danw@129: p = r; danw@129: while (p < end && p->name == r->name && danw@129: p->type == r->type) danw@129: p++; krh@37: krh@35: /* If there is more than one version of a provides, krh@35: * seek to the end for the highest version. */ krh@66: /* FIXME: This doesn't work if we have a series of krh@66: * requires a = 1, provides a = 1, requires a = 2, krh@66: * provides a = 2, as the kernel and kernel-devel krh@66: * does.*/ danw@119: while (p + 1 < end && p->name == (p + 1)->name && danw@119: p->type == (p + 1)->type) krh@35: p++; krh@37: krh@37: /* FIXME: We need to track property flags (<, <=, = krh@37: * etc) to properly determine if a requires is krh@37: * satisfied. The current code doesn't track that the krh@37: * requires a = 1 isn't satisfied by a = 2 provides. */ krh@37: krh@66: if (p == end || danw@119: p->type != RAZOR_PROPERTY_PROVIDES || danw@119: r->name != p->name || krh@35: versioncmp(&pool[r->version], &pool[p->version]) > 0) { krh@35: /* FIXME: We ignore file requires for now. */ danw@119: if (pool[r->name] == '/') krh@35: continue; krh@21: u = array_add(unsatisfied, sizeof *u); krh@66: *u = r - (struct razor_property *) set->properties.data; krh@21: } krh@21: } krh@21: } krh@21: krh@21: void krh@21: razor_set_list_unsatisfied(struct razor_set *set) krh@21: { krh@21: struct array unsatisfied; krh@66: struct razor_property *properties, *r; danw@108: uint32_t *u, *end; krh@21: char *pool; krh@21: krh@21: array_init(&unsatisfied); krh@21: razor_set_validate(set, &unsatisfied); krh@21: krh@21: end = unsatisfied.data + unsatisfied.size; krh@66: properties = set->properties.data; krh@21: pool = set->string_pool.data; krh@21: krh@21: for (u = unsatisfied.data; u < end; u++) { krh@66: r = properties + *u; krh@66: if (pool[r->version] == '\0') krh@220: printf("%s not satisfied\n", danw@119: &pool[r->name]); krh@66: else krh@66: printf("%s-%s not satisfied\n", danw@119: &pool[r->name], krh@66: &pool[r->version]); krh@21: } krh@21: krh@21: array_release(&unsatisfied); krh@21: } krh@21: danw@120: #define UPSTREAM_SOURCE 0x80 krh@41: krh@41: struct source { krh@41: struct razor_set *set; danw@108: uint32_t *property_map; danw@127: uint32_t *file_map; krh@41: }; krh@41: krh@79: struct razor_merger { krh@79: struct razor_set *set; krh@79: struct hashtable table; jbowes@227: struct hashtable file_table; jbowes@228: struct hashtable details_table; krh@79: struct source source1; krh@79: struct source source2; krh@79: }; krh@79: krh@79: static struct razor_merger * krh@79: razor_merger_create(struct razor_set *set1, struct razor_set *set2) krh@41: { krh@79: struct razor_merger *merger; krh@41: int count; krh@41: size_t size; krh@41: krh@79: merger = zalloc(sizeof *merger); krh@79: merger->set = razor_set_create(); krh@79: hashtable_init(&merger->table, &merger->set->string_pool); jbowes@227: hashtable_init(&merger->file_table, &merger->set->file_string_pool); jbowes@228: hashtable_init(&merger->details_table, &merger->set->details_string_pool); krh@41: danw@127: merger->source1.set = set1; krh@79: count = set1->properties.size / sizeof (struct razor_property); krh@79: size = count * sizeof merger->source1.property_map[0]; krh@79: merger->source1.property_map = zalloc(size); danw@127: count = set1->files.size / sizeof (struct razor_entry); danw@127: size = count * sizeof merger->source1.file_map[0]; danw@127: merger->source1.file_map = zalloc(size); krh@79: danw@127: merger->source2.set = set2; krh@79: count = set2->properties.size / sizeof (struct razor_property); krh@79: size = count * sizeof merger->source2.property_map[0]; krh@79: merger->source2.property_map = zalloc(size); danw@127: count = set2->files.size / sizeof (struct razor_entry); danw@127: size = count * sizeof merger->source2.file_map[0]; danw@127: merger->source2.file_map = zalloc(size); krh@79: krh@79: return merger; krh@41: } krh@41: krh@33: static void krh@79: add_package(struct razor_merger *merger, krh@41: struct razor_package *package, struct source *source, danw@108: uint32_t flags) krh@33: { krh@33: char *pool; danw@117: struct list *r; krh@41: struct razor_package *p; krh@33: krh@41: pool = source->set->string_pool.data; krh@79: p = array_add(&merger->set->packages, sizeof *p); krh@79: p->name = hashtable_tokenize(&merger->table, &pool[package->name]); danw@120: p->flags = flags; krh@79: p->version = hashtable_tokenize(&merger->table, krh@79: &pool[package->version]); krh@192: p->arch = hashtable_tokenize(&merger->table, krh@192: &pool[package->arch]); danw@127: krh@66: p->properties = package->properties; danw@116: r = list_first(&package->properties, &source->set->property_pool); danw@116: while (r) { danw@117: source->property_map[r->data] = 1; danw@116: r = list_next(r); krh@64: } danw@127: danw@127: p->files = package->files; danw@127: r = list_first(&package->files, &source->set->file_pool); danw@127: while (r) { danw@127: source->file_map[r->data] = 1; danw@127: r = list_next(r); danw@127: } krh@41: } krh@41: danw@108: static uint32_t krh@79: add_property(struct razor_merger *merger, danw@109: const char *name, enum razor_version_relation relation, danw@109: const char *version, int type) krh@41: { krh@41: struct razor_property *p; krh@41: krh@79: p = array_add(&merger->set->properties, sizeof *p); danw@119: p->name = hashtable_tokenize(&merger->table, name); danw@119: p->flags = 0; danw@119: p->type = type; danw@109: p->relation = relation; krh@79: p->version = hashtable_tokenize(&merger->table, version); krh@41: krh@79: return p - (struct razor_property *) merger->set->properties.data; krh@41: } krh@41: krh@41: static void krh@79: merge_properties(struct razor_merger *merger) krh@41: { krh@41: struct razor_property *p1, *p2; krh@79: struct razor_set *set1, *set2; danw@108: uint32_t *map1, *map2; krh@41: int i, j, cmp, count1, count2; krh@41: char *pool1, *pool2; krh@41: krh@79: set1 = merger->source1.set; krh@79: set2 = merger->source2.set; krh@79: map1 = merger->source1.property_map; krh@79: map2 = merger->source2.property_map; krh@79: krh@41: i = 0; krh@41: j = 0; krh@41: pool1 = set1->string_pool.data; krh@41: pool2 = set2->string_pool.data; krh@41: krh@66: count1 = set1->properties.size / sizeof *p1; krh@66: count2 = set2->properties.size / sizeof *p2; krh@41: while (i < count1 || j < count2) { krh@41: if (i < count1 && map1[i] == 0) { krh@41: i++; krh@41: continue; krh@41: } krh@41: if (j < count2 && map2[j] == 0) { krh@41: j++; krh@41: continue; krh@41: } krh@66: p1 = (struct razor_property *) set1->properties.data + i; krh@66: p2 = (struct razor_property *) set2->properties.data + j; krh@41: if (i < count1 && j < count2) danw@119: cmp = strcmp(&pool1[p1->name], &pool2[p2->name]); krh@41: else if (i < count1) krh@41: cmp = -1; krh@41: else krh@41: cmp = 1; krh@41: if (cmp == 0) danw@121: cmp = p1->type - p2->type; danw@121: if (cmp == 0) danw@109: cmp = p1->relation - p2->relation; danw@109: if (cmp == 0) krh@41: cmp = versioncmp(&pool1[p1->version], krh@41: &pool2[p2->version]); krh@41: if (cmp < 0) { krh@79: map1[i++] = add_property(merger, danw@119: &pool1[p1->name], danw@109: p1->relation, krh@69: &pool1[p1->version], danw@119: p1->type); krh@41: } else if (cmp > 0) { krh@79: map2[j++] = add_property(merger, danw@119: &pool2[p2->name], danw@109: p2->relation, krh@69: &pool2[p2->version], danw@119: p2->type); krh@41: } else { krh@79: map1[i++] = map2[j++] = add_property(merger, danw@119: &pool1[p1->name], danw@109: p1->relation, krh@69: &pool1[p1->version], danw@119: p1->type); krh@41: } krh@41: } krh@41: } krh@41: danw@116: static void danw@117: emit_properties(struct list_head *properties, struct array *source_pool, danw@108: uint32_t *map, struct array *pool) krh@41: { danw@117: uint32_t r; danw@117: struct list *p, *q; krh@41: krh@41: r = pool->size / sizeof *q; danw@116: p = list_first(properties, source_pool); danw@116: while (p) { krh@41: q = array_add(pool, sizeof *q); danw@117: q->data = map[p->data]; danw@117: q->flags = p->flags; danw@116: p = list_next(p); krh@33: } krh@33: danw@117: list_set_ptr(properties, r); krh@41: } danw@127: danw@127: static uint32_t danw@127: add_file(struct razor_merger *merger, const char *name) danw@127: { danw@127: struct razor_entry *e; danw@127: danw@127: e = array_add(&merger->set->files, sizeof *e); jbowes@227: e->name = hashtable_tokenize(&merger->file_table, name); danw@127: e->flags = 0; danw@127: e->start = 0; danw@127: danw@127: return e - (struct razor_entry *)merger->set->files.data; danw@127: } danw@127: danw@129: /* FIXME. Blah */ danw@127: static int danw@127: fix_file_map(uint32_t *map, danw@127: struct razor_entry *files, danw@127: struct razor_entry *top) danw@127: { danw@127: uint32_t e; danw@127: int found_file = 0; danw@127: danw@127: e = top->start; danw@127: do { danw@127: if (files[e].start) danw@127: fix_file_map(map, files, &files[e]); danw@127: if (map[e]) danw@127: found_file = 1; danw@127: } while (!(files[e++].flags & RAZOR_ENTRY_LAST)); danw@127: danw@127: if (found_file) danw@127: map[top - files] = 1; danw@127: return found_file; danw@127: } danw@127: danw@127: struct merge_directory { danw@127: uint32_t merged, dir1, dir2; danw@127: }; danw@127: danw@127: static void danw@127: merge_one_directory(struct razor_merger *merger, struct merge_directory *md) danw@127: { danw@127: struct razor_entry *root1, *root2, *mroot, *e1, *e2; danw@127: struct razor_set *set1, *set2; danw@127: struct array merge_stack; danw@127: struct merge_directory *child_md, *end_md; danw@127: uint32_t *map1, *map2, start, last; danw@127: int cmp; danw@127: char *pool1, *pool2; danw@127: danw@127: set1 = merger->source1.set; danw@127: set2 = merger->source2.set; danw@127: map1 = merger->source1.file_map; danw@127: map2 = merger->source2.file_map; danw@127: pool1 = set1->string_pool.data; danw@127: pool2 = set2->string_pool.data; danw@127: root1 = (struct razor_entry *) set1->files.data; danw@127: root2 = (struct razor_entry *) set2->files.data; danw@127: danw@127: array_init(&merge_stack); danw@127: danw@127: start = merger->set->files.size / sizeof (struct razor_entry); danw@127: last = 0; danw@127: e1 = md->dir1 ? root1 + md->dir1 : NULL; danw@127: e2 = md->dir2 ? root2 + md->dir2 : NULL; danw@127: while (e1 || e2) { danw@127: if (!e2 && !map1[e1 - root1]) { danw@127: if ((e1++)->flags & RAZOR_ENTRY_LAST) danw@127: e1 = NULL; danw@127: continue; danw@127: } danw@127: if (!e1 && !map2[e2 - root2]) { danw@127: if ((e2++)->flags & RAZOR_ENTRY_LAST) danw@127: e2 = NULL; danw@127: continue; danw@127: } danw@127: if (e1 && !map1[e1 - root1] && danw@127: e2 && !map1[e2 - root2]) { danw@127: if ((e1++)->flags & RAZOR_ENTRY_LAST) danw@127: e1 = NULL; danw@127: if ((e2++)->flags & RAZOR_ENTRY_LAST) danw@127: e2 = NULL; danw@127: continue; danw@127: } danw@127: danw@127: if (!e1) danw@127: cmp = 1; danw@127: else if (!e2) danw@127: cmp = -1; danw@127: else { danw@127: cmp = strcmp (&pool1[e1->name], danw@127: &pool2[e2->name]); danw@127: } danw@127: danw@127: if (cmp < 0) { danw@127: if (map1[e1 - root1]) { danw@127: map1[e1 - root1] = last = danw@127: add_file(merger, &pool1[e1->name]); danw@127: if (e1->start) { danw@127: child_md = array_add(&merge_stack, sizeof (struct merge_directory)); danw@127: child_md->merged = last; danw@127: child_md->dir1 = e1->start; danw@127: child_md->dir2 = 0; danw@127: } danw@127: } danw@127: if ((e1++)->flags & RAZOR_ENTRY_LAST) danw@127: e1 = NULL; danw@127: } else if (cmp > 0) { danw@127: if (map2[e2 - root2]) { danw@127: map2[e2 - root2] = last = danw@127: add_file(merger, &pool2[e2->name]); danw@127: if (e2->start) { danw@127: child_md = array_add(&merge_stack, sizeof (struct merge_directory)); danw@127: child_md->merged = last; danw@127: child_md->dir1 = 0; danw@127: child_md->dir2 = e2->start; danw@127: } danw@127: } danw@127: if ((e2++)->flags & RAZOR_ENTRY_LAST) danw@127: e2 = NULL; danw@127: } else { danw@127: map1[e1 - root1] = map2[e2- root2] = last = danw@127: add_file(merger, &pool1[e1->name]); danw@127: if (e1->start || e2->start) { danw@127: child_md = array_add(&merge_stack, sizeof (struct merge_directory)); danw@127: child_md->merged = last; danw@127: child_md->dir1 = e1->start; danw@127: child_md->dir2 = e2->start; danw@127: } danw@127: if ((e1++)->flags & RAZOR_ENTRY_LAST) danw@127: e1 = NULL; danw@127: if ((e2++)->flags & RAZOR_ENTRY_LAST) danw@127: e2 = NULL; danw@127: } danw@127: } danw@127: danw@127: mroot = (struct razor_entry *)merger->set->files.data; danw@127: if (last) { danw@127: mroot[last].flags = RAZOR_ENTRY_LAST; danw@127: mroot[md->merged].start = start; danw@127: } else danw@127: mroot[md->merged].start = 0; danw@127: danw@127: end_md = merge_stack.data + merge_stack.size; danw@127: for (child_md = merge_stack.data; child_md < end_md; child_md++) danw@127: merge_one_directory(merger, child_md); danw@127: array_release(&merge_stack); danw@127: } danw@127: danw@127: static void danw@127: merge_files(struct razor_merger *merger) danw@127: { danw@129: struct razor_entry *root; danw@127: struct merge_directory md; danw@127: uint32_t *map1, *map2; danw@127: danw@127: map1 = merger->source1.file_map; danw@127: map2 = merger->source2.file_map; danw@127: danw@164: md.merged = 0; danw@129: danw@129: if (merger->source1.set->files.size) { danw@129: root = (struct razor_entry *) merger->source1.set->files.data; danw@129: if (root->start) danw@129: fix_file_map(map1, root, root); danw@129: md.dir1 = root->start; danw@129: } else danw@129: md.dir1 = 0; danw@129: danw@129: if (merger->source2.set->files.size) { danw@129: root = (struct razor_entry *) merger->source2.set->files.data; danw@129: if (root->start) danw@129: fix_file_map(map2, root, root); danw@129: md.dir2 = root->start; danw@129: } else danw@129: md.dir2 = 0; danw@129: danw@127: merge_one_directory(merger, &md); danw@127: } danw@127: danw@127: static void danw@127: emit_files(struct list_head *files, struct array *source_pool, danw@127: uint32_t *map, struct array *pool) danw@127: { danw@127: uint32_t r; danw@127: struct list *p, *q; danw@127: danw@127: r = pool->size / sizeof *q; danw@127: p = list_first(files, source_pool); danw@127: while (p) { danw@127: q = array_add(pool, sizeof *q); danw@127: q->data = map[p->data]; danw@127: q->flags = p->flags; danw@127: p = list_next(p); danw@127: } danw@127: danw@127: list_set_ptr(files, r); danw@127: } danw@127: krh@41: /* Rebuild property->packages maps. We can't just remap these, as a krh@41: * property may have lost or gained a number of packages. Allocate an krh@41: * array per property and loop through the packages and add them to krh@41: * the arrays for their properties. */ krh@41: static void danw@127: rebuild_property_package_lists(struct razor_set *set) krh@41: { krh@66: struct array *pkgs, *a; krh@41: struct razor_package *pkg, *pkg_end; krh@41: struct razor_property *prop, *prop_end; danw@117: struct list *r; danw@117: uint32_t *q; krh@66: int count; krh@41: krh@66: count = set->properties.size / sizeof (struct razor_property); krh@66: pkgs = zalloc(count * sizeof *pkgs); krh@41: pkg_end = set->packages.data + set->packages.size; krh@41: krh@41: for (pkg = set->packages.data; pkg < pkg_end; pkg++) { danw@128: r = list_first(&pkg->properties, &set->property_pool); danw@116: while (r) { danw@117: q = array_add(&pkgs[r->data], sizeof *q); krh@41: *q = pkg - (struct razor_package *) set->packages.data; danw@116: r = list_next(r); krh@41: } krh@33: } krh@33: krh@66: prop_end = set->properties.data + set->properties.size; krh@66: a = pkgs; krh@66: for (prop = set->properties.data; prop < prop_end; prop++, a++) { danw@128: list_set_array(&prop->packages, &set->package_pool, a, 0); krh@41: array_release(a); krh@41: } krh@66: free(pkgs); krh@33: } krh@33: danw@127: static void danw@127: rebuild_file_package_lists(struct razor_set *set) danw@127: { danw@127: struct array *pkgs, *a; danw@127: struct razor_package *pkg, *pkg_end; danw@127: struct razor_entry *entry, *entry_end; danw@127: struct list *r; danw@127: uint32_t *q; danw@127: int count; danw@127: danw@127: count = set->files.size / sizeof (struct razor_entry); danw@127: pkgs = zalloc(count * sizeof *pkgs); danw@127: pkg_end = set->packages.data + set->packages.size; danw@127: danw@127: for (pkg = set->packages.data; pkg < pkg_end; pkg++) { danw@128: r = list_first(&pkg->files, &set->file_pool); danw@127: while (r) { danw@127: q = array_add(&pkgs[r->data], sizeof *q); danw@127: *q = pkg - (struct razor_package *) set->packages.data; danw@127: r = list_next(r); danw@127: } danw@127: } danw@127: danw@127: entry_end = set->files.data + set->files.size; danw@127: a = pkgs; danw@127: for (entry = set->files.data; entry < entry_end; entry++, a++) { danw@128: list_set_array(&entry->packages, &set->package_pool, a, 0); danw@127: array_release(a); danw@127: } danw@127: free(pkgs); danw@127: } danw@127: danw@137: static struct razor_set * krh@79: razor_merger_finish(struct razor_merger *merger) krh@79: { krh@79: struct razor_set *result; krh@41: struct razor_package *p, *pend; krh@33: krh@41: /* As we built the package list, we filled out a bitvector of krh@41: * the properties that are referenced by the packages in the krh@41: * new set. Now we do a parallel loop through the properties krh@41: * and emit those marked in the bit vector to the new set. In krh@41: * the process, we update the bit vector to actually map from krh@41: * indices in the old property list to indices in the new krh@41: * property list for both sets. */ krh@41: krh@79: merge_properties(merger); danw@127: merge_files(merger); krh@41: krh@41: /* Now we loop through the packages again and emit the krh@41: * property lists, remapped to point to the new properties. */ krh@41: krh@79: pend = merger->set->packages.data + merger->set->packages.size; krh@79: for (p = merger->set->packages.data; p < pend; p++) { krh@41: struct source *src; krh@41: danw@120: if (p->flags & UPSTREAM_SOURCE) krh@79: src = &merger->source2; krh@41: else krh@79: src = &merger->source1; krh@41: danw@116: emit_properties(&p->properties, danw@116: &src->set->property_pool, danw@116: src->property_map, danw@116: &merger->set->property_pool); danw@127: emit_files(&p->files, danw@127: &src->set->file_pool, danw@127: src->file_map, danw@127: &merger->set->file_pool); danw@120: p->flags &= ~UPSTREAM_SOURCE; krh@33: } krh@33: danw@127: rebuild_property_package_lists(merger->set); danw@127: rebuild_file_package_lists(merger->set); krh@41: danw@129: result = merger->set; danw@129: hashtable_release(&merger->table); jbowes@227: hashtable_release(&merger->file_table); jbowes@228: hashtable_release(&merger->details_table); danw@129: free(merger); danw@129: danw@129: return result; danw@129: } danw@129: danw@146: /* The diff order matters. We should sort the packages so that a danw@146: * REMOVE of a package comes before the INSTALL, and so that all danw@146: * requires for a package have been installed before the package. danw@146: **/ danw@146: danw@146: void danw@146: razor_set_diff(struct razor_set *set, struct razor_set *upstream, danw@146: razor_package_callback_t callback, void *data) danw@146: { danw@146: struct razor_package_iterator *pi1, *pi2; danw@146: struct razor_package *p1, *p2; krh@192: const char *name1, *name2, *version1, *version2, *arch1, *arch2; danw@146: int res; danw@146: danw@146: pi1 = razor_package_iterator_create(set); danw@146: pi2 = razor_package_iterator_create(upstream); danw@146: krh@192: razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1); krh@192: razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2); danw@146: danw@146: while (p1 || p2) { danw@146: if (p1 && p2) { danw@146: res = strcmp(name1, name2); danw@146: if (res == 0) danw@146: res = versioncmp(version1, version2); danw@146: } else { danw@146: res = 0; danw@146: } danw@146: danw@146: if (p2 == NULL || res < 0) krh@192: callback(name1, version1, NULL, arch1, data); danw@146: else if (p1 == NULL || res > 0) krh@192: callback(name2, NULL, version2, arch2, data); danw@146: danw@146: if (p1 != NULL && res <= 0) danw@146: razor_package_iterator_next(pi1, &p1, krh@192: &name1, &version1, &arch1); danw@146: if (p2 != NULL && res >= 0) danw@146: razor_package_iterator_next(pi2, &p2, krh@192: &name2, &version2, &arch2); danw@146: } danw@146: danw@146: razor_package_iterator_destroy(pi1); danw@146: razor_package_iterator_destroy(pi2); danw@146: } danw@146: krh@190: struct razor_transaction; krh@190: struct razor_transaction_package; krh@190: struct razor_transaction_resolver; krh@190: krh@190: struct razor_transaction { krh@190: int package_count, errors; krh@190: struct razor_set *system, *upstream; krh@191: krh@191: struct bitarray syspkgs, uppkgs; krh@191: struct array packages; krh@190: }; krh@190: krh@190: struct razor_transaction_package { krh@190: const char *name, *old_version, *new_version; krh@190: struct razor_package *old_package, *new_package; krh@190: enum razor_transaction_package_state state; krh@190: krh@190: /* dep_package is the name of the package that resulted in krh@190: * this entry being created (or NULL if the user requested the krh@190: * install/remove), with the other dep_ fields providing krh@190: * additional information. krh@190: * krh@190: * For INSTALL, if dep_type is REQUIRES, then dep_package krh@190: * required something that this package provides. If dep_type krh@190: * is CONFLICTS, then dep_package is a package that conflicted krh@190: * with an older version of this package, forcing an upgrade. krh@190: * krh@190: * For REMOVE, if dep_type is REQUIRES, then dep_package is a krh@190: * package that is being removed. If dep_type is OBSOLETES, krh@190: * then dep_package is a package that obsoletes this one. krh@190: * krh@190: * For OLD_CONFLICT or NEW_CONFLICT, dep_package is an krh@190: * existing package that conflicts with this one. The krh@190: * conflicting property comes from the already-installed krh@190: * package for OLD_CONFLICT, or the to-be-installed package krh@190: * for NEW_CONFLICT. krh@190: * krh@190: * For UNSATISFIABLE, the dep_ fields are as for an INSTALL, krh@190: * but the name field will be NULL. krh@190: */ krh@190: const char *dep_package; krh@190: enum razor_property_type dep_type; krh@190: const char *dep_property; krh@190: enum razor_version_relation dep_relation; krh@190: const char *dep_version; krh@190: }; danw@141: danw@144: static int danw@144: package_in_set(void *package, struct razor_set *set) danw@144: { danw@144: return package >= set->packages.data && danw@144: package < set->packages.data + set->packages.size; danw@144: } danw@144: danw@144: static int danw@144: property_in_set(void *property, struct razor_set *set) danw@144: { danw@144: return property >= set->properties.data && danw@144: property < set->properties.data + set->properties.size; danw@144: } danw@144: danw@168: static struct razor_package * krh@191: property_provider_package(struct razor_transaction *trans, danw@168: struct razor_property *prop, danw@168: int installed) danw@168: { danw@168: struct razor_set *set; danw@168: struct bitarray *pkgbits; danw@168: struct razor_package *pkgs; danw@168: struct list *p; danw@168: danw@168: if (installed && prop->type != RAZOR_PROPERTY_PROVIDES) danw@168: return NULL; danw@168: else if (!installed && danw@168: prop->type != RAZOR_PROPERTY_PROVIDES && danw@168: prop->type != RAZOR_PROPERTY_OBSOLETES) danw@168: return NULL; danw@168: danw@168: if (property_in_set(prop, trans->system)) { danw@168: set = trans->system; danw@168: pkgbits = &trans->syspkgs; danw@168: } else { danw@168: set = trans->upstream; danw@168: pkgbits = &trans->uppkgs; danw@168: } danw@168: pkgs = set->packages.data; danw@168: danw@168: for (p = list_first(&prop->packages, &set->package_pool); p; p = list_next(p)) { danw@168: if (bitarray_get(pkgbits, p->data) != installed) danw@168: continue; danw@168: if (prop->type == RAZOR_PROPERTY_OBSOLETES || danw@168: pkgs[p->data].name == prop->name) danw@168: return &pkgs[p->data]; danw@168: } danw@168: return NULL; danw@168: } danw@168: danw@144: static int danw@144: compare_transaction_packages(const void *one, const void *two) danw@144: { danw@160: struct razor_transaction_package **tp1 = (void *)one; danw@160: struct razor_transaction_package **tp2 = (void *)two; danw@160: danw@160: if (!(*tp1)->name) danw@160: return 1; danw@160: else if (!(*tp2)->name) danw@160: return -1; danw@160: else danw@160: return strcmp((*tp1)->name, (*tp2)->name); danw@144: } danw@144: danw@168: /* FIXME: merge this into the other property loop in razor_transaction_satisfy */ danw@141: static void krh@191: resolve_new_packages(struct razor_transaction *trans, danw@160: int start, int end) krh@38: { danw@168: struct razor_property *sp, *up, *sp_end, *up_end; danw@168: struct razor_package *spkg, *spkgs, *upkg, *upkgs; danw@160: struct razor_transaction_package **packages; danw@144: const char *spool, *upool; danw@144: int i; danw@144: danw@168: sp_end = trans->system->properties.data + trans->system->properties.size; danw@168: spool = trans->system->string_pool.data; danw@144: spkgs = trans->system->packages.data; danw@168: up_end = trans->upstream->properties.data + trans->upstream->properties.size; danw@168: upool = trans->upstream->string_pool.data; danw@144: upkgs = trans->upstream->packages.data; danw@168: danw@168: /* FIXME, check if sorting the packages directly (rather than danw@168: * sorting pointers-to-packages) still results in confusing danw@168: * descriptions. danw@168: */ danw@160: packages = calloc(end - start, sizeof *packages); danw@160: for (i = start; i < end; i++) danw@160: packages[i - start] = ((struct razor_transaction_package *)trans->packages.data) + i; danw@160: qsort(packages, end - start, sizeof *packages, danw@160: compare_transaction_packages); danw@144: danw@168: sp = trans->system->properties.data; danw@168: up = trans->upstream->properties.data; danw@160: for (i = 0; i < end - start; i++) { danw@169: if (!packages[i]->name || danw@169: packages[i]->state >= RAZOR_PACKAGE_FIRST_ERROR_STATE) danw@160: continue; danw@168: danw@168: spkg = NULL; danw@168: while (sp < sp_end && danw@168: strcmp(&spool[sp->name], packages[i]->name) < 0) danw@144: sp++; danw@168: while (sp < sp_end && danw@168: strcmp(&spool[sp->name], packages[i]->name) == 0 && danw@168: !(spkg = property_provider_package(trans, sp, 1))) danw@168: sp++; danw@168: danw@168: upkg = NULL; danw@168: while (up < up_end && danw@168: strcmp(&upool[up->name], packages[i]->name) < 0) danw@168: up++; danw@168: while (up < up_end && danw@168: strcmp(&upool[up->name], packages[i]->name) == 0 && danw@168: !(upkg = property_provider_package(trans, up, 0))) danw@144: up++; danw@144: danw@160: if (packages[i]->state == RAZOR_PACKAGE_REMOVE || danw@160: packages[i]->state == RAZOR_PACKAGE_OBSOLETED) { danw@168: if (spkg) { danw@168: packages[i]->old_package = spkg; danw@168: packages[i]->name = &spool[spkg->name]; danw@168: packages[i]->old_version = &spool[spkg->version]; danw@168: bitarray_set(&trans->syspkgs, spkg - spkgs, 0); danw@169: } danw@169: if (!packages[i]->old_package) { danw@160: packages[i]->name = strdup(packages[i]->name); danw@169: packages[i]->state |= RAZOR_PACKAGE_UNAVAILABLE_FLAG; danw@144: trans->errors++; danw@144: } danw@144: } else { danw@168: if (upkg) { danw@168: packages[i]->new_package = upkg; danw@168: packages[i]->name = &upool[upkg->name]; danw@168: packages[i]->new_version = &upool[upkg->version]; danw@168: danw@168: if (up->name != upkg->name) { danw@168: packages[i]->dep_package = &upool[upkg->name]; danw@168: packages[i]->dep_type = up->type; danw@168: packages[i]->dep_property = &upool[up->name]; danw@168: packages[i]->dep_relation = up->relation; danw@168: packages[i]->dep_version = &upool[up->version]; danw@168: } danw@168: danw@168: if (spkg) { danw@168: packages[i]->old_package = spkg; danw@168: packages[i]->old_version = &spool[spkg->version]; danw@168: if (versioncmp(&spool[spkg->version], &upool[up->version]) >= 0) { danw@160: packages[i]->state = RAZOR_PACKAGE_UP_TO_DATE; danw@144: trans->errors++; danw@144: continue; danw@144: } danw@168: bitarray_set(&trans->syspkgs, spkg - spkgs, 0); danw@144: } danw@168: bitarray_set(&trans->uppkgs, upkg - upkgs, 1); danw@169: } danw@169: if (!packages[i]->new_package) { danw@160: packages[i]->name = strdup(packages[i]->name); danw@169: packages[i]->state |= RAZOR_PACKAGE_UNAVAILABLE_FLAG; danw@144: trans->errors++; krh@105: } krh@105: } krh@38: } krh@38: } krh@38: danw@137: static int danw@137: provider_satisfies_requirement(struct razor_property *provider, danw@137: const char *provider_strings, danw@137: struct razor_property *requirement, danw@137: const char *requirement_strings) danw@137: { danw@137: int cmp, len; danw@137: const char *provided = &provider_strings[provider->version]; danw@137: const char *required = &requirement_strings[requirement->version]; danw@137: danw@137: if (!*required) danw@137: return 1; danw@170: if (!*provided) { danw@170: if (requirement->relation >= RAZOR_VERSION_EQUAL) danw@170: return 1; danw@170: else danw@170: return 0; danw@170: } danw@137: danw@137: cmp = versioncmp(provided, required); danw@137: danw@137: switch (requirement->relation) { danw@137: case RAZOR_VERSION_LESS: danw@137: return cmp < 0; danw@137: danw@137: case RAZOR_VERSION_LESS_OR_EQUAL: danw@137: if (cmp <= 0) danw@137: return 1; danw@137: /* fall through: FIXME, make sure this is correct */ danw@137: danw@137: case RAZOR_VERSION_EQUAL: danw@137: if (cmp == 0) danw@137: return 1; danw@137: danw@137: /* "foo == 1.1" is satisfied by "foo 1.1-2" */ danw@137: len = strlen(required); danw@137: if (!strncmp(required, provided, len) && provided[len] == '-') danw@137: return 1; danw@137: return 0; danw@137: danw@137: case RAZOR_VERSION_GREATER_OR_EQUAL: danw@137: return cmp >= 0; danw@137: danw@137: case RAZOR_VERSION_GREATER: danw@137: return cmp > 0; danw@137: } danw@137: danw@137: /* shouldn't happen */ danw@137: return 0; danw@137: } danw@137: danw@142: static struct razor_package * danw@144: find_package_for_file(struct razor_set *set, struct bitarray *pkgbits, danw@144: const char *filename, int installed) danw@134: { danw@142: struct razor_package *pkgs = set->packages.data; danw@140: struct razor_entry *entry; danw@140: struct list *p; danw@134: danw@140: if (filename[0] != '/') danw@140: return 0; danw@140: danw@142: entry = find_entry(set, set->files.data, filename); danw@140: if (!entry) danw@140: return 0; danw@140: danw@142: for (p = list_first(&entry->packages, &set->package_pool); p; p = list_next(p)) { danw@142: if (bitarray_get(pkgbits, p->data) == installed) danw@142: return &pkgs[p->data]; danw@134: } danw@142: return NULL; danw@142: } danw@142: danw@142: static struct razor_package * krh@191: find_installed_package_for_file(struct razor_transaction *trans, danw@144: const char *filename) danw@142: { danw@144: struct razor_package *pkg; danw@144: danw@144: pkg = find_package_for_file(trans->system, &trans->syspkgs, danw@144: filename, 1); danw@144: if (!pkg) danw@144: pkg = find_package_for_file(trans->upstream, &trans->uppkgs, danw@144: filename, 1); danw@144: return pkg; danw@142: } danw@142: danw@142: static struct razor_package * krh@191: find_uninstalled_package_for_file(struct razor_transaction *trans, danw@144: const char *filename) danw@142: { danw@144: struct razor_package *pkg; danw@144: danw@144: pkg = find_package_for_file(trans->upstream, &trans->uppkgs, danw@144: filename, 0); danw@144: if (!pkg) danw@144: pkg = find_package_for_file(trans->system, &trans->syspkgs, danw@144: filename, 0); danw@144: return pkg; danw@134: } danw@134: danw@154: static struct razor_property * krh@191: skip_to_matching_property(struct razor_transaction *trans, danw@154: struct razor_property *match, danw@154: struct razor_property *prop) danw@154: { danw@154: struct razor_set *mset, *pset; danw@154: const char *ppool, *mpool; danw@154: struct razor_property *prop_end; danw@154: danw@154: if (property_in_set(match, trans->system)) danw@154: mset = trans->system; danw@154: else danw@154: mset = trans->upstream; danw@154: danw@154: if (property_in_set(prop, trans->system)) danw@154: pset = trans->system; danw@154: else if (property_in_set(prop, trans->upstream)) danw@154: pset = trans->upstream; danw@154: else danw@154: return prop; danw@154: danw@154: prop_end = pset->properties.data + pset->properties.size; danw@154: ppool = pset->string_pool.data; danw@154: mpool = mset->string_pool.data; danw@154: danw@154: while (prop < prop_end && danw@154: strcmp(&ppool[prop->name], &mpool[match->name]) < 0) danw@154: prop++; danw@154: return prop; danw@154: } danw@154: danw@140: static struct razor_package * krh@191: find_package_matching(struct razor_transaction *trans, int installed, danw@154: struct razor_property *prop, danw@144: struct razor_property *req, danw@144: struct razor_set *req_set) danw@138: { danw@144: struct razor_set *set; danw@144: struct bitarray *pkgbits; danw@144: struct razor_package *pkgs; danw@154: struct razor_property *props, *prop_end; danw@144: enum razor_property_type match_type; danw@144: const char *pool; danw@154: const char *rpool; danw@154: int match_name = (req->type == RAZOR_PROPERTY_OBSOLETES); danw@144: int match; danw@144: danw@144: if (property_in_set(prop, trans->system)) { danw@144: set = trans->system; danw@144: pkgbits = &trans->syspkgs; danw@144: } else if (property_in_set(prop, trans->upstream)) { danw@144: set = trans->upstream; danw@144: pkgbits = &trans->uppkgs; danw@144: } else danw@144: return NULL; danw@144: danw@154: if (!req_set) { danw@154: if (property_in_set(req, trans->system)) danw@154: req_set = trans->system; danw@154: else danw@154: req_set = trans->upstream; danw@154: } danw@154: rpool = req_set->string_pool.data; danw@154: danw@144: if (req->type == RAZOR_PROPERTY_PROVIDES) danw@144: match_type = RAZOR_PROPERTY_CONFLICTS; danw@144: else danw@144: match_type = RAZOR_PROPERTY_PROVIDES; danw@144: danw@144: pkgs = set->packages.data; danw@144: props = set->properties.data; danw@144: prop_end = set->properties.data + set->properties.size; danw@144: pool = set->string_pool.data; danw@144: danw@144: /* Find first matching property */ danw@144: while (prop < prop_end && danw@144: strcmp(&pool[prop->name], &rpool[req->name]) < 0) danw@144: prop++; danw@144: if (prop == prop_end || danw@144: strcmp(&pool[prop->name], &rpool[req->name]) > 0) danw@144: return NULL; danw@144: danw@144: if (prop->type < match_type) { danw@144: while (prop < prop_end && prop->type != match_type) danw@144: prop++; danw@144: } else { danw@144: while (prop >= props && prop->type != match_type) danw@144: prop--; danw@183: while (prop > props + 1 && (prop - 1)->name == prop->name && danw@183: (prop - 1)->type == match_type) danw@144: prop--; danw@144: } danw@144: danw@153: /* Scan matching properties */ danw@144: while (prop < prop_end && prop->type == match_type && danw@144: strcmp(&pool[prop->name], &rpool[req->name]) == 0) { danw@144: if (match_type == RAZOR_PROPERTY_PROVIDES) danw@144: match = provider_satisfies_requirement(prop, pool, req, rpool); danw@144: else danw@144: match = provider_satisfies_requirement(req, rpool, prop, pool); danw@144: if (match) { danw@140: struct list *pkg; danw@140: danw@144: for (pkg = list_first(&prop->packages, &set->package_pool); pkg; pkg = list_next(pkg)) { danw@144: if (bitarray_get(pkgbits, pkg->data) != installed) danw@140: continue; danw@140: if (!match_name || danw@144: strcmp(&pool[pkgs[pkg->data].name], danw@144: &rpool[req->name]) == 0) danw@144: return &pkgs[pkg->data]; danw@140: } danw@140: } danw@144: prop++; danw@140: } danw@140: danw@140: return NULL; danw@138: } danw@138: danw@140: static struct razor_package * krh@191: find_installed_package_for_property(struct razor_transaction *trans, danw@154: struct razor_property *sys_start, danw@154: struct razor_property *up_start, danw@144: struct razor_property *req) danw@138: { danw@144: struct razor_package *pkg; danw@144: danw@154: pkg = find_package_matching(trans, 1, sys_start, req, NULL); danw@144: if (!pkg) danw@154: pkg = find_package_matching(trans, 1, up_start, req, NULL); danw@144: return pkg; danw@144: } danw@144: danw@144: static struct razor_package * krh@191: find_uninstalled_package_for_property(struct razor_transaction *trans, danw@154: struct razor_property *sys_start, danw@154: struct razor_property *up_start, danw@144: struct razor_property *req) danw@144: { danw@144: struct razor_package *pkg; danw@144: danw@154: pkg = find_package_matching(trans, 0, up_start, req, NULL); danw@144: if (!pkg) danw@154: pkg = find_package_matching(trans, 0, sys_start, req, NULL); danw@144: return pkg; danw@140: } danw@140: danw@147: static struct razor_transaction_package * krh@191: find_transaction_package(struct razor_transaction *trans, const char *name) danw@147: { danw@147: struct razor_transaction_package *packages; danw@147: int count, i; danw@147: danw@147: packages = trans->packages.data; danw@147: count = trans->packages.size / sizeof *packages; danw@147: for (i = 0; i < count; i++) { danw@147: if (packages[i].name && !strcmp(packages[i].name, name)) danw@147: return &packages[i]; danw@147: } danw@147: return NULL; danw@147: } danw@147: danw@160: /* FIXME? */ danw@160: static int krh@191: prop_is_being_installed(struct razor_transaction *trans, danw@160: struct razor_property *prop) danw@160: { danw@160: struct list *pkg; danw@160: danw@160: for (pkg = list_first(&prop->packages, &trans->upstream->package_pool); pkg; pkg = list_next(pkg)) { danw@160: if (bitarray_get(&trans->uppkgs, pkg->data)) danw@160: return 1; danw@160: } danw@160: return 0; danw@160: } danw@160: danw@160: static int krh@191: prop_is_being_removed(struct razor_transaction *trans, danw@160: struct razor_property *prop) danw@160: { danw@160: struct list *pkg; danw@160: danw@160: for (pkg = list_first(&prop->packages, &trans->system->package_pool); pkg; pkg = list_next(pkg)) { danw@160: if (bitarray_get(&trans->syspkgs, pkg->data)) danw@160: return 0; danw@160: } danw@160: return 1; danw@160: } danw@160: danw@160: static int krh@191: prop_is_being_updated(struct razor_transaction *trans, danw@160: struct razor_property *prop) danw@160: { danw@160: struct razor_package *packages = trans->system->packages.data; danw@160: const char *pool = trans->system->string_pool.data; danw@160: struct razor_transaction_package *tp; danw@160: struct list *pkg; danw@160: danw@160: /* Assumes prop_is_being_removed returns true */ danw@160: danw@160: for (pkg = list_first(&prop->packages, &trans->system->package_pool); pkg; pkg = list_next(pkg)) { danw@160: tp = find_transaction_package(trans, &pool[packages[pkg->data].name]); danw@160: if (tp && tp->state == RAZOR_PACKAGE_REMOVE) danw@160: return 0; danw@160: } danw@160: return 1; danw@160: } danw@160: danw@131: static void krh@191: add_transaction_package(struct razor_transaction *trans, danw@147: struct razor_package *new_package, danw@147: struct razor_package *old_package, danw@140: enum razor_transaction_package_state state, danw@144: const char *req_package, danw@144: struct razor_property *req_prop) danw@131: { danw@147: struct razor_set *new_package_set, *old_package_set, *req_set; danw@160: struct bitarray *reqpkgbits; danw@147: struct razor_transaction_package *tp, *already; danw@140: const char *pool; danw@140: struct razor_package *pkgs; danw@140: struct list *pkg; danw@147: int contradiction = 0; danw@147: danw@160: if (package_in_set(new_package, trans->system)) danw@147: new_package_set = trans->system; danw@160: else danw@147: new_package_set = trans->upstream; danw@160: if (package_in_set(old_package, trans->system)) danw@147: old_package_set = trans->system; danw@160: else danw@147: old_package_set = trans->upstream; danw@145: if (property_in_set(req_prop, trans->system)) { danw@145: req_set = trans->system; danw@145: reqpkgbits = &trans->syspkgs; danw@145: } else { danw@145: req_set = trans->upstream; danw@145: reqpkgbits = &trans->uppkgs; danw@145: } danw@144: danw@147: if (new_package) { danw@147: pool = new_package_set->string_pool.data; danw@147: already = find_transaction_package(trans, &pool[new_package->name]); danw@147: if (already) { danw@147: if (already->new_package == new_package) { danw@147: /* Already taken care of */ danw@147: return; danw@166: } else if (new_package_set == trans->upstream && danw@166: already->state == RAZOR_PACKAGE_FORCED_UPDATE) { danw@166: already->new_package = new_package; danw@166: return; krh@209: } else if (new_package_set == trans->upstream) { krh@209: return; danw@147: } danw@166: danw@147: /* Oops. We lose */ danw@147: if (state != RAZOR_PACKAGE_CONTRADICTION) danw@147: contradiction = 1; danw@147: } danw@147: } else if (old_package) { danw@147: pool = old_package_set->string_pool.data; danw@147: already = find_transaction_package(trans, &pool[old_package->name]); danw@147: if (already) { danw@147: if (already->old_package == old_package) { danw@147: /* Already taken care of */ danw@147: return; danw@166: } else if (old_package_set == trans->system) { danw@166: already->old_package = old_package; danw@166: return; danw@147: } danw@166: danw@147: /* Oops. We lose */ danw@147: if (state != RAZOR_PACKAGE_CONTRADICTION) danw@147: contradiction = 1; danw@147: } danw@147: } else danw@147: state = RAZOR_PACKAGE_UNSATISFIABLE; danw@147: danw@141: tp = array_add(&trans->packages, sizeof *tp); danw@140: memset(tp, 0, sizeof *tp); danw@131: danw@147: if (new_package) { danw@147: pool = new_package_set->string_pool.data; danw@147: tp->new_package = new_package; danw@147: tp->name = &pool[new_package->name]; danw@147: tp->new_version = &pool[new_package->version]; danw@147: danw@147: pkgs = new_package_set->packages.data; danw@147: } danw@147: if (old_package) { danw@147: pool = old_package_set->string_pool.data; danw@147: tp->old_package = old_package; danw@147: tp->name = &pool[old_package->name]; danw@147: tp->old_version = &pool[old_package->version]; danw@147: danw@147: pkgs = old_package_set->packages.data; danw@147: } danw@147: danw@147: tp->state = state; danw@147: if (state != RAZOR_PACKAGE_INSTALL && danw@154: state != RAZOR_PACKAGE_FORCED_UPDATE && danw@154: state != RAZOR_PACKAGE_REMOVE && danw@154: state != RAZOR_PACKAGE_OBSOLETED) danw@145: trans->errors++; danw@147: danw@147: if (contradiction) { danw@147: /* Do this now, after adding tp, so that it ends up danw@147: * after both the INSTALL and the REMOVE in the array. danw@147: */ danw@147: add_transaction_package(trans, new_package, old_package, danw@147: RAZOR_PACKAGE_CONTRADICTION, danw@147: NULL, NULL); danw@145: } danw@140: danw@144: if (req_package) danw@145: tp->dep_package = req_package; danw@145: if (!req_prop) danw@145: return; danw@145: danw@145: pool = req_set->string_pool.data; danw@145: pkgs = req_set->packages.data; danw@145: if (!req_package) { danw@145: for (pkg = list_first(&req_prop->packages, &req_set->package_pool); pkg; pkg = list_next(pkg)) { danw@145: if (bitarray_get(reqpkgbits, pkg->data)) danw@144: break; danw@144: } danw@145: if (pkg) danw@145: tp->dep_package = &pool[pkgs[pkg->data].name]; danw@131: } danw@144: danw@145: tp->dep_type = req_prop->type; danw@145: tp->dep_property = &pool[req_prop->name]; danw@145: tp->dep_relation = req_prop->relation; danw@145: tp->dep_version = &pool[req_prop->version]; danw@140: } danw@140: danw@160: static void krh@191: razor_transaction_satisfy(struct razor_transaction *trans) danw@147: { danw@160: struct razor_package *spkgs, *upkgs, *pkg; danw@144: struct razor_property *sp, *sprops, *sprop_end; danw@144: struct razor_property *up, *uprops, *uprop_end; danw@160: struct razor_property *sr, *ur, *first_up; danw@160: const char *spool, *upool, *removed_package; danw@160: struct list *reqpkg; danw@134: danw@140: spkgs = trans->system->packages.data; danw@140: sprops = trans->system->properties.data; danw@144: sprop_end = trans->system->properties.data + trans->system->properties.size; danw@145: spool = trans->system->string_pool.data; danw@140: upkgs = trans->upstream->packages.data; danw@140: uprops = trans->upstream->properties.data; danw@144: uprop_end = trans->upstream->properties.data + trans->upstream->properties.size; danw@140: upool = trans->upstream->string_pool.data; krh@33: danw@144: sp = sprops; danw@160: for (up = uprops; up < uprop_end; up++) { danw@140: /* Skip 'up' ahead to a property of a package which is danw@140: * to-be-installed. danw@140: */ danw@144: while (up < uprop_end && danw@144: !prop_is_being_installed(trans, up)) danw@140: up++; danw@144: if (up == uprop_end) danw@140: break; danw@154: sp = skip_to_matching_property(trans, up, sp); krh@33: danw@144: switch (up->type) { danw@140: case RAZOR_PROPERTY_REQUIRES: danw@144: if (!strncmp(&upool[up->name], "rpmlib(", 7)) danw@140: break; danw@131: danw@154: if (find_installed_package_for_property(trans, sp, up, up) || danw@144: find_installed_package_for_file(trans, &upool[up->name])) { danw@140: /* Requires something that is either installed danw@140: * or to-be-installed. danw@140: */ danw@140: break; danw@137: } danw@137: danw@140: /* See if we can install a new upstream provider */ danw@154: pkg = find_uninstalled_package_for_property(trans, sp, up, up); danw@154: if (!pkg) danw@144: pkg = find_uninstalled_package_for_file(trans, &upool[up->name]); danw@160: add_transaction_package(trans, pkg, NULL, danw@144: RAZOR_PACKAGE_INSTALL, danw@144: NULL, up); danw@144: break; danw@144: danw@144: case RAZOR_PROPERTY_PROVIDES: danw@144: /* find_installed_package_for_property works backwards danw@144: * here, finding a *conflicting* installed package. danw@144: */ danw@154: pkg = find_installed_package_for_property(trans, sp, up, up); danw@140: if (!pkg) danw@144: break; danw@144: danw@145: if (package_in_set(pkg, trans->system)) { danw@145: /* pkg CONFLICTS with what 'up' PROVIDES. Try danw@145: * finding an upgrade danw@145: */ danw@160: add_transaction_package(trans, NULL, pkg, danw@160: RAZOR_PACKAGE_FORCED_UPDATE, danw@165: &upool[up->name], sp); danw@160: } else { danw@160: add_transaction_package(trans, NULL, pkg, danw@160: RAZOR_PACKAGE_CONTRADICTION, danw@160: NULL, up); danw@144: } danw@140: break; danw@140: danw@140: case RAZOR_PROPERTY_CONFLICTS: danw@154: pkg = find_installed_package_for_property(trans, sp, up, up); danw@144: if (!pkg) danw@144: break; danw@144: danw@144: if (package_in_set(pkg, trans->system)) { danw@140: /* Conflicts with something already installed. danw@140: * Try to upgrade out. danw@140: */ danw@160: add_transaction_package(trans, NULL, pkg, danw@160: RAZOR_PACKAGE_FORCED_UPDATE, danw@160: NULL, up); danw@160: } else { danw@160: add_transaction_package(trans, pkg, NULL, danw@160: RAZOR_PACKAGE_CONTRADICTION, danw@160: NULL, up); danw@140: } danw@140: break; danw@140: danw@140: case RAZOR_PROPERTY_OBSOLETES: danw@154: pkg = find_installed_package_for_property(trans, sp, up, up); danw@145: if (pkg) { danw@145: /* If pkg is to-be-installed, this danw@145: * will add a CONTRADICTION error as well. danw@145: */ danw@147: add_transaction_package(trans, NULL, pkg, danw@154: RAZOR_PACKAGE_OBSOLETED, danw@144: NULL, up); danw@140: } danw@140: break; danw@140: danw@140: default: danw@140: /* can't happen */ danw@140: break; danw@131: } krh@37: } danw@154: danw@154: up = uprops; danw@154: for (sp = sprops; sp < sprop_end; sp++) { danw@154: /* Skip 'sp' ahead to a PROVIDES of a package which is danw@154: * to-be-removed. danw@154: */ danw@154: while (sp < sprop_end && danw@154: (sp->type != RAZOR_PROPERTY_PROVIDES || danw@154: !prop_is_being_removed(trans, sp))) danw@154: sp++; danw@154: if (sp == sprop_end) danw@154: break; danw@154: danw@154: removed_package = &spool[spkgs[list_first(&sp->packages, &trans->system->package_pool)->data].name]; danw@154: danw@154: /* Skip 'up' to match */ danw@154: up = skip_to_matching_property(trans, sp, up); danw@154: ur = first_up = up; danw@154: danw@154: /* If the package is just being upgraded, we may danw@154: * already be installing an identical PROVIDES, so danw@154: * check for that. danw@154: */ danw@154: while (up < uprop_end && danw@154: strcmp(&spool[sp->name], &upool[up->name]) == 0 && danw@154: (up->type != RAZOR_PROPERTY_PROVIDES || danw@154: sp->relation != up->relation || danw@154: strcmp(&spool[sp->name], &upool[up->name]) != 0)) danw@154: up++; danw@154: if (up < uprop_end && danw@154: up->type == RAZOR_PROPERTY_PROVIDES && danw@154: strcmp(&spool[sp->name], &upool[up->name]) == 0 && danw@154: sp->relation == up->relation && danw@154: strcmp(&spool[sp->version], &upool[up->version]) == 0 && danw@154: prop_is_being_installed(trans, up)) { danw@154: up = first_up; danw@154: continue; danw@154: } danw@154: up = first_up; danw@154: danw@154: /* For all still-installed packages that require danw@154: * sp->name, see if they are satisfied by any other danw@154: * still-installed or to-be-installed property. If danw@154: * not, either remove or attempt to update the danw@154: * package, depending on why the required property has danw@154: * disappeared danw@154: */ danw@154: sr = sp; danw@154: while (sr > sprops + 1 && (sr - 1)->name == sr->name) danw@154: sr--; danw@154: for (; sr->type == RAZOR_PROPERTY_REQUIRES; sr++) { danw@154: if (prop_is_being_removed(trans, sr)) danw@154: continue; danw@154: if (find_installed_package_for_property(trans, sp, up, sr)) danw@154: continue; danw@154: danw@154: for (reqpkg = list_first(&sr->packages, &trans->system->package_pool); reqpkg; reqpkg = list_next(reqpkg)) { danw@154: if (!bitarray_get(&trans->syspkgs, reqpkg->data)) danw@154: continue; danw@154: pkg = &spkgs[reqpkg->data]; danw@154: if (prop_is_being_updated(trans, sp)) { danw@160: add_transaction_package(trans, NULL, pkg, danw@160: RAZOR_PACKAGE_FORCED_UPDATE, danw@160: removed_package, NULL); danw@154: } else { danw@154: add_transaction_package(trans, NULL, pkg, danw@154: RAZOR_PACKAGE_REMOVE, danw@154: removed_package, sr); danw@154: } danw@154: } danw@154: } danw@154: } danw@154: } danw@129: krh@208: void krh@208: razor_transaction_install_package(struct razor_transaction *transaction, krh@208: struct razor_package *package) krh@208: { krh@208: add_transaction_package(transaction, package, NULL, krh@208: RAZOR_PACKAGE_INSTALL, NULL, NULL); krh@208: } krh@208: krh@208: void krh@208: razor_transaction_remove_package(struct razor_transaction *transaction, krh@208: struct razor_package *package) krh@208: { krh@208: add_transaction_package(transaction, NULL, package, krh@208: RAZOR_PACKAGE_REMOVE, NULL, NULL); krh@208: } krh@208: krh@208: void krh@208: razor_transaction_update_all(struct razor_transaction *trans) krh@208: { krh@208: struct razor_package *sp, *spkgs, *send, *up, *upkgs, *uend; krh@208: const char *spool, *upool; krh@208: krh@208: spkgs = trans->system->packages.data; krh@208: send = trans->system->packages.data + trans->system->packages.size; krh@208: spool = trans->system->string_pool.data; krh@208: up = upkgs = trans->upstream->packages.data; krh@208: uend = trans->upstream->packages.data + trans->upstream->packages.size; krh@208: upool = trans->upstream->string_pool.data; krh@208: krh@208: for (sp = spkgs; sp < send; sp++) { krh@208: while (up < uend && strcmp(&spool[sp->name], &upool[up->name]) > 0) krh@208: up++; krh@208: if (strcmp(&spool[sp->name], &upool[up->name]) == 0 && krh@208: versioncmp(&spool[sp->version], &upool[up->version]) < 0) { krh@208: add_transaction_package(trans, up, sp, krh@208: RAZOR_PACKAGE_INSTALL, krh@208: NULL, NULL); krh@208: } krh@208: } krh@208: } krh@208: danw@137: struct razor_transaction * krh@208: razor_transaction_create(struct razor_set *system, struct razor_set *upstream) danw@137: { krh@191: struct razor_transaction *trans; krh@208: int count; danw@137: krh@191: trans = zalloc(sizeof *trans); krh@191: krh@191: trans->system = system; krh@191: trans->upstream = upstream ? upstream : razor_set_create(); krh@191: array_init(&trans->packages); krh@208: count = trans->system->packages.size / sizeof (struct razor_package); krh@208: bitarray_init(&trans->syspkgs, count, 1); krh@208: count = trans->upstream->packages.size / sizeof (struct razor_package); krh@208: bitarray_init(&trans->uppkgs, count, 0); krh@208: krh@208: return trans; krh@208: } krh@208: krh@208: static void krh@208: resolve_transaction(struct razor_transaction *trans) krh@208: { krh@208: int start, end; krh@208: krh@208: if (trans->package_count > 0) krh@208: /* Already did this, return. */ krh@208: return; danw@137: danw@137: start = 0; krh@191: end = trans->packages.size / sizeof (struct razor_transaction_package); danw@137: danw@160: while (start != end) { krh@191: resolve_new_packages(trans, start, end); krh@191: if (trans->errors) danw@160: break; danw@160: krh@191: razor_transaction_satisfy(trans); danw@137: danw@137: start = end; krh@191: end = trans->packages.size / sizeof (struct razor_transaction_package); danw@137: } danw@137: krh@191: trans->package_count = end; danw@137: } danw@137: danw@137: const char * const razor_version_relations[] = { danw@137: /* same order as enum razor_version_relation */ danw@137: "<", "<=", "=", ">=", ">" danw@137: }; danw@137: danw@140: const char * const razor_property_types[] = { danw@140: /* same order as enum razor_property_type */ danw@140: "requires", "provides", "conflicts with", "obsoletes" danw@140: }; danw@140: danw@169: static void danw@169: print_requirement(struct razor_transaction_package *p) danw@169: { danw@169: if (p->dep_type == RAZOR_PROPERTY_CONFLICTS && danw@169: !strcmp(p->dep_package, p->name)) { danw@169: printf(" because %s %s conflicts with %s", danw@169: p->name, p->old_version, p->dep_property); danw@169: if (*p->dep_version) { danw@169: printf(" %s %s", danw@169: razor_version_relations[p->dep_relation], danw@169: p->dep_version); danw@169: } danw@169: } else { danw@169: if (strcmp(p->name, p->dep_package) != 0) danw@169: printf(" for %s", p->dep_package); danw@169: if (*p->dep_version) { danw@169: printf(", which %s %s %s %s", danw@169: razor_property_types[p->dep_type], danw@169: p->dep_property, danw@169: razor_version_relations[p->dep_relation], danw@169: p->dep_version); danw@169: } else if (strcmp(p->dep_property, p->name) != 0) { danw@169: printf(", which %s %s", danw@169: razor_property_types[p->dep_type], danw@169: p->dep_property); danw@169: } danw@169: } danw@169: } danw@169: krh@190: int krh@210: razor_transaction_resolve(struct razor_transaction *trans) danw@137: { danw@137: struct razor_transaction_package *p, *pend, *tps; danw@137: int errors_only = 0; danw@137: krh@208: resolve_transaction(trans); krh@208: krh@191: tps = trans->packages.data; krh@191: pend = trans->packages.data + trans->packages.size; krh@191: for (p = trans->packages.data; p < pend; p++) { danw@137: switch (p->state) { danw@137: case RAZOR_PACKAGE_INSTALL: danw@137: if (errors_only) danw@137: break; danw@137: danw@147: printf("Installing %s %s", p->name, p->new_version); danw@169: if (p->dep_package) danw@169: print_requirement(p); danw@137: printf("\n"); danw@137: break; danw@137: danw@154: case RAZOR_PACKAGE_FORCED_UPDATE: danw@154: if (errors_only) danw@154: break; danw@154: danw@154: printf("Updating %s to %s due to update of %s\n", danw@154: p->name, p->new_version, p->dep_package); danw@154: break; danw@154: danw@137: case RAZOR_PACKAGE_REMOVE: danw@137: if (errors_only) danw@137: break; danw@147: printf("Removing %s %s", p->name, p->old_version); danw@145: if (p->dep_package) { danw@154: printf(" which required %s", danw@154: p->dep_package); danw@162: if (strcmp(p->dep_property, p->dep_package) != 0) danw@154: printf(" for %s", p->dep_property); danw@154: } danw@154: printf("\n"); danw@154: break; danw@154: danw@154: case RAZOR_PACKAGE_OBSOLETED: danw@154: if (errors_only) danw@154: break; danw@154: printf("Removing %s %s", p->name, p->old_version); danw@154: if (p->dep_package) { danw@154: printf(" which is obsoleted by %s", danw@154: p->dep_package); danw@137: } danw@137: printf("\n"); danw@137: break; danw@137: danw@145: case RAZOR_PACKAGE_INSTALL_UNAVAILABLE: danw@169: printf("Error: can't find %s", p->name); danw@169: if (p->dep_package) { danw@169: printf(" (which is required"); danw@169: print_requirement(p); danw@169: printf(")"); danw@169: } danw@169: printf("\n"); danw@169: errors_only = 1; danw@169: break; danw@169: danw@169: case RAZOR_PACKAGE_UPDATE_UNAVAILABLE: danw@169: printf("Error: can't find an updated version of %s (which must be updated due to update of %s)\n", danw@169: p->name, p->dep_package); danw@137: errors_only = 1; danw@137: break; danw@137: danw@145: case RAZOR_PACKAGE_REMOVE_NOT_INSTALLED: danw@145: printf("Error: can't remove %s: not installed\n", p->name); danw@137: errors_only = 1; danw@137: break; danw@137: danw@145: case RAZOR_PACKAGE_UP_TO_DATE: danw@169: printf("Error: can't update %s", p->name); danw@169: if (p->dep_package) danw@169: printf(" (which must be updated due to update of %s)", p->dep_package); danw@169: printf(": %s is most recent version\n", p->old_version); danw@145: errors_only = 1; danw@145: break; danw@145: danw@145: case RAZOR_PACKAGE_CONTRADICTION: danw@147: printf("Error: package %s is marked for both installation and removal\n", p->name); danw@145: errors_only = 1; danw@145: break; danw@145: danw@145: case RAZOR_PACKAGE_OLD_CONFLICT: danw@145: printf("Error: can't install %s, because installed package %s conflicts with ", danw@145: p->name, p->dep_package); danw@145: if (*p->dep_version) { danw@145: printf("%s %s %s", danw@145: p->dep_property, danw@145: razor_version_relations[p->dep_relation], danw@145: p->dep_version); danw@145: } else danw@145: printf("it"); danw@145: printf("\n"); danw@145: danw@145: errors_only = 1; danw@145: break; danw@145: danw@145: case RAZOR_PACKAGE_NEW_CONFLICT: danw@145: printf("Error: can't install %s, because it conflicts with %s", danw@145: p->name, p->dep_package); danw@145: if (*p->dep_version) { danw@145: printf(" %s %s", danw@145: razor_version_relations[p->dep_relation], danw@145: p->dep_version); danw@145: } danw@145: printf("\n"); danw@145: danw@145: errors_only = 1; danw@145: break; danw@145: danw@145: case RAZOR_PACKAGE_UNSATISFIABLE: danw@145: printf("Error: can't find package for %s", p->dep_property); danw@145: if (*p->dep_version) { danw@145: printf(" %s %s", danw@145: razor_version_relations[p->dep_relation], danw@145: p->dep_version); danw@145: } danw@145: printf(" which is required by %s\n", danw@145: p->dep_package); danw@140: errors_only = 1; danw@140: break; danw@140: danw@137: default: danw@137: /* Shouldn't actually happen */ danw@137: break; danw@137: } danw@137: } krh@190: krh@190: return trans->errors; krh@190: } krh@190: krh@190: int krh@190: razor_transaction_unsatisfied_property(struct razor_transaction *trans, krh@190: const char *name, krh@190: enum razor_version_relation rel, krh@190: const char *version) krh@190: { krh@190: struct razor_transaction_package *p, *end; krh@190: krh@191: end = trans->packages.data + trans->packages.size; krh@191: for (p = trans->packages.data; p < end; p++) { krh@190: if (p->state != RAZOR_PACKAGE_UNSATISFIABLE) krh@190: continue; krh@190: if (strcmp(name, p->dep_property) != 0 || krh@190: rel != p->dep_relation || krh@190: strcmp(version, p->dep_version) != 0) krh@190: continue; krh@190: krh@190: return 1; krh@190: } krh@190: krh@190: return 0; danw@137: } danw@137: danw@137: struct razor_set * krh@196: razor_transaction_finish(struct razor_transaction *trans) danw@137: { danw@137: struct array install_packages, remove_packages; danw@137: struct razor_merger *merger; danw@137: struct razor_package *pkg, *i, *iend, *r, *rend, *s, *send; krh@196: struct razor_set *set; danw@137: struct source *source1, *source2; danw@137: char *spool, *ipool, *rpool; danw@137: uint32_t *map; krh@191: struct razor_transaction_package *p, *end; krh@191: int cmp; danw@137: danw@137: /* FIXME */ danw@137: if (trans->errors) danw@137: return NULL; danw@137: danw@137: /* Sort the transaction packages into two arrays */ danw@137: array_init(&install_packages); danw@137: array_init(&remove_packages); krh@191: krh@191: end = trans->packages.data + trans->packages.size; krh@191: for (p = trans->packages.data; p < end; p++) { krh@191: if (p->new_package) { danw@137: pkg = array_add(&install_packages, sizeof *pkg); krh@191: *pkg = *p->new_package; danw@147: } else { danw@137: pkg = array_add(&remove_packages, sizeof *pkg); krh@191: *pkg = *p->old_package; danw@147: } danw@137: } krh@186: map = razor_qsort_with_data(install_packages.data, krh@186: install_packages.size / sizeof *pkg, krh@186: sizeof *pkg, krh@186: compare_packages, krh@186: trans->upstream); danw@137: free(map); krh@186: map = razor_qsort_with_data(remove_packages.data, krh@186: remove_packages.size / sizeof *pkg, krh@186: sizeof *pkg, krh@186: compare_packages, krh@186: trans->system); danw@137: free(map); danw@137: danw@137: merger = razor_merger_create(trans->system, trans->upstream); danw@137: danw@137: source1 = &merger->source1; danw@137: source2 = &merger->source2; danw@137: danw@137: i = install_packages.data; danw@137: iend = install_packages.data + install_packages.size; danw@137: ipool = trans->upstream->string_pool.data; danw@137: danw@137: r = remove_packages.data; danw@137: rend = remove_packages.data + remove_packages.size; danw@137: rpool = trans->system->string_pool.data; danw@137: danw@137: s = trans->system->packages.data; danw@137: send = trans->system->packages.data + trans->system->packages.size; danw@137: spool = trans->system->string_pool.data; danw@137: danw@137: while (s < send || i < iend) { danw@137: /* Check if s is being removed */ danw@137: if (s < send && r < rend && danw@137: s->name == r->name && s->version && r->version) { danw@137: s++; danw@137: r++; danw@137: continue; danw@137: } danw@137: danw@137: if (s < send && i < iend) danw@137: cmp = strcmp(&spool[s->name], &ipool[i->name]); danw@137: else if (s < send) danw@137: cmp = -1; danw@137: else danw@137: cmp = 1; danw@137: if (cmp < 0) { danw@137: add_package(merger, s, source1, 0); danw@137: s++; danw@137: } else if (cmp == 0) { danw@137: add_package(merger, i, source2, UPSTREAM_SOURCE); danw@137: s++; danw@137: i++; danw@137: } else { danw@137: add_package(merger, i, source2, UPSTREAM_SOURCE); danw@137: i++; danw@137: } danw@137: } danw@137: danw@137: array_release(&install_packages); danw@137: array_release(&remove_packages); danw@137: krh@196: set = razor_merger_finish(merger); krh@196: razor_transaction_destroy(trans); krh@196: krh@196: return set; danw@137: } danw@137: danw@137: void danw@137: razor_transaction_destroy(struct razor_transaction *trans) danw@137: { krh@191: struct razor_transaction_package *p, *end; krh@191: krh@191: end = trans->packages.data + trans->packages.size; krh@191: for (p = trans->packages.data; p < end; p++) { krh@191: if (!p->dep_package && krh@191: (p->state == RAZOR_PACKAGE_INSTALL_UNAVAILABLE || krh@191: p->state == RAZOR_PACKAGE_REMOVE_NOT_INSTALLED)) krh@191: free((char *)p->name); danw@137: } krh@195: krh@195: array_release(&trans->packages); krh@195: bitarray_release(&trans->syspkgs); krh@195: bitarray_release(&trans->uppkgs); danw@137: free(trans); danw@137: danw@137: /* FIXME: free upstream if it was created as an empty set */ danw@137: } krh@216: krh@216: struct razor_package_query { krh@216: struct razor_set *set; krh@216: char *vector; krh@216: int count; krh@216: }; krh@216: krh@216: struct razor_package_query * krh@216: razor_package_query_create(struct razor_set *set) krh@216: { krh@216: struct razor_package_query *pq; krh@216: int count; krh@216: krh@216: pq = zalloc(sizeof *pq); krh@216: pq->set = set; krh@216: count = set->packages.size / sizeof(struct razor_package); krh@216: pq->vector = zalloc(count * sizeof(char)); krh@216: krh@216: return pq; krh@216: } krh@216: krh@216: void krh@216: razor_package_query_add_package(struct razor_package_query *pq, krh@216: struct razor_package *p) krh@216: { krh@216: struct razor_package *packages; krh@216: krh@216: packages = pq->set->packages.data; krh@216: pq->count += pq->vector[p - packages] ^ 1; krh@216: pq->vector[p - packages] = 1; krh@216: } krh@216: krh@216: void krh@216: razor_package_query_add_iterator(struct razor_package_query *pq, krh@216: struct razor_package_iterator *pi) krh@216: { krh@216: struct razor_package *packages, *p; krh@216: const char *name, *version, *arch; krh@216: krh@216: packages = pq->set->packages.data; krh@216: while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) { krh@216: pq->count += pq->vector[p - packages] ^ 1; krh@216: pq->vector[p - packages] = 1; krh@216: } krh@216: } krh@216: krh@216: struct razor_package_iterator * krh@216: razor_package_query_finish(struct razor_package_query *pq) krh@216: { krh@216: struct razor_package_iterator *pi; krh@216: struct razor_set *set; krh@216: struct list *index; krh@216: int i, j, count; krh@216: krh@216: set = pq->set; krh@216: count = set->packages.size / sizeof(struct razor_package); krh@216: index = zalloc(pq->count * sizeof *index); krh@216: krh@216: for (i = 0, j = 0; i < count; i++) { krh@216: if (!pq->vector[i]) krh@216: continue; krh@216: krh@216: index[j].data = i; krh@216: if (j == pq->count - 1) krh@216: index[j].flags = 0x80; krh@216: j++; krh@216: } krh@216: krh@216: free(pq); krh@216: krh@216: pi = razor_package_iterator_create_with_index(set, index); krh@216: pi->free_index = 1; krh@216: krh@216: return pi; krh@216: }