librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Aug 23 11:13:48 2014 +0100 (2014-08-23)
changeset 440 48204dea0b9f
parent 422 6fa783097ca1
child 442 c4bcba8023a9
permissions -rw-r--r--
Remove INTLLIBS from librazor_la_LIBADD.

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