librazor/razor.c
changeset 241 c3eb520e2219
child 244 708a3d9c759a
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/librazor/razor.c	Mon Jun 16 15:40:30 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 +}