razor.c
author Kristian H?gsberg <krh@jiraiya.boston.redhat.com>
Wed Apr 09 02:41:03 2008 -0400 (2008-04-09)
changeset 211 cf0ca962262b
parent 209 78afac5bb7b8
child 212 e8f493d8ff9a
permissions -rw-r--r--
Use the cpio headers instead of the rpm headers when unpacking.

The files in the cpio payload doesn't actually follow the file order
in the rpm headers, so we need to decode the cpio header and use the
information there.
     1 #define _GNU_SOURCE
     2 
     3 #include <stdlib.h>
     4 #include <stddef.h>
     5 #include <stdint.h>
     6 #include <stdio.h>
     7 #include <string.h>
     8 #include <sys/types.h>
     9 #include <sys/stat.h>
    10 #include <sys/mman.h>
    11 #include <unistd.h>
    12 #include <fcntl.h>
    13 #include <errno.h>
    14 #include <ctype.h>
    15 #include <fnmatch.h>
    16 
    17 #include "razor.h"
    18 #include "razor-internal.h"
    19 #include "types.h"
    20 
    21 struct razor_set_section {
    22 	uint32_t type;
    23 	uint32_t offset;
    24 	uint32_t size;
    25 };
    26 
    27 struct razor_set_header {
    28 	uint32_t magic;
    29 	uint32_t version;
    30 	struct razor_set_section sections[0];
    31 };
    32 
    33 #define RAZOR_MAGIC 0x7a7a7a7a
    34 #define RAZOR_VERSION 1
    35 
    36 #define RAZOR_STRING_POOL	0
    37 #define RAZOR_PACKAGES		1
    38 #define RAZOR_PROPERTIES	2
    39 #define RAZOR_FILES		3
    40 #define RAZOR_PACKAGE_POOL	4
    41 #define RAZOR_PROPERTY_POOL	5
    42 #define RAZOR_FILE_POOL		6
    43 
    44 struct razor_package {
    45 	uint name  : 24;
    46 	uint flags : 8;
    47 	uint32_t version;
    48 	uint32_t arch;
    49 	struct list_head properties;
    50 	struct list_head files;
    51 };
    52 
    53 struct razor_property {
    54 	uint name  : 24;
    55 	uint flags : 6;
    56 	enum razor_property_type type : 2;
    57 	enum razor_version_relation relation : 32;
    58 	uint32_t version;
    59 	struct list_head packages;
    60 };
    61 
    62 struct razor_entry {
    63 	uint name  : 24;
    64 	uint flags : 8;
    65 	uint32_t start;
    66 	struct list_head packages;
    67 };
    68 
    69 #define RAZOR_ENTRY_LAST	0x80
    70 
    71 struct razor_set {
    72 	struct array string_pool;
    73  	struct array packages;
    74  	struct array properties;
    75  	struct array files;
    76 	struct array package_pool;
    77  	struct array property_pool;
    78  	struct array file_pool;
    79 	struct razor_set_header *header;
    80 };
    81 
    82 struct import_entry {
    83 	uint32_t package;
    84 	char *name;
    85 };
    86 
    87 struct import_directory {
    88 	uint32_t name, count;
    89 	struct array files;
    90 	struct array packages;
    91 	struct import_directory *last;
    92 };
    93 
    94 struct razor_importer {
    95 	struct razor_set *set;
    96 	struct hashtable table;
    97 	struct razor_package *package;
    98 	struct array properties;
    99 	struct array files;
   100 	struct array file_requires;
   101 };
   102 
   103 static void *
   104 zalloc(size_t size)
   105 {
   106 	void *p;
   107 
   108 	p = malloc(size);
   109 	memset(p, 0, size);
   110 
   111 	return p;
   112 }
   113 
   114 struct razor_set_section razor_sections[] = {
   115 	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
   116 	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
   117 	{ RAZOR_PROPERTIES,	offsetof(struct razor_set, properties) },
   118 	{ RAZOR_FILES,		offsetof(struct razor_set, files) },
   119 	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
   120 	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
   121 	{ RAZOR_FILE_POOL,	offsetof(struct razor_set, file_pool) },
   122 };
   123 
   124 struct razor_set *
   125 razor_set_create(void)
   126 {
   127 	struct razor_set *set;
   128 	struct razor_entry *e;
   129 	char *empty;
   130 
   131 	set = zalloc(sizeof *set);
   132 
   133 	e = array_add(&set->files, sizeof *e);
   134 	empty = array_add(&set->string_pool, 1);
   135 	*empty = '\0';
   136 	e->name = 0;
   137 	e->flags = RAZOR_ENTRY_LAST;
   138 	e->start = 0;
   139 	list_set_empty(&e->packages);
   140 
   141 	return set;
   142 }
   143 
   144 struct razor_set *
   145 razor_set_open(const char *filename)
   146 {
   147 	struct razor_set *set;
   148 	struct razor_set_section *s;
   149 	struct stat stat;
   150 	struct array *array;
   151 	int fd;
   152 
   153 	set = zalloc(sizeof *set);
   154 	fd = open(filename, O_RDONLY);
   155 	if (fstat(fd, &stat) < 0)
   156 		return NULL;
   157 	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   158 	if (set->header == MAP_FAILED) {
   159 		free(set);
   160 		return NULL;
   161 	}
   162 
   163 	for (s = set->header->sections; ~s->type; s++) {
   164 		if (s->type >= ARRAY_SIZE(razor_sections))
   165 			continue;
   166 		if (s->type != razor_sections[s->type].type)
   167 			continue;
   168 		array = (void *) set + razor_sections[s->type].offset;
   169 		array->data = (void *) set->header + s->offset;
   170 		array->size = s->size;
   171 		array->alloc = s->size;
   172 	}
   173 	close(fd);
   174 
   175 	return set;
   176 }
   177 
   178 void
   179 razor_set_destroy(struct razor_set *set)
   180 {
   181 	unsigned int size;
   182 	struct array *a;
   183 	int i;
   184 
   185 	if (set->header) {
   186 		for (i = 0; set->header->sections[i].type; i++)
   187 			;
   188 		size = set->header->sections[i].type;
   189 		munmap(set->header, size);
   190 	} else {
   191 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   192 			a = (void *) set + razor_sections[i].offset;
   193 			free(a->data);
   194 		}
   195 	}
   196 
   197 	free(set);
   198 }
   199 
   200 int
   201 razor_set_write_to_fd(struct razor_set *set, int fd)
   202 {
   203 	char data[4096];
   204 	struct razor_set_header *header = (struct razor_set_header *) data;
   205 	struct array *a;
   206 	uint32_t offset;
   207 	int i;
   208 
   209 	memset(data, 0, sizeof data);
   210 	header->magic = RAZOR_MAGIC;
   211 	header->version = RAZOR_VERSION;
   212 	offset = sizeof data;
   213 
   214 	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   215 		if (razor_sections[i].type != i)
   216 			continue;
   217 		a = (void *) set + razor_sections[i].offset;
   218 		header->sections[i].type = i;
   219 		header->sections[i].offset = offset;
   220 		header->sections[i].size = a->size;
   221 		offset += ALIGN(a->size, 4096);
   222 	}
   223 
   224 	header->sections[i].type = ~0;
   225 	header->sections[i].offset = 0;
   226 	header->sections[i].size = 0;
   227 
   228 	razor_write(fd, data, sizeof data);
   229 	memset(data, 0, sizeof data);
   230 	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   231 		if (razor_sections[i].type != i)
   232 			continue;
   233 		a = (void *) set + razor_sections[i].offset;
   234 		razor_write(fd, a->data, a->size);
   235 		razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
   236 	}
   237 
   238 	return 0;
   239 }
   240 
   241 int
   242 razor_set_write(struct razor_set *set, const char *filename)
   243 {
   244 	int fd, status;
   245 
   246 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
   247 	if (fd < 0)
   248 		return -1;
   249 
   250 	status = razor_set_write_to_fd(set, fd);
   251 	if (status) {
   252 	    close(fd);
   253 	    return status;
   254 	}
   255 
   256 	return close(fd);
   257 }
   258 
   259 void
   260 razor_build_evr(char *evr_buf, int size, const char *epoch,
   261 		const char *version, const char *release)
   262 {
   263 	int len;
   264 
   265 	if (!version || !*version) {
   266 		*evr_buf = '\0';
   267 		return;
   268 	}
   269 
   270 	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
   271 		len = snprintf(evr_buf, size, "%s:", epoch);
   272 		evr_buf += len;
   273 		size -= len;
   274 	}
   275 	len = snprintf(evr_buf, size, "%s", version);
   276 	evr_buf += len;
   277 	size -= len;
   278 	if (release && *release)
   279 		snprintf(evr_buf, size, "-%s", release);
   280 }
   281 
   282 void
   283 razor_importer_begin_package(struct razor_importer *importer,
   284 			     const char *name,
   285 			     const char *version,
   286 			     const char *arch)
   287 {
   288 	struct razor_package *p;
   289 
   290 	p = array_add(&importer->set->packages, sizeof *p);
   291 	p->name = hashtable_tokenize(&importer->table, name);
   292 	p->flags = 0;
   293 	p->version = hashtable_tokenize(&importer->table, version);
   294 	p->arch = hashtable_tokenize(&importer->table, arch);
   295 
   296 	importer->package = p;
   297 	array_init(&importer->properties);
   298 }
   299 
   300 void
   301 razor_importer_finish_package(struct razor_importer *importer)
   302 {
   303 	list_set_array(&importer->package->properties,
   304 		       &importer->set->property_pool,
   305 		       &importer->properties,
   306 		       1);
   307 
   308 	array_release(&importer->properties);
   309 }
   310 
   311 void
   312 razor_importer_add_property(struct razor_importer *importer,
   313 			    const char *name,
   314 			    enum razor_version_relation relation,
   315 			    const char *version,
   316 			    enum razor_property_type type)
   317 {
   318 	struct razor_property *p;
   319 	uint32_t *r;
   320 
   321 	p = array_add(&importer->set->properties, sizeof *p);
   322 	p->name = hashtable_tokenize(&importer->table, name);
   323 	p->flags = 0;
   324 	p->type = type;
   325 	p->relation = relation;
   326 	p->version = hashtable_tokenize(&importer->table, version);
   327 	list_set_ptr(&p->packages, importer->package -
   328 		     (struct razor_package *) importer->set->packages.data);
   329 
   330 	r = array_add(&importer->properties, sizeof *r);
   331 	*r = p - (struct razor_property *) importer->set->properties.data;
   332 
   333 	if (type == RAZOR_PROPERTY_REQUIRES && *name == '/') {
   334 		r = array_add(&importer->file_requires, sizeof *r);
   335 		*r = p->name;
   336 	}
   337 }
   338 
   339 void
   340 razor_importer_add_file(struct razor_importer *importer, const char *name)
   341 {
   342 	struct import_entry *e;
   343 
   344 	e = array_add(&importer->files, sizeof *e);
   345 
   346 	e->package = importer->package -
   347 		(struct razor_package *) importer->set->packages.data;
   348 	e->name = strdup(name);
   349 }
   350 
   351 struct razor_importer *
   352 razor_importer_new(void)
   353 {
   354 	struct razor_importer *importer;
   355 
   356 	importer = zalloc(sizeof *importer);
   357 	importer->set = razor_set_create();
   358 	hashtable_init(&importer->table, &importer->set->string_pool);
   359 
   360 	return importer;
   361 }
   362 
   363 /* Destroy an importer without creating the set. */
   364 void
   365 razor_importer_destroy(struct razor_importer *importer)
   366 {
   367 	/* FIXME: write this */
   368 }
   369 
   370 static int
   371 versioncmp(const char *s1, const char *s2)
   372 {
   373 	const char *p1, *p2;
   374 	long n1, n2;
   375 	int res;
   376 
   377 	n1 = strtol(s1, (char **) &p1, 10);
   378 	n2 = strtol(s2, (char **) &p2, 10);
   379 
   380 	/* Epoch; if one but not the other has an epoch set, default
   381 	 * the epoch-less version to 0. */
   382 	res = (*p1 == ':') - (*p2 == ':');
   383 	if (res < 0) {
   384 		n1 = 0;
   385 		p1 = s1;
   386 		p2++;
   387 	} else if (res > 0) {
   388 		p1++;
   389 		n2 = 0;
   390 		p2 = s2;
   391 	}
   392 
   393 	if (n1 != n2)
   394 		return n1 - n2;
   395 	while (*p1 && *p2) {
   396 		if (*p1 != *p2)
   397 			return *p1 - *p2;
   398 		p1++;
   399 		p2++;
   400 		if (isdigit(*p1) && isdigit(*p2))
   401 			return versioncmp(p1, p2);
   402 	}
   403 
   404 	return *p1 - *p2;
   405 }
   406 
   407 static int
   408 compare_packages(const void *p1, const void *p2, void *data)
   409 {
   410 	const struct razor_package *pkg1 = p1, *pkg2 = p2;
   411 	struct razor_set *set = data;
   412 	char *pool = set->string_pool.data;
   413 
   414 	/* FIXME: what if the flags are different? */
   415 	if (pkg1->name == pkg2->name)
   416 		return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
   417 	else
   418 		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
   419 }
   420 
   421 static int
   422 compare_properties(const void *p1, const void *p2, void *data)
   423 {
   424 	const struct razor_property *prop1 = p1, *prop2 = p2;
   425 	struct razor_set *set = data;
   426 	char *pool = set->string_pool.data;
   427 
   428 	if (prop1->name != prop2->name) 
   429 		return strcmp(&pool[prop1->name], &pool[prop2->name]);
   430 	else if (prop1->type != prop2->type)
   431 		return prop1->type - prop2->type;
   432 	else if (prop1->relation != prop2->relation)
   433 		return prop1->relation - prop2->relation;
   434 	else
   435 		return versioncmp(&pool[prop1->version], &pool[prop2->version]);
   436 }
   437 
   438 static uint32_t *
   439 uniqueify_properties(struct razor_set *set)
   440 {
   441 	struct razor_property *rp, *up, *rp_end;
   442 	struct array *pkgs, *p;
   443 	struct list_head *r;
   444 	uint32_t *map, *rmap;
   445 	int i, count, unique;
   446 
   447 	count = set->properties.size / sizeof(struct razor_property);
   448 	map = razor_qsort_with_data(set->properties.data,
   449 				    count,
   450 				    sizeof(struct razor_property),
   451 				    compare_properties,
   452 				    set);
   453 
   454 	rp_end = set->properties.data + set->properties.size;
   455 	rmap = malloc(count * sizeof *map);
   456 	pkgs = zalloc(count * sizeof *pkgs);
   457 	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
   458 		if (rp->name != up->name || rp->type != up->type ||
   459 		    rp->relation != up->relation || rp->version != up->version) {
   460 			up++;
   461 			up->name = rp->name;
   462 			up->flags = 0;
   463 			up->type = rp->type;
   464 			up->relation = rp->relation;
   465 			up->version = rp->version;
   466 		}
   467 
   468 		unique = up - (struct razor_property *) set->properties.data;
   469 		rmap[map[i]] = unique;
   470 		r = array_add(&pkgs[unique], sizeof *r);
   471 		*r = rp->packages;
   472 	}
   473 	free(map);
   474 
   475 	if (up != rp)
   476 		up++;
   477 	set->properties.size = (void *) up - set->properties.data;
   478 	rp_end = up;
   479 	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
   480 		list_set_array(&rp->packages, &set->package_pool, p, 0);
   481 		array_release(p);
   482 	}
   483 
   484 	free(pkgs);
   485 
   486 	return rmap;
   487 }
   488 
   489 static int
   490 compare_filenames(const void *p1, const void *p2, void *data)
   491 {
   492 	const struct import_entry *e1 = p1;
   493 	const struct import_entry *e2 = p2;
   494 	const char *n1 = e1->name;
   495 	const char *n2 = e2->name;
   496 
   497 	/* Need to make sure that the contents of a directory
   498 	 * are sorted immediately after it. So "foo/bar" has to
   499 	 * sort before "foo.conf"
   500 	 *
   501 	 * FIXME: this is about 60% slower than strcmp
   502 	 */
   503 	while (*n1 && *n2) {
   504 		if (*n1 < *n2)
   505 			return *n2 == '/' ? 1 : -1;
   506 		else if (*n1 > *n2)
   507 			return *n1 == '/' ? -1 : 1;
   508 		n1++;
   509 		n2++;
   510 	}
   511 	if (*n1)
   512 		return 1;
   513 	else if (*n2)
   514 		return -1;
   515 	else
   516 		return 0;
   517 }
   518 
   519 static void
   520 count_entries(struct import_directory *d)
   521 {
   522 	struct import_directory *p, *end;
   523 
   524 	p = d->files.data;
   525 	end = d->files.data + d->files.size;
   526 	d->count = 0;
   527 	while (p < end) {
   528 		count_entries(p);
   529 		d->count += p->count + 1;
   530 		p++;
   531 	}		
   532 }
   533 
   534 static void
   535 serialize_files(struct razor_set *set,
   536 		struct import_directory *d, struct array *array)
   537 {
   538 	struct import_directory *p, *end;
   539 	struct razor_entry *e = NULL;
   540 	uint32_t s;
   541 
   542 	p = d->files.data;
   543 	end = d->files.data + d->files.size;
   544 	s = array->size / sizeof *e + d->files.size / sizeof *p;
   545 	while (p < end) {
   546 		e = array_add(array, sizeof *e);
   547 		e->name = p->name;
   548 		e->flags = 0;
   549 		e->start = p->count > 0 ? s : 0;
   550 		s += p->count;
   551 
   552 		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
   553 		array_release(&p->packages);
   554 		p++;
   555 	}		
   556 	if (e != NULL)
   557 		e->flags |= RAZOR_ENTRY_LAST;
   558 
   559 	p = d->files.data;
   560 	end = d->files.data + d->files.size;
   561 	while (p < end) {
   562 		serialize_files(set, p, array);
   563 		p++;
   564 	}
   565 }
   566 
   567 static void
   568 remap_property_package_links(struct array *properties, uint32_t *rmap)
   569 {
   570 	struct razor_property *p, *end;
   571 
   572 	end = properties->data + properties->size;
   573 	for (p = properties->data; p < end; p++)
   574 		list_remap_head(&p->packages, rmap);
   575 }
   576 
   577 static void
   578 build_file_tree(struct razor_importer *importer)
   579 {
   580 	int count, i, length;
   581 	struct import_entry *filenames;
   582 	char *f, *end;
   583 	uint32_t name, *r;
   584 	char dirname[256];
   585 	struct import_directory *d, root;
   586 	struct razor_entry *e;
   587 
   588 	count = importer->files.size / sizeof (struct import_entry);
   589 	razor_qsort_with_data(importer->files.data,
   590 			      count,
   591 			      sizeof (struct import_entry),
   592 			      compare_filenames,
   593 			      NULL);
   594 
   595 	root.name = hashtable_tokenize(&importer->table, "");
   596 	array_init(&root.files);
   597 	array_init(&root.packages);
   598 	root.last = NULL;
   599 
   600 	filenames = importer->files.data;
   601 	for (i = 0; i < count; i++) {
   602 		f = filenames[i].name;
   603 		if (*f != '/')
   604 			continue;
   605 		f++;
   606 
   607 		d = &root;
   608 		while (*f) {
   609 			end = strchr(f, '/');
   610 			if (end == NULL)
   611 				end = f + strlen(f);
   612 			length = end - f;
   613 			memcpy(dirname, f, length);
   614 			dirname[length] ='\0';
   615 			name = hashtable_tokenize(&importer->table, dirname);
   616 			if (d->last == NULL || d->last->name != name) {
   617 				d->last = array_add(&d->files, sizeof *d);
   618 				d->last->name = name;
   619 				d->last->last = NULL;
   620 				array_init(&d->last->files);
   621 				array_init(&d->last->packages);
   622 			}
   623 			d = d->last;				
   624 			f = end + 1;
   625 			if (*end == '\0')
   626 				break;
   627 		}
   628 
   629 		r = array_add(&d->packages, sizeof *r);
   630 		*r = filenames[i].package;
   631 		free(filenames[i].name);
   632 	}
   633 
   634 	count_entries(&root);
   635 	e = importer->set->files.data;
   636 	e->name = root.name;
   637 	e->flags = RAZOR_ENTRY_LAST;
   638 	e->start = importer->files.size ? 1 : 0;
   639 	list_set_empty(&e->packages);
   640 
   641 	serialize_files(importer->set, &root, &importer->set->files);
   642 
   643 	array_release(&importer->files);
   644 }
   645 
   646 static struct razor_entry *
   647 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern);
   648 
   649 static void
   650 list_to_array(struct list *list, struct array *array)
   651 {
   652 	uint32_t *item;
   653 
   654 	while (list) {
   655 		 item = array_add(array, sizeof *item);
   656 		 *item = list->data;
   657 		 list = list_next(list);
   658 	}
   659 }
   660 
   661 static int
   662 compare_file_requires(const void *p1, const void *p2, void *data)
   663 {
   664 	uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
   665 	const char *pool = data;
   666 
   667 	return strcmp(&pool[*f1], &pool[*f2]);
   668 }
   669 
   670 static void
   671 find_file_provides(struct razor_importer *importer)
   672 {
   673 	struct razor_property *prop;
   674 	struct razor_entry *top, *entry;
   675 	struct razor_package *packages;
   676 	struct array pkgprops;
   677 	struct list *pkg;
   678 	uint32_t *req, *req_start, *req_end;
   679 	uint32_t *map, *newprop;
   680 	char *pool;
   681 
   682 	pool = importer->set->string_pool.data;
   683 	packages = importer->set->packages.data;
   684 	top = importer->set->files.data;
   685 
   686 	req = req_start = importer->file_requires.data;
   687 	req_end = importer->file_requires.data + importer->file_requires.size;
   688 	map = razor_qsort_with_data(req, req_end - req, sizeof *req,
   689 				    compare_file_requires, pool);
   690 	free(map);
   691 
   692 	for (req = req_start; req < req_end; req++) {
   693 		if (req > req_start && req[0] == req[-1])
   694 			continue;
   695 		entry = find_entry(importer->set, top, &pool[*req]);
   696 		if (!entry)
   697 			continue;
   698 
   699 		for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
   700 			prop = array_add(&importer->set->properties, sizeof *prop);
   701 			prop->name = *req;
   702 			prop->type = RAZOR_PROPERTY_PROVIDES;
   703 			prop->relation = RAZOR_VERSION_EQUAL;
   704 			prop->version = hashtable_tokenize(&importer->table, "");
   705 			list_set_ptr(&prop->packages, pkg->data);
   706 
   707 			/* Update property list of pkg */
   708 			array_init(&pkgprops);
   709 			list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
   710 			newprop = array_add(&pkgprops, sizeof *newprop);
   711 			*newprop = prop - (struct razor_property *)importer->set->properties.data;
   712 			list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
   713 			array_release(&pkgprops);
   714 		}
   715 	}
   716 
   717 	array_release(&importer->file_requires);
   718 }
   719 
   720 static void
   721 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
   722 {
   723 	struct razor_package *p, *packages;
   724 	struct array *pkgs;
   725 	struct razor_entry *e, *end;
   726 	struct list *r;
   727 	uint32_t *q;
   728 	int i, count;
   729 
   730 	count = set->packages.size / sizeof *p;
   731 	pkgs = zalloc(count * sizeof *pkgs);
   732 
   733 	end = set->files.data + set->files.size;
   734 	for (e = set->files.data; e < end; e++) {
   735 		list_remap_head(&e->packages, rmap);
   736 		r = list_first(&e->packages, &set->package_pool);
   737 		while (r) {
   738 			q = array_add(&pkgs[r->data], sizeof *q);
   739 			*q = e - (struct razor_entry *) set->files.data;
   740 			r = list_next(r);
   741 		}
   742 	}
   743 
   744 	packages = set->packages.data;
   745 	for (i = 0; i < count; i++) {
   746 		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
   747 		array_release(&pkgs[i]);
   748 	}
   749 	free(pkgs);
   750 }
   751 
   752 struct razor_set *
   753 razor_importer_finish(struct razor_importer *importer)
   754 {
   755 	struct razor_set *set;
   756 	uint32_t *map, *rmap;
   757 	int i, count;
   758 
   759 	build_file_tree(importer);
   760 	find_file_provides(importer);
   761 
   762 	map = uniqueify_properties(importer->set);
   763 	list_remap_pool(&importer->set->property_pool, map);
   764 	free(map);
   765 
   766 	count = importer->set->packages.size / sizeof(struct razor_package);
   767 	map = razor_qsort_with_data(importer->set->packages.data,
   768 				    count,
   769 				    sizeof(struct razor_package),
   770 				    compare_packages,
   771 				    importer->set);
   772 
   773 	rmap = malloc(count * sizeof *rmap);
   774 	for (i = 0; i < count; i++)
   775 		rmap[map[i]] = i;
   776 	free(map);
   777 
   778 	list_remap_pool(&importer->set->package_pool, rmap);
   779 	build_package_file_lists(importer->set, rmap);
   780 	remap_property_package_links(&importer->set->properties, rmap);
   781 	free(rmap);
   782 
   783 	set = importer->set;
   784 	hashtable_release(&importer->table);
   785 	free(importer);
   786 
   787 	return set;
   788 }
   789 
   790 struct razor_package_iterator {
   791 	struct razor_set *set;
   792 	struct razor_package *package, *end;
   793 	struct list *index;
   794 };
   795 
   796 static struct razor_package_iterator *
   797 razor_package_iterator_create_with_index(struct razor_set *set,
   798 					 struct list *index)
   799 {
   800 	struct razor_package_iterator *pi;
   801 
   802 	pi = zalloc(sizeof *pi);
   803 	pi->set = set;
   804 	pi->index = index;
   805 
   806 	return pi;
   807 }
   808 
   809 struct razor_package_iterator *
   810 razor_package_iterator_create(struct razor_set *set)
   811 {
   812 	struct razor_package_iterator *pi;
   813 
   814 	pi = zalloc(sizeof *pi);
   815 	pi->set = set;
   816 	pi->end = set->packages.data + set->packages.size;
   817 	pi->package = set->packages.data;
   818 
   819 	return pi;
   820 }
   821 
   822 struct razor_package_iterator *
   823 razor_package_iterator_create_for_property(struct razor_set *set,
   824 					   struct razor_property *property)
   825 {
   826 	struct list *index;
   827 
   828 	index = list_first(&property->packages, &set->package_pool);
   829 	return razor_package_iterator_create_with_index(set, index);
   830 }
   831 
   832 int
   833 razor_package_iterator_next(struct razor_package_iterator *pi,
   834 			    struct razor_package **package,
   835 			    const char **name,
   836 			    const char **version,
   837 			    const char **arch)
   838 {
   839 	char *pool;
   840 	int valid;
   841 	struct razor_package *p, *packages;
   842 
   843 	if (pi->package) {
   844 		p = pi->package++;
   845 		valid = p < pi->end;
   846 	} else if (pi->index) {
   847 		packages = pi->set->packages.data;
   848 		p = &packages[pi->index->data];
   849 		pi->index = list_next(pi->index);
   850 		valid = 1;
   851 	} else
   852 		valid = 0;
   853 
   854 	if (valid) {
   855 		pool = pi->set->string_pool.data;
   856 		*package = p;
   857 		*name = &pool[p->name];
   858 		*version = &pool[p->version];
   859 		*arch = &pool[p->arch];
   860 	} else {
   861 		*package = NULL;
   862 	}
   863 
   864 	return valid;
   865 }
   866 
   867 void
   868 razor_package_iterator_destroy(struct razor_package_iterator *pi)
   869 {
   870 	free(pi);
   871 }
   872 
   873 struct razor_package *
   874 razor_set_get_package(struct razor_set *set, const char *package)
   875 {
   876 	struct razor_package_iterator *pi;
   877 	struct razor_package *p;
   878 	const char *name, *version, *arch;
   879 
   880 	pi = razor_package_iterator_create(set);
   881 	while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
   882 		if (strcmp(package, name) == 0)
   883 			break;
   884 	}
   885 	razor_package_iterator_destroy(pi);
   886 
   887 	return p;
   888 }
   889 
   890 struct razor_property_iterator {
   891 	struct razor_set *set;
   892 	struct razor_property *property, *end;
   893 	struct list *index;
   894 };
   895 
   896 struct razor_property_iterator *
   897 razor_property_iterator_create(struct razor_set *set,
   898 			       struct razor_package *package)
   899 {
   900 	struct razor_property_iterator *pi;
   901 
   902 	pi = zalloc(sizeof *pi);
   903 	pi->set = set;
   904 
   905 	if (package) {
   906 		pi->index = list_first(&package->properties,
   907 				       &set->property_pool);
   908 	} else {
   909 		pi->property = set->properties.data;
   910 		pi->end = set->properties.data + set->properties.size;
   911 	}
   912 
   913 	return pi;
   914 }
   915 
   916 int
   917 razor_property_iterator_next(struct razor_property_iterator *pi,
   918 			     struct razor_property **property,
   919 			     const char **name,
   920 			     enum razor_version_relation *relation,
   921 			     const char **version,
   922 			     enum razor_property_type *type)
   923 {
   924 	char *pool;
   925 	int valid;
   926 	struct razor_property *p, *properties;
   927 
   928 	if (pi->property) {
   929 		p = pi->property++;
   930 		valid = p < pi->end;
   931 	} else if (pi->index) {
   932 		properties = pi->set->properties.data;
   933 		p = &properties[pi->index->data];
   934 		pi->index = list_next(pi->index);
   935 		valid = 1;
   936 	} else
   937 		valid = 0;
   938 
   939 	if (valid) {
   940 		pool = pi->set->string_pool.data;
   941 		*property = p;
   942 		*name = &pool[p->name];
   943 		*relation = p->relation;
   944 		*version = &pool[p->version];
   945 		*type = p->type;
   946 	} else {
   947 		*property = NULL;
   948 	}
   949 
   950 	return valid;
   951 }
   952 
   953 void
   954 razor_property_iterator_destroy(struct razor_property_iterator *pi)
   955 {
   956 	free(pi);
   957 }
   958 
   959 static struct razor_entry *
   960 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
   961 {
   962 	struct razor_entry *e;
   963 	const char *n, *pool = set->string_pool.data;
   964 	int len;
   965 
   966 	e = (struct razor_entry *) set->files.data + dir->start;
   967 	do {
   968 		n = pool + e->name;
   969 		if (strcmp(pattern + 1, n) == 0)
   970 			return e;
   971 		len = strlen(n);
   972 		if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
   973 		    pattern[len + 1] == '/') {
   974 			return find_entry(set, e, pattern + len + 1);
   975 		}
   976 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   977 
   978 	return NULL;
   979 }
   980 
   981 static void
   982 list_dir(struct razor_set *set, struct razor_entry *dir,
   983 	 char *prefix, const char *pattern)
   984 {
   985 	struct razor_entry *e;
   986 	const char *n, *pool = set->string_pool.data;
   987 
   988 	e = (struct razor_entry *) set->files.data + dir->start;
   989 	do {
   990 		n = pool + e->name;
   991 		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
   992 			continue;
   993 		printf("%s/%s\n", prefix, n);
   994 		if (e->start) {
   995 			char *sub = prefix + strlen (prefix);
   996 			*sub = '/';
   997 			strcpy (sub + 1, n);
   998 			list_dir(set, e, prefix, pattern);
   999 			*sub = '\0';
  1000 		}
  1001 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
  1002 }
  1003 
  1004 void
  1005 razor_set_list_files(struct razor_set *set, const char *pattern)
  1006 {
  1007 	struct razor_entry *e;
  1008 	char buffer[512], *p, *base;
  1009 
  1010 	if (pattern == NULL || !strcmp (pattern, "/")) {
  1011 		buffer[0] = '\0';
  1012 		list_dir(set, set->files.data, buffer, NULL);
  1013 		return;
  1014 	}
  1015 
  1016 	strcpy(buffer, pattern);
  1017 	e = find_entry(set, set->files.data, buffer);
  1018 	if (e && e->start > 0) {
  1019 		base = NULL;
  1020 	} else {
  1021 		p = strrchr(buffer, '/');
  1022 		if (p) {
  1023 			*p = '\0';
  1024 			base = p + 1;
  1025 		} else {
  1026 			base = NULL;
  1027 		}
  1028 	}
  1029 	e = find_entry(set, set->files.data, buffer);
  1030 	if (e->start != 0)
  1031 		list_dir(set, e, buffer, base);
  1032 }
  1033 
  1034 struct razor_package_iterator *
  1035 razor_package_iterator_create_for_file(struct razor_set *set,
  1036 				       const char *filename)
  1037 {
  1038 	struct razor_entry *entry;
  1039 	struct list *index;
  1040 
  1041 	entry = find_entry(set, set->files.data, filename);
  1042 	if (entry == NULL)
  1043 		return NULL;
  1044 	
  1045 	index = list_first(&entry->packages, &set->package_pool);
  1046 	return razor_package_iterator_create_with_index(set, index);
  1047 }
  1048 
  1049 static struct list *
  1050 list_package_files(struct razor_set *set, struct list *r,
  1051 		   struct razor_entry *dir, uint32_t end,
  1052 		   char *prefix)
  1053 {
  1054 	struct razor_entry *e, *f, *entries;
  1055 	uint32_t next, file;
  1056 	char *pool;
  1057 	int len;
  1058 	
  1059 	entries = (struct razor_entry *) set->files.data;
  1060 	pool = set->string_pool.data;
  1061 
  1062 	e = entries + dir->start;
  1063 	do {
  1064 		if (entries + r->data == e) {
  1065 			printf("%s/%s\n", prefix, pool + e->name);
  1066 			r = list_next(r);
  1067 			if (!r)
  1068 				return NULL;
  1069 			if (r->data >= end)
  1070 				return r;
  1071 		}
  1072 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
  1073 
  1074 	e = entries + dir->start;
  1075 	do {
  1076 		if (e->start == 0)
  1077 			continue;
  1078 
  1079 		if (e->flags & RAZOR_ENTRY_LAST)
  1080 			next = end;
  1081 		else {
  1082 			f = e + 1; 
  1083 			while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
  1084 				f++;
  1085 			if (f->start == 0)
  1086 				next = end;
  1087 			else
  1088 				next = f->start;
  1089 		}
  1090 
  1091 		file = r->data;
  1092 		if (e->start <= file && file < next) {
  1093 			len = strlen(prefix);
  1094 			prefix[len] = '/';
  1095 			strcpy(prefix + len + 1, pool + e->name);
  1096 			r = list_package_files(set, r, e, next, prefix);
  1097 			prefix[len] = '\0';
  1098 		}
  1099 	} while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
  1100 
  1101 	return r;
  1102 }
  1103 
  1104 void
  1105 razor_set_list_package_files(struct razor_set *set, const char *name)
  1106 {
  1107 	struct razor_package *package;
  1108 	struct list *r;
  1109 	uint32_t end;
  1110 	char buffer[512];
  1111 
  1112 	package = razor_set_get_package(set, name);
  1113 
  1114 	r = list_first(&package->files, &set->file_pool);
  1115 	end = set->files.size / sizeof (struct razor_entry);
  1116 	buffer[0] = '\0';
  1117 	list_package_files(set, r, set->files.data, end, buffer);
  1118 }
  1119 
  1120 static void
  1121 razor_set_validate(struct razor_set *set, struct array *unsatisfied)
  1122 {
  1123 	struct razor_property *r, *p, *end;
  1124 	uint32_t *u;
  1125 	char *pool;
  1126 
  1127 	end = set->properties.data + set->properties.size;
  1128 	pool = set->string_pool.data;
  1129 	
  1130 	for (r = set->properties.data, p = r; r < end; r++) {
  1131 		if (r->type != RAZOR_PROPERTY_REQUIRES)
  1132 			continue;
  1133 
  1134 		p = r;
  1135 		while (p < end && p->name == r->name &&
  1136 		       p->type == r->type)
  1137 			p++;
  1138 
  1139 		/* If there is more than one version of a provides,
  1140 		 * seek to the end for the highest version. */
  1141 		/* FIXME: This doesn't work if we have a series of
  1142 		 * requires a = 1, provides a = 1, requires a = 2,
  1143 		 * provides a = 2, as the kernel and kernel-devel
  1144 		 * does.*/
  1145 		while (p + 1 < end && p->name == (p + 1)->name &&
  1146 		       p->type == (p + 1)->type)
  1147 			p++;
  1148 
  1149 		/* FIXME: We need to track property flags (<, <=, =
  1150 		 * etc) to properly determine if a requires is
  1151 		 * satisfied.  The current code doesn't track that the
  1152 		 * requires a = 1 isn't satisfied by a = 2 provides. */
  1153 
  1154 		if (p == end ||
  1155 		    p->type != RAZOR_PROPERTY_PROVIDES ||
  1156 		    r->name != p->name ||
  1157 		    versioncmp(&pool[r->version], &pool[p->version]) > 0) {
  1158 			/* FIXME: We ignore file requires for now. */
  1159 			if (pool[r->name] == '/')
  1160 				continue;
  1161 			u = array_add(unsatisfied, sizeof *u);
  1162 			*u = r - (struct razor_property *) set->properties.data;
  1163 		}
  1164 	}
  1165 }
  1166 
  1167 void
  1168 razor_set_list_unsatisfied(struct razor_set *set)
  1169 {
  1170 	struct array unsatisfied;
  1171 	struct razor_property *properties, *r;
  1172 	uint32_t *u, *end;
  1173 	char *pool;
  1174 
  1175 	array_init(&unsatisfied);
  1176 	razor_set_validate(set, &unsatisfied);
  1177 
  1178 	end = unsatisfied.data + unsatisfied.size;
  1179 	properties = set->properties.data;
  1180 	pool = set->string_pool.data;
  1181 
  1182 	for (u = unsatisfied.data; u < end; u++) {
  1183 		r = properties + *u;
  1184 		if (pool[r->version] == '\0')
  1185 			printf("%ss not satisfied\n",
  1186 			       &pool[r->name]);
  1187 		else
  1188 			printf("%s-%s not satisfied\n",
  1189 			       &pool[r->name],
  1190 			       &pool[r->version]);
  1191 	}
  1192 
  1193 	array_release(&unsatisfied);
  1194 }
  1195 
  1196 #define UPSTREAM_SOURCE 0x80
  1197 
  1198 struct source {
  1199 	struct razor_set *set;
  1200 	uint32_t *property_map;
  1201 	uint32_t *file_map;
  1202 };
  1203 
  1204 struct razor_merger {
  1205 	struct razor_set *set;
  1206 	struct hashtable table;
  1207 	struct source source1;
  1208 	struct source source2;
  1209 };
  1210 
  1211 static struct razor_merger *
  1212 razor_merger_create(struct razor_set *set1, struct razor_set *set2)
  1213 {
  1214 	struct razor_merger *merger;
  1215 	int count;
  1216 	size_t size;
  1217 
  1218 	merger = zalloc(sizeof *merger);
  1219 	merger->set = razor_set_create();
  1220 	hashtable_init(&merger->table, &merger->set->string_pool);
  1221 
  1222 	merger->source1.set = set1;
  1223 	count = set1->properties.size / sizeof (struct razor_property);
  1224 	size = count * sizeof merger->source1.property_map[0];
  1225 	merger->source1.property_map = zalloc(size);
  1226 	count = set1->files.size / sizeof (struct razor_entry);
  1227 	size = count * sizeof merger->source1.file_map[0];
  1228 	merger->source1.file_map = zalloc(size);
  1229 
  1230 	merger->source2.set = set2;
  1231 	count = set2->properties.size / sizeof (struct razor_property);
  1232 	size = count * sizeof merger->source2.property_map[0];
  1233 	merger->source2.property_map = zalloc(size);
  1234 	count = set2->files.size / sizeof (struct razor_entry);
  1235 	size = count * sizeof merger->source2.file_map[0];
  1236 	merger->source2.file_map = zalloc(size);
  1237 
  1238 	return merger;
  1239 }
  1240 
  1241 static void
  1242 add_package(struct razor_merger *merger,
  1243 	    struct razor_package *package, struct source *source,
  1244 	    uint32_t flags)
  1245 {
  1246 	char *pool;
  1247 	struct list *r;
  1248 	struct razor_package *p;
  1249 
  1250 	pool = source->set->string_pool.data;
  1251 	p = array_add(&merger->set->packages, sizeof *p);
  1252 	p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
  1253 	p->flags = flags;
  1254 	p->version = hashtable_tokenize(&merger->table,
  1255 					&pool[package->version]);
  1256 	p->arch = hashtable_tokenize(&merger->table,
  1257 				     &pool[package->arch]);
  1258 
  1259 	p->properties = package->properties;
  1260 	r = list_first(&package->properties, &source->set->property_pool);
  1261 	while (r) {
  1262 		source->property_map[r->data] = 1;
  1263 		r = list_next(r);
  1264 	}
  1265 
  1266 	p->files = package->files;
  1267 	r = list_first(&package->files, &source->set->file_pool);
  1268 	while (r) {
  1269 		source->file_map[r->data] = 1;
  1270 		r = list_next(r);
  1271 	}
  1272 }
  1273 
  1274 static uint32_t
  1275 add_property(struct razor_merger *merger,
  1276 	     const char *name, enum razor_version_relation relation,
  1277 	     const char *version, int type)
  1278 {
  1279 	struct razor_property *p;
  1280 
  1281 	p = array_add(&merger->set->properties, sizeof *p);
  1282 	p->name = hashtable_tokenize(&merger->table, name);
  1283 	p->flags = 0;
  1284 	p->type = type;
  1285 	p->relation = relation;
  1286 	p->version = hashtable_tokenize(&merger->table, version);
  1287 
  1288 	return p - (struct razor_property *) merger->set->properties.data;
  1289 }
  1290 
  1291 static void
  1292 merge_properties(struct razor_merger *merger)
  1293 {
  1294 	struct razor_property *p1, *p2;
  1295 	struct razor_set *set1, *set2;
  1296 	uint32_t *map1, *map2;
  1297 	int i, j, cmp, count1, count2;
  1298 	char *pool1, *pool2;
  1299 
  1300 	set1 = merger->source1.set;
  1301 	set2 = merger->source2.set;
  1302 	map1 = merger->source1.property_map;
  1303 	map2 = merger->source2.property_map;
  1304 
  1305 	i = 0;
  1306 	j = 0;
  1307 	pool1 = set1->string_pool.data;
  1308 	pool2 = set2->string_pool.data;
  1309 
  1310 	count1 = set1->properties.size / sizeof *p1;
  1311 	count2 = set2->properties.size / sizeof *p2;
  1312 	while (i < count1 || j < count2) {
  1313 		if (i < count1 && map1[i] == 0) {
  1314 			i++;
  1315 			continue;
  1316 		}
  1317 		if (j < count2 && map2[j] == 0) {
  1318 			j++;
  1319 			continue;
  1320 		}
  1321 		p1 = (struct razor_property *) set1->properties.data + i;
  1322 		p2 = (struct razor_property *) set2->properties.data + j;
  1323 		if (i < count1 && j < count2)
  1324 			cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
  1325 		else if (i < count1)
  1326 			cmp = -1;
  1327 		else
  1328 			cmp = 1;
  1329 		if (cmp == 0)
  1330 			cmp = p1->type - p2->type;
  1331 		if (cmp == 0)
  1332 			cmp = p1->relation - p2->relation;
  1333 		if (cmp == 0)
  1334 			cmp = versioncmp(&pool1[p1->version],
  1335 					 &pool2[p2->version]);
  1336 		if (cmp < 0) {
  1337 			map1[i++] = add_property(merger,
  1338 						 &pool1[p1->name],
  1339 						 p1->relation,
  1340 						 &pool1[p1->version],
  1341 						 p1->type);
  1342 		} else if (cmp > 0) {
  1343 			map2[j++] = add_property(merger,
  1344 						 &pool2[p2->name],
  1345 						 p2->relation,
  1346 						 &pool2[p2->version],
  1347 						 p2->type);
  1348 		} else  {
  1349 			map1[i++] = map2[j++] = add_property(merger,
  1350 							     &pool1[p1->name],
  1351 							     p1->relation,
  1352 							     &pool1[p1->version],
  1353 							     p1->type);
  1354 		}
  1355 	}
  1356 }
  1357 
  1358 static void
  1359 emit_properties(struct list_head *properties, struct array *source_pool,
  1360 		uint32_t *map, struct array *pool)
  1361 {
  1362 	uint32_t r;
  1363 	struct list *p, *q;
  1364 
  1365 	r = pool->size / sizeof *q;
  1366 	p = list_first(properties, source_pool);
  1367 	while (p) {
  1368 		q = array_add(pool, sizeof *q);
  1369 		q->data = map[p->data];
  1370 		q->flags = p->flags;
  1371 		p = list_next(p);
  1372 	}
  1373 
  1374 	list_set_ptr(properties, r);
  1375 }
  1376 
  1377 static uint32_t
  1378 add_file(struct razor_merger *merger, const char *name)
  1379 {
  1380 	struct razor_entry *e;
  1381 
  1382 	e = array_add(&merger->set->files, sizeof *e);
  1383 	e->name = hashtable_tokenize(&merger->table, name);
  1384 	e->flags = 0;
  1385 	e->start = 0;
  1386 
  1387 	return e - (struct razor_entry *)merger->set->files.data;
  1388 }
  1389 
  1390 /* FIXME. Blah */
  1391 static int
  1392 fix_file_map(uint32_t *map,
  1393 	     struct razor_entry *files,
  1394 	     struct razor_entry *top)
  1395 {
  1396 	uint32_t e;
  1397 	int found_file = 0;
  1398 
  1399 	e = top->start;
  1400 	do {
  1401 		if (files[e].start)
  1402 			fix_file_map(map, files, &files[e]);
  1403 		if (map[e])
  1404 			found_file = 1;
  1405 	} while (!(files[e++].flags & RAZOR_ENTRY_LAST));
  1406 
  1407 	if (found_file)
  1408 		map[top - files] = 1;
  1409 	return found_file;
  1410 }
  1411 
  1412 struct merge_directory {
  1413 	uint32_t merged, dir1, dir2;
  1414 };
  1415 
  1416 static void
  1417 merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
  1418 {
  1419 	struct razor_entry *root1, *root2, *mroot, *e1, *e2;
  1420 	struct razor_set *set1, *set2;
  1421 	struct array merge_stack;
  1422 	struct merge_directory *child_md, *end_md;
  1423 	uint32_t *map1, *map2, start, last;
  1424 	int cmp;
  1425 	char *pool1, *pool2;
  1426 
  1427 	set1 = merger->source1.set;
  1428 	set2 = merger->source2.set;
  1429 	map1 = merger->source1.file_map;
  1430 	map2 = merger->source2.file_map;
  1431 	pool1 = set1->string_pool.data;
  1432 	pool2 = set2->string_pool.data;
  1433 	root1 = (struct razor_entry *) set1->files.data;
  1434 	root2 = (struct razor_entry *) set2->files.data;
  1435 
  1436 	array_init(&merge_stack);
  1437 
  1438 	start = merger->set->files.size / sizeof (struct razor_entry);
  1439 	last = 0;
  1440 	e1 = md->dir1 ? root1 + md->dir1 : NULL;
  1441 	e2 = md->dir2 ? root2 + md->dir2 : NULL;
  1442 	while (e1 || e2) {
  1443 		if (!e2 && !map1[e1 - root1]) {
  1444 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1445 				e1 = NULL;
  1446 			continue;
  1447 		}
  1448 		if (!e1 && !map2[e2 - root2]) {
  1449 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1450 				e2 = NULL;
  1451 			continue;
  1452 		}
  1453 		if (e1 && !map1[e1 - root1] &&
  1454 		    e2 && !map1[e2 - root2]) {
  1455 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1456 				e1 = NULL;
  1457 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1458 				e2 = NULL;
  1459 			continue;
  1460 		}
  1461 
  1462 		if (!e1)
  1463 			cmp = 1;
  1464 		else if (!e2)
  1465 			cmp = -1;
  1466 		else {
  1467 			cmp = strcmp (&pool1[e1->name],
  1468 				      &pool2[e2->name]);
  1469 		}
  1470 
  1471 		if (cmp < 0) {
  1472 			if (map1[e1 - root1]) {
  1473 				map1[e1 - root1] = last =
  1474 					add_file(merger, &pool1[e1->name]);
  1475 				if (e1->start) {
  1476 					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
  1477 					child_md->merged = last;
  1478 					child_md->dir1 = e1->start;
  1479 					child_md->dir2 = 0;
  1480 				}
  1481 			}
  1482 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1483 				e1 = NULL;
  1484 		} else if (cmp > 0) {
  1485 			if (map2[e2 - root2]) {
  1486 				map2[e2 - root2] = last =
  1487 					add_file(merger, &pool2[e2->name]);
  1488 				if (e2->start) {
  1489 					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
  1490 					child_md->merged = last;
  1491 					child_md->dir1 = 0;
  1492 					child_md->dir2 = e2->start;
  1493 				}
  1494 			}
  1495 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1496 				e2 = NULL;
  1497 		} else {
  1498 			map1[e1 - root1] = map2[e2- root2] = last =
  1499 				add_file(merger, &pool1[e1->name]);
  1500 			if (e1->start || e2->start) {
  1501 				child_md = array_add(&merge_stack, sizeof (struct merge_directory));
  1502 				child_md->merged = last;
  1503 				child_md->dir1 = e1->start;
  1504 				child_md->dir2 = e2->start;
  1505 			}
  1506 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1507 				e1 = NULL;
  1508 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1509 				e2 = NULL;
  1510 		}
  1511 	}
  1512 
  1513 	mroot = (struct razor_entry *)merger->set->files.data;
  1514 	if (last) {
  1515 		mroot[last].flags = RAZOR_ENTRY_LAST;
  1516 		mroot[md->merged].start = start;
  1517 	} else
  1518 		mroot[md->merged].start = 0;
  1519 
  1520 	end_md = merge_stack.data + merge_stack.size;
  1521 	for (child_md = merge_stack.data; child_md < end_md; child_md++)
  1522 		merge_one_directory(merger, child_md);
  1523 	array_release(&merge_stack);
  1524 }
  1525 
  1526 static void
  1527 merge_files(struct razor_merger *merger)
  1528 {
  1529 	struct razor_entry *root;
  1530 	struct merge_directory md;
  1531 	uint32_t *map1, *map2;
  1532 
  1533 	map1 = merger->source1.file_map;
  1534 	map2 = merger->source2.file_map;
  1535 
  1536 	md.merged = 0;
  1537 
  1538 	if (merger->source1.set->files.size) {
  1539 		root = (struct razor_entry *) merger->source1.set->files.data;
  1540 		if (root->start)
  1541 			fix_file_map(map1, root, root);
  1542 		md.dir1 = root->start;
  1543 	} else
  1544 		md.dir1 = 0;
  1545 
  1546 	if (merger->source2.set->files.size) {
  1547 		root = (struct razor_entry *) merger->source2.set->files.data;
  1548 		if (root->start)
  1549 			fix_file_map(map2, root, root);
  1550 		md.dir2 = root->start;
  1551 	} else
  1552 		md.dir2 = 0;
  1553 
  1554 	merge_one_directory(merger, &md);
  1555 }
  1556 
  1557 static void
  1558 emit_files(struct list_head *files, struct array *source_pool,
  1559 	   uint32_t *map, struct array *pool)
  1560 {
  1561 	uint32_t r;
  1562 	struct list *p, *q;
  1563 
  1564 	r = pool->size / sizeof *q;
  1565 	p = list_first(files, source_pool);
  1566 	while (p) {
  1567 		q = array_add(pool, sizeof *q);
  1568 		q->data = map[p->data];
  1569 		q->flags = p->flags;
  1570 		p = list_next(p);
  1571 	}
  1572 
  1573 	list_set_ptr(files, r);
  1574 }
  1575 
  1576 /* Rebuild property->packages maps.  We can't just remap these, as a
  1577  * property may have lost or gained a number of packages.  Allocate an
  1578  * array per property and loop through the packages and add them to
  1579  * the arrays for their properties. */
  1580 static void
  1581 rebuild_property_package_lists(struct razor_set *set)
  1582 {
  1583 	struct array *pkgs, *a;
  1584 	struct razor_package *pkg, *pkg_end;
  1585 	struct razor_property *prop, *prop_end;
  1586 	struct list *r;
  1587 	uint32_t *q;
  1588 	int count;
  1589 
  1590 	count = set->properties.size / sizeof (struct razor_property);
  1591 	pkgs = zalloc(count * sizeof *pkgs);
  1592 	pkg_end = set->packages.data + set->packages.size;
  1593 
  1594 	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
  1595 		r = list_first(&pkg->properties, &set->property_pool);
  1596 		while (r) {
  1597 			q = array_add(&pkgs[r->data], sizeof *q);
  1598 			*q = pkg - (struct razor_package *) set->packages.data;
  1599 			r = list_next(r);
  1600 		}
  1601 	}
  1602 
  1603 	prop_end = set->properties.data + set->properties.size;
  1604 	a = pkgs;
  1605 	for (prop = set->properties.data; prop < prop_end; prop++, a++) {
  1606 		list_set_array(&prop->packages, &set->package_pool, a, 0);
  1607 		array_release(a);
  1608 	}
  1609 	free(pkgs);
  1610 }
  1611 
  1612 static void
  1613 rebuild_file_package_lists(struct razor_set *set)
  1614 {
  1615 	struct array *pkgs, *a;
  1616 	struct razor_package *pkg, *pkg_end;
  1617 	struct razor_entry *entry, *entry_end;
  1618 	struct list *r;
  1619 	uint32_t *q;
  1620 	int count;
  1621 
  1622 	count = set->files.size / sizeof (struct razor_entry);
  1623 	pkgs = zalloc(count * sizeof *pkgs);
  1624 	pkg_end = set->packages.data + set->packages.size;
  1625 
  1626 	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
  1627 		r = list_first(&pkg->files, &set->file_pool);
  1628 		while (r) {
  1629 			q = array_add(&pkgs[r->data], sizeof *q);
  1630 			*q = pkg - (struct razor_package *) set->packages.data;
  1631 			r = list_next(r);
  1632 		}
  1633 	}
  1634 
  1635 	entry_end = set->files.data + set->files.size;
  1636 	a = pkgs;
  1637 	for (entry = set->files.data; entry < entry_end; entry++, a++) {
  1638 		list_set_array(&entry->packages, &set->package_pool, a, 0);
  1639 		array_release(a);
  1640 	}
  1641 	free(pkgs);
  1642 }
  1643 
  1644 static struct razor_set *
  1645 razor_merger_finish(struct razor_merger *merger)
  1646 {
  1647 	struct razor_set *result;
  1648 	struct razor_package *p, *pend;
  1649 
  1650 	/* As we built the package list, we filled out a bitvector of
  1651 	 * the properties that are referenced by the packages in the
  1652 	 * new set.  Now we do a parallel loop through the properties
  1653 	 * and emit those marked in the bit vector to the new set.  In
  1654 	 * the process, we update the bit vector to actually map from
  1655 	 * indices in the old property list to indices in the new
  1656 	 * property list for both sets. */
  1657 
  1658 	merge_properties(merger);
  1659 	merge_files(merger);
  1660 
  1661 	/* Now we loop through the packages again and emit the
  1662 	 * property lists, remapped to point to the new properties. */
  1663 
  1664 	pend = merger->set->packages.data + merger->set->packages.size;
  1665 	for (p = merger->set->packages.data; p < pend; p++) {
  1666 		struct source *src;
  1667 
  1668 		if (p->flags & UPSTREAM_SOURCE)
  1669 			src = &merger->source2;
  1670 		else
  1671 			src = &merger->source1;
  1672 
  1673 		emit_properties(&p->properties,
  1674 				&src->set->property_pool,
  1675 				src->property_map,
  1676 				&merger->set->property_pool);
  1677 		emit_files(&p->files,
  1678 			   &src->set->file_pool,
  1679 			   src->file_map,
  1680 			   &merger->set->file_pool);
  1681 		p->flags &= ~UPSTREAM_SOURCE;
  1682 	}
  1683 
  1684 	rebuild_property_package_lists(merger->set);
  1685 	rebuild_file_package_lists(merger->set);
  1686 
  1687 	result = merger->set;
  1688 	hashtable_release(&merger->table);
  1689 	free(merger);
  1690 
  1691 	return result;
  1692 }
  1693 
  1694 /* The diff order matters.  We should sort the packages so that a
  1695  * REMOVE of a package comes before the INSTALL, and so that all
  1696  * requires for a package have been installed before the package.
  1697  **/
  1698 
  1699 void
  1700 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
  1701 	       razor_package_callback_t callback, void *data)
  1702 {
  1703 	struct razor_package_iterator *pi1, *pi2;
  1704 	struct razor_package *p1, *p2;
  1705 	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
  1706 	int res;
  1707 
  1708 	pi1 = razor_package_iterator_create(set);
  1709 	pi2 = razor_package_iterator_create(upstream);
  1710 
  1711 	razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
  1712 	razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
  1713 
  1714 	while (p1 || p2) {
  1715 		if (p1 && p2) {
  1716 			res = strcmp(name1, name2);
  1717 			if (res == 0)
  1718 				res = versioncmp(version1, version2);
  1719 		} else {
  1720 			res = 0;
  1721 		}
  1722 
  1723 		if (p2 == NULL || res < 0)
  1724 			callback(name1, version1, NULL, arch1, data);
  1725 		else if (p1 == NULL || res > 0)
  1726 			callback(name2, NULL, version2, arch2, data);
  1727 
  1728 		if (p1 != NULL && res <= 0)
  1729 			razor_package_iterator_next(pi1, &p1,
  1730 						    &name1, &version1, &arch1);
  1731 		if (p2 != NULL && res >= 0)
  1732 			razor_package_iterator_next(pi2, &p2,
  1733 						    &name2, &version2, &arch2);
  1734 	}
  1735 
  1736 	razor_package_iterator_destroy(pi1);
  1737 	razor_package_iterator_destroy(pi2);
  1738 }
  1739 
  1740 struct razor_transaction;
  1741 struct razor_transaction_package;
  1742 struct razor_transaction_resolver;
  1743 
  1744 struct razor_transaction {
  1745 	int package_count, errors;
  1746 	struct razor_set *system, *upstream;
  1747 
  1748 	struct bitarray syspkgs, uppkgs;
  1749 	struct array packages;
  1750 };
  1751 
  1752 struct razor_transaction_package {
  1753 	const char *name, *old_version, *new_version;
  1754 	struct razor_package *old_package, *new_package;
  1755 	enum razor_transaction_package_state state;
  1756 
  1757 	/* dep_package is the name of the package that resulted in
  1758 	 * this entry being created (or NULL if the user requested the
  1759 	 * install/remove), with the other dep_ fields providing
  1760 	 * additional information.
  1761 	 *
  1762 	 * For INSTALL, if dep_type is REQUIRES, then dep_package
  1763 	 * required something that this package provides. If dep_type
  1764 	 * is CONFLICTS, then dep_package is a package that conflicted
  1765 	 * with an older version of this package, forcing an upgrade.
  1766 	 *
  1767 	 * For REMOVE, if dep_type is REQUIRES, then dep_package is a
  1768 	 * package that is being removed. If dep_type is OBSOLETES,
  1769 	 * then dep_package is a package that obsoletes this one.
  1770 	 *
  1771 	 * For OLD_CONFLICT or NEW_CONFLICT, dep_package is an
  1772 	 * existing package that conflicts with this one. The
  1773 	 * conflicting property comes from the already-installed
  1774 	 * package for OLD_CONFLICT, or the to-be-installed package
  1775 	 * for NEW_CONFLICT.
  1776 	 *
  1777 	 * For UNSATISFIABLE, the dep_ fields are as for an INSTALL,
  1778 	 * but the name field will be NULL.
  1779 	 */
  1780 	const char *dep_package;
  1781 	enum razor_property_type dep_type;
  1782 	const char *dep_property;
  1783 	enum razor_version_relation dep_relation;
  1784 	const char *dep_version;
  1785 };
  1786 
  1787 static int
  1788 package_in_set(void *package, struct razor_set *set)
  1789 {
  1790 	return package >= set->packages.data &&
  1791 		package < set->packages.data + set->packages.size;
  1792 }
  1793 
  1794 static int
  1795 property_in_set(void *property, struct razor_set *set)
  1796 {
  1797 	return property >= set->properties.data &&
  1798 		property < set->properties.data + set->properties.size;
  1799 }
  1800 
  1801 static struct razor_package *
  1802 property_provider_package(struct razor_transaction *trans,
  1803 			  struct razor_property *prop,
  1804 			  int installed)
  1805 {
  1806 	struct razor_set *set;
  1807 	struct bitarray *pkgbits;
  1808 	struct razor_package *pkgs;
  1809 	struct list *p;
  1810 
  1811 	if (installed && prop->type != RAZOR_PROPERTY_PROVIDES)
  1812 		return NULL;
  1813 	else if (!installed &&
  1814 		 prop->type != RAZOR_PROPERTY_PROVIDES &&
  1815 		 prop->type != RAZOR_PROPERTY_OBSOLETES)
  1816 		return NULL;
  1817 
  1818 	if (property_in_set(prop, trans->system)) {
  1819 		set = trans->system;
  1820 		pkgbits = &trans->syspkgs;
  1821 	} else {
  1822 		set = trans->upstream;
  1823 		pkgbits = &trans->uppkgs;
  1824 	}
  1825 	pkgs = set->packages.data;
  1826 
  1827 	for (p = list_first(&prop->packages, &set->package_pool); p; p = list_next(p)) {
  1828 		if (bitarray_get(pkgbits, p->data) != installed)
  1829 			continue;
  1830 		if (prop->type == RAZOR_PROPERTY_OBSOLETES ||
  1831 		    pkgs[p->data].name == prop->name)
  1832 			return &pkgs[p->data];
  1833 	}
  1834 	return NULL;
  1835 }
  1836 
  1837 static int
  1838 compare_transaction_packages(const void *one, const void *two)
  1839 {
  1840 	struct razor_transaction_package **tp1 = (void *)one;
  1841 	struct razor_transaction_package **tp2 = (void *)two;
  1842 
  1843 	if (!(*tp1)->name)
  1844 		return 1;
  1845 	else if (!(*tp2)->name)
  1846 		return -1;
  1847 	else
  1848 		return strcmp((*tp1)->name, (*tp2)->name);
  1849 }
  1850 
  1851 /* FIXME: merge this into the other property loop in razor_transaction_satisfy */
  1852 static void
  1853 resolve_new_packages(struct razor_transaction *trans,
  1854 		     int start, int end)
  1855 {
  1856 	struct razor_property *sp, *up, *sp_end, *up_end;
  1857 	struct razor_package *spkg, *spkgs, *upkg, *upkgs;
  1858 	struct razor_transaction_package **packages;
  1859 	const char *spool, *upool;
  1860 	int i;
  1861 
  1862 	sp_end = trans->system->properties.data + trans->system->properties.size;
  1863 	spool = trans->system->string_pool.data;
  1864 	spkgs = trans->system->packages.data;
  1865 	up_end = trans->upstream->properties.data + trans->upstream->properties.size;
  1866 	upool = trans->upstream->string_pool.data;
  1867 	upkgs = trans->upstream->packages.data;
  1868 
  1869 	/* FIXME, check if sorting the packages directly (rather than
  1870 	 * sorting pointers-to-packages) still results in confusing
  1871 	 * descriptions.
  1872 	 */
  1873 	packages = calloc(end - start, sizeof *packages);
  1874 	for (i = start; i < end; i++)
  1875 		packages[i - start] = ((struct razor_transaction_package *)trans->packages.data) + i;
  1876 	qsort(packages, end - start, sizeof *packages,
  1877 	      compare_transaction_packages);
  1878 
  1879 	sp = trans->system->properties.data;
  1880 	up = trans->upstream->properties.data;
  1881 	for (i = 0; i < end - start; i++) {
  1882 		if (!packages[i]->name ||
  1883 		    packages[i]->state >= RAZOR_PACKAGE_FIRST_ERROR_STATE)
  1884 			continue;
  1885 
  1886 		spkg = NULL;
  1887 		while (sp < sp_end &&
  1888 		       strcmp(&spool[sp->name], packages[i]->name) < 0)
  1889 			sp++;
  1890 		while (sp < sp_end &&
  1891 		       strcmp(&spool[sp->name], packages[i]->name) == 0 &&
  1892 		       !(spkg = property_provider_package(trans, sp, 1)))
  1893 			sp++;
  1894 
  1895 		upkg = NULL;
  1896 		while (up < up_end &&
  1897 		       strcmp(&upool[up->name], packages[i]->name) < 0)
  1898 			up++;
  1899 		while (up < up_end &&
  1900 		       strcmp(&upool[up->name], packages[i]->name) == 0 &&
  1901 		       !(upkg = property_provider_package(trans, up, 0)))
  1902 			up++;
  1903 
  1904 		if (packages[i]->state == RAZOR_PACKAGE_REMOVE ||
  1905 		    packages[i]->state == RAZOR_PACKAGE_OBSOLETED) {
  1906 			if (spkg) {
  1907 				packages[i]->old_package = spkg;
  1908 				packages[i]->name = &spool[spkg->name];
  1909 				packages[i]->old_version = &spool[spkg->version];
  1910 				bitarray_set(&trans->syspkgs, spkg - spkgs, 0);
  1911 			}
  1912 			if (!packages[i]->old_package) {
  1913 				packages[i]->name = strdup(packages[i]->name);
  1914 				packages[i]->state |= RAZOR_PACKAGE_UNAVAILABLE_FLAG;
  1915 				trans->errors++;
  1916 			}
  1917 		} else {
  1918 			if (upkg) {
  1919 				packages[i]->new_package = upkg;
  1920 				packages[i]->name = &upool[upkg->name];
  1921 				packages[i]->new_version = &upool[upkg->version];
  1922 
  1923 				if (up->name != upkg->name) {
  1924 					packages[i]->dep_package = &upool[upkg->name];
  1925 					packages[i]->dep_type = up->type;
  1926 					packages[i]->dep_property = &upool[up->name];
  1927 					packages[i]->dep_relation = up->relation;
  1928 					packages[i]->dep_version = &upool[up->version];
  1929 				}
  1930 
  1931 				if (spkg) {
  1932 					packages[i]->old_package = spkg;
  1933 					packages[i]->old_version = &spool[spkg->version];
  1934 					if (versioncmp(&spool[spkg->version], &upool[up->version]) >= 0) {
  1935 						packages[i]->state = RAZOR_PACKAGE_UP_TO_DATE;
  1936 						trans->errors++;
  1937 						continue;
  1938 					}
  1939 					bitarray_set(&trans->syspkgs, spkg - spkgs, 0);
  1940 				}
  1941 				bitarray_set(&trans->uppkgs, upkg - upkgs, 1);
  1942 			}
  1943 			if (!packages[i]->new_package) {
  1944 				packages[i]->name = strdup(packages[i]->name);
  1945 				packages[i]->state |= RAZOR_PACKAGE_UNAVAILABLE_FLAG;
  1946 				trans->errors++;
  1947 			}
  1948 		}
  1949 	}
  1950 }
  1951 
  1952 static int
  1953 provider_satisfies_requirement(struct razor_property *provider,
  1954 			       const char *provider_strings,
  1955 			       struct razor_property *requirement,
  1956 			       const char *requirement_strings)
  1957 {
  1958 	int cmp, len;
  1959 	const char *provided = &provider_strings[provider->version];
  1960 	const char *required = &requirement_strings[requirement->version];
  1961 
  1962 	if (!*required)
  1963 		return 1;
  1964 	if (!*provided) {
  1965 		if (requirement->relation >= RAZOR_VERSION_EQUAL)
  1966 			return 1;
  1967 		else
  1968 			return 0;
  1969 	}
  1970 
  1971 	cmp = versioncmp(provided, required);
  1972 
  1973 	switch (requirement->relation) {
  1974 	case RAZOR_VERSION_LESS:
  1975 		return cmp < 0;
  1976 
  1977 	case RAZOR_VERSION_LESS_OR_EQUAL:
  1978 		if (cmp <= 0)
  1979 			return 1;
  1980 		/* fall through: FIXME, make sure this is correct */
  1981 
  1982 	case RAZOR_VERSION_EQUAL:
  1983 		if (cmp == 0)
  1984 			return 1;
  1985 
  1986 		/* "foo == 1.1" is satisfied by "foo 1.1-2" */
  1987 		len = strlen(required);
  1988 		if (!strncmp(required, provided, len) && provided[len] == '-')
  1989 			return 1;
  1990 		return 0;
  1991 
  1992 	case RAZOR_VERSION_GREATER_OR_EQUAL:
  1993 		return cmp >= 0;
  1994 
  1995 	case RAZOR_VERSION_GREATER:
  1996 		return cmp > 0;
  1997 	}
  1998 
  1999 	/* shouldn't happen */
  2000 	return 0;
  2001 }
  2002 
  2003 static struct razor_package *
  2004 find_package_for_file(struct razor_set *set, struct bitarray *pkgbits,
  2005 		      const char *filename, int installed)
  2006 {
  2007 	struct razor_package *pkgs = set->packages.data;
  2008 	struct razor_entry *entry;
  2009 	struct list *p;
  2010 
  2011 	if (filename[0] != '/')
  2012 		return 0;
  2013 
  2014 	entry = find_entry(set, set->files.data, filename);
  2015 	if (!entry)
  2016 		return 0;
  2017 
  2018 	for (p = list_first(&entry->packages, &set->package_pool); p; p = list_next(p)) {
  2019 		if (bitarray_get(pkgbits, p->data) == installed)
  2020 			return &pkgs[p->data];
  2021 	}
  2022 	return NULL;
  2023 }
  2024 
  2025 static struct razor_package *
  2026 find_installed_package_for_file(struct razor_transaction *trans,
  2027 				const char *filename)
  2028 {
  2029 	struct razor_package *pkg;
  2030 
  2031 	pkg = find_package_for_file(trans->system, &trans->syspkgs,
  2032 				    filename, 1);
  2033 	if (!pkg)
  2034 		pkg = find_package_for_file(trans->upstream, &trans->uppkgs,
  2035 					    filename, 1);
  2036 	return pkg;
  2037 }
  2038 
  2039 static struct razor_package *
  2040 find_uninstalled_package_for_file(struct razor_transaction *trans,
  2041 				  const char *filename)
  2042 {
  2043 	struct razor_package *pkg;
  2044 
  2045 	pkg = find_package_for_file(trans->upstream, &trans->uppkgs,
  2046 				    filename, 0);
  2047 	if (!pkg)
  2048 		pkg = find_package_for_file(trans->system, &trans->syspkgs,
  2049 					    filename, 0);
  2050 	return pkg;
  2051 }
  2052 
  2053 static struct razor_property *
  2054 skip_to_matching_property(struct razor_transaction *trans,
  2055 			  struct razor_property *match,
  2056 			  struct razor_property *prop)
  2057 {
  2058 	struct razor_set *mset, *pset;
  2059 	const char *ppool, *mpool;
  2060 	struct razor_property *prop_end;
  2061 
  2062 	if (property_in_set(match, trans->system))
  2063 		mset = trans->system;
  2064 	else
  2065 		mset = trans->upstream;
  2066 
  2067 	if (property_in_set(prop, trans->system))
  2068 		pset = trans->system;
  2069 	else if (property_in_set(prop, trans->upstream))
  2070 		pset = trans->upstream;
  2071 	else
  2072 		return prop;
  2073 
  2074 	prop_end = pset->properties.data + pset->properties.size;
  2075 	ppool = pset->string_pool.data;
  2076 	mpool = mset->string_pool.data;
  2077 
  2078 	while (prop < prop_end &&
  2079 	       strcmp(&ppool[prop->name], &mpool[match->name]) < 0)
  2080 		prop++;
  2081 	return prop;
  2082 }
  2083 
  2084 static struct razor_package *
  2085 find_package_matching(struct razor_transaction *trans, int installed,
  2086 		      struct razor_property *prop,
  2087 		      struct razor_property *req,
  2088 		      struct razor_set *req_set)
  2089 {
  2090 	struct razor_set *set;
  2091 	struct bitarray *pkgbits;
  2092 	struct razor_package *pkgs;
  2093 	struct razor_property *props, *prop_end;
  2094 	enum razor_property_type match_type;
  2095 	const char *pool;
  2096 	const char *rpool;
  2097 	int match_name = (req->type == RAZOR_PROPERTY_OBSOLETES);
  2098 	int match;
  2099 
  2100 	if (property_in_set(prop, trans->system)) {
  2101 		set = trans->system;
  2102 		pkgbits = &trans->syspkgs;
  2103 	} else if (property_in_set(prop, trans->upstream)) {
  2104 		set = trans->upstream;
  2105 		pkgbits = &trans->uppkgs;
  2106 	} else
  2107 		return NULL;
  2108 
  2109 	if (!req_set) {
  2110 		if (property_in_set(req, trans->system))
  2111 			req_set = trans->system;
  2112 		else
  2113 			req_set = trans->upstream;
  2114 	}
  2115 	rpool = req_set->string_pool.data;
  2116 
  2117 	if (req->type == RAZOR_PROPERTY_PROVIDES)
  2118 		match_type = RAZOR_PROPERTY_CONFLICTS;
  2119 	else
  2120 		match_type = RAZOR_PROPERTY_PROVIDES;
  2121 
  2122 	pkgs = set->packages.data;
  2123 	props = set->properties.data;
  2124 	prop_end = set->properties.data + set->properties.size;
  2125 	pool = set->string_pool.data;
  2126 
  2127 	/* Find first matching property */
  2128 	while (prop < prop_end &&
  2129 	       strcmp(&pool[prop->name], &rpool[req->name]) < 0)
  2130 		prop++;
  2131 	if (prop == prop_end ||
  2132 	    strcmp(&pool[prop->name], &rpool[req->name]) > 0)
  2133 		return NULL;
  2134 
  2135 	if (prop->type < match_type) {
  2136 		while (prop < prop_end && prop->type != match_type)
  2137 			prop++;
  2138 	} else {
  2139 		while (prop >= props && prop->type != match_type)
  2140 			prop--;
  2141 		while (prop > props + 1 && (prop - 1)->name == prop->name &&
  2142 		       (prop - 1)->type == match_type)
  2143 			prop--;
  2144 	}
  2145 
  2146 	/* Scan matching properties */
  2147 	while (prop < prop_end && prop->type == match_type &&
  2148 	       strcmp(&pool[prop->name], &rpool[req->name]) == 0) {
  2149 		if (match_type == RAZOR_PROPERTY_PROVIDES)
  2150 			match = provider_satisfies_requirement(prop, pool, req, rpool);
  2151 		else
  2152 			match = provider_satisfies_requirement(req, rpool, prop, pool);
  2153 		if (match) {
  2154 			struct list *pkg;
  2155 
  2156 			for (pkg = list_first(&prop->packages, &set->package_pool); pkg; pkg = list_next(pkg)) {
  2157 				if (bitarray_get(pkgbits, pkg->data) != installed)
  2158 					continue;
  2159 				if (!match_name ||
  2160 				    strcmp(&pool[pkgs[pkg->data].name],
  2161 					   &rpool[req->name]) == 0)
  2162 					return &pkgs[pkg->data];
  2163 			}
  2164 		}
  2165 		prop++;
  2166 	}
  2167 
  2168 	return NULL;
  2169 }
  2170 
  2171 static struct razor_package *
  2172 find_installed_package_for_property(struct razor_transaction *trans,
  2173 				    struct razor_property *sys_start,
  2174 				    struct razor_property *up_start,
  2175 				    struct razor_property *req)
  2176 {
  2177 	struct razor_package *pkg;
  2178 
  2179 	pkg = find_package_matching(trans, 1, sys_start, req, NULL);
  2180 	if (!pkg)
  2181 		pkg = find_package_matching(trans, 1, up_start, req, NULL);
  2182 	return pkg;
  2183 }
  2184 
  2185 static struct razor_package *
  2186 find_uninstalled_package_for_property(struct razor_transaction *trans,
  2187 				      struct razor_property *sys_start,
  2188 				      struct razor_property *up_start,
  2189 				      struct razor_property *req)
  2190 {
  2191 	struct razor_package *pkg;
  2192 
  2193 	pkg = find_package_matching(trans, 0, up_start, req, NULL);
  2194 	if (!pkg)
  2195 		pkg = find_package_matching(trans, 0, sys_start, req, NULL);
  2196 	return pkg;
  2197 }
  2198 
  2199 static struct razor_transaction_package *
  2200 find_transaction_package(struct razor_transaction *trans, const char *name)
  2201 {
  2202 	struct razor_transaction_package *packages;
  2203 	int count, i;
  2204 
  2205 	packages = trans->packages.data;
  2206 	count = trans->packages.size / sizeof *packages;
  2207 	for (i = 0; i < count; i++) {
  2208 		if (packages[i].name && !strcmp(packages[i].name, name))
  2209 			return &packages[i];
  2210 	}
  2211 	return NULL;
  2212 }
  2213 
  2214 /* FIXME? */
  2215 static int
  2216 prop_is_being_installed(struct razor_transaction *trans,
  2217 			struct razor_property *prop)
  2218 {
  2219 	struct list *pkg;
  2220 
  2221 	for (pkg = list_first(&prop->packages, &trans->upstream->package_pool); pkg; pkg = list_next(pkg)) {
  2222 		if (bitarray_get(&trans->uppkgs, pkg->data))
  2223 			return 1;
  2224 	}
  2225 	return 0;
  2226 }
  2227 
  2228 static int
  2229 prop_is_being_removed(struct razor_transaction *trans,
  2230 		      struct razor_property *prop)
  2231 {
  2232 	struct list *pkg;
  2233 
  2234 	for (pkg = list_first(&prop->packages, &trans->system->package_pool); pkg; pkg = list_next(pkg)) {
  2235 		if (bitarray_get(&trans->syspkgs, pkg->data))
  2236 			return 0;
  2237 	}
  2238 	return 1;
  2239 }
  2240 
  2241 static int
  2242 prop_is_being_updated(struct razor_transaction *trans,
  2243 		      struct razor_property *prop)
  2244 {
  2245 	struct razor_package *packages = trans->system->packages.data;
  2246 	const char *pool = trans->system->string_pool.data;
  2247 	struct razor_transaction_package *tp;
  2248 	struct list *pkg;
  2249 
  2250 	/* Assumes prop_is_being_removed returns true */
  2251 
  2252 	for (pkg = list_first(&prop->packages, &trans->system->package_pool); pkg; pkg = list_next(pkg)) {
  2253 		tp = find_transaction_package(trans, &pool[packages[pkg->data].name]);
  2254 		if (tp && tp->state == RAZOR_PACKAGE_REMOVE)
  2255 			return 0;
  2256 	}
  2257 	return 1;
  2258 }
  2259 
  2260 static void
  2261 add_transaction_package(struct razor_transaction *trans,
  2262 			struct razor_package *new_package,
  2263 			struct razor_package *old_package,
  2264 			enum razor_transaction_package_state state,
  2265 			const char *req_package,
  2266 			struct razor_property *req_prop)
  2267 {
  2268 	struct razor_set *new_package_set, *old_package_set, *req_set;
  2269 	struct bitarray *reqpkgbits;
  2270 	struct razor_transaction_package *tp, *already;
  2271 	const char *pool;
  2272 	struct razor_package *pkgs;
  2273 	struct list *pkg;
  2274 	int contradiction = 0;
  2275 
  2276 	if (package_in_set(new_package, trans->system))
  2277 		new_package_set = trans->system;
  2278 	else
  2279 		new_package_set = trans->upstream;
  2280 	if (package_in_set(old_package, trans->system))
  2281 		old_package_set = trans->system;
  2282 	else
  2283 		old_package_set = trans->upstream;
  2284 	if (property_in_set(req_prop, trans->system)) {
  2285 		req_set = trans->system;
  2286 		reqpkgbits = &trans->syspkgs;
  2287 	} else {
  2288 		req_set = trans->upstream;
  2289 		reqpkgbits = &trans->uppkgs;
  2290 	}
  2291 
  2292 	if (new_package) {
  2293 		pool = new_package_set->string_pool.data;
  2294 		already = find_transaction_package(trans, &pool[new_package->name]);
  2295 		if (already) {
  2296 			if (already->new_package == new_package) {
  2297 				/* Already taken care of */
  2298 				return;
  2299 			} else if (new_package_set == trans->upstream &&
  2300 				   already->state == RAZOR_PACKAGE_FORCED_UPDATE) {
  2301 				already->new_package = new_package;
  2302 				return;
  2303 			} else if (new_package_set == trans->upstream) {
  2304 				return;
  2305 			}
  2306 
  2307 			/* Oops. We lose */
  2308 			if (state != RAZOR_PACKAGE_CONTRADICTION)
  2309 				contradiction = 1;
  2310 		}
  2311 	} else if (old_package) {
  2312 		pool = old_package_set->string_pool.data;
  2313 		already = find_transaction_package(trans, &pool[old_package->name]);
  2314 		if (already) {
  2315 			if (already->old_package == old_package) {
  2316 				/* Already taken care of */
  2317 				return;
  2318 			} else if (old_package_set == trans->system) {
  2319 				already->old_package = old_package;
  2320 				return;
  2321 			}
  2322 
  2323 			/* Oops. We lose */
  2324 			if (state != RAZOR_PACKAGE_CONTRADICTION)
  2325 				contradiction = 1;
  2326 		}
  2327 	} else
  2328 		state = RAZOR_PACKAGE_UNSATISFIABLE;
  2329 
  2330 	tp = array_add(&trans->packages, sizeof *tp);
  2331 	memset(tp, 0, sizeof *tp);
  2332 
  2333 	if (new_package) {
  2334 		pool = new_package_set->string_pool.data;
  2335 		tp->new_package = new_package;
  2336 		tp->name = &pool[new_package->name];
  2337 		tp->new_version = &pool[new_package->version];
  2338 
  2339 		pkgs = new_package_set->packages.data;
  2340 	}
  2341 	if (old_package) {
  2342 		pool = old_package_set->string_pool.data;
  2343 		tp->old_package = old_package;
  2344 		tp->name = &pool[old_package->name];
  2345 		tp->old_version = &pool[old_package->version];
  2346 
  2347 		pkgs = old_package_set->packages.data;
  2348 	}
  2349 
  2350 	tp->state = state;
  2351 	if (state != RAZOR_PACKAGE_INSTALL &&
  2352 	    state != RAZOR_PACKAGE_FORCED_UPDATE &&
  2353 	    state != RAZOR_PACKAGE_REMOVE &&
  2354 	    state != RAZOR_PACKAGE_OBSOLETED)
  2355 		trans->errors++;
  2356 
  2357 	if (contradiction) {
  2358 		/* Do this now, after adding tp, so that it ends up
  2359 		 * after both the INSTALL and the REMOVE in the array.
  2360 		 */
  2361 		add_transaction_package(trans, new_package, old_package,
  2362 					RAZOR_PACKAGE_CONTRADICTION,
  2363 					NULL, NULL);
  2364 	}
  2365 
  2366 	if (req_package)
  2367 		tp->dep_package = req_package;
  2368 	if (!req_prop)
  2369 		return;
  2370 
  2371 	pool = req_set->string_pool.data;
  2372 	pkgs = req_set->packages.data;
  2373 	if (!req_package) {
  2374 		for (pkg = list_first(&req_prop->packages, &req_set->package_pool); pkg; pkg = list_next(pkg)) {
  2375 			if (bitarray_get(reqpkgbits, pkg->data))
  2376 				break;
  2377 		}
  2378 		if (pkg)
  2379 			tp->dep_package = &pool[pkgs[pkg->data].name];
  2380 	}
  2381 
  2382 	tp->dep_type = req_prop->type;
  2383 	tp->dep_property = &pool[req_prop->name];
  2384 	tp->dep_relation = req_prop->relation;
  2385 	tp->dep_version = &pool[req_prop->version];
  2386 }
  2387 
  2388 static void
  2389 razor_transaction_satisfy(struct razor_transaction *trans)
  2390 {
  2391 	struct razor_package *spkgs, *upkgs, *pkg;
  2392 	struct razor_property *sp, *sprops, *sprop_end;
  2393 	struct razor_property *up, *uprops, *uprop_end;
  2394 	struct razor_property *sr, *ur, *first_up;
  2395 	const char *spool, *upool, *removed_package;
  2396 	struct list *reqpkg;
  2397 
  2398 	spkgs = trans->system->packages.data;
  2399 	sprops = trans->system->properties.data;
  2400 	sprop_end = trans->system->properties.data + trans->system->properties.size;
  2401 	spool = trans->system->string_pool.data;
  2402 	upkgs = trans->upstream->packages.data;
  2403 	uprops = trans->upstream->properties.data;
  2404 	uprop_end = trans->upstream->properties.data + trans->upstream->properties.size;
  2405 	upool = trans->upstream->string_pool.data;
  2406 
  2407 	sp = sprops;
  2408 	for (up = uprops; up < uprop_end; up++) {
  2409 		/* Skip 'up' ahead to a property of a package which is
  2410 		 * to-be-installed.
  2411 		 */
  2412 		while (up < uprop_end &&
  2413 		       !prop_is_being_installed(trans, up))
  2414 			up++;
  2415 		if (up == uprop_end)
  2416 			break;
  2417 		sp = skip_to_matching_property(trans, up, sp);
  2418 
  2419 		switch (up->type) {
  2420 		case RAZOR_PROPERTY_REQUIRES:
  2421 			if (!strncmp(&upool[up->name], "rpmlib(", 7))
  2422 				break;
  2423 
  2424 			if (find_installed_package_for_property(trans, sp, up, up) ||
  2425 			    find_installed_package_for_file(trans, &upool[up->name])) {
  2426 				/* Requires something that is either installed
  2427 				 * or to-be-installed.
  2428 				 */
  2429 				break;
  2430 			}
  2431 
  2432 			/* See if we can install a new upstream provider */
  2433 			pkg = find_uninstalled_package_for_property(trans, sp, up, up);
  2434 			if (!pkg)
  2435 				pkg = find_uninstalled_package_for_file(trans, &upool[up->name]);
  2436 			add_transaction_package(trans, pkg, NULL,
  2437 						RAZOR_PACKAGE_INSTALL,
  2438 						NULL, up);
  2439 			break;
  2440 
  2441 		case RAZOR_PROPERTY_PROVIDES:
  2442 			/* find_installed_package_for_property works backwards
  2443 			 * here, finding a *conflicting* installed package.
  2444 			 */
  2445 			pkg = find_installed_package_for_property(trans, sp, up, up);
  2446 			if (!pkg)
  2447 				break;
  2448 
  2449 			if (package_in_set(pkg, trans->system)) {
  2450 				/* pkg CONFLICTS with what 'up' PROVIDES. Try
  2451 				 * finding an upgrade
  2452 				 */
  2453 				add_transaction_package(trans, NULL, pkg,
  2454 							RAZOR_PACKAGE_FORCED_UPDATE,
  2455 							&upool[up->name], sp);
  2456 			} else {
  2457 				add_transaction_package(trans, NULL, pkg,
  2458 							RAZOR_PACKAGE_CONTRADICTION,
  2459 							NULL, up);
  2460 			}
  2461 			break;
  2462 
  2463 		case RAZOR_PROPERTY_CONFLICTS:
  2464 			pkg = find_installed_package_for_property(trans, sp, up, up);
  2465 			if (!pkg)
  2466 				break;
  2467 
  2468 			if (package_in_set(pkg, trans->system)) {
  2469 				/* Conflicts with something already installed.
  2470 				 * Try to upgrade out.
  2471 				 */
  2472 				add_transaction_package(trans, NULL, pkg,
  2473 							RAZOR_PACKAGE_FORCED_UPDATE,
  2474 							NULL, up);
  2475 			} else {
  2476 				add_transaction_package(trans, pkg, NULL,
  2477 							RAZOR_PACKAGE_CONTRADICTION,
  2478 							NULL, up);
  2479 			}
  2480 			break;
  2481 
  2482 		case RAZOR_PROPERTY_OBSOLETES:
  2483 			pkg = find_installed_package_for_property(trans, sp, up, up);
  2484 			if (pkg) {
  2485 				/* If pkg is to-be-installed, this
  2486 				 * will add a CONTRADICTION error as well.
  2487 				 */
  2488 				add_transaction_package(trans, NULL, pkg,
  2489 							RAZOR_PACKAGE_OBSOLETED,
  2490 							NULL, up);
  2491 			}
  2492 			break;
  2493 
  2494 		default:
  2495 			/* can't happen */
  2496 			break;
  2497 		}
  2498 	}
  2499 
  2500 	up = uprops;
  2501 	for (sp = sprops; sp < sprop_end; sp++) {
  2502 		/* Skip 'sp' ahead to a PROVIDES of a package which is
  2503 		 * to-be-removed.
  2504 		 */
  2505 		while (sp < sprop_end &&
  2506 		       (sp->type != RAZOR_PROPERTY_PROVIDES ||
  2507 			!prop_is_being_removed(trans, sp)))
  2508 			sp++;
  2509 		if (sp == sprop_end)
  2510 			break;
  2511 
  2512 		removed_package = &spool[spkgs[list_first(&sp->packages, &trans->system->package_pool)->data].name];
  2513 
  2514 		/* Skip 'up' to match */
  2515 		up = skip_to_matching_property(trans, sp, up);
  2516 		ur = first_up = up;
  2517 
  2518 		/* If the package is just being upgraded, we may
  2519 		 * already be installing an identical PROVIDES, so
  2520 		 * check for that.
  2521 		 */
  2522 		while (up < uprop_end &&
  2523 		       strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
  2524 		       (up->type != RAZOR_PROPERTY_PROVIDES || 
  2525 			sp->relation != up->relation ||
  2526 			strcmp(&spool[sp->name], &upool[up->name]) != 0))
  2527 			up++;
  2528 		if (up < uprop_end &&
  2529 		    up->type == RAZOR_PROPERTY_PROVIDES &&
  2530 		    strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
  2531 		    sp->relation == up->relation &&
  2532 		    strcmp(&spool[sp->version], &upool[up->version]) == 0 &&
  2533 		    prop_is_being_installed(trans, up)) {
  2534 			up = first_up;
  2535 			continue;
  2536 		}
  2537 		up = first_up;
  2538 
  2539 		/* For all still-installed packages that require
  2540 		 * sp->name, see if they are satisfied by any other
  2541 		 * still-installed or to-be-installed property. If
  2542 		 * not, either remove or attempt to update the
  2543 		 * package, depending on why the required property has
  2544 		 * disappeared
  2545 		 */
  2546 		sr = sp;
  2547 		while (sr > sprops + 1 && (sr - 1)->name == sr->name)
  2548 			sr--;
  2549 		for (; sr->type == RAZOR_PROPERTY_REQUIRES; sr++) {
  2550 			if (prop_is_being_removed(trans, sr))
  2551 				continue;
  2552 			if (find_installed_package_for_property(trans, sp, up, sr))
  2553 				continue;
  2554 
  2555 			for (reqpkg = list_first(&sr->packages, &trans->system->package_pool); reqpkg; reqpkg = list_next(reqpkg)) {
  2556 				if (!bitarray_get(&trans->syspkgs, reqpkg->data))
  2557 					continue;
  2558 				pkg = &spkgs[reqpkg->data];
  2559 				if (prop_is_being_updated(trans, sp)) {
  2560 					add_transaction_package(trans, NULL, pkg,
  2561 								RAZOR_PACKAGE_FORCED_UPDATE,
  2562 								removed_package, NULL);
  2563 				} else {
  2564 					add_transaction_package(trans, NULL, pkg,
  2565 								RAZOR_PACKAGE_REMOVE,
  2566 								removed_package, sr);
  2567 				}
  2568 			}
  2569 		}
  2570 	}
  2571 }
  2572 
  2573 void
  2574 razor_transaction_install_package(struct razor_transaction *transaction,
  2575 				  struct razor_package *package)
  2576 {
  2577 	add_transaction_package(transaction, package, NULL,
  2578 				RAZOR_PACKAGE_INSTALL, NULL, NULL);
  2579 }
  2580 
  2581 void
  2582 razor_transaction_remove_package(struct razor_transaction *transaction,
  2583 				 struct razor_package *package)
  2584 {
  2585 	add_transaction_package(transaction, NULL, package,
  2586 				RAZOR_PACKAGE_REMOVE, NULL, NULL);
  2587 }
  2588 
  2589 void
  2590 razor_transaction_update_all(struct razor_transaction *trans)
  2591 {
  2592 	struct razor_package *sp, *spkgs, *send, *up, *upkgs, *uend;
  2593 	const char *spool, *upool;
  2594 
  2595 	spkgs = trans->system->packages.data;
  2596 	send = trans->system->packages.data + trans->system->packages.size;
  2597 	spool = trans->system->string_pool.data;
  2598 	up = upkgs = trans->upstream->packages.data;
  2599 	uend = trans->upstream->packages.data + trans->upstream->packages.size;
  2600 	upool = trans->upstream->string_pool.data;
  2601 
  2602 	for (sp = spkgs; sp < send; sp++) {
  2603 		while (up < uend && strcmp(&spool[sp->name], &upool[up->name]) > 0)
  2604 			up++;
  2605 		if (strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
  2606 		    versioncmp(&spool[sp->version], &upool[up->version]) < 0) {
  2607 			add_transaction_package(trans, up, sp,
  2608 						RAZOR_PACKAGE_INSTALL,
  2609 						NULL, NULL);
  2610 		}
  2611 	}
  2612 }
  2613 
  2614 struct razor_transaction *
  2615 razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
  2616 {
  2617 	struct razor_transaction *trans;
  2618 	int count;
  2619 
  2620 	trans = zalloc(sizeof *trans);
  2621 
  2622 	trans->system = system;
  2623 	trans->upstream = upstream ? upstream : razor_set_create();
  2624 	array_init(&trans->packages);
  2625 	count = trans->system->packages.size / sizeof (struct razor_package);
  2626 	bitarray_init(&trans->syspkgs, count, 1);
  2627 	count = trans->upstream->packages.size / sizeof (struct razor_package);
  2628 	bitarray_init(&trans->uppkgs, count, 0);
  2629 
  2630 	return trans;
  2631 }
  2632 
  2633 static void
  2634 resolve_transaction(struct razor_transaction *trans)
  2635 {
  2636 	int start, end;
  2637 
  2638 	if (trans->package_count > 0)
  2639 		/* Already did this, return. */
  2640 		return;
  2641 
  2642 	start = 0;
  2643 	end = trans->packages.size / sizeof (struct razor_transaction_package);
  2644 
  2645 	while (start != end) {
  2646 		resolve_new_packages(trans, start, end);
  2647 		if (trans->errors)
  2648 			break;
  2649 
  2650 		razor_transaction_satisfy(trans);
  2651 
  2652 		start = end;
  2653 		end = trans->packages.size / sizeof (struct razor_transaction_package);
  2654 	}
  2655 
  2656 	trans->package_count = end;
  2657 }
  2658 
  2659 const char * const razor_version_relations[] = {
  2660 	/* same order as enum razor_version_relation */
  2661 	"<", "<=", "=", ">=", ">"
  2662 };
  2663 
  2664 const char * const razor_property_types[] = {
  2665 	/* same order as enum razor_property_type */
  2666 	"requires", "provides", "conflicts with", "obsoletes"
  2667 };
  2668 
  2669 static void
  2670 print_requirement(struct razor_transaction_package *p)
  2671 {
  2672 	if (p->dep_type == RAZOR_PROPERTY_CONFLICTS &&
  2673 	    !strcmp(p->dep_package, p->name)) {
  2674 		printf(" because %s %s conflicts with %s",
  2675 		       p->name, p->old_version, p->dep_property);
  2676 		if (*p->dep_version) {
  2677 			printf(" %s %s",
  2678 			       razor_version_relations[p->dep_relation],
  2679 			       p->dep_version);
  2680 		}
  2681 	} else {
  2682 		if (strcmp(p->name, p->dep_package) != 0)
  2683 			printf(" for %s", p->dep_package);
  2684 		if (*p->dep_version) {
  2685 			printf(", which %s %s %s %s",
  2686 			       razor_property_types[p->dep_type],
  2687 			       p->dep_property,
  2688 			       razor_version_relations[p->dep_relation],
  2689 			       p->dep_version);
  2690 		} else if (strcmp(p->dep_property, p->name) != 0) {
  2691 			printf(", which %s %s",
  2692 			       razor_property_types[p->dep_type],
  2693 			       p->dep_property);
  2694 		}
  2695 	}
  2696 }
  2697 
  2698 int
  2699 razor_transaction_resolve(struct razor_transaction *trans)
  2700 {
  2701 	struct razor_transaction_package *p, *pend, *tps;
  2702 	int errors_only = 0;
  2703 
  2704 	resolve_transaction(trans);
  2705 
  2706 	tps = trans->packages.data;
  2707 	pend = trans->packages.data + trans->packages.size;
  2708 	for (p = trans->packages.data; p < pend; p++) {
  2709 		switch (p->state) {
  2710 		case RAZOR_PACKAGE_INSTALL:
  2711 			if (errors_only)
  2712 				break;
  2713 
  2714 			printf("Installing %s %s", p->name, p->new_version);
  2715 			if (p->dep_package)
  2716 				print_requirement(p);
  2717 			printf("\n");
  2718 			break;
  2719 
  2720 		case RAZOR_PACKAGE_FORCED_UPDATE:
  2721 			if (errors_only)
  2722 				break;
  2723 
  2724 			printf("Updating %s to %s due to update of %s\n",
  2725 			       p->name, p->new_version, p->dep_package);
  2726 			break;
  2727 
  2728 		case RAZOR_PACKAGE_REMOVE:
  2729 			if (errors_only)
  2730 				break;
  2731 			printf("Removing %s %s", p->name, p->old_version);
  2732 			if (p->dep_package) {
  2733 				printf(" which required %s",
  2734 				       p->dep_package);
  2735 				if (strcmp(p->dep_property, p->dep_package) != 0)
  2736 					printf(" for %s", p->dep_property);
  2737 			}
  2738 			printf("\n");
  2739 			break;
  2740 
  2741 		case RAZOR_PACKAGE_OBSOLETED:
  2742 			if (errors_only)
  2743 				break;
  2744 			printf("Removing %s %s", p->name, p->old_version);
  2745 			if (p->dep_package) {
  2746 				printf(" which is obsoleted by %s",
  2747 				       p->dep_package);
  2748 			}
  2749 			printf("\n");
  2750 			break;
  2751 
  2752 		case RAZOR_PACKAGE_INSTALL_UNAVAILABLE:
  2753 			printf("Error: can't find %s", p->name);
  2754 			if (p->dep_package) {
  2755 				printf(" (which is required");
  2756 				print_requirement(p);
  2757 				printf(")");
  2758 			}
  2759 			printf("\n");
  2760 			errors_only = 1;
  2761 			break;
  2762 
  2763 		case RAZOR_PACKAGE_UPDATE_UNAVAILABLE:
  2764 			printf("Error: can't find an updated version of %s (which must be updated due to update of %s)\n",
  2765 			       p->name, p->dep_package);
  2766 			errors_only = 1;
  2767 			break;
  2768 
  2769 		case RAZOR_PACKAGE_REMOVE_NOT_INSTALLED:
  2770 			printf("Error: can't remove %s: not installed\n", p->name);
  2771 			errors_only = 1;
  2772 			break;
  2773 
  2774 		case RAZOR_PACKAGE_UP_TO_DATE:
  2775 			printf("Error: can't update %s", p->name);
  2776 			if (p->dep_package)
  2777 				printf(" (which must be updated due to update of %s)", p->dep_package);
  2778 			printf(": %s is most recent version\n", p->old_version);
  2779 			errors_only = 1;
  2780 			break;
  2781 
  2782 		case RAZOR_PACKAGE_CONTRADICTION:
  2783 			printf("Error: package %s is marked for both installation and removal\n", p->name);
  2784 			errors_only = 1;
  2785 			break;
  2786 
  2787 		case RAZOR_PACKAGE_OLD_CONFLICT:
  2788 			printf("Error: can't install %s, because installed package %s conflicts with ",
  2789 			       p->name, p->dep_package);
  2790 			if (*p->dep_version) {
  2791 				printf("%s %s %s",
  2792 				       p->dep_property,
  2793 				       razor_version_relations[p->dep_relation],
  2794 				       p->dep_version);
  2795 			} else
  2796 				printf("it");
  2797 			printf("\n");
  2798 
  2799 			errors_only = 1;
  2800 			break;
  2801 
  2802 		case RAZOR_PACKAGE_NEW_CONFLICT:
  2803 			printf("Error: can't install %s, because it conflicts with %s",
  2804 			       p->name, p->dep_package);
  2805 			if (*p->dep_version) {
  2806 				printf(" %s %s",
  2807 				       razor_version_relations[p->dep_relation],
  2808 				       p->dep_version);
  2809 			}
  2810 			printf("\n");
  2811 
  2812 			errors_only = 1;
  2813 			break;
  2814 
  2815 		case RAZOR_PACKAGE_UNSATISFIABLE:
  2816 			printf("Error: can't find package for %s", p->dep_property);
  2817 			if (*p->dep_version) {
  2818 				printf(" %s %s",
  2819 					razor_version_relations[p->dep_relation],
  2820 					p->dep_version);
  2821 			}
  2822 			printf(" which is required by %s\n",
  2823 				p->dep_package);
  2824 			errors_only = 1;
  2825 			break;
  2826 
  2827 		default:
  2828 			/* Shouldn't actually happen */
  2829 			break;
  2830 		}
  2831 	}
  2832 
  2833 	return trans->errors;
  2834 }
  2835 
  2836 int
  2837 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
  2838 				       const char *name,
  2839 				       enum razor_version_relation rel,
  2840 				       const char *version)
  2841 {
  2842 	struct razor_transaction_package *p, *end;
  2843 
  2844 	end = trans->packages.data + trans->packages.size;
  2845 	for (p = trans->packages.data; p < end; p++) {
  2846 		if (p->state != RAZOR_PACKAGE_UNSATISFIABLE)
  2847 			continue;
  2848 		if (strcmp(name, p->dep_property) != 0 ||
  2849 		    rel != p->dep_relation ||
  2850 		    strcmp(version, p->dep_version) != 0)
  2851 			continue;
  2852 
  2853 		return 1;
  2854 	}
  2855 
  2856 	return 0;
  2857 }
  2858 
  2859 struct razor_set *
  2860 razor_transaction_finish(struct razor_transaction *trans)
  2861 {
  2862 	struct array install_packages, remove_packages;
  2863 	struct razor_merger *merger;
  2864 	struct razor_package *pkg, *i, *iend, *r, *rend, *s, *send;
  2865 	struct razor_set *set;
  2866 	struct source *source1, *source2;
  2867 	char *spool, *ipool, *rpool;
  2868 	uint32_t *map;
  2869 	struct razor_transaction_package *p, *end;
  2870 	int cmp;
  2871 
  2872 	/* FIXME */
  2873 	if (trans->errors)
  2874 		return NULL;
  2875 
  2876 	/* Sort the transaction packages into two arrays */
  2877 	array_init(&install_packages);
  2878 	array_init(&remove_packages);
  2879 
  2880 	end = trans->packages.data + trans->packages.size;
  2881 	for (p = trans->packages.data; p < end; p++) {
  2882 		if (p->new_package) {
  2883 			pkg = array_add(&install_packages, sizeof *pkg);
  2884 			*pkg = *p->new_package;
  2885 		} else {
  2886 			pkg = array_add(&remove_packages, sizeof *pkg);
  2887 			*pkg = *p->old_package;
  2888 		}
  2889 	}
  2890 	map = razor_qsort_with_data(install_packages.data,
  2891 				    install_packages.size / sizeof *pkg,
  2892 				    sizeof *pkg,
  2893 				    compare_packages,
  2894 				    trans->upstream);
  2895 	free(map);
  2896 	map = razor_qsort_with_data(remove_packages.data,
  2897 				    remove_packages.size / sizeof *pkg,
  2898 				    sizeof *pkg,
  2899 				    compare_packages,
  2900 				    trans->system);
  2901 	free(map);
  2902 
  2903 	merger = razor_merger_create(trans->system, trans->upstream);
  2904 
  2905 	source1 = &merger->source1;
  2906 	source2 = &merger->source2;
  2907 
  2908 	i = install_packages.data;
  2909 	iend = install_packages.data + install_packages.size;
  2910 	ipool = trans->upstream->string_pool.data;
  2911 
  2912 	r = remove_packages.data;
  2913 	rend = remove_packages.data + remove_packages.size;
  2914 	rpool = trans->system->string_pool.data;
  2915 
  2916 	s = trans->system->packages.data;
  2917 	send = trans->system->packages.data + trans->system->packages.size;
  2918 	spool = trans->system->string_pool.data;
  2919 
  2920 	while (s < send || i < iend) {
  2921 		/* Check if s is being removed */
  2922 		if (s < send && r < rend &&
  2923 		    s->name == r->name && s->version && r->version) {
  2924 			s++;
  2925 			r++;
  2926 			continue;
  2927 		}
  2928 
  2929 		if (s < send && i < iend)
  2930 			cmp = strcmp(&spool[s->name], &ipool[i->name]);
  2931 		else if (s < send)
  2932 			cmp = -1;
  2933 		else
  2934 			cmp = 1;
  2935 		if (cmp < 0) {
  2936 			add_package(merger, s, source1, 0);
  2937 			s++;
  2938 		} else if (cmp == 0) {
  2939 			add_package(merger, i, source2, UPSTREAM_SOURCE);
  2940 			s++;
  2941 			i++;
  2942 		} else {
  2943 			add_package(merger, i, source2, UPSTREAM_SOURCE);
  2944 			i++;
  2945 		}
  2946 	}
  2947 
  2948 	array_release(&install_packages);
  2949 	array_release(&remove_packages);
  2950 
  2951 	set = razor_merger_finish(merger);
  2952 	razor_transaction_destroy(trans);
  2953 
  2954 	return set;
  2955 }
  2956 
  2957 void
  2958 razor_transaction_destroy(struct razor_transaction *trans)
  2959 {
  2960 	struct razor_transaction_package *p, *end;
  2961 
  2962 	end = trans->packages.data + trans->packages.size;
  2963 	for (p = trans->packages.data; p < end; p++) {
  2964 		if (!p->dep_package &&
  2965 		    (p->state == RAZOR_PACKAGE_INSTALL_UNAVAILABLE ||
  2966 		     p->state == RAZOR_PACKAGE_REMOVE_NOT_INSTALLED))
  2967 			free((char *)p->name);
  2968 	}
  2969 
  2970 	array_release(&trans->packages);
  2971 	bitarray_release(&trans->syspkgs);
  2972 	bitarray_release(&trans->uppkgs);
  2973 	free(trans);
  2974 
  2975 	/* FIXME: free upstream if it was created as an empty set */
  2976 }