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