librazor/razor.c
author Richard Hughes <richard@hughsie.com>
Sun Jun 29 17:32:19 2008 +0100 (2008-06-29)
changeset 301 4124c37fd953
parent 298 ddc35bb593ef
child 302 9b71b537d175
permissions -rw-r--r--
protect all exported functions by checking the input parameters for NULL input
     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 <stdlib.h>
    23 #include <stddef.h>
    24 #include <stdint.h>
    25 #include <stdio.h>
    26 #include <string.h>
    27 #include <sys/types.h>
    28 #include <sys/stat.h>
    29 #include <sys/mman.h>
    30 #include <unistd.h>
    31 #include <fcntl.h>
    32 #include <errno.h>
    33 #include <ctype.h>
    34 #include <fnmatch.h>
    35 #include <assert.h>
    36 
    37 #include "razor-internal.h"
    38 #include "razor.h"
    39 
    40 void *
    41 zalloc(size_t size)
    42 {
    43 	void *p;
    44 
    45 	p = malloc(size);
    46 	memset(p, 0, size);
    47 
    48 	return p;
    49 }
    50 
    51 struct razor_set_section razor_sections[] = {
    52 	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
    53 	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
    54 	{ RAZOR_PROPERTIES,	offsetof(struct razor_set, properties) },
    55 	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
    56 	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
    57 };
    58 
    59 struct razor_set_section razor_files_sections[] = {
    60 	{ RAZOR_FILES,			offsetof(struct razor_set, files) },
    61 	{ RAZOR_FILE_POOL,		offsetof(struct razor_set, file_pool) },
    62 	{ RAZOR_FILE_STRING_POOL,	offsetof(struct razor_set, file_string_pool) },
    63 };
    64 
    65 struct razor_set_section razor_details_sections[] = {
    66 	{ RAZOR_DETAILS_STRING_POOL,	offsetof(struct razor_set, details_string_pool) },
    67 };
    68 
    69 RAZOR_EXPORT struct razor_set *
    70 razor_set_create(void)
    71 {
    72 	struct razor_set *set;
    73 	struct razor_entry *e;
    74 	char *empty;
    75 
    76 	set = zalloc(sizeof *set);
    77 
    78 	e = array_add(&set->files, sizeof *e);
    79 	empty = array_add(&set->string_pool, 1);
    80 	*empty = '\0';
    81 	e->name = 0;
    82 	e->flags = RAZOR_ENTRY_LAST;
    83 	e->start = 0;
    84 	list_set_empty(&e->packages);
    85 
    86 	return set;
    87 }
    88 
    89 RAZOR_EXPORT struct razor_set *
    90 razor_set_open(const char *filename)
    91 {
    92 	struct razor_set *set;
    93 	struct razor_set_section *s;
    94 	struct stat stat;
    95 	struct array *array;
    96 	int fd;
    97 
    98 	set = zalloc(sizeof *set);
    99 	fd = open(filename, O_RDONLY);
   100 	if (fstat(fd, &stat) < 0)
   101 		return NULL;
   102 	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   103 	if (set->header == MAP_FAILED) {
   104 		free(set);
   105 		return NULL;
   106 	}
   107 
   108 	for (s = set->header->sections; ~s->type; s++) {
   109 		if (s->type >= ARRAY_SIZE(razor_sections))
   110 			continue;
   111 		if (s->type != razor_sections[s->type].type)
   112 			continue;
   113 		array = (void *) set + razor_sections[s->type].offset;
   114 		array->data = (void *) set->header + s->offset;
   115 		array->size = s->size;
   116 		array->alloc = s->size;
   117 	}
   118 	close(fd);
   119 
   120 	return set;
   121 }
   122 
   123 RAZOR_EXPORT int
   124 razor_set_open_details(struct razor_set *set, const char *filename)
   125 {
   126 	struct razor_set_section *s;
   127 	struct stat stat;
   128 	struct array *array;
   129 	int fd;
   130 
   131 	assert (set != NULL);
   132 	assert (filename != NULL);
   133 
   134 	fd = open(filename, O_RDONLY);
   135 	if (fstat(fd, &stat) < 0)
   136 		return -1;
   137 	set->details_header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   138 	if (set->details_header == MAP_FAILED)
   139 		return -1;
   140 
   141 	for (s = set->details_header->sections; ~s->type; s++) {
   142 		if (s->type >= ARRAY_SIZE(razor_details_sections))
   143 			continue;
   144 		if (s->type != razor_details_sections[s->type].type)
   145 			continue;
   146 		array = (void *) set + razor_details_sections[s->type].offset;
   147 		array->data = (void *) set->details_header + s->offset;
   148 		array->size = s->size;
   149 		array->alloc = s->size;
   150 	}
   151 	close(fd);
   152 
   153 	return 0;
   154 }
   155 
   156 RAZOR_EXPORT int
   157 razor_set_open_files(struct razor_set *set, const char *filename)
   158 {
   159 	struct razor_set_section *s;
   160 	struct stat stat;
   161 	struct array *array;
   162 	int fd;
   163 
   164 	assert (set != NULL);
   165 	assert (filename != NULL);
   166 
   167 	fd = open(filename, O_RDONLY);
   168 	if (fstat(fd, &stat) < 0)
   169 		return -1;
   170 	set->files_header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   171 	if (set->files_header == MAP_FAILED)
   172 		return -1;
   173 
   174 	for (s = set->files_header->sections; ~s->type; s++) {
   175 		if (s->type >= ARRAY_SIZE(razor_files_sections))
   176 			continue;
   177 		if (s->type != razor_files_sections[s->type].type)
   178 			continue;
   179 		array = (void *) set + razor_files_sections[s->type].offset;
   180 		array->data = (void *) set->files_header + s->offset;
   181 		array->size = s->size;
   182 		array->alloc = s->size;
   183 	}
   184 	close(fd);
   185 
   186 	return 0;
   187 }
   188 
   189 RAZOR_EXPORT void
   190 razor_set_destroy(struct razor_set *set)
   191 {
   192 	unsigned int size;
   193 	struct array *a;
   194 	int i;
   195 
   196 	assert (set != NULL);
   197 
   198 	if (set->header) {
   199 		for (i = 0; set->header->sections[i].type; i++)
   200 			;
   201 		size = set->header->sections[i].type;
   202 		munmap(set->header, size);
   203 	} else {
   204 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   205 			a = (void *) set + razor_sections[i].offset;
   206 			free(a->data);
   207 		}
   208 	}
   209 
   210 	if (set->details_header) {
   211 		for (i = 0; set->details_header->sections[i].type; i++)
   212 			;
   213 		size = set->details_header->sections[i].type;
   214 		munmap(set->details_header, size);
   215 	} else {
   216 		for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
   217 			a = (void *) set + razor_details_sections[i].offset;
   218 			free(a->data);
   219 		}
   220 	}
   221 
   222 	if (set->files_header) {
   223 		for (i = 0; set->files_header->sections[i].type; i++)
   224 			;
   225 		size = set->files_header->sections[i].type;
   226 		munmap(set->files_header, size);
   227 	} else {
   228 		for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
   229 			a = (void *) set + razor_files_sections[i].offset;
   230 			free(a->data);
   231 		}
   232 	}
   233 
   234 	free(set);
   235 }
   236 
   237 static int
   238 razor_set_write_sections_to_fd(struct razor_set *set, int fd, int magic,
   239 			       struct razor_set_section *sections,
   240 			       size_t array_size)
   241 {
   242 	char data[4096];
   243 	struct razor_set_header *header = (struct razor_set_header *) data;
   244 	struct array *a;
   245 	uint32_t offset;
   246 	int i;
   247 
   248 	memset(data, 0, sizeof data);
   249 	header->magic = magic;
   250 	header->version = RAZOR_VERSION;
   251 	offset = sizeof data;
   252 
   253 	for (i = 0; i < array_size; i++) {
   254 		if (sections[i].type != i)
   255 			continue;
   256 		a = (void *) set + sections[i].offset;
   257 		header->sections[i].type = i;
   258 		header->sections[i].offset = offset;
   259 		header->sections[i].size = a->size;
   260 		offset += ALIGN(a->size, 4096);
   261 	}
   262 
   263 	header->sections[i].type = ~0;
   264 	header->sections[i].offset = 0;
   265 	header->sections[i].size = 0;
   266 
   267 	razor_write(fd, data, sizeof data);
   268 	memset(data, 0, sizeof data);
   269 	for (i = 0; i < array_size; i++) {
   270 		if (sections[i].type != i)
   271 			continue;
   272 		a = (void *) set + sections[i].offset;
   273 		razor_write(fd, a->data, a->size);
   274 		razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
   275 	}
   276 
   277 	return 0;
   278 }
   279 
   280 RAZOR_EXPORT int
   281 razor_set_write_to_fd(struct razor_set *set, int fd,
   282 		      enum razor_repo_file_type type)
   283 {
   284 	switch (type) {
   285 	case RAZOR_REPO_FILE_MAIN:
   286 		return razor_set_write_sections_to_fd(set, fd, RAZOR_MAGIC,
   287 						      razor_sections,
   288 						      ARRAY_SIZE(razor_sections));
   289 
   290 	case RAZOR_REPO_FILE_DETAILS:
   291 		return razor_set_write_sections_to_fd(set, fd, RAZOR_DETAILS_MAGIC,
   292 						      razor_details_sections,
   293 						      ARRAY_SIZE(razor_details_sections));
   294 	case RAZOR_REPO_FILE_FILES:
   295 		return razor_set_write_sections_to_fd(set, fd, RAZOR_FILES_MAGIC,
   296 						      razor_files_sections,
   297 						      ARRAY_SIZE(razor_files_sections));
   298 	default:
   299 		return -1;
   300 	}
   301 }
   302 
   303 RAZOR_EXPORT int
   304 razor_set_write(struct razor_set *set, const char *filename,
   305 		enum razor_repo_file_type type)
   306 {
   307 	int fd, status;
   308 
   309 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
   310 	if (fd < 0)
   311 		return -1;
   312 
   313 	status = razor_set_write_to_fd(set, fd, type);
   314 	if (status) {
   315 	    close(fd);
   316 	    return status;
   317 	}
   318 
   319 	return close(fd);
   320 }
   321 
   322 RAZOR_EXPORT void
   323 razor_build_evr(char *evr_buf, int size, const char *epoch,
   324 		const char *version, const char *release)
   325 {
   326 	int len;
   327 
   328 	if (!version || !*version) {
   329 		*evr_buf = '\0';
   330 		return;
   331 	}
   332 
   333 	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
   334 		len = snprintf(evr_buf, size, "%s:", epoch);
   335 		evr_buf += len;
   336 		size -= len;
   337 	}
   338 	len = snprintf(evr_buf, size, "%s", version);
   339 	evr_buf += len;
   340 	size -= len;
   341 	if (release && *release)
   342 		snprintf(evr_buf, size, "-%s", release);
   343 }
   344 
   345 RAZOR_EXPORT int
   346 razor_versioncmp(const char *s1, const char *s2)
   347 {
   348 	const char *p1, *p2;
   349 	long n1, n2;
   350 	int res;
   351 
   352 	assert (s1 != NULL);
   353 	assert (s2 != NULL);
   354 
   355 	n1 = strtol(s1, (char **) &p1, 10);
   356 	n2 = strtol(s2, (char **) &p2, 10);
   357 
   358 	/* Epoch; if one but not the other has an epoch set, default
   359 	 * the epoch-less version to 0. */
   360 	res = (*p1 == ':') - (*p2 == ':');
   361 	if (res < 0) {
   362 		n1 = 0;
   363 		p1 = s1;
   364 		p2++;
   365 	} else if (res > 0) {
   366 		p1++;
   367 		n2 = 0;
   368 		p2 = s2;
   369 	}
   370 
   371 	if (n1 != n2)
   372 		return n1 - n2;
   373 	while (*p1 && *p2) {
   374 		if (*p1 != *p2)
   375 			return *p1 - *p2;
   376 		p1++;
   377 		p2++;
   378 		if (isdigit(*p1) && isdigit(*p2))
   379 			return razor_versioncmp(p1, p2);
   380 	}
   381 
   382 	return *p1 - *p2;
   383 }
   384 
   385 RAZOR_EXPORT struct razor_package *
   386 razor_set_get_package(struct razor_set *set, const char *package)
   387 {
   388 	struct razor_package_iterator *pi;
   389 	struct razor_package *p;
   390 	const char *name, *version, *arch;
   391 
   392 	assert (set != NULL);
   393 	assert (package != NULL);
   394 
   395 	pi = razor_package_iterator_create(set);
   396 	while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
   397 		if (strcmp(package, name) == 0)
   398 			break;
   399 	}
   400 	razor_package_iterator_destroy(pi);
   401 
   402 	return p;
   403 }
   404 
   405 RAZOR_EXPORT void
   406 razor_package_get_details(struct razor_set *set,
   407 			  struct razor_package *package,
   408 			  const char **summary, const char **description,
   409 			  const char **url, const char **license)
   410 {
   411 	const char *pool = set->details_string_pool.data;
   412 
   413 	assert (set != NULL);
   414 	assert (package != NULL);
   415 
   416 	if (summary != NULL)
   417 		*summary = &pool[package->summary];
   418 	if (description != NULL)
   419 		*description = &pool[package->description];
   420 	if (url != NULL)
   421 		*url = &pool[package->url];
   422 	if (license != NULL)
   423 		*license = &pool[package->license];
   424 }
   425 
   426 RAZOR_EXPORT const char *
   427 razor_property_relation_to_string(struct razor_property *p)
   428 {
   429 	assert (p != NULL);
   430 
   431 	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
   432 	case RAZOR_PROPERTY_LESS:
   433 		return "<";
   434 
   435 	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
   436 		return "<=";
   437 
   438 	case RAZOR_PROPERTY_EQUAL:
   439 		return "=";
   440 
   441 	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
   442 		return ">=";
   443 
   444 	case RAZOR_PROPERTY_GREATER:
   445 		return ">";
   446 
   447 	default:
   448 		return "?";
   449 	}
   450 }
   451 
   452 RAZOR_EXPORT const char *
   453 razor_property_type_to_string(struct razor_property *p)
   454 {
   455 	assert (p != NULL);
   456 
   457 	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
   458 	case RAZOR_PROPERTY_REQUIRES:
   459 		return "requires";
   460 	case RAZOR_PROPERTY_PROVIDES:
   461 		return "provides";
   462 	case RAZOR_PROPERTY_CONFLICTS:
   463 		return "conflicts";
   464 	case RAZOR_PROPERTY_OBSOLETES:
   465 		return "obsoletes";
   466 	default:
   467 		return NULL;
   468 	}
   469 }
   470 
   471 RAZOR_EXPORT struct razor_entry *
   472 razor_set_find_entry(struct razor_set *set,
   473 		     struct razor_entry *dir, const char *pattern)
   474 {
   475 	struct razor_entry *e;
   476 	const char *n, *pool = set->file_string_pool.data;
   477 	int len;
   478 
   479 	assert (set != NULL);
   480 	assert (dir != NULL);
   481 	assert (pattern != NULL);
   482 
   483 	e = (struct razor_entry *) set->files.data + dir->start;
   484 	do {
   485 		n = pool + e->name;
   486 		if (strcmp(pattern + 1, n) == 0)
   487 			return e;
   488 		len = strlen(n);
   489 		if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
   490 		    pattern[len + 1] == '/') {
   491 			return razor_set_find_entry(set, e, pattern + len + 1);
   492 		}
   493 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   494 
   495 	return NULL;
   496 }
   497 
   498 static void
   499 list_dir(struct razor_set *set, struct razor_entry *dir,
   500 	 char *prefix, const char *pattern)
   501 {
   502 	struct razor_entry *e;
   503 	const char *n, *pool = set->file_string_pool.data;
   504 
   505 	e = (struct razor_entry *) set->files.data + dir->start;
   506 	do {
   507 		n = pool + e->name;
   508 		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
   509 			continue;
   510 		printf("%s/%s\n", prefix, n);
   511 		if (e->start) {
   512 			char *sub = prefix + strlen (prefix);
   513 			*sub = '/';
   514 			strcpy (sub + 1, n);
   515 			list_dir(set, e, prefix, pattern);
   516 			*sub = '\0';
   517 		}
   518 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   519 }
   520 
   521 RAZOR_EXPORT void
   522 razor_set_list_files(struct razor_set *set, const char *pattern)
   523 {
   524 	struct razor_entry *e;
   525 	char buffer[512], *p, *base;
   526 
   527 	assert (set != NULL);
   528 
   529 	if (pattern == NULL || !strcmp (pattern, "/")) {
   530 		buffer[0] = '\0';
   531 		list_dir(set, set->files.data, buffer, NULL);
   532 		return;
   533 	}
   534 
   535 	strcpy(buffer, pattern);
   536 	e = razor_set_find_entry(set, set->files.data, buffer);
   537 	if (e && e->start > 0) {
   538 		base = NULL;
   539 	} else {
   540 		p = strrchr(buffer, '/');
   541 		if (p) {
   542 			*p = '\0';
   543 			base = p + 1;
   544 		} else {
   545 			base = NULL;
   546 		}
   547 	}
   548 	e = razor_set_find_entry(set, set->files.data, buffer);
   549 	if (e && e->start != 0)
   550 		list_dir(set, e, buffer, base);
   551 }
   552 
   553 static struct list *
   554 list_package_files(struct razor_set *set, struct list *r,
   555 		   struct razor_entry *dir, uint32_t end,
   556 		   char *prefix)
   557 {
   558 	struct razor_entry *e, *f, *entries;
   559 	uint32_t next, file;
   560 	char *pool;
   561 	int len;
   562 
   563 	entries = (struct razor_entry *) set->files.data;
   564 	pool = set->file_string_pool.data;
   565 
   566 	e = entries + dir->start;
   567 	do {
   568 		if (entries + r->data == e) {
   569 			printf("%s/%s\n", prefix, pool + e->name);
   570 			r = list_next(r);
   571 			if (!r)
   572 				return NULL;
   573 			if (r->data >= end)
   574 				return r;
   575 		}
   576 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   577 
   578 	e = entries + dir->start;
   579 	do {
   580 		if (e->start == 0)
   581 			continue;
   582 
   583 		if (e->flags & RAZOR_ENTRY_LAST)
   584 			next = end;
   585 		else {
   586 			f = e + 1;
   587 			while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
   588 				f++;
   589 			if (f->start == 0)
   590 				next = end;
   591 			else
   592 				next = f->start;
   593 		}
   594 
   595 		file = r->data;
   596 		if (e->start <= file && file < next) {
   597 			len = strlen(prefix);
   598 			prefix[len] = '/';
   599 			strcpy(prefix + len + 1, pool + e->name);
   600 			r = list_package_files(set, r, e, next, prefix);
   601 			prefix[len] = '\0';
   602 		}
   603 	} while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
   604 
   605 	return r;
   606 }
   607 
   608 RAZOR_EXPORT void
   609 razor_set_list_package_files(struct razor_set *set, const char *name)
   610 {
   611 	struct razor_package *package;
   612 	struct list *r;
   613 	uint32_t end;
   614 	char buffer[512];
   615 
   616 	assert (set != NULL);
   617 	assert (name != NULL);
   618 
   619 	package = razor_set_get_package(set, name);
   620 	/* TODO: we should return the error to the caller */
   621 	if (!package)
   622 		return;
   623 
   624 	r = list_first(&package->files, &set->file_pool);
   625 	end = set->files.size / sizeof (struct razor_entry);
   626 	buffer[0] = '\0';
   627 	list_package_files(set, r, set->files.data, end, buffer);
   628 }
   629 
   630 /* The diff order matters.  We should sort the packages so that a
   631  * REMOVE of a package comes before the INSTALL, and so that all
   632  * requires for a package have been installed before the package.
   633  **/
   634 
   635 RAZOR_EXPORT void
   636 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
   637 	       razor_diff_callback_t callback, void *data)
   638 {
   639  	struct razor_package_iterator *pi1, *pi2;
   640  	struct razor_package *p1, *p2;
   641 	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
   642 	int res;
   643 
   644 	assert (set != NULL);
   645 	assert (upstream != NULL);
   646 
   647 	pi1 = razor_package_iterator_create(set);
   648 	pi2 = razor_package_iterator_create(upstream);
   649 
   650 	razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
   651 	razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
   652 
   653 	while (p1 || p2) {
   654 		if (p1 && p2) {
   655 			res = strcmp(name1, name2);
   656 			if (res == 0)
   657 				res = razor_versioncmp(version1, version2);
   658 		} else {
   659 			res = 0;
   660 		}
   661 
   662 		if (p2 == NULL || res < 0)
   663 			callback(RAZOR_DIFF_ACTION_REMOVE,
   664 				 p1, name1, version1, arch1, data);
   665 		else if (p1 == NULL || res > 0)
   666 			callback(RAZOR_DIFF_ACTION_ADD,
   667 				 p2, name2, version2, arch2, data);
   668 
   669 		if (p1 != NULL && res <= 0)
   670 			razor_package_iterator_next(pi1, &p1,
   671 						    &name1, &version1, &arch1);
   672 		if (p2 != NULL && res >= 0)
   673 			razor_package_iterator_next(pi2, &p2,
   674 						    &name2, &version2, &arch2);
   675 	}
   676 
   677 	razor_package_iterator_destroy(pi1);
   678 	razor_package_iterator_destroy(pi2);
   679 }
   680 
   681 static void
   682 add_new_package(enum razor_diff_action action,
   683 		struct razor_package *package,
   684 		const char *name,
   685 		const char *version,
   686 		const char *arch,
   687 		void *data)
   688 {
   689 	if (action == RAZOR_DIFF_ACTION_ADD)
   690 		razor_package_query_add_package(data, package);
   691 }
   692 
   693 RAZOR_EXPORT struct razor_package_iterator *
   694 razor_set_create_remove_iterator(struct razor_set *set,
   695 				 struct razor_set *next)
   696 {
   697 	struct razor_package_query *query;
   698 	struct razor_package_iterator *pi;
   699 
   700 	assert (set != NULL);
   701 	assert (next != NULL);
   702 
   703 	query = razor_package_query_create(set);
   704 	razor_set_diff(next, set, add_new_package, query);
   705 
   706 	pi = razor_package_query_finish(query);
   707 
   708 	/* FIXME: We need to figure out the right install order here,
   709 	 * so the post and pre scripts can run. */
   710 
   711 	/* sort */
   712 
   713 	return pi;
   714 }
   715 
   716 RAZOR_EXPORT struct razor_package_iterator *
   717 razor_set_create_install_iterator(struct razor_set *set,
   718 				  struct razor_set *next)
   719 {
   720 	struct razor_package_query *query;
   721 	struct razor_package_iterator *pi;
   722 
   723 	assert (set != NULL);
   724 	assert (next != NULL);
   725 
   726 	query = razor_package_query_create(next);
   727 	razor_set_diff(set, next, add_new_package, query);
   728 
   729 	pi = razor_package_query_finish(query);
   730 
   731 	/* FIXME: We need to figure out the right install order here,
   732 	 * so the post and pre scripts can run. */
   733 
   734 	/* sort */
   735 
   736 	return pi;
   737 }