razor.c
author Dan Winship <danw@gnome.org>
Fri Feb 29 12:45:08 2008 -0500 (2008-02-29)
changeset 138 49deac048d07
parent 137 4722cd3437cb
child 139 a416240614e3
permissions -rw-r--r--
implement file dependencies for installs

removes are trickier because there are no backlinks from the files array
the properties array, so there's currently no way to efficiently determine
what packages are affected by the removal of a particular file
     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 	struct list_head properties;
    49 	struct list_head files;
    50 };
    51 
    52 struct razor_property {
    53 	uint name  : 24;
    54 	uint flags : 6;
    55 	uint type  : 2;
    56 	uint32_t relation;
    57 	uint32_t version;
    58 	struct list_head packages;
    59 };
    60 
    61 struct razor_entry {
    62 	uint name  : 24;
    63 	uint flags : 8;
    64 	uint32_t start;
    65 	struct list_head packages;
    66 };
    67 
    68 #define RAZOR_ENTRY_LAST	0x80
    69 
    70 struct razor_set {
    71 	struct array string_pool;
    72  	struct array packages;
    73  	struct array properties;
    74  	struct array files;
    75 	struct array package_pool;
    76  	struct array property_pool;
    77  	struct array file_pool;
    78 	struct razor_set_header *header;
    79 };
    80 
    81 struct import_entry {
    82 	uint32_t package;
    83 	char *name;
    84 };
    85 
    86 struct import_directory {
    87 	uint32_t name, count;
    88 	struct array files;
    89 	struct array packages;
    90 	struct import_directory *last;
    91 };
    92 
    93 struct razor_importer {
    94 	struct razor_set *set;
    95 	struct hashtable table;
    96 	struct razor_package *package;
    97 	struct array properties;
    98 	struct array files;
    99 };
   100 
   101 static void *
   102 zalloc(size_t size)
   103 {
   104 	void *p;
   105 
   106 	p = malloc(size);
   107 	memset(p, 0, size);
   108 
   109 	return p;
   110 }
   111 
   112 struct razor_set_section razor_sections[] = {
   113 	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
   114 	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
   115 	{ RAZOR_PROPERTIES,	offsetof(struct razor_set, properties) },
   116 	{ RAZOR_FILES,		offsetof(struct razor_set, files) },
   117 	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
   118 	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
   119 	{ RAZOR_FILE_POOL,	offsetof(struct razor_set, file_pool) },
   120 };
   121 
   122 struct razor_set *
   123 razor_set_create(void)
   124 {
   125 	return zalloc(sizeof(struct razor_set));
   126 }
   127 
   128 struct razor_set *
   129 razor_set_open(const char *filename)
   130 {
   131 	struct razor_set *set;
   132 	struct razor_set_section *s;
   133 	struct stat stat;
   134 	struct array *array;
   135 	int fd;
   136 
   137 	set = zalloc(sizeof *set);
   138 	fd = open(filename, O_RDONLY);
   139 	if (fstat(fd, &stat) < 0)
   140 		return NULL;
   141 	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   142 	if (set->header == MAP_FAILED) {
   143 		free(set);
   144 		return NULL;
   145 	}
   146 
   147 	for (s = set->header->sections; ~s->type; s++) {
   148 		if (s->type >= ARRAY_SIZE(razor_sections))
   149 			continue;
   150 		if (s->type != razor_sections[s->type].type)
   151 			continue;
   152 		array = (void *) set + razor_sections[s->type].offset;
   153 		array->data = (void *) set->header + s->offset;
   154 		array->size = s->size;
   155 		array->alloc = s->size;
   156 	}
   157 	close(fd);
   158 
   159 	return set;
   160 }
   161 
   162 void
   163 razor_set_destroy(struct razor_set *set)
   164 {
   165 	unsigned int size;
   166 	struct array *a;
   167 	int i;
   168 
   169 	if (set->header) {
   170 		for (i = 0; set->header->sections[i].type; i++)
   171 			;
   172 		size = set->header->sections[i].type;
   173 		munmap(set->header, size);
   174 	} else {
   175 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   176 			a = (void *) set + razor_sections[i].offset;
   177 			free(a->data);
   178 		}
   179 	}
   180 
   181 	free(set);
   182 }
   183 
   184 int
   185 razor_set_write(struct razor_set *set, const char *filename)
   186 {
   187 	char data[4096];
   188 	struct razor_set_header *header = (struct razor_set_header *) data;
   189 	struct array *a;
   190 	uint32_t offset;
   191 	int i, fd;
   192 
   193 	memset(data, 0, sizeof data);
   194 	header->magic = RAZOR_MAGIC;
   195 	header->version = RAZOR_VERSION;
   196 	offset = sizeof data;
   197 
   198 	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   199 		if (razor_sections[i].type != i)
   200 			continue;
   201 		a = (void *) set + razor_sections[i].offset;
   202 		header->sections[i].type = i;
   203 		header->sections[i].offset = offset;
   204 		header->sections[i].size = a->size;
   205 		offset += ALIGN(a->size, 4096);
   206 	}
   207 
   208 	header->sections[i].type = ~0;
   209 	header->sections[i].offset = 0;
   210 	header->sections[i].size = 0;
   211 
   212 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
   213 	if (fd < 0)
   214 		return -1;
   215 
   216 	razor_write(fd, data, sizeof data);
   217 	memset(data, 0, sizeof data);
   218 	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   219 		if (razor_sections[i].type != i)
   220 			continue;
   221 		a = (void *) set + razor_sections[i].offset;
   222 		razor_write(fd, a->data, a->size);
   223 		razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
   224 	}
   225 
   226 	close(fd);
   227 
   228 	return 0;
   229 }
   230 
   231 void
   232 razor_importer_begin_package(struct razor_importer *importer,
   233 			     const char *name, const char *version)
   234 {
   235 	struct razor_package *p;
   236 
   237 	p = array_add(&importer->set->packages, sizeof *p);
   238 	p->name = hashtable_tokenize(&importer->table, name);
   239 	p->flags = 0;
   240 	p->version = hashtable_tokenize(&importer->table, version);
   241 
   242 	importer->package = p;
   243 	array_init(&importer->properties);
   244 }
   245 
   246 void
   247 razor_importer_finish_package(struct razor_importer *importer)
   248 {
   249 	list_set_array(&importer->package->properties,
   250 		       &importer->set->property_pool,
   251 		       &importer->properties,
   252 		       1);
   253 
   254 	array_release(&importer->properties);
   255 }
   256 
   257 void
   258 razor_importer_add_property(struct razor_importer *importer,
   259 			    const char *name,
   260 			    enum razor_version_relation relation,
   261 			    const char *version,
   262 			    enum razor_property_type type)
   263 {
   264 	struct razor_property *p;
   265 	uint32_t *r;
   266 
   267 	p = array_add(&importer->set->properties, sizeof *p);
   268 	p->name = hashtable_tokenize(&importer->table, name);
   269 	p->flags = 0;
   270 	p->type = type;
   271 	p->relation = relation;
   272 	p->version = hashtable_tokenize(&importer->table, version);
   273 	list_set_ptr(&p->packages, importer->package -
   274 		     (struct razor_package *) importer->set->packages.data);
   275 
   276 	r = array_add(&importer->properties, sizeof *r);
   277 	*r = p - (struct razor_property *) importer->set->properties.data;
   278 }
   279 
   280 void
   281 razor_importer_add_file(struct razor_importer *importer, const char *name)
   282 {
   283 	struct import_entry *e;
   284 
   285 	e = array_add(&importer->files, sizeof *e);
   286 
   287 	e->package = importer->package -
   288 		(struct razor_package *) importer->set->packages.data;
   289 	e->name = strdup(name);
   290 }
   291 
   292 struct razor_importer *
   293 razor_importer_new(void)
   294 {
   295 	struct razor_importer *importer;
   296 
   297 	importer = zalloc(sizeof *importer);
   298 	importer->set = razor_set_create();
   299 	hashtable_init(&importer->table, &importer->set->string_pool);
   300 
   301 	return importer;
   302 }
   303 
   304 /* Destroy an importer without creating the set. */
   305 void
   306 razor_importer_destroy(struct razor_importer *importer)
   307 {
   308 	/* FIXME: write this */
   309 }
   310 
   311 
   312 typedef int (*compare_with_data_func_t)(const void *p1,
   313 					const void *p,
   314 					void *data);
   315 
   316 struct qsort_context {
   317 	size_t size;
   318 	compare_with_data_func_t compare;
   319 	void *data;
   320 };
   321 
   322 static void
   323 qsort_swap(void *p1, void *p2, size_t size)
   324 {
   325 	char buffer[size];
   326 
   327 	memcpy(buffer, p1, size);
   328 	memcpy(p1, p2, size);
   329 	memcpy(p2, buffer, size);
   330 }
   331 
   332 static void
   333 __qsort_with_data(void *base, size_t nelem, uint32_t *map,
   334 		  struct qsort_context *ctx)
   335 {
   336 	void *p, *start, *end, *pivot;
   337 	uint32_t *mp, *mstart, *mend, tmp;
   338 	int left, right, result;
   339 	size_t size = ctx->size;
   340 
   341 	p = base;
   342 	start = base;
   343 	end = base + nelem * size;
   344 	mp = map;
   345 	mstart = map;
   346 	mend = map + nelem;
   347 	pivot = base + (random() % nelem) * size;
   348 
   349 	while (p < end) {
   350 		result = ctx->compare(p, pivot, ctx->data);
   351 		if (result < 0) {
   352 			qsort_swap(p, start, size);
   353 			tmp = *mp;
   354 			*mp = *mstart;
   355 			*mstart = tmp;
   356 			if (start == pivot)
   357 				pivot = p;
   358 			start += size;
   359 			mstart++;
   360 			p += size;
   361 			mp++;
   362 		} else if (result == 0) {
   363 			p += size;
   364 			mp++;
   365 		} else {
   366  			end -= size;
   367 			mend--;
   368 			qsort_swap(p, end, size);
   369 			tmp = *mp;
   370 			*mp = *mend;
   371 			*mend = tmp;
   372 			if (end == pivot)
   373 				pivot = p;
   374 		}
   375 	}
   376 
   377 	left = (start - base) / size;
   378 	right = (base + nelem * size - end) / size;
   379 	if (left > 1)
   380 		__qsort_with_data(base, left, map, ctx);
   381 	if (right > 1)
   382 		__qsort_with_data(end, right, mend, ctx);
   383 }
   384 
   385 static uint32_t *
   386 qsort_with_data(void *base, size_t nelem, size_t size,
   387 		compare_with_data_func_t compare, void *data)
   388 {
   389 	struct qsort_context ctx;
   390 	uint32_t *map;
   391 	int i;
   392 
   393 	if (nelem == 0)
   394 		return NULL;
   395 
   396 	ctx.size = size;
   397 	ctx.compare = compare;
   398 	ctx.data = data;
   399 
   400 	map = malloc(nelem * sizeof (uint32_t));
   401 	for (i = 0; i < nelem; i++)
   402 		map[i] = i;
   403 
   404 	__qsort_with_data(base, nelem, map, &ctx);
   405 
   406 	return map;
   407 }
   408 
   409 static int
   410 versioncmp(const char *s1, const char *s2)
   411 {
   412 	const char *p1, *p2;
   413 	long n1, n2;
   414 	int res;
   415 
   416 	n1 = strtol(s1, (char **) &p1, 0);
   417 	n2 = strtol(s2, (char **) &p2, 0);
   418 
   419 	/* Epoch; if one but not the other has an epoch set, default
   420 	 * the epoch-less version to 0. */
   421 	res = (*p1 == ':') - (*p2 == ':');
   422 	if (res < 0) {
   423 		n1 = 0;
   424 		p1 = s1;
   425 		p2++;
   426 	} else if (res > 0) {
   427 		p1++;
   428 		n2 = 0;
   429 		p2 = s2;
   430 	}
   431 
   432 	if (n1 != n2)
   433 		return n1 - n2;
   434 	while (*p1 && *p2) {
   435 		if (*p1 != *p2)
   436 			return *p1 - *p2;
   437 		p1++;
   438 		p2++;
   439 		if (isdigit(*p1) && isdigit(*p2))
   440 			return versioncmp(p1, p2);
   441 	}
   442 
   443 	return *p1 - *p2;
   444 }
   445 
   446 static int
   447 compare_packages(const void *p1, const void *p2, void *data)
   448 {
   449 	const struct razor_package *pkg1 = p1, *pkg2 = p2;
   450 	struct razor_set *set = data;
   451 	char *pool = set->string_pool.data;
   452 
   453 	/* FIXME: what if the flags are different? */
   454 	if (pkg1->name == pkg2->name)
   455 		return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
   456 	else
   457 		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
   458 }
   459 
   460 static int
   461 compare_properties(const void *p1, const void *p2, void *data)
   462 {
   463 	const struct razor_property *prop1 = p1, *prop2 = p2;
   464 	struct razor_set *set = data;
   465 	char *pool = set->string_pool.data;
   466 
   467 	if (prop1->name != prop2->name) 
   468 		return strcmp(&pool[prop1->name], &pool[prop2->name]);
   469 	else if (prop1->type != prop2->type)
   470 		return prop1->type - prop2->type;
   471 	else if (prop1->relation != prop2->relation)
   472 		return prop1->relation - prop2->relation;
   473 	else
   474 		return versioncmp(&pool[prop1->version], &pool[prop2->version]);
   475 }
   476 
   477 static uint32_t *
   478 uniqueify_properties(struct razor_set *set)
   479 {
   480 	struct razor_property *rp, *up, *rp_end;
   481 	struct array *pkgs, *p;
   482 	struct list_head *r;
   483 	uint32_t *map, *rmap;
   484 	int i, count, unique;
   485 
   486 	count = set->properties.size / sizeof(struct razor_property);
   487 	map = qsort_with_data(set->properties.data,
   488 			      count,
   489 			      sizeof(struct razor_property),
   490 			      compare_properties,
   491 			      set);
   492 
   493 	rp_end = set->properties.data + set->properties.size;
   494 	rmap = malloc(count * sizeof *map);
   495 	pkgs = zalloc(count * sizeof *pkgs);
   496 	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
   497 		if (rp->name != up->name || rp->type != up->type ||
   498 		    rp->relation != up->relation || rp->version != up->version) {
   499 			up++;
   500 			up->name = rp->name;
   501 			up->flags = 0;
   502 			up->type = rp->type;
   503 			up->relation = rp->relation;
   504 			up->version = rp->version;
   505 		}
   506 
   507 		unique = up - (struct razor_property *) set->properties.data;
   508 		rmap[map[i]] = unique;
   509 		r = array_add(&pkgs[unique], sizeof *r);
   510 		*r = rp->packages;
   511 	}
   512 	free(map);
   513 
   514 	if (up != rp)
   515 		up++;
   516 	set->properties.size = (void *) up - set->properties.data;
   517 	rp_end = up;
   518 	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
   519 		list_set_array(&rp->packages, &set->package_pool, p, 0);
   520 		array_release(p);
   521 	}
   522 
   523 	free(pkgs);
   524 
   525 	return rmap;
   526 }
   527 
   528 static int
   529 compare_filenames(const void *p1, const void *p2, void *data)
   530 {
   531 	const struct import_entry *e1 = p1;
   532 	const struct import_entry *e2 = p2;
   533 	const char *n1 = e1->name;
   534 	const char *n2 = e2->name;
   535 
   536 	/* Need to make sure that the contents of a directory
   537 	 * are sorted immediately after it. So "foo/bar" has to
   538 	 * sort before "foo.conf"
   539 	 *
   540 	 * FIXME: this is about 60% slower than strcmp
   541 	 */
   542 	while (*n1 && *n2) {
   543 		if (*n1 < *n2)
   544 			return *n2 == '/' ? 1 : -1;
   545 		else if (*n1 > *n2)
   546 			return *n1 == '/' ? -1 : 1;
   547 		n1++;
   548 		n2++;
   549 	}
   550 	if (*n1)
   551 		return 1;
   552 	else if (*n2)
   553 		return -1;
   554 	else
   555 		return 0;
   556 }
   557 
   558 static void
   559 count_entries(struct import_directory *d)
   560 {
   561 	struct import_directory *p, *end;
   562 
   563 	p = d->files.data;
   564 	end = d->files.data + d->files.size;
   565 	d->count = 0;
   566 	while (p < end) {
   567 		count_entries(p);
   568 		d->count += p->count + 1;
   569 		p++;
   570 	}		
   571 }
   572 
   573 static void
   574 serialize_files(struct razor_set *set,
   575 		struct import_directory *d, struct array *array)
   576 {
   577 	struct import_directory *p, *end;
   578 	struct razor_entry *e = NULL;
   579 	uint32_t s;
   580 
   581 	p = d->files.data;
   582 	end = d->files.data + d->files.size;
   583 	s = array->size / sizeof *e + d->files.size / sizeof *p;
   584 	while (p < end) {
   585 		e = array_add(array, sizeof *e);
   586 		e->name = p->name;
   587 		e->flags = 0;
   588 		e->start = p->count > 0 ? s : 0;
   589 		s += p->count;
   590 
   591 		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
   592 		array_release(&p->packages);
   593 		p++;
   594 	}		
   595 	if (e != NULL)
   596 		e->flags |= RAZOR_ENTRY_LAST;
   597 
   598 	p = d->files.data;
   599 	end = d->files.data + d->files.size;
   600 	while (p < end) {
   601 		serialize_files(set, p, array);
   602 		p++;
   603 	}
   604 }
   605 
   606 static void
   607 remap_property_package_links(struct array *properties, uint32_t *rmap)
   608 {
   609 	struct razor_property *p, *end;
   610 
   611 	end = properties->data + properties->size;
   612 	for (p = properties->data; p < end; p++)
   613 		list_remap_head(&p->packages, rmap);
   614 }
   615 
   616 static void
   617 build_file_tree(struct razor_importer *importer)
   618 {
   619 	int count, i, length;
   620 	struct import_entry *filenames;
   621 	char *f, *end;
   622 	uint32_t name, *r;
   623 	char dirname[256];
   624 	struct import_directory *d, root;
   625 	struct razor_entry *e;
   626 
   627 	count = importer->files.size / sizeof (struct import_entry);
   628 	qsort_with_data(importer->files.data,
   629 			count,
   630 			sizeof (struct import_entry),
   631 			compare_filenames,
   632 			NULL);
   633 
   634 	root.name = hashtable_tokenize(&importer->table, "");
   635 	array_init(&root.files);
   636 	array_init(&root.packages);
   637 	root.last = NULL;
   638 
   639 	filenames = importer->files.data;
   640 	for (i = 0; i < count; i++) {
   641 		f = filenames[i].name;
   642 		if (*f != '/')
   643 			continue;
   644 		f++;
   645 
   646 		d = &root;
   647 		while (*f) {
   648 			end = strchr(f, '/');
   649 			if (end == NULL)
   650 				end = f + strlen(f);
   651 			length = end - f;
   652 			memcpy(dirname, f, length);
   653 			dirname[length] ='\0';
   654 			name = hashtable_tokenize(&importer->table, dirname);
   655 			if (d->last == NULL || d->last->name != name) {
   656 				d->last = array_add(&d->files, sizeof *d);
   657 				d->last->name = name;
   658 				d->last->last = NULL;
   659 				array_init(&d->last->files);
   660 				array_init(&d->last->packages);
   661 			}
   662 			d = d->last;				
   663 			f = end + 1;
   664 			if (*end == '\0')
   665 				break;
   666 		}
   667 
   668 		r = array_add(&d->packages, sizeof *r);
   669 		*r = filenames[i].package;
   670 		free(filenames[i].name);
   671 	}
   672 
   673 	count_entries(&root);
   674 	array_init(&importer->set->files);
   675 
   676 	e = array_add(&importer->set->files, sizeof *e);
   677 	e->name = root.name;
   678 	e->flags = RAZOR_ENTRY_LAST;
   679 	e->start = importer->files.size ? 1 : 0;
   680 	list_set_empty(&e->packages);
   681 
   682 	serialize_files(importer->set, &root, &importer->set->files);
   683 
   684 	array_release(&importer->files);
   685 }
   686 
   687 static void
   688 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
   689 {
   690 	struct razor_package *p, *packages;
   691 	struct array *pkgs;
   692 	struct razor_entry *e, *end;
   693 	struct list *r;
   694 	uint32_t *q;
   695 	int i, count;
   696 
   697 	count = set->packages.size / sizeof *p;
   698 	pkgs = zalloc(count * sizeof *pkgs);
   699 
   700 	end = set->files.data + set->files.size;
   701 	for (e = set->files.data; e < end; e++) {
   702 		list_remap_head(&e->packages, rmap);
   703 		r = list_first(&e->packages, &set->package_pool);
   704 		while (r) {
   705 			q = array_add(&pkgs[r->data], sizeof *q);
   706 			*q = e - (struct razor_entry *) set->files.data;
   707 			r = list_next(r);
   708 		}
   709 	}
   710 
   711 	packages = set->packages.data;
   712 	for (i = 0; i < count; i++) {
   713 		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
   714 		array_release(&pkgs[i]);
   715 	}
   716 	free(pkgs);
   717 }
   718 
   719 struct razor_set *
   720 razor_importer_finish(struct razor_importer *importer)
   721 {
   722 	struct razor_set *set;
   723 	uint32_t *map, *rmap;
   724 	int i, count;
   725 
   726 	map = uniqueify_properties(importer->set);
   727 	list_remap_pool(&importer->set->property_pool, map);
   728 	free(map);
   729 
   730 	count = importer->set->packages.size / sizeof(struct razor_package);
   731 	map = qsort_with_data(importer->set->packages.data,
   732 			      count,
   733 			      sizeof(struct razor_package),
   734 			      compare_packages,
   735 			      importer->set);
   736 
   737 	rmap = malloc(count * sizeof *rmap);
   738 	for (i = 0; i < count; i++)
   739 		rmap[map[i]] = i;
   740 	free(map);
   741 
   742 	build_file_tree(importer);
   743 	list_remap_pool(&importer->set->package_pool, rmap);
   744 	build_package_file_lists(importer->set, rmap);
   745 	remap_property_package_links(&importer->set->properties, rmap);
   746 	free(rmap);
   747 
   748 	set = importer->set;
   749 	hashtable_release(&importer->table);
   750 	free(importer);
   751 
   752 	return set;
   753 }
   754 
   755 struct razor_package_iterator {
   756 	struct razor_set *set;
   757 	struct razor_package *package, *end;
   758 	struct list *index;
   759 };
   760 
   761 static struct razor_package_iterator *
   762 razor_package_iterator_create_with_index(struct razor_set *set,
   763 					 struct list *index)
   764 {
   765 	struct razor_package_iterator *pi;
   766 
   767 	pi = zalloc(sizeof *pi);
   768 	pi->set = set;
   769 	pi->index = index;
   770 
   771 	return pi;
   772 }
   773 
   774 struct razor_package_iterator *
   775 razor_package_iterator_create(struct razor_set *set)
   776 {
   777 	struct razor_package_iterator *pi;
   778 
   779 	pi = zalloc(sizeof *pi);
   780 	pi->set = set;
   781 	pi->end = set->packages.data + set->packages.size;
   782 	pi->package = set->packages.data;
   783 
   784 	return pi;
   785 }
   786 
   787 struct razor_package_iterator *
   788 razor_package_iterator_create_for_property(struct razor_set *set,
   789 					   struct razor_property *property)
   790 {
   791 	struct list *index;
   792 
   793 	index = list_first(&property->packages, &set->package_pool);
   794 	return razor_package_iterator_create_with_index(set, index);
   795 }
   796 
   797 int
   798 razor_package_iterator_next(struct razor_package_iterator *pi,
   799 			    struct razor_package **package,
   800 			    const char **name, const char **version)
   801 {
   802 	char *pool;
   803 	int valid;
   804 	struct razor_package *p, *packages;
   805 
   806 	if (pi->package) {
   807 		p = pi->package++;
   808 		valid = p < pi->end;
   809 	} else if (pi->index) {
   810 		packages = pi->set->packages.data;
   811 		p = &packages[pi->index->data];
   812 		pi->index = list_next(pi->index);
   813 		valid = 1;
   814 	} else
   815 		valid = 0;
   816 
   817 	if (valid) {
   818 		pool = pi->set->string_pool.data;
   819 		*package = p;
   820 		*name = &pool[p->name];
   821 		*version = &pool[p->version];
   822 	} else {
   823 		*package = NULL;
   824 	}
   825 
   826 	return valid;
   827 }
   828 
   829 void
   830 razor_package_iterator_destroy(struct razor_package_iterator *pi)
   831 {
   832 	free(pi);
   833 }
   834 
   835 struct razor_package *
   836 razor_set_get_package(struct razor_set *set, const char *package)
   837 {
   838 	struct razor_package_iterator *pi;
   839 	struct razor_package *p;
   840 	const char *name, *version;
   841 
   842 	pi = razor_package_iterator_create(set);
   843 	while (razor_package_iterator_next(pi, &p, &name, &version)) {
   844 		if (strcmp(package, name) == 0)
   845 			break;
   846 	}
   847 	razor_package_iterator_destroy(pi);
   848 
   849 	return p;
   850 }
   851 
   852 struct razor_property_iterator {
   853 	struct razor_set *set;
   854 	struct razor_property *property, *end;
   855 	struct list *index;
   856 };
   857 
   858 struct razor_property_iterator *
   859 razor_property_iterator_create(struct razor_set *set,
   860 			       struct razor_package *package)
   861 {
   862 	struct razor_property_iterator *pi;
   863 
   864 	pi = zalloc(sizeof *pi);
   865 	pi->set = set;
   866 
   867 	if (package) {
   868 		pi->index = list_first(&package->properties,
   869 				       &set->property_pool);
   870 	} else {
   871 		pi->property = set->properties.data;
   872 		pi->end = set->properties.data + set->properties.size;
   873 	}
   874 
   875 	return pi;
   876 }
   877 
   878 int
   879 razor_property_iterator_next(struct razor_property_iterator *pi,
   880 			     struct razor_property **property,
   881 			     const char **name,
   882 			     enum razor_version_relation *relation,
   883 			     const char **version,
   884 			     enum razor_property_type *type)
   885 {
   886 	char *pool;
   887 	int valid;
   888 	struct razor_property *p, *properties;
   889 
   890 	if (pi->property) {
   891 		p = pi->property++;
   892 		valid = p < pi->end;
   893 	} else if (pi->index) {
   894 		properties = pi->set->properties.data;
   895 		p = &properties[pi->index->data];
   896 		pi->index = list_next(pi->index);
   897 		valid = 1;
   898 	} else
   899 		valid = 0;
   900 
   901 	if (valid) {
   902 		pool = pi->set->string_pool.data;
   903 		*property = p;
   904 		*name = &pool[p->name];
   905 		*relation = p->relation;
   906 		*version = &pool[p->version];
   907 		*type = p->type;
   908 	} else {
   909 		*property = NULL;
   910 	}
   911 
   912 	return valid;
   913 }
   914 
   915 void
   916 razor_property_iterator_destroy(struct razor_property_iterator *pi)
   917 {
   918 	free(pi);
   919 }
   920 
   921 static struct razor_entry *
   922 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
   923 {
   924 	struct razor_entry *e;
   925 	const char *n, *pool = set->string_pool.data;
   926 	int len;
   927 
   928 	e = (struct razor_entry *) set->files.data + dir->start;
   929 	do {
   930 		n = pool + e->name;
   931 		if (strcmp(pattern + 1, n) == 0)
   932 			return e;
   933 		len = strlen(n);
   934 		if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
   935 		    pattern[len + 1] == '/') {
   936 			return find_entry(set, e, pattern + len + 1);
   937 		}
   938 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   939 
   940 	return NULL;
   941 }
   942 
   943 static void
   944 list_dir(struct razor_set *set, struct razor_entry *dir,
   945 	 char *prefix, const char *pattern)
   946 {
   947 	struct razor_entry *e;
   948 	const char *n, *pool = set->string_pool.data;
   949 
   950 	e = (struct razor_entry *) set->files.data + dir->start;
   951 	do {
   952 		n = pool + e->name;
   953 		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
   954 			continue;
   955 		printf("%s/%s\n", prefix, n);
   956 		if (e->start) {
   957 			char *sub = prefix + strlen (prefix);
   958 			*sub = '/';
   959 			strcpy (sub + 1, n);
   960 			list_dir(set, e, prefix, pattern);
   961 			*sub = '\0';
   962 		}
   963 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   964 }
   965 
   966 void
   967 razor_set_list_files(struct razor_set *set, const char *pattern)
   968 {
   969 	struct razor_entry *e;
   970 	char buffer[512], *p, *base;
   971 
   972 	if (pattern == NULL || !strcmp (pattern, "/")) {
   973 		buffer[0] = '\0';
   974 		list_dir(set, set->files.data, buffer, NULL);
   975 		return;
   976 	}
   977 
   978 	strcpy(buffer, pattern);
   979 	e = find_entry(set, set->files.data, buffer);
   980 	if (e && e->start > 0) {
   981 		base = NULL;
   982 	} else {
   983 		p = strrchr(buffer, '/');
   984 		if (p) {
   985 			*p = '\0';
   986 			base = p + 1;
   987 		} else {
   988 			base = NULL;
   989 		}
   990 	}
   991 	e = find_entry(set, set->files.data, buffer);
   992 	if (e->start != 0)
   993 		list_dir(set, e, buffer, base);
   994 }
   995 
   996 struct razor_package_iterator *
   997 razor_package_iterator_create_for_file(struct razor_set *set,
   998 				       const char *filename)
   999 {
  1000 	struct razor_entry *entry;
  1001 	struct list *index;
  1002 
  1003 	entry = find_entry(set, set->files.data, filename);
  1004 	if (entry == NULL)
  1005 		return NULL;
  1006 	
  1007 	index = list_first(&entry->packages, &set->package_pool);
  1008 	return razor_package_iterator_create_with_index(set, index);
  1009 }
  1010 
  1011 static struct list *
  1012 list_package_files(struct razor_set *set, struct list *r,
  1013 		   struct razor_entry *dir, uint32_t end,
  1014 		   char *prefix)
  1015 {
  1016 	struct razor_entry *e, *f, *entries;
  1017 	uint32_t next, file;
  1018 	char *pool;
  1019 	int len;
  1020 	
  1021 	entries = (struct razor_entry *) set->files.data;
  1022 	pool = set->string_pool.data;
  1023 
  1024 	e = entries + dir->start;
  1025 	do {
  1026 		if (entries + r->data == e) {
  1027 			printf("%s/%s\n", prefix, pool + e->name);
  1028 			r = list_next(r);
  1029 			if (!r)
  1030 				return NULL;
  1031 			if (r->data >= end)
  1032 				return r;
  1033 		}
  1034 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
  1035 
  1036 	e = entries + dir->start;
  1037 	do {
  1038 		if (e->start == 0)
  1039 			continue;
  1040 
  1041 		if (e->flags & RAZOR_ENTRY_LAST)
  1042 			next = end;
  1043 		else {
  1044 			f = e + 1; 
  1045 			while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
  1046 				f++;
  1047 			if (f->start == 0)
  1048 				next = end;
  1049 			else
  1050 				next = f->start;
  1051 		}
  1052 
  1053 		file = r->data;
  1054 		if (e->start <= file && file < next) {
  1055 			len = strlen(prefix);
  1056 			prefix[len] = '/';
  1057 			strcpy(prefix + len + 1, pool + e->name);
  1058 			r = list_package_files(set, r, e, next, prefix);
  1059 			prefix[len] = '\0';
  1060 		}
  1061 	} while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
  1062 
  1063 	return r;
  1064 }
  1065 
  1066 void
  1067 razor_set_list_package_files(struct razor_set *set, const char *name)
  1068 {
  1069 	struct razor_package *package;
  1070 	struct list *r;
  1071 	uint32_t end;
  1072 	char buffer[512];
  1073 
  1074 	package = razor_set_get_package(set, name);
  1075 
  1076 	r = list_first(&package->files, &set->file_pool);
  1077 	end = set->files.size / sizeof (struct razor_entry);
  1078 	buffer[0] = '\0';
  1079 	list_package_files(set, r, set->files.data, end, buffer);
  1080 }
  1081 
  1082 static void
  1083 razor_set_validate(struct razor_set *set, struct array *unsatisfied)
  1084 {
  1085 	struct razor_property *r, *p, *end;
  1086 	uint32_t *u;
  1087 	char *pool;
  1088 
  1089 	end = set->properties.data + set->properties.size;
  1090 	pool = set->string_pool.data;
  1091 	
  1092 	for (r = set->properties.data, p = r; r < end; r++) {
  1093 		if (r->type != RAZOR_PROPERTY_REQUIRES)
  1094 			continue;
  1095 
  1096 		p = r;
  1097 		while (p < end && p->name == r->name &&
  1098 		       p->type == r->type)
  1099 			p++;
  1100 
  1101 		/* If there is more than one version of a provides,
  1102 		 * seek to the end for the highest version. */
  1103 		/* FIXME: This doesn't work if we have a series of
  1104 		 * requires a = 1, provides a = 1, requires a = 2,
  1105 		 * provides a = 2, as the kernel and kernel-devel
  1106 		 * does.*/
  1107 		while (p + 1 < end && p->name == (p + 1)->name &&
  1108 		       p->type == (p + 1)->type)
  1109 			p++;
  1110 
  1111 		/* FIXME: We need to track property flags (<, <=, =
  1112 		 * etc) to properly determine if a requires is
  1113 		 * satisfied.  The current code doesn't track that the
  1114 		 * requires a = 1 isn't satisfied by a = 2 provides. */
  1115 
  1116 		if (p == end ||
  1117 		    p->type != RAZOR_PROPERTY_PROVIDES ||
  1118 		    r->name != p->name ||
  1119 		    versioncmp(&pool[r->version], &pool[p->version]) > 0) {
  1120 			/* FIXME: We ignore file requires for now. */
  1121 			if (pool[r->name] == '/')
  1122 				continue;
  1123 			u = array_add(unsatisfied, sizeof *u);
  1124 			*u = r - (struct razor_property *) set->properties.data;
  1125 		}
  1126 	}
  1127 }
  1128 
  1129 void
  1130 razor_set_list_unsatisfied(struct razor_set *set)
  1131 {
  1132 	struct array unsatisfied;
  1133 	struct razor_property *properties, *r;
  1134 	uint32_t *u, *end;
  1135 	char *pool;
  1136 
  1137 	array_init(&unsatisfied);
  1138 	razor_set_validate(set, &unsatisfied);
  1139 
  1140 	end = unsatisfied.data + unsatisfied.size;
  1141 	properties = set->properties.data;
  1142 	pool = set->string_pool.data;
  1143 
  1144 	for (u = unsatisfied.data; u < end; u++) {
  1145 		r = properties + *u;
  1146 		if (pool[r->version] == '\0')
  1147 			printf("%ss not satisfied\n",
  1148 			       &pool[r->name]);
  1149 		else
  1150 			printf("%s-%s not satisfied\n",
  1151 			       &pool[r->name],
  1152 			       &pool[r->version]);
  1153 	}
  1154 
  1155 	array_release(&unsatisfied);
  1156 }
  1157 
  1158 #define UPSTREAM_SOURCE 0x80
  1159 
  1160 struct source {
  1161 	struct razor_set *set;
  1162 	uint32_t *property_map;
  1163 	uint32_t *file_map;
  1164 };
  1165 
  1166 struct razor_merger {
  1167 	struct razor_set *set;
  1168 	struct hashtable table;
  1169 	struct source source1;
  1170 	struct source source2;
  1171 };
  1172 
  1173 static struct razor_merger *
  1174 razor_merger_create(struct razor_set *set1, struct razor_set *set2)
  1175 {
  1176 	struct razor_merger *merger;
  1177 	int count;
  1178 	size_t size;
  1179 
  1180 	merger = zalloc(sizeof *merger);
  1181 	merger->set = razor_set_create();
  1182 	hashtable_init(&merger->table, &merger->set->string_pool);
  1183 
  1184 	merger->source1.set = set1;
  1185 	count = set1->properties.size / sizeof (struct razor_property);
  1186 	size = count * sizeof merger->source1.property_map[0];
  1187 	merger->source1.property_map = zalloc(size);
  1188 	count = set1->files.size / sizeof (struct razor_entry);
  1189 	size = count * sizeof merger->source1.file_map[0];
  1190 	merger->source1.file_map = zalloc(size);
  1191 
  1192 	merger->source2.set = set2;
  1193 	count = set2->properties.size / sizeof (struct razor_property);
  1194 	size = count * sizeof merger->source2.property_map[0];
  1195 	merger->source2.property_map = zalloc(size);
  1196 	count = set2->files.size / sizeof (struct razor_entry);
  1197 	size = count * sizeof merger->source2.file_map[0];
  1198 	merger->source2.file_map = zalloc(size);
  1199 
  1200 	return merger;
  1201 }
  1202 
  1203 static void
  1204 add_package(struct razor_merger *merger,
  1205 	    struct razor_package *package, struct source *source,
  1206 	    uint32_t flags)
  1207 {
  1208 	char *pool;
  1209 	struct list *r;
  1210 	struct razor_package *p;
  1211 
  1212 	pool = source->set->string_pool.data;
  1213 	p = array_add(&merger->set->packages, sizeof *p);
  1214 	p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
  1215 	p->flags = flags;
  1216 	p->version = hashtable_tokenize(&merger->table,
  1217 					&pool[package->version]);
  1218 
  1219 	p->properties = package->properties;
  1220 	r = list_first(&package->properties, &source->set->property_pool);
  1221 	while (r) {
  1222 		source->property_map[r->data] = 1;
  1223 		r = list_next(r);
  1224 	}
  1225 
  1226 	p->files = package->files;
  1227 	r = list_first(&package->files, &source->set->file_pool);
  1228 	while (r) {
  1229 		source->file_map[r->data] = 1;
  1230 		r = list_next(r);
  1231 	}
  1232 }
  1233 
  1234 static uint32_t
  1235 add_property(struct razor_merger *merger,
  1236 	     const char *name, enum razor_version_relation relation,
  1237 	     const char *version, int type)
  1238 {
  1239 	struct razor_property *p;
  1240 
  1241 	p = array_add(&merger->set->properties, sizeof *p);
  1242 	p->name = hashtable_tokenize(&merger->table, name);
  1243 	p->flags = 0;
  1244 	p->type = type;
  1245 	p->relation = relation;
  1246 	p->version = hashtable_tokenize(&merger->table, version);
  1247 
  1248 	return p - (struct razor_property *) merger->set->properties.data;
  1249 }
  1250 
  1251 static void
  1252 merge_properties(struct razor_merger *merger)
  1253 {
  1254 	struct razor_property *p1, *p2;
  1255 	struct razor_set *set1, *set2;
  1256 	uint32_t *map1, *map2;
  1257 	int i, j, cmp, count1, count2;
  1258 	char *pool1, *pool2;
  1259 
  1260 	set1 = merger->source1.set;
  1261 	set2 = merger->source2.set;
  1262 	map1 = merger->source1.property_map;
  1263 	map2 = merger->source2.property_map;
  1264 
  1265 	i = 0;
  1266 	j = 0;
  1267 	pool1 = set1->string_pool.data;
  1268 	pool2 = set2->string_pool.data;
  1269 
  1270 	count1 = set1->properties.size / sizeof *p1;
  1271 	count2 = set2->properties.size / sizeof *p2;
  1272 	while (i < count1 || j < count2) {
  1273 		if (i < count1 && map1[i] == 0) {
  1274 			i++;
  1275 			continue;
  1276 		}
  1277 		if (j < count2 && map2[j] == 0) {
  1278 			j++;
  1279 			continue;
  1280 		}
  1281 		p1 = (struct razor_property *) set1->properties.data + i;
  1282 		p2 = (struct razor_property *) set2->properties.data + j;
  1283 		if (i < count1 && j < count2)
  1284 			cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
  1285 		else if (i < count1)
  1286 			cmp = -1;
  1287 		else
  1288 			cmp = 1;
  1289 		if (cmp == 0)
  1290 			cmp = p1->type - p2->type;
  1291 		if (cmp == 0)
  1292 			cmp = p1->relation - p2->relation;
  1293 		if (cmp == 0)
  1294 			cmp = versioncmp(&pool1[p1->version],
  1295 					 &pool2[p2->version]);
  1296 		if (cmp < 0) {
  1297 			map1[i++] = add_property(merger,
  1298 						 &pool1[p1->name],
  1299 						 p1->relation,
  1300 						 &pool1[p1->version],
  1301 						 p1->type);
  1302 		} else if (cmp > 0) {
  1303 			map2[j++] = add_property(merger,
  1304 						 &pool2[p2->name],
  1305 						 p2->relation,
  1306 						 &pool2[p2->version],
  1307 						 p2->type);
  1308 		} else  {
  1309 			map1[i++] = map2[j++] = add_property(merger,
  1310 							     &pool1[p1->name],
  1311 							     p1->relation,
  1312 							     &pool1[p1->version],
  1313 							     p1->type);
  1314 		}
  1315 	}
  1316 }
  1317 
  1318 static void
  1319 emit_properties(struct list_head *properties, struct array *source_pool,
  1320 		uint32_t *map, struct array *pool)
  1321 {
  1322 	uint32_t r;
  1323 	struct list *p, *q;
  1324 
  1325 	r = pool->size / sizeof *q;
  1326 	p = list_first(properties, source_pool);
  1327 	while (p) {
  1328 		q = array_add(pool, sizeof *q);
  1329 		q->data = map[p->data];
  1330 		q->flags = p->flags;
  1331 		p = list_next(p);
  1332 	}
  1333 
  1334 	list_set_ptr(properties, r);
  1335 }
  1336 
  1337 static uint32_t
  1338 add_file(struct razor_merger *merger, const char *name)
  1339 {
  1340 	struct razor_entry *e;
  1341 
  1342 	e = array_add(&merger->set->files, sizeof *e);
  1343 	e->name = hashtable_tokenize(&merger->table, name);
  1344 	e->flags = 0;
  1345 	e->start = 0;
  1346 
  1347 	return e - (struct razor_entry *)merger->set->files.data;
  1348 }
  1349 
  1350 /* FIXME. Blah */
  1351 static int
  1352 fix_file_map(uint32_t *map,
  1353 	     struct razor_entry *files,
  1354 	     struct razor_entry *top)
  1355 {
  1356 	uint32_t e;
  1357 	int found_file = 0;
  1358 
  1359 	e = top->start;
  1360 	do {
  1361 		if (files[e].start)
  1362 			fix_file_map(map, files, &files[e]);
  1363 		if (map[e])
  1364 			found_file = 1;
  1365 	} while (!(files[e++].flags & RAZOR_ENTRY_LAST));
  1366 
  1367 	if (found_file)
  1368 		map[top - files] = 1;
  1369 	return found_file;
  1370 }
  1371 
  1372 struct merge_directory {
  1373 	uint32_t merged, dir1, dir2;
  1374 };
  1375 
  1376 static void
  1377 merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
  1378 {
  1379 	struct razor_entry *root1, *root2, *mroot, *e1, *e2;
  1380 	struct razor_set *set1, *set2;
  1381 	struct array merge_stack;
  1382 	struct merge_directory *child_md, *end_md;
  1383 	uint32_t *map1, *map2, start, last;
  1384 	int cmp;
  1385 	char *pool1, *pool2;
  1386 
  1387 	set1 = merger->source1.set;
  1388 	set2 = merger->source2.set;
  1389 	map1 = merger->source1.file_map;
  1390 	map2 = merger->source2.file_map;
  1391 	pool1 = set1->string_pool.data;
  1392 	pool2 = set2->string_pool.data;
  1393 	root1 = (struct razor_entry *) set1->files.data;
  1394 	root2 = (struct razor_entry *) set2->files.data;
  1395 
  1396 	array_init(&merge_stack);
  1397 
  1398 	start = merger->set->files.size / sizeof (struct razor_entry);
  1399 	last = 0;
  1400 	e1 = md->dir1 ? root1 + md->dir1 : NULL;
  1401 	e2 = md->dir2 ? root2 + md->dir2 : NULL;
  1402 	while (e1 || e2) {
  1403 		if (!e2 && !map1[e1 - root1]) {
  1404 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1405 				e1 = NULL;
  1406 			continue;
  1407 		}
  1408 		if (!e1 && !map2[e2 - root2]) {
  1409 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1410 				e2 = NULL;
  1411 			continue;
  1412 		}
  1413 		if (e1 && !map1[e1 - root1] &&
  1414 		    e2 && !map1[e2 - root2]) {
  1415 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1416 				e1 = NULL;
  1417 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1418 				e2 = NULL;
  1419 			continue;
  1420 		}
  1421 
  1422 		if (!e1)
  1423 			cmp = 1;
  1424 		else if (!e2)
  1425 			cmp = -1;
  1426 		else {
  1427 			cmp = strcmp (&pool1[e1->name],
  1428 				      &pool2[e2->name]);
  1429 		}
  1430 
  1431 		if (cmp < 0) {
  1432 			if (map1[e1 - root1]) {
  1433 				map1[e1 - root1] = last =
  1434 					add_file(merger, &pool1[e1->name]);
  1435 				if (e1->start) {
  1436 					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
  1437 					child_md->merged = last;
  1438 					child_md->dir1 = e1->start;
  1439 					child_md->dir2 = 0;
  1440 				}
  1441 			}
  1442 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1443 				e1 = NULL;
  1444 		} else if (cmp > 0) {
  1445 			if (map2[e2 - root2]) {
  1446 				map2[e2 - root2] = last =
  1447 					add_file(merger, &pool2[e2->name]);
  1448 				if (e2->start) {
  1449 					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
  1450 					child_md->merged = last;
  1451 					child_md->dir1 = 0;
  1452 					child_md->dir2 = e2->start;
  1453 				}
  1454 			}
  1455 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1456 				e2 = NULL;
  1457 		} else {
  1458 			map1[e1 - root1] = map2[e2- root2] = last =
  1459 				add_file(merger, &pool1[e1->name]);
  1460 			if (e1->start || e2->start) {
  1461 				child_md = array_add(&merge_stack, sizeof (struct merge_directory));
  1462 				child_md->merged = last;
  1463 				child_md->dir1 = e1->start;
  1464 				child_md->dir2 = e2->start;
  1465 			}
  1466 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
  1467 				e1 = NULL;
  1468 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
  1469 				e2 = NULL;
  1470 		}
  1471 	}
  1472 
  1473 	mroot = (struct razor_entry *)merger->set->files.data;
  1474 	if (last) {
  1475 		mroot[last].flags = RAZOR_ENTRY_LAST;
  1476 		mroot[md->merged].start = start;
  1477 	} else
  1478 		mroot[md->merged].start = 0;
  1479 
  1480 	end_md = merge_stack.data + merge_stack.size;
  1481 	for (child_md = merge_stack.data; child_md < end_md; child_md++)
  1482 		merge_one_directory(merger, child_md);
  1483 	array_release(&merge_stack);
  1484 }
  1485 
  1486 static void
  1487 merge_files(struct razor_merger *merger)
  1488 {
  1489 	struct razor_entry *root;
  1490 	struct merge_directory md;
  1491 	uint32_t *map1, *map2;
  1492 
  1493 	map1 = merger->source1.file_map;
  1494 	map2 = merger->source2.file_map;
  1495 
  1496 	md.merged = add_file(merger, "");
  1497 
  1498 	if (merger->source1.set->files.size) {
  1499 		root = (struct razor_entry *) merger->source1.set->files.data;
  1500 		if (root->start)
  1501 			fix_file_map(map1, root, root);
  1502 		md.dir1 = root->start;
  1503 	} else
  1504 		md.dir1 = 0;
  1505 
  1506 	if (merger->source2.set->files.size) {
  1507 		root = (struct razor_entry *) merger->source2.set->files.data;
  1508 		if (root->start)
  1509 			fix_file_map(map2, root, root);
  1510 		md.dir2 = root->start;
  1511 	} else
  1512 		md.dir2 = 0;
  1513 
  1514 	merge_one_directory(merger, &md);
  1515 }
  1516 
  1517 static void
  1518 emit_files(struct list_head *files, struct array *source_pool,
  1519 	   uint32_t *map, struct array *pool)
  1520 {
  1521 	uint32_t r;
  1522 	struct list *p, *q;
  1523 
  1524 	r = pool->size / sizeof *q;
  1525 	p = list_first(files, source_pool);
  1526 	while (p) {
  1527 		q = array_add(pool, sizeof *q);
  1528 		q->data = map[p->data];
  1529 		q->flags = p->flags;
  1530 		p = list_next(p);
  1531 	}
  1532 
  1533 	list_set_ptr(files, r);
  1534 }
  1535 
  1536 /* Rebuild property->packages maps.  We can't just remap these, as a
  1537  * property may have lost or gained a number of packages.  Allocate an
  1538  * array per property and loop through the packages and add them to
  1539  * the arrays for their properties. */
  1540 static void
  1541 rebuild_property_package_lists(struct razor_set *set)
  1542 {
  1543 	struct array *pkgs, *a;
  1544 	struct razor_package *pkg, *pkg_end;
  1545 	struct razor_property *prop, *prop_end;
  1546 	struct list *r;
  1547 	uint32_t *q;
  1548 	int count;
  1549 
  1550 	count = set->properties.size / sizeof (struct razor_property);
  1551 	pkgs = zalloc(count * sizeof *pkgs);
  1552 	pkg_end = set->packages.data + set->packages.size;
  1553 
  1554 	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
  1555 		r = list_first(&pkg->properties, &set->property_pool);
  1556 		while (r) {
  1557 			q = array_add(&pkgs[r->data], sizeof *q);
  1558 			*q = pkg - (struct razor_package *) set->packages.data;
  1559 			r = list_next(r);
  1560 		}
  1561 	}
  1562 
  1563 	prop_end = set->properties.data + set->properties.size;
  1564 	a = pkgs;
  1565 	for (prop = set->properties.data; prop < prop_end; prop++, a++) {
  1566 		list_set_array(&prop->packages, &set->package_pool, a, 0);
  1567 		array_release(a);
  1568 	}
  1569 	free(pkgs);
  1570 }
  1571 
  1572 static void
  1573 rebuild_file_package_lists(struct razor_set *set)
  1574 {
  1575 	struct array *pkgs, *a;
  1576 	struct razor_package *pkg, *pkg_end;
  1577 	struct razor_entry *entry, *entry_end;
  1578 	struct list *r;
  1579 	uint32_t *q;
  1580 	int count;
  1581 
  1582 	count = set->files.size / sizeof (struct razor_entry);
  1583 	pkgs = zalloc(count * sizeof *pkgs);
  1584 	pkg_end = set->packages.data + set->packages.size;
  1585 
  1586 	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
  1587 		r = list_first(&pkg->files, &set->file_pool);
  1588 		while (r) {
  1589 			q = array_add(&pkgs[r->data], sizeof *q);
  1590 			*q = pkg - (struct razor_package *) set->packages.data;
  1591 			r = list_next(r);
  1592 		}
  1593 	}
  1594 
  1595 	entry_end = set->files.data + set->files.size;
  1596 	a = pkgs;
  1597 	for (entry = set->files.data; entry < entry_end; entry++, a++) {
  1598 		list_set_array(&entry->packages, &set->package_pool, a, 0);
  1599 		array_release(a);
  1600 	}
  1601 	free(pkgs);
  1602 }
  1603 
  1604 static struct razor_set *
  1605 razor_merger_finish(struct razor_merger *merger)
  1606 {
  1607 	struct razor_set *result;
  1608 	struct razor_package *p, *pend;
  1609 
  1610 	/* As we built the package list, we filled out a bitvector of
  1611 	 * the properties that are referenced by the packages in the
  1612 	 * new set.  Now we do a parallel loop through the properties
  1613 	 * and emit those marked in the bit vector to the new set.  In
  1614 	 * the process, we update the bit vector to actually map from
  1615 	 * indices in the old property list to indices in the new
  1616 	 * property list for both sets. */
  1617 
  1618 	merge_properties(merger);
  1619 	merge_files(merger);
  1620 
  1621 	/* Now we loop through the packages again and emit the
  1622 	 * property lists, remapped to point to the new properties. */
  1623 
  1624 	pend = merger->set->packages.data + merger->set->packages.size;
  1625 	for (p = merger->set->packages.data; p < pend; p++) {
  1626 		struct source *src;
  1627 
  1628 		if (p->flags & UPSTREAM_SOURCE)
  1629 			src = &merger->source2;
  1630 		else
  1631 			src = &merger->source1;
  1632 
  1633 		emit_properties(&p->properties,
  1634 				&src->set->property_pool,
  1635 				src->property_map,
  1636 				&merger->set->property_pool);
  1637 		emit_files(&p->files,
  1638 			   &src->set->file_pool,
  1639 			   src->file_map,
  1640 			   &merger->set->file_pool);
  1641 		p->flags &= ~UPSTREAM_SOURCE;
  1642 	}
  1643 
  1644 	rebuild_property_package_lists(merger->set);
  1645 	rebuild_file_package_lists(merger->set);
  1646 
  1647 	result = merger->set;
  1648 	hashtable_release(&merger->table);
  1649 	free(merger);
  1650 
  1651 	return result;
  1652 }
  1653 
  1654 static int
  1655 find_packages(struct razor_set *set, int count, const char **package_names,
  1656 	      struct array *package_array,
  1657 	      enum razor_transaction_package_state state)
  1658 {
  1659 	struct razor_package_iterator *pi;
  1660 	struct razor_package *p, *packages;
  1661 	const char *name, *version;
  1662 	struct razor_transaction_package *tp;
  1663 	int i, *found, errors = 0;
  1664 
  1665 	packages = (struct razor_package *) set->packages.data;
  1666 	pi = razor_package_iterator_create(set);
  1667 	found = zalloc(count * sizeof (int));
  1668 
  1669 	while (razor_package_iterator_next(pi, &p, &name, &version)) {
  1670 		for (i = 0; i < count; i++) {
  1671 			if (strcmp(name, package_names[i]) == 0) {
  1672 				found[i] = 1;
  1673 				tp = array_add(package_array, sizeof *tp);
  1674 				memset(tp, 0, sizeof *tp);
  1675 				tp->package = p;
  1676 				tp->name = name;
  1677 				tp->version = version;
  1678 				tp->state = state;
  1679 				break;
  1680 			}
  1681 		}
  1682 	}
  1683 
  1684 	for (i = 0; i < count; i++) {
  1685 		if (!found[i]) {
  1686 			tp = array_add(package_array, sizeof *tp);
  1687 			memset(tp, 0, sizeof *tp);
  1688 			tp->name = strdup(package_names[i]);
  1689 			tp->state = state | RAZOR_PACKAGE_UNAVAILABLE;
  1690 			errors++;
  1691 		}
  1692 	}
  1693 
  1694 	razor_package_iterator_destroy(pi);
  1695 	free(found);
  1696 
  1697 	return errors;
  1698 }
  1699 
  1700 static void
  1701 find_all_packages(struct razor_set *set,
  1702 		  struct razor_set *upstream, struct array *package_array)
  1703 {
  1704 	struct razor_transaction_package *tp;
  1705 	struct razor_package *p, *u, *pend, *uend;
  1706 	char *pool, *upool;
  1707 
  1708 	pend = set->packages.data + set->packages.size;
  1709 	pool = set->string_pool.data;
  1710 	u = upstream->packages.data;
  1711 	uend = upstream->packages.data + upstream->packages.size;
  1712 	upool = upstream->string_pool.data;
  1713 
  1714 	for (p = set->packages.data; p < pend; p++) {
  1715 		while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0)
  1716 			u++;
  1717 		if (strcmp(&pool[p->name], &upool[u->name]) == 0) {
  1718 			tp = array_add(package_array, sizeof *tp);
  1719 			memset(tp, 0, sizeof *tp);
  1720 			tp->name = &upool[u->name];
  1721 			tp->version = &upool[u->version];
  1722 			tp->state = RAZOR_PACKAGE_INSTALL;
  1723 		}
  1724 	}
  1725 }
  1726 
  1727 /* FIXME: wrong, need to compare names, not razor_package* */
  1728 static int
  1729 find_transaction_package(struct array *package_array,
  1730 			 struct razor_package *package)
  1731 {
  1732 	struct razor_transaction_package *tps = package_array->data;
  1733 	int i, tpcount = package_array->size / sizeof *tps;
  1734 
  1735 	for (i = 0; i < tpcount; i++) {
  1736 		if (tps[i].package == package)
  1737 			return i;
  1738 	}
  1739 	return -1;
  1740 }
  1741 
  1742 static int
  1743 provider_satisfies_requirement(struct razor_property *provider,
  1744 			       const char *provider_strings,
  1745 			       struct razor_property *requirement,
  1746 			       const char *requirement_strings)
  1747 {
  1748 	int cmp, len;
  1749 	const char *provided = &provider_strings[provider->version];
  1750 	const char *required = &requirement_strings[requirement->version];
  1751 
  1752 	if (!*required)
  1753 		return 1;
  1754 
  1755 	cmp = versioncmp(provided, required);
  1756 
  1757 	switch (requirement->relation) {
  1758 	case RAZOR_VERSION_LESS:
  1759 		return cmp < 0;
  1760 
  1761 	case RAZOR_VERSION_LESS_OR_EQUAL:
  1762 		if (cmp <= 0)
  1763 			return 1;
  1764 		/* fall through: FIXME, make sure this is correct */
  1765 
  1766 	case RAZOR_VERSION_EQUAL:
  1767 		if (cmp == 0)
  1768 			return 1;
  1769 
  1770 		/* "foo == 1.1" is satisfied by "foo 1.1-2" */
  1771 		len = strlen(required);
  1772 		if (!strncmp(required, provided, len) && provided[len] == '-')
  1773 			return 1;
  1774 		return 0;
  1775 
  1776 	case RAZOR_VERSION_GREATER_OR_EQUAL:
  1777 		return cmp >= 0;
  1778 
  1779 	case RAZOR_VERSION_GREATER:
  1780 		return cmp > 0;
  1781 	}
  1782 
  1783 	/* shouldn't happen */
  1784 	return 0;
  1785 }
  1786 
  1787 static int
  1788 find_property_provider(struct razor_set *set,
  1789 		       struct razor_property *requirement,
  1790 		       const char *requirement_strings)
  1791 {
  1792 	struct razor_property *props = set->properties.data;
  1793 	int p, hi, lo, cmp;
  1794 	char *pool = set->string_pool.data;
  1795 
  1796 	lo = 0;
  1797 	hi = set->properties.size / sizeof *props;
  1798 	while (lo < hi) {
  1799 		p = (lo + hi) / 2;
  1800 		cmp = strcmp(&pool[props[p].name],
  1801 			     &requirement_strings[requirement->name]);
  1802 		if (cmp < 0)
  1803 			lo = p + 1;
  1804 		else if (cmp > 0)
  1805 			hi = p;
  1806 		else
  1807 			break;
  1808 	}
  1809 	if (lo >= hi)
  1810 		return -1;
  1811 
  1812 	/* Seek to the last (ie, highest version number) PROVIDES
  1813 	 * entry for this name.
  1814 	 */
  1815 	if (props[p].type < RAZOR_PROPERTY_PROVIDES) {
  1816 		while (p < hi &&
  1817 		       props[p].type != RAZOR_PROPERTY_PROVIDES &&
  1818 		       props[p + 1].name == props[p].name)
  1819 			p++;
  1820 	} else if (props[p].type > RAZOR_PROPERTY_PROVIDES) {
  1821 		while (p > lo &&
  1822 		       props[p].type != RAZOR_PROPERTY_PROVIDES &&
  1823 		       props[p - 1].name == props[p].name)
  1824 			p--;
  1825 	}
  1826 	while (p < hi &&
  1827 	       props[p + 1].type == RAZOR_PROPERTY_PROVIDES &&
  1828 	       props[p + 1].name == props[p].name)
  1829 		p++;
  1830 
  1831 	if (props[p].type != RAZOR_PROPERTY_PROVIDES)
  1832 		return -1;
  1833 
  1834 	do {
  1835 		if (provider_satisfies_requirement(&props[p], pool,
  1836 						   requirement, requirement_strings))
  1837 			return list_first(&props[p].packages, &set->package_pool)->data;
  1838 
  1839 		p--;
  1840 	} while (p > lo && props[p].name == props[p + 1].name &&
  1841 		 props[p].type == RAZOR_PROPERTY_PROVIDES);
  1842 
  1843 	return -1;
  1844 }
  1845 
  1846 static int
  1847 find_file_provider(struct razor_set *set, const char *filename)
  1848 {
  1849 	struct razor_entry *entry;
  1850 
  1851 	entry = find_entry(set, set->files.data, filename);
  1852 	if (entry)
  1853 		return list_first(&entry->packages, &set->package_pool)->data;
  1854 	else
  1855 		return -1;
  1856 }
  1857 
  1858 static int
  1859 find_provider(struct razor_set *set, struct razor_property *requirement,
  1860 	      const char *requirement_strings)
  1861 {
  1862 	const char *name = &requirement_strings[requirement->name];
  1863 	if (*name == '/')
  1864 		return find_file_provider(set, name);
  1865 	else
  1866 		return find_property_provider(set, requirement, requirement_strings);
  1867 }
  1868 
  1869 static void
  1870 gather_new_requires(struct razor_set *system, struct razor_set *upstream,
  1871 		    struct razor_package *pkg, struct array *new_requires)
  1872 {
  1873 	struct razor_property *uprops = upstream->properties.data, *prop;
  1874 	char *upool = upstream->string_pool.data;
  1875 	struct list *p;
  1876 	uint32_t *new;
  1877 
  1878 	for (p = list_first(&pkg->properties, &upstream->property_pool); p; p = list_next(p)) {
  1879 		prop = &uprops[p->data];
  1880 		if (prop->type != RAZOR_PROPERTY_REQUIRES)
  1881 			continue;
  1882 		if (!strncmp(&upool[prop->name], "rpmlib(", 7))
  1883 			continue;
  1884 
  1885 		if (find_provider(system, prop, upool) == -1) {
  1886 			new = array_add(new_requires, sizeof *new);
  1887 			*new = p->data;
  1888 		}
  1889 	}
  1890 }
  1891 
  1892 static void
  1893 razor_transaction_satisfy_installs(struct razor_transaction *trans,
  1894 				   struct array *package_array,
  1895 				   int start, int end)
  1896 {
  1897 	struct razor_package *pkgs;
  1898 	struct razor_transaction_package *packages, *tp;
  1899 	int p, provider, already;
  1900 	uint32_t *new, *new_end;
  1901 	struct razor_property *props, *prop_end;
  1902 	struct array new_requires;
  1903 	char *pool;
  1904 
  1905 	pkgs = trans->upstream->packages.data;
  1906 	props = trans->upstream->properties.data;
  1907 	prop_end = trans->upstream->properties.data + trans->upstream->properties.size;
  1908 	pool = trans->upstream->string_pool.data;
  1909 
  1910 	packages = package_array->data;
  1911 	for (p = start; p < end; p++) {
  1912 		if (packages[p].state != RAZOR_PACKAGE_INSTALL)
  1913 			continue;
  1914 
  1915 		array_init(&new_requires);
  1916 		gather_new_requires(trans->system, trans->upstream,
  1917 				    packages[p].package, &new_requires);
  1918 
  1919 		new_end = new_requires.data + new_requires.size;
  1920 		for (new = new_requires.data; new < new_end; new++) {
  1921 			provider = find_provider(trans->upstream,
  1922 						 &props[*new], pool);
  1923 			already = find_transaction_package(package_array,
  1924 							   &pkgs[provider]);
  1925 			if (already != -1 &&
  1926 			    (packages[already].state & RAZOR_PACKAGE_INSTALL))
  1927 				continue;
  1928 
  1929 			tp = array_add(package_array, sizeof *tp);
  1930 			memset(tp, 0, sizeof *tp);
  1931 			tp->req_package = packages[p].name;
  1932 			tp->req_property = &pool[props[*new].name];
  1933 			tp->req_relation = props[*new].relation;
  1934 			tp->req_version = &pool[props[*new].version];
  1935 
  1936 			if (provider != -1) {
  1937 				tp->package = &pkgs[provider];
  1938 				tp->name = &pool[tp->package->name];
  1939 				tp->version = &pool[tp->package->version];
  1940 				if (already != -1) {
  1941 					tp->state = RAZOR_PACKAGE_INSTALL_BLOCKED;
  1942 					trans->errors++;
  1943 				} else
  1944 					tp->state = RAZOR_PACKAGE_INSTALL;
  1945 			} else {
  1946 				tp->state = RAZOR_PACKAGE_INSTALL_UNSATISFIABLE;
  1947 				trans->errors++;
  1948 			}
  1949 
  1950 			packages = package_array->data;
  1951 		}
  1952 		array_release(&new_requires);
  1953 	}
  1954 }
  1955 
  1956 /* Look through pkg's PROVIDES, and for each one that no other package
  1957  * provides, add its property index to lost_provides.
  1958  */
  1959 static void
  1960 gather_lost_provides(struct razor_set *set, struct razor_package *pkg,
  1961 		     struct array *lost_provides)
  1962 {
  1963 	struct razor_property *props = set->properties.data, *prop;
  1964 	struct list *p, *providers;
  1965 	uint32_t *lost;
  1966 
  1967 	for (p = list_first(&pkg->properties, &set->property_pool); p; p = list_next(p)) {
  1968 		prop = &props[p->data];
  1969 		if (prop->type != RAZOR_PROPERTY_PROVIDES)
  1970 			continue;
  1971 
  1972 		providers = list_first(&prop->packages, &set->package_pool);
  1973 		if (providers && !list_next(providers)) {
  1974 			lost = array_add(lost_provides, sizeof *lost);
  1975 			*lost = p->data;
  1976 		}
  1977 	}
  1978 }
  1979 
  1980 static void
  1981 lose_requirement(struct razor_transaction *trans, struct array *package_array,
  1982 		 const char *req_package, struct razor_property *req,
  1983 		 struct razor_property *lost_provider,
  1984 		 struct razor_property *first_provider)
  1985 {
  1986 	struct razor_property *provider, *prop_end;
  1987 	struct razor_package *pkgs;
  1988 	char *pool = trans->system->string_pool.data;
  1989 	struct list *p;
  1990 	struct razor_transaction_package *tp, *packages;;
  1991 	int already;
  1992 
  1993 	pkgs = trans->system->packages.data;
  1994 	prop_end = trans->system->properties.data + trans->system->properties.size;
  1995 
  1996 	/* See if any other provider satisfies req */
  1997 	for (provider = first_provider;
  1998 	     provider < prop_end && provider->type == RAZOR_PROPERTY_PROVIDES && provider->name == lost_provider->name;
  1999 	     provider++) {
  2000 		if (provider == lost_provider)
  2001 			continue;
  2002 
  2003 		if (provider_satisfies_requirement(provider, pool, req, pool))
  2004 			return;
  2005 	}
  2006 
  2007 	/* Remove each of the packages requiring req */
  2008 	for (p = list_first(&req->packages, &trans->system->package_pool); p; p = list_next(p)) {
  2009 		packages = package_array->data;
  2010 		already = find_transaction_package(package_array, &pkgs[p->data]);
  2011 		if (already != -1 &&
  2012 		    (packages[already].state & RAZOR_PACKAGE_REMOVE))
  2013 			continue;
  2014 
  2015 		tp = array_add(package_array, sizeof *tp);
  2016 		memset(tp, 0, sizeof *tp);
  2017 		tp->package = &pkgs[p->data];
  2018 		tp->name = &pool[tp->package->name];
  2019 		tp->version = &pool[tp->package->version];
  2020 		tp->req_package = req_package;
  2021 		tp->req_property = &pool[req->name];
  2022 		tp->req_relation = req->relation;
  2023 		tp->req_version = &pool[req->version];
  2024 		if (already != -1) {
  2025 			tp->state = RAZOR_PACKAGE_REMOVE_BLOCKED;
  2026 			trans->errors++;
  2027 		} else
  2028 			tp->state = RAZOR_PACKAGE_REMOVE;
  2029 	}
  2030 }
  2031 
  2032 static void
  2033 razor_transaction_satisfy_removes(struct razor_transaction *trans,
  2034 				  struct array *package_array,
  2035 				  int start, int end)
  2036 {
  2037 	struct razor_transaction_package *packages;
  2038 	struct razor_package *pkgs;
  2039 	int pkg_count, r;
  2040 	uint32_t *lost, *lost_end;
  2041 	struct razor_property *props, *prop_end, *req, *first_provider;
  2042 	struct array lost_provides;
  2043 	const char *req_package;
  2044 
  2045 	pkgs = trans->system->packages.data;
  2046 	pkg_count = trans->system->packages.size / sizeof (struct razor_package);
  2047 	props = trans->system->properties.data;
  2048 	prop_end = trans->system->properties.data + trans->system->properties.size;
  2049 
  2050 	for (r = start; r < end; r++) {
  2051 		packages = package_array->data;
  2052 		if (packages[r].state != RAZOR_PACKAGE_REMOVE)
  2053 			continue;
  2054 
  2055 		array_init(&lost_provides);
  2056 		req_package = packages[r].name;
  2057 		gather_lost_provides(trans->system, packages[r].package,
  2058 				     &lost_provides);
  2059 
  2060 		lost_end = lost_provides.data + lost_provides.size;
  2061 		for (lost = lost_provides.data; lost < lost_end; lost++) {
  2062 			/* Requires FOO will appear before Provides FOO */
  2063 			for (req = &props[*lost]; req > props && req->name == props[*lost].name && req->type != RAZOR_PROPERTY_REQUIRES; req--)
  2064 				;
  2065 			first_provider = req + 1;
  2066 
  2067 			while (req > props && req->name == props[*lost].name) {
  2068 				lose_requirement(trans, package_array,
  2069 						 req_package, req,
  2070 						 &props[*lost], first_provider);
  2071 				req--;
  2072 			}
  2073 		}
  2074 		array_release(&lost_provides);
  2075 	}
  2076 }
  2077 
  2078 /* The diff order matters.  We should sort the packages so that a
  2079  * REMOVE of a package comes before the INSTALL, and so that all
  2080  * requires for a package have been installed before the package.
  2081  **/
  2082 
  2083 void
  2084 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
  2085 	       razor_package_callback_t callback, void *data)
  2086 {
  2087 	struct razor_package_iterator *pi1, *pi2;
  2088 	struct razor_package *p1, *p2;
  2089 	const char *name1, *name2, *version1, *version2;
  2090 	int res;
  2091 
  2092 	pi1 = razor_package_iterator_create(set);
  2093 	pi2 = razor_package_iterator_create(upstream);
  2094 
  2095 	razor_package_iterator_next(pi1, &p1, &name1, &version1);
  2096 	razor_package_iterator_next(pi2, &p2, &name2, &version2);
  2097 
  2098 	while (p1 || p2) {
  2099 		if (p1 && p2) {
  2100 			res = strcmp(name1, name2);
  2101 			if (res == 0)
  2102 				res = versioncmp(version1, version2);
  2103 		} else {
  2104 			res = 0;
  2105 		}
  2106 
  2107 		if (p2 == NULL || res < 0)
  2108 			callback(name1, version1, NULL, data);
  2109 		else if (p1 == NULL || res > 0)
  2110 			callback(name2, NULL, version2, data);
  2111 
  2112 		if (p1 != NULL && res <= 0)
  2113 			razor_package_iterator_next(pi1, &p1,
  2114 						    &name1, &version1);
  2115 		if (p2 != NULL && res >= 0)
  2116 			razor_package_iterator_next(pi2, &p2,
  2117 						    &name2, &version2);
  2118 	}
  2119 
  2120 	razor_package_iterator_destroy(pi1);
  2121 	razor_package_iterator_destroy(pi2);
  2122 }
  2123 
  2124 struct razor_transaction *
  2125 razor_transaction_create(struct razor_set *system, struct razor_set *upstream,
  2126 			 int update_count, const char **update_packages,
  2127 			 int remove_count, const char **remove_packages)
  2128 {
  2129 	struct razor_transaction *trans;
  2130 	struct array packages;
  2131 	int start, end;
  2132 
  2133 	trans = zalloc(sizeof *trans);
  2134 	trans->system = system;
  2135 	trans->upstream = upstream ? upstream : razor_set_create();
  2136 	array_init(&packages);
  2137 
  2138 	/* Find initial upstream packages to be installed */
  2139 	if (update_count > 0) {
  2140 		trans->errors +=
  2141 			find_packages(upstream, update_count, update_packages,
  2142 				      &packages, RAZOR_PACKAGE_INSTALL);
  2143 	} else if (remove_count == 0)
  2144 		find_all_packages(system, upstream, &packages);
  2145 
  2146 	/* Find initial installed packages to remove. */
  2147 	if (remove_count > 0) {
  2148 		trans->errors +=
  2149 			find_packages(system, remove_count, remove_packages,
  2150 				      &packages, RAZOR_PACKAGE_REMOVE);
  2151 	}
  2152 
  2153 	start = 0;
  2154 	end = packages.size / sizeof (struct razor_transaction_package);
  2155 
  2156 	while (!trans->errors && start != end) {
  2157 		if (upstream)
  2158 			razor_transaction_satisfy_installs(trans, &packages, start, end);
  2159 		razor_transaction_satisfy_removes(trans, &packages, start, end);
  2160 
  2161 		start = end;
  2162 		end = packages.size / sizeof (struct razor_transaction_package);
  2163 	}
  2164 
  2165 	trans->packages = packages.data;
  2166 	trans->package_count = packages.size / sizeof (struct razor_transaction_package);
  2167 	return trans;
  2168 }
  2169 
  2170 const char * const razor_version_relations[] = {
  2171 	/* same order as enum razor_version_relation */
  2172 	"<", "<=", "=", ">=", ">"
  2173 };
  2174 
  2175 void
  2176 razor_transaction_describe(struct razor_transaction *trans)
  2177 {
  2178 	struct razor_transaction_package *p, *pend, *tps;
  2179 	int errors_only = 0;
  2180 
  2181 	tps = trans->packages;
  2182 	pend = trans->packages + trans->package_count;
  2183 	for (p = trans->packages; p < pend; p++) {
  2184 		switch (p->state) {
  2185 		case RAZOR_PACKAGE_INSTALL:
  2186 			if (errors_only)
  2187 				break;
  2188 
  2189 			printf ("Installing %s %s", p->name, p->version);
  2190 			if (p->req_package) {
  2191 				printf (" for %s", p->req_package);
  2192 				if (*p->req_version) {
  2193 					printf (", which requires %s %s %s",
  2194 						p->req_property,
  2195 						razor_version_relations[p->req_relation],
  2196 						p->req_version);
  2197 				} else if (strcmp(p->req_property, p->name) != 0) {
  2198 					printf (", which requires %s",
  2199 						p->req_property);
  2200 				}
  2201 			}
  2202 			printf("\n");
  2203 			break;
  2204 
  2205 		case RAZOR_PACKAGE_INSTALL_UNAVAILABLE:
  2206 			if (*p->req_version && strcmp(p->req_property, p->name) == 0) {
  2207 				printf ("Can't find %s %s %s, which is required by %s",
  2208 					p->name,
  2209 					razor_version_relations[p->req_relation],
  2210 					p->req_version,
  2211 					p->req_package);
  2212 			} else {
  2213 				printf ("Can't find %s", p->name);
  2214 				if (*p->version)
  2215 					printf (" %s", p->version);
  2216 				
  2217 				if (p->req_package) {
  2218 					printf ("  which is required by %s",
  2219 						p->req_package);
  2220 					if (strcmp(p->req_property, p->name) != 0)
  2221 						printf (" for %s", p->req_property);
  2222 				}
  2223 			}
  2224 			printf("\n");
  2225 			errors_only = 1;
  2226 			break;
  2227 
  2228 		case RAZOR_PACKAGE_INSTALL_BLOCKED:
  2229 			printf ("Cannot install %s, which is already marked for removal but is required by %s\n", p->name, p->req_package);
  2230 			errors_only = 1;
  2231 			break;
  2232 
  2233 		case RAZOR_PACKAGE_INSTALL_UNSATISFIABLE:
  2234 			printf ("Cannot find package for %s", p->req_property);
  2235 			if (*p->req_version) {
  2236 				printf (" %s %s",
  2237 					razor_version_relations[p->req_relation],
  2238 					p->req_version);
  2239 			}
  2240 			printf (" which is required by %s\n",
  2241 				p->req_package);
  2242 			errors_only = 1;
  2243 			break;
  2244 
  2245 		case RAZOR_PACKAGE_REMOVE:
  2246 			if (errors_only)
  2247 				break;
  2248 			printf ("Removing %s %s", p->name, p->version);
  2249 			if (p->req_package) {
  2250 				printf (" which required %s", p->req_package);
  2251 				if (strcmp(p->req_property, p->req_package) != 0)
  2252 					printf (" for %s", p->req_property);
  2253 			}
  2254 			printf("\n");
  2255 			break;
  2256 
  2257 		case RAZOR_PACKAGE_REMOVE_NOT_INSTALLED:
  2258 			printf ("Package %s is not installed\n", p->name);
  2259 			errors_only = 1;
  2260 			break;
  2261 
  2262 		case RAZOR_PACKAGE_REMOVE_BLOCKED:
  2263 			printf ("Cannot remove %s, which is marked for installation but requires %s\n", p->name, p->req_package);
  2264 			errors_only = 1;
  2265 			break;
  2266 
  2267 		default:
  2268 			/* Shouldn't actually happen */
  2269 			break;
  2270 		}
  2271 	}
  2272 }
  2273 
  2274 struct razor_set *
  2275 razor_transaction_run(struct razor_transaction *trans)
  2276 {
  2277 	struct array install_packages, remove_packages;
  2278 	struct razor_merger *merger;
  2279 	struct razor_package *pkg, *i, *iend, *r, *rend, *s, *send;
  2280 	struct source *source1, *source2;
  2281 	char *spool, *ipool, *rpool;
  2282 	uint32_t *map;
  2283 	int p, cmp;
  2284 
  2285 	/* FIXME */
  2286 	if (trans->errors)
  2287 		return NULL;
  2288 
  2289 	/* Sort the transaction packages into two arrays */
  2290 	array_init(&install_packages);
  2291 	array_init(&remove_packages);
  2292 	for (p = 0; p < trans->package_count; p++) {
  2293 		if (trans->packages[p].state & RAZOR_PACKAGE_INSTALL)
  2294 			pkg = array_add(&install_packages, sizeof *pkg);
  2295 		else
  2296 			pkg = array_add(&remove_packages, sizeof *pkg);
  2297 		*pkg = *trans->packages[p].package;
  2298 	}
  2299 	map = qsort_with_data(install_packages.data,
  2300 			      install_packages.size / sizeof *pkg,
  2301 			      sizeof *pkg,
  2302 			      compare_packages,
  2303 			      trans->upstream);
  2304 	free(map);
  2305 	map = qsort_with_data(remove_packages.data,
  2306 			      remove_packages.size / sizeof *pkg,
  2307 			      sizeof *pkg,
  2308 			      compare_packages,
  2309 			      trans->system);
  2310 	free(map);
  2311 
  2312 	merger = razor_merger_create(trans->system, trans->upstream);
  2313 
  2314 	source1 = &merger->source1;
  2315 	source2 = &merger->source2;
  2316 
  2317 	i = install_packages.data;
  2318 	iend = install_packages.data + install_packages.size;
  2319 	ipool = trans->upstream->string_pool.data;
  2320 
  2321 	r = remove_packages.data;
  2322 	rend = remove_packages.data + remove_packages.size;
  2323 	rpool = trans->system->string_pool.data;
  2324 
  2325 	s = trans->system->packages.data;
  2326 	send = trans->system->packages.data + trans->system->packages.size;
  2327 	spool = trans->system->string_pool.data;
  2328 
  2329 	while (s < send || i < iend) {
  2330 		/* Check if s is being removed */
  2331 		if (s < send && r < rend &&
  2332 		    s->name == r->name && s->version && r->version) {
  2333 			s++;
  2334 			r++;
  2335 			continue;
  2336 		}
  2337 
  2338 		if (s < send && i < iend)
  2339 			cmp = strcmp(&spool[s->name], &ipool[i->name]);
  2340 		else if (s < send)
  2341 			cmp = -1;
  2342 		else
  2343 			cmp = 1;
  2344 		if (cmp < 0) {
  2345 			add_package(merger, s, source1, 0);
  2346 			s++;
  2347 		} else if (cmp == 0) {
  2348 			add_package(merger, i, source2, UPSTREAM_SOURCE);
  2349 			s++;
  2350 			i++;
  2351 		} else {
  2352 			add_package(merger, i, source2, UPSTREAM_SOURCE);
  2353 			i++;
  2354 		}
  2355 	}
  2356 
  2357 	array_release(&install_packages);
  2358 	array_release(&remove_packages);
  2359 
  2360 	return razor_merger_finish(merger);
  2361 }
  2362 
  2363 void
  2364 razor_transaction_destroy(struct razor_transaction *trans)
  2365 {
  2366 	int p;
  2367 
  2368 	for (p = 0; p < trans->package_count; p++) {
  2369 		if (!trans->packages[p].req_package &&
  2370 		    (trans->packages[p].state == RAZOR_PACKAGE_INSTALL_UNAVAILABLE ||
  2371 		     trans->packages[p].state == RAZOR_PACKAGE_REMOVE_NOT_INSTALLED))
  2372 			free((char *)trans->packages[p].name);
  2373 	}
  2374 	free(trans);
  2375 
  2376 	/* FIXME: free upstream if it was created as an empty set */
  2377 }