librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Oct 09 17:27:41 2014 +0100 (2014-10-09)
changeset 455 df914f383f5c
parent 442 c4bcba8023a9
child 458 3f841a46eab5
permissions -rw-r--r--
Support downloading from local repository even without libcurl

Using the --url option of the razor executable, it is possible
to specify a yum repository on the local machine (eg., on installation
media) and import from there, eg.,:

C> razor --url file:///d:/ import-yum

This will be handled by libcurl if available but if not, an internal
copy routine will be used.

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