librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 28 11:59:02 2010 +0100 (2010-04-28)
changeset 395 ed134fdfe95f
parent 390 297c6c8be2d1
child 403 e63951c1d0f8
permissions -rw-r--r--
Treat missing detail strings as empty
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2010  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 void *
    52 zalloc(size_t size)
    53 {
    54 	void *p;
    55 
    56 	p = malloc(size);
    57 	memset(p, 0, size);
    58 
    59 	return p;
    60 }
    61 
    62 struct razor_set_section_index {
    63 	const char *name;
    64 	uint32_t offset;
    65 	uint32_t flags;
    66 };
    67 
    68 #define MAIN(type, field) \
    69 	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
    70 #define FILES(type, field) \
    71 	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
    72 #define DETAILS(type, field) \
    73 	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
    74 
    75 struct razor_set_section_index razor_sections[] = {
    76 	MAIN(RAZOR_STRING_POOL, string_pool),
    77 	MAIN(RAZOR_PACKAGES, packages),
    78 	MAIN(RAZOR_PROPERTIES, properties),
    79 	MAIN(RAZOR_PACKAGE_POOL, package_pool),
    80 	MAIN(RAZOR_PROPERTY_POOL, property_pool),
    81 	MAIN(RAZOR_PREFIX_POOL, prefix_pool),
    82 	FILES(RAZOR_FILES, files),
    83 	FILES(RAZOR_FILE_POOL, file_pool),
    84 	FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
    85 	DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
    86 };
    87 
    88 RAZOR_EXPORT struct razor_set *
    89 razor_set_create_without_root(void)
    90 {
    91 	struct razor_set *set;
    92 	char *empty;
    93 
    94 	set = zalloc(sizeof *set);
    95 
    96 	empty = array_add(&set->string_pool, 1);
    97 	*empty = '\0';
    98 
    99 	set->lock_fd = -1;
   100 
   101 	return set;
   102 }
   103 
   104 RAZOR_EXPORT struct razor_set *
   105 razor_set_create(void)
   106 {
   107 	struct razor_set *set;
   108 	struct razor_entry *e;
   109 
   110 	set = razor_set_create_without_root();
   111 
   112 	e = array_add(&set->files, sizeof *e);
   113 	e->name = 0;
   114 	e->flags = RAZOR_ENTRY_LAST;
   115 	e->start = 0;
   116 	list_set_empty(&e->packages);
   117 
   118 	return set;
   119 }
   120 
   121 struct razor_mapped_file {
   122 	struct razor_set_header *header;
   123 	size_t size;
   124 	struct razor_mapped_file *next;
   125 };
   126 
   127 RAZOR_EXPORT int
   128 razor_set_bind_sections(struct razor_set *set, const char *filename)
   129 {
   130 	struct razor_set_section *s, *sections;
   131 	struct razor_mapped_file *file;
   132 	const char *pool;
   133 	struct array *array;
   134 	int i, j;
   135 
   136 	file = zalloc(sizeof *file);
   137 	if (file == NULL)
   138 		return -1;
   139 
   140 	file->header = razor_file_get_contents(filename, &file->size);
   141 	if (!file->header) {
   142 		free(file);
   143 		return -1;
   144 	}
   145 
   146 	if (file->size < sizeof *file->header ||
   147 	    file->header->magic != RAZOR_MAGIC ||
   148 	    file->header->version != RAZOR_VERSION) {
   149 		razor_file_free_contents(file->header, file->size);
   150 		free(file);
   151 		return -1;
   152 	}
   153 
   154 	if (set->mapped_files == NULL) {
   155 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   156 			array = (void *) set + razor_sections[i].offset;
   157 			array_release(array);
   158 		}
   159 	}
   160 
   161 	file->next = set->mapped_files;
   162 	set->mapped_files = file;
   163 
   164 	sections = (void *) file->header + sizeof *file->header;
   165 	pool = (void *) sections +
   166 		file->header->num_sections * sizeof *sections;
   167 
   168 	for (i = 0; i < file->header->num_sections; i++) {
   169 		s = sections + i;
   170 		for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
   171 			if (!strcmp(razor_sections[j].name, &pool[s->name]))
   172 				break;
   173 		if (j == ARRAY_SIZE(razor_sections))
   174 			continue;
   175 		array = (void *) set + razor_sections[j].offset;
   176 		array->data = (void *) file->header + s->offset;
   177 		array->size = s->size;
   178 		array->alloc = s->size;
   179 	}
   180 
   181 	return 0;
   182 }
   183 
   184 RAZOR_EXPORT struct razor_set *
   185 razor_set_open(const char *filename)
   186 {
   187 	struct razor_set *set;
   188 
   189 	set = zalloc(sizeof *set);
   190 	set->lock_fd = -1;
   191 	if (razor_set_bind_sections(set, filename)){
   192 		free(set);
   193 		return NULL;
   194 	}
   195 	return set;
   196 }
   197 
   198 int
   199 razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive)
   200 {
   201 	int fd;
   202 	assert(set != NULL);
   203 
   204 	if (path) {
   205 		fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0666);
   206 		if (fd < 0)
   207 			return -1;
   208 	} else {
   209 		fd = -1;
   210 	}
   211 
   212 #ifdef MSWIN_API
   213 	DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
   214 	OVERLAPPED lock = {0};
   215 
   216 	if (exclusive)
   217 		flags |= LOCKFILE_EXCLUSIVE_LOCK;
   218 	if (fd >= 0 && !LockFileEx(_get_osfhandle(fd), flags, 0, 1, 0, &lock)) {
   219 		close(fd);
   220 		return -1;
   221 	}
   222 	if (set->lock_fd >= 0)
   223 		(void)UnlockFile(_get_osfhandle(set->lock_fd), 0, 0, 1, 0);
   224 #else
   225 	struct flock lock = {0};
   226 
   227 	lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
   228 	lock.l_whence = SEEK_SET;
   229 	lock.l_start = 0;
   230 	lock.l_len = 0;
   231 	if (fd >= 0 && fcntl(fd, F_SETLK, &lock) < 0) {
   232 		close(fd);
   233 		return -1;
   234 	}
   235 	if (set->lock_fd >= 0) {
   236 		lock.l_type = F_UNLCK;
   237 		(void)fcntl(set->lock_fd, F_SETLK, &lock);
   238 	}
   239 #endif
   240 
   241 	if (set->lock_fd >= 0)
   242 		close(set->lock_fd);
   243 	set->lock_fd = fd;
   244 
   245 	return 0;
   246 }
   247 
   248 RAZOR_EXPORT void
   249 razor_set_destroy(struct razor_set *set)
   250 {
   251 	struct razor_mapped_file *file, *next;
   252 	struct array *array;
   253 	int i;
   254 
   255 	assert (set != NULL);
   256 
   257 	if (set->mapped_files == NULL) {
   258 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   259 			array = (void *) set + razor_sections[i].offset;
   260 			array_release(array);
   261 		}
   262 	} else {
   263 		for (file = set->mapped_files; file != NULL; file = next) {
   264 			next = file->next;
   265 			razor_file_free_contents(file->header, file->size);
   266 			free(file);
   267 		}
   268 	}
   269 
   270 	razor_set_aquire_lock(set, NULL, 0);
   271 	free(set);
   272 }
   273 
   274 RAZOR_EXPORT int
   275 razor_set_write_to_fd(struct razor_set *set, int fd, uint32_t section_mask)
   276 {
   277 	struct razor_set_header header;
   278 	struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
   279 	struct hashtable table;
   280 	struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
   281 	uint32_t offset;
   282 	int count, i, j;
   283 	static const char padding[4];
   284 
   285 	array_init(&pool);
   286 	hashtable_init(&table, &pool);
   287 
   288 	j = 0;
   289 	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   290 		if ((razor_sections[i].flags & section_mask) == 0)
   291 			continue;
   292 
   293 		arrays[j] = (void *) set + razor_sections[i].offset;
   294 		sections[j].name =
   295 			hashtable_tokenize(&table, razor_sections[i].name);
   296 		j++;
   297 	}
   298 
   299 	count = j;
   300 	header.magic = RAZOR_MAGIC;
   301 	header.version = RAZOR_VERSION;
   302 	header.num_sections = count;
   303 	offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
   304 
   305 	for (i = 0; i < count; i++) {
   306 		sections[i].offset = offset;
   307 		sections[i].size = arrays[i]->size;
   308 		offset += ALIGN(arrays[i]->size, 4);
   309 	}
   310 
   311 	razor_write(fd, &header, sizeof header);
   312 	razor_write(fd, sections, count * sizeof *sections);
   313 	razor_write(fd, pool.data, pool.size);
   314 	razor_write(fd, padding, PADDING(pool.size, 4));
   315 
   316 	for (i = 0; i < count; i++) {
   317 		razor_write(fd, arrays[i]->data, arrays[i]->size);
   318 		razor_write(fd, padding, PADDING(arrays[i]->size, 4));
   319 	}
   320 
   321 	array_release(&pool);
   322 	hashtable_release(&table);
   323 
   324 	return 0;
   325 }
   326 
   327 RAZOR_EXPORT int
   328 razor_set_write(struct razor_set *set, const char *filename, uint32_t sections)
   329 {
   330 	int fd, status;
   331 
   332 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
   333 	if (fd < 0)
   334 		return -1;
   335 
   336 	status = razor_set_write_to_fd(set, fd, sections);
   337 	if (status) {
   338 	    close(fd);
   339 	    return status;
   340 	}
   341 
   342 	return close(fd);
   343 }
   344 
   345 RAZOR_EXPORT void
   346 razor_build_evr(char *evr_buf, int size, const char *epoch,
   347 		const char *version, const char *release)
   348 {
   349 	int len;
   350 
   351 	if (!version || !*version) {
   352 		*evr_buf = '\0';
   353 		return;
   354 	}
   355 
   356 	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
   357 		len = snprintf(evr_buf, size, "%s:", epoch);
   358 		evr_buf += len;
   359 		size -= len;
   360 	}
   361 	len = snprintf(evr_buf, size, "%s", version);
   362 	evr_buf += len;
   363 	size -= len;
   364 	if (release && *release)
   365 		snprintf(evr_buf, size, "-%s", release);
   366 }
   367 
   368 RAZOR_EXPORT int
   369 razor_versioncmp(const char *s1, const char *s2)
   370 {
   371 	const char *p1, *p2;
   372 	long n1, n2;
   373 	int res;
   374 
   375 	assert (s1 != NULL);
   376 	assert (s2 != NULL);
   377 
   378 	n1 = strtol(s1, (char **) &p1, 10);
   379 	n2 = strtol(s2, (char **) &p2, 10);
   380 
   381 	/* Epoch; if one but not the other has an epoch set, default
   382 	 * the epoch-less version to 0. */
   383 	res = (*p1 == ':') - (*p2 == ':');
   384 	if (res < 0) {
   385 		n1 = 0;
   386 		p1 = s1;
   387 		p2++;
   388 	} else if (res > 0) {
   389 		p1++;
   390 		n2 = 0;
   391 		p2 = s2;
   392 	}
   393 
   394 	if (n1 != n2)
   395 		return n1 - n2;
   396 	while (*p1 && *p2) {
   397 		if (*p1 != *p2)
   398 			return *p1 - *p2;
   399 		p1++;
   400 		p2++;
   401 		if (isdigit(*p1) && isdigit(*p2))
   402 			return razor_versioncmp(p1, p2);
   403 	}
   404 
   405 	return *p1 - *p2;
   406 }
   407 
   408 static const char *
   409 razor_package_get_details_string(struct razor_set *set,
   410 				 struct razor_package *package,
   411 				 enum razor_detail_type type)
   412 {
   413 	const char *pool;
   414 
   415 	switch (type) {
   416 	case RAZOR_DETAIL_NAME:
   417 		pool = set->string_pool.data;
   418 		return &pool[package->name];
   419 
   420 	case RAZOR_DETAIL_VERSION:
   421 		pool = set->string_pool.data;
   422 		return &pool[package->version];
   423 
   424 	case RAZOR_DETAIL_ARCH:
   425 		pool = set->string_pool.data;
   426 		return &pool[package->arch];
   427 
   428 	case RAZOR_DETAIL_SUMMARY:
   429 		if (!set->details_string_pool.size)
   430 			return "";
   431 		pool = set->details_string_pool.data;
   432 		return &pool[package->summary];
   433 
   434 	case RAZOR_DETAIL_DESCRIPTION:
   435 		if (!set->details_string_pool.size)
   436 			return "";
   437 		pool = set->details_string_pool.data;
   438 		return &pool[package->description];
   439 
   440 	case RAZOR_DETAIL_URL:
   441 		if (!set->details_string_pool.size)
   442 			return "";
   443 		pool = set->details_string_pool.data;
   444 		return &pool[package->url];
   445 
   446 	case RAZOR_DETAIL_LICENSE:
   447 		if (!set->details_string_pool.size)
   448 			return "";
   449 		pool = set->details_string_pool.data;
   450 		return &pool[package->license];
   451 
   452 	case RAZOR_DETAIL_PREUNPROG:
   453 		pool = set->string_pool.data;
   454 		return &pool[package->preun.program];
   455 
   456 	case RAZOR_DETAIL_PREUN:
   457 		pool = set->string_pool.data;
   458 		return &pool[package->preun.body];
   459 
   460 	case RAZOR_DETAIL_POSTUNPROG:
   461 		pool = set->string_pool.data;
   462 		return &pool[package->postun.program];
   463 
   464 	case RAZOR_DETAIL_POSTUN:
   465 		pool = set->string_pool.data;
   466 		return &pool[package->postun.body];
   467 
   468 	default:
   469 		fprintf(stderr, "type %u not found\n", type);
   470 		return NULL;
   471 	}
   472 }
   473 
   474 static const char *const *
   475 razor_package_get_details_array(struct razor_set *set,
   476 				struct razor_package *package,
   477 				enum razor_detail_type type)
   478 {
   479 	switch (type) {
   480 	case RAZOR_DETAIL_PREFIXES:
   481 		/* We don't track prefixes in packages. Install prefixes
   482 		 * are tracked, but we don't provide an API to get them.
   483 		 */
   484 		return NULL;
   485 
   486 	default:
   487 		fprintf(stderr, "type %u not found\n", type);
   488 		return NULL;
   489 	}
   490 }
   491 
   492 /**
   493  * razor_package_get_details_varg:
   494  * @set: a %razor_set
   495  * @package: a %razor_package
   496  * @args: a va_list of arguments to set
   497  **/
   498 void
   499 razor_package_get_details_varg(struct razor_set *set,
   500 			       struct razor_package *package,
   501 			       va_list args)
   502 {
   503 	int i;
   504 	enum razor_detail_type type;
   505 	const char **string;
   506 	const char *const **array;
   507 
   508 	for (i = 0;; i += 2) {
   509 		type = va_arg(args, enum razor_detail_type);
   510 		if (type == RAZOR_DETAIL_LAST)
   511 			break;
   512 		if (type == RAZOR_DETAIL_PREFIXES) {
   513 			array = va_arg(args, const char *const **);
   514 			*array = razor_package_get_details_array(set, package,
   515 								 type);
   516 		} else {
   517 			string = va_arg(args, const char **);
   518 			*string = razor_package_get_details_string(set, package,
   519 								   type);
   520 		}
   521 	}
   522 
   523 }
   524 
   525 /**
   526  * razor_package_get_details:
   527  * @set: a %razor_set
   528  * @package: a %razor_package
   529  *
   530  * Gets details about a package using a varg interface
   531  * The vararg must be terminated with %RAZOR_DETAIL_LAST.
   532  *
   533  * Example: razor_package_get_details (set, package,
   534  *				       RAZOR_DETAIL_URL, &url,
   535  *				       RAZOR_DETAIL_LAST);
   536  **/
   537 RAZOR_EXPORT void
   538 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
   539 {
   540 	va_list args;
   541 
   542 	assert (set != NULL);
   543 	assert (package != NULL);
   544 
   545 	va_start(args, NULL);
   546 	razor_package_get_details_varg (set, package, args);
   547 	va_end (args);
   548 }
   549 
   550 /**
   551  * razor_package_remove:
   552  * @prev: The %razor_set before the current transaction
   553  * @next: The %razor_set after the current transaction is applied
   554  * @package: a %razor_package
   555  * @root: the root into which the package is currently installed
   556  * @install_count: the value to pass to uninstall scripts
   557  *
   558  * Removes an installed package.
   559  **/
   560 RAZOR_EXPORT int
   561 razor_package_remove(struct razor_set *prev, struct razor_set *next,
   562 		     struct razor_package *package, const char *root,
   563 		     int install_count)
   564 {
   565 	struct razor_file_iterator *fi;
   566 	struct razor_package_iterator *pi;
   567 	struct razor_package *p;
   568 	char buffer[PATH_MAX];
   569 	const char *name, *program, *script;
   570 	int retval = 0, i, count;
   571 	struct environment env;
   572 	struct list *link;
   573 	const char *prefix;
   574 
   575 	environment_init(&env);
   576 	link = list_first(&package->install_prefixes, &prev->prefix_pool);
   577 	for (i = 0; link; i++) {
   578 		prefix = (const char *)prev->string_pool.data + link->data;
   579 		sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
   580 		environment_add_variable(&env, buffer, prefix);
   581 		link = list_next(link);
   582 	}
   583 	environment_set(&env);
   584 
   585 	razor_package_get_details(prev, package,
   586 				  RAZOR_DETAIL_PREUNPROG, &program,
   587 				  RAZOR_DETAIL_PREUN, &script,
   588 				  RAZOR_DETAIL_LAST);
   589 
   590 	retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program, script,
   591 				  install_count);
   592 
   593 	fi = razor_file_iterator_create(prev, package, 1);
   594 
   595 	while (razor_file_iterator_next(fi, &name)) {
   596 		pi = razor_package_iterator_create_for_file(next, name);
   597 		count = 0;
   598 		while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_LAST))
   599 			count++;
   600 		razor_package_iterator_destroy(pi);
   601 		if (count <= 0) {
   602 			snprintf(buffer, sizeof buffer, "%s%s", root, name);
   603 			if (razor_remove(buffer) && errno != ENOENT) {
   604 				perror(name);
   605 				retval = -1;
   606 			}
   607 		}
   608 	}
   609 
   610 	razor_file_iterator_destroy(fi);
   611 
   612 	razor_package_get_details(prev, package,
   613 				  RAZOR_DETAIL_POSTUNPROG, &program,
   614 				  RAZOR_DETAIL_POSTUN, &script,
   615 				  RAZOR_DETAIL_LAST);
   616 
   617 	if (razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script,
   618 			     install_count))
   619 		retval = -1;
   620 
   621 	environment_unset(&env);
   622 	environment_release(&env);
   623 
   624 	return retval;
   625 }
   626 
   627 RAZOR_EXPORT const char *
   628 razor_property_relation_to_string(struct razor_property *p)
   629 {
   630 	assert (p != NULL);
   631 
   632 	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
   633 	case RAZOR_PROPERTY_LESS:
   634 		return "<";
   635 
   636 	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
   637 		return "<=";
   638 
   639 	case RAZOR_PROPERTY_EQUAL:
   640 		return "=";
   641 
   642 	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
   643 		return ">=";
   644 
   645 	case RAZOR_PROPERTY_GREATER:
   646 		return ">";
   647 
   648 	default:
   649 		return "?";
   650 	}
   651 }
   652 
   653 RAZOR_EXPORT const char *
   654 razor_property_type_to_string(struct razor_property *p)
   655 {
   656 	assert (p != NULL);
   657 
   658 	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
   659 	case RAZOR_PROPERTY_REQUIRES:
   660 		return "requires";
   661 	case RAZOR_PROPERTY_PROVIDES:
   662 		return "provides";
   663 	case RAZOR_PROPERTY_CONFLICTS:
   664 		return "conflicts";
   665 	case RAZOR_PROPERTY_OBSOLETES:
   666 		return "obsoletes";
   667 	default:
   668 		return NULL;
   669 	}
   670 }
   671 
   672 RAZOR_EXPORT struct razor_entry *
   673 razor_set_find_entry(struct razor_set *set,
   674 		     struct razor_entry *dir, const char *pattern)
   675 {
   676 	struct razor_entry *e, *subdir;
   677 	const char *n, *pool = set->file_string_pool.data;
   678 	int len;
   679 
   680 	assert (set != NULL);
   681 	assert (pattern != NULL);
   682 
   683 	if (dir == NULL)
   684 		return NULL;
   685 
   686 	e = dir;
   687 	do {
   688 		n = pool + e->name;
   689 		if (strcmp(pattern, n) == 0)
   690 			return e;
   691 		len = strlen(n);
   692 		if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
   693 		    pattern[len] == '/') {
   694 			subdir = (struct razor_entry *) set->files.data +
   695 				 e->start;
   696 			return razor_set_find_entry(set, subdir,
   697 						    pattern + len + 1);
   698 		}
   699 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   700 
   701 	return NULL;
   702 }
   703 
   704 static void
   705 list_dir(struct razor_set *set, struct razor_entry *dir,
   706 	 char *prefix, const char *pattern)
   707 {
   708 	struct razor_entry *e, *subdir;
   709 	const char *n, *pool = set->file_string_pool.data;
   710 
   711 	e = dir;
   712 	do {
   713 		n = pool + e->name;
   714 		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
   715 			continue;
   716 		printf("%s/%s\n", prefix, n);
   717 		if (e->start) {
   718 			char *sub = prefix + strlen (prefix);
   719 			*sub = '/';
   720 			strcpy (sub + 1, n);
   721 			subdir = (struct razor_entry *) set->files.data +
   722 				 e->start;
   723 			list_dir(set, subdir, prefix, pattern);
   724 			*sub = '\0';
   725 		}
   726 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   727 }
   728 
   729 RAZOR_EXPORT void
   730 razor_set_list_files(struct razor_set *set, const char *pattern)
   731 {
   732 	struct razor_entry *root, *e;
   733 	char buffer[512], *p, *base;
   734 
   735 	assert (set != NULL);
   736 
   737 	root = (struct razor_entry *) set->files.data;
   738 
   739 	if (pattern == NULL) {
   740 		p = set->file_string_pool.data;
   741 		e = root;
   742 		do {
   743 			if (e->start) {
   744 				strcpy(buffer, p + e->name);
   745 				list_dir(set, root + e->start, buffer, NULL);
   746 			}
   747 		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   748 		return;
   749 	}
   750 
   751 	strcpy(buffer, pattern);
   752 	e = razor_set_find_entry(set, root, buffer);
   753 	if (e && e->start) {
   754 		base = NULL;
   755 	} else {
   756 		p = strrchr(buffer, '/');
   757 		if (p) {
   758 			*p = '\0';
   759 			base = p + 1;
   760 		} else {
   761 			base = NULL;
   762 		}
   763 	}
   764 	e = razor_set_find_entry(set, root, buffer);
   765 	if (e && e->start)
   766 		list_dir(set, root + e->start, buffer, base);
   767 }
   768 
   769 RAZOR_EXPORT void
   770 razor_set_list_package_files(struct razor_set *set,
   771 			     struct razor_package *package)
   772 {
   773 	struct razor_file_iterator *fi;
   774 	const char *name;
   775 
   776 	assert (set != NULL);
   777 	assert (package != NULL);
   778 
   779 	fi = razor_file_iterator_create(set, package, 0);
   780 
   781 	while (razor_file_iterator_next(fi, &name))
   782 		printf("%s\n", name);
   783 
   784 	razor_file_iterator_destroy(fi);
   785 }
   786 
   787 /*
   788  * Package data can potentially come from two places. The so-called
   789  * metadata (eg., from comps.xml) and from an RPM file. We consider
   790  * a package which has additional data from an RPM file as "fixed".
   791  * If a package needs fixing, then razor_transaction_fixup_package()
   792  * will do so. When considering what packages to add and to remove
   793  * we need to take this into account since we always want to add
   794  * unfixed packages (otherwise we have a potential conflict between
   795  * the existing package data and that present in the RPM).
   796  */
   797 static int
   798 razor_package_is_fixed(struct razor_set *set, struct razor_package *p)
   799 {
   800 	const char *preunprog, *preun, *postunprog, *postun;
   801 
   802 	if (!p)
   803 		return 0;
   804 	razor_package_get_details(set, p,
   805 				  RAZOR_DETAIL_PREUNPROG, &preunprog,
   806 				  RAZOR_DETAIL_PREUN, &preun,
   807 				  RAZOR_DETAIL_POSTUNPROG, &postunprog,
   808 				  RAZOR_DETAIL_POSTUN, &postun,
   809 				  RAZOR_DETAIL_LAST);
   810 	return *preunprog || *preun || *postunprog || *postun;
   811 }
   812 
   813 RAZOR_EXPORT void
   814 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
   815 	       razor_diff_callback_t callback, void *data)
   816 {
   817  	struct razor_package_iterator *pi1, *pi2;
   818  	struct razor_package *p1, *p2;
   819 	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
   820 	int res, is_fixed1, is_fixed2;
   821 
   822 	assert (set != NULL);
   823 	assert (upstream != NULL);
   824 
   825 	pi1 = razor_package_iterator_create(set);
   826 	pi2 = razor_package_iterator_create(upstream);
   827 
   828 	razor_package_iterator_next(pi1, &p1,
   829 				    RAZOR_DETAIL_NAME, &name1,
   830 				    RAZOR_DETAIL_VERSION, &version1,
   831 				    RAZOR_DETAIL_ARCH, &arch1,
   832 				    RAZOR_DETAIL_LAST);
   833 	is_fixed1 = razor_package_is_fixed(set, p1);
   834 	razor_package_iterator_next(pi2, &p2,
   835 				    RAZOR_DETAIL_NAME, &name2,
   836 				    RAZOR_DETAIL_VERSION, &version2,
   837 				    RAZOR_DETAIL_ARCH, &arch2,
   838 				    RAZOR_DETAIL_LAST);
   839 	is_fixed2 = razor_package_is_fixed(upstream, p2);
   840 
   841 	while (p1 || p2) {
   842 		if (p1 && p2) {
   843 			res = strcmp(name1, name2);
   844 			if (res == 0)
   845 				res = razor_versioncmp(version1, version2);
   846 			if (res == 0)
   847 				res = is_fixed1 - is_fixed2;
   848 		} else {
   849 			res = 0;
   850 		}
   851 
   852 		if (p2 == NULL || res < 0)
   853 			callback(RAZOR_DIFF_ACTION_REMOVE,
   854 				 p1, name1, version1, arch1, data);
   855 		else if (p1 == NULL || res > 0)
   856 			callback(RAZOR_DIFF_ACTION_ADD,
   857 				 p2, name2, version2, arch2, data);
   858 
   859 		if (p1 != NULL && res <= 0) {
   860 			razor_package_iterator_next(pi1, &p1,
   861 						    RAZOR_DETAIL_NAME, &name1,
   862 						    RAZOR_DETAIL_VERSION, &version1,
   863 						    RAZOR_DETAIL_ARCH, &arch1,
   864 						    RAZOR_DETAIL_LAST);
   865 			is_fixed1 = razor_package_is_fixed(set, p1);
   866 		}
   867 		if (p2 != NULL && res >= 0) {
   868 			razor_package_iterator_next(pi2, &p2,
   869 						    RAZOR_DETAIL_NAME, &name2,
   870 						    RAZOR_DETAIL_VERSION, &version2,
   871 						    RAZOR_DETAIL_ARCH, &arch2,
   872 						    RAZOR_DETAIL_LAST);
   873 			is_fixed2 = razor_package_is_fixed(upstream, p2);
   874 		}
   875 	}
   876 
   877 	razor_package_iterator_destroy(pi1);
   878 	razor_package_iterator_destroy(pi2);
   879 }
   880 
   881 struct install_action {
   882 	enum razor_install_action action;
   883 	struct razor_package *package;
   884 };
   885 
   886 struct razor_install_iterator {
   887 	struct razor_set *set;
   888 	struct razor_set *next;
   889 	struct array actions;
   890 	struct deque *order;
   891 };
   892 
   893 static void
   894 add_action(enum razor_diff_action action,
   895 	   struct razor_package *package,
   896 	   const char *name,
   897 	   const char *version,
   898 	   const char *arch,
   899 	   void *data)
   900 {
   901 	struct razor_install_iterator *ii = data;
   902 	struct install_action *a;
   903 
   904 	a = array_add(&ii->actions, sizeof *a);
   905 	a->package = package;
   906 
   907 	switch (action) {
   908 	case RAZOR_DIFF_ACTION_ADD:
   909 		a->action = RAZOR_INSTALL_ACTION_ADD;
   910 		break;
   911 	case RAZOR_DIFF_ACTION_REMOVE:
   912 		a->action = RAZOR_INSTALL_ACTION_REMOVE;
   913 		break;
   914 	}
   915 }
   916 
   917 RAZOR_EXPORT struct razor_install_iterator *
   918 razor_set_create_install_iterator(struct razor_set *set,
   919 				  struct razor_set *next)
   920 {
   921 	struct razor_install_iterator *ii;
   922 	struct razor_property *prop;
   923 	/* A graph of the actions to be perfomed where
   924 	 * A->B means action A should follow action B.
   925 	 */
   926 	struct graph follows;
   927 	struct install_action *actions, *ai, *aj;
   928 	int i, j, count, vertex_added;
   929 	struct list *link;
   930 	struct razor_set *rs;
   931 
   932 	assert (set != NULL);
   933 	assert (next != NULL);
   934 
   935 	ii = zalloc(sizeof *ii);
   936 	ii->set = set;
   937 	ii->next = next;
   938 	
   939 	razor_set_diff(set, next, add_action, ii);
   940 
   941 	actions = ii->actions.data;
   942 	count = ii->actions.size / sizeof (struct install_action);
   943 
   944 	graph_init(&follows);
   945 
   946 	for(i = 0; i < count; i++) {
   947 		ai = actions + i;
   948 		rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
   949 		vertex_added = 0;
   950 		link = list_first(&ai->package->properties, &rs->property_pool);
   951 		for(; link; link = list_next(link)) {
   952 			prop = rs->properties.data;
   953 			prop += link->data;
   954 			switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
   955 			case RAZOR_PROPERTY_REQUIRES:
   956 			case RAZOR_PROPERTY_CONFLICTS:
   957 				for(j = 0; j < count; j++) {
   958 					if (j == i)
   959 						continue;
   960 					aj = actions + j;
   961 					if (aj->package->name == prop->name) {
   962 						if (ai->action ==
   963 						    RAZOR_INSTALL_ACTION_ADD)
   964 							graph_add_edge(&follows,
   965 								       i, j);
   966 						else
   967 							graph_add_edge(&follows,
   968 								       j, i);
   969 						vertex_added++;
   970 					}
   971 				}
   972 				break;
   973 			}
   974 		}
   975 		if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
   976 			for(j = 0; j < count; j++) {
   977 				if (j == i)
   978 					continue;
   979 				aj = actions + j;
   980 				if (aj->package == ai->package &&
   981 				    aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
   982 					graph_add_edge(&follows, i, j);
   983 					vertex_added++;
   984 				}
   985 			}
   986 		}
   987 		if (!vertex_added)
   988 			graph_add_edge(&follows, i, i);
   989 	}
   990 
   991 	ii->order = graph_sort(&follows);
   992 	graph_release(&follows);
   993 
   994 	return ii;
   995 }
   996 
   997 RAZOR_EXPORT int
   998 razor_install_iterator_next(struct razor_install_iterator *ii,
   999 			    struct razor_package **package,
  1000 			    enum razor_install_action *action,
  1001 			    int *count)
  1002 {
  1003 	struct install_action *a;
  1004 	struct razor_package_iterator *pi;
  1005 	struct razor_package *pkg;
  1006 	const char *removing, *name;
  1007 
  1008 	if (deque_empty(ii->order))
  1009 		return 0;
  1010 
  1011 	a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
  1012 	*package = a->package;
  1013 	*action = a->action;
  1014 	*count = 0;
  1015 
  1016 	if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
  1017 		razor_package_get_details(ii->set, a->package,
  1018 					  RAZOR_DETAIL_NAME, &removing,
  1019 					  RAZOR_DETAIL_LAST);
  1020 
  1021 		pi = razor_package_iterator_create(ii->next);
  1022 		while (razor_package_iterator_next(pi, &pkg,
  1023 						   RAZOR_DETAIL_NAME, &name,
  1024 						   RAZOR_DETAIL_LAST)) {
  1025 			if (!strcmp(name, removing))
  1026 				(*count)++;
  1027 		}
  1028 		razor_package_iterator_destroy(pi);
  1029 	}
  1030 
  1031 	return 1;
  1032 }
  1033 
  1034 RAZOR_EXPORT void
  1035 razor_install_iterator_destroy(struct razor_install_iterator *ii)
  1036 {
  1037 	array_release(&ii->actions);
  1038 	deque_free(ii->order);
  1039 	free(ii);
  1040 }