librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Fri Jul 03 18:02:33 2009 +0100 (2009-07-03)
changeset 372 6e93e5485947
parent 369 f8c27fe9fe63
child 373 fda83d91e600
permissions -rw-r--r--
Support RPM_INSTALL_PREFIX{n} during uninstall
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #define _GNU_SOURCE
    22 
    23 #include "config.h"
    24 
    25 #include <stdlib.h>
    26 #include <stddef.h>
    27 #include <stdint.h>
    28 #include <stdio.h>
    29 #include <stdarg.h>
    30 #include <string.h>
    31 #include <sys/types.h>
    32 #include <sys/stat.h>
    33 #include <unistd.h>
    34 #include <fcntl.h>
    35 #include <errno.h>
    36 #include <ctype.h>
    37 #include <fnmatch.h>
    38 #include <limits.h>
    39 #include <assert.h>
    40 
    41 #include "razor-internal.h"
    42 #include "razor.h"
    43 
    44 #ifndef O_BINARY
    45 #define O_BINARY	0
    46 #endif
    47 
    48 void *
    49 zalloc(size_t size)
    50 {
    51 	void *p;
    52 
    53 	p = malloc(size);
    54 	memset(p, 0, size);
    55 
    56 	return p;
    57 }
    58 
    59 struct razor_set_section_index {
    60 	const char *name;
    61 	uint32_t offset;
    62 };
    63 
    64 struct razor_set_section_index razor_sections[] = {
    65 	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
    66 	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
    67 	{ RAZOR_PROPERTIES,	offsetof(struct razor_set, properties) },
    68 	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
    69 	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
    70 	{ RAZOR_PREFIX_POOL,	offsetof(struct razor_set, prefix_pool) },
    71 };
    72 
    73 struct razor_set_section_index razor_files_sections[] = {
    74 	{ RAZOR_FILES,			offsetof(struct razor_set, files) },
    75 	{ RAZOR_FILE_POOL,		offsetof(struct razor_set, file_pool) },
    76 	{ RAZOR_FILE_STRING_POOL,	offsetof(struct razor_set, file_string_pool) },
    77 };
    78 
    79 struct razor_set_section_index razor_details_sections[] = {
    80 	{ RAZOR_DETAILS_STRING_POOL,	offsetof(struct razor_set, details_string_pool) },
    81 };
    82 
    83 RAZOR_EXPORT struct razor_set *
    84 razor_set_create_without_root(void)
    85 {
    86 	struct razor_set *set;
    87 	char *empty;
    88 
    89 	set = zalloc(sizeof *set);
    90 
    91 	empty = array_add(&set->string_pool, 1);
    92 	*empty = '\0';
    93 
    94 	return set;
    95 }
    96 
    97 RAZOR_EXPORT struct razor_set *
    98 razor_set_create(void)
    99 {
   100 	struct razor_set *set;
   101 	struct razor_entry *e;
   102 
   103 	set = razor_set_create_without_root();
   104 
   105 	e = array_add(&set->files, sizeof *e);
   106 	e->name = 0;
   107 	e->flags = RAZOR_ENTRY_LAST;
   108 	e->start = 0;
   109 	list_set_empty(&e->packages);
   110 
   111 	return set;
   112 }
   113 
   114 static int
   115 razor_set_bind_sections(struct razor_set *set,
   116 			struct razor_set_header **header,
   117 			size_t *header_size,
   118 			struct razor_set_section_index section_index[],
   119 			int section_index_size,
   120 			const char *filename)
   121 {
   122 	struct razor_set_section *s, *sections;
   123 	struct array *array;
   124 	const char *pool;
   125 	int i;
   126 
   127 	*header = razor_file_get_contents(filename, header_size);
   128 	if (!*header)
   129 		return -1;
   130 
   131 	sections = (void *) *header + sizeof **header;
   132 	pool = (void *) sections + (*header)->num_sections * sizeof *sections;
   133 
   134 	for (i = 0; i < (*header)->num_sections; i++) {
   135 		int j;
   136 		s = sections + i;
   137 		for (j = 0; j < section_index_size; j++)
   138 			if (!strcmp(section_index[j].name,
   139 				    &pool[s->name]))
   140 				break;
   141 		if (j == section_index_size)
   142 			continue;
   143 		array = (void *) set + section_index[j].offset;
   144 		array->data = (void *) *header + s->offset;
   145 		array->size = s->size;
   146 		array->alloc = s->size;
   147 	}
   148 
   149 	return 0;
   150 }
   151 
   152 RAZOR_EXPORT struct razor_set *
   153 razor_set_open(const char *filename)
   154 {
   155 	struct razor_set *set;
   156 
   157 	set = zalloc(sizeof *set);
   158 	if (razor_set_bind_sections(set, &set->header, &set->header_size,
   159 				    razor_sections, ARRAY_SIZE(razor_sections),
   160 				    filename)){
   161 		free(set);
   162 		return NULL;
   163 	}
   164 	return set;
   165 }
   166 
   167 RAZOR_EXPORT int
   168 razor_set_open_details(struct razor_set *set, const char *filename)
   169 {
   170 	return razor_set_bind_sections(set, &set->details_header,
   171 				       &set->details_header_size,
   172 				       razor_details_sections,
   173 				       ARRAY_SIZE(razor_details_sections),
   174 				       filename);
   175 }
   176 
   177 RAZOR_EXPORT int
   178 razor_set_open_files(struct razor_set *set, const char *filename)
   179 {
   180 	return razor_set_bind_sections(set, &set->files_header,
   181 				       &set->files_header_size,
   182 				       razor_files_sections,
   183 				       ARRAY_SIZE(razor_files_sections),
   184 				       filename);
   185 }
   186 
   187 RAZOR_EXPORT void
   188 razor_set_destroy(struct razor_set *set)
   189 {
   190 	struct array *a;
   191 	int i;
   192 
   193 	assert (set != NULL);
   194 
   195 	if (set->header) {
   196 		razor_file_free_contents(set->header, set->header_size);
   197 	} else {
   198 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   199 			a = (void *) set + razor_sections[i].offset;
   200 			free(a->data);
   201 		}
   202 	}
   203 
   204 	if (set->details_header) {
   205 		razor_file_free_contents(set->details_header,
   206 			set->details_header_size);
   207 	} else {
   208 		for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
   209 			a = (void *) set + razor_details_sections[i].offset;
   210 			free(a->data);
   211 		}
   212 	}
   213 
   214 	if (set->files_header) {
   215 		razor_file_free_contents(set->files_header,
   216 			set->files_header_size);
   217 	} else {
   218 		for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
   219 			a = (void *) set + razor_files_sections[i].offset;
   220 			free(a->data);
   221 		}
   222 	}
   223 
   224 	free(set);
   225 }
   226 
   227 static int
   228 razor_set_write_sections_to_fd(struct razor_set *set, int fd,
   229 			       struct razor_set_section_index *sections,
   230 			       size_t array_size)
   231 {
   232 	struct razor_set_header header;
   233 	struct razor_set_section *out_sections =
   234 		malloc(array_size * sizeof *out_sections);
   235 	struct hashtable table;
   236 	struct array *a, pool;
   237 	uint32_t offset;
   238 	int i;
   239 
   240 	header.magic = RAZOR_MAGIC;
   241 	header.version = RAZOR_VERSION;
   242 	header.num_sections = array_size;
   243 	offset = sizeof header + array_size * sizeof *out_sections;
   244 
   245 	array_init(&pool);
   246 	hashtable_init(&table, &pool);
   247 
   248 	for (i = 0; i < array_size; i++)
   249 		out_sections[i].name =
   250 			hashtable_tokenize(&table, sections[i].name);
   251 
   252 	offset += pool.size;
   253 
   254 	for (i = 0; i < array_size; i++) {
   255 		a = (void *) set + sections[i].offset;
   256 		out_sections[i].offset = offset;
   257 		out_sections[i].size = a->size;
   258 		offset += a->size;
   259 	}
   260 
   261 	razor_write(fd, &header, sizeof header);
   262 	razor_write(fd, out_sections, array_size * sizeof *out_sections);
   263 	razor_write(fd, pool.data, pool.size);
   264 
   265 	for (i = 0; i < array_size; i++) {
   266 		a = (void *) set + sections[i].offset;
   267 		razor_write(fd, a->data, a->size);
   268 	}
   269 
   270 	free(out_sections);
   271 
   272 	return 0;
   273 }
   274 
   275 RAZOR_EXPORT int
   276 razor_set_write_to_fd(struct razor_set *set, int fd,
   277 		      enum razor_repo_file_type type)
   278 {
   279 	switch (type) {
   280 	case RAZOR_REPO_FILE_MAIN:
   281 		return razor_set_write_sections_to_fd(set, fd,
   282 						      razor_sections,
   283 						      ARRAY_SIZE(razor_sections));
   284 
   285 	case RAZOR_REPO_FILE_DETAILS:
   286 		return razor_set_write_sections_to_fd(set, fd,
   287 						      razor_details_sections,
   288 						      ARRAY_SIZE(razor_details_sections));
   289 	case RAZOR_REPO_FILE_FILES:
   290 		return razor_set_write_sections_to_fd(set, fd,
   291 						      razor_files_sections,
   292 						      ARRAY_SIZE(razor_files_sections));
   293 	default:
   294 		return -1;
   295 	}
   296 }
   297 
   298 RAZOR_EXPORT int
   299 razor_set_write(struct razor_set *set, const char *filename,
   300 		enum razor_repo_file_type type)
   301 {
   302 	int fd, status;
   303 
   304 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
   305 	if (fd < 0)
   306 		return -1;
   307 
   308 	status = razor_set_write_to_fd(set, fd, type);
   309 	if (status) {
   310 	    close(fd);
   311 	    return status;
   312 	}
   313 
   314 	return close(fd);
   315 }
   316 
   317 RAZOR_EXPORT void
   318 razor_build_evr(char *evr_buf, int size, const char *epoch,
   319 		const char *version, const char *release)
   320 {
   321 	int len;
   322 
   323 	if (!version || !*version) {
   324 		*evr_buf = '\0';
   325 		return;
   326 	}
   327 
   328 	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
   329 		len = snprintf(evr_buf, size, "%s:", epoch);
   330 		evr_buf += len;
   331 		size -= len;
   332 	}
   333 	len = snprintf(evr_buf, size, "%s", version);
   334 	evr_buf += len;
   335 	size -= len;
   336 	if (release && *release)
   337 		snprintf(evr_buf, size, "-%s", release);
   338 }
   339 
   340 RAZOR_EXPORT int
   341 razor_versioncmp(const char *s1, const char *s2)
   342 {
   343 	const char *p1, *p2;
   344 	long n1, n2;
   345 	int res;
   346 
   347 	assert (s1 != NULL);
   348 	assert (s2 != NULL);
   349 
   350 	n1 = strtol(s1, (char **) &p1, 10);
   351 	n2 = strtol(s2, (char **) &p2, 10);
   352 
   353 	/* Epoch; if one but not the other has an epoch set, default
   354 	 * the epoch-less version to 0. */
   355 	res = (*p1 == ':') - (*p2 == ':');
   356 	if (res < 0) {
   357 		n1 = 0;
   358 		p1 = s1;
   359 		p2++;
   360 	} else if (res > 0) {
   361 		p1++;
   362 		n2 = 0;
   363 		p2 = s2;
   364 	}
   365 
   366 	if (n1 != n2)
   367 		return n1 - n2;
   368 	while (*p1 && *p2) {
   369 		if (*p1 != *p2)
   370 			return *p1 - *p2;
   371 		p1++;
   372 		p2++;
   373 		if (isdigit(*p1) && isdigit(*p2))
   374 			return razor_versioncmp(p1, p2);
   375 	}
   376 
   377 	return *p1 - *p2;
   378 }
   379 
   380 static const char *
   381 razor_package_get_details_string(struct razor_set *set,
   382 				 struct razor_package *package,
   383 				 enum razor_detail_type type)
   384 {
   385 	const char *pool;
   386 
   387 	switch (type) {
   388 	case RAZOR_DETAIL_NAME:
   389 		pool = set->string_pool.data;
   390 		return &pool[package->name];
   391 
   392 	case RAZOR_DETAIL_VERSION:
   393 		pool = set->string_pool.data;
   394 		return &pool[package->version];
   395 
   396 	case RAZOR_DETAIL_ARCH:
   397 		pool = set->string_pool.data;
   398 		return &pool[package->arch];
   399 
   400 	case RAZOR_DETAIL_SUMMARY:
   401 		pool = set->details_string_pool.data;
   402 		return &pool[package->summary];
   403 
   404 	case RAZOR_DETAIL_DESCRIPTION:
   405 		pool = set->details_string_pool.data;
   406 		return &pool[package->description];
   407 
   408 	case RAZOR_DETAIL_URL:
   409 		pool = set->details_string_pool.data;
   410 		return &pool[package->url];
   411 
   412 	case RAZOR_DETAIL_LICENSE:
   413 		pool = set->details_string_pool.data;
   414 		return &pool[package->license];
   415 
   416 	case RAZOR_DETAIL_PREUNPROG:
   417 		pool = set->string_pool.data;
   418 		return &pool[package->preun.program];
   419 
   420 	case RAZOR_DETAIL_PREUN:
   421 		pool = set->string_pool.data;
   422 		return &pool[package->preun.body];
   423 
   424 	case RAZOR_DETAIL_POSTUNPROG:
   425 		pool = set->string_pool.data;
   426 		return &pool[package->postun.program];
   427 
   428 	case RAZOR_DETAIL_POSTUN:
   429 		pool = set->string_pool.data;
   430 		return &pool[package->postun.body];
   431 
   432 	default:
   433 		fprintf(stderr, "type %u not found\n", type);
   434 		return NULL;
   435 	}
   436 }
   437 
   438 static const char *const *
   439 razor_package_get_details_array(struct razor_set *set,
   440 				struct razor_package *package,
   441 				enum razor_detail_type type)
   442 {
   443 	switch (type) {
   444 	case RAZOR_DETAIL_PREFIXES:
   445 		/* We don't track prefixes in packages. Install prefixes
   446 		 * are tracked, but we don't provide an API to get them.
   447 		 */
   448 		return NULL;
   449 
   450 	default:
   451 		fprintf(stderr, "type %u not found\n", type);
   452 		return NULL;
   453 	}
   454 }
   455 
   456 /**
   457  * razor_package_get_details_varg:
   458  * @set: a %razor_set
   459  * @package: a %razor_package
   460  * @args: a va_list of arguments to set
   461  **/
   462 void
   463 razor_package_get_details_varg(struct razor_set *set,
   464 			       struct razor_package *package,
   465 			       va_list args)
   466 {
   467 	int i;
   468 	enum razor_detail_type type;
   469 	const char **string;
   470 	const char *const **array;
   471 
   472 	for (i = 0;; i += 2) {
   473 		type = va_arg(args, enum razor_detail_type);
   474 		if (type == RAZOR_DETAIL_LAST)
   475 			break;
   476 		if (type == RAZOR_DETAIL_PREFIXES) {
   477 			array = va_arg(args, const char *const **);
   478 			*array = razor_package_get_details_array(set, package,
   479 								 type);
   480 		} else {
   481 			string = va_arg(args, const char **);
   482 			*string = razor_package_get_details_string(set, package,
   483 								   type);
   484 		}
   485 	}
   486 
   487 }
   488 
   489 /**
   490  * razor_package_get_details:
   491  * @set: a %razor_set
   492  * @package: a %razor_package
   493  *
   494  * Gets details about a package using a varg interface
   495  * The vararg must be terminated with %RAZOR_DETAIL_LAST.
   496  *
   497  * Example: razor_package_get_details (set, package,
   498  *				       RAZOR_DETAIL_URL, &url,
   499  *				       RAZOR_DETAIL_LAST);
   500  **/
   501 RAZOR_EXPORT void
   502 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
   503 {
   504 	va_list args;
   505 
   506 	assert (set != NULL);
   507 	assert (package != NULL);
   508 
   509 	va_start(args, NULL);
   510 	razor_package_get_details_varg (set, package, args);
   511 	va_end (args);
   512 }
   513 
   514 /**
   515  * razor_package_remove:
   516  * @set: a %razor_set
   517  * @package: a %razor_package
   518  * @root: the root into which the package is currently installed
   519  *
   520  * Removes an installed package.
   521  **/
   522 RAZOR_EXPORT int
   523 razor_package_remove(struct razor_set *set, struct razor_package *package,
   524 		     const char *root)
   525 {
   526 	struct razor_file_iterator *fi;
   527 	struct razor_package_iterator *pi;
   528 	struct razor_package *p;
   529 	char buffer[PATH_MAX];
   530 	const char *name, *program, *script;
   531 	int retval = 0, i, count;
   532 	struct environment env;
   533 	struct list *link;
   534 	const char *prefix;
   535 
   536 	razor_package_get_details(set, package,
   537 				  RAZOR_DETAIL_PREUNPROG, &program,
   538 				  RAZOR_DETAIL_PREUN, &script,
   539 				  RAZOR_DETAIL_LAST);
   540 
   541 	if (razor_run_script(root, RAZOR_PROPERTY_PREUN, program, script))
   542 		return -1;
   543 
   544 	fi = razor_file_iterator_create(set, package);
   545 
   546 	while (!retval && razor_file_iterator_next(fi, &name)) {
   547 		pi = razor_package_iterator_create_for_file(set, name);
   548 		count = 0;
   549 		while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_LAST))
   550 			count++;
   551 		razor_package_iterator_destroy(pi);
   552 		if (count <= 1) {
   553 			snprintf(buffer, sizeof buffer, "%s%s", root, name);
   554 			retval = remove(buffer);
   555 		}
   556 	}
   557 
   558 	razor_file_iterator_destroy(fi);
   559 
   560 	if (retval)
   561 		return retval;
   562 
   563 	razor_package_get_details(set, package,
   564 				  RAZOR_DETAIL_POSTUNPROG, &program,
   565 				  RAZOR_DETAIL_POSTUN, &script,
   566 				  RAZOR_DETAIL_LAST);
   567 
   568 	environment_init(&env);
   569 	link = list_first(&package->install_prefixes, &set->prefix_pool);
   570 	for (i = 0; link; i++) {
   571 		prefix = (const char *)set->string_pool.data + link->data;
   572 		sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
   573 		environment_add_variable(&env, buffer, prefix);
   574 		link = list_next(link);
   575 	}
   576 	environment_set(&env);
   577 
   578 	retval = razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script);
   579 
   580 	environment_unset(&env);
   581 	environment_release(&env);
   582 
   583 	return retval;
   584 }
   585 
   586 RAZOR_EXPORT const char *
   587 razor_property_relation_to_string(struct razor_property *p)
   588 {
   589 	assert (p != NULL);
   590 
   591 	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
   592 	case RAZOR_PROPERTY_LESS:
   593 		return "<";
   594 
   595 	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
   596 		return "<=";
   597 
   598 	case RAZOR_PROPERTY_EQUAL:
   599 		return "=";
   600 
   601 	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
   602 		return ">=";
   603 
   604 	case RAZOR_PROPERTY_GREATER:
   605 		return ">";
   606 
   607 	default:
   608 		return "?";
   609 	}
   610 }
   611 
   612 RAZOR_EXPORT const char *
   613 razor_property_type_to_string(struct razor_property *p)
   614 {
   615 	assert (p != NULL);
   616 
   617 	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
   618 	case RAZOR_PROPERTY_REQUIRES:
   619 		return "requires";
   620 	case RAZOR_PROPERTY_PROVIDES:
   621 		return "provides";
   622 	case RAZOR_PROPERTY_CONFLICTS:
   623 		return "conflicts";
   624 	case RAZOR_PROPERTY_OBSOLETES:
   625 		return "obsoletes";
   626 	default:
   627 		return NULL;
   628 	}
   629 }
   630 
   631 RAZOR_EXPORT struct razor_entry *
   632 razor_set_find_entry(struct razor_set *set,
   633 		     struct razor_entry *dir, const char *pattern)
   634 {
   635 	struct razor_entry *e, *subdir;
   636 	const char *n, *pool = set->file_string_pool.data;
   637 	int len;
   638 
   639 	assert (set != NULL);
   640 	assert (dir != NULL);
   641 	assert (pattern != NULL);
   642 
   643 	e = dir;
   644 	do {
   645 		n = pool + e->name;
   646 		if (strcmp(pattern, n) == 0)
   647 			return e;
   648 		len = strlen(n);
   649 		if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
   650 		    pattern[len] == '/') {
   651 			subdir = (struct razor_entry *) set->files.data +
   652 				 e->start;
   653 			return razor_set_find_entry(set, subdir,
   654 						    pattern + len + 1);
   655 		}
   656 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   657 
   658 	return NULL;
   659 }
   660 
   661 static void
   662 list_dir(struct razor_set *set, struct razor_entry *dir,
   663 	 char *prefix, const char *pattern)
   664 {
   665 	struct razor_entry *e, *subdir;
   666 	const char *n, *pool = set->file_string_pool.data;
   667 
   668 	e = dir;
   669 	do {
   670 		n = pool + e->name;
   671 		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
   672 			continue;
   673 		printf("%s/%s\n", prefix, n);
   674 		if (e->start) {
   675 			char *sub = prefix + strlen (prefix);
   676 			*sub = '/';
   677 			strcpy (sub + 1, n);
   678 			subdir = (struct razor_entry *) set->files.data +
   679 				 e->start;
   680 			list_dir(set, subdir, prefix, pattern);
   681 			*sub = '\0';
   682 		}
   683 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   684 }
   685 
   686 RAZOR_EXPORT void
   687 razor_set_list_files(struct razor_set *set, const char *pattern)
   688 {
   689 	struct razor_entry *root, *e;
   690 	char buffer[512], *p, *base;
   691 
   692 	assert (set != NULL);
   693 
   694 	root = (struct razor_entry *) set->files.data;
   695 
   696 	if (pattern == NULL) {
   697 		p = set->file_string_pool.data;
   698 		e = root;
   699 		do {
   700 			if (e->start) {
   701 				strcpy(buffer, p + e->name);
   702 				list_dir(set, root + e->start, buffer, NULL);
   703 			}
   704 		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   705 		return;
   706 	}
   707 
   708 	strcpy(buffer, pattern);
   709 	e = razor_set_find_entry(set, root, buffer);
   710 	if (e && e->start) {
   711 		base = NULL;
   712 	} else {
   713 		p = strrchr(buffer, '/');
   714 		if (p) {
   715 			*p = '\0';
   716 			base = p + 1;
   717 		} else {
   718 			base = NULL;
   719 		}
   720 	}
   721 	e = razor_set_find_entry(set, root, buffer);
   722 	if (e && e->start)
   723 		list_dir(set, root + e->start, buffer, base);
   724 }
   725 
   726 RAZOR_EXPORT void
   727 razor_set_list_package_files(struct razor_set *set,
   728 			     struct razor_package *package)
   729 {
   730 	struct razor_file_iterator *fi;
   731 	const char *name;
   732 
   733 	assert (set != NULL);
   734 	assert (package != NULL);
   735 
   736 	fi = razor_file_iterator_create(set, package);
   737 
   738 	while (razor_file_iterator_next(fi, &name))
   739 		printf("%s\n", name);
   740 
   741 	razor_file_iterator_destroy(fi);
   742 }
   743 
   744 RAZOR_EXPORT void
   745 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
   746 	       razor_diff_callback_t callback, void *data)
   747 {
   748  	struct razor_package_iterator *pi1, *pi2;
   749  	struct razor_package *p1, *p2;
   750 	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
   751 	int res;
   752 
   753 	assert (set != NULL);
   754 	assert (upstream != NULL);
   755 
   756 	pi1 = razor_package_iterator_create(set);
   757 	pi2 = razor_package_iterator_create(upstream);
   758 
   759 	razor_package_iterator_next(pi1, &p1,
   760 				    RAZOR_DETAIL_NAME, &name1,
   761 				    RAZOR_DETAIL_VERSION, &version1,
   762 				    RAZOR_DETAIL_ARCH, &arch1,
   763 				    RAZOR_DETAIL_LAST);
   764 	razor_package_iterator_next(pi2, &p2,
   765 				    RAZOR_DETAIL_NAME, &name2,
   766 				    RAZOR_DETAIL_VERSION, &version2,
   767 				    RAZOR_DETAIL_ARCH, &arch2,
   768 				    RAZOR_DETAIL_LAST);
   769 
   770 	while (p1 || p2) {
   771 		if (p1 && p2) {
   772 			res = strcmp(name1, name2);
   773 			if (res == 0)
   774 				res = razor_versioncmp(version1, version2);
   775 		} else {
   776 			res = 0;
   777 		}
   778 
   779 		if (p2 == NULL || res < 0)
   780 			callback(RAZOR_DIFF_ACTION_REMOVE,
   781 				 p1, name1, version1, arch1, data);
   782 		else if (p1 == NULL || res > 0)
   783 			callback(RAZOR_DIFF_ACTION_ADD,
   784 				 p2, name2, version2, arch2, data);
   785 
   786 		if (p1 != NULL && res <= 0)
   787 			razor_package_iterator_next(pi1, &p1,
   788 						    RAZOR_DETAIL_NAME, &name1,
   789 						    RAZOR_DETAIL_VERSION, &version1,
   790 						    RAZOR_DETAIL_ARCH, &arch1,
   791 						    RAZOR_DETAIL_LAST);
   792 		if (p2 != NULL && res >= 0)
   793 			razor_package_iterator_next(pi2, &p2,
   794 						    RAZOR_DETAIL_NAME, &name2,
   795 						    RAZOR_DETAIL_VERSION, &version2,
   796 						    RAZOR_DETAIL_ARCH, &arch2,
   797 						    RAZOR_DETAIL_LAST);
   798 	}
   799 
   800 	razor_package_iterator_destroy(pi1);
   801 	razor_package_iterator_destroy(pi2);
   802 }
   803 
   804 struct install_action {
   805 	enum razor_install_action action;
   806 	struct razor_package *package;
   807 };
   808 
   809 struct razor_install_iterator {
   810 	struct razor_set *set;
   811 	struct razor_set *next;
   812 	struct array actions;
   813 	struct deque *order;
   814 };
   815 
   816 static void
   817 add_action(enum razor_diff_action action,
   818 	   struct razor_package *package,
   819 	   const char *name,
   820 	   const char *version,
   821 	   const char *arch,
   822 	   void *data)
   823 {
   824 	struct razor_install_iterator *ii = data;
   825 	struct install_action *a;
   826 
   827 	a = array_add(&ii->actions, sizeof *a);
   828 	a->package = package;
   829 
   830 	switch (action) {
   831 	case RAZOR_DIFF_ACTION_ADD:
   832 		a->action = RAZOR_INSTALL_ACTION_ADD;
   833 		break;
   834 	case RAZOR_DIFF_ACTION_REMOVE:
   835 		a->action = RAZOR_INSTALL_ACTION_REMOVE;
   836 		break;
   837 	}
   838 }
   839 
   840 RAZOR_EXPORT struct razor_install_iterator *
   841 razor_set_create_install_iterator(struct razor_set *set,
   842 				  struct razor_set *next)
   843 {
   844 	struct razor_install_iterator *ii;
   845 	struct razor_property *prop;
   846 	/* A graph of the actions to be perfomed where
   847 	 * A->B means action A should follow action B.
   848 	 */
   849 	struct graph follows;
   850 	struct install_action *actions, *ai, *aj;
   851 	int i, j, count, vertex_added;
   852 	struct list *link;
   853 	struct razor_set *rs;
   854 
   855 	assert (set != NULL);
   856 	assert (next != NULL);
   857 
   858 	ii = zalloc(sizeof *ii);
   859 	ii->set = set;
   860 	ii->next = next;
   861 	
   862 	razor_set_diff(set, next, add_action, ii);
   863 
   864 	actions = ii->actions.data;
   865 	count = ii->actions.size / sizeof (struct install_action);
   866 
   867 	graph_init(&follows);
   868 
   869 	for(i = 0; i < count; i++) {
   870 		ai = actions + i;
   871 		rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
   872 		vertex_added = 0;
   873 		link = list_first(&ai->package->properties, &rs->property_pool);
   874 		for(; link; link = list_next(link)) {
   875 			prop = rs->properties.data;
   876 			prop += link->data;
   877 			switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
   878 			case RAZOR_PROPERTY_REQUIRES:
   879 			case RAZOR_PROPERTY_CONFLICTS:
   880 				for(j = 0; j < count; j++) {
   881 					if (j == i)
   882 						continue;
   883 					aj = actions + j;
   884 					if (aj->package->name == prop->name) {
   885 						if (ai->action ==
   886 						    RAZOR_INSTALL_ACTION_ADD)
   887 							graph_add_edge(&follows,
   888 								       i, j);
   889 						else
   890 							graph_add_edge(&follows,
   891 								       j, i);
   892 						vertex_added++;
   893 					}
   894 				}
   895 				break;
   896 			}
   897 		}
   898 		if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
   899 			for(j = 0; j < count; j++) {
   900 				if (j == i)
   901 					continue;
   902 				aj = actions + j;
   903 				if (aj->package == ai->package &&
   904 				    aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
   905 					graph_add_edge(&follows, i, j);
   906 					vertex_added++;
   907 				}
   908 			}
   909 		}
   910 		if (!vertex_added)
   911 			graph_add_edge(&follows, i, i);
   912 	}
   913 
   914 	ii->order = graph_sort(&follows);
   915 	graph_release(&follows);
   916 
   917 	return ii;
   918 }
   919 
   920 RAZOR_EXPORT int
   921 razor_install_iterator_next(struct razor_install_iterator *ii,
   922 			    struct razor_set **set,
   923 			    struct razor_package **package,
   924 			    enum razor_install_action *action,
   925 			    int *count)
   926 {
   927 	struct install_action *a;
   928 	if (deque_empty(ii->order))
   929 		return 0;
   930 
   931 	a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
   932 	switch (a->action) {
   933 	case RAZOR_INSTALL_ACTION_ADD:
   934 		*set = ii->next;
   935 		break;
   936 	case RAZOR_INSTALL_ACTION_REMOVE:
   937 		*set = ii->set;
   938 		break;
   939 	}
   940 
   941 	*package = a->package;
   942 	*action = a->action;
   943 	*count = 0;
   944 
   945 	return 1;
   946 }
   947 
   948 RAZOR_EXPORT void
   949 razor_install_iterator_destroy(struct razor_install_iterator *ii)
   950 {
   951 	array_release(&ii->actions);
   952 	deque_free(ii->order);
   953 	free(ii);
   954 }