1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/librazor/razor.c Mon Jun 16 17:54:29 2008 -0400
1.3 @@ -0,0 +1,2611 @@
1.4 +/*
1.5 + * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
1.6 + * Copyright (C) 2008 Red Hat, Inc
1.7 + *
1.8 + * This program is free software; you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation; either version 2 of the License, or
1.11 + * (at your option) any later version.
1.12 + *
1.13 + * This program is distributed in the hope that it will be useful,
1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.16 + * GNU General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU General Public License along
1.19 + * with this program; if not, write to the Free Software Foundation, Inc.,
1.20 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.21 + */
1.22 +
1.23 +#define _GNU_SOURCE
1.24 +
1.25 +#include <stdlib.h>
1.26 +#include <stddef.h>
1.27 +#include <stdint.h>
1.28 +#include <stdio.h>
1.29 +#include <string.h>
1.30 +#include <sys/types.h>
1.31 +#include <sys/stat.h>
1.32 +#include <sys/mman.h>
1.33 +#include <unistd.h>
1.34 +#include <fcntl.h>
1.35 +#include <errno.h>
1.36 +#include <ctype.h>
1.37 +#include <fnmatch.h>
1.38 +
1.39 +#include "razor.h"
1.40 +#include "razor-internal.h"
1.41 +#include "types.h"
1.42 +
1.43 +struct razor_set_section {
1.44 + uint32_t type;
1.45 + uint32_t offset;
1.46 + uint32_t size;
1.47 +};
1.48 +
1.49 +struct razor_set_header {
1.50 + uint32_t magic;
1.51 + uint32_t version;
1.52 + struct razor_set_section sections[0];
1.53 +};
1.54 +
1.55 +#define RAZOR_MAGIC 0x7a7a7a7a
1.56 +#define RAZOR_VERSION 1
1.57 +
1.58 +#define RAZOR_STRING_POOL 0
1.59 +#define RAZOR_PACKAGES 1
1.60 +#define RAZOR_PROPERTIES 2
1.61 +#define RAZOR_FILES 3
1.62 +#define RAZOR_PACKAGE_POOL 4
1.63 +#define RAZOR_PROPERTY_POOL 5
1.64 +#define RAZOR_FILE_POOL 6
1.65 +
1.66 +struct razor_package {
1.67 + uint name : 24;
1.68 + uint flags : 8;
1.69 + uint32_t version;
1.70 + uint32_t arch;
1.71 + struct list_head properties;
1.72 + struct list_head files;
1.73 +};
1.74 +
1.75 +struct razor_property {
1.76 + uint name : 24;
1.77 + uint flags : 6;
1.78 + enum razor_property_type type : 2;
1.79 + enum razor_version_relation relation : 32;
1.80 + uint32_t version;
1.81 + struct list_head packages;
1.82 +};
1.83 +
1.84 +struct razor_entry {
1.85 + uint name : 24;
1.86 + uint flags : 8;
1.87 + uint32_t start;
1.88 + struct list_head packages;
1.89 +};
1.90 +
1.91 +#define RAZOR_ENTRY_LAST 0x80
1.92 +
1.93 +struct razor_set {
1.94 + struct array string_pool;
1.95 + struct array packages;
1.96 + struct array properties;
1.97 + struct array files;
1.98 + struct array package_pool;
1.99 + struct array property_pool;
1.100 + struct array file_pool;
1.101 + struct razor_set_header *header;
1.102 +};
1.103 +
1.104 +struct import_entry {
1.105 + uint32_t package;
1.106 + char *name;
1.107 +};
1.108 +
1.109 +struct import_directory {
1.110 + uint32_t name, count;
1.111 + struct array files;
1.112 + struct array packages;
1.113 + struct import_directory *last;
1.114 +};
1.115 +
1.116 +struct razor_importer {
1.117 + struct razor_set *set;
1.118 + struct hashtable table;
1.119 + struct razor_package *package;
1.120 + struct array properties;
1.121 + struct array files;
1.122 + struct array file_requires;
1.123 +};
1.124 +
1.125 +static void *
1.126 +zalloc(size_t size)
1.127 +{
1.128 + void *p;
1.129 +
1.130 + p = malloc(size);
1.131 + memset(p, 0, size);
1.132 +
1.133 + return p;
1.134 +}
1.135 +
1.136 +struct razor_set_section razor_sections[] = {
1.137 + { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
1.138 + { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
1.139 + { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
1.140 + { RAZOR_FILES, offsetof(struct razor_set, files) },
1.141 + { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
1.142 + { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
1.143 + { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
1.144 +};
1.145 +
1.146 +struct razor_set *
1.147 +razor_set_create(void)
1.148 +{
1.149 + struct razor_set *set;
1.150 + struct razor_entry *e;
1.151 + char *empty;
1.152 +
1.153 + set = zalloc(sizeof *set);
1.154 +
1.155 + e = array_add(&set->files, sizeof *e);
1.156 + empty = array_add(&set->string_pool, 1);
1.157 + *empty = '\0';
1.158 + e->name = 0;
1.159 + e->flags = RAZOR_ENTRY_LAST;
1.160 + e->start = 0;
1.161 + list_set_empty(&e->packages);
1.162 +
1.163 + return set;
1.164 +}
1.165 +
1.166 +struct razor_set *
1.167 +razor_set_open(const char *filename)
1.168 +{
1.169 + struct razor_set *set;
1.170 + struct razor_set_section *s;
1.171 + struct stat stat;
1.172 + struct array *array;
1.173 + int fd;
1.174 +
1.175 + set = zalloc(sizeof *set);
1.176 + fd = open(filename, O_RDONLY);
1.177 + if (fstat(fd, &stat) < 0)
1.178 + return NULL;
1.179 + set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1.180 + if (set->header == MAP_FAILED) {
1.181 + free(set);
1.182 + return NULL;
1.183 + }
1.184 +
1.185 + for (s = set->header->sections; ~s->type; s++) {
1.186 + if (s->type >= ARRAY_SIZE(razor_sections))
1.187 + continue;
1.188 + if (s->type != razor_sections[s->type].type)
1.189 + continue;
1.190 + array = (void *) set + razor_sections[s->type].offset;
1.191 + array->data = (void *) set->header + s->offset;
1.192 + array->size = s->size;
1.193 + array->alloc = s->size;
1.194 + }
1.195 + close(fd);
1.196 +
1.197 + return set;
1.198 +}
1.199 +
1.200 +void
1.201 +razor_set_destroy(struct razor_set *set)
1.202 +{
1.203 + unsigned int size;
1.204 + struct array *a;
1.205 + int i;
1.206 +
1.207 + if (set->header) {
1.208 + for (i = 0; set->header->sections[i].type; i++)
1.209 + ;
1.210 + size = set->header->sections[i].type;
1.211 + munmap(set->header, size);
1.212 + } else {
1.213 + for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
1.214 + a = (void *) set + razor_sections[i].offset;
1.215 + free(a->data);
1.216 + }
1.217 + }
1.218 +
1.219 + free(set);
1.220 +}
1.221 +
1.222 +int
1.223 +razor_set_write_to_fd(struct razor_set *set, int fd)
1.224 +{
1.225 + char data[4096];
1.226 + struct razor_set_header *header = (struct razor_set_header *) data;
1.227 + struct array *a;
1.228 + uint32_t offset;
1.229 + int i;
1.230 +
1.231 + memset(data, 0, sizeof data);
1.232 + header->magic = RAZOR_MAGIC;
1.233 + header->version = RAZOR_VERSION;
1.234 + offset = sizeof data;
1.235 +
1.236 + for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
1.237 + if (razor_sections[i].type != i)
1.238 + continue;
1.239 + a = (void *) set + razor_sections[i].offset;
1.240 + header->sections[i].type = i;
1.241 + header->sections[i].offset = offset;
1.242 + header->sections[i].size = a->size;
1.243 + offset += ALIGN(a->size, 4096);
1.244 + }
1.245 +
1.246 + header->sections[i].type = ~0;
1.247 + header->sections[i].offset = 0;
1.248 + header->sections[i].size = 0;
1.249 +
1.250 + razor_write(fd, data, sizeof data);
1.251 + memset(data, 0, sizeof data);
1.252 + for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
1.253 + if (razor_sections[i].type != i)
1.254 + continue;
1.255 + a = (void *) set + razor_sections[i].offset;
1.256 + razor_write(fd, a->data, a->size);
1.257 + razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
1.258 + }
1.259 +
1.260 + return 0;
1.261 +}
1.262 +
1.263 +int
1.264 +razor_set_write(struct razor_set *set, const char *filename)
1.265 +{
1.266 + int fd, status;
1.267 +
1.268 + fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
1.269 + if (fd < 0)
1.270 + return -1;
1.271 +
1.272 + status = razor_set_write_to_fd(set, fd);
1.273 + if (status) {
1.274 + close(fd);
1.275 + return status;
1.276 + }
1.277 +
1.278 + return close(fd);
1.279 +}
1.280 +
1.281 +void
1.282 +razor_build_evr(char *evr_buf, int size, const char *epoch,
1.283 + const char *version, const char *release)
1.284 +{
1.285 + int len;
1.286 +
1.287 + if (!version || !*version) {
1.288 + *evr_buf = '\0';
1.289 + return;
1.290 + }
1.291 +
1.292 + if (epoch && *epoch && strcmp(epoch, "0") != 0) {
1.293 + len = snprintf(evr_buf, size, "%s:", epoch);
1.294 + evr_buf += len;
1.295 + size -= len;
1.296 + }
1.297 + len = snprintf(evr_buf, size, "%s", version);
1.298 + evr_buf += len;
1.299 + size -= len;
1.300 + if (release && *release)
1.301 + snprintf(evr_buf, size, "-%s", release);
1.302 +}
1.303 +
1.304 +void
1.305 +razor_importer_begin_package(struct razor_importer *importer,
1.306 + const char *name,
1.307 + const char *version,
1.308 + const char *arch)
1.309 +{
1.310 + struct razor_package *p;
1.311 +
1.312 + p = array_add(&importer->set->packages, sizeof *p);
1.313 + p->name = hashtable_tokenize(&importer->table, name);
1.314 + p->flags = 0;
1.315 + p->version = hashtable_tokenize(&importer->table, version);
1.316 + p->arch = hashtable_tokenize(&importer->table, arch);
1.317 +
1.318 + importer->package = p;
1.319 + array_init(&importer->properties);
1.320 +}
1.321 +
1.322 +void
1.323 +razor_importer_finish_package(struct razor_importer *importer)
1.324 +{
1.325 + list_set_array(&importer->package->properties,
1.326 + &importer->set->property_pool,
1.327 + &importer->properties,
1.328 + 1);
1.329 +
1.330 + array_release(&importer->properties);
1.331 +}
1.332 +
1.333 +void
1.334 +razor_importer_add_property(struct razor_importer *importer,
1.335 + const char *name,
1.336 + enum razor_version_relation relation,
1.337 + const char *version,
1.338 + enum razor_property_type type)
1.339 +{
1.340 + struct razor_property *p;
1.341 + uint32_t *r;
1.342 +
1.343 + p = array_add(&importer->set->properties, sizeof *p);
1.344 + p->name = hashtable_tokenize(&importer->table, name);
1.345 + p->flags = 0;
1.346 + p->type = type;
1.347 + p->relation = relation;
1.348 + p->version = hashtable_tokenize(&importer->table, version);
1.349 + list_set_ptr(&p->packages, importer->package -
1.350 + (struct razor_package *) importer->set->packages.data);
1.351 +
1.352 + r = array_add(&importer->properties, sizeof *r);
1.353 + *r = p - (struct razor_property *) importer->set->properties.data;
1.354 +
1.355 + if (type == RAZOR_PROPERTY_REQUIRES && *name == '/') {
1.356 + r = array_add(&importer->file_requires, sizeof *r);
1.357 + *r = p->name;
1.358 + }
1.359 +}
1.360 +
1.361 +void
1.362 +razor_importer_add_file(struct razor_importer *importer, const char *name)
1.363 +{
1.364 + struct import_entry *e;
1.365 +
1.366 + e = array_add(&importer->files, sizeof *e);
1.367 +
1.368 + e->package = importer->package -
1.369 + (struct razor_package *) importer->set->packages.data;
1.370 + e->name = strdup(name);
1.371 +}
1.372 +
1.373 +struct razor_importer *
1.374 +razor_importer_new(void)
1.375 +{
1.376 + struct razor_importer *importer;
1.377 +
1.378 + importer = zalloc(sizeof *importer);
1.379 + importer->set = razor_set_create();
1.380 + hashtable_init(&importer->table, &importer->set->string_pool);
1.381 +
1.382 + return importer;
1.383 +}
1.384 +
1.385 +/* Destroy an importer without creating the set. */
1.386 +void
1.387 +razor_importer_destroy(struct razor_importer *importer)
1.388 +{
1.389 + /* FIXME: write this */
1.390 +}
1.391 +
1.392 +static int
1.393 +versioncmp(const char *s1, const char *s2)
1.394 +{
1.395 + const char *p1, *p2;
1.396 + long n1, n2;
1.397 + int res;
1.398 +
1.399 + n1 = strtol(s1, (char **) &p1, 10);
1.400 + n2 = strtol(s2, (char **) &p2, 10);
1.401 +
1.402 + /* Epoch; if one but not the other has an epoch set, default
1.403 + * the epoch-less version to 0. */
1.404 + res = (*p1 == ':') - (*p2 == ':');
1.405 + if (res < 0) {
1.406 + n1 = 0;
1.407 + p1 = s1;
1.408 + p2++;
1.409 + } else if (res > 0) {
1.410 + p1++;
1.411 + n2 = 0;
1.412 + p2 = s2;
1.413 + }
1.414 +
1.415 + if (n1 != n2)
1.416 + return n1 - n2;
1.417 + while (*p1 && *p2) {
1.418 + if (*p1 != *p2)
1.419 + return *p1 - *p2;
1.420 + p1++;
1.421 + p2++;
1.422 + if (isdigit(*p1) && isdigit(*p2))
1.423 + return versioncmp(p1, p2);
1.424 + }
1.425 +
1.426 + return *p1 - *p2;
1.427 +}
1.428 +
1.429 +static int
1.430 +compare_packages(const void *p1, const void *p2, void *data)
1.431 +{
1.432 + const struct razor_package *pkg1 = p1, *pkg2 = p2;
1.433 + struct razor_set *set = data;
1.434 + char *pool = set->string_pool.data;
1.435 +
1.436 + /* FIXME: what if the flags are different? */
1.437 + if (pkg1->name == pkg2->name)
1.438 + return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
1.439 + else
1.440 + return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
1.441 +}
1.442 +
1.443 +static int
1.444 +compare_properties(const void *p1, const void *p2, void *data)
1.445 +{
1.446 + const struct razor_property *prop1 = p1, *prop2 = p2;
1.447 + struct razor_set *set = data;
1.448 + char *pool = set->string_pool.data;
1.449 +
1.450 + if (prop1->name != prop2->name)
1.451 + return strcmp(&pool[prop1->name], &pool[prop2->name]);
1.452 + else if (prop1->type != prop2->type)
1.453 + return prop1->type - prop2->type;
1.454 + else if (prop1->relation != prop2->relation)
1.455 + return prop1->relation - prop2->relation;
1.456 + else
1.457 + return versioncmp(&pool[prop1->version], &pool[prop2->version]);
1.458 +}
1.459 +
1.460 +static uint32_t *
1.461 +uniqueify_properties(struct razor_set *set)
1.462 +{
1.463 + struct razor_property *rp, *up, *rp_end;
1.464 + struct array *pkgs, *p;
1.465 + struct list_head *r;
1.466 + uint32_t *map, *rmap;
1.467 + int i, count, unique;
1.468 +
1.469 + count = set->properties.size / sizeof(struct razor_property);
1.470 + map = razor_qsort_with_data(set->properties.data,
1.471 + count,
1.472 + sizeof(struct razor_property),
1.473 + compare_properties,
1.474 + set);
1.475 +
1.476 + rp_end = set->properties.data + set->properties.size;
1.477 + rmap = malloc(count * sizeof *map);
1.478 + pkgs = zalloc(count * sizeof *pkgs);
1.479 + for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
1.480 + if (rp->name != up->name || rp->type != up->type ||
1.481 + rp->relation != up->relation || rp->version != up->version) {
1.482 + up++;
1.483 + up->name = rp->name;
1.484 + up->flags = 0;
1.485 + up->type = rp->type;
1.486 + up->relation = rp->relation;
1.487 + up->version = rp->version;
1.488 + }
1.489 +
1.490 + unique = up - (struct razor_property *) set->properties.data;
1.491 + rmap[map[i]] = unique;
1.492 + r = array_add(&pkgs[unique], sizeof *r);
1.493 + *r = rp->packages;
1.494 + }
1.495 + free(map);
1.496 +
1.497 + if (up != rp)
1.498 + up++;
1.499 + set->properties.size = (void *) up - set->properties.data;
1.500 + rp_end = up;
1.501 + for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
1.502 + list_set_array(&rp->packages, &set->package_pool, p, 0);
1.503 + array_release(p);
1.504 + }
1.505 +
1.506 + free(pkgs);
1.507 +
1.508 + return rmap;
1.509 +}
1.510 +
1.511 +static int
1.512 +compare_filenames(const void *p1, const void *p2, void *data)
1.513 +{
1.514 + const struct import_entry *e1 = p1;
1.515 + const struct import_entry *e2 = p2;
1.516 + const char *n1 = e1->name;
1.517 + const char *n2 = e2->name;
1.518 +
1.519 + /* Need to make sure that the contents of a directory
1.520 + * are sorted immediately after it. So "foo/bar" has to
1.521 + * sort before "foo.conf"
1.522 + *
1.523 + * FIXME: this is about 60% slower than strcmp
1.524 + */
1.525 + while (*n1 && *n2) {
1.526 + if (*n1 < *n2)
1.527 + return *n2 == '/' ? 1 : -1;
1.528 + else if (*n1 > *n2)
1.529 + return *n1 == '/' ? -1 : 1;
1.530 + n1++;
1.531 + n2++;
1.532 + }
1.533 + if (*n1)
1.534 + return 1;
1.535 + else if (*n2)
1.536 + return -1;
1.537 + else
1.538 + return 0;
1.539 +}
1.540 +
1.541 +static void
1.542 +count_entries(struct import_directory *d)
1.543 +{
1.544 + struct import_directory *p, *end;
1.545 +
1.546 + p = d->files.data;
1.547 + end = d->files.data + d->files.size;
1.548 + d->count = 0;
1.549 + while (p < end) {
1.550 + count_entries(p);
1.551 + d->count += p->count + 1;
1.552 + p++;
1.553 + }
1.554 +}
1.555 +
1.556 +static void
1.557 +serialize_files(struct razor_set *set,
1.558 + struct import_directory *d, struct array *array)
1.559 +{
1.560 + struct import_directory *p, *end;
1.561 + struct razor_entry *e = NULL;
1.562 + uint32_t s;
1.563 +
1.564 + p = d->files.data;
1.565 + end = d->files.data + d->files.size;
1.566 + s = array->size / sizeof *e + d->files.size / sizeof *p;
1.567 + while (p < end) {
1.568 + e = array_add(array, sizeof *e);
1.569 + e->name = p->name;
1.570 + e->flags = 0;
1.571 + e->start = p->count > 0 ? s : 0;
1.572 + s += p->count;
1.573 +
1.574 + list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
1.575 + array_release(&p->packages);
1.576 + p++;
1.577 + }
1.578 + if (e != NULL)
1.579 + e->flags |= RAZOR_ENTRY_LAST;
1.580 +
1.581 + p = d->files.data;
1.582 + end = d->files.data + d->files.size;
1.583 + while (p < end) {
1.584 + serialize_files(set, p, array);
1.585 + p++;
1.586 + }
1.587 +}
1.588 +
1.589 +static void
1.590 +remap_property_package_links(struct array *properties, uint32_t *rmap)
1.591 +{
1.592 + struct razor_property *p, *end;
1.593 +
1.594 + end = properties->data + properties->size;
1.595 + for (p = properties->data; p < end; p++)
1.596 + list_remap_head(&p->packages, rmap);
1.597 +}
1.598 +
1.599 +static void
1.600 +build_file_tree(struct razor_importer *importer)
1.601 +{
1.602 + int count, i, length;
1.603 + struct import_entry *filenames;
1.604 + char *f, *end;
1.605 + uint32_t name, *r;
1.606 + char dirname[256];
1.607 + struct import_directory *d, root;
1.608 + struct razor_entry *e;
1.609 +
1.610 + count = importer->files.size / sizeof (struct import_entry);
1.611 + razor_qsort_with_data(importer->files.data,
1.612 + count,
1.613 + sizeof (struct import_entry),
1.614 + compare_filenames,
1.615 + NULL);
1.616 +
1.617 + root.name = hashtable_tokenize(&importer->table, "");
1.618 + array_init(&root.files);
1.619 + array_init(&root.packages);
1.620 + root.last = NULL;
1.621 +
1.622 + filenames = importer->files.data;
1.623 + for (i = 0; i < count; i++) {
1.624 + f = filenames[i].name;
1.625 + if (*f != '/')
1.626 + continue;
1.627 + f++;
1.628 +
1.629 + d = &root;
1.630 + while (*f) {
1.631 + end = strchr(f, '/');
1.632 + if (end == NULL)
1.633 + end = f + strlen(f);
1.634 + length = end - f;
1.635 + memcpy(dirname, f, length);
1.636 + dirname[length] ='\0';
1.637 + name = hashtable_tokenize(&importer->table, dirname);
1.638 + if (d->last == NULL || d->last->name != name) {
1.639 + d->last = array_add(&d->files, sizeof *d);
1.640 + d->last->name = name;
1.641 + d->last->last = NULL;
1.642 + array_init(&d->last->files);
1.643 + array_init(&d->last->packages);
1.644 + }
1.645 + d = d->last;
1.646 + f = end + 1;
1.647 + if (*end == '\0')
1.648 + break;
1.649 + }
1.650 +
1.651 + r = array_add(&d->packages, sizeof *r);
1.652 + *r = filenames[i].package;
1.653 + free(filenames[i].name);
1.654 + }
1.655 +
1.656 + count_entries(&root);
1.657 + e = importer->set->files.data;
1.658 + e->name = root.name;
1.659 + e->flags = RAZOR_ENTRY_LAST;
1.660 + e->start = importer->files.size ? 1 : 0;
1.661 + list_set_empty(&e->packages);
1.662 +
1.663 + serialize_files(importer->set, &root, &importer->set->files);
1.664 +
1.665 + array_release(&importer->files);
1.666 +}
1.667 +
1.668 +static struct razor_entry *
1.669 +find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern);
1.670 +
1.671 +static void
1.672 +list_to_array(struct list *list, struct array *array)
1.673 +{
1.674 + uint32_t *item;
1.675 +
1.676 + while (list) {
1.677 + item = array_add(array, sizeof *item);
1.678 + *item = list->data;
1.679 + list = list_next(list);
1.680 + }
1.681 +}
1.682 +
1.683 +static int
1.684 +compare_file_requires(const void *p1, const void *p2, void *data)
1.685 +{
1.686 + uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
1.687 + const char *pool = data;
1.688 +
1.689 + return strcmp(&pool[*f1], &pool[*f2]);
1.690 +}
1.691 +
1.692 +static void
1.693 +find_file_provides(struct razor_importer *importer)
1.694 +{
1.695 + struct razor_property *prop;
1.696 + struct razor_entry *top, *entry;
1.697 + struct razor_package *packages;
1.698 + struct array pkgprops;
1.699 + struct list *pkg;
1.700 + uint32_t *req, *req_start, *req_end;
1.701 + uint32_t *map, *newprop;
1.702 + char *pool;
1.703 +
1.704 + pool = importer->set->string_pool.data;
1.705 + packages = importer->set->packages.data;
1.706 + top = importer->set->files.data;
1.707 +
1.708 + req = req_start = importer->file_requires.data;
1.709 + req_end = importer->file_requires.data + importer->file_requires.size;
1.710 + map = razor_qsort_with_data(req, req_end - req, sizeof *req,
1.711 + compare_file_requires, pool);
1.712 + free(map);
1.713 +
1.714 + for (req = req_start; req < req_end; req++) {
1.715 + if (req > req_start && req[0] == req[-1])
1.716 + continue;
1.717 + entry = find_entry(importer->set, top, &pool[*req]);
1.718 + if (!entry)
1.719 + continue;
1.720 +
1.721 + for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
1.722 + prop = array_add(&importer->set->properties, sizeof *prop);
1.723 + prop->name = *req;
1.724 + prop->type = RAZOR_PROPERTY_PROVIDES;
1.725 + prop->relation = RAZOR_VERSION_EQUAL;
1.726 + prop->version = hashtable_tokenize(&importer->table, "");
1.727 + list_set_ptr(&prop->packages, pkg->data);
1.728 +
1.729 + /* Update property list of pkg */
1.730 + array_init(&pkgprops);
1.731 + list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
1.732 + newprop = array_add(&pkgprops, sizeof *newprop);
1.733 + *newprop = prop - (struct razor_property *)importer->set->properties.data;
1.734 + list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
1.735 + array_release(&pkgprops);
1.736 + }
1.737 + }
1.738 +
1.739 + array_release(&importer->file_requires);
1.740 +}
1.741 +
1.742 +static void
1.743 +build_package_file_lists(struct razor_set *set, uint32_t *rmap)
1.744 +{
1.745 + struct razor_package *p, *packages;
1.746 + struct array *pkgs;
1.747 + struct razor_entry *e, *end;
1.748 + struct list *r;
1.749 + uint32_t *q;
1.750 + int i, count;
1.751 +
1.752 + count = set->packages.size / sizeof *p;
1.753 + pkgs = zalloc(count * sizeof *pkgs);
1.754 +
1.755 + end = set->files.data + set->files.size;
1.756 + for (e = set->files.data; e < end; e++) {
1.757 + list_remap_head(&e->packages, rmap);
1.758 + r = list_first(&e->packages, &set->package_pool);
1.759 + while (r) {
1.760 + q = array_add(&pkgs[r->data], sizeof *q);
1.761 + *q = e - (struct razor_entry *) set->files.data;
1.762 + r = list_next(r);
1.763 + }
1.764 + }
1.765 +
1.766 + packages = set->packages.data;
1.767 + for (i = 0; i < count; i++) {
1.768 + list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
1.769 + array_release(&pkgs[i]);
1.770 + }
1.771 + free(pkgs);
1.772 +}
1.773 +
1.774 +struct razor_set *
1.775 +razor_importer_finish(struct razor_importer *importer)
1.776 +{
1.777 + struct razor_set *set;
1.778 + uint32_t *map, *rmap;
1.779 + int i, count;
1.780 +
1.781 + build_file_tree(importer);
1.782 + find_file_provides(importer);
1.783 +
1.784 + map = uniqueify_properties(importer->set);
1.785 + list_remap_pool(&importer->set->property_pool, map);
1.786 + free(map);
1.787 +
1.788 + count = importer->set->packages.size / sizeof(struct razor_package);
1.789 + map = razor_qsort_with_data(importer->set->packages.data,
1.790 + count,
1.791 + sizeof(struct razor_package),
1.792 + compare_packages,
1.793 + importer->set);
1.794 +
1.795 + rmap = malloc(count * sizeof *rmap);
1.796 + for (i = 0; i < count; i++)
1.797 + rmap[map[i]] = i;
1.798 + free(map);
1.799 +
1.800 + list_remap_pool(&importer->set->package_pool, rmap);
1.801 + build_package_file_lists(importer->set, rmap);
1.802 + remap_property_package_links(&importer->set->properties, rmap);
1.803 + free(rmap);
1.804 +
1.805 + set = importer->set;
1.806 + hashtable_release(&importer->table);
1.807 + free(importer);
1.808 +
1.809 + return set;
1.810 +}
1.811 +
1.812 +struct razor_package_iterator {
1.813 + struct razor_set *set;
1.814 + struct razor_package *package, *end;
1.815 + struct list *index;
1.816 + int free_index;
1.817 +};
1.818 +
1.819 +static struct razor_package_iterator *
1.820 +razor_package_iterator_create_with_index(struct razor_set *set,
1.821 + struct list *index)
1.822 +{
1.823 + struct razor_package_iterator *pi;
1.824 +
1.825 + pi = zalloc(sizeof *pi);
1.826 + pi->set = set;
1.827 + pi->index = index;
1.828 +
1.829 + return pi;
1.830 +}
1.831 +
1.832 +struct razor_package_iterator *
1.833 +razor_package_iterator_create(struct razor_set *set)
1.834 +{
1.835 + struct razor_package_iterator *pi;
1.836 +
1.837 + pi = zalloc(sizeof *pi);
1.838 + pi->set = set;
1.839 + pi->end = set->packages.data + set->packages.size;
1.840 + pi->package = set->packages.data;
1.841 +
1.842 + return pi;
1.843 +}
1.844 +
1.845 +static void
1.846 +razor_package_iterator_init_for_property(struct razor_package_iterator *pi,
1.847 + struct razor_set *set,
1.848 + struct razor_property *property)
1.849 +{
1.850 + memset(pi, 0, sizeof *pi);
1.851 + pi->set = set;
1.852 + pi->index = list_first(&property->packages, &set->package_pool);
1.853 +}
1.854 +
1.855 +struct razor_package_iterator *
1.856 +razor_package_iterator_create_for_property(struct razor_set *set,
1.857 + struct razor_property *property)
1.858 +{
1.859 + struct list *index;
1.860 +
1.861 + index = list_first(&property->packages, &set->package_pool);
1.862 + return razor_package_iterator_create_with_index(set, index);
1.863 +}
1.864 +
1.865 +int
1.866 +razor_package_iterator_next(struct razor_package_iterator *pi,
1.867 + struct razor_package **package,
1.868 + const char **name,
1.869 + const char **version,
1.870 + const char **arch)
1.871 +{
1.872 + char *pool;
1.873 + int valid;
1.874 + struct razor_package *p, *packages;
1.875 +
1.876 + if (pi->package) {
1.877 + p = pi->package++;
1.878 + valid = p < pi->end;
1.879 + } else if (pi->index) {
1.880 + packages = pi->set->packages.data;
1.881 + p = &packages[pi->index->data];
1.882 + pi->index = list_next(pi->index);
1.883 + valid = 1;
1.884 + } else
1.885 + valid = 0;
1.886 +
1.887 + if (valid) {
1.888 + pool = pi->set->string_pool.data;
1.889 + *package = p;
1.890 + *name = &pool[p->name];
1.891 + *version = &pool[p->version];
1.892 + *arch = &pool[p->arch];
1.893 + } else {
1.894 + *package = NULL;
1.895 + }
1.896 +
1.897 + return valid;
1.898 +}
1.899 +
1.900 +void
1.901 +razor_package_iterator_destroy(struct razor_package_iterator *pi)
1.902 +{
1.903 + if (pi->free_index)
1.904 + free(pi->index);
1.905 +
1.906 + free(pi);
1.907 +}
1.908 +
1.909 +struct razor_package *
1.910 +razor_set_get_package(struct razor_set *set, const char *package)
1.911 +{
1.912 + struct razor_package_iterator *pi;
1.913 + struct razor_package *p;
1.914 + const char *name, *version, *arch;
1.915 +
1.916 + pi = razor_package_iterator_create(set);
1.917 + while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
1.918 + if (strcmp(package, name) == 0)
1.919 + break;
1.920 + }
1.921 + razor_package_iterator_destroy(pi);
1.922 +
1.923 + return p;
1.924 +}
1.925 +
1.926 +struct razor_property_iterator {
1.927 + struct razor_set *set;
1.928 + struct razor_property *property, *end;
1.929 + struct list *index;
1.930 +};
1.931 +
1.932 +struct razor_property_iterator *
1.933 +razor_property_iterator_create(struct razor_set *set,
1.934 + struct razor_package *package)
1.935 +{
1.936 + struct razor_property_iterator *pi;
1.937 +
1.938 + pi = zalloc(sizeof *pi);
1.939 + pi->set = set;
1.940 +
1.941 + if (package) {
1.942 + pi->index = list_first(&package->properties,
1.943 + &set->property_pool);
1.944 + } else {
1.945 + pi->property = set->properties.data;
1.946 + pi->end = set->properties.data + set->properties.size;
1.947 + }
1.948 +
1.949 + return pi;
1.950 +}
1.951 +
1.952 +int
1.953 +razor_property_iterator_next(struct razor_property_iterator *pi,
1.954 + struct razor_property **property,
1.955 + const char **name,
1.956 + enum razor_version_relation *relation,
1.957 + const char **version,
1.958 + enum razor_property_type *type)
1.959 +{
1.960 + char *pool;
1.961 + int valid;
1.962 + struct razor_property *p, *properties;
1.963 +
1.964 + if (pi->property) {
1.965 + p = pi->property++;
1.966 + valid = p < pi->end;
1.967 + } else if (pi->index) {
1.968 + properties = pi->set->properties.data;
1.969 + p = &properties[pi->index->data];
1.970 + pi->index = list_next(pi->index);
1.971 + valid = 1;
1.972 + } else
1.973 + valid = 0;
1.974 +
1.975 + if (valid) {
1.976 + pool = pi->set->string_pool.data;
1.977 + *property = p;
1.978 + *name = &pool[p->name];
1.979 + *relation = p->relation;
1.980 + *version = &pool[p->version];
1.981 + *type = p->type;
1.982 + } else {
1.983 + *property = NULL;
1.984 + }
1.985 +
1.986 + return valid;
1.987 +}
1.988 +
1.989 +void
1.990 +razor_property_iterator_destroy(struct razor_property_iterator *pi)
1.991 +{
1.992 + free(pi);
1.993 +}
1.994 +
1.995 +static struct razor_entry *
1.996 +find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
1.997 +{
1.998 + struct razor_entry *e;
1.999 + const char *n, *pool = set->string_pool.data;
1.1000 + int len;
1.1001 +
1.1002 + e = (struct razor_entry *) set->files.data + dir->start;
1.1003 + do {
1.1004 + n = pool + e->name;
1.1005 + if (strcmp(pattern + 1, n) == 0)
1.1006 + return e;
1.1007 + len = strlen(n);
1.1008 + if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
1.1009 + pattern[len + 1] == '/') {
1.1010 + return find_entry(set, e, pattern + len + 1);
1.1011 + }
1.1012 + } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1.1013 +
1.1014 + return NULL;
1.1015 +}
1.1016 +
1.1017 +static void
1.1018 +list_dir(struct razor_set *set, struct razor_entry *dir,
1.1019 + char *prefix, const char *pattern)
1.1020 +{
1.1021 + struct razor_entry *e;
1.1022 + const char *n, *pool = set->string_pool.data;
1.1023 +
1.1024 + e = (struct razor_entry *) set->files.data + dir->start;
1.1025 + do {
1.1026 + n = pool + e->name;
1.1027 + if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
1.1028 + continue;
1.1029 + printf("%s/%s\n", prefix, n);
1.1030 + if (e->start) {
1.1031 + char *sub = prefix + strlen (prefix);
1.1032 + *sub = '/';
1.1033 + strcpy (sub + 1, n);
1.1034 + list_dir(set, e, prefix, pattern);
1.1035 + *sub = '\0';
1.1036 + }
1.1037 + } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1.1038 +}
1.1039 +
1.1040 +void
1.1041 +razor_set_list_files(struct razor_set *set, const char *pattern)
1.1042 +{
1.1043 + struct razor_entry *e;
1.1044 + char buffer[512], *p, *base;
1.1045 +
1.1046 + if (pattern == NULL || !strcmp (pattern, "/")) {
1.1047 + buffer[0] = '\0';
1.1048 + list_dir(set, set->files.data, buffer, NULL);
1.1049 + return;
1.1050 + }
1.1051 +
1.1052 + strcpy(buffer, pattern);
1.1053 + e = find_entry(set, set->files.data, buffer);
1.1054 + if (e && e->start > 0) {
1.1055 + base = NULL;
1.1056 + } else {
1.1057 + p = strrchr(buffer, '/');
1.1058 + if (p) {
1.1059 + *p = '\0';
1.1060 + base = p + 1;
1.1061 + } else {
1.1062 + base = NULL;
1.1063 + }
1.1064 + }
1.1065 + e = find_entry(set, set->files.data, buffer);
1.1066 + if (e->start != 0)
1.1067 + list_dir(set, e, buffer, base);
1.1068 +}
1.1069 +
1.1070 +struct razor_package_iterator *
1.1071 +razor_package_iterator_create_for_file(struct razor_set *set,
1.1072 + const char *filename)
1.1073 +{
1.1074 + struct razor_entry *entry;
1.1075 + struct list *index;
1.1076 +
1.1077 + entry = find_entry(set, set->files.data, filename);
1.1078 + if (entry == NULL)
1.1079 + return NULL;
1.1080 +
1.1081 + index = list_first(&entry->packages, &set->package_pool);
1.1082 + return razor_package_iterator_create_with_index(set, index);
1.1083 +}
1.1084 +
1.1085 +static struct list *
1.1086 +list_package_files(struct razor_set *set, struct list *r,
1.1087 + struct razor_entry *dir, uint32_t end,
1.1088 + char *prefix)
1.1089 +{
1.1090 + struct razor_entry *e, *f, *entries;
1.1091 + uint32_t next, file;
1.1092 + char *pool;
1.1093 + int len;
1.1094 +
1.1095 + entries = (struct razor_entry *) set->files.data;
1.1096 + pool = set->string_pool.data;
1.1097 +
1.1098 + e = entries + dir->start;
1.1099 + do {
1.1100 + if (entries + r->data == e) {
1.1101 + printf("%s/%s\n", prefix, pool + e->name);
1.1102 + r = list_next(r);
1.1103 + if (!r)
1.1104 + return NULL;
1.1105 + if (r->data >= end)
1.1106 + return r;
1.1107 + }
1.1108 + } while (!((e++)->flags & RAZOR_ENTRY_LAST));
1.1109 +
1.1110 + e = entries + dir->start;
1.1111 + do {
1.1112 + if (e->start == 0)
1.1113 + continue;
1.1114 +
1.1115 + if (e->flags & RAZOR_ENTRY_LAST)
1.1116 + next = end;
1.1117 + else {
1.1118 + f = e + 1;
1.1119 + while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
1.1120 + f++;
1.1121 + if (f->start == 0)
1.1122 + next = end;
1.1123 + else
1.1124 + next = f->start;
1.1125 + }
1.1126 +
1.1127 + file = r->data;
1.1128 + if (e->start <= file && file < next) {
1.1129 + len = strlen(prefix);
1.1130 + prefix[len] = '/';
1.1131 + strcpy(prefix + len + 1, pool + e->name);
1.1132 + r = list_package_files(set, r, e, next, prefix);
1.1133 + prefix[len] = '\0';
1.1134 + }
1.1135 + } while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
1.1136 +
1.1137 + return r;
1.1138 +}
1.1139 +
1.1140 +void
1.1141 +razor_set_list_package_files(struct razor_set *set, const char *name)
1.1142 +{
1.1143 + struct razor_package *package;
1.1144 + struct list *r;
1.1145 + uint32_t end;
1.1146 + char buffer[512];
1.1147 +
1.1148 + package = razor_set_get_package(set, name);
1.1149 +
1.1150 + r = list_first(&package->files, &set->file_pool);
1.1151 + end = set->files.size / sizeof (struct razor_entry);
1.1152 + buffer[0] = '\0';
1.1153 + list_package_files(set, r, set->files.data, end, buffer);
1.1154 +}
1.1155 +
1.1156 +#define UPSTREAM_SOURCE 0x80
1.1157 +
1.1158 +struct source {
1.1159 + struct razor_set *set;
1.1160 + uint32_t *property_map;
1.1161 + uint32_t *file_map;
1.1162 +};
1.1163 +
1.1164 +struct razor_merger {
1.1165 + struct razor_set *set;
1.1166 + struct hashtable table;
1.1167 + struct source source1;
1.1168 + struct source source2;
1.1169 +};
1.1170 +
1.1171 +static struct razor_merger *
1.1172 +razor_merger_create(struct razor_set *set1, struct razor_set *set2)
1.1173 +{
1.1174 + struct razor_merger *merger;
1.1175 + int count;
1.1176 + size_t size;
1.1177 +
1.1178 + merger = zalloc(sizeof *merger);
1.1179 + merger->set = razor_set_create();
1.1180 + hashtable_init(&merger->table, &merger->set->string_pool);
1.1181 +
1.1182 + merger->source1.set = set1;
1.1183 + count = set1->properties.size / sizeof (struct razor_property);
1.1184 + size = count * sizeof merger->source1.property_map[0];
1.1185 + merger->source1.property_map = zalloc(size);
1.1186 + count = set1->files.size / sizeof (struct razor_entry);
1.1187 + size = count * sizeof merger->source1.file_map[0];
1.1188 + merger->source1.file_map = zalloc(size);
1.1189 +
1.1190 + merger->source2.set = set2;
1.1191 + count = set2->properties.size / sizeof (struct razor_property);
1.1192 + size = count * sizeof merger->source2.property_map[0];
1.1193 + merger->source2.property_map = zalloc(size);
1.1194 + count = set2->files.size / sizeof (struct razor_entry);
1.1195 + size = count * sizeof merger->source2.file_map[0];
1.1196 + merger->source2.file_map = zalloc(size);
1.1197 +
1.1198 + return merger;
1.1199 +}
1.1200 +
1.1201 +static void
1.1202 +razor_merger_add_package(struct razor_merger *merger,
1.1203 + struct razor_package *package)
1.1204 +{
1.1205 + char *pool;
1.1206 + struct list *r;
1.1207 + struct razor_package *p;
1.1208 + struct razor_set *set1;
1.1209 + struct source *source;
1.1210 + uint32_t flags;
1.1211 +
1.1212 + set1 = merger->source1.set;
1.1213 + if (set1->packages.data <= (void *) package &&
1.1214 + (void *) package < set1->packages.data + set1->packages.size) {
1.1215 + source = &merger->source1;
1.1216 + flags = 0;
1.1217 + } else {
1.1218 + source = &merger->source2;
1.1219 + flags = UPSTREAM_SOURCE;
1.1220 + }
1.1221 +
1.1222 + pool = source->set->string_pool.data;
1.1223 + p = array_add(&merger->set->packages, sizeof *p);
1.1224 + p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
1.1225 + p->flags = flags;
1.1226 + p->version = hashtable_tokenize(&merger->table,
1.1227 + &pool[package->version]);
1.1228 + p->arch = hashtable_tokenize(&merger->table,
1.1229 + &pool[package->arch]);
1.1230 +
1.1231 + p->properties = package->properties;
1.1232 + r = list_first(&package->properties, &source->set->property_pool);
1.1233 + while (r) {
1.1234 + source->property_map[r->data] = 1;
1.1235 + r = list_next(r);
1.1236 + }
1.1237 +
1.1238 + p->files = package->files;
1.1239 + r = list_first(&package->files, &source->set->file_pool);
1.1240 + while (r) {
1.1241 + source->file_map[r->data] = 1;
1.1242 + r = list_next(r);
1.1243 + }
1.1244 +}
1.1245 +
1.1246 +static uint32_t
1.1247 +add_property(struct razor_merger *merger,
1.1248 + const char *name, enum razor_version_relation relation,
1.1249 + const char *version, int type)
1.1250 +{
1.1251 + struct razor_property *p;
1.1252 +
1.1253 + p = array_add(&merger->set->properties, sizeof *p);
1.1254 + p->name = hashtable_tokenize(&merger->table, name);
1.1255 + p->flags = 0;
1.1256 + p->type = type;
1.1257 + p->relation = relation;
1.1258 + p->version = hashtable_tokenize(&merger->table, version);
1.1259 +
1.1260 + return p - (struct razor_property *) merger->set->properties.data;
1.1261 +}
1.1262 +
1.1263 +static void
1.1264 +merge_properties(struct razor_merger *merger)
1.1265 +{
1.1266 + struct razor_property *p1, *p2;
1.1267 + struct razor_set *set1, *set2;
1.1268 + uint32_t *map1, *map2;
1.1269 + int i, j, cmp, count1, count2;
1.1270 + char *pool1, *pool2;
1.1271 +
1.1272 + set1 = merger->source1.set;
1.1273 + set2 = merger->source2.set;
1.1274 + map1 = merger->source1.property_map;
1.1275 + map2 = merger->source2.property_map;
1.1276 +
1.1277 + i = 0;
1.1278 + j = 0;
1.1279 + pool1 = set1->string_pool.data;
1.1280 + pool2 = set2->string_pool.data;
1.1281 +
1.1282 + count1 = set1->properties.size / sizeof *p1;
1.1283 + count2 = set2->properties.size / sizeof *p2;
1.1284 + while (i < count1 || j < count2) {
1.1285 + if (i < count1 && map1[i] == 0) {
1.1286 + i++;
1.1287 + continue;
1.1288 + }
1.1289 + if (j < count2 && map2[j] == 0) {
1.1290 + j++;
1.1291 + continue;
1.1292 + }
1.1293 + p1 = (struct razor_property *) set1->properties.data + i;
1.1294 + p2 = (struct razor_property *) set2->properties.data + j;
1.1295 + if (i < count1 && j < count2)
1.1296 + cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
1.1297 + else if (i < count1)
1.1298 + cmp = -1;
1.1299 + else
1.1300 + cmp = 1;
1.1301 + if (cmp == 0)
1.1302 + cmp = p1->type - p2->type;
1.1303 + if (cmp == 0)
1.1304 + cmp = p1->relation - p2->relation;
1.1305 + if (cmp == 0)
1.1306 + cmp = versioncmp(&pool1[p1->version],
1.1307 + &pool2[p2->version]);
1.1308 + if (cmp < 0) {
1.1309 + map1[i++] = add_property(merger,
1.1310 + &pool1[p1->name],
1.1311 + p1->relation,
1.1312 + &pool1[p1->version],
1.1313 + p1->type);
1.1314 + } else if (cmp > 0) {
1.1315 + map2[j++] = add_property(merger,
1.1316 + &pool2[p2->name],
1.1317 + p2->relation,
1.1318 + &pool2[p2->version],
1.1319 + p2->type);
1.1320 + } else {
1.1321 + map1[i++] = map2[j++] = add_property(merger,
1.1322 + &pool1[p1->name],
1.1323 + p1->relation,
1.1324 + &pool1[p1->version],
1.1325 + p1->type);
1.1326 + }
1.1327 + }
1.1328 +}
1.1329 +
1.1330 +static void
1.1331 +emit_properties(struct list_head *properties, struct array *source_pool,
1.1332 + uint32_t *map, struct array *pool)
1.1333 +{
1.1334 + uint32_t r;
1.1335 + struct list *p, *q;
1.1336 +
1.1337 + r = pool->size / sizeof *q;
1.1338 + p = list_first(properties, source_pool);
1.1339 + while (p) {
1.1340 + q = array_add(pool, sizeof *q);
1.1341 + q->data = map[p->data];
1.1342 + q->flags = p->flags;
1.1343 + p = list_next(p);
1.1344 + }
1.1345 +
1.1346 + list_set_ptr(properties, r);
1.1347 +}
1.1348 +
1.1349 +static uint32_t
1.1350 +add_file(struct razor_merger *merger, const char *name)
1.1351 +{
1.1352 + struct razor_entry *e;
1.1353 +
1.1354 + e = array_add(&merger->set->files, sizeof *e);
1.1355 + e->name = hashtable_tokenize(&merger->table, name);
1.1356 + e->flags = 0;
1.1357 + e->start = 0;
1.1358 +
1.1359 + return e - (struct razor_entry *)merger->set->files.data;
1.1360 +}
1.1361 +
1.1362 +/* FIXME. Blah */
1.1363 +static int
1.1364 +fix_file_map(uint32_t *map,
1.1365 + struct razor_entry *files,
1.1366 + struct razor_entry *top)
1.1367 +{
1.1368 + uint32_t e;
1.1369 + int found_file = 0;
1.1370 +
1.1371 + e = top->start;
1.1372 + do {
1.1373 + if (files[e].start)
1.1374 + fix_file_map(map, files, &files[e]);
1.1375 + if (map[e])
1.1376 + found_file = 1;
1.1377 + } while (!(files[e++].flags & RAZOR_ENTRY_LAST));
1.1378 +
1.1379 + if (found_file)
1.1380 + map[top - files] = 1;
1.1381 + return found_file;
1.1382 +}
1.1383 +
1.1384 +struct merge_directory {
1.1385 + uint32_t merged, dir1, dir2;
1.1386 +};
1.1387 +
1.1388 +static void
1.1389 +merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
1.1390 +{
1.1391 + struct razor_entry *root1, *root2, *mroot, *e1, *e2;
1.1392 + struct razor_set *set1, *set2;
1.1393 + struct array merge_stack;
1.1394 + struct merge_directory *child_md, *end_md;
1.1395 + uint32_t *map1, *map2, start, last;
1.1396 + int cmp;
1.1397 + char *pool1, *pool2;
1.1398 +
1.1399 + set1 = merger->source1.set;
1.1400 + set2 = merger->source2.set;
1.1401 + map1 = merger->source1.file_map;
1.1402 + map2 = merger->source2.file_map;
1.1403 + pool1 = set1->string_pool.data;
1.1404 + pool2 = set2->string_pool.data;
1.1405 + root1 = (struct razor_entry *) set1->files.data;
1.1406 + root2 = (struct razor_entry *) set2->files.data;
1.1407 +
1.1408 + array_init(&merge_stack);
1.1409 +
1.1410 + start = merger->set->files.size / sizeof (struct razor_entry);
1.1411 + last = 0;
1.1412 + e1 = md->dir1 ? root1 + md->dir1 : NULL;
1.1413 + e2 = md->dir2 ? root2 + md->dir2 : NULL;
1.1414 + while (e1 || e2) {
1.1415 + if (!e2 && !map1[e1 - root1]) {
1.1416 + if ((e1++)->flags & RAZOR_ENTRY_LAST)
1.1417 + e1 = NULL;
1.1418 + continue;
1.1419 + }
1.1420 + if (!e1 && !map2[e2 - root2]) {
1.1421 + if ((e2++)->flags & RAZOR_ENTRY_LAST)
1.1422 + e2 = NULL;
1.1423 + continue;
1.1424 + }
1.1425 + if (e1 && !map1[e1 - root1] &&
1.1426 + e2 && !map1[e2 - root2]) {
1.1427 + if ((e1++)->flags & RAZOR_ENTRY_LAST)
1.1428 + e1 = NULL;
1.1429 + if ((e2++)->flags & RAZOR_ENTRY_LAST)
1.1430 + e2 = NULL;
1.1431 + continue;
1.1432 + }
1.1433 +
1.1434 + if (!e1)
1.1435 + cmp = 1;
1.1436 + else if (!e2)
1.1437 + cmp = -1;
1.1438 + else {
1.1439 + cmp = strcmp (&pool1[e1->name],
1.1440 + &pool2[e2->name]);
1.1441 + }
1.1442 +
1.1443 + if (cmp < 0) {
1.1444 + if (map1[e1 - root1]) {
1.1445 + map1[e1 - root1] = last =
1.1446 + add_file(merger, &pool1[e1->name]);
1.1447 + if (e1->start) {
1.1448 + child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1.1449 + child_md->merged = last;
1.1450 + child_md->dir1 = e1->start;
1.1451 + child_md->dir2 = 0;
1.1452 + }
1.1453 + }
1.1454 + if ((e1++)->flags & RAZOR_ENTRY_LAST)
1.1455 + e1 = NULL;
1.1456 + } else if (cmp > 0) {
1.1457 + if (map2[e2 - root2]) {
1.1458 + map2[e2 - root2] = last =
1.1459 + add_file(merger, &pool2[e2->name]);
1.1460 + if (e2->start) {
1.1461 + child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1.1462 + child_md->merged = last;
1.1463 + child_md->dir1 = 0;
1.1464 + child_md->dir2 = e2->start;
1.1465 + }
1.1466 + }
1.1467 + if ((e2++)->flags & RAZOR_ENTRY_LAST)
1.1468 + e2 = NULL;
1.1469 + } else {
1.1470 + map1[e1 - root1] = map2[e2- root2] = last =
1.1471 + add_file(merger, &pool1[e1->name]);
1.1472 + if (e1->start || e2->start) {
1.1473 + child_md = array_add(&merge_stack, sizeof (struct merge_directory));
1.1474 + child_md->merged = last;
1.1475 + child_md->dir1 = e1->start;
1.1476 + child_md->dir2 = e2->start;
1.1477 + }
1.1478 + if ((e1++)->flags & RAZOR_ENTRY_LAST)
1.1479 + e1 = NULL;
1.1480 + if ((e2++)->flags & RAZOR_ENTRY_LAST)
1.1481 + e2 = NULL;
1.1482 + }
1.1483 + }
1.1484 +
1.1485 + mroot = (struct razor_entry *)merger->set->files.data;
1.1486 + if (last) {
1.1487 + mroot[last].flags = RAZOR_ENTRY_LAST;
1.1488 + mroot[md->merged].start = start;
1.1489 + } else
1.1490 + mroot[md->merged].start = 0;
1.1491 +
1.1492 + end_md = merge_stack.data + merge_stack.size;
1.1493 + for (child_md = merge_stack.data; child_md < end_md; child_md++)
1.1494 + merge_one_directory(merger, child_md);
1.1495 + array_release(&merge_stack);
1.1496 +}
1.1497 +
1.1498 +static void
1.1499 +merge_files(struct razor_merger *merger)
1.1500 +{
1.1501 + struct razor_entry *root;
1.1502 + struct merge_directory md;
1.1503 + uint32_t *map1, *map2;
1.1504 +
1.1505 + map1 = merger->source1.file_map;
1.1506 + map2 = merger->source2.file_map;
1.1507 +
1.1508 + md.merged = 0;
1.1509 +
1.1510 + if (merger->source1.set->files.size) {
1.1511 + root = (struct razor_entry *) merger->source1.set->files.data;
1.1512 + if (root->start)
1.1513 + fix_file_map(map1, root, root);
1.1514 + md.dir1 = root->start;
1.1515 + } else
1.1516 + md.dir1 = 0;
1.1517 +
1.1518 + if (merger->source2.set->files.size) {
1.1519 + root = (struct razor_entry *) merger->source2.set->files.data;
1.1520 + if (root->start)
1.1521 + fix_file_map(map2, root, root);
1.1522 + md.dir2 = root->start;
1.1523 + } else
1.1524 + md.dir2 = 0;
1.1525 +
1.1526 + merge_one_directory(merger, &md);
1.1527 +}
1.1528 +
1.1529 +static void
1.1530 +emit_files(struct list_head *files, struct array *source_pool,
1.1531 + uint32_t *map, struct array *pool)
1.1532 +{
1.1533 + uint32_t r;
1.1534 + struct list *p, *q;
1.1535 +
1.1536 + r = pool->size / sizeof *q;
1.1537 + p = list_first(files, source_pool);
1.1538 + while (p) {
1.1539 + q = array_add(pool, sizeof *q);
1.1540 + q->data = map[p->data];
1.1541 + q->flags = p->flags;
1.1542 + p = list_next(p);
1.1543 + }
1.1544 +
1.1545 + list_set_ptr(files, r);
1.1546 +}
1.1547 +
1.1548 +/* Rebuild property->packages maps. We can't just remap these, as a
1.1549 + * property may have lost or gained a number of packages. Allocate an
1.1550 + * array per property and loop through the packages and add them to
1.1551 + * the arrays for their properties. */
1.1552 +static void
1.1553 +rebuild_property_package_lists(struct razor_set *set)
1.1554 +{
1.1555 + struct array *pkgs, *a;
1.1556 + struct razor_package *pkg, *pkg_end;
1.1557 + struct razor_property *prop, *prop_end;
1.1558 + struct list *r;
1.1559 + uint32_t *q;
1.1560 + int count;
1.1561 +
1.1562 + count = set->properties.size / sizeof (struct razor_property);
1.1563 + pkgs = zalloc(count * sizeof *pkgs);
1.1564 + pkg_end = set->packages.data + set->packages.size;
1.1565 +
1.1566 + for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1.1567 + r = list_first(&pkg->properties, &set->property_pool);
1.1568 + while (r) {
1.1569 + q = array_add(&pkgs[r->data], sizeof *q);
1.1570 + *q = pkg - (struct razor_package *) set->packages.data;
1.1571 + r = list_next(r);
1.1572 + }
1.1573 + }
1.1574 +
1.1575 + prop_end = set->properties.data + set->properties.size;
1.1576 + a = pkgs;
1.1577 + for (prop = set->properties.data; prop < prop_end; prop++, a++) {
1.1578 + list_set_array(&prop->packages, &set->package_pool, a, 0);
1.1579 + array_release(a);
1.1580 + }
1.1581 + free(pkgs);
1.1582 +}
1.1583 +
1.1584 +static void
1.1585 +rebuild_file_package_lists(struct razor_set *set)
1.1586 +{
1.1587 + struct array *pkgs, *a;
1.1588 + struct razor_package *pkg, *pkg_end;
1.1589 + struct razor_entry *entry, *entry_end;
1.1590 + struct list *r;
1.1591 + uint32_t *q;
1.1592 + int count;
1.1593 +
1.1594 + count = set->files.size / sizeof (struct razor_entry);
1.1595 + pkgs = zalloc(count * sizeof *pkgs);
1.1596 + pkg_end = set->packages.data + set->packages.size;
1.1597 +
1.1598 + for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1.1599 + r = list_first(&pkg->files, &set->file_pool);
1.1600 + while (r) {
1.1601 + q = array_add(&pkgs[r->data], sizeof *q);
1.1602 + *q = pkg - (struct razor_package *) set->packages.data;
1.1603 + r = list_next(r);
1.1604 + }
1.1605 + }
1.1606 +
1.1607 + entry_end = set->files.data + set->files.size;
1.1608 + a = pkgs;
1.1609 + for (entry = set->files.data; entry < entry_end; entry++, a++) {
1.1610 + list_set_array(&entry->packages, &set->package_pool, a, 0);
1.1611 + array_release(a);
1.1612 + }
1.1613 + free(pkgs);
1.1614 +}
1.1615 +
1.1616 +static struct razor_set *
1.1617 +razor_merger_finish(struct razor_merger *merger)
1.1618 +{
1.1619 + struct razor_set *result;
1.1620 + struct razor_package *p, *pend;
1.1621 +
1.1622 + /* As we built the package list, we filled out a bitvector of
1.1623 + * the properties that are referenced by the packages in the
1.1624 + * new set. Now we do a parallel loop through the properties
1.1625 + * and emit those marked in the bit vector to the new set. In
1.1626 + * the process, we update the bit vector to actually map from
1.1627 + * indices in the old property list to indices in the new
1.1628 + * property list for both sets. */
1.1629 +
1.1630 + merge_properties(merger);
1.1631 + merge_files(merger);
1.1632 +
1.1633 + /* Now we loop through the packages again and emit the
1.1634 + * property lists, remapped to point to the new properties. */
1.1635 +
1.1636 + pend = merger->set->packages.data + merger->set->packages.size;
1.1637 + for (p = merger->set->packages.data; p < pend; p++) {
1.1638 + struct source *src;
1.1639 +
1.1640 + if (p->flags & UPSTREAM_SOURCE)
1.1641 + src = &merger->source2;
1.1642 + else
1.1643 + src = &merger->source1;
1.1644 +
1.1645 + emit_properties(&p->properties,
1.1646 + &src->set->property_pool,
1.1647 + src->property_map,
1.1648 + &merger->set->property_pool);
1.1649 + emit_files(&p->files,
1.1650 + &src->set->file_pool,
1.1651 + src->file_map,
1.1652 + &merger->set->file_pool);
1.1653 + p->flags &= ~UPSTREAM_SOURCE;
1.1654 + }
1.1655 +
1.1656 + rebuild_property_package_lists(merger->set);
1.1657 + rebuild_file_package_lists(merger->set);
1.1658 +
1.1659 + result = merger->set;
1.1660 + hashtable_release(&merger->table);
1.1661 + free(merger);
1.1662 +
1.1663 + return result;
1.1664 +}
1.1665 +
1.1666 +/* The diff order matters. We should sort the packages so that a
1.1667 + * REMOVE of a package comes before the INSTALL, and so that all
1.1668 + * requires for a package have been installed before the package.
1.1669 + **/
1.1670 +
1.1671 +void
1.1672 +razor_set_diff(struct razor_set *set, struct razor_set *upstream,
1.1673 + razor_package_callback_t callback, void *data)
1.1674 +{
1.1675 + struct razor_package_iterator *pi1, *pi2;
1.1676 + struct razor_package *p1, *p2;
1.1677 + const char *name1, *name2, *version1, *version2, *arch1, *arch2;
1.1678 + int res;
1.1679 +
1.1680 + pi1 = razor_package_iterator_create(set);
1.1681 + pi2 = razor_package_iterator_create(upstream);
1.1682 +
1.1683 + razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
1.1684 + razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
1.1685 +
1.1686 + while (p1 || p2) {
1.1687 + if (p1 && p2) {
1.1688 + res = strcmp(name1, name2);
1.1689 + if (res == 0)
1.1690 + res = versioncmp(version1, version2);
1.1691 + } else {
1.1692 + res = 0;
1.1693 + }
1.1694 +
1.1695 + if (p2 == NULL || res < 0)
1.1696 + callback(name1, version1, NULL, arch1, data);
1.1697 + else if (p1 == NULL || res > 0)
1.1698 + callback(name2, NULL, version2, arch2, data);
1.1699 +
1.1700 + if (p1 != NULL && res <= 0)
1.1701 + razor_package_iterator_next(pi1, &p1,
1.1702 + &name1, &version1, &arch1);
1.1703 + if (p2 != NULL && res >= 0)
1.1704 + razor_package_iterator_next(pi2, &p2,
1.1705 + &name2, &version2, &arch2);
1.1706 + }
1.1707 +
1.1708 + razor_package_iterator_destroy(pi1);
1.1709 + razor_package_iterator_destroy(pi2);
1.1710 +}
1.1711 +
1.1712 +static int
1.1713 +provider_satisfies_requirement(struct razor_property *provider,
1.1714 + const char *provider_strings,
1.1715 + enum razor_version_relation relation,
1.1716 + const char *required)
1.1717 +{
1.1718 + int cmp, len;
1.1719 + const char *provided = &provider_strings[provider->version];
1.1720 +
1.1721 + if (!*required)
1.1722 + return 1;
1.1723 + if (!*provided) {
1.1724 + if (relation >= RAZOR_VERSION_EQUAL)
1.1725 + return 1;
1.1726 + else
1.1727 + return 0;
1.1728 + }
1.1729 +
1.1730 + cmp = versioncmp(provided, required);
1.1731 +
1.1732 + switch (relation) {
1.1733 + case RAZOR_VERSION_LESS:
1.1734 + return cmp < 0;
1.1735 +
1.1736 + case RAZOR_VERSION_LESS_OR_EQUAL:
1.1737 + if (cmp <= 0)
1.1738 + return 1;
1.1739 + /* fall through: FIXME, make sure this is correct */
1.1740 +
1.1741 + case RAZOR_VERSION_EQUAL:
1.1742 + if (cmp == 0)
1.1743 + return 1;
1.1744 +
1.1745 + /* "foo == 1.1" is satisfied by "foo 1.1-2" */
1.1746 + len = strlen(required);
1.1747 + if (!strncmp(required, provided, len) && provided[len] == '-')
1.1748 + return 1;
1.1749 + return 0;
1.1750 +
1.1751 + case RAZOR_VERSION_GREATER_OR_EQUAL:
1.1752 + return cmp >= 0;
1.1753 +
1.1754 + case RAZOR_VERSION_GREATER:
1.1755 + return cmp > 0;
1.1756 + }
1.1757 +
1.1758 + /* shouldn't happen */
1.1759 + return 0;
1.1760 +}
1.1761 +
1.1762 +#define TRANS_PACKAGE_PRESENT 1
1.1763 +#define TRANS_PACKAGE_UPDATE 2
1.1764 +#define TRANS_PROPERTY_SATISFIED 0x80000000
1.1765 +
1.1766 +struct transaction_set {
1.1767 + struct razor_set *set;
1.1768 + uint32_t *packages;
1.1769 + uint32_t *properties;
1.1770 +};
1.1771 +
1.1772 +struct razor_transaction {
1.1773 + int package_count, errors;
1.1774 + struct transaction_set system, upstream;
1.1775 + int changes;
1.1776 +};
1.1777 +
1.1778 +static void
1.1779 +transaction_set_init(struct transaction_set *ts, struct razor_set *set)
1.1780 +{
1.1781 + int count;
1.1782 +
1.1783 + ts->set = set;
1.1784 + count = set->packages.size / sizeof (struct razor_package);
1.1785 + ts->packages = zalloc(count * sizeof *ts->packages);
1.1786 + count = set->properties.size / sizeof (struct razor_property);
1.1787 + ts->properties = zalloc(count * sizeof *ts->properties);
1.1788 +}
1.1789 +
1.1790 +static void
1.1791 +transaction_set_release(struct transaction_set *ts)
1.1792 +{
1.1793 + free(ts->packages);
1.1794 + free(ts->properties);
1.1795 +}
1.1796 +
1.1797 +static void
1.1798 +transaction_set_install_package(struct transaction_set *ts,
1.1799 + struct razor_package *package)
1.1800 +{
1.1801 + struct razor_package *pkgs;
1.1802 + struct list *prop;
1.1803 + int i;
1.1804 +
1.1805 + pkgs = ts->set->packages.data;
1.1806 + i = package - pkgs;
1.1807 + if (ts->packages[i] == TRANS_PACKAGE_PRESENT)
1.1808 + return;
1.1809 +
1.1810 + ts->packages[i] = TRANS_PACKAGE_PRESENT;
1.1811 +
1.1812 + prop = list_first(&package->properties, &ts->set->property_pool);
1.1813 + while (prop) {
1.1814 + ts->properties[prop->data]++;
1.1815 + prop = list_next(prop);
1.1816 + }
1.1817 +}
1.1818 +
1.1819 +static void
1.1820 +transaction_set_remove_package(struct transaction_set *ts,
1.1821 + struct razor_package *package)
1.1822 +{
1.1823 + struct razor_package *pkgs;
1.1824 + struct list *prop;
1.1825 + int i;
1.1826 +
1.1827 + pkgs = ts->set->packages.data;
1.1828 + i = package - pkgs;
1.1829 + if (ts->packages[i] == 0)
1.1830 + return;
1.1831 +
1.1832 + ts->packages[i] = 0;
1.1833 +
1.1834 + prop = list_first(&package->properties, &ts->set->property_pool);
1.1835 + while (prop) {
1.1836 + ts->properties[prop->data]--;
1.1837 + prop = list_next(prop);
1.1838 + }
1.1839 +}
1.1840 +
1.1841 +struct razor_transaction *
1.1842 +razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
1.1843 +{
1.1844 + struct razor_transaction *trans;
1.1845 + struct razor_package *p, *spkgs, *pend;
1.1846 +
1.1847 + trans = zalloc(sizeof *trans);
1.1848 + transaction_set_init(&trans->system, system);
1.1849 + transaction_set_init(&trans->upstream, upstream);
1.1850 +
1.1851 + spkgs = trans->system.set->packages.data;
1.1852 + pend = trans->system.set->packages.data +
1.1853 + trans->system.set->packages.size;
1.1854 + for (p = spkgs; p < pend; p++)
1.1855 + transaction_set_install_package(&trans->system, p);
1.1856 +
1.1857 + return trans;
1.1858 +}
1.1859 +
1.1860 +void
1.1861 +razor_transaction_install_package(struct razor_transaction *trans,
1.1862 + struct razor_package *package)
1.1863 +{
1.1864 + transaction_set_install_package(&trans->upstream, package);
1.1865 + trans->changes++;
1.1866 +}
1.1867 +
1.1868 +void
1.1869 +razor_transaction_remove_package(struct razor_transaction *trans,
1.1870 + struct razor_package *package)
1.1871 +{
1.1872 + transaction_set_remove_package(&trans->system, package);
1.1873 + trans->changes++;
1.1874 +}
1.1875 +
1.1876 +void
1.1877 +razor_transaction_update_package(struct razor_transaction *trans,
1.1878 + struct razor_package *package)
1.1879 +{
1.1880 + struct razor_package *spkgs, *upkgs, *end;
1.1881 +
1.1882 + spkgs = trans->system.set->packages.data;
1.1883 + upkgs = trans->upstream.set->packages.data;
1.1884 + end = trans->system.set->packages.data +
1.1885 + trans->system.set->packages.size;
1.1886 + if (spkgs <= package && package < end)
1.1887 + trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE;
1.1888 + else
1.1889 + trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE;
1.1890 +}
1.1891 +
1.1892 +struct prop_iter {
1.1893 + struct razor_property *p, *start, *end;
1.1894 + const char *pool;
1.1895 + uint32_t *present;
1.1896 +};
1.1897 +
1.1898 +static void
1.1899 +prop_iter_init(struct prop_iter *pi, struct transaction_set *ts)
1.1900 +{
1.1901 + pi->p = ts->set->properties.data;
1.1902 + pi->start = ts->set->properties.data;
1.1903 + pi->end = ts->set->properties.data + ts->set->properties.size;
1.1904 + pi->pool = ts->set->string_pool.data;
1.1905 + pi->present = ts->properties;
1.1906 +}
1.1907 +
1.1908 +static int
1.1909 +prop_iter_next(struct prop_iter *pi,
1.1910 + enum razor_property_type type, struct razor_property **p)
1.1911 +{
1.1912 + while (pi->p < pi->end) {
1.1913 + if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) &&
1.1914 + pi->p->type == type) {
1.1915 + *p = pi->p++;
1.1916 + return 1;
1.1917 + }
1.1918 + pi->p++;
1.1919 + }
1.1920 +
1.1921 + return 0;
1.1922 +}
1.1923 +
1.1924 +static struct razor_property *
1.1925 +prop_iter_seek_to(struct prop_iter *pi,
1.1926 + enum razor_property_type type, const char *match)
1.1927 +{
1.1928 + uint32_t name;
1.1929 +
1.1930 + while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0)
1.1931 + pi->p++;
1.1932 +
1.1933 + if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0)
1.1934 + return NULL;
1.1935 +
1.1936 + name = pi->p->name;
1.1937 + while (pi->p < pi->end &&
1.1938 + pi->p->name == name &&
1.1939 + pi->p->type != type)
1.1940 + pi->p++;
1.1941 +
1.1942 + if (pi->p == pi->end || pi->p->name != name)
1.1943 + return NULL;
1.1944 +
1.1945 + return pi->p;
1.1946 +}
1.1947 +
1.1948 +/* Remove packages from set that provide any of the matching (same
1.1949 + * name and type) providers from ppi onwards that match the
1.1950 + * requirement that rpi points to. */
1.1951 +static void
1.1952 +remove_matching_providers(struct razor_transaction *trans,
1.1953 + struct prop_iter *ppi,
1.1954 + enum razor_version_relation relation,
1.1955 + const char *version)
1.1956 +{
1.1957 + struct razor_property *p;
1.1958 + struct razor_package *pkg, *pkgs;
1.1959 + struct razor_package_iterator pkg_iter;
1.1960 + struct razor_set *set;
1.1961 + const char *n, *v, *a;
1.1962 +
1.1963 + if (ppi->present == trans->system.properties)
1.1964 + set = trans->system.set;
1.1965 + else
1.1966 + set = trans->upstream.set;
1.1967 +
1.1968 + pkgs = (struct razor_package *) set->packages.data;
1.1969 + for (p = ppi->p;
1.1970 + p < ppi->end &&
1.1971 + p->name == ppi->p->name &&
1.1972 + p->type == ppi->p->type;
1.1973 + p++) {
1.1974 + if (!ppi->present[p - ppi->start])
1.1975 + continue;
1.1976 + if (!provider_satisfies_requirement(p, ppi->pool,
1.1977 + relation, version))
1.1978 + continue;
1.1979 +
1.1980 + razor_package_iterator_init_for_property(&pkg_iter, set, p);
1.1981 + while (razor_package_iterator_next(&pkg_iter,
1.1982 + &pkg, &n, &v, &a)) {
1.1983 + fprintf(stderr, "removing %s-%s\n", n, v);
1.1984 + razor_transaction_remove_package(trans, pkg);
1.1985 + }
1.1986 + }
1.1987 +}
1.1988 +
1.1989 +static void
1.1990 +flag_matching_providers(struct razor_transaction *trans,
1.1991 + struct prop_iter *ppi,
1.1992 + struct razor_property *r,
1.1993 + struct prop_iter *rpi,
1.1994 + unsigned int flag)
1.1995 +{
1.1996 + struct razor_property *p;
1.1997 + struct razor_package *pkg, *pkgs;
1.1998 + struct razor_package_iterator pkg_iter;
1.1999 + struct razor_set *set;
1.2000 + const char *name, *version, *arch;
1.2001 + uint32_t *flags;
1.2002 +
1.2003 + if (ppi->present == trans->system.properties) {
1.2004 + set = trans->system.set;
1.2005 + flags = trans->system.packages;
1.2006 + } else {
1.2007 + set = trans->upstream.set;
1.2008 + flags = trans->upstream.packages;
1.2009 + }
1.2010 +
1.2011 + pkgs = (struct razor_package *) set->packages.data;
1.2012 + for (p = ppi->p;
1.2013 + p < ppi->end &&
1.2014 + p->name == ppi->p->name &&
1.2015 + p->type == ppi->p->type;
1.2016 + p++) {
1.2017 + if (!ppi->present[p - ppi->start])
1.2018 + continue;
1.2019 + if (!provider_satisfies_requirement(p, ppi->pool,
1.2020 + r->relation,
1.2021 + &rpi->pool[r->version]))
1.2022 + continue;
1.2023 +
1.2024 + razor_package_iterator_init_for_property(&pkg_iter, set, p);
1.2025 + while (razor_package_iterator_next(&pkg_iter, &pkg,
1.2026 + &name, &version, &arch)) {
1.2027 +
1.2028 + fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
1.2029 + name, version,
1.2030 + ppi->pool + p->name,
1.2031 + rpi->pool + r->name,
1.2032 + rpi->pool + r->version);
1.2033 + flags[pkg - pkgs] |= flag;
1.2034 + }
1.2035 + }
1.2036 +}
1.2037 +
1.2038 +static struct razor_package *
1.2039 +pick_matching_provider(struct razor_set *set,
1.2040 + struct prop_iter *ppi,
1.2041 + enum razor_version_relation relation,
1.2042 + const char *version)
1.2043 +{
1.2044 + struct razor_property *p;
1.2045 + struct razor_package *pkgs;
1.2046 + struct list *i;
1.2047 +
1.2048 + /* This is where we decide which pkgs to pull in to satisfy a
1.2049 + * requirement. There may be several different providers
1.2050 + * (different versions) and each version of a provider may
1.2051 + * come from a number of packages. We pick the first package
1.2052 + * from the first provider that matches. */
1.2053 +
1.2054 + pkgs = set->packages.data;
1.2055 + for (p = ppi->p;
1.2056 + p < ppi->end &&
1.2057 + p->name == ppi->p->name &&
1.2058 + p->type == ppi->p->type &&
1.2059 + ppi->present[p - ppi->start] == 0;
1.2060 + p++) {
1.2061 + if (!provider_satisfies_requirement(p, ppi->pool,
1.2062 + relation, version))
1.2063 + continue;
1.2064 +
1.2065 + i = list_first(&p->packages, &set->package_pool);
1.2066 +
1.2067 + return &pkgs[i->data];
1.2068 + }
1.2069 +
1.2070 + return NULL;
1.2071 +}
1.2072 +
1.2073 +static void
1.2074 +remove_obsoleted_packages(struct razor_transaction *trans)
1.2075 +{
1.2076 + struct razor_property *up;
1.2077 + struct razor_package *spkgs;
1.2078 + struct prop_iter spi, upi;
1.2079 +
1.2080 + spkgs = trans->system.set->packages.data;
1.2081 + prop_iter_init(&spi, &trans->system);
1.2082 + prop_iter_init(&upi, &trans->upstream);
1.2083 +
1.2084 + while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
1.2085 + if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
1.2086 + &upi.pool[up->name]))
1.2087 + continue;
1.2088 + remove_matching_providers(trans, &spi, up->relation,
1.2089 + &upi.pool[up->version]);
1.2090 + }
1.2091 +}
1.2092 +
1.2093 +static int
1.2094 +any_provider_satisfies_requirement(struct prop_iter *ppi,
1.2095 + enum razor_version_relation relation,
1.2096 + const char *version)
1.2097 +{
1.2098 + struct razor_property *p;
1.2099 +
1.2100 + for (p = ppi->p;
1.2101 + p < ppi->end &&
1.2102 + p->name == ppi->p->name &&
1.2103 + p->type == ppi->p->type;
1.2104 + p++) {
1.2105 + if (ppi->present[p - ppi->start] > 0 &&
1.2106 + provider_satisfies_requirement(p, ppi->pool,
1.2107 + relation, version))
1.2108 + return 1;
1.2109 + }
1.2110 +
1.2111 + return 0;
1.2112 +}
1.2113 +
1.2114 +static void
1.2115 +clear_requires_flags(struct transaction_set *ts)
1.2116 +{
1.2117 + struct razor_property *p;
1.2118 + const char *pool;
1.2119 + int i, count;
1.2120 +
1.2121 + count = ts->set->properties.size / sizeof *p;
1.2122 + p = ts->set->properties.data;
1.2123 + pool = ts->set->string_pool.data;
1.2124 + for (i = 0; i < count; i++) {
1.2125 + ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
1.2126 + if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
1.2127 + ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
1.2128 + }
1.2129 +}
1.2130 +
1.2131 +static const char *relation_string[] = { "<", "<=", "=", ">=", ">" };
1.2132 +
1.2133 +static void
1.2134 +mark_satisfied_requires(struct razor_transaction *trans,
1.2135 + struct transaction_set *rts,
1.2136 + struct transaction_set *pts)
1.2137 +{
1.2138 + struct prop_iter rpi, ppi;
1.2139 + struct razor_property *rp;
1.2140 +
1.2141 + prop_iter_init(&rpi, rts);
1.2142 + prop_iter_init(&ppi, pts);
1.2143 +
1.2144 + while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
1.2145 + if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
1.2146 + &rpi.pool[rp->name]))
1.2147 + continue;
1.2148 +
1.2149 + if (any_provider_satisfies_requirement(&ppi, rp->relation,
1.2150 + &rpi.pool[rp->version]))
1.2151 + rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
1.2152 + }
1.2153 +}
1.2154 +
1.2155 +static void
1.2156 +mark_all_satisfied_requires(struct razor_transaction *trans)
1.2157 +{
1.2158 + clear_requires_flags(&trans->system);
1.2159 + clear_requires_flags(&trans->upstream);
1.2160 + mark_satisfied_requires(trans, &trans->system, &trans->system);
1.2161 + mark_satisfied_requires(trans, &trans->system, &trans->upstream);
1.2162 + mark_satisfied_requires(trans, &trans->upstream, &trans->system);
1.2163 + mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
1.2164 +}
1.2165 +
1.2166 +static void
1.2167 +update_unsatisfied_packages(struct razor_transaction *trans)
1.2168 +{
1.2169 + struct razor_package *spkgs, *pkg;
1.2170 + struct razor_property *sp;
1.2171 + struct prop_iter spi;
1.2172 + struct razor_package_iterator pkg_iter;
1.2173 + const char *name, *version, *arch;
1.2174 +
1.2175 + spkgs = trans->system.set->packages.data;
1.2176 + prop_iter_init(&spi, &trans->system);
1.2177 +
1.2178 + while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
1.2179 + if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
1.2180 + continue;
1.2181 +
1.2182 + razor_package_iterator_init_for_property(&pkg_iter,
1.2183 + trans->system.set,
1.2184 + sp);
1.2185 + while (razor_package_iterator_next(&pkg_iter, &pkg,
1.2186 + &name, &version, &arch)) {
1.2187 + fprintf(stderr, "updating %s because %s %s %s "
1.2188 + "isn't satisfied\n",
1.2189 + name, spi.pool + sp->name,
1.2190 + relation_string[sp->relation],
1.2191 + spi.pool + sp->version);
1.2192 + trans->system.packages[pkg - spkgs] |=
1.2193 + TRANS_PACKAGE_UPDATE;
1.2194 + }
1.2195 + }
1.2196 +}
1.2197 +
1.2198 +void
1.2199 +razor_transaction_update_all(struct razor_transaction *trans)
1.2200 +{
1.2201 + struct razor_package *p;
1.2202 + int i, count;
1.2203 +
1.2204 + count = trans->system.set->packages.size / sizeof *p;
1.2205 + for (i = 0; i < count; i++)
1.2206 + trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
1.2207 +}
1.2208 +
1.2209 +static void
1.2210 +update_conflicted_packages(struct razor_transaction *trans)
1.2211 +{
1.2212 + struct razor_package *pkg, *spkgs;
1.2213 + struct razor_property *up, *sp;
1.2214 + struct prop_iter spi, upi;
1.2215 + struct razor_package_iterator pkg_iter;
1.2216 + const char *name, *version, *arch;
1.2217 +
1.2218 + spkgs = trans->system.set->packages.data;
1.2219 + prop_iter_init(&spi, &trans->system);
1.2220 + prop_iter_init(&upi, &trans->upstream);
1.2221 +
1.2222 + while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
1.2223 + if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
1.2224 + &spi.pool[sp->name]))
1.2225 + continue;
1.2226 +
1.2227 + if (!any_provider_satisfies_requirement(&upi, sp->relation,
1.2228 + &spi.pool[sp->version]))
1.2229 + continue;
1.2230 +
1.2231 + razor_package_iterator_init_for_property(&pkg_iter,
1.2232 + trans->system.set,
1.2233 + sp);
1.2234 + while (razor_package_iterator_next(&pkg_iter, &pkg,
1.2235 + &name, &version, &arch)) {
1.2236 + fprintf(stderr, "updating %s %s because it conflicts with %s",
1.2237 + name, version, spi.pool + sp->name);
1.2238 + trans->system.packages[pkg - spkgs] |=
1.2239 + TRANS_PACKAGE_UPDATE;
1.2240 + }
1.2241 + }
1.2242 +
1.2243 + prop_iter_init(&spi, &trans->system);
1.2244 + prop_iter_init(&upi, &trans->upstream);
1.2245 +
1.2246 + while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
1.2247 + sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
1.2248 + &upi.pool[upi.p->name]);
1.2249 +
1.2250 + if (sp)
1.2251 + flag_matching_providers(trans, &spi, up, &upi,
1.2252 + TRANS_PACKAGE_UPDATE);
1.2253 + }
1.2254 +}
1.2255 +
1.2256 +static void
1.2257 +pull_in_requirements(struct razor_transaction *trans,
1.2258 + struct prop_iter *rpi, struct prop_iter *ppi)
1.2259 +{
1.2260 + struct razor_property *rp, *pp;
1.2261 + struct razor_package *pkg, *upkgs;
1.2262 +
1.2263 + upkgs = trans->upstream.set->packages.data;
1.2264 + while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
1.2265 + if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
1.2266 + continue;
1.2267 +
1.2268 + pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
1.2269 + &rpi->pool[rp->name]);
1.2270 + if (pp == NULL)
1.2271 + continue;
1.2272 + pkg = pick_matching_provider(trans->upstream.set,
1.2273 + ppi, rp->relation,
1.2274 + &rpi->pool[rp->version]);
1.2275 + if (pkg == NULL)
1.2276 + continue;
1.2277 +
1.2278 + rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
1.2279 +
1.2280 + fprintf(stderr, "pulling in %s which provides %s %s %s "
1.2281 + "to satisfy %s %s %s\n",
1.2282 + ppi->pool + pkg->name,
1.2283 + ppi->pool + pp->name,
1.2284 + relation_string[pp->relation],
1.2285 + ppi->pool + pp->version,
1.2286 + &rpi->pool[rp->name],
1.2287 + relation_string[rp->relation],
1.2288 + &rpi->pool[rp->version]);
1.2289 +
1.2290 + trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
1.2291 + }
1.2292 +}
1.2293 +
1.2294 +static void
1.2295 +pull_in_all_requirements(struct razor_transaction *trans)
1.2296 +{
1.2297 + struct prop_iter rpi, ppi;
1.2298 +
1.2299 + prop_iter_init(&rpi, &trans->system);
1.2300 + prop_iter_init(&ppi, &trans->upstream);
1.2301 + pull_in_requirements(trans, &rpi, &ppi);
1.2302 +
1.2303 + prop_iter_init(&rpi, &trans->upstream);
1.2304 + prop_iter_init(&ppi, &trans->upstream);
1.2305 + pull_in_requirements(trans, &rpi, &ppi);
1.2306 +}
1.2307 +
1.2308 +static void
1.2309 +flush_scheduled_system_updates(struct razor_transaction *trans)
1.2310 +{
1.2311 + struct razor_package_iterator *pi;
1.2312 + struct razor_package *p, *pkg, *spkgs;
1.2313 + struct prop_iter ppi;
1.2314 + const char *name, *version, *arch;
1.2315 +
1.2316 + spkgs = trans->system.set->packages.data;
1.2317 + pi = razor_package_iterator_create(trans->system.set);
1.2318 + prop_iter_init(&ppi, &trans->upstream);
1.2319 +
1.2320 + while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
1.2321 + if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
1.2322 + continue;
1.2323 +
1.2324 + if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
1.2325 + continue;
1.2326 +
1.2327 + pkg = pick_matching_provider(trans->upstream.set, &ppi,
1.2328 + RAZOR_VERSION_GREATER, version);
1.2329 + if (pkg == NULL)
1.2330 + continue;
1.2331 +
1.2332 + fprintf(stderr, "updating %s-%s to %s-%s\n",
1.2333 + name, version,
1.2334 + &ppi.pool[pkg->name], &ppi.pool[pkg->version]);
1.2335 +
1.2336 + razor_transaction_remove_package(trans, p);
1.2337 + razor_transaction_install_package(trans, pkg);
1.2338 + }
1.2339 +
1.2340 + razor_package_iterator_destroy(pi);
1.2341 +}
1.2342 +
1.2343 +static void
1.2344 +flush_scheduled_upstream_updates(struct razor_transaction *trans)
1.2345 +{
1.2346 + struct razor_package_iterator *pi;
1.2347 + struct razor_package *p, *upkgs;
1.2348 + struct prop_iter spi;
1.2349 + const char *name, *version, *arch;
1.2350 +
1.2351 + upkgs = trans->upstream.set->packages.data;
1.2352 + pi = razor_package_iterator_create(trans->upstream.set);
1.2353 + prop_iter_init(&spi, &trans->system);
1.2354 +
1.2355 + while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
1.2356 + if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
1.2357 + continue;
1.2358 +
1.2359 + if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
1.2360 + continue;
1.2361 + remove_matching_providers(trans, &spi,
1.2362 + RAZOR_VERSION_LESS, version);
1.2363 + razor_transaction_install_package(trans, p);
1.2364 + fprintf(stderr, "installing %s-%s\n", name, version);
1.2365 + }
1.2366 +}
1.2367 +
1.2368 +int
1.2369 +razor_transaction_resolve(struct razor_transaction *trans)
1.2370 +{
1.2371 + int last = 0;
1.2372 +
1.2373 + flush_scheduled_system_updates(trans);
1.2374 +
1.2375 + while (last < trans->changes) {
1.2376 + last = trans->changes;
1.2377 + remove_obsoleted_packages(trans);
1.2378 + mark_all_satisfied_requires(trans);
1.2379 + update_unsatisfied_packages(trans);
1.2380 + update_conflicted_packages(trans);
1.2381 + pull_in_all_requirements(trans);
1.2382 + flush_scheduled_system_updates(trans);
1.2383 + flush_scheduled_upstream_updates(trans);
1.2384 + }
1.2385 +
1.2386 + return trans->changes;
1.2387 +}
1.2388 +
1.2389 +static void
1.2390 +describe_unsatisfied(struct razor_set *set, struct razor_property *rp)
1.2391 +{
1.2392 + struct razor_package_iterator pi;
1.2393 + struct razor_package *pkg;
1.2394 + const char *name, *version, *arch, *pool;
1.2395 +
1.2396 + pool = set->string_pool.data;
1.2397 + if (pool[rp->version] == '\0') {
1.2398 + razor_package_iterator_init_for_property(&pi, set, rp);
1.2399 + while (razor_package_iterator_next(&pi, &pkg,
1.2400 + &name, &version, &arch))
1.2401 + fprintf(stderr, "%s is needed by %s-%s.%s\n",
1.2402 + &pool[rp->name],
1.2403 + name, version, arch);
1.2404 + } else {
1.2405 + razor_package_iterator_init_for_property(&pi, set, rp);
1.2406 + while (razor_package_iterator_next(&pi, &pkg,
1.2407 + &name, &version, &arch))
1.2408 + fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n",
1.2409 + &pool[rp->name],
1.2410 + relation_string[rp->relation],
1.2411 + &pool[rp->version],
1.2412 + name, version, arch);
1.2413 + }
1.2414 +}
1.2415 +
1.2416 +int
1.2417 +razor_transaction_describe(struct razor_transaction *trans)
1.2418 +{
1.2419 + struct prop_iter rpi;
1.2420 + struct razor_property *rp;
1.2421 + int unsatisfied;
1.2422 +
1.2423 + flush_scheduled_system_updates(trans);
1.2424 + flush_scheduled_upstream_updates(trans);
1.2425 + mark_all_satisfied_requires(trans);
1.2426 +
1.2427 + unsatisfied = 0;
1.2428 + prop_iter_init(&rpi, &trans->system);
1.2429 + while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
1.2430 + if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
1.2431 + describe_unsatisfied(trans->system.set, rp);
1.2432 + unsatisfied++;
1.2433 + }
1.2434 + }
1.2435 +
1.2436 + prop_iter_init(&rpi, &trans->upstream);
1.2437 + while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
1.2438 + if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
1.2439 + describe_unsatisfied(trans->upstream.set, rp);
1.2440 + unsatisfied++;
1.2441 + }
1.2442 + }
1.2443 +
1.2444 + return unsatisfied;
1.2445 +}
1.2446 +
1.2447 +int
1.2448 +razor_transaction_unsatisfied_property(struct razor_transaction *trans,
1.2449 + const char *name,
1.2450 + enum razor_version_relation rel,
1.2451 + const char *version,
1.2452 + enum razor_property_type type)
1.2453 +{
1.2454 + struct prop_iter pi;
1.2455 + struct razor_property *p;
1.2456 +
1.2457 + prop_iter_init(&pi, &trans->system);
1.2458 + while (prop_iter_next(&pi, type, &p)) {
1.2459 + if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
1.2460 + p->relation == rel &&
1.2461 + strcmp(&pi.pool[p->name], name) == 0 &&
1.2462 + strcmp(&pi.pool[p->version], version) == 0)
1.2463 +
1.2464 + return 1;
1.2465 + }
1.2466 +
1.2467 + prop_iter_init(&pi, &trans->upstream);
1.2468 + while (prop_iter_next(&pi, type, &p)) {
1.2469 + if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
1.2470 + p->relation == rel &&
1.2471 + strcmp(&pi.pool[p->name], name) == 0 &&
1.2472 + strcmp(&pi.pool[p->version], version) == 0)
1.2473 +
1.2474 + return 1;
1.2475 + }
1.2476 +
1.2477 + return 0;
1.2478 +}
1.2479 +
1.2480 +struct razor_set *
1.2481 +razor_transaction_finish(struct razor_transaction *trans)
1.2482 +{
1.2483 + struct razor_merger *merger;
1.2484 + struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
1.2485 + char *upool, *spool;
1.2486 + int cmp;
1.2487 +
1.2488 + s = trans->system.set->packages.data;
1.2489 + spkgs = trans->system.set->packages.data;
1.2490 + send = trans->system.set->packages.data +
1.2491 + trans->system.set->packages.size;
1.2492 + spool = trans->system.set->string_pool.data;
1.2493 +
1.2494 + u = trans->upstream.set->packages.data;
1.2495 + upkgs = trans->upstream.set->packages.data;
1.2496 + uend = trans->upstream.set->packages.data +
1.2497 + trans->upstream.set->packages.size;
1.2498 + upool = trans->upstream.set->string_pool.data;
1.2499 +
1.2500 + merger = razor_merger_create(trans->system.set, trans->upstream.set);
1.2501 + while (s < send || u < uend) {
1.2502 + if (s < send && u < uend)
1.2503 + cmp = strcmp(&spool[s->name], &upool[u->name]);
1.2504 + else if (s < send)
1.2505 + cmp = -1;
1.2506 + else
1.2507 + cmp = 1;
1.2508 +
1.2509 + if (cmp < 0) {
1.2510 + if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
1.2511 + razor_merger_add_package(merger, s);
1.2512 + s++;
1.2513 + } else if (cmp == 0) {
1.2514 + if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
1.2515 + razor_merger_add_package(merger, s);
1.2516 + if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
1.2517 + razor_merger_add_package(merger, u);
1.2518 +
1.2519 + s++;
1.2520 + u++;
1.2521 + } else {
1.2522 + if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
1.2523 + razor_merger_add_package(merger, u);
1.2524 + u++;
1.2525 + }
1.2526 + }
1.2527 +
1.2528 + razor_transaction_destroy(trans);
1.2529 +
1.2530 + return razor_merger_finish(merger);
1.2531 +}
1.2532 +
1.2533 +void
1.2534 +razor_transaction_destroy(struct razor_transaction *trans)
1.2535 +{
1.2536 + transaction_set_release(&trans->system);
1.2537 + transaction_set_release(&trans->upstream);
1.2538 + free(trans);
1.2539 +}
1.2540 +
1.2541 +struct razor_package_query {
1.2542 + struct razor_set *set;
1.2543 + char *vector;
1.2544 + int count;
1.2545 +};
1.2546 +
1.2547 +struct razor_package_query *
1.2548 +razor_package_query_create(struct razor_set *set)
1.2549 +{
1.2550 + struct razor_package_query *pq;
1.2551 + int count;
1.2552 +
1.2553 + pq = zalloc(sizeof *pq);
1.2554 + pq->set = set;
1.2555 + count = set->packages.size / sizeof(struct razor_package);
1.2556 + pq->vector = zalloc(count * sizeof(char));
1.2557 +
1.2558 + return pq;
1.2559 +}
1.2560 +
1.2561 +void
1.2562 +razor_package_query_add_package(struct razor_package_query *pq,
1.2563 + struct razor_package *p)
1.2564 +{
1.2565 + struct razor_package *packages;
1.2566 +
1.2567 + packages = pq->set->packages.data;
1.2568 + pq->count += pq->vector[p - packages] ^ 1;
1.2569 + pq->vector[p - packages] = 1;
1.2570 +}
1.2571 +
1.2572 +void
1.2573 +razor_package_query_add_iterator(struct razor_package_query *pq,
1.2574 + struct razor_package_iterator *pi)
1.2575 +{
1.2576 + struct razor_package *packages, *p;
1.2577 + const char *name, *version, *arch;
1.2578 +
1.2579 + packages = pq->set->packages.data;
1.2580 + while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
1.2581 + pq->count += pq->vector[p - packages] ^ 1;
1.2582 + pq->vector[p - packages] = 1;
1.2583 + }
1.2584 +}
1.2585 +
1.2586 +struct razor_package_iterator *
1.2587 +razor_package_query_finish(struct razor_package_query *pq)
1.2588 +{
1.2589 + struct razor_package_iterator *pi;
1.2590 + struct razor_set *set;
1.2591 + struct list *index;
1.2592 + int i, j, count;
1.2593 +
1.2594 + set = pq->set;
1.2595 + count = set->packages.size / sizeof(struct razor_package);
1.2596 + index = zalloc(pq->count * sizeof *index);
1.2597 +
1.2598 + for (i = 0, j = 0; i < count; i++) {
1.2599 + if (!pq->vector[i])
1.2600 + continue;
1.2601 +
1.2602 + index[j].data = i;
1.2603 + if (j == pq->count - 1)
1.2604 + index[j].flags = 0x80;
1.2605 + j++;
1.2606 + }
1.2607 +
1.2608 + free(pq);
1.2609 +
1.2610 + pi = razor_package_iterator_create_with_index(set, index);
1.2611 + pi->free_index = 1;
1.2612 +
1.2613 + return pi;
1.2614 +}