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