librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Tue Apr 24 19:27:53 2018 +0100 (2018-04-24)
changeset 497 6fbb686d919f
parent 475 008c75a5e08d
child 499 c89e5edb8eae
permissions -rw-r--r--
Added tag Release 0.6.3.112 for changeset 203fa998c6df
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009-2012, 2016  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 <fcntl.h>
    32 #include <unistd.h>
    33 #include <errno.h>
    34 #include <ctype.h>
    35 #include <fnmatch.h>
    36 #include <limits.h>
    37 #include <assert.h>
    38 #ifdef MSWIN_API
    39 #include <windows.h>
    40 #endif
    41 
    42 #include "razor-internal.h"
    43 #include "razor.h"
    44 
    45 #ifndef O_BINARY
    46 #define O_BINARY	0
    47 #endif
    48 
    49 struct razor_set_section_index {
    50 	const char *name;
    51 	uint32_t offset;
    52 	uint32_t flags;
    53 };
    54 
    55 #define MAIN(type, field) \
    56 	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
    57 #define FILES(type, field) \
    58 	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
    59 #define DETAILS(type, field) \
    60 	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
    61 
    62 struct razor_set_section_index razor_sections[] = {
    63 	MAIN(RAZOR_STRING_POOL, string_pool),
    64 	MAIN(RAZOR_PACKAGES, packages),
    65 	MAIN(RAZOR_PROPERTIES, properties),
    66 	MAIN(RAZOR_PACKAGE_POOL, package_pool),
    67 	MAIN(RAZOR_PROPERTY_POOL, property_pool),
    68 	MAIN(RAZOR_PREFIX_POOL, prefix_pool),
    69 	FILES(RAZOR_FILES, files),
    70 	FILES(RAZOR_FILE_POOL, file_pool),
    71 	FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
    72 	DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
    73 };
    74 
    75 RAZOR_EXPORT struct razor_set *
    76 razor_set_create_without_root(void)
    77 {
    78 	struct razor_set *set;
    79 	char *empty;
    80 
    81 	set = zalloc(sizeof *set);
    82 
    83 	if (set) {
    84 		empty = array_add(&set->string_pool, 1);
    85 		*empty = '\0';
    86 
    87 		set->lock_fd = -1;
    88 
    89 		set->ref_count = 1;
    90 
    91 		set->header_version = RAZOR_HEADER_VERSION;
    92 
    93 		set->flags = RAZOR_SET_PRIVATE;
    94 	}
    95 
    96 	return set;
    97 }
    98 
    99 RAZOR_EXPORT struct razor_set *
   100 razor_set_create(void)
   101 {
   102 	struct razor_set *set;
   103 	struct razor_entry *e;
   104 
   105 	set = razor_set_create_without_root();
   106 
   107 	e = array_add(&set->files, sizeof *e);
   108 	e->name = 0;
   109 	e->flags = RAZOR_ENTRY_LAST;
   110 	e->start = 0;
   111 	list_set_empty(&e->packages);
   112 
   113 	return set;
   114 }
   115 
   116 RAZOR_EXPORT uint32_t
   117 razor_set_get_header_version(struct razor_set *set)
   118 {
   119 	return set->header_version;
   120 }
   121 
   122 RAZOR_EXPORT int
   123 razor_set_set_header_version(struct razor_set *set, uint32_t header_version)
   124 {
   125 	if (header_version<RAZOR_HEADER_VERSION_MIN ||
   126 	    header_version>RAZOR_HEADER_VERSION)
   127 		return -1;
   128 	else {
   129 		set->header_version = header_version;
   130 		return 0;
   131 	}
   132 }
   133 
   134 struct razor_mapped_file {
   135 	struct razor_set_header *header;
   136 	size_t size;
   137 	struct razor_mapped_file *next;
   138 };
   139 
   140 RAZOR_EXPORT int
   141 razor_set_bind_sections(struct razor_set *set, const char *uri,
   142 			enum razor_set_flags flags, struct razor_error **error)
   143 {
   144 	struct razor_set_section *s, *sections;
   145 	struct razor_mapped_file *file;
   146 	const char *pool, *reason;
   147 	struct array *array;
   148 	int i, j, code;
   149 
   150 	file = zalloc(sizeof *file);
   151 	if (file == NULL) {
   152 		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   153 				"Not enough memory");
   154 		return -1;
   155 	}
   156 
   157 	file->header = razor_uri_get_contents(uri, &file->size,
   158 					      flags & RAZOR_SET_PRIVATE,
   159 					      error);
   160 	if (!file->header) {
   161 		free(file);
   162 		return -1;
   163 	}
   164 
   165 	if (file->size < sizeof *file->header) {
   166 		code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED;
   167 		reason = "Premature EOF";
   168 	} else if (file->header->magic != RAZOR_MAGIC) {
   169 		code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED;
   170 		reason = "Bad magic number";
   171 	} else if (file->header->version < RAZOR_HEADER_VERSION_MIN ||
   172 		   file->header->version > RAZOR_HEADER_VERSION) {
   173 		code = RAZOR_GENERAL_ERROR_DATABASE_INCOMPATIBLE;
   174 		reason = "Incompatible file version";
   175 	} else
   176 		reason = NULL;
   177 
   178 	if (reason) {
   179 		razor_set_error(error, RAZOR_GENERAL_ERROR, code, uri, reason);
   180 		razor_uri_free_contents(file->header, file->size);
   181 		free(file);
   182 		return -1;
   183 	}
   184 
   185 	set->flags = flags & RAZOR_SET_PRIVATE;
   186 
   187 	set->header_version = file->header->version;
   188 
   189 	if (set->mapped_files == NULL) {
   190 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   191 			array = (void *) set + razor_sections[i].offset;
   192 			array_release(array);
   193 		}
   194 	}
   195 
   196 	file->next = set->mapped_files;
   197 	set->mapped_files = file;
   198 
   199 	sections = (void *) file->header + sizeof *file->header;
   200 	pool = (void *) sections +
   201 		file->header->num_sections * sizeof *sections;
   202 
   203 	for (i = 0; i < file->header->num_sections; i++) {
   204 		s = sections + i;
   205 		for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
   206 			if (!strcmp(razor_sections[j].name, &pool[s->name]))
   207 				break;
   208 		if (j == ARRAY_SIZE(razor_sections))
   209 			continue;
   210 		array = (void *) set + razor_sections[j].offset;
   211 		array->data = (void *) file->header + s->offset;
   212 		array->size = s->size;
   213 		array->alloc = s->size;
   214 	}
   215 
   216 	return 0;
   217 }
   218 
   219 RAZOR_EXPORT struct razor_set *
   220 razor_set_open(const char *uri, enum razor_set_flags flags,
   221 	       struct razor_error **error)
   222 {
   223 	struct razor_set *set;
   224 
   225 	set = zalloc(sizeof *set);
   226 	if (!set) {
   227 		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   228 				"Not enough memory");
   229 		return NULL;
   230 	}
   231 
   232 	set->lock_fd = -1;
   233 	set->ref_count = 1;
   234 	if (razor_set_bind_sections(set, uri, flags, error)) {
   235 		free(set);
   236 		return NULL;
   237 	}
   238 	return set;
   239 }
   240 
   241 int
   242 razor_set_acquire_lock(struct razor_set *set, const char *uri, int exclusive)
   243 {
   244 	int fd;
   245 	assert(set != NULL);
   246 
   247 	if (uri) {
   248 		fd = razor_uri_open(uri, O_CREAT | O_RDWR | O_TRUNC | O_BINARY,
   249 				    0666, NULL);
   250 		if (fd < 0)
   251 			return -1;
   252 	} else
   253 		fd = -1;
   254 
   255 #ifdef MSWIN_API
   256 	DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
   257 	OVERLAPPED lock = {0};
   258 
   259 	if (exclusive)
   260 		flags |= LOCKFILE_EXCLUSIVE_LOCK;
   261 	if (fd >= 0 && !LockFileEx((HANDLE)_get_osfhandle(fd), flags, 0, 1, 0,
   262 				   &lock)) {
   263 		close(fd);
   264 		return -1;
   265 	}
   266 	if (set->lock_fd >= 0)
   267 		(void)UnlockFile((HANDLE)_get_osfhandle(set->lock_fd), 0, 0, 1,
   268 				 0);
   269 #else
   270 	struct flock lock = {0};
   271 
   272 	lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
   273 	lock.l_whence = SEEK_SET;
   274 	lock.l_start = 0;
   275 	lock.l_len = 0;
   276 	if (fd >= 0 && fcntl(fd, F_SETLK, &lock) < 0) {
   277 		close(fd);
   278 		return -1;
   279 	}
   280 	if (set->lock_fd >= 0) {
   281 		lock.l_type = F_UNLCK;
   282 		(void)fcntl(set->lock_fd, F_SETLK, &lock);
   283 	}
   284 #endif
   285 
   286 	if (set->lock_fd >= 0)
   287 		close(set->lock_fd);
   288 	set->lock_fd = fd;
   289 
   290 	return 0;
   291 }
   292 
   293 static void
   294 razor_set_destroy(struct razor_set *set)
   295 {
   296 	struct razor_mapped_file *file, *next;
   297 	struct array *array;
   298 	int i;
   299 
   300 	assert (set != NULL);
   301 
   302 	if (set->mapped_files == NULL) {
   303 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   304 			array = (void *) set + razor_sections[i].offset;
   305 			array_release(array);
   306 		}
   307 	} else {
   308 		for (file = set->mapped_files; file != NULL; file = next) {
   309 			next = file->next;
   310 			razor_uri_free_contents(file->header, file->size);
   311 			free(file);
   312 		}
   313 	}
   314 
   315 	razor_set_acquire_lock(set, NULL, 0);
   316 	free(set);
   317 }
   318 
   319 RAZOR_EXPORT void
   320 razor_set_unref(struct razor_set *set)
   321 {
   322 	if (set && !--set->ref_count)
   323 		razor_set_destroy(set);
   324 }
   325 
   326 RAZOR_EXPORT struct razor_set *
   327 razor_set_ref(struct razor_set *set)
   328 {
   329 	if (set)
   330 		set->ref_count++;
   331 	return set;
   332 }
   333 
   334 RAZOR_EXPORT void
   335 razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic,
   336 			  int handle, uint32_t section_mask)
   337 {
   338 	struct razor_set_header header;
   339 	struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
   340 	struct hashtable table;
   341 	struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
   342 	uint32_t offset;
   343 	int count, i, j;
   344 	static const char padding[4];
   345 
   346 	array_init(&pool);
   347 	hashtable_init(&table, &pool);
   348 
   349 	j = 0;
   350 	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   351 		if ((razor_sections[i].flags & section_mask) == 0)
   352 			continue;
   353 
   354 		arrays[j] = (void *) set + razor_sections[i].offset;
   355 		sections[j].name =
   356 			hashtable_tokenize(&table, razor_sections[i].name);
   357 		j++;
   358 	}
   359 
   360 	count = j;
   361 	header.magic = RAZOR_MAGIC;
   362 	header.version = set->header_version;
   363 	header.num_sections = count;
   364 	offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
   365 
   366 	for (i = 0; i < count; i++) {
   367 		sections[i].offset = offset;
   368 		sections[i].size = arrays[i]->size;
   369 		offset += ALIGN(arrays[i]->size, 4);
   370 	}
   371 
   372 	razor_atomic_write(atomic, handle, &header, sizeof header);
   373 	razor_atomic_write(atomic, handle, sections, count * sizeof *sections);
   374 	razor_atomic_write(atomic, handle, pool.data, pool.size);
   375 	razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4));
   376 
   377 	for (i = 0; i < count; i++) {
   378 		razor_atomic_write(atomic, handle, arrays[i]->data,
   379 				   arrays[i]->size);
   380 		razor_atomic_write(atomic, handle, padding,
   381 				   PADDING(arrays[i]->size, 4));
   382 	}
   383 
   384 	array_release(&pool);
   385 	hashtable_release(&table);
   386 }
   387 
   388 RAZOR_EXPORT int
   389 razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
   390 		const char *uri, uint32_t sections)
   391 {
   392 	int h;
   393 
   394 	h = razor_atomic_create_file(atomic, uri,
   395 				     S_IRWXU | S_IRWXG | S_IRWXO);
   396 	if (h < 0)
   397 		return -1;
   398 
   399 	razor_set_write_to_handle(set, atomic, h, sections);
   400 
   401 	return razor_atomic_close(atomic, h);
   402 }
   403 
   404 RAZOR_EXPORT void
   405 razor_build_evr(char *evr_buf, int size, const char *epoch,
   406 		const char *version, const char *release)
   407 {
   408 	int len;
   409 
   410 	if (!version || !*version) {
   411 		*evr_buf = '\0';
   412 		return;
   413 	}
   414 
   415 	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
   416 		len = snprintf(evr_buf, size, "%s:", epoch);
   417 		evr_buf += len;
   418 		size -= len;
   419 	}
   420 	len = snprintf(evr_buf, size, "%s", version);
   421 	evr_buf += len;
   422 	size -= len;
   423 	if (release && *release)
   424 		snprintf(evr_buf, size, "-%s", release);
   425 }
   426 
   427 RAZOR_EXPORT int
   428 razor_versioncmp(const char *s1, const char *s2)
   429 {
   430 	const char *p1, *p2;
   431 	long n1, n2;
   432 	int res;
   433 
   434 	assert (s1 != NULL);
   435 	assert (s2 != NULL);
   436 
   437 	n1 = strtol(s1, (char **) &p1, 10);
   438 	n2 = strtol(s2, (char **) &p2, 10);
   439 
   440 	/* Epoch; if one but not the other has an epoch set, default
   441 	 * the epoch-less version to 0. */
   442 	res = (*p1 == ':') - (*p2 == ':');
   443 	if (res < 0) {
   444 		n1 = 0;
   445 		p1 = s1;
   446 		p2++;
   447 	} else if (res > 0) {
   448 		p1++;
   449 		n2 = 0;
   450 		p2 = s2;
   451 	}
   452 
   453 	if (n1 != n2)
   454 		return n1 - n2;
   455 	while (*p1 && *p2) {
   456 		if (*p1 != *p2)
   457 			return *p1 - *p2;
   458 		p1++;
   459 		p2++;
   460 		if (isdigit(*p1) && isdigit(*p2))
   461 			return razor_versioncmp(p1, p2);
   462 	}
   463 
   464 	return *p1 - *p2;
   465 }
   466 
   467 static const char *
   468 razor_package_get_details_string(struct razor_set *set,
   469 				 struct razor_package *package,
   470 				 enum razor_detail_type type)
   471 {
   472 	const char *pool;
   473 
   474 	switch (type) {
   475 	case RAZOR_DETAIL_NAME:
   476 		pool = set->string_pool.data;
   477 		return &pool[package->name];
   478 
   479 	case RAZOR_DETAIL_VERSION:
   480 		pool = set->string_pool.data;
   481 		return &pool[package->version];
   482 
   483 	case RAZOR_DETAIL_ARCH:
   484 		pool = set->string_pool.data;
   485 		return &pool[package->arch];
   486 
   487 	case RAZOR_DETAIL_SUMMARY:
   488 		if (!set->details_string_pool.size)
   489 			return "";
   490 		pool = set->details_string_pool.data;
   491 		return &pool[package->summary];
   492 
   493 	case RAZOR_DETAIL_DESCRIPTION:
   494 		if (!set->details_string_pool.size)
   495 			return "";
   496 		pool = set->details_string_pool.data;
   497 		return &pool[package->description];
   498 
   499 	case RAZOR_DETAIL_URL:
   500 		if (!set->details_string_pool.size)
   501 			return "";
   502 		pool = set->details_string_pool.data;
   503 		return &pool[package->url];
   504 
   505 	case RAZOR_DETAIL_LICENSE:
   506 		if (!set->details_string_pool.size)
   507 			return "";
   508 		pool = set->details_string_pool.data;
   509 		return &pool[package->license];
   510 
   511 	case RAZOR_DETAIL_PREUNPROG:
   512 		pool = set->string_pool.data;
   513 		return &pool[package->preun.program];
   514 
   515 	case RAZOR_DETAIL_PREUN:
   516 		pool = set->string_pool.data;
   517 		return &pool[package->preun.body];
   518 
   519 	case RAZOR_DETAIL_POSTUNPROG:
   520 		pool = set->string_pool.data;
   521 		return &pool[package->postun.program];
   522 
   523 	case RAZOR_DETAIL_POSTUN:
   524 		pool = set->string_pool.data;
   525 		return &pool[package->postun.body];
   526 
   527 	default:
   528 		fprintf(stderr, "type %u not found\n", type);
   529 		return NULL;
   530 	}
   531 }
   532 
   533 static const char *const *
   534 razor_package_get_details_array(struct razor_set *set,
   535 				struct razor_package *package,
   536 				enum razor_detail_type type)
   537 {
   538 	switch (type) {
   539 	case RAZOR_DETAIL_PREFIXES:
   540 		/* We don't track prefixes in packages. Install
   541 		 * prefixes are tracked, and made available via
   542 		 * razor_install_prefix_iterator_create().
   543 		 */
   544 		return NULL;
   545 
   546 	default:
   547 		fprintf(stderr, "type %u not found\n", type);
   548 		return NULL;
   549 	}
   550 }
   551 
   552 /**
   553  * razor_package_get_details_varg:
   554  * @set: a %razor_set
   555  * @package: a %razor_package
   556  * @args: a va_list of arguments to set
   557  **/
   558 void
   559 razor_package_get_details_varg(struct razor_set *set,
   560 			       struct razor_package *package,
   561 			       va_list args)
   562 {
   563 	int i;
   564 	enum razor_detail_type type;
   565 	const char **string;
   566 	const char *const **array;
   567 
   568 	for (i = 0;; i += 2) {
   569 		type = va_arg(args, enum razor_detail_type);
   570 		if (type == RAZOR_DETAIL_LAST)
   571 			break;
   572 		if (type == RAZOR_DETAIL_PREFIXES) {
   573 			array = va_arg(args, const char *const **);
   574 			*array = razor_package_get_details_array(set, package,
   575 								 type);
   576 		} else {
   577 			string = va_arg(args, const char **);
   578 			*string = razor_package_get_details_string(set, package,
   579 								   type);
   580 		}
   581 	}
   582 
   583 }
   584 
   585 /**
   586  * razor_package_get_details:
   587  * @set: a %razor_set
   588  * @package: a %razor_package
   589  *
   590  * Gets details about a package using a varg interface
   591  * The vararg must be terminated with %RAZOR_DETAIL_LAST.
   592  *
   593  * Example: razor_package_get_details (set, package,
   594  *				       RAZOR_DETAIL_URL, &url,
   595  *				       RAZOR_DETAIL_LAST);
   596  **/
   597 RAZOR_EXPORT void
   598 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
   599 {
   600 	va_list args;
   601 
   602 	assert (set != NULL);
   603 	assert (package != NULL);
   604 
   605 	va_start(args, NULL);
   606 	razor_package_get_details_varg (set, package, args);
   607 	va_end (args);
   608 }
   609 
   610 /**
   611  * razor_package_remove:
   612  * @prev: The %razor_set before the current transaction
   613  * @next: The %razor_set after the current transaction is applied
   614  * @package: a %razor_package
   615  * @root: the root into which the package is currently installed
   616  * @install_count: the value to pass to uninstall scripts
   617  * @stage: Limit the removal to just the scripts or the files
   618  *
   619  * Removes an installed package.
   620  **/
   621 RAZOR_EXPORT int
   622 razor_package_remove(struct razor_set *prev, struct razor_set *next,
   623 		     struct razor_atomic *atomic, struct razor_package *package,
   624 		     const char *root_uri, int install_count,
   625 		     enum razor_stage_type stage)
   626 {
   627 	struct razor_file_iterator *fi;
   628 	struct razor_package_iterator *pi;
   629 	struct razor_package *p;
   630 	char *uri, *relative, *buffer, buf[32];
   631 	const char *name, *program, *script;
   632 	int i, count, retval = 0;
   633 	struct environment env;
   634 	struct list *link;
   635 	const char *prefix;
   636 	struct razor_error *tmp_error = NULL;
   637 
   638 	if (stage & RAZOR_STAGE_SCRIPTS) {
   639 		environment_init(&env);
   640 		link = list_first(&package->install_prefixes,
   641 				  &prev->prefix_pool);
   642 		for (i = 0; link; i++) {
   643 			prefix = (const char *)prev->string_pool.data +
   644 				 link->data;
   645 			sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
   646 			environment_add_variable(&env, buf, prefix);
   647 			link = list_next(link);
   648 		}
   649 		environment_set(&env);
   650 	}
   651 
   652 	if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
   653 		razor_package_get_details(prev, package,
   654 					  RAZOR_DETAIL_PREUNPROG, &program,
   655 					  RAZOR_DETAIL_PREUN, &script,
   656 					  RAZOR_DETAIL_LAST);
   657 
   658 		retval = razor_run_script(root_uri, RAZOR_PROPERTY_PREUN,
   659 					  program, script, install_count,
   660 					  &tmp_error);
   661 
   662 		if (retval < 0) {
   663 			razor_atomic_propagate_error(atomic, tmp_error, NULL);
   664 			tmp_error = NULL;
   665 		}
   666 	}
   667 
   668 	if (!retval && (stage & RAZOR_STAGE_FILES)) {
   669 		fi = razor_file_iterator_create(prev, package, 1);
   670 
   671 		while (razor_file_iterator_next(fi, &name)) {
   672 			pi = razor_package_iterator_create_for_file(next, name);
   673 			count = 0;
   674 			while (razor_package_iterator_next(pi, &p,
   675 							   RAZOR_DETAIL_LAST))
   676 				count++;
   677 			razor_package_iterator_destroy(pi);
   678 			if (count <= 0) {
   679 				uri = razor_path_to_uri(name);
   680 
   681 				if (str_has_prefix(uri, "file:///"))
   682 					relative = uri + 8;
   683 				else if (str_has_prefix(uri, "file:/"))
   684 					relative = uri + 6;
   685 				else if (str_has_prefix(uri, "file:"))
   686 					relative = uri + 5;
   687 				else if (str_has_prefix(uri, "/"))
   688 					relative = uri + 1;
   689 				else
   690 					relative = uri;
   691 
   692 				buffer = razor_resolve_uri_root(root_uri,
   693 								relative, 1,
   694 								&tmp_error);
   695 				free(uri);
   696 
   697 				if (buffer) {
   698 					razor_atomic_remove(atomic, buffer);
   699 					free(buffer);
   700 				} else {
   701 					razor_atomic_propagate_error(atomic,
   702 								     tmp_error,
   703 								     NULL);
   704 					tmp_error = NULL;
   705 					break;
   706 				}
   707 			}
   708 		}
   709 
   710 		razor_file_iterator_destroy(fi);
   711 
   712 		retval = razor_atomic_in_error_state(atomic);
   713 	}
   714 
   715 	if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST)) {
   716 		razor_package_get_details(prev, package,
   717 					  RAZOR_DETAIL_POSTUNPROG, &program,
   718 					  RAZOR_DETAIL_POSTUN, &script,
   719 					  RAZOR_DETAIL_LAST);
   720 
   721 		retval |= razor_run_script(root_uri, RAZOR_PROPERTY_POSTUN,
   722 					   program, script, install_count,
   723 					   &tmp_error);
   724 
   725 		if (retval < 0) {
   726 			razor_atomic_propagate_error(atomic, tmp_error, NULL);
   727 			tmp_error = NULL;
   728 		}
   729 	}
   730 
   731 	if (stage & RAZOR_STAGE_SCRIPTS) {
   732 		environment_unset(&env);
   733 		environment_release(&env);
   734 	}
   735 
   736 	return retval;
   737 }
   738 
   739 RAZOR_EXPORT const char *
   740 razor_property_relation_to_string(struct razor_property *p)
   741 {
   742 	assert (p != NULL);
   743 
   744 	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
   745 	case RAZOR_PROPERTY_LESS:
   746 		return "<";
   747 
   748 	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
   749 		return "<=";
   750 
   751 	case RAZOR_PROPERTY_EQUAL:
   752 		return "=";
   753 
   754 	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
   755 		return ">=";
   756 
   757 	case RAZOR_PROPERTY_GREATER:
   758 		return ">";
   759 
   760 	default:
   761 		return "?";
   762 	}
   763 }
   764 
   765 RAZOR_EXPORT const char *
   766 razor_property_type_to_string(struct razor_property *p)
   767 {
   768 	assert (p != NULL);
   769 
   770 	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
   771 	case RAZOR_PROPERTY_REQUIRES:
   772 		return "requires";
   773 	case RAZOR_PROPERTY_PROVIDES:
   774 		return "provides";
   775 	case RAZOR_PROPERTY_CONFLICTS:
   776 		return "conflicts";
   777 	case RAZOR_PROPERTY_OBSOLETES:
   778 		return "obsoletes";
   779 	default:
   780 		return NULL;
   781 	}
   782 }
   783 
   784 RAZOR_EXPORT struct razor_entry *
   785 razor_set_find_entry(struct razor_set *set,
   786 		     struct razor_entry *dir, const char *pattern)
   787 {
   788 	struct razor_entry *e, *subdir;
   789 	const char *n, *pool = set->file_string_pool.data;
   790 	int len;
   791 
   792 	assert (set != NULL);
   793 	assert (pattern != NULL);
   794 
   795 	if (dir == NULL)
   796 		return NULL;
   797 
   798 	e = dir;
   799 	do {
   800 		n = pool + e->name;
   801 		if (strcmp(pattern, n) == 0)
   802 			return e;
   803 		len = strlen(n);
   804 		if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
   805 		    pattern[len] == '/') {
   806 			subdir = (struct razor_entry *) set->files.data +
   807 				 e->start;
   808 			return razor_set_find_entry(set, subdir,
   809 						    pattern + len + 1);
   810 		}
   811 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   812 
   813 	return NULL;
   814 }
   815 
   816 static void
   817 list_dir(struct razor_set *set, struct razor_entry *dir,
   818 	 char *prefix, const char *pattern)
   819 {
   820 	struct razor_entry *e, *subdir;
   821 	const char *n, *pool = set->file_string_pool.data;
   822 
   823 	e = dir;
   824 	do {
   825 		n = pool + e->name;
   826 		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
   827 			continue;
   828 		printf("%s/%s\n", prefix, n);
   829 		if (e->start) {
   830 			char *sub = prefix + strlen (prefix);
   831 			*sub = '/';
   832 			strcpy (sub + 1, n);
   833 			subdir = (struct razor_entry *) set->files.data +
   834 				 e->start;
   835 			list_dir(set, subdir, prefix, pattern);
   836 			*sub = '\0';
   837 		}
   838 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   839 }
   840 
   841 RAZOR_EXPORT void
   842 razor_set_list_files(struct razor_set *set, const char *pattern)
   843 {
   844 	struct razor_entry *root, *e;
   845 	char buffer[512], *p, *base;
   846 
   847 	assert (set != NULL);
   848 
   849 	root = (struct razor_entry *) set->files.data;
   850 
   851 	if (pattern == NULL) {
   852 		p = set->file_string_pool.data;
   853 		e = root;
   854 		do {
   855 			if (e->start) {
   856 				strcpy(buffer, p + e->name);
   857 				list_dir(set, root + e->start, buffer, NULL);
   858 			}
   859 		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   860 		return;
   861 	}
   862 
   863 	strcpy(buffer, pattern);
   864 	e = razor_set_find_entry(set, root, buffer);
   865 	if (e && e->start) {
   866 		base = NULL;
   867 	} else {
   868 		p = strrchr(buffer, '/');
   869 		if (p) {
   870 			*p = '\0';
   871 			base = p + 1;
   872 		} else {
   873 			base = NULL;
   874 		}
   875 	}
   876 	e = razor_set_find_entry(set, root, buffer);
   877 	if (e && e->start)
   878 		list_dir(set, root + e->start, buffer, base);
   879 }
   880 
   881 RAZOR_EXPORT void
   882 razor_set_list_package_files(struct razor_set *set,
   883 			     struct razor_package *package)
   884 {
   885 	struct razor_file_iterator *fi;
   886 	const char *name;
   887 
   888 	assert (set != NULL);
   889 	assert (package != NULL);
   890 
   891 	fi = razor_file_iterator_create(set, package, 0);
   892 
   893 	while (razor_file_iterator_next(fi, &name))
   894 		printf("%s\n", name);
   895 
   896 	razor_file_iterator_destroy(fi);
   897 }
   898 
   899 /*
   900  * Package data can potentially come from two places. The so-called
   901  * metadata (eg., from comps.xml) and from an RPM file. We consider
   902  * a package which has additional data from an RPM file as "fixed".
   903  * If a package needs fixing, then razor_transaction_fixup_package()
   904  * will do so. When considering what packages to add and to remove
   905  * we need to take this into account since we always want to add
   906  * unfixed packages (otherwise we have a potential conflict between
   907  * the existing package data and that present in the RPM).
   908  */
   909 static int
   910 razor_package_is_fixed(struct razor_set *set, struct razor_package *p)
   911 {
   912 	const char *preunprog, *preun, *postunprog, *postun;
   913 
   914 	if (!p)
   915 		return 0;
   916 	razor_package_get_details(set, p,
   917 				  RAZOR_DETAIL_PREUNPROG, &preunprog,
   918 				  RAZOR_DETAIL_PREUN, &preun,
   919 				  RAZOR_DETAIL_POSTUNPROG, &postunprog,
   920 				  RAZOR_DETAIL_POSTUN, &postun,
   921 				  RAZOR_DETAIL_LAST);
   922 	return *preunprog || *preun || *postunprog || *postun;
   923 }
   924 
   925 RAZOR_EXPORT void
   926 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
   927 	       razor_diff_callback_t callback, void *data)
   928 {
   929  	struct razor_package_iterator *pi1, *pi2;
   930  	struct razor_package *p1, *p2;
   931 	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
   932 	int res, is_fixed1, is_fixed2;
   933 
   934 	assert (set != NULL);
   935 	assert (upstream != NULL);
   936 
   937 	pi1 = razor_package_iterator_create(set);
   938 	pi2 = razor_package_iterator_create(upstream);
   939 
   940 	razor_package_iterator_next(pi1, &p1,
   941 				    RAZOR_DETAIL_NAME, &name1,
   942 				    RAZOR_DETAIL_VERSION, &version1,
   943 				    RAZOR_DETAIL_ARCH, &arch1,
   944 				    RAZOR_DETAIL_LAST);
   945 	is_fixed1 = razor_package_is_fixed(set, p1);
   946 	razor_package_iterator_next(pi2, &p2,
   947 				    RAZOR_DETAIL_NAME, &name2,
   948 				    RAZOR_DETAIL_VERSION, &version2,
   949 				    RAZOR_DETAIL_ARCH, &arch2,
   950 				    RAZOR_DETAIL_LAST);
   951 	is_fixed2 = razor_package_is_fixed(upstream, p2);
   952 
   953 	while (p1 || p2) {
   954 		if (p1 && p2) {
   955 			res = strcmp(name1, name2);
   956 			if (res == 0)
   957 				res = razor_versioncmp(version1, version2);
   958 			if (res == 0)
   959 				res = is_fixed1 - is_fixed2;
   960 		} else {
   961 			res = 0;
   962 		}
   963 
   964 		if (p2 == NULL || res < 0)
   965 			callback(RAZOR_DIFF_ACTION_REMOVE,
   966 				 p1, name1, version1, arch1, data);
   967 		else if (p1 == NULL || res > 0)
   968 			callback(RAZOR_DIFF_ACTION_ADD,
   969 				 p2, name2, version2, arch2, data);
   970 
   971 		if (p1 != NULL && res <= 0) {
   972 			razor_package_iterator_next(pi1, &p1,
   973 						    RAZOR_DETAIL_NAME, &name1,
   974 						    RAZOR_DETAIL_VERSION, &version1,
   975 						    RAZOR_DETAIL_ARCH, &arch1,
   976 						    RAZOR_DETAIL_LAST);
   977 			is_fixed1 = razor_package_is_fixed(set, p1);
   978 		}
   979 		if (p2 != NULL && res >= 0) {
   980 			razor_package_iterator_next(pi2, &p2,
   981 						    RAZOR_DETAIL_NAME, &name2,
   982 						    RAZOR_DETAIL_VERSION, &version2,
   983 						    RAZOR_DETAIL_ARCH, &arch2,
   984 						    RAZOR_DETAIL_LAST);
   985 			is_fixed2 = razor_package_is_fixed(upstream, p2);
   986 		}
   987 	}
   988 
   989 	razor_package_iterator_destroy(pi1);
   990 	razor_package_iterator_destroy(pi2);
   991 }
   992 
   993 struct install_action {
   994 	enum razor_install_action action;
   995 	struct razor_package *package;
   996 };
   997 
   998 struct razor_install_iterator {
   999 	struct razor_set *set;
  1000 	struct razor_set *next;
  1001 	struct array actions;
  1002 	struct deque *order, *left;
  1003 };
  1004 
  1005 static void
  1006 add_action(enum razor_diff_action action,
  1007 	   struct razor_package *package,
  1008 	   const char *name,
  1009 	   const char *version,
  1010 	   const char *arch,
  1011 	   void *data)
  1012 {
  1013 	struct razor_install_iterator *ii = data;
  1014 	struct install_action *a;
  1015 
  1016 	a = array_add(&ii->actions, sizeof *a);
  1017 	a->package = package;
  1018 
  1019 	switch (action) {
  1020 	case RAZOR_DIFF_ACTION_ADD:
  1021 		a->action = RAZOR_INSTALL_ACTION_ADD;
  1022 		break;
  1023 	case RAZOR_DIFF_ACTION_REMOVE:
  1024 		a->action = RAZOR_INSTALL_ACTION_REMOVE;
  1025 		break;
  1026 	}
  1027 }
  1028 
  1029 /*
  1030  * Does <package> have a requirement for <script> which is
  1031  * satisfied by <provider> ?
  1032  * Note: We already know that <provider> is to be added as part of this install
  1033  * so there is no need to check the relation.
  1034  */
  1035 static int
  1036 package_script_requires(struct razor_set *set, struct razor_package *package,
  1037 			enum razor_property_flags script,
  1038 			struct razor_package *provider)
  1039 {
  1040 	struct list *link;
  1041 	struct razor_property *prop;
  1042 
  1043 	link = list_first(&package->properties, &set->property_pool);
  1044 	for(; link; link = list_next(link)) {
  1045 		prop = set->properties.data;
  1046 		prop += link->data;
  1047 		if ((prop->flags & RAZOR_PROPERTY_SCRIPT_MASK) & script &&
  1048 		    (prop->flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES &&
  1049 		    provider->name == prop->name)
  1050 			return 1;
  1051 	}
  1052 	return 0;
  1053 }
  1054 
  1055 RAZOR_EXPORT struct razor_install_iterator *
  1056 razor_set_create_install_iterator(struct razor_set *set,
  1057 				  struct razor_set *next)
  1058 {
  1059 	struct razor_install_iterator *ii;
  1060 	struct razor_property *prop;
  1061 	/* A graph of the actions to be perfomed where
  1062 	 * A->B means action A should follow action B.
  1063 	 */
  1064 	struct graph follows;
  1065 	struct install_action *actions, *ai, *aj, *an;
  1066 	int i, j, count, vertex_added;
  1067 	struct list *link;
  1068 	struct razor_set *rs;
  1069 	struct deque *order;
  1070 	int barrier_needed;
  1071 
  1072 	assert (set != NULL);
  1073 	assert (next != NULL);
  1074 
  1075 	ii = zalloc(sizeof *ii);
  1076 	ii->set = set;
  1077 	ii->next = next;
  1078 	
  1079 	razor_set_diff(set, next, add_action, ii);
  1080 
  1081 	actions = ii->actions.data;
  1082 	count = ii->actions.size / sizeof (struct install_action);
  1083 
  1084 	graph_init(&follows);
  1085 
  1086 	for(i = 0; i < count; i++) {
  1087 		ai = actions + i;
  1088 		rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
  1089 		vertex_added = 0;
  1090 		link = list_first(&ai->package->properties, &rs->property_pool);
  1091 		for(; link; link = list_next(link)) {
  1092 			prop = rs->properties.data;
  1093 			prop += link->data;
  1094 			switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
  1095 			case RAZOR_PROPERTY_REQUIRES:
  1096 			case RAZOR_PROPERTY_CONFLICTS:
  1097 				for(j = 0; j < count; j++) {
  1098 					if (j == i)
  1099 						continue;
  1100 					aj = actions + j;
  1101 					if (aj->package->name == prop->name) {
  1102 						if (ai->action ==
  1103 						    RAZOR_INSTALL_ACTION_ADD)
  1104 							graph_add_edge(&follows,
  1105 								       i, j);
  1106 						else
  1107 							graph_add_edge(&follows,
  1108 								       j, i);
  1109 						vertex_added++;
  1110 					}
  1111 				}
  1112 				break;
  1113 			}
  1114 		}
  1115 		if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
  1116 			for(j = 0; j < count; j++) {
  1117 				if (j == i)
  1118 					continue;
  1119 				aj = actions + j;
  1120 				if (aj->package == ai->package &&
  1121 				    aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
  1122 					graph_add_edge(&follows, i, j);
  1123 					vertex_added++;
  1124 				}
  1125 			}
  1126 		}
  1127 		if (!vertex_added)
  1128 			graph_add_edge(&follows, i, i);
  1129 	}
  1130 
  1131 	/*
  1132 	 * Because files are installed and removed using razor_atomic,
  1133 	 * but scripts are run with no regard for these, we need some
  1134 	 * means for synchronisation between the two. We support this
  1135 	 * via transaction barriers which are points where
  1136 	 * razor_atomic_commit() should be called so that scripts can
  1137 	 * rely on the files they need being present.
  1138 	 *
  1139 	 * Rules:
  1140 	 *   1)	Transaction barriers never occur within a dependency
  1141 	 *	loop. Since we can't guarantee any ordering of actions
  1142 	 *	within such a loop, they make no sense.
  1143 	 *   2) Otherwise the following table applies:
  1144 	 *	Action I    Action J	Barrier between I and J iff
  1145 	 *	ADD P	    ADD Q	%pre(Q) requires P
  1146 	 *	ADD P	    REMOVE Q	%preun(Q) requires P
  1147 	 *	REMOVE P    ADD Q	never
  1148 	 *	REMOVE P    REMOVE Q	%postun(P) requires Q
  1149 	 *
  1150 	 * FIXME:
  1151 	 *	This should take account of conflicts somehow.
  1152 	 */
  1153 	order = graph_sort(&follows);
  1154 	ii->order = deque_new(0);
  1155 	if (!deque_empty(order)) {
  1156 		j = deque_pop(order);
  1157 		deque_unshift(ii->order, j);
  1158 	}
  1159 	while (!deque_empty(order)) {
  1160 		i = j;
  1161 		j = deque_pop(order);
  1162 		ai = actions + i;
  1163 		aj = actions + j;
  1164 		if (graph_is_connected(&follows, i, j) &&
  1165 		    graph_is_connected(&follows, j, i))
  1166 			barrier_needed = 0;
  1167 		else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
  1168 			 aj->action == RAZOR_INSTALL_ACTION_ADD &&
  1169 			 package_script_requires(next, aj->package,
  1170 						 RAZOR_PROPERTY_PRE,
  1171 						 ai->package))
  1172 			barrier_needed = 1;
  1173 		else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
  1174 			 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
  1175 			 package_script_requires(set, aj->package,
  1176 						 RAZOR_PROPERTY_PREUN,
  1177 						 ai->package))
  1178 			barrier_needed = 1;
  1179 		else if (ai->action == RAZOR_INSTALL_ACTION_REMOVE &&
  1180 			 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
  1181 			 package_script_requires(set, ai->package,
  1182 						 RAZOR_PROPERTY_POSTUN,
  1183 						 aj->package))
  1184 			barrier_needed = 1;
  1185 		else
  1186 			barrier_needed = 0;
  1187 		if (barrier_needed) {
  1188 			an = array_add(&ii->actions, sizeof *an);
  1189 			actions = ii->actions.data;
  1190 			an->package = NULL;
  1191 			an->action = RAZOR_INSTALL_ACTION_COMMIT;
  1192 			deque_unshift(ii->order, an - actions);
  1193 		}
  1194 		deque_unshift(ii->order, j);
  1195 	}
  1196 	deque_free(order);
  1197 
  1198 	ii->left = deque_dup(ii->order);
  1199 	graph_release(&follows);
  1200 
  1201 	return ii;
  1202 }
  1203 
  1204 RAZOR_EXPORT int
  1205 razor_install_iterator_next(struct razor_install_iterator *ii,
  1206 			    struct razor_package **package,
  1207 			    enum razor_install_action *action,
  1208 			    int *count)
  1209 {
  1210 	struct install_action *a;
  1211 	struct razor_package_iterator *pi;
  1212 	struct razor_package *pkg;
  1213 	const char *removing, *name;
  1214 
  1215 	if (deque_empty(ii->left))
  1216 		return 0;
  1217 
  1218 	a = (struct install_action *)ii->actions.data + deque_pop(ii->left);
  1219 	*package = a->package;
  1220 	*action = a->action;
  1221 	*count = 0;
  1222 
  1223 	if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
  1224 		razor_package_get_details(ii->set, a->package,
  1225 					  RAZOR_DETAIL_NAME, &removing,
  1226 					  RAZOR_DETAIL_LAST);
  1227 
  1228 		pi = razor_package_iterator_create(ii->next);
  1229 		while (razor_package_iterator_next(pi, &pkg,
  1230 						   RAZOR_DETAIL_NAME, &name,
  1231 						   RAZOR_DETAIL_LAST)) {
  1232 			if (!strcmp(name, removing))
  1233 				(*count)++;
  1234 		}
  1235 		razor_package_iterator_destroy(pi);
  1236 	} else if (a->action == RAZOR_INSTALL_ACTION_ADD)
  1237 		*count = 1;
  1238 
  1239 	return 1;
  1240 }
  1241 
  1242 static int
  1243 action_is_included(struct razor_install_iterator *ii, struct deque *done,
  1244 		   struct razor_package *package,
  1245 		   enum razor_install_action action)
  1246 {
  1247 	struct deque *t;
  1248 	struct install_action *a;
  1249 	int retval;
  1250 
  1251 	t = deque_dup(done);
  1252 
  1253 	while(!deque_empty(t)) {
  1254 		a = (struct install_action *)ii->actions.data + deque_pop(t);
  1255 		if (a->package == package && a->action == action)
  1256 			break;
  1257 	}
  1258 	retval = !deque_empty(t);
  1259 
  1260 	deque_free(t);
  1261 
  1262 	return retval;
  1263 }
  1264 
  1265 RAZOR_EXPORT struct razor_set *
  1266 razor_install_iterator_commit_set(struct razor_install_iterator *ii)
  1267 {
  1268 	struct razor_merger *merger;
  1269 	struct razor_set *set;
  1270 	struct razor_package *n, *nend, *s, *send;
  1271 	struct deque *done;
  1272 	size_t pos;
  1273 	char *npool, *spool;
  1274 	int cmp;
  1275 
  1276 	done = deque_dup(ii->order);
  1277 	pos = razor_install_iterator_tell(ii);
  1278 	while(deque_length(done) > pos)
  1279 		deque_shift(done);
  1280 
  1281 	s = ii->set->packages.data;
  1282 	send = ii->set->packages.data + ii->set->packages.size;
  1283 	spool = ii->set->string_pool.data;
  1284 
  1285 	n = ii->next->packages.data;
  1286 	nend = ii->next->packages.data + ii->next->packages.size;
  1287 	npool = ii->next->string_pool.data;
  1288 
  1289 	merger = razor_merger_create(ii->set, ii->next);
  1290 	while (s < send || n < nend) {
  1291 		if (s < send && n < nend)
  1292 			cmp = strcmp(&spool[s->name], &npool[n->name]);
  1293 		else if (s < send)
  1294 			cmp = -1;
  1295 		else
  1296 			cmp = 1;
  1297 
  1298 		if (cmp < 0) {
  1299 			if (!action_is_included(ii, done, s,
  1300 						RAZOR_INSTALL_ACTION_REMOVE))
  1301 				razor_merger_add_package(merger, s);
  1302 			s++;
  1303 		} else if (cmp == 0) {
  1304 			if (!action_is_included(ii, done, s,
  1305 						RAZOR_INSTALL_ACTION_REMOVE))
  1306 				razor_merger_add_package(merger, s);
  1307 			if (action_is_included(ii, done, n,
  1308 					       RAZOR_INSTALL_ACTION_ADD))
  1309 				razor_merger_add_package(merger, n);
  1310 
  1311 			s++;
  1312 			n++;
  1313 		} else {
  1314 			if (action_is_included(ii, done, n,
  1315 					       RAZOR_INSTALL_ACTION_ADD))
  1316 				razor_merger_add_package(merger, n);
  1317 			n++;
  1318 		}
  1319 	}
  1320 
  1321 	set = razor_merger_commit(merger);
  1322 	razor_merger_destroy(merger);
  1323 	deque_free(done);
  1324 
  1325 	return set;
  1326 }
  1327 
  1328 RAZOR_EXPORT void
  1329 razor_install_iterator_rewind(struct razor_install_iterator *ii)
  1330 {
  1331 	deque_free(ii->left);
  1332 	ii->left=deque_dup(ii->order);
  1333 }
  1334 
  1335 RAZOR_EXPORT size_t
  1336 razor_install_iterator_tell(struct razor_install_iterator *ii)
  1337 {
  1338 	return deque_length(ii->order) - deque_length(ii->left);
  1339 }
  1340 
  1341 RAZOR_EXPORT size_t
  1342 razor_install_iterator_seek(struct razor_install_iterator *ii, size_t pos)
  1343 {
  1344 	size_t current_pos;
  1345 
  1346 	if (pos > deque_length(ii->order))
  1347 		pos = deque_length(ii->order);
  1348 
  1349 	current_pos = razor_install_iterator_tell(ii);
  1350 
  1351 	if (pos < current_pos) {
  1352 		razor_install_iterator_rewind(ii);
  1353 		current_pos = 0;
  1354 	}
  1355 
  1356 	while(current_pos < pos) {
  1357 		(void) deque_pop(ii->left);
  1358 		current_pos++;
  1359 	}
  1360 
  1361 	return current_pos;
  1362 }
  1363 
  1364 RAZOR_EXPORT void
  1365 razor_install_iterator_destroy(struct razor_install_iterator *ii)
  1366 {
  1367 	array_release(&ii->actions);
  1368 	deque_free(ii->order);
  1369 	deque_free(ii->left);
  1370 	free(ii);
  1371 }