razor.c
changeset 258 29d5002bd17f
parent 229 cae6308aa5b1
parent 248 057933050c42
child 259 5b0601d184ed
     1.1 --- a/razor.c	Sun Jun 15 18:16:20 2008 -0400
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,3244 +0,0 @@
     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_DETAILS_MAGIC 	0x7a7a7a7b
    1.57 -#define RAZOR_FILES_MAGIC 	0x7a7a7a7c
    1.58 -#define RAZOR_VERSION 1
    1.59 -
    1.60 -#define RAZOR_STRING_POOL		0
    1.61 -#define RAZOR_PACKAGES			1
    1.62 -#define RAZOR_PROPERTIES		2
    1.63 -#define RAZOR_PACKAGE_POOL		3
    1.64 -#define RAZOR_PROPERTY_POOL		4
    1.65 -
    1.66 -#define RAZOR_DETAILS_STRING_POOL	0
    1.67 -
    1.68 -#define RAZOR_FILES			0
    1.69 -#define RAZOR_FILE_POOL			1
    1.70 -#define RAZOR_FILE_STRING_POOL		2
    1.71 -
    1.72 -struct razor_package {
    1.73 -	uint name  : 24;
    1.74 -	uint flags : 8;
    1.75 -	uint32_t version;
    1.76 -	uint32_t arch;
    1.77 -	uint32_t summary;
    1.78 -	uint32_t description;
    1.79 -	uint32_t url;
    1.80 -	uint32_t license;
    1.81 -	struct list_head properties;
    1.82 -	struct list_head files;
    1.83 -};
    1.84 -
    1.85 -struct razor_property {
    1.86 -	uint name  : 24;
    1.87 -	uint flags : 6;
    1.88 -	enum razor_property_type type : 2;
    1.89 -	enum razor_version_relation relation : 32;
    1.90 -	uint32_t version;
    1.91 -	struct list_head packages;
    1.92 -};
    1.93 -
    1.94 -struct razor_entry {
    1.95 -	uint name  : 24;
    1.96 -	uint flags : 8;
    1.97 -	uint32_t start;
    1.98 -	struct list_head packages;
    1.99 -};
   1.100 -
   1.101 -#define RAZOR_ENTRY_LAST	0x80
   1.102 -
   1.103 -struct razor_set {
   1.104 -	struct array string_pool;
   1.105 - 	struct array packages;
   1.106 - 	struct array properties;
   1.107 - 	struct array files;
   1.108 -	struct array package_pool;
   1.109 - 	struct array property_pool;
   1.110 - 	struct array file_pool;
   1.111 -	struct array file_string_pool;
   1.112 -	struct array details_string_pool;
   1.113 -	struct razor_set_header *header;
   1.114 -	struct razor_set_header *details_header;
   1.115 -	struct razor_set_header *files_header;
   1.116 -};
   1.117 -
   1.118 -struct import_entry {
   1.119 -	uint32_t package;
   1.120 -	char *name;
   1.121 -};
   1.122 -
   1.123 -struct import_directory {
   1.124 -	uint32_t name, count;
   1.125 -	struct array files;
   1.126 -	struct array packages;
   1.127 -	struct import_directory *last;
   1.128 -};
   1.129 -
   1.130 -struct razor_importer {
   1.131 -	struct razor_set *set;
   1.132 -	struct hashtable table;
   1.133 -	struct hashtable file_table;
   1.134 -	struct hashtable details_table;
   1.135 -	struct razor_package *package;
   1.136 -	struct array properties;
   1.137 -	struct array files;
   1.138 -	struct array file_requires;
   1.139 -};
   1.140 -
   1.141 -static void *
   1.142 -zalloc(size_t size)
   1.143 -{
   1.144 -	void *p;
   1.145 -
   1.146 -	p = malloc(size);
   1.147 -	memset(p, 0, size);
   1.148 -
   1.149 -	return p;
   1.150 -}
   1.151 -
   1.152 -struct razor_set_section razor_sections[] = {
   1.153 -	{ RAZOR_STRING_POOL,		offsetof(struct razor_set, string_pool) },
   1.154 -	{ RAZOR_PACKAGES,		offsetof(struct razor_set, packages) },
   1.155 -	{ RAZOR_PROPERTIES,		offsetof(struct razor_set, properties) },
   1.156 -	{ RAZOR_PACKAGE_POOL,		offsetof(struct razor_set, package_pool) },
   1.157 -	{ RAZOR_PROPERTY_POOL,		offsetof(struct razor_set, property_pool) },
   1.158 -};
   1.159 -
   1.160 -struct razor_set_section razor_files_sections[] = {
   1.161 -	{ RAZOR_FILES,			offsetof(struct razor_set, files) },
   1.162 -	{ RAZOR_FILE_POOL,		offsetof(struct razor_set, file_pool) },
   1.163 -	{ RAZOR_FILE_STRING_POOL,	offsetof(struct razor_set, file_string_pool) },
   1.164 -};
   1.165 -
   1.166 -struct razor_set_section razor_details_sections[] = {
   1.167 -	{ RAZOR_DETAILS_STRING_POOL,	offsetof(struct razor_set, details_string_pool) },
   1.168 -};
   1.169 -
   1.170 -struct razor_set *
   1.171 -razor_set_create(void)
   1.172 -{
   1.173 -	struct razor_set *set;
   1.174 -	struct razor_entry *e;
   1.175 -	char *empty;
   1.176 -
   1.177 -	set = zalloc(sizeof *set);
   1.178 -
   1.179 -	e = array_add(&set->files, sizeof *e);
   1.180 -	empty = array_add(&set->string_pool, 1);
   1.181 -	*empty = '\0';
   1.182 -	empty = array_add(&set->file_string_pool, 1);
   1.183 -	*empty = '\0';
   1.184 -	empty = array_add(&set->details_string_pool, 1);
   1.185 -	*empty = '\0';
   1.186 -	e->name = 0;
   1.187 -	e->flags = RAZOR_ENTRY_LAST;
   1.188 -	e->start = 0;
   1.189 -	list_set_empty(&e->packages);
   1.190 -
   1.191 -	return set;
   1.192 -}
   1.193 -
   1.194 -struct razor_set *
   1.195 -razor_set_open(const char *filename)
   1.196 -{
   1.197 -	struct razor_set *set;
   1.198 -	struct razor_set_section *s;
   1.199 -	struct stat stat;
   1.200 -	struct array *array;
   1.201 -	int fd;
   1.202 -
   1.203 -	set = zalloc(sizeof *set);
   1.204 -	fd = open(filename, O_RDONLY);
   1.205 -	if (fstat(fd, &stat) < 0)
   1.206 -		return NULL;
   1.207 -	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   1.208 -	if (set->header == MAP_FAILED) {
   1.209 -		free(set);
   1.210 -		return NULL;
   1.211 -	}
   1.212 -
   1.213 -	for (s = set->header->sections; ~s->type; s++) {
   1.214 -		if (s->type >= ARRAY_SIZE(razor_sections))
   1.215 -			continue;
   1.216 -		if (s->type != razor_sections[s->type].type)
   1.217 -			continue;
   1.218 -		array = (void *) set + razor_sections[s->type].offset;
   1.219 -		array->data = (void *) set->header + s->offset;
   1.220 -		array->size = s->size;
   1.221 -		array->alloc = s->size;
   1.222 -	}
   1.223 -	close(fd);
   1.224 -
   1.225 -	return set;
   1.226 -}
   1.227 -
   1.228 -void
   1.229 -razor_set_destroy(struct razor_set *set)
   1.230 -{
   1.231 -	unsigned int size;
   1.232 -	struct array *a;
   1.233 -	int i;
   1.234 -
   1.235 -	if (set->header) {
   1.236 -		for (i = 0; set->header->sections[i].type; i++)
   1.237 -			;
   1.238 -		size = set->header->sections[i].type;
   1.239 -		munmap(set->header, size);
   1.240 -	} else {
   1.241 -		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   1.242 -			a = (void *) set + razor_sections[i].offset;
   1.243 -			free(a->data);
   1.244 -		}
   1.245 -	}
   1.246 -
   1.247 -	if (set->details_header) {
   1.248 -		for (i = 0; set->details_header->sections[i].type; i++)
   1.249 -			;
   1.250 -		size = set->details_header->sections[i].type;
   1.251 -		munmap(set->details_header, size);
   1.252 -	} else {
   1.253 -		for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
   1.254 -			a = (void *) set + razor_details_sections[i].offset;
   1.255 -			free(a->data);
   1.256 -		}
   1.257 -	}
   1.258 -
   1.259 -	if (set->files_header) {
   1.260 -		for (i = 0; set->files_header->sections[i].type; i++)
   1.261 -			;
   1.262 -		size = set->files_header->sections[i].type;
   1.263 -		munmap(set->files_header, size);
   1.264 -	} else {
   1.265 -		for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
   1.266 -			a = (void *) set + razor_files_sections[i].offset;
   1.267 -			free(a->data);
   1.268 -		}
   1.269 -	}
   1.270 -
   1.271 -	free(set);
   1.272 -}
   1.273 -
   1.274 -void
   1.275 -razor_set_open_details(struct razor_set *set, const char *filename)
   1.276 -{
   1.277 -	struct razor_set_section *s;
   1.278 -	struct stat stat;
   1.279 -	struct array *array;
   1.280 -	int fd;
   1.281 -
   1.282 -	fd = open(filename, O_RDONLY);
   1.283 -	if (fstat(fd, &stat) < 0)
   1.284 -		return;
   1.285 -	set->details_header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   1.286 -	if (set->details_header == MAP_FAILED)
   1.287 -		return;
   1.288 -
   1.289 -	for (s = set->details_header->sections; ~s->type; s++) {
   1.290 -		if (s->type >= ARRAY_SIZE(razor_details_sections))
   1.291 -			continue;
   1.292 -		if (s->type != razor_details_sections[s->type].type)
   1.293 -			continue;
   1.294 -		array = (void *) set + razor_details_sections[s->type].offset;
   1.295 -		array->data = (void *) set->details_header + s->offset;
   1.296 -		array->size = s->size;
   1.297 -		array->alloc = s->size;
   1.298 -	}
   1.299 -	close(fd);
   1.300 -}
   1.301 -
   1.302 -void
   1.303 -razor_set_open_files(struct razor_set *set, const char *filename)
   1.304 -{
   1.305 -	struct razor_set_section *s;
   1.306 -	struct stat stat;
   1.307 -	struct array *array;
   1.308 -	int fd;
   1.309 -
   1.310 -	fd = open(filename, O_RDONLY);
   1.311 -	if (fstat(fd, &stat) < 0)
   1.312 -		return;
   1.313 -	set->files_header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   1.314 -	if (set->files_header == MAP_FAILED)
   1.315 -		return;
   1.316 -
   1.317 -	for (s = set->files_header->sections; ~s->type; s++) {
   1.318 -		if (s->type >= ARRAY_SIZE(razor_files_sections))
   1.319 -			continue;
   1.320 -		if (s->type != razor_files_sections[s->type].type)
   1.321 -			continue;
   1.322 -		array = (void *) set + razor_files_sections[s->type].offset;
   1.323 -		array->data = (void *) set->files_header + s->offset;
   1.324 -		array->size = s->size;
   1.325 -		array->alloc = s->size;
   1.326 -	}
   1.327 -	close(fd);
   1.328 -}
   1.329 -
   1.330 -static int
   1.331 -razor_set_write_sections_to_fd(struct razor_set *set, int fd, int magic,
   1.332 -			       struct razor_set_section *sections,
   1.333 -			       size_t array_size)
   1.334 -{
   1.335 -	char data[4096];
   1.336 -	struct razor_set_header *header = (struct razor_set_header *) data;
   1.337 -	struct array *a;
   1.338 -	uint32_t offset;
   1.339 -	int i;
   1.340 -
   1.341 -	memset(data, 0, sizeof data);
   1.342 -	header->magic = magic;
   1.343 -	header->version = RAZOR_VERSION;
   1.344 -	offset = sizeof data;
   1.345 -
   1.346 -	for (i = 0; i < array_size; i++) {
   1.347 -		if (sections[i].type != i)
   1.348 -			continue;
   1.349 -		a = (void *) set + sections[i].offset;
   1.350 -		header->sections[i].type = i;
   1.351 -		header->sections[i].offset = offset;
   1.352 -		header->sections[i].size = a->size;
   1.353 -		offset += ALIGN(a->size, 4096);
   1.354 -	}
   1.355 -
   1.356 -	header->sections[i].type = ~0;
   1.357 -	header->sections[i].offset = 0;
   1.358 -	header->sections[i].size = 0;
   1.359 -
   1.360 -	razor_write(fd, data, sizeof data);
   1.361 -	memset(data, 0, sizeof data);
   1.362 -	for (i = 0; i < array_size; i++) {
   1.363 -		if (sections[i].type != i)
   1.364 -			continue;
   1.365 -		a = (void *) set + sections[i].offset;
   1.366 -		razor_write(fd, a->data, a->size);
   1.367 -		razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
   1.368 -	}
   1.369 -
   1.370 -	return 0;
   1.371 -}
   1.372 -
   1.373 -int
   1.374 -razor_set_write_to_fd(struct razor_set *set, int fd,
   1.375 -		      enum razor_repo_file_type type)
   1.376 -{
   1.377 -	switch (type) {
   1.378 -	case RAZOR_REPO_FILE_MAIN:
   1.379 -		return razor_set_write_sections_to_fd(set, fd, RAZOR_MAGIC,
   1.380 -						      razor_sections,
   1.381 -						      ARRAY_SIZE(razor_sections));
   1.382 -
   1.383 -	case RAZOR_REPO_FILE_DETAILS:
   1.384 -		return razor_set_write_sections_to_fd(set, fd, RAZOR_DETAILS_MAGIC,
   1.385 -						      razor_details_sections,
   1.386 -						      ARRAY_SIZE(razor_details_sections));
   1.387 -	case RAZOR_REPO_FILE_FILES:
   1.388 -		return razor_set_write_sections_to_fd(set, fd, RAZOR_FILES_MAGIC,
   1.389 -						      razor_files_sections,
   1.390 -						      ARRAY_SIZE(razor_files_sections));
   1.391 -	default:
   1.392 -		return -1;
   1.393 -	}
   1.394 -}
   1.395 -
   1.396 -int
   1.397 -razor_set_write(struct razor_set *set, const char *filename,
   1.398 -		enum razor_repo_file_type type)
   1.399 -{
   1.400 -	int fd, status;
   1.401 -
   1.402 -	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
   1.403 -	if (fd < 0)
   1.404 -		return -1;
   1.405 -
   1.406 -	status = razor_set_write_to_fd(set, fd, type);
   1.407 -	if (status) {
   1.408 -	    close(fd);
   1.409 -	    return status;
   1.410 -	}
   1.411 -
   1.412 -	return close(fd);
   1.413 -}
   1.414 -
   1.415 -void
   1.416 -razor_build_evr(char *evr_buf, int size, const char *epoch,
   1.417 -		const char *version, const char *release)
   1.418 -{
   1.419 -	int len;
   1.420 -
   1.421 -	if (!version || !*version) {
   1.422 -		*evr_buf = '\0';
   1.423 -		return;
   1.424 -	}
   1.425 -
   1.426 -	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
   1.427 -		len = snprintf(evr_buf, size, "%s:", epoch);
   1.428 -		evr_buf += len;
   1.429 -		size -= len;
   1.430 -	}
   1.431 -	len = snprintf(evr_buf, size, "%s", version);
   1.432 -	evr_buf += len;
   1.433 -	size -= len;
   1.434 -	if (release && *release)
   1.435 -		snprintf(evr_buf, size, "-%s", release);
   1.436 -}
   1.437 -
   1.438 -void
   1.439 -razor_importer_begin_package(struct razor_importer *importer,
   1.440 -			     const char *name,
   1.441 -			     const char *version,
   1.442 -			     const char *arch)
   1.443 -{
   1.444 -	struct razor_package *p;
   1.445 -
   1.446 -	p = array_add(&importer->set->packages, sizeof *p);
   1.447 -	p->name = hashtable_tokenize(&importer->table, name);
   1.448 -	p->flags = 0;
   1.449 -	p->version = hashtable_tokenize(&importer->table, version);
   1.450 -	p->arch = hashtable_tokenize(&importer->table, arch);
   1.451 -
   1.452 -	importer->package = p;
   1.453 -	array_init(&importer->properties);
   1.454 -}
   1.455 -
   1.456 -void
   1.457 -razor_importer_finish_package(struct razor_importer *importer)
   1.458 -{
   1.459 -	list_set_array(&importer->package->properties,
   1.460 -		       &importer->set->property_pool,
   1.461 -		       &importer->properties,
   1.462 -		       1);
   1.463 -
   1.464 -	array_release(&importer->properties);
   1.465 -}
   1.466 -
   1.467 -void
   1.468 -razor_importer_add_details(struct razor_importer *importer,
   1.469 -			   const char *summary,
   1.470 -			   const char *description,
   1.471 -			   const char *url,
   1.472 -			   const char *license)
   1.473 -{
   1.474 -	importer->package->summary = hashtable_tokenize(&importer->details_table, summary);
   1.475 -	importer->package->description = hashtable_tokenize(&importer->details_table, description);
   1.476 -	importer->package->url = hashtable_tokenize(&importer->details_table, url);
   1.477 -	importer->package->license = hashtable_tokenize(&importer->details_table, license);
   1.478 -}
   1.479 -
   1.480 -void
   1.481 -razor_importer_add_property(struct razor_importer *importer,
   1.482 -			    const char *name,
   1.483 -			    enum razor_version_relation relation,
   1.484 -			    const char *version,
   1.485 -			    enum razor_property_type type)
   1.486 -{
   1.487 -	struct razor_property *p;
   1.488 -	uint32_t *r;
   1.489 -
   1.490 -	p = array_add(&importer->set->properties, sizeof *p);
   1.491 -	p->name = hashtable_tokenize(&importer->table, name);
   1.492 -	p->flags = 0;
   1.493 -	p->type = type;
   1.494 -	p->relation = relation;
   1.495 -	p->version = hashtable_tokenize(&importer->table, version);
   1.496 -	list_set_ptr(&p->packages, importer->package -
   1.497 -		     (struct razor_package *) importer->set->packages.data);
   1.498 -
   1.499 -	r = array_add(&importer->properties, sizeof *r);
   1.500 -	*r = p - (struct razor_property *) importer->set->properties.data;
   1.501 -
   1.502 -	if (type == RAZOR_PROPERTY_REQUIRES && *name == '/') {
   1.503 -		r = array_add(&importer->file_requires, sizeof *r);
   1.504 -		*r = p->name;
   1.505 -	}
   1.506 -}
   1.507 -
   1.508 -void
   1.509 -razor_importer_add_file(struct razor_importer *importer, const char *name)
   1.510 -{
   1.511 -	struct import_entry *e;
   1.512 -
   1.513 -	e = array_add(&importer->files, sizeof *e);
   1.514 -
   1.515 -	e->package = importer->package -
   1.516 -		(struct razor_package *) importer->set->packages.data;
   1.517 -	e->name = strdup(name);
   1.518 -}
   1.519 -
   1.520 -struct razor_importer *
   1.521 -razor_importer_new(void)
   1.522 -{
   1.523 -	struct razor_importer *importer;
   1.524 -
   1.525 -	importer = zalloc(sizeof *importer);
   1.526 -	importer->set = razor_set_create();
   1.527 -	hashtable_init(&importer->table, &importer->set->string_pool);
   1.528 -	hashtable_init(&importer->file_table, &importer->set->file_string_pool);
   1.529 -	hashtable_init(&importer->details_table, &importer->set->details_string_pool);
   1.530 -
   1.531 -	return importer;
   1.532 -}
   1.533 -
   1.534 -/* Destroy an importer without creating the set. */
   1.535 -void
   1.536 -razor_importer_destroy(struct razor_importer *importer)
   1.537 -{
   1.538 -	/* FIXME: write this */
   1.539 -}
   1.540 -
   1.541 -static int
   1.542 -versioncmp(const char *s1, const char *s2)
   1.543 -{
   1.544 -	const char *p1, *p2;
   1.545 -	long n1, n2;
   1.546 -	int res;
   1.547 -
   1.548 -	n1 = strtol(s1, (char **) &p1, 10);
   1.549 -	n2 = strtol(s2, (char **) &p2, 10);
   1.550 -
   1.551 -	/* Epoch; if one but not the other has an epoch set, default
   1.552 -	 * the epoch-less version to 0. */
   1.553 -	res = (*p1 == ':') - (*p2 == ':');
   1.554 -	if (res < 0) {
   1.555 -		n1 = 0;
   1.556 -		p1 = s1;
   1.557 -		p2++;
   1.558 -	} else if (res > 0) {
   1.559 -		p1++;
   1.560 -		n2 = 0;
   1.561 -		p2 = s2;
   1.562 -	}
   1.563 -
   1.564 -	if (n1 != n2)
   1.565 -		return n1 - n2;
   1.566 -	while (*p1 && *p2) {
   1.567 -		if (*p1 != *p2)
   1.568 -			return *p1 - *p2;
   1.569 -		p1++;
   1.570 -		p2++;
   1.571 -		if (isdigit(*p1) && isdigit(*p2))
   1.572 -			return versioncmp(p1, p2);
   1.573 -	}
   1.574 -
   1.575 -	return *p1 - *p2;
   1.576 -}
   1.577 -
   1.578 -static int
   1.579 -compare_packages(const void *p1, const void *p2, void *data)
   1.580 -{
   1.581 -	const struct razor_package *pkg1 = p1, *pkg2 = p2;
   1.582 -	struct razor_set *set = data;
   1.583 -	char *pool = set->string_pool.data;
   1.584 -
   1.585 -	/* FIXME: what if the flags are different? */
   1.586 -	if (pkg1->name == pkg2->name)
   1.587 -		return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
   1.588 -	else
   1.589 -		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
   1.590 -}
   1.591 -
   1.592 -static int
   1.593 -compare_properties(const void *p1, const void *p2, void *data)
   1.594 -{
   1.595 -	const struct razor_property *prop1 = p1, *prop2 = p2;
   1.596 -	struct razor_set *set = data;
   1.597 -	char *pool = set->string_pool.data;
   1.598 -
   1.599 -	if (prop1->name != prop2->name) 
   1.600 -		return strcmp(&pool[prop1->name], &pool[prop2->name]);
   1.601 -	else if (prop1->type != prop2->type)
   1.602 -		return prop1->type - prop2->type;
   1.603 -	else if (prop1->relation != prop2->relation)
   1.604 -		return prop1->relation - prop2->relation;
   1.605 -	else
   1.606 -		return versioncmp(&pool[prop1->version], &pool[prop2->version]);
   1.607 -}
   1.608 -
   1.609 -static uint32_t *
   1.610 -uniqueify_properties(struct razor_set *set)
   1.611 -{
   1.612 -	struct razor_property *rp, *up, *rp_end;
   1.613 -	struct array *pkgs, *p;
   1.614 -	struct list_head *r;
   1.615 -	uint32_t *map, *rmap;
   1.616 -	int i, count, unique;
   1.617 -
   1.618 -	count = set->properties.size / sizeof(struct razor_property);
   1.619 -	map = razor_qsort_with_data(set->properties.data,
   1.620 -				    count,
   1.621 -				    sizeof(struct razor_property),
   1.622 -				    compare_properties,
   1.623 -				    set);
   1.624 -
   1.625 -	rp_end = set->properties.data + set->properties.size;
   1.626 -	rmap = malloc(count * sizeof *map);
   1.627 -	pkgs = zalloc(count * sizeof *pkgs);
   1.628 -	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
   1.629 -		if (rp->name != up->name || rp->type != up->type ||
   1.630 -		    rp->relation != up->relation || rp->version != up->version) {
   1.631 -			up++;
   1.632 -			up->name = rp->name;
   1.633 -			up->flags = 0;
   1.634 -			up->type = rp->type;
   1.635 -			up->relation = rp->relation;
   1.636 -			up->version = rp->version;
   1.637 -		}
   1.638 -
   1.639 -		unique = up - (struct razor_property *) set->properties.data;
   1.640 -		rmap[map[i]] = unique;
   1.641 -		r = array_add(&pkgs[unique], sizeof *r);
   1.642 -		*r = rp->packages;
   1.643 -	}
   1.644 -	free(map);
   1.645 -
   1.646 -	if (up != rp)
   1.647 -		up++;
   1.648 -	set->properties.size = (void *) up - set->properties.data;
   1.649 -	rp_end = up;
   1.650 -	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
   1.651 -		list_set_array(&rp->packages, &set->package_pool, p, 0);
   1.652 -		array_release(p);
   1.653 -	}
   1.654 -
   1.655 -	free(pkgs);
   1.656 -
   1.657 -	return rmap;
   1.658 -}
   1.659 -
   1.660 -static int
   1.661 -compare_filenames(const void *p1, const void *p2, void *data)
   1.662 -{
   1.663 -	const struct import_entry *e1 = p1;
   1.664 -	const struct import_entry *e2 = p2;
   1.665 -	const char *n1 = e1->name;
   1.666 -	const char *n2 = e2->name;
   1.667 -
   1.668 -	/* Need to make sure that the contents of a directory
   1.669 -	 * are sorted immediately after it. So "foo/bar" has to
   1.670 -	 * sort before "foo.conf"
   1.671 -	 *
   1.672 -	 * FIXME: this is about 60% slower than strcmp
   1.673 -	 */
   1.674 -	while (*n1 && *n2) {
   1.675 -		if (*n1 < *n2)
   1.676 -			return *n2 == '/' ? 1 : -1;
   1.677 -		else if (*n1 > *n2)
   1.678 -			return *n1 == '/' ? -1 : 1;
   1.679 -		n1++;
   1.680 -		n2++;
   1.681 -	}
   1.682 -	if (*n1)
   1.683 -		return 1;
   1.684 -	else if (*n2)
   1.685 -		return -1;
   1.686 -	else
   1.687 -		return 0;
   1.688 -}
   1.689 -
   1.690 -static void
   1.691 -count_entries(struct import_directory *d)
   1.692 -{
   1.693 -	struct import_directory *p, *end;
   1.694 -
   1.695 -	p = d->files.data;
   1.696 -	end = d->files.data + d->files.size;
   1.697 -	d->count = 0;
   1.698 -	while (p < end) {
   1.699 -		count_entries(p);
   1.700 -		d->count += p->count + 1;
   1.701 -		p++;
   1.702 -	}		
   1.703 -}
   1.704 -
   1.705 -static void
   1.706 -serialize_files(struct razor_set *set,
   1.707 -		struct import_directory *d, struct array *array)
   1.708 -{
   1.709 -	struct import_directory *p, *end;
   1.710 -	struct razor_entry *e = NULL;
   1.711 -	uint32_t s;
   1.712 -
   1.713 -	p = d->files.data;
   1.714 -	end = d->files.data + d->files.size;
   1.715 -	s = array->size / sizeof *e + d->files.size / sizeof *p;
   1.716 -	while (p < end) {
   1.717 -		e = array_add(array, sizeof *e);
   1.718 -		e->name = p->name;
   1.719 -		e->flags = 0;
   1.720 -		e->start = p->count > 0 ? s : 0;
   1.721 -		s += p->count;
   1.722 -
   1.723 -		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
   1.724 -		array_release(&p->packages);
   1.725 -		p++;
   1.726 -	}		
   1.727 -	if (e != NULL)
   1.728 -		e->flags |= RAZOR_ENTRY_LAST;
   1.729 -
   1.730 -	p = d->files.data;
   1.731 -	end = d->files.data + d->files.size;
   1.732 -	while (p < end) {
   1.733 -		serialize_files(set, p, array);
   1.734 -		p++;
   1.735 -	}
   1.736 -}
   1.737 -
   1.738 -static void
   1.739 -remap_property_package_links(struct array *properties, uint32_t *rmap)
   1.740 -{
   1.741 -	struct razor_property *p, *end;
   1.742 -
   1.743 -	end = properties->data + properties->size;
   1.744 -	for (p = properties->data; p < end; p++)
   1.745 -		list_remap_head(&p->packages, rmap);
   1.746 -}
   1.747 -
   1.748 -static void
   1.749 -build_file_tree(struct razor_importer *importer)
   1.750 -{
   1.751 -	int count, i, length;
   1.752 -	struct import_entry *filenames;
   1.753 -	char *f, *end;
   1.754 -	uint32_t name, *r;
   1.755 -	char dirname[256];
   1.756 -	struct import_directory *d, root;
   1.757 -	struct razor_entry *e;
   1.758 -
   1.759 -	count = importer->files.size / sizeof (struct import_entry);
   1.760 -	razor_qsort_with_data(importer->files.data,
   1.761 -			      count,
   1.762 -			      sizeof (struct import_entry),
   1.763 -			      compare_filenames,
   1.764 -			      NULL);
   1.765 -
   1.766 -	root.name = hashtable_tokenize(&importer->file_table, "");
   1.767 -	array_init(&root.files);
   1.768 -	array_init(&root.packages);
   1.769 -	root.last = NULL;
   1.770 -
   1.771 -	filenames = importer->files.data;
   1.772 -	for (i = 0; i < count; i++) {
   1.773 -		f = filenames[i].name;
   1.774 -		if (*f != '/')
   1.775 -			continue;
   1.776 -		f++;
   1.777 -
   1.778 -		d = &root;
   1.779 -		while (*f) {
   1.780 -			end = strchr(f, '/');
   1.781 -			if (end == NULL)
   1.782 -				end = f + strlen(f);
   1.783 -			length = end - f;
   1.784 -			memcpy(dirname, f, length);
   1.785 -			dirname[length] ='\0';
   1.786 -			name = hashtable_tokenize(&importer->file_table, dirname);
   1.787 -			if (d->last == NULL || d->last->name != name) {
   1.788 -				d->last = array_add(&d->files, sizeof *d);
   1.789 -				d->last->name = name;
   1.790 -				d->last->last = NULL;
   1.791 -				array_init(&d->last->files);
   1.792 -				array_init(&d->last->packages);
   1.793 -			}
   1.794 -			d = d->last;				
   1.795 -			f = end + 1;
   1.796 -			if (*end == '\0')
   1.797 -				break;
   1.798 -		}
   1.799 -
   1.800 -		r = array_add(&d->packages, sizeof *r);
   1.801 -		*r = filenames[i].package;
   1.802 -		free(filenames[i].name);
   1.803 -	}
   1.804 -
   1.805 -	count_entries(&root);
   1.806 -	e = importer->set->files.data;
   1.807 -	e->name = root.name;
   1.808 -	e->flags = RAZOR_ENTRY_LAST;
   1.809 -	e->start = importer->files.size ? 1 : 0;
   1.810 -	list_set_empty(&e->packages);
   1.811 -
   1.812 -	serialize_files(importer->set, &root, &importer->set->files);
   1.813 -
   1.814 -	array_release(&importer->files);
   1.815 -}
   1.816 -
   1.817 -static struct razor_entry *
   1.818 -find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern);
   1.819 -
   1.820 -static void
   1.821 -list_to_array(struct list *list, struct array *array)
   1.822 -{
   1.823 -	uint32_t *item;
   1.824 -
   1.825 -	while (list) {
   1.826 -		 item = array_add(array, sizeof *item);
   1.827 -		 *item = list->data;
   1.828 -		 list = list_next(list);
   1.829 -	}
   1.830 -}
   1.831 -
   1.832 -static int
   1.833 -compare_file_requires(const void *p1, const void *p2, void *data)
   1.834 -{
   1.835 -	uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
   1.836 -	const char *pool = data;
   1.837 -
   1.838 -	return strcmp(&pool[*f1], &pool[*f2]);
   1.839 -}
   1.840 -
   1.841 -static void
   1.842 -find_file_provides(struct razor_importer *importer)
   1.843 -{
   1.844 -	struct razor_property *prop;
   1.845 -	struct razor_entry *top, *entry;
   1.846 -	struct razor_package *packages;
   1.847 -	struct array pkgprops;
   1.848 -	struct list *pkg;
   1.849 -	uint32_t *req, *req_start, *req_end;
   1.850 -	uint32_t *map, *newprop;
   1.851 -	char *pool;
   1.852 -
   1.853 -	pool = importer->set->string_pool.data;
   1.854 -	packages = importer->set->packages.data;
   1.855 -	top = importer->set->files.data;
   1.856 -
   1.857 -	req = req_start = importer->file_requires.data;
   1.858 -	req_end = importer->file_requires.data + importer->file_requires.size;
   1.859 -	map = razor_qsort_with_data(req, req_end - req, sizeof *req,
   1.860 -				    compare_file_requires, pool);
   1.861 -	free(map);
   1.862 -
   1.863 -	for (req = req_start; req < req_end; req++) {
   1.864 -		if (req > req_start && req[0] == req[-1])
   1.865 -			continue;
   1.866 -		entry = find_entry(importer->set, top, &pool[*req]);
   1.867 -		if (!entry)
   1.868 -			continue;
   1.869 -
   1.870 -		for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
   1.871 -			prop = array_add(&importer->set->properties, sizeof *prop);
   1.872 -			prop->name = *req;
   1.873 -			prop->type = RAZOR_PROPERTY_PROVIDES;
   1.874 -			prop->relation = RAZOR_VERSION_EQUAL;
   1.875 -			prop->version = hashtable_tokenize(&importer->table, "");
   1.876 -			list_set_ptr(&prop->packages, pkg->data);
   1.877 -
   1.878 -			/* Update property list of pkg */
   1.879 -			array_init(&pkgprops);
   1.880 -			list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
   1.881 -			newprop = array_add(&pkgprops, sizeof *newprop);
   1.882 -			*newprop = prop - (struct razor_property *)importer->set->properties.data;
   1.883 -			list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
   1.884 -			array_release(&pkgprops);
   1.885 -		}
   1.886 -	}
   1.887 -
   1.888 -	array_release(&importer->file_requires);
   1.889 -}
   1.890 -
   1.891 -static void
   1.892 -build_package_file_lists(struct razor_set *set, uint32_t *rmap)
   1.893 -{
   1.894 -	struct razor_package *p, *packages;
   1.895 -	struct array *pkgs;
   1.896 -	struct razor_entry *e, *end;
   1.897 -	struct list *r;
   1.898 -	uint32_t *q;
   1.899 -	int i, count;
   1.900 -
   1.901 -	count = set->packages.size / sizeof *p;
   1.902 -	pkgs = zalloc(count * sizeof *pkgs);
   1.903 -
   1.904 -	end = set->files.data + set->files.size;
   1.905 -	for (e = set->files.data; e < end; e++) {
   1.906 -		list_remap_head(&e->packages, rmap);
   1.907 -		r = list_first(&e->packages, &set->package_pool);
   1.908 -		while (r) {
   1.909 -			q = array_add(&pkgs[r->data], sizeof *q);
   1.910 -			*q = e - (struct razor_entry *) set->files.data;
   1.911 -			r = list_next(r);
   1.912 -		}
   1.913 -	}
   1.914 -
   1.915 -	packages = set->packages.data;
   1.916 -	for (i = 0; i < count; i++) {
   1.917 -		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
   1.918 -		array_release(&pkgs[i]);
   1.919 -	}
   1.920 -	free(pkgs);
   1.921 -}
   1.922 -
   1.923 -struct razor_set *
   1.924 -razor_importer_finish(struct razor_importer *importer)
   1.925 -{
   1.926 -	struct razor_set *set;
   1.927 -	uint32_t *map, *rmap;
   1.928 -	int i, count;
   1.929 -
   1.930 -	build_file_tree(importer);
   1.931 -	find_file_provides(importer);
   1.932 -
   1.933 -	map = uniqueify_properties(importer->set);
   1.934 -	list_remap_pool(&importer->set->property_pool, map);
   1.935 -	free(map);
   1.936 -
   1.937 -	count = importer->set->packages.size / sizeof(struct razor_package);
   1.938 -	map = razor_qsort_with_data(importer->set->packages.data,
   1.939 -				    count,
   1.940 -				    sizeof(struct razor_package),
   1.941 -				    compare_packages,
   1.942 -				    importer->set);
   1.943 -
   1.944 -	rmap = malloc(count * sizeof *rmap);
   1.945 -	for (i = 0; i < count; i++)
   1.946 -		rmap[map[i]] = i;
   1.947 -	free(map);
   1.948 -
   1.949 -	list_remap_pool(&importer->set->package_pool, rmap);
   1.950 -	build_package_file_lists(importer->set, rmap);
   1.951 -	remap_property_package_links(&importer->set->properties, rmap);
   1.952 -	free(rmap);
   1.953 -
   1.954 -	set = importer->set;
   1.955 -	hashtable_release(&importer->table);
   1.956 -	hashtable_release(&importer->file_table);
   1.957 -	hashtable_release(&importer->details_table);
   1.958 -	free(importer);
   1.959 -
   1.960 -	return set;
   1.961 -}
   1.962 -
   1.963 -struct razor_package_iterator {
   1.964 -	struct razor_set *set;
   1.965 -	struct razor_package *package, *end;
   1.966 -	struct list *index;
   1.967 -	int free_index;
   1.968 -};
   1.969 -
   1.970 -static struct razor_package_iterator *
   1.971 -razor_package_iterator_create_with_index(struct razor_set *set,
   1.972 -					 struct list *index)
   1.973 -{
   1.974 -	struct razor_package_iterator *pi;
   1.975 -
   1.976 -	pi = zalloc(sizeof *pi);
   1.977 -	pi->set = set;
   1.978 -	pi->index = index;
   1.979 -
   1.980 -	return pi;
   1.981 -}
   1.982 -
   1.983 -struct razor_package_iterator *
   1.984 -razor_package_iterator_create(struct razor_set *set)
   1.985 -{
   1.986 -	struct razor_package_iterator *pi;
   1.987 -
   1.988 -	pi = zalloc(sizeof *pi);
   1.989 -	pi->set = set;
   1.990 -	pi->end = set->packages.data + set->packages.size;
   1.991 -	pi->package = set->packages.data;
   1.992 -
   1.993 -	return pi;
   1.994 -}
   1.995 -
   1.996 -struct razor_package_iterator *
   1.997 -razor_package_iterator_create_for_property(struct razor_set *set,
   1.998 -					   struct razor_property *property)
   1.999 -{
  1.1000 -	struct list *index;
  1.1001 -
  1.1002 -	index = list_first(&property->packages, &set->package_pool);
  1.1003 -	return razor_package_iterator_create_with_index(set, index);
  1.1004 -}
  1.1005 -
  1.1006 -int
  1.1007 -razor_package_iterator_next(struct razor_package_iterator *pi,
  1.1008 -			    struct razor_package **package,
  1.1009 -			    const char **name,
  1.1010 -			    const char **version,
  1.1011 -			    const char **arch)
  1.1012 -{
  1.1013 -	char *pool;
  1.1014 -	int valid;
  1.1015 -	struct razor_package *p, *packages;
  1.1016 -
  1.1017 -	if (pi->package) {
  1.1018 -		p = pi->package++;
  1.1019 -		valid = p < pi->end;
  1.1020 -	} else if (pi->index) {
  1.1021 -		packages = pi->set->packages.data;
  1.1022 -		p = &packages[pi->index->data];
  1.1023 -		pi->index = list_next(pi->index);
  1.1024 -		valid = 1;
  1.1025 -	} else
  1.1026 -		valid = 0;
  1.1027 -
  1.1028 -	if (valid) {
  1.1029 -		pool = pi->set->string_pool.data;
  1.1030 -		*package = p;
  1.1031 -		*name = &pool[p->name];
  1.1032 -		*version = &pool[p->version];
  1.1033 -		*arch = &pool[p->arch];
  1.1034 -	} else {
  1.1035 -		*package = NULL;
  1.1036 -	}
  1.1037 -
  1.1038 -	return valid;
  1.1039 -}
  1.1040 -
  1.1041 -void
  1.1042 -razor_package_iterator_destroy(struct razor_package_iterator *pi)
  1.1043 -{
  1.1044 -	if (pi->free_index)
  1.1045 -		free(pi->index);
  1.1046 -
  1.1047 -	free(pi);
  1.1048 -}
  1.1049 -
  1.1050 -struct razor_package *
  1.1051 -razor_set_get_package(struct razor_set *set, const char *package)
  1.1052 -{
  1.1053 -	struct razor_package_iterator *pi;
  1.1054 -	struct razor_package *p;
  1.1055 -	const char *name, *version, *arch;
  1.1056 -
  1.1057 -	pi = razor_package_iterator_create(set);
  1.1058 -	while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
  1.1059 -		if (strcmp(package, name) == 0)
  1.1060 -			break;
  1.1061 -	}
  1.1062 -	razor_package_iterator_destroy(pi);
  1.1063 -
  1.1064 -	return p;
  1.1065 -}
  1.1066 -
  1.1067 -void
  1.1068 -razor_package_get_details(struct razor_set *set, struct razor_package *package,
  1.1069 -			  const char **summary, const char **description,
  1.1070 -			  const char **url, const char **license)
  1.1071 -{
  1.1072 -	const char *pool = set->details_string_pool.data;
  1.1073 -
  1.1074 -	*summary = &pool[package->summary];
  1.1075 -	*description = &pool[package->description];
  1.1076 -	*url = &pool[package->url];
  1.1077 -	*license = &pool[package->license];
  1.1078 -}
  1.1079 -
  1.1080 -struct razor_property_iterator {
  1.1081 -	struct razor_set *set;
  1.1082 -	struct razor_property *property, *end;
  1.1083 -	struct list *index;
  1.1084 -};
  1.1085 -
  1.1086 -struct razor_property_iterator *
  1.1087 -razor_property_iterator_create(struct razor_set *set,
  1.1088 -			       struct razor_package *package)
  1.1089 -{
  1.1090 -	struct razor_property_iterator *pi;
  1.1091 -
  1.1092 -	pi = zalloc(sizeof *pi);
  1.1093 -	pi->set = set;
  1.1094 -
  1.1095 -	if (package) {
  1.1096 -		pi->index = list_first(&package->properties,
  1.1097 -				       &set->property_pool);
  1.1098 -	} else {
  1.1099 -		pi->property = set->properties.data;
  1.1100 -		pi->end = set->properties.data + set->properties.size;
  1.1101 -	}
  1.1102 -
  1.1103 -	return pi;
  1.1104 -}
  1.1105 -
  1.1106 -int
  1.1107 -razor_property_iterator_next(struct razor_property_iterator *pi,
  1.1108 -			     struct razor_property **property,
  1.1109 -			     const char **name,
  1.1110 -			     enum razor_version_relation *relation,
  1.1111 -			     const char **version,
  1.1112 -			     enum razor_property_type *type)
  1.1113 -{
  1.1114 -	char *pool;
  1.1115 -	int valid;
  1.1116 -	struct razor_property *p, *properties;
  1.1117 -
  1.1118 -	if (pi->property) {
  1.1119 -		p = pi->property++;
  1.1120 -		valid = p < pi->end;
  1.1121 -	} else if (pi->index) {
  1.1122 -		properties = pi->set->properties.data;
  1.1123 -		p = &properties[pi->index->data];
  1.1124 -		pi->index = list_next(pi->index);
  1.1125 -		valid = 1;
  1.1126 -	} else
  1.1127 -		valid = 0;
  1.1128 -
  1.1129 -	if (valid) {
  1.1130 -		pool = pi->set->string_pool.data;
  1.1131 -		*property = p;
  1.1132 -		*name = &pool[p->name];
  1.1133 -		*relation = p->relation;
  1.1134 -		*version = &pool[p->version];
  1.1135 -		*type = p->type;
  1.1136 -	} else {
  1.1137 -		*property = NULL;
  1.1138 -	}
  1.1139 -
  1.1140 -	return valid;
  1.1141 -}
  1.1142 -
  1.1143 -void
  1.1144 -razor_property_iterator_destroy(struct razor_property_iterator *pi)
  1.1145 -{
  1.1146 -	free(pi);
  1.1147 -}
  1.1148 -
  1.1149 -static struct razor_entry *
  1.1150 -find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
  1.1151 -{
  1.1152 -	struct razor_entry *e;
  1.1153 -	const char *n, *pool = set->file_string_pool.data;
  1.1154 -	int len;
  1.1155 -
  1.1156 -	e = (struct razor_entry *) set->files.data + dir->start;
  1.1157 -	do {
  1.1158 -		n = pool + e->name;
  1.1159 -		if (strcmp(pattern + 1, n) == 0)
  1.1160 -			return e;
  1.1161 -		len = strlen(n);
  1.1162 -		if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
  1.1163 -		    pattern[len + 1] == '/') {
  1.1164 -			return find_entry(set, e, pattern + len + 1);
  1.1165 -		}
  1.1166 -	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
  1.1167 -
  1.1168 -	return NULL;
  1.1169 -}
  1.1170 -
  1.1171 -static void
  1.1172 -list_dir(struct razor_set *set, struct razor_entry *dir,
  1.1173 -	 char *prefix, const char *pattern)
  1.1174 -{
  1.1175 -	struct razor_entry *e;
  1.1176 -	const char *n, *pool = set->file_string_pool.data;
  1.1177 -
  1.1178 -	e = (struct razor_entry *) set->files.data + dir->start;
  1.1179 -	do {
  1.1180 -		n = pool + e->name;
  1.1181 -		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
  1.1182 -			continue;
  1.1183 -		printf("%s/%s\n", prefix, n);
  1.1184 -		if (e->start) {
  1.1185 -			char *sub = prefix + strlen (prefix);
  1.1186 -			*sub = '/';
  1.1187 -			strcpy (sub + 1, n);
  1.1188 -			list_dir(set, e, prefix, pattern);
  1.1189 -			*sub = '\0';
  1.1190 -		}
  1.1191 -	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
  1.1192 -}
  1.1193 -
  1.1194 -void
  1.1195 -razor_set_list_files(struct razor_set *set, const char *pattern)
  1.1196 -{
  1.1197 -	struct razor_entry *e;
  1.1198 -	char buffer[512], *p, *base;
  1.1199 -
  1.1200 -	if (pattern == NULL || !strcmp (pattern, "/")) {
  1.1201 -		buffer[0] = '\0';
  1.1202 -		list_dir(set, set->files.data, buffer, NULL);
  1.1203 -		return;
  1.1204 -	}
  1.1205 -
  1.1206 -	strcpy(buffer, pattern);
  1.1207 -	e = find_entry(set, set->files.data, buffer);
  1.1208 -	if (e && e->start > 0) {
  1.1209 -		base = NULL;
  1.1210 -	} else {
  1.1211 -		p = strrchr(buffer, '/');
  1.1212 -		if (p) {
  1.1213 -			*p = '\0';
  1.1214 -			base = p + 1;
  1.1215 -		} else {
  1.1216 -			base = NULL;
  1.1217 -		}
  1.1218 -	}
  1.1219 -	e = find_entry(set, set->files.data, buffer);
  1.1220 -	if (e->start != 0)
  1.1221 -		list_dir(set, e, buffer, base);
  1.1222 -}
  1.1223 -
  1.1224 -struct razor_package_iterator *
  1.1225 -razor_package_iterator_create_for_file(struct razor_set *set,
  1.1226 -				       const char *filename)
  1.1227 -{
  1.1228 -	struct razor_entry *entry;
  1.1229 -	struct list *index;
  1.1230 -
  1.1231 -	entry = find_entry(set, set->files.data, filename);
  1.1232 -	if (entry == NULL)
  1.1233 -		return NULL;
  1.1234 -	
  1.1235 -	index = list_first(&entry->packages, &set->package_pool);
  1.1236 -	return razor_package_iterator_create_with_index(set, index);
  1.1237 -}
  1.1238 -
  1.1239 -static struct list *
  1.1240 -list_package_files(struct razor_set *set, struct list *r,
  1.1241 -		   struct razor_entry *dir, uint32_t end,
  1.1242 -		   char *prefix)
  1.1243 -{
  1.1244 -	struct razor_entry *e, *f, *entries;
  1.1245 -	uint32_t next, file;
  1.1246 -	char *pool;
  1.1247 -	int len;
  1.1248 -	
  1.1249 -	entries = (struct razor_entry *) set->files.data;
  1.1250 -	pool = set->file_string_pool.data;
  1.1251 -
  1.1252 -	e = entries + dir->start;
  1.1253 -	do {
  1.1254 -		if (entries + r->data == e) {
  1.1255 -			printf("%s/%s\n", prefix, pool + e->name);
  1.1256 -			r = list_next(r);
  1.1257 -			if (!r)
  1.1258 -				return NULL;
  1.1259 -			if (r->data >= end)
  1.1260 -				return r;
  1.1261 -		}
  1.1262 -	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
  1.1263 -
  1.1264 -	e = entries + dir->start;
  1.1265 -	do {
  1.1266 -		if (e->start == 0)
  1.1267 -			continue;
  1.1268 -
  1.1269 -		if (e->flags & RAZOR_ENTRY_LAST)
  1.1270 -			next = end;
  1.1271 -		else {
  1.1272 -			f = e + 1; 
  1.1273 -			while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
  1.1274 -				f++;
  1.1275 -			if (f->start == 0)
  1.1276 -				next = end;
  1.1277 -			else
  1.1278 -				next = f->start;
  1.1279 -		}
  1.1280 -
  1.1281 -		file = r->data;
  1.1282 -		if (e->start <= file && file < next) {
  1.1283 -			len = strlen(prefix);
  1.1284 -			prefix[len] = '/';
  1.1285 -			strcpy(prefix + len + 1, pool + e->name);
  1.1286 -			r = list_package_files(set, r, e, next, prefix);
  1.1287 -			prefix[len] = '\0';
  1.1288 -		}
  1.1289 -	} while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
  1.1290 -
  1.1291 -	return r;
  1.1292 -}
  1.1293 -
  1.1294 -void
  1.1295 -razor_set_list_package_files(struct razor_set *set, const char *name)
  1.1296 -{
  1.1297 -	struct razor_package *package;
  1.1298 -	struct list *r;
  1.1299 -	uint32_t end;
  1.1300 -	char buffer[512];
  1.1301 -
  1.1302 -	package = razor_set_get_package(set, name);
  1.1303 -
  1.1304 -	r = list_first(&package->files, &set->file_pool);
  1.1305 -	end = set->files.size / sizeof (struct razor_entry);
  1.1306 -	buffer[0] = '\0';
  1.1307 -	list_package_files(set, r, set->files.data, end, buffer);
  1.1308 -}
  1.1309 -
  1.1310 -static void
  1.1311 -razor_set_validate(struct razor_set *set, struct array *unsatisfied)
  1.1312 -{
  1.1313 -	struct razor_property *r, *p, *end;
  1.1314 -	uint32_t *u;
  1.1315 -	char *pool;
  1.1316 -
  1.1317 -	end = set->properties.data + set->properties.size;
  1.1318 -	pool = set->string_pool.data;
  1.1319 -	
  1.1320 -	for (r = set->properties.data, p = r; r < end; r++) {
  1.1321 -		if (r->type != RAZOR_PROPERTY_REQUIRES)
  1.1322 -			continue;
  1.1323 -
  1.1324 -		p = r;
  1.1325 -		while (p < end && p->name == r->name &&
  1.1326 -		       p->type == r->type)
  1.1327 -			p++;
  1.1328 -
  1.1329 -		/* If there is more than one version of a provides,
  1.1330 -		 * seek to the end for the highest version. */
  1.1331 -		/* FIXME: This doesn't work if we have a series of
  1.1332 -		 * requires a = 1, provides a = 1, requires a = 2,
  1.1333 -		 * provides a = 2, as the kernel and kernel-devel
  1.1334 -		 * does.*/
  1.1335 -		while (p + 1 < end && p->name == (p + 1)->name &&
  1.1336 -		       p->type == (p + 1)->type)
  1.1337 -			p++;
  1.1338 -
  1.1339 -		/* FIXME: We need to track property flags (<, <=, =
  1.1340 -		 * etc) to properly determine if a requires is
  1.1341 -		 * satisfied.  The current code doesn't track that the
  1.1342 -		 * requires a = 1 isn't satisfied by a = 2 provides. */
  1.1343 -
  1.1344 -		if (p == end ||
  1.1345 -		    p->type != RAZOR_PROPERTY_PROVIDES ||
  1.1346 -		    r->name != p->name ||
  1.1347 -		    versioncmp(&pool[r->version], &pool[p->version]) > 0) {
  1.1348 -			/* FIXME: We ignore file requires for now. */
  1.1349 -			if (pool[r->name] == '/')
  1.1350 -				continue;
  1.1351 -			u = array_add(unsatisfied, sizeof *u);
  1.1352 -			*u = r - (struct razor_property *) set->properties.data;
  1.1353 -		}
  1.1354 -	}
  1.1355 -}
  1.1356 -
  1.1357 -void
  1.1358 -razor_set_list_unsatisfied(struct razor_set *set)
  1.1359 -{
  1.1360 -	struct array unsatisfied;
  1.1361 -	struct razor_property *properties, *r;
  1.1362 -	uint32_t *u, *end;
  1.1363 -	char *pool;
  1.1364 -
  1.1365 -	array_init(&unsatisfied);
  1.1366 -	razor_set_validate(set, &unsatisfied);
  1.1367 -
  1.1368 -	end = unsatisfied.data + unsatisfied.size;
  1.1369 -	properties = set->properties.data;
  1.1370 -	pool = set->string_pool.data;
  1.1371 -
  1.1372 -	for (u = unsatisfied.data; u < end; u++) {
  1.1373 -		r = properties + *u;
  1.1374 -		if (pool[r->version] == '\0')
  1.1375 -			printf("%s not satisfied\n",
  1.1376 -			       &pool[r->name]);
  1.1377 -		else
  1.1378 -			printf("%s-%s not satisfied\n",
  1.1379 -			       &pool[r->name],
  1.1380 -			       &pool[r->version]);
  1.1381 -	}
  1.1382 -
  1.1383 -	array_release(&unsatisfied);
  1.1384 -}
  1.1385 -
  1.1386 -#define UPSTREAM_SOURCE 0x80
  1.1387 -
  1.1388 -struct source {
  1.1389 -	struct razor_set *set;
  1.1390 -	uint32_t *property_map;
  1.1391 -	uint32_t *file_map;
  1.1392 -};
  1.1393 -
  1.1394 -struct razor_merger {
  1.1395 -	struct razor_set *set;
  1.1396 -	struct hashtable table;
  1.1397 -	struct hashtable file_table;
  1.1398 -	struct hashtable details_table;
  1.1399 -	struct source source1;
  1.1400 -	struct source source2;
  1.1401 -};
  1.1402 -
  1.1403 -static struct razor_merger *
  1.1404 -razor_merger_create(struct razor_set *set1, struct razor_set *set2)
  1.1405 -{
  1.1406 -	struct razor_merger *merger;
  1.1407 -	int count;
  1.1408 -	size_t size;
  1.1409 -
  1.1410 -	merger = zalloc(sizeof *merger);
  1.1411 -	merger->set = razor_set_create();
  1.1412 -	hashtable_init(&merger->table, &merger->set->string_pool);
  1.1413 -	hashtable_init(&merger->file_table, &merger->set->file_string_pool);
  1.1414 -	hashtable_init(&merger->details_table, &merger->set->details_string_pool);
  1.1415 -
  1.1416 -	merger->source1.set = set1;
  1.1417 -	count = set1->properties.size / sizeof (struct razor_property);
  1.1418 -	size = count * sizeof merger->source1.property_map[0];
  1.1419 -	merger->source1.property_map = zalloc(size);
  1.1420 -	count = set1->files.size / sizeof (struct razor_entry);
  1.1421 -	size = count * sizeof merger->source1.file_map[0];
  1.1422 -	merger->source1.file_map = zalloc(size);
  1.1423 -
  1.1424 -	merger->source2.set = set2;
  1.1425 -	count = set2->properties.size / sizeof (struct razor_property);
  1.1426 -	size = count * sizeof merger->source2.property_map[0];
  1.1427 -	merger->source2.property_map = zalloc(size);
  1.1428 -	count = set2->files.size / sizeof (struct razor_entry);
  1.1429 -	size = count * sizeof merger->source2.file_map[0];
  1.1430 -	merger->source2.file_map = zalloc(size);
  1.1431 -
  1.1432 -	return merger;
  1.1433 -}
  1.1434 -
  1.1435 -static void
  1.1436 -add_package(struct razor_merger *merger,
  1.1437 -	    struct razor_package *package, struct source *source,
  1.1438 -	    uint32_t flags)
  1.1439 -{
  1.1440 -	char *pool;
  1.1441 -	struct list *r;
  1.1442 -	struct razor_package *p;
  1.1443 -
  1.1444 -	pool = source->set->string_pool.data;
  1.1445 -	p = array_add(&merger->set->packages, sizeof *p);
  1.1446 -	p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
  1.1447 -	p->flags = flags;
  1.1448 -	p->version = hashtable_tokenize(&merger->table,
  1.1449 -					&pool[package->version]);
  1.1450 -	p->arch = hashtable_tokenize(&merger->table,
  1.1451 -				     &pool[package->arch]);
  1.1452 -
  1.1453 -	p->properties = package->properties;
  1.1454 -	r = list_first(&package->properties, &source->set->property_pool);
  1.1455 -	while (r) {
  1.1456 -		source->property_map[r->data] = 1;
  1.1457 -		r = list_next(r);
  1.1458 -	}
  1.1459 -
  1.1460 -	p->files = package->files;
  1.1461 -	r = list_first(&package->files, &source->set->file_pool);
  1.1462 -	while (r) {
  1.1463 -		source->file_map[r->data] = 1;
  1.1464 -		r = list_next(r);
  1.1465 -	}
  1.1466 -}
  1.1467 -
  1.1468 -static uint32_t
  1.1469 -add_property(struct razor_merger *merger,
  1.1470 -	     const char *name, enum razor_version_relation relation,
  1.1471 -	     const char *version, int type)
  1.1472 -{
  1.1473 -	struct razor_property *p;
  1.1474 -
  1.1475 -	p = array_add(&merger->set->properties, sizeof *p);
  1.1476 -	p->name = hashtable_tokenize(&merger->table, name);
  1.1477 -	p->flags = 0;
  1.1478 -	p->type = type;
  1.1479 -	p->relation = relation;
  1.1480 -	p->version = hashtable_tokenize(&merger->table, version);
  1.1481 -
  1.1482 -	return p - (struct razor_property *) merger->set->properties.data;
  1.1483 -}
  1.1484 -
  1.1485 -static void
  1.1486 -merge_properties(struct razor_merger *merger)
  1.1487 -{
  1.1488 -	struct razor_property *p1, *p2;
  1.1489 -	struct razor_set *set1, *set2;
  1.1490 -	uint32_t *map1, *map2;
  1.1491 -	int i, j, cmp, count1, count2;
  1.1492 -	char *pool1, *pool2;
  1.1493 -
  1.1494 -	set1 = merger->source1.set;
  1.1495 -	set2 = merger->source2.set;
  1.1496 -	map1 = merger->source1.property_map;
  1.1497 -	map2 = merger->source2.property_map;
  1.1498 -
  1.1499 -	i = 0;
  1.1500 -	j = 0;
  1.1501 -	pool1 = set1->string_pool.data;
  1.1502 -	pool2 = set2->string_pool.data;
  1.1503 -
  1.1504 -	count1 = set1->properties.size / sizeof *p1;
  1.1505 -	count2 = set2->properties.size / sizeof *p2;
  1.1506 -	while (i < count1 || j < count2) {
  1.1507 -		if (i < count1 && map1[i] == 0) {
  1.1508 -			i++;
  1.1509 -			continue;
  1.1510 -		}
  1.1511 -		if (j < count2 && map2[j] == 0) {
  1.1512 -			j++;
  1.1513 -			continue;
  1.1514 -		}
  1.1515 -		p1 = (struct razor_property *) set1->properties.data + i;
  1.1516 -		p2 = (struct razor_property *) set2->properties.data + j;
  1.1517 -		if (i < count1 && j < count2)
  1.1518 -			cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
  1.1519 -		else if (i < count1)
  1.1520 -			cmp = -1;
  1.1521 -		else
  1.1522 -			cmp = 1;
  1.1523 -		if (cmp == 0)
  1.1524 -			cmp = p1->type - p2->type;
  1.1525 -		if (cmp == 0)
  1.1526 -			cmp = p1->relation - p2->relation;
  1.1527 -		if (cmp == 0)
  1.1528 -			cmp = versioncmp(&pool1[p1->version],
  1.1529 -					 &pool2[p2->version]);
  1.1530 -		if (cmp < 0) {
  1.1531 -			map1[i++] = add_property(merger,
  1.1532 -						 &pool1[p1->name],
  1.1533 -						 p1->relation,
  1.1534 -						 &pool1[p1->version],
  1.1535 -						 p1->type);
  1.1536 -		} else if (cmp > 0) {
  1.1537 -			map2[j++] = add_property(merger,
  1.1538 -						 &pool2[p2->name],
  1.1539 -						 p2->relation,
  1.1540 -						 &pool2[p2->version],
  1.1541 -						 p2->type);
  1.1542 -		} else  {
  1.1543 -			map1[i++] = map2[j++] = add_property(merger,
  1.1544 -							     &pool1[p1->name],
  1.1545 -							     p1->relation,
  1.1546 -							     &pool1[p1->version],
  1.1547 -							     p1->type);
  1.1548 -		}
  1.1549 -	}
  1.1550 -}
  1.1551 -
  1.1552 -static void
  1.1553 -emit_properties(struct list_head *properties, struct array *source_pool,
  1.1554 -		uint32_t *map, struct array *pool)
  1.1555 -{
  1.1556 -	uint32_t r;
  1.1557 -	struct list *p, *q;
  1.1558 -
  1.1559 -	r = pool->size / sizeof *q;
  1.1560 -	p = list_first(properties, source_pool);
  1.1561 -	while (p) {
  1.1562 -		q = array_add(pool, sizeof *q);
  1.1563 -		q->data = map[p->data];
  1.1564 -		q->flags = p->flags;
  1.1565 -		p = list_next(p);
  1.1566 -	}
  1.1567 -
  1.1568 -	list_set_ptr(properties, r);
  1.1569 -}
  1.1570 -
  1.1571 -static uint32_t
  1.1572 -add_file(struct razor_merger *merger, const char *name)
  1.1573 -{
  1.1574 -	struct razor_entry *e;
  1.1575 -
  1.1576 -	e = array_add(&merger->set->files, sizeof *e);
  1.1577 -	e->name = hashtable_tokenize(&merger->file_table, name);
  1.1578 -	e->flags = 0;
  1.1579 -	e->start = 0;
  1.1580 -
  1.1581 -	return e - (struct razor_entry *)merger->set->files.data;
  1.1582 -}
  1.1583 -
  1.1584 -/* FIXME. Blah */
  1.1585 -static int
  1.1586 -fix_file_map(uint32_t *map,
  1.1587 -	     struct razor_entry *files,
  1.1588 -	     struct razor_entry *top)
  1.1589 -{
  1.1590 -	uint32_t e;
  1.1591 -	int found_file = 0;
  1.1592 -
  1.1593 -	e = top->start;
  1.1594 -	do {
  1.1595 -		if (files[e].start)
  1.1596 -			fix_file_map(map, files, &files[e]);
  1.1597 -		if (map[e])
  1.1598 -			found_file = 1;
  1.1599 -	} while (!(files[e++].flags & RAZOR_ENTRY_LAST));
  1.1600 -
  1.1601 -	if (found_file)
  1.1602 -		map[top - files] = 1;
  1.1603 -	return found_file;
  1.1604 -}
  1.1605 -
  1.1606 -struct merge_directory {
  1.1607 -	uint32_t merged, dir1, dir2;
  1.1608 -};
  1.1609 -
  1.1610 -static void
  1.1611 -merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
  1.1612 -{
  1.1613 -	struct razor_entry *root1, *root2, *mroot, *e1, *e2;
  1.1614 -	struct razor_set *set1, *set2;
  1.1615 -	struct array merge_stack;
  1.1616 -	struct merge_directory *child_md, *end_md;
  1.1617 -	uint32_t *map1, *map2, start, last;
  1.1618 -	int cmp;
  1.1619 -	char *pool1, *pool2;
  1.1620 -
  1.1621 -	set1 = merger->source1.set;
  1.1622 -	set2 = merger->source2.set;
  1.1623 -	map1 = merger->source1.file_map;
  1.1624 -	map2 = merger->source2.file_map;
  1.1625 -	pool1 = set1->string_pool.data;
  1.1626 -	pool2 = set2->string_pool.data;
  1.1627 -	root1 = (struct razor_entry *) set1->files.data;
  1.1628 -	root2 = (struct razor_entry *) set2->files.data;
  1.1629 -
  1.1630 -	array_init(&merge_stack);
  1.1631 -
  1.1632 -	start = merger->set->files.size / sizeof (struct razor_entry);
  1.1633 -	last = 0;
  1.1634 -	e1 = md->dir1 ? root1 + md->dir1 : NULL;
  1.1635 -	e2 = md->dir2 ? root2 + md->dir2 : NULL;
  1.1636 -	while (e1 || e2) {
  1.1637 -		if (!e2 && !map1[e1 - root1]) {
  1.1638 -			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1.1639 -				e1 = NULL;
  1.1640 -			continue;
  1.1641 -		}
  1.1642 -		if (!e1 && !map2[e2 - root2]) {
  1.1643 -			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1.1644 -				e2 = NULL;
  1.1645 -			continue;
  1.1646 -		}
  1.1647 -		if (e1 && !map1[e1 - root1] &&
  1.1648 -		    e2 && !map1[e2 - root2]) {
  1.1649 -			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1.1650 -				e1 = NULL;
  1.1651 -			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1.1652 -				e2 = NULL;
  1.1653 -			continue;
  1.1654 -		}
  1.1655 -
  1.1656 -		if (!e1)
  1.1657 -			cmp = 1;
  1.1658 -		else if (!e2)
  1.1659 -			cmp = -1;
  1.1660 -		else {
  1.1661 -			cmp = strcmp (&pool1[e1->name],
  1.1662 -				      &pool2[e2->name]);
  1.1663 -		}
  1.1664 -
  1.1665 -		if (cmp < 0) {
  1.1666 -			if (map1[e1 - root1]) {
  1.1667 -				map1[e1 - root1] = last =
  1.1668 -					add_file(merger, &pool1[e1->name]);
  1.1669 -				if (e1->start) {
  1.1670 -					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
  1.1671 -					child_md->merged = last;
  1.1672 -					child_md->dir1 = e1->start;
  1.1673 -					child_md->dir2 = 0;
  1.1674 -				}
  1.1675 -			}
  1.1676 -			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1.1677 -				e1 = NULL;
  1.1678 -		} else if (cmp > 0) {
  1.1679 -			if (map2[e2 - root2]) {
  1.1680 -				map2[e2 - root2] = last =
  1.1681 -					add_file(merger, &pool2[e2->name]);
  1.1682 -				if (e2->start) {
  1.1683 -					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
  1.1684 -					child_md->merged = last;
  1.1685 -					child_md->dir1 = 0;
  1.1686 -					child_md->dir2 = e2->start;
  1.1687 -				}
  1.1688 -			}
  1.1689 -			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1.1690 -				e2 = NULL;
  1.1691 -		} else {
  1.1692 -			map1[e1 - root1] = map2[e2- root2] = last =
  1.1693 -				add_file(merger, &pool1[e1->name]);
  1.1694 -			if (e1->start || e2->start) {
  1.1695 -				child_md = array_add(&merge_stack, sizeof (struct merge_directory));
  1.1696 -				child_md->merged = last;
  1.1697 -				child_md->dir1 = e1->start;
  1.1698 -				child_md->dir2 = e2->start;
  1.1699 -			}
  1.1700 -			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1.1701 -				e1 = NULL;
  1.1702 -			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1.1703 -				e2 = NULL;
  1.1704 -		}
  1.1705 -	}
  1.1706 -
  1.1707 -	mroot = (struct razor_entry *)merger->set->files.data;
  1.1708 -	if (last) {
  1.1709 -		mroot[last].flags = RAZOR_ENTRY_LAST;
  1.1710 -		mroot[md->merged].start = start;
  1.1711 -	} else
  1.1712 -		mroot[md->merged].start = 0;
  1.1713 -
  1.1714 -	end_md = merge_stack.data + merge_stack.size;
  1.1715 -	for (child_md = merge_stack.data; child_md < end_md; child_md++)
  1.1716 -		merge_one_directory(merger, child_md);
  1.1717 -	array_release(&merge_stack);
  1.1718 -}
  1.1719 -
  1.1720 -static void
  1.1721 -merge_files(struct razor_merger *merger)
  1.1722 -{
  1.1723 -	struct razor_entry *root;
  1.1724 -	struct merge_directory md;
  1.1725 -	uint32_t *map1, *map2;
  1.1726 -
  1.1727 -	map1 = merger->source1.file_map;
  1.1728 -	map2 = merger->source2.file_map;
  1.1729 -
  1.1730 -	md.merged = 0;
  1.1731 -
  1.1732 -	if (merger->source1.set->files.size) {
  1.1733 -		root = (struct razor_entry *) merger->source1.set->files.data;
  1.1734 -		if (root->start)
  1.1735 -			fix_file_map(map1, root, root);
  1.1736 -		md.dir1 = root->start;
  1.1737 -	} else
  1.1738 -		md.dir1 = 0;
  1.1739 -
  1.1740 -	if (merger->source2.set->files.size) {
  1.1741 -		root = (struct razor_entry *) merger->source2.set->files.data;
  1.1742 -		if (root->start)
  1.1743 -			fix_file_map(map2, root, root);
  1.1744 -		md.dir2 = root->start;
  1.1745 -	} else
  1.1746 -		md.dir2 = 0;
  1.1747 -
  1.1748 -	merge_one_directory(merger, &md);
  1.1749 -}
  1.1750 -
  1.1751 -static void
  1.1752 -emit_files(struct list_head *files, struct array *source_pool,
  1.1753 -	   uint32_t *map, struct array *pool)
  1.1754 -{
  1.1755 -	uint32_t r;
  1.1756 -	struct list *p, *q;
  1.1757 -
  1.1758 -	r = pool->size / sizeof *q;
  1.1759 -	p = list_first(files, source_pool);
  1.1760 -	while (p) {
  1.1761 -		q = array_add(pool, sizeof *q);
  1.1762 -		q->data = map[p->data];
  1.1763 -		q->flags = p->flags;
  1.1764 -		p = list_next(p);
  1.1765 -	}
  1.1766 -
  1.1767 -	list_set_ptr(files, r);
  1.1768 -}
  1.1769 -
  1.1770 -/* Rebuild property->packages maps.  We can't just remap these, as a
  1.1771 - * property may have lost or gained a number of packages.  Allocate an
  1.1772 - * array per property and loop through the packages and add them to
  1.1773 - * the arrays for their properties. */
  1.1774 -static void
  1.1775 -rebuild_property_package_lists(struct razor_set *set)
  1.1776 -{
  1.1777 -	struct array *pkgs, *a;
  1.1778 -	struct razor_package *pkg, *pkg_end;
  1.1779 -	struct razor_property *prop, *prop_end;
  1.1780 -	struct list *r;
  1.1781 -	uint32_t *q;
  1.1782 -	int count;
  1.1783 -
  1.1784 -	count = set->properties.size / sizeof (struct razor_property);
  1.1785 -	pkgs = zalloc(count * sizeof *pkgs);
  1.1786 -	pkg_end = set->packages.data + set->packages.size;
  1.1787 -
  1.1788 -	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
  1.1789 -		r = list_first(&pkg->properties, &set->property_pool);
  1.1790 -		while (r) {
  1.1791 -			q = array_add(&pkgs[r->data], sizeof *q);
  1.1792 -			*q = pkg - (struct razor_package *) set->packages.data;
  1.1793 -			r = list_next(r);
  1.1794 -		}
  1.1795 -	}
  1.1796 -
  1.1797 -	prop_end = set->properties.data + set->properties.size;
  1.1798 -	a = pkgs;
  1.1799 -	for (prop = set->properties.data; prop < prop_end; prop++, a++) {
  1.1800 -		list_set_array(&prop->packages, &set->package_pool, a, 0);
  1.1801 -		array_release(a);
  1.1802 -	}
  1.1803 -	free(pkgs);
  1.1804 -}
  1.1805 -
  1.1806 -static void
  1.1807 -rebuild_file_package_lists(struct razor_set *set)
  1.1808 -{
  1.1809 -	struct array *pkgs, *a;
  1.1810 -	struct razor_package *pkg, *pkg_end;
  1.1811 -	struct razor_entry *entry, *entry_end;
  1.1812 -	struct list *r;
  1.1813 -	uint32_t *q;
  1.1814 -	int count;
  1.1815 -
  1.1816 -	count = set->files.size / sizeof (struct razor_entry);
  1.1817 -	pkgs = zalloc(count * sizeof *pkgs);
  1.1818 -	pkg_end = set->packages.data + set->packages.size;
  1.1819 -
  1.1820 -	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
  1.1821 -		r = list_first(&pkg->files, &set->file_pool);
  1.1822 -		while (r) {
  1.1823 -			q = array_add(&pkgs[r->data], sizeof *q);
  1.1824 -			*q = pkg - (struct razor_package *) set->packages.data;
  1.1825 -			r = list_next(r);
  1.1826 -		}
  1.1827 -	}
  1.1828 -
  1.1829 -	entry_end = set->files.data + set->files.size;
  1.1830 -	a = pkgs;
  1.1831 -	for (entry = set->files.data; entry < entry_end; entry++, a++) {
  1.1832 -		list_set_array(&entry->packages, &set->package_pool, a, 0);
  1.1833 -		array_release(a);
  1.1834 -	}
  1.1835 -	free(pkgs);
  1.1836 -}
  1.1837 -
  1.1838 -static struct razor_set *
  1.1839 -razor_merger_finish(struct razor_merger *merger)
  1.1840 -{
  1.1841 -	struct razor_set *result;
  1.1842 -	struct razor_package *p, *pend;
  1.1843 -
  1.1844 -	/* As we built the package list, we filled out a bitvector of
  1.1845 -	 * the properties that are referenced by the packages in the
  1.1846 -	 * new set.  Now we do a parallel loop through the properties
  1.1847 -	 * and emit those marked in the bit vector to the new set.  In
  1.1848 -	 * the process, we update the bit vector to actually map from
  1.1849 -	 * indices in the old property list to indices in the new
  1.1850 -	 * property list for both sets. */
  1.1851 -
  1.1852 -	merge_properties(merger);
  1.1853 -	merge_files(merger);
  1.1854 -
  1.1855 -	/* Now we loop through the packages again and emit the
  1.1856 -	 * property lists, remapped to point to the new properties. */
  1.1857 -
  1.1858 -	pend = merger->set->packages.data + merger->set->packages.size;
  1.1859 -	for (p = merger->set->packages.data; p < pend; p++) {
  1.1860 -		struct source *src;
  1.1861 -
  1.1862 -		if (p->flags & UPSTREAM_SOURCE)
  1.1863 -			src = &merger->source2;
  1.1864 -		else
  1.1865 -			src = &merger->source1;
  1.1866 -
  1.1867 -		emit_properties(&p->properties,
  1.1868 -				&src->set->property_pool,
  1.1869 -				src->property_map,
  1.1870 -				&merger->set->property_pool);
  1.1871 -		emit_files(&p->files,
  1.1872 -			   &src->set->file_pool,
  1.1873 -			   src->file_map,
  1.1874 -			   &merger->set->file_pool);
  1.1875 -		p->flags &= ~UPSTREAM_SOURCE;
  1.1876 -	}
  1.1877 -
  1.1878 -	rebuild_property_package_lists(merger->set);
  1.1879 -	rebuild_file_package_lists(merger->set);
  1.1880 -
  1.1881 -	result = merger->set;
  1.1882 -	hashtable_release(&merger->table);
  1.1883 -	hashtable_release(&merger->file_table);
  1.1884 -	hashtable_release(&merger->details_table);
  1.1885 -	free(merger);
  1.1886 -
  1.1887 -	return result;
  1.1888 -}
  1.1889 -
  1.1890 -/* The diff order matters.  We should sort the packages so that a
  1.1891 - * REMOVE of a package comes before the INSTALL, and so that all
  1.1892 - * requires for a package have been installed before the package.
  1.1893 - **/
  1.1894 -
  1.1895 -void
  1.1896 -razor_set_diff(struct razor_set *set, struct razor_set *upstream,
  1.1897 -	       razor_package_callback_t callback, void *data)
  1.1898 -{
  1.1899 -	struct razor_package_iterator *pi1, *pi2;
  1.1900 -	struct razor_package *p1, *p2;
  1.1901 -	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
  1.1902 -	int res;
  1.1903 -
  1.1904 -	pi1 = razor_package_iterator_create(set);
  1.1905 -	pi2 = razor_package_iterator_create(upstream);
  1.1906 -
  1.1907 -	razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
  1.1908 -	razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
  1.1909 -
  1.1910 -	while (p1 || p2) {
  1.1911 -		if (p1 && p2) {
  1.1912 -			res = strcmp(name1, name2);
  1.1913 -			if (res == 0)
  1.1914 -				res = versioncmp(version1, version2);
  1.1915 -		} else {
  1.1916 -			res = 0;
  1.1917 -		}
  1.1918 -
  1.1919 -		if (p2 == NULL || res < 0)
  1.1920 -			callback(name1, version1, NULL, arch1, data);
  1.1921 -		else if (p1 == NULL || res > 0)
  1.1922 -			callback(name2, NULL, version2, arch2, data);
  1.1923 -
  1.1924 -		if (p1 != NULL && res <= 0)
  1.1925 -			razor_package_iterator_next(pi1, &p1,
  1.1926 -						    &name1, &version1, &arch1);
  1.1927 -		if (p2 != NULL && res >= 0)
  1.1928 -			razor_package_iterator_next(pi2, &p2,
  1.1929 -						    &name2, &version2, &arch2);
  1.1930 -	}
  1.1931 -
  1.1932 -	razor_package_iterator_destroy(pi1);
  1.1933 -	razor_package_iterator_destroy(pi2);
  1.1934 -}
  1.1935 -
  1.1936 -struct razor_transaction;
  1.1937 -struct razor_transaction_package;
  1.1938 -struct razor_transaction_resolver;
  1.1939 -
  1.1940 -struct razor_transaction {
  1.1941 -	int package_count, errors;
  1.1942 -	struct razor_set *system, *upstream;
  1.1943 -
  1.1944 -	struct bitarray syspkgs, uppkgs;
  1.1945 -	struct array packages;
  1.1946 -};
  1.1947 -
  1.1948 -struct razor_transaction_package {
  1.1949 -	const char *name, *old_version, *new_version;
  1.1950 -	struct razor_package *old_package, *new_package;
  1.1951 -	enum razor_transaction_package_state state;
  1.1952 -
  1.1953 -	/* dep_package is the name of the package that resulted in
  1.1954 -	 * this entry being created (or NULL if the user requested the
  1.1955 -	 * install/remove), with the other dep_ fields providing
  1.1956 -	 * additional information.
  1.1957 -	 *
  1.1958 -	 * For INSTALL, if dep_type is REQUIRES, then dep_package
  1.1959 -	 * required something that this package provides. If dep_type
  1.1960 -	 * is CONFLICTS, then dep_package is a package that conflicted
  1.1961 -	 * with an older version of this package, forcing an upgrade.
  1.1962 -	 *
  1.1963 -	 * For REMOVE, if dep_type is REQUIRES, then dep_package is a
  1.1964 -	 * package that is being removed. If dep_type is OBSOLETES,
  1.1965 -	 * then dep_package is a package that obsoletes this one.
  1.1966 -	 *
  1.1967 -	 * For OLD_CONFLICT or NEW_CONFLICT, dep_package is an
  1.1968 -	 * existing package that conflicts with this one. The
  1.1969 -	 * conflicting property comes from the already-installed
  1.1970 -	 * package for OLD_CONFLICT, or the to-be-installed package
  1.1971 -	 * for NEW_CONFLICT.
  1.1972 -	 *
  1.1973 -	 * For UNSATISFIABLE, the dep_ fields are as for an INSTALL,
  1.1974 -	 * but the name field will be NULL.
  1.1975 -	 */
  1.1976 -	const char *dep_package;
  1.1977 -	enum razor_property_type dep_type;
  1.1978 -	const char *dep_property;
  1.1979 -	enum razor_version_relation dep_relation;
  1.1980 -	const char *dep_version;
  1.1981 -};
  1.1982 -
  1.1983 -static int
  1.1984 -package_in_set(void *package, struct razor_set *set)
  1.1985 -{
  1.1986 -	return package >= set->packages.data &&
  1.1987 -		package < set->packages.data + set->packages.size;
  1.1988 -}
  1.1989 -
  1.1990 -static int
  1.1991 -property_in_set(void *property, struct razor_set *set)
  1.1992 -{
  1.1993 -	return property >= set->properties.data &&
  1.1994 -		property < set->properties.data + set->properties.size;
  1.1995 -}
  1.1996 -
  1.1997 -static struct razor_package *
  1.1998 -property_provider_package(struct razor_transaction *trans,
  1.1999 -			  struct razor_property *prop,
  1.2000 -			  int installed)
  1.2001 -{
  1.2002 -	struct razor_set *set;
  1.2003 -	struct bitarray *pkgbits;
  1.2004 -	struct razor_package *pkgs;
  1.2005 -	struct list *p;
  1.2006 -
  1.2007 -	if (installed && prop->type != RAZOR_PROPERTY_PROVIDES)
  1.2008 -		return NULL;
  1.2009 -	else if (!installed &&
  1.2010 -		 prop->type != RAZOR_PROPERTY_PROVIDES &&
  1.2011 -		 prop->type != RAZOR_PROPERTY_OBSOLETES)
  1.2012 -		return NULL;
  1.2013 -
  1.2014 -	if (property_in_set(prop, trans->system)) {
  1.2015 -		set = trans->system;
  1.2016 -		pkgbits = &trans->syspkgs;
  1.2017 -	} else {
  1.2018 -		set = trans->upstream;
  1.2019 -		pkgbits = &trans->uppkgs;
  1.2020 -	}
  1.2021 -	pkgs = set->packages.data;
  1.2022 -
  1.2023 -	for (p = list_first(&prop->packages, &set->package_pool); p; p = list_next(p)) {
  1.2024 -		if (bitarray_get(pkgbits, p->data) != installed)
  1.2025 -			continue;
  1.2026 -		if (prop->type == RAZOR_PROPERTY_OBSOLETES ||
  1.2027 -		    pkgs[p->data].name == prop->name)
  1.2028 -			return &pkgs[p->data];
  1.2029 -	}
  1.2030 -	return NULL;
  1.2031 -}
  1.2032 -
  1.2033 -static int
  1.2034 -compare_transaction_packages(const void *one, const void *two)
  1.2035 -{
  1.2036 -	struct razor_transaction_package **tp1 = (void *)one;
  1.2037 -	struct razor_transaction_package **tp2 = (void *)two;
  1.2038 -
  1.2039 -	if (!(*tp1)->name)
  1.2040 -		return 1;
  1.2041 -	else if (!(*tp2)->name)
  1.2042 -		return -1;
  1.2043 -	else
  1.2044 -		return strcmp((*tp1)->name, (*tp2)->name);
  1.2045 -}
  1.2046 -
  1.2047 -/* FIXME: merge this into the other property loop in razor_transaction_satisfy */
  1.2048 -static void
  1.2049 -resolve_new_packages(struct razor_transaction *trans,
  1.2050 -		     int start, int end)
  1.2051 -{
  1.2052 -	struct razor_property *sp, *up, *sp_end, *up_end;
  1.2053 -	struct razor_package *spkg, *spkgs, *upkg, *upkgs;
  1.2054 -	struct razor_transaction_package **packages;
  1.2055 -	const char *spool, *upool;
  1.2056 -	int i;
  1.2057 -
  1.2058 -	sp_end = trans->system->properties.data + trans->system->properties.size;
  1.2059 -	spool = trans->system->string_pool.data;
  1.2060 -	spkgs = trans->system->packages.data;
  1.2061 -	up_end = trans->upstream->properties.data + trans->upstream->properties.size;
  1.2062 -	upool = trans->upstream->string_pool.data;
  1.2063 -	upkgs = trans->upstream->packages.data;
  1.2064 -
  1.2065 -	/* FIXME, check if sorting the packages directly (rather than
  1.2066 -	 * sorting pointers-to-packages) still results in confusing
  1.2067 -	 * descriptions.
  1.2068 -	 */
  1.2069 -	packages = calloc(end - start, sizeof *packages);
  1.2070 -	for (i = start; i < end; i++)
  1.2071 -		packages[i - start] = ((struct razor_transaction_package *)trans->packages.data) + i;
  1.2072 -	qsort(packages, end - start, sizeof *packages,
  1.2073 -	      compare_transaction_packages);
  1.2074 -
  1.2075 -	sp = trans->system->properties.data;
  1.2076 -	up = trans->upstream->properties.data;
  1.2077 -	for (i = 0; i < end - start; i++) {
  1.2078 -		if (!packages[i]->name ||
  1.2079 -		    packages[i]->state >= RAZOR_PACKAGE_FIRST_ERROR_STATE)
  1.2080 -			continue;
  1.2081 -
  1.2082 -		spkg = NULL;
  1.2083 -		while (sp < sp_end &&
  1.2084 -		       strcmp(&spool[sp->name], packages[i]->name) < 0)
  1.2085 -			sp++;
  1.2086 -		while (sp < sp_end &&
  1.2087 -		       strcmp(&spool[sp->name], packages[i]->name) == 0 &&
  1.2088 -		       !(spkg = property_provider_package(trans, sp, 1)))
  1.2089 -			sp++;
  1.2090 -
  1.2091 -		upkg = NULL;
  1.2092 -		while (up < up_end &&
  1.2093 -		       strcmp(&upool[up->name], packages[i]->name) < 0)
  1.2094 -			up++;
  1.2095 -		while (up < up_end &&
  1.2096 -		       strcmp(&upool[up->name], packages[i]->name) == 0 &&
  1.2097 -		       !(upkg = property_provider_package(trans, up, 0)))
  1.2098 -			up++;
  1.2099 -
  1.2100 -		if (packages[i]->state == RAZOR_PACKAGE_REMOVE ||
  1.2101 -		    packages[i]->state == RAZOR_PACKAGE_OBSOLETED) {
  1.2102 -			if (spkg) {
  1.2103 -				packages[i]->old_package = spkg;
  1.2104 -				packages[i]->name = &spool[spkg->name];
  1.2105 -				packages[i]->old_version = &spool[spkg->version];
  1.2106 -				bitarray_set(&trans->syspkgs, spkg - spkgs, 0);
  1.2107 -			}
  1.2108 -			if (!packages[i]->old_package) {
  1.2109 -				packages[i]->name = strdup(packages[i]->name);
  1.2110 -				packages[i]->state |= RAZOR_PACKAGE_UNAVAILABLE_FLAG;
  1.2111 -				trans->errors++;
  1.2112 -			}
  1.2113 -		} else {
  1.2114 -			if (upkg) {
  1.2115 -				packages[i]->new_package = upkg;
  1.2116 -				packages[i]->name = &upool[upkg->name];
  1.2117 -				packages[i]->new_version = &upool[upkg->version];
  1.2118 -
  1.2119 -				if (up->name != upkg->name) {
  1.2120 -					packages[i]->dep_package = &upool[upkg->name];
  1.2121 -					packages[i]->dep_type = up->type;
  1.2122 -					packages[i]->dep_property = &upool[up->name];
  1.2123 -					packages[i]->dep_relation = up->relation;
  1.2124 -					packages[i]->dep_version = &upool[up->version];
  1.2125 -				}
  1.2126 -
  1.2127 -				if (spkg) {
  1.2128 -					packages[i]->old_package = spkg;
  1.2129 -					packages[i]->old_version = &spool[spkg->version];
  1.2130 -					if (versioncmp(&spool[spkg->version], &upool[up->version]) >= 0) {
  1.2131 -						packages[i]->state = RAZOR_PACKAGE_UP_TO_DATE;
  1.2132 -						trans->errors++;
  1.2133 -						continue;
  1.2134 -					}
  1.2135 -					bitarray_set(&trans->syspkgs, spkg - spkgs, 0);
  1.2136 -				}
  1.2137 -				bitarray_set(&trans->uppkgs, upkg - upkgs, 1);
  1.2138 -			}
  1.2139 -			if (!packages[i]->new_package) {
  1.2140 -				packages[i]->name = strdup(packages[i]->name);
  1.2141 -				packages[i]->state |= RAZOR_PACKAGE_UNAVAILABLE_FLAG;
  1.2142 -				trans->errors++;
  1.2143 -			}
  1.2144 -		}
  1.2145 -	}
  1.2146 -}
  1.2147 -
  1.2148 -static int
  1.2149 -provider_satisfies_requirement(struct razor_property *provider,
  1.2150 -			       const char *provider_strings,
  1.2151 -			       struct razor_property *requirement,
  1.2152 -			       const char *requirement_strings)
  1.2153 -{
  1.2154 -	int cmp, len;
  1.2155 -	const char *provided = &provider_strings[provider->version];
  1.2156 -	const char *required = &requirement_strings[requirement->version];
  1.2157 -
  1.2158 -	if (!*required)
  1.2159 -		return 1;
  1.2160 -	if (!*provided) {
  1.2161 -		if (requirement->relation >= RAZOR_VERSION_EQUAL)
  1.2162 -			return 1;
  1.2163 -		else
  1.2164 -			return 0;
  1.2165 -	}
  1.2166 -
  1.2167 -	cmp = versioncmp(provided, required);
  1.2168 -
  1.2169 -	switch (requirement->relation) {
  1.2170 -	case RAZOR_VERSION_LESS:
  1.2171 -		return cmp < 0;
  1.2172 -
  1.2173 -	case RAZOR_VERSION_LESS_OR_EQUAL:
  1.2174 -		if (cmp <= 0)
  1.2175 -			return 1;
  1.2176 -		/* fall through: FIXME, make sure this is correct */
  1.2177 -
  1.2178 -	case RAZOR_VERSION_EQUAL:
  1.2179 -		if (cmp == 0)
  1.2180 -			return 1;
  1.2181 -
  1.2182 -		/* "foo == 1.1" is satisfied by "foo 1.1-2" */
  1.2183 -		len = strlen(required);
  1.2184 -		if (!strncmp(required, provided, len) && provided[len] == '-')
  1.2185 -			return 1;
  1.2186 -		return 0;
  1.2187 -
  1.2188 -	case RAZOR_VERSION_GREATER_OR_EQUAL:
  1.2189 -		return cmp >= 0;
  1.2190 -
  1.2191 -	case RAZOR_VERSION_GREATER:
  1.2192 -		return cmp > 0;
  1.2193 -	}
  1.2194 -
  1.2195 -	/* shouldn't happen */
  1.2196 -	return 0;
  1.2197 -}
  1.2198 -
  1.2199 -static struct razor_package *
  1.2200 -find_package_for_file(struct razor_set *set, struct bitarray *pkgbits,
  1.2201 -		      const char *filename, int installed)
  1.2202 -{
  1.2203 -	struct razor_package *pkgs = set->packages.data;
  1.2204 -	struct razor_entry *entry;
  1.2205 -	struct list *p;
  1.2206 -
  1.2207 -	if (filename[0] != '/')
  1.2208 -		return 0;
  1.2209 -
  1.2210 -	entry = find_entry(set, set->files.data, filename);
  1.2211 -	if (!entry)
  1.2212 -		return 0;
  1.2213 -
  1.2214 -	for (p = list_first(&entry->packages, &set->package_pool); p; p = list_next(p)) {
  1.2215 -		if (bitarray_get(pkgbits, p->data) == installed)
  1.2216 -			return &pkgs[p->data];
  1.2217 -	}
  1.2218 -	return NULL;
  1.2219 -}
  1.2220 -
  1.2221 -static struct razor_package *
  1.2222 -find_installed_package_for_file(struct razor_transaction *trans,
  1.2223 -				const char *filename)
  1.2224 -{
  1.2225 -	struct razor_package *pkg;
  1.2226 -
  1.2227 -	pkg = find_package_for_file(trans->system, &trans->syspkgs,
  1.2228 -				    filename, 1);
  1.2229 -	if (!pkg)
  1.2230 -		pkg = find_package_for_file(trans->upstream, &trans->uppkgs,
  1.2231 -					    filename, 1);
  1.2232 -	return pkg;
  1.2233 -}
  1.2234 -
  1.2235 -static struct razor_package *
  1.2236 -find_uninstalled_package_for_file(struct razor_transaction *trans,
  1.2237 -				  const char *filename)
  1.2238 -{
  1.2239 -	struct razor_package *pkg;
  1.2240 -
  1.2241 -	pkg = find_package_for_file(trans->upstream, &trans->uppkgs,
  1.2242 -				    filename, 0);
  1.2243 -	if (!pkg)
  1.2244 -		pkg = find_package_for_file(trans->system, &trans->syspkgs,
  1.2245 -					    filename, 0);
  1.2246 -	return pkg;
  1.2247 -}
  1.2248 -
  1.2249 -static struct razor_property *
  1.2250 -skip_to_matching_property(struct razor_transaction *trans,
  1.2251 -			  struct razor_property *match,
  1.2252 -			  struct razor_property *prop)
  1.2253 -{
  1.2254 -	struct razor_set *mset, *pset;
  1.2255 -	const char *ppool, *mpool;
  1.2256 -	struct razor_property *prop_end;
  1.2257 -
  1.2258 -	if (property_in_set(match, trans->system))
  1.2259 -		mset = trans->system;
  1.2260 -	else
  1.2261 -		mset = trans->upstream;
  1.2262 -
  1.2263 -	if (property_in_set(prop, trans->system))
  1.2264 -		pset = trans->system;
  1.2265 -	else if (property_in_set(prop, trans->upstream))
  1.2266 -		pset = trans->upstream;
  1.2267 -	else
  1.2268 -		return prop;
  1.2269 -
  1.2270 -	prop_end = pset->properties.data + pset->properties.size;
  1.2271 -	ppool = pset->string_pool.data;
  1.2272 -	mpool = mset->string_pool.data;
  1.2273 -
  1.2274 -	while (prop < prop_end &&
  1.2275 -	       strcmp(&ppool[prop->name], &mpool[match->name]) < 0)
  1.2276 -		prop++;
  1.2277 -	return prop;
  1.2278 -}
  1.2279 -
  1.2280 -static struct razor_package *
  1.2281 -find_package_matching(struct razor_transaction *trans, int installed,
  1.2282 -		      struct razor_property *prop,
  1.2283 -		      struct razor_property *req,
  1.2284 -		      struct razor_set *req_set)
  1.2285 -{
  1.2286 -	struct razor_set *set;
  1.2287 -	struct bitarray *pkgbits;
  1.2288 -	struct razor_package *pkgs;
  1.2289 -	struct razor_property *props, *prop_end;
  1.2290 -	enum razor_property_type match_type;
  1.2291 -	const char *pool;
  1.2292 -	const char *rpool;
  1.2293 -	int match_name = (req->type == RAZOR_PROPERTY_OBSOLETES);
  1.2294 -	int match;
  1.2295 -
  1.2296 -	if (property_in_set(prop, trans->system)) {
  1.2297 -		set = trans->system;
  1.2298 -		pkgbits = &trans->syspkgs;
  1.2299 -	} else if (property_in_set(prop, trans->upstream)) {
  1.2300 -		set = trans->upstream;
  1.2301 -		pkgbits = &trans->uppkgs;
  1.2302 -	} else
  1.2303 -		return NULL;
  1.2304 -
  1.2305 -	if (!req_set) {
  1.2306 -		if (property_in_set(req, trans->system))
  1.2307 -			req_set = trans->system;
  1.2308 -		else
  1.2309 -			req_set = trans->upstream;
  1.2310 -	}
  1.2311 -	rpool = req_set->string_pool.data;
  1.2312 -
  1.2313 -	if (req->type == RAZOR_PROPERTY_PROVIDES)
  1.2314 -		match_type = RAZOR_PROPERTY_CONFLICTS;
  1.2315 -	else
  1.2316 -		match_type = RAZOR_PROPERTY_PROVIDES;
  1.2317 -
  1.2318 -	pkgs = set->packages.data;
  1.2319 -	props = set->properties.data;
  1.2320 -	prop_end = set->properties.data + set->properties.size;
  1.2321 -	pool = set->string_pool.data;
  1.2322 -
  1.2323 -	/* Find first matching property */
  1.2324 -	while (prop < prop_end &&
  1.2325 -	       strcmp(&pool[prop->name], &rpool[req->name]) < 0)
  1.2326 -		prop++;
  1.2327 -	if (prop == prop_end ||
  1.2328 -	    strcmp(&pool[prop->name], &rpool[req->name]) > 0)
  1.2329 -		return NULL;
  1.2330 -
  1.2331 -	if (prop->type < match_type) {
  1.2332 -		while (prop < prop_end && prop->type != match_type)
  1.2333 -			prop++;
  1.2334 -	} else {
  1.2335 -		while (prop >= props && prop->type != match_type)
  1.2336 -			prop--;
  1.2337 -		while (prop > props + 1 && (prop - 1)->name == prop->name &&
  1.2338 -		       (prop - 1)->type == match_type)
  1.2339 -			prop--;
  1.2340 -	}
  1.2341 -
  1.2342 -	/* Scan matching properties */
  1.2343 -	while (prop < prop_end && prop->type == match_type &&
  1.2344 -	       strcmp(&pool[prop->name], &rpool[req->name]) == 0) {
  1.2345 -		if (match_type == RAZOR_PROPERTY_PROVIDES)
  1.2346 -			match = provider_satisfies_requirement(prop, pool, req, rpool);
  1.2347 -		else
  1.2348 -			match = provider_satisfies_requirement(req, rpool, prop, pool);
  1.2349 -		if (match) {
  1.2350 -			struct list *pkg;
  1.2351 -
  1.2352 -			for (pkg = list_first(&prop->packages, &set->package_pool); pkg; pkg = list_next(pkg)) {
  1.2353 -				if (bitarray_get(pkgbits, pkg->data) != installed)
  1.2354 -					continue;
  1.2355 -				if (!match_name ||
  1.2356 -				    strcmp(&pool[pkgs[pkg->data].name],
  1.2357 -					   &rpool[req->name]) == 0)
  1.2358 -					return &pkgs[pkg->data];
  1.2359 -			}
  1.2360 -		}
  1.2361 -		prop++;
  1.2362 -	}
  1.2363 -
  1.2364 -	return NULL;
  1.2365 -}
  1.2366 -
  1.2367 -static struct razor_package *
  1.2368 -find_installed_package_for_property(struct razor_transaction *trans,
  1.2369 -				    struct razor_property *sys_start,
  1.2370 -				    struct razor_property *up_start,
  1.2371 -				    struct razor_property *req)
  1.2372 -{
  1.2373 -	struct razor_package *pkg;
  1.2374 -
  1.2375 -	pkg = find_package_matching(trans, 1, sys_start, req, NULL);
  1.2376 -	if (!pkg)
  1.2377 -		pkg = find_package_matching(trans, 1, up_start, req, NULL);
  1.2378 -	return pkg;
  1.2379 -}
  1.2380 -
  1.2381 -static struct razor_package *
  1.2382 -find_uninstalled_package_for_property(struct razor_transaction *trans,
  1.2383 -				      struct razor_property *sys_start,
  1.2384 -				      struct razor_property *up_start,
  1.2385 -				      struct razor_property *req)
  1.2386 -{
  1.2387 -	struct razor_package *pkg;
  1.2388 -
  1.2389 -	pkg = find_package_matching(trans, 0, up_start, req, NULL);
  1.2390 -	if (!pkg)
  1.2391 -		pkg = find_package_matching(trans, 0, sys_start, req, NULL);
  1.2392 -	return pkg;
  1.2393 -}
  1.2394 -
  1.2395 -static struct razor_transaction_package *
  1.2396 -find_transaction_package(struct razor_transaction *trans, const char *name)
  1.2397 -{
  1.2398 -	struct razor_transaction_package *packages;
  1.2399 -	int count, i;
  1.2400 -
  1.2401 -	packages = trans->packages.data;
  1.2402 -	count = trans->packages.size / sizeof *packages;
  1.2403 -	for (i = 0; i < count; i++) {
  1.2404 -		if (packages[i].name && !strcmp(packages[i].name, name))
  1.2405 -			return &packages[i];
  1.2406 -	}
  1.2407 -	return NULL;
  1.2408 -}
  1.2409 -
  1.2410 -/* FIXME? */
  1.2411 -static int
  1.2412 -prop_is_being_installed(struct razor_transaction *trans,
  1.2413 -			struct razor_property *prop)
  1.2414 -{
  1.2415 -	struct list *pkg;
  1.2416 -
  1.2417 -	for (pkg = list_first(&prop->packages, &trans->upstream->package_pool); pkg; pkg = list_next(pkg)) {
  1.2418 -		if (bitarray_get(&trans->uppkgs, pkg->data))
  1.2419 -			return 1;
  1.2420 -	}
  1.2421 -	return 0;
  1.2422 -}
  1.2423 -
  1.2424 -static int
  1.2425 -prop_is_being_removed(struct razor_transaction *trans,
  1.2426 -		      struct razor_property *prop)
  1.2427 -{
  1.2428 -	struct list *pkg;
  1.2429 -
  1.2430 -	for (pkg = list_first(&prop->packages, &trans->system->package_pool); pkg; pkg = list_next(pkg)) {
  1.2431 -		if (bitarray_get(&trans->syspkgs, pkg->data))
  1.2432 -			return 0;
  1.2433 -	}
  1.2434 -	return 1;
  1.2435 -}
  1.2436 -
  1.2437 -static int
  1.2438 -prop_is_being_updated(struct razor_transaction *trans,
  1.2439 -		      struct razor_property *prop)
  1.2440 -{
  1.2441 -	struct razor_package *packages = trans->system->packages.data;
  1.2442 -	const char *pool = trans->system->string_pool.data;
  1.2443 -	struct razor_transaction_package *tp;
  1.2444 -	struct list *pkg;
  1.2445 -
  1.2446 -	/* Assumes prop_is_being_removed returns true */
  1.2447 -
  1.2448 -	for (pkg = list_first(&prop->packages, &trans->system->package_pool); pkg; pkg = list_next(pkg)) {
  1.2449 -		tp = find_transaction_package(trans, &pool[packages[pkg->data].name]);
  1.2450 -		if (tp && tp->state == RAZOR_PACKAGE_REMOVE)
  1.2451 -			return 0;
  1.2452 -	}
  1.2453 -	return 1;
  1.2454 -}
  1.2455 -
  1.2456 -static void
  1.2457 -add_transaction_package(struct razor_transaction *trans,
  1.2458 -			struct razor_package *new_package,
  1.2459 -			struct razor_package *old_package,
  1.2460 -			enum razor_transaction_package_state state,
  1.2461 -			const char *req_package,
  1.2462 -			struct razor_property *req_prop)
  1.2463 -{
  1.2464 -	struct razor_set *new_package_set, *old_package_set, *req_set;
  1.2465 -	struct bitarray *reqpkgbits;
  1.2466 -	struct razor_transaction_package *tp, *already;
  1.2467 -	const char *pool;
  1.2468 -	struct razor_package *pkgs;
  1.2469 -	struct list *pkg;
  1.2470 -	int contradiction = 0;
  1.2471 -
  1.2472 -	if (package_in_set(new_package, trans->system))
  1.2473 -		new_package_set = trans->system;
  1.2474 -	else
  1.2475 -		new_package_set = trans->upstream;
  1.2476 -	if (package_in_set(old_package, trans->system))
  1.2477 -		old_package_set = trans->system;
  1.2478 -	else
  1.2479 -		old_package_set = trans->upstream;
  1.2480 -	if (property_in_set(req_prop, trans->system)) {
  1.2481 -		req_set = trans->system;
  1.2482 -		reqpkgbits = &trans->syspkgs;
  1.2483 -	} else {
  1.2484 -		req_set = trans->upstream;
  1.2485 -		reqpkgbits = &trans->uppkgs;
  1.2486 -	}
  1.2487 -
  1.2488 -	if (new_package) {
  1.2489 -		pool = new_package_set->string_pool.data;
  1.2490 -		already = find_transaction_package(trans, &pool[new_package->name]);
  1.2491 -		if (already) {
  1.2492 -			if (already->new_package == new_package) {
  1.2493 -				/* Already taken care of */
  1.2494 -				return;
  1.2495 -			} else if (new_package_set == trans->upstream &&
  1.2496 -				   already->state == RAZOR_PACKAGE_FORCED_UPDATE) {
  1.2497 -				already->new_package = new_package;
  1.2498 -				return;
  1.2499 -			} else if (new_package_set == trans->upstream) {
  1.2500 -				return;
  1.2501 -			}
  1.2502 -
  1.2503 -			/* Oops. We lose */
  1.2504 -			if (state != RAZOR_PACKAGE_CONTRADICTION)
  1.2505 -				contradiction = 1;
  1.2506 -		}
  1.2507 -	} else if (old_package) {
  1.2508 -		pool = old_package_set->string_pool.data;
  1.2509 -		already = find_transaction_package(trans, &pool[old_package->name]);
  1.2510 -		if (already) {
  1.2511 -			if (already->old_package == old_package) {
  1.2512 -				/* Already taken care of */
  1.2513 -				return;
  1.2514 -			} else if (old_package_set == trans->system) {
  1.2515 -				already->old_package = old_package;
  1.2516 -				return;
  1.2517 -			}
  1.2518 -
  1.2519 -			/* Oops. We lose */
  1.2520 -			if (state != RAZOR_PACKAGE_CONTRADICTION)
  1.2521 -				contradiction = 1;
  1.2522 -		}
  1.2523 -	} else
  1.2524 -		state = RAZOR_PACKAGE_UNSATISFIABLE;
  1.2525 -
  1.2526 -	tp = array_add(&trans->packages, sizeof *tp);
  1.2527 -	memset(tp, 0, sizeof *tp);
  1.2528 -
  1.2529 -	if (new_package) {
  1.2530 -		pool = new_package_set->string_pool.data;
  1.2531 -		tp->new_package = new_package;
  1.2532 -		tp->name = &pool[new_package->name];
  1.2533 -		tp->new_version = &pool[new_package->version];
  1.2534 -
  1.2535 -		pkgs = new_package_set->packages.data;
  1.2536 -	}
  1.2537 -	if (old_package) {
  1.2538 -		pool = old_package_set->string_pool.data;
  1.2539 -		tp->old_package = old_package;
  1.2540 -		tp->name = &pool[old_package->name];
  1.2541 -		tp->old_version = &pool[old_package->version];
  1.2542 -
  1.2543 -		pkgs = old_package_set->packages.data;
  1.2544 -	}
  1.2545 -
  1.2546 -	tp->state = state;
  1.2547 -	if (state != RAZOR_PACKAGE_INSTALL &&
  1.2548 -	    state != RAZOR_PACKAGE_FORCED_UPDATE &&
  1.2549 -	    state != RAZOR_PACKAGE_REMOVE &&
  1.2550 -	    state != RAZOR_PACKAGE_OBSOLETED)
  1.2551 -		trans->errors++;
  1.2552 -
  1.2553 -	if (contradiction) {
  1.2554 -		/* Do this now, after adding tp, so that it ends up
  1.2555 -		 * after both the INSTALL and the REMOVE in the array.
  1.2556 -		 */
  1.2557 -		add_transaction_package(trans, new_package, old_package,
  1.2558 -					RAZOR_PACKAGE_CONTRADICTION,
  1.2559 -					NULL, NULL);
  1.2560 -	}
  1.2561 -
  1.2562 -	if (req_package)
  1.2563 -		tp->dep_package = req_package;
  1.2564 -	if (!req_prop)
  1.2565 -		return;
  1.2566 -
  1.2567 -	pool = req_set->string_pool.data;
  1.2568 -	pkgs = req_set->packages.data;
  1.2569 -	if (!req_package) {
  1.2570 -		for (pkg = list_first(&req_prop->packages, &req_set->package_pool); pkg; pkg = list_next(pkg)) {
  1.2571 -			if (bitarray_get(reqpkgbits, pkg->data))
  1.2572 -				break;
  1.2573 -		}
  1.2574 -		if (pkg)
  1.2575 -			tp->dep_package = &pool[pkgs[pkg->data].name];
  1.2576 -	}
  1.2577 -
  1.2578 -	tp->dep_type = req_prop->type;
  1.2579 -	tp->dep_property = &pool[req_prop->name];
  1.2580 -	tp->dep_relation = req_prop->relation;
  1.2581 -	tp->dep_version = &pool[req_prop->version];
  1.2582 -}
  1.2583 -
  1.2584 -static void
  1.2585 -razor_transaction_satisfy(struct razor_transaction *trans)
  1.2586 -{
  1.2587 -	struct razor_package *spkgs, *upkgs, *pkg;
  1.2588 -	struct razor_property *sp, *sprops, *sprop_end;
  1.2589 -	struct razor_property *up, *uprops, *uprop_end;
  1.2590 -	struct razor_property *sr, *ur, *first_up;
  1.2591 -	const char *spool, *upool, *removed_package;
  1.2592 -	struct list *reqpkg;
  1.2593 -
  1.2594 -	spkgs = trans->system->packages.data;
  1.2595 -	sprops = trans->system->properties.data;
  1.2596 -	sprop_end = trans->system->properties.data + trans->system->properties.size;
  1.2597 -	spool = trans->system->string_pool.data;
  1.2598 -	upkgs = trans->upstream->packages.data;
  1.2599 -	uprops = trans->upstream->properties.data;
  1.2600 -	uprop_end = trans->upstream->properties.data + trans->upstream->properties.size;
  1.2601 -	upool = trans->upstream->string_pool.data;
  1.2602 -
  1.2603 -	sp = sprops;
  1.2604 -	for (up = uprops; up < uprop_end; up++) {
  1.2605 -		/* Skip 'up' ahead to a property of a package which is
  1.2606 -		 * to-be-installed.
  1.2607 -		 */
  1.2608 -		while (up < uprop_end &&
  1.2609 -		       !prop_is_being_installed(trans, up))
  1.2610 -			up++;
  1.2611 -		if (up == uprop_end)
  1.2612 -			break;
  1.2613 -		sp = skip_to_matching_property(trans, up, sp);
  1.2614 -
  1.2615 -		switch (up->type) {
  1.2616 -		case RAZOR_PROPERTY_REQUIRES:
  1.2617 -			if (!strncmp(&upool[up->name], "rpmlib(", 7))
  1.2618 -				break;
  1.2619 -
  1.2620 -			if (find_installed_package_for_property(trans, sp, up, up) ||
  1.2621 -			    find_installed_package_for_file(trans, &upool[up->name])) {
  1.2622 -				/* Requires something that is either installed
  1.2623 -				 * or to-be-installed.
  1.2624 -				 */
  1.2625 -				break;
  1.2626 -			}
  1.2627 -
  1.2628 -			/* See if we can install a new upstream provider */
  1.2629 -			pkg = find_uninstalled_package_for_property(trans, sp, up, up);
  1.2630 -			if (!pkg)
  1.2631 -				pkg = find_uninstalled_package_for_file(trans, &upool[up->name]);
  1.2632 -			add_transaction_package(trans, pkg, NULL,
  1.2633 -						RAZOR_PACKAGE_INSTALL,
  1.2634 -						NULL, up);
  1.2635 -			break;
  1.2636 -
  1.2637 -		case RAZOR_PROPERTY_PROVIDES:
  1.2638 -			/* find_installed_package_for_property works backwards
  1.2639 -			 * here, finding a *conflicting* installed package.
  1.2640 -			 */
  1.2641 -			pkg = find_installed_package_for_property(trans, sp, up, up);
  1.2642 -			if (!pkg)
  1.2643 -				break;
  1.2644 -
  1.2645 -			if (package_in_set(pkg, trans->system)) {
  1.2646 -				/* pkg CONFLICTS with what 'up' PROVIDES. Try
  1.2647 -				 * finding an upgrade
  1.2648 -				 */
  1.2649 -				add_transaction_package(trans, NULL, pkg,
  1.2650 -							RAZOR_PACKAGE_FORCED_UPDATE,
  1.2651 -							&upool[up->name], sp);
  1.2652 -			} else {
  1.2653 -				add_transaction_package(trans, NULL, pkg,
  1.2654 -							RAZOR_PACKAGE_CONTRADICTION,
  1.2655 -							NULL, up);
  1.2656 -			}
  1.2657 -			break;
  1.2658 -
  1.2659 -		case RAZOR_PROPERTY_CONFLICTS:
  1.2660 -			pkg = find_installed_package_for_property(trans, sp, up, up);
  1.2661 -			if (!pkg)
  1.2662 -				break;
  1.2663 -
  1.2664 -			if (package_in_set(pkg, trans->system)) {
  1.2665 -				/* Conflicts with something already installed.
  1.2666 -				 * Try to upgrade out.
  1.2667 -				 */
  1.2668 -				add_transaction_package(trans, NULL, pkg,
  1.2669 -							RAZOR_PACKAGE_FORCED_UPDATE,
  1.2670 -							NULL, up);
  1.2671 -			} else {
  1.2672 -				add_transaction_package(trans, pkg, NULL,
  1.2673 -							RAZOR_PACKAGE_CONTRADICTION,
  1.2674 -							NULL, up);
  1.2675 -			}
  1.2676 -			break;
  1.2677 -
  1.2678 -		case RAZOR_PROPERTY_OBSOLETES:
  1.2679 -			pkg = find_installed_package_for_property(trans, sp, up, up);
  1.2680 -			if (pkg) {
  1.2681 -				/* If pkg is to-be-installed, this
  1.2682 -				 * will add a CONTRADICTION error as well.
  1.2683 -				 */
  1.2684 -				add_transaction_package(trans, NULL, pkg,
  1.2685 -							RAZOR_PACKAGE_OBSOLETED,
  1.2686 -							NULL, up);
  1.2687 -			}
  1.2688 -			break;
  1.2689 -
  1.2690 -		default:
  1.2691 -			/* can't happen */
  1.2692 -			break;
  1.2693 -		}
  1.2694 -	}
  1.2695 -
  1.2696 -	up = uprops;
  1.2697 -	for (sp = sprops; sp < sprop_end; sp++) {
  1.2698 -		/* Skip 'sp' ahead to a PROVIDES of a package which is
  1.2699 -		 * to-be-removed.
  1.2700 -		 */
  1.2701 -		while (sp < sprop_end &&
  1.2702 -		       (sp->type != RAZOR_PROPERTY_PROVIDES ||
  1.2703 -			!prop_is_being_removed(trans, sp)))
  1.2704 -			sp++;
  1.2705 -		if (sp == sprop_end)
  1.2706 -			break;
  1.2707 -
  1.2708 -		removed_package = &spool[spkgs[list_first(&sp->packages, &trans->system->package_pool)->data].name];
  1.2709 -
  1.2710 -		/* Skip 'up' to match */
  1.2711 -		up = skip_to_matching_property(trans, sp, up);
  1.2712 -		ur = first_up = up;
  1.2713 -
  1.2714 -		/* If the package is just being upgraded, we may
  1.2715 -		 * already be installing an identical PROVIDES, so
  1.2716 -		 * check for that.
  1.2717 -		 */
  1.2718 -		while (up < uprop_end &&
  1.2719 -		       strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
  1.2720 -		       (up->type != RAZOR_PROPERTY_PROVIDES || 
  1.2721 -			sp->relation != up->relation ||
  1.2722 -			strcmp(&spool[sp->name], &upool[up->name]) != 0))
  1.2723 -			up++;
  1.2724 -		if (up < uprop_end &&
  1.2725 -		    up->type == RAZOR_PROPERTY_PROVIDES &&
  1.2726 -		    strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
  1.2727 -		    sp->relation == up->relation &&
  1.2728 -		    strcmp(&spool[sp->version], &upool[up->version]) == 0 &&
  1.2729 -		    prop_is_being_installed(trans, up)) {
  1.2730 -			up = first_up;
  1.2731 -			continue;
  1.2732 -		}
  1.2733 -		up = first_up;
  1.2734 -
  1.2735 -		/* For all still-installed packages that require
  1.2736 -		 * sp->name, see if they are satisfied by any other
  1.2737 -		 * still-installed or to-be-installed property. If
  1.2738 -		 * not, either remove or attempt to update the
  1.2739 -		 * package, depending on why the required property has
  1.2740 -		 * disappeared
  1.2741 -		 */
  1.2742 -		sr = sp;
  1.2743 -		while (sr > sprops + 1 && (sr - 1)->name == sr->name)
  1.2744 -			sr--;
  1.2745 -		for (; sr->type == RAZOR_PROPERTY_REQUIRES; sr++) {
  1.2746 -			if (prop_is_being_removed(trans, sr))
  1.2747 -				continue;
  1.2748 -			if (find_installed_package_for_property(trans, sp, up, sr))
  1.2749 -				continue;
  1.2750 -
  1.2751 -			for (reqpkg = list_first(&sr->packages, &trans->system->package_pool); reqpkg; reqpkg = list_next(reqpkg)) {
  1.2752 -				if (!bitarray_get(&trans->syspkgs, reqpkg->data))
  1.2753 -					continue;
  1.2754 -				pkg = &spkgs[reqpkg->data];
  1.2755 -				if (prop_is_being_updated(trans, sp)) {
  1.2756 -					add_transaction_package(trans, NULL, pkg,
  1.2757 -								RAZOR_PACKAGE_FORCED_UPDATE,
  1.2758 -								removed_package, NULL);
  1.2759 -				} else {
  1.2760 -					add_transaction_package(trans, NULL, pkg,
  1.2761 -								RAZOR_PACKAGE_REMOVE,
  1.2762 -								removed_package, sr);
  1.2763 -				}
  1.2764 -			}
  1.2765 -		}
  1.2766 -	}
  1.2767 -}
  1.2768 -
  1.2769 -void
  1.2770 -razor_transaction_install_package(struct razor_transaction *transaction,
  1.2771 -				  struct razor_package *package)
  1.2772 -{
  1.2773 -	add_transaction_package(transaction, package, NULL,
  1.2774 -				RAZOR_PACKAGE_INSTALL, NULL, NULL);
  1.2775 -}
  1.2776 -
  1.2777 -void
  1.2778 -razor_transaction_remove_package(struct razor_transaction *transaction,
  1.2779 -				 struct razor_package *package)
  1.2780 -{
  1.2781 -	add_transaction_package(transaction, NULL, package,
  1.2782 -				RAZOR_PACKAGE_REMOVE, NULL, NULL);
  1.2783 -}
  1.2784 -
  1.2785 -void
  1.2786 -razor_transaction_update_all(struct razor_transaction *trans)
  1.2787 -{
  1.2788 -	struct razor_package *sp, *spkgs, *send, *up, *upkgs, *uend;
  1.2789 -	const char *spool, *upool;
  1.2790 -
  1.2791 -	spkgs = trans->system->packages.data;
  1.2792 -	send = trans->system->packages.data + trans->system->packages.size;
  1.2793 -	spool = trans->system->string_pool.data;
  1.2794 -	up = upkgs = trans->upstream->packages.data;
  1.2795 -	uend = trans->upstream->packages.data + trans->upstream->packages.size;
  1.2796 -	upool = trans->upstream->string_pool.data;
  1.2797 -
  1.2798 -	for (sp = spkgs; sp < send; sp++) {
  1.2799 -		while (up < uend && strcmp(&spool[sp->name], &upool[up->name]) > 0)
  1.2800 -			up++;
  1.2801 -		if (strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
  1.2802 -		    versioncmp(&spool[sp->version], &upool[up->version]) < 0) {
  1.2803 -			add_transaction_package(trans, up, sp,
  1.2804 -						RAZOR_PACKAGE_INSTALL,
  1.2805 -						NULL, NULL);
  1.2806 -		}
  1.2807 -	}
  1.2808 -}
  1.2809 -
  1.2810 -struct razor_transaction *
  1.2811 -razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
  1.2812 -{
  1.2813 -	struct razor_transaction *trans;
  1.2814 -	int count;
  1.2815 -
  1.2816 -	trans = zalloc(sizeof *trans);
  1.2817 -
  1.2818 -	trans->system = system;
  1.2819 -	trans->upstream = upstream ? upstream : razor_set_create();
  1.2820 -	array_init(&trans->packages);
  1.2821 -	count = trans->system->packages.size / sizeof (struct razor_package);
  1.2822 -	bitarray_init(&trans->syspkgs, count, 1);
  1.2823 -	count = trans->upstream->packages.size / sizeof (struct razor_package);
  1.2824 -	bitarray_init(&trans->uppkgs, count, 0);
  1.2825 -
  1.2826 -	return trans;
  1.2827 -}
  1.2828 -
  1.2829 -static void
  1.2830 -resolve_transaction(struct razor_transaction *trans)
  1.2831 -{
  1.2832 -	int start, end;
  1.2833 -
  1.2834 -	if (trans->package_count > 0)
  1.2835 -		/* Already did this, return. */
  1.2836 -		return;
  1.2837 -
  1.2838 -	start = 0;
  1.2839 -	end = trans->packages.size / sizeof (struct razor_transaction_package);
  1.2840 -
  1.2841 -	while (start != end) {
  1.2842 -		resolve_new_packages(trans, start, end);
  1.2843 -		if (trans->errors)
  1.2844 -			break;
  1.2845 -
  1.2846 -		razor_transaction_satisfy(trans);
  1.2847 -
  1.2848 -		start = end;
  1.2849 -		end = trans->packages.size / sizeof (struct razor_transaction_package);
  1.2850 -	}
  1.2851 -
  1.2852 -	trans->package_count = end;
  1.2853 -}
  1.2854 -
  1.2855 -const char * const razor_version_relations[] = {
  1.2856 -	/* same order as enum razor_version_relation */
  1.2857 -	"<", "<=", "=", ">=", ">"
  1.2858 -};
  1.2859 -
  1.2860 -const char * const razor_property_types[] = {
  1.2861 -	/* same order as enum razor_property_type */
  1.2862 -	"requires", "provides", "conflicts with", "obsoletes"
  1.2863 -};
  1.2864 -
  1.2865 -static void
  1.2866 -print_requirement(struct razor_transaction_package *p)
  1.2867 -{
  1.2868 -	if (p->dep_type == RAZOR_PROPERTY_CONFLICTS &&
  1.2869 -	    !strcmp(p->dep_package, p->name)) {
  1.2870 -		printf(" because %s %s conflicts with %s",
  1.2871 -		       p->name, p->old_version, p->dep_property);
  1.2872 -		if (*p->dep_version) {
  1.2873 -			printf(" %s %s",
  1.2874 -			       razor_version_relations[p->dep_relation],
  1.2875 -			       p->dep_version);
  1.2876 -		}
  1.2877 -	} else {
  1.2878 -		if (strcmp(p->name, p->dep_package) != 0)
  1.2879 -			printf(" for %s", p->dep_package);
  1.2880 -		if (*p->dep_version) {
  1.2881 -			printf(", which %s %s %s %s",
  1.2882 -			       razor_property_types[p->dep_type],
  1.2883 -			       p->dep_property,
  1.2884 -			       razor_version_relations[p->dep_relation],
  1.2885 -			       p->dep_version);
  1.2886 -		} else if (strcmp(p->dep_property, p->name) != 0) {
  1.2887 -			printf(", which %s %s",
  1.2888 -			       razor_property_types[p->dep_type],
  1.2889 -			       p->dep_property);
  1.2890 -		}
  1.2891 -	}
  1.2892 -}
  1.2893 -
  1.2894 -int
  1.2895 -razor_transaction_resolve(struct razor_transaction *trans)
  1.2896 -{
  1.2897 -	struct razor_transaction_package *p, *pend, *tps;
  1.2898 -	int errors_only = 0;
  1.2899 -
  1.2900 -	resolve_transaction(trans);
  1.2901 -
  1.2902 -	tps = trans->packages.data;
  1.2903 -	pend = trans->packages.data + trans->packages.size;
  1.2904 -	for (p = trans->packages.data; p < pend; p++) {
  1.2905 -		switch (p->state) {
  1.2906 -		case RAZOR_PACKAGE_INSTALL:
  1.2907 -			if (errors_only)
  1.2908 -				break;
  1.2909 -
  1.2910 -			printf("Installing %s %s", p->name, p->new_version);
  1.2911 -			if (p->dep_package)
  1.2912 -				print_requirement(p);
  1.2913 -			printf("\n");
  1.2914 -			break;
  1.2915 -
  1.2916 -		case RAZOR_PACKAGE_FORCED_UPDATE:
  1.2917 -			if (errors_only)
  1.2918 -				break;
  1.2919 -
  1.2920 -			printf("Updating %s to %s due to update of %s\n",
  1.2921 -			       p->name, p->new_version, p->dep_package);
  1.2922 -			break;
  1.2923 -
  1.2924 -		case RAZOR_PACKAGE_REMOVE:
  1.2925 -			if (errors_only)
  1.2926 -				break;
  1.2927 -			printf("Removing %s %s", p->name, p->old_version);
  1.2928 -			if (p->dep_package) {
  1.2929 -				printf(" which required %s",
  1.2930 -				       p->dep_package);
  1.2931 -				if (strcmp(p->dep_property, p->dep_package) != 0)
  1.2932 -					printf(" for %s", p->dep_property);
  1.2933 -			}
  1.2934 -			printf("\n");
  1.2935 -			break;
  1.2936 -
  1.2937 -		case RAZOR_PACKAGE_OBSOLETED:
  1.2938 -			if (errors_only)
  1.2939 -				break;
  1.2940 -			printf("Removing %s %s", p->name, p->old_version);
  1.2941 -			if (p->dep_package) {
  1.2942 -				printf(" which is obsoleted by %s",
  1.2943 -				       p->dep_package);
  1.2944 -			}
  1.2945 -			printf("\n");
  1.2946 -			break;
  1.2947 -
  1.2948 -		case RAZOR_PACKAGE_INSTALL_UNAVAILABLE:
  1.2949 -			printf("Error: can't find %s", p->name);
  1.2950 -			if (p->dep_package) {
  1.2951 -				printf(" (which is required");
  1.2952 -				print_requirement(p);
  1.2953 -				printf(")");
  1.2954 -			}
  1.2955 -			printf("\n");
  1.2956 -			errors_only = 1;
  1.2957 -			break;
  1.2958 -
  1.2959 -		case RAZOR_PACKAGE_UPDATE_UNAVAILABLE:
  1.2960 -			printf("Error: can't find an updated version of %s (which must be updated due to update of %s)\n",
  1.2961 -			       p->name, p->dep_package);
  1.2962 -			errors_only = 1;
  1.2963 -			break;
  1.2964 -
  1.2965 -		case RAZOR_PACKAGE_REMOVE_NOT_INSTALLED:
  1.2966 -			printf("Error: can't remove %s: not installed\n", p->name);
  1.2967 -			errors_only = 1;
  1.2968 -			break;
  1.2969 -
  1.2970 -		case RAZOR_PACKAGE_UP_TO_DATE:
  1.2971 -			printf("Error: can't update %s", p->name);
  1.2972 -			if (p->dep_package)
  1.2973 -				printf(" (which must be updated due to update of %s)", p->dep_package);
  1.2974 -			printf(": %s is most recent version\n", p->old_version);
  1.2975 -			errors_only = 1;
  1.2976 -			break;
  1.2977 -
  1.2978 -		case RAZOR_PACKAGE_CONTRADICTION:
  1.2979 -			printf("Error: package %s is marked for both installation and removal\n", p->name);
  1.2980 -			errors_only = 1;
  1.2981 -			break;
  1.2982 -
  1.2983 -		case RAZOR_PACKAGE_OLD_CONFLICT:
  1.2984 -			printf("Error: can't install %s, because installed package %s conflicts with ",
  1.2985 -			       p->name, p->dep_package);
  1.2986 -			if (*p->dep_version) {
  1.2987 -				printf("%s %s %s",
  1.2988 -				       p->dep_property,
  1.2989 -				       razor_version_relations[p->dep_relation],
  1.2990 -				       p->dep_version);
  1.2991 -			} else
  1.2992 -				printf("it");
  1.2993 -			printf("\n");
  1.2994 -
  1.2995 -			errors_only = 1;
  1.2996 -			break;
  1.2997 -
  1.2998 -		case RAZOR_PACKAGE_NEW_CONFLICT:
  1.2999 -			printf("Error: can't install %s, because it conflicts with %s",
  1.3000 -			       p->name, p->dep_package);
  1.3001 -			if (*p->dep_version) {
  1.3002 -				printf(" %s %s",
  1.3003 -				       razor_version_relations[p->dep_relation],
  1.3004 -				       p->dep_version);
  1.3005 -			}
  1.3006 -			printf("\n");
  1.3007 -
  1.3008 -			errors_only = 1;
  1.3009 -			break;
  1.3010 -
  1.3011 -		case RAZOR_PACKAGE_UNSATISFIABLE:
  1.3012 -			printf("Error: can't find package for %s", p->dep_property);
  1.3013 -			if (*p->dep_version) {
  1.3014 -				printf(" %s %s",
  1.3015 -					razor_version_relations[p->dep_relation],
  1.3016 -					p->dep_version);
  1.3017 -			}
  1.3018 -			printf(" which is required by %s\n",
  1.3019 -				p->dep_package);
  1.3020 -			errors_only = 1;
  1.3021 -			break;
  1.3022 -
  1.3023 -		default:
  1.3024 -			/* Shouldn't actually happen */
  1.3025 -			break;
  1.3026 -		}
  1.3027 -	}
  1.3028 -
  1.3029 -	return trans->errors;
  1.3030 -}
  1.3031 -
  1.3032 -int
  1.3033 -razor_transaction_unsatisfied_property(struct razor_transaction *trans,
  1.3034 -				       const char *name,
  1.3035 -				       enum razor_version_relation rel,
  1.3036 -				       const char *version)
  1.3037 -{
  1.3038 -	struct razor_transaction_package *p, *end;
  1.3039 -
  1.3040 -	end = trans->packages.data + trans->packages.size;
  1.3041 -	for (p = trans->packages.data; p < end; p++) {
  1.3042 -		if (p->state != RAZOR_PACKAGE_UNSATISFIABLE)
  1.3043 -			continue;
  1.3044 -		if (strcmp(name, p->dep_property) != 0 ||
  1.3045 -		    rel != p->dep_relation ||
  1.3046 -		    strcmp(version, p->dep_version) != 0)
  1.3047 -			continue;
  1.3048 -
  1.3049 -		return 1;
  1.3050 -	}
  1.3051 -
  1.3052 -	return 0;
  1.3053 -}
  1.3054 -
  1.3055 -struct razor_set *
  1.3056 -razor_transaction_finish(struct razor_transaction *trans)
  1.3057 -{
  1.3058 -	struct array install_packages, remove_packages;
  1.3059 -	struct razor_merger *merger;
  1.3060 -	struct razor_package *pkg, *i, *iend, *r, *rend, *s, *send;
  1.3061 -	struct razor_set *set;
  1.3062 -	struct source *source1, *source2;
  1.3063 -	char *spool, *ipool, *rpool;
  1.3064 -	uint32_t *map;
  1.3065 -	struct razor_transaction_package *p, *end;
  1.3066 -	int cmp;
  1.3067 -
  1.3068 -	/* FIXME */
  1.3069 -	if (trans->errors)
  1.3070 -		return NULL;
  1.3071 -
  1.3072 -	/* Sort the transaction packages into two arrays */
  1.3073 -	array_init(&install_packages);
  1.3074 -	array_init(&remove_packages);
  1.3075 -
  1.3076 -	end = trans->packages.data + trans->packages.size;
  1.3077 -	for (p = trans->packages.data; p < end; p++) {
  1.3078 -		if (p->new_package) {
  1.3079 -			pkg = array_add(&install_packages, sizeof *pkg);
  1.3080 -			*pkg = *p->new_package;
  1.3081 -		} else {
  1.3082 -			pkg = array_add(&remove_packages, sizeof *pkg);
  1.3083 -			*pkg = *p->old_package;
  1.3084 -		}
  1.3085 -	}
  1.3086 -	map = razor_qsort_with_data(install_packages.data,
  1.3087 -				    install_packages.size / sizeof *pkg,
  1.3088 -				    sizeof *pkg,
  1.3089 -				    compare_packages,
  1.3090 -				    trans->upstream);
  1.3091 -	free(map);
  1.3092 -	map = razor_qsort_with_data(remove_packages.data,
  1.3093 -				    remove_packages.size / sizeof *pkg,
  1.3094 -				    sizeof *pkg,
  1.3095 -				    compare_packages,
  1.3096 -				    trans->system);
  1.3097 -	free(map);
  1.3098 -
  1.3099 -	merger = razor_merger_create(trans->system, trans->upstream);
  1.3100 -
  1.3101 -	source1 = &merger->source1;
  1.3102 -	source2 = &merger->source2;
  1.3103 -
  1.3104 -	i = install_packages.data;
  1.3105 -	iend = install_packages.data + install_packages.size;
  1.3106 -	ipool = trans->upstream->string_pool.data;
  1.3107 -
  1.3108 -	r = remove_packages.data;
  1.3109 -	rend = remove_packages.data + remove_packages.size;
  1.3110 -	rpool = trans->system->string_pool.data;
  1.3111 -
  1.3112 -	s = trans->system->packages.data;
  1.3113 -	send = trans->system->packages.data + trans->system->packages.size;
  1.3114 -	spool = trans->system->string_pool.data;
  1.3115 -
  1.3116 -	while (s < send || i < iend) {
  1.3117 -		/* Check if s is being removed */
  1.3118 -		if (s < send && r < rend &&
  1.3119 -		    s->name == r->name && s->version && r->version) {
  1.3120 -			s++;
  1.3121 -			r++;
  1.3122 -			continue;
  1.3123 -		}
  1.3124 -
  1.3125 -		if (s < send && i < iend)
  1.3126 -			cmp = strcmp(&spool[s->name], &ipool[i->name]);
  1.3127 -		else if (s < send)
  1.3128 -			cmp = -1;
  1.3129 -		else
  1.3130 -			cmp = 1;
  1.3131 -		if (cmp < 0) {
  1.3132 -			add_package(merger, s, source1, 0);
  1.3133 -			s++;
  1.3134 -		} else if (cmp == 0) {
  1.3135 -			add_package(merger, i, source2, UPSTREAM_SOURCE);
  1.3136 -			s++;
  1.3137 -			i++;
  1.3138 -		} else {
  1.3139 -			add_package(merger, i, source2, UPSTREAM_SOURCE);
  1.3140 -			i++;
  1.3141 -		}
  1.3142 -	}
  1.3143 -
  1.3144 -	array_release(&install_packages);
  1.3145 -	array_release(&remove_packages);
  1.3146 -
  1.3147 -	set = razor_merger_finish(merger);
  1.3148 -	razor_transaction_destroy(trans);
  1.3149 -
  1.3150 -	return set;
  1.3151 -}
  1.3152 -
  1.3153 -void
  1.3154 -razor_transaction_destroy(struct razor_transaction *trans)
  1.3155 -{
  1.3156 -	struct razor_transaction_package *p, *end;
  1.3157 -
  1.3158 -	end = trans->packages.data + trans->packages.size;
  1.3159 -	for (p = trans->packages.data; p < end; p++) {
  1.3160 -		if (!p->dep_package &&
  1.3161 -		    (p->state == RAZOR_PACKAGE_INSTALL_UNAVAILABLE ||
  1.3162 -		     p->state == RAZOR_PACKAGE_REMOVE_NOT_INSTALLED))
  1.3163 -			free((char *)p->name);
  1.3164 -	}
  1.3165 -
  1.3166 -	array_release(&trans->packages);
  1.3167 -	bitarray_release(&trans->syspkgs);
  1.3168 -	bitarray_release(&trans->uppkgs);
  1.3169 -	free(trans);
  1.3170 -
  1.3171 -	/* FIXME: free upstream if it was created as an empty set */
  1.3172 -}
  1.3173 -
  1.3174 -struct razor_package_query {
  1.3175 -	struct razor_set *set;
  1.3176 -	char *vector;
  1.3177 -	int count;
  1.3178 -};
  1.3179 -
  1.3180 -struct razor_package_query *
  1.3181 -razor_package_query_create(struct razor_set *set)
  1.3182 -{
  1.3183 -	struct razor_package_query *pq;
  1.3184 -	int count;
  1.3185 -
  1.3186 -	pq = zalloc(sizeof *pq);
  1.3187 -	pq->set = set;
  1.3188 -	count = set->packages.size / sizeof(struct razor_package);
  1.3189 -	pq->vector = zalloc(count * sizeof(char));
  1.3190 -
  1.3191 -	return pq;
  1.3192 -}
  1.3193 -
  1.3194 -void
  1.3195 -razor_package_query_add_package(struct razor_package_query *pq,
  1.3196 -				struct razor_package *p)
  1.3197 -{
  1.3198 -	struct razor_package *packages;
  1.3199 -
  1.3200 -	packages = pq->set->packages.data;
  1.3201 -	pq->count += pq->vector[p - packages] ^ 1;
  1.3202 -	pq->vector[p - packages] = 1;
  1.3203 -}
  1.3204 -
  1.3205 -void
  1.3206 -razor_package_query_add_iterator(struct razor_package_query *pq,
  1.3207 -				 struct razor_package_iterator *pi)
  1.3208 -{
  1.3209 -	struct razor_package *packages, *p;
  1.3210 -	const char *name, *version, *arch;
  1.3211 -
  1.3212 -	packages = pq->set->packages.data;
  1.3213 -	while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
  1.3214 -		pq->count += pq->vector[p - packages] ^ 1;
  1.3215 -		pq->vector[p - packages] = 1;
  1.3216 -	}
  1.3217 -}
  1.3218 -
  1.3219 -struct razor_package_iterator *
  1.3220 -razor_package_query_finish(struct razor_package_query *pq)
  1.3221 -{
  1.3222 -	struct razor_package_iterator *pi;
  1.3223 -	struct razor_set *set;
  1.3224 -	struct list *index;
  1.3225 -	int i, j, count;
  1.3226 -
  1.3227 -	set = pq->set;
  1.3228 -	count = set->packages.size / sizeof(struct razor_package);
  1.3229 -	index = zalloc(pq->count * sizeof *index);
  1.3230 -
  1.3231 -	for (i = 0, j = 0; i < count; i++) {
  1.3232 -		if (!pq->vector[i])
  1.3233 -			continue;
  1.3234 -
  1.3235 -		index[j].data = i;
  1.3236 -		if (j == pq->count - 1)
  1.3237 -			index[j].flags = 0x80;
  1.3238 -		j++;
  1.3239 -	}
  1.3240 -
  1.3241 -	free(pq);
  1.3242 -
  1.3243 -	pi = razor_package_iterator_create_with_index(set, index);
  1.3244 -	pi->free_index = 1;
  1.3245 -
  1.3246 -	return pi;
  1.3247 -}