librazor/transaction.c
author James Bowes <jbowes@redhat.com>
Wed Jul 09 10:11:13 2008 -0400 (2008-07-09)
changeset 318 829d6711b316
parent 304 bf23ba00db03
child 331 890a49fb2c71
permissions -rw-r--r--
Use strings to identify section types in the on-disk repo format.

Previously, a given razor file type had a fixed number of sections in a
fixed order, identified by an integer type. Now, sections are identified
by a named string (stored in a string pool after the section lists).

This will allow for razor files to contain arbitrary sections.

For bonus points, also drop the 4k section alignment and change the
magic byte string to "RZDB".

committer: Kristian H?gsberg <krh@redhat.com>
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; either version 2 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along
    16  * with this program; if not, write to the Free Software Foundation, Inc.,
    17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    18  */
    19 
    20 #define _GNU_SOURCE
    21 
    22 #include <stdlib.h>
    23 #include <stddef.h>
    24 #include <stdint.h>
    25 #include <stdio.h>
    26 #include <string.h>
    27 #include <sys/types.h>
    28 #include <sys/stat.h>
    29 #include <sys/mman.h>
    30 #include <unistd.h>
    31 #include <fcntl.h>
    32 #include <errno.h>
    33 #include <ctype.h>
    34 #include <fnmatch.h>
    35 #include <assert.h>
    36 
    37 #include "razor-internal.h"
    38 #include "razor.h"
    39 
    40 static int
    41 provider_satisfies_requirement(struct razor_property *provider,
    42 			       const char *provider_strings,
    43 			       uint32_t flags,
    44 			       const char *required)
    45 {
    46 	int cmp, len;
    47 	const char *provided = &provider_strings[provider->version];
    48 
    49 	if (!*required)
    50 		return 1;
    51 	if (!*provided) {
    52 		if (flags & RAZOR_PROPERTY_LESS)
    53 			return 0;
    54 		else
    55 			return 1;
    56 	}
    57 
    58 	cmp = razor_versioncmp(provided, required);
    59 
    60 	switch (flags & RAZOR_PROPERTY_RELATION_MASK) {
    61 	case RAZOR_PROPERTY_LESS:
    62 		return cmp < 0;
    63 
    64 	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
    65 		if (cmp <= 0)
    66 			return 1;
    67 		/* fall through: FIXME, make sure this is correct */
    68 
    69 	case RAZOR_PROPERTY_EQUAL:
    70 		if (cmp == 0)
    71 			return 1;
    72 
    73 		/* "foo == 1.1" is satisfied by "foo 1.1-2" */
    74 		len = strlen(required);
    75 		if (!strncmp(required, provided, len) && provided[len] == '-')
    76 			return 1;
    77 		return 0;
    78 
    79 	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
    80 		return cmp >= 0;
    81 
    82 	case RAZOR_PROPERTY_GREATER:
    83 		return cmp > 0;
    84 	}
    85 
    86 	/* shouldn't happen */
    87 	return 0;
    88 }
    89 
    90 #define TRANS_PACKAGE_PRESENT		1
    91 #define TRANS_PACKAGE_UPDATE		2
    92 #define TRANS_PROPERTY_SATISFIED	0x80000000
    93 
    94 struct transaction_set {
    95 	struct razor_set *set;
    96 	uint32_t *packages;
    97 	uint32_t *properties;
    98 };
    99 
   100 struct razor_transaction {
   101 	int package_count, errors;
   102 	struct transaction_set system, upstream;
   103 	int changes;
   104 };
   105 
   106 static void
   107 transaction_set_init(struct transaction_set *ts, struct razor_set *set)
   108 {
   109 	int count;
   110 
   111 	ts->set = set;
   112 	count = set->packages.size / sizeof (struct razor_package);
   113 	ts->packages = zalloc(count * sizeof *ts->packages);
   114 	count = set->properties.size / sizeof (struct razor_property);
   115 	ts->properties = zalloc(count * sizeof *ts->properties);
   116 }
   117 
   118 static void
   119 transaction_set_release(struct transaction_set *ts)
   120 {
   121 	free(ts->packages);
   122 	free(ts->properties);
   123 }
   124 
   125 static void
   126 transaction_set_install_package(struct transaction_set *ts,
   127 				struct razor_package *package)
   128 {
   129 	struct razor_package *pkgs;
   130 	struct list *prop;
   131 	int i;
   132 
   133 	pkgs = ts->set->packages.data;
   134 	i = package - pkgs;
   135 	if (ts->packages[i] == TRANS_PACKAGE_PRESENT)
   136 		return;
   137 
   138 	ts->packages[i] = TRANS_PACKAGE_PRESENT;
   139 
   140 	prop = list_first(&package->properties, &ts->set->property_pool);
   141 	while (prop) {
   142 		ts->properties[prop->data]++;
   143 		prop = list_next(prop);
   144 	}
   145 }
   146 
   147 static void
   148 transaction_set_remove_package(struct transaction_set *ts,
   149 			       struct razor_package *package)
   150 {
   151 	struct razor_package *pkgs;
   152 	struct list *prop;
   153 	int i;
   154 
   155 	pkgs = ts->set->packages.data;
   156 	i = package - pkgs;
   157 	if (ts->packages[i] == 0)
   158 		return;
   159 
   160 	ts->packages[i] = 0;
   161 
   162 	prop = list_first(&package->properties, &ts->set->property_pool);
   163 	while (prop) {
   164 		ts->properties[prop->data]--;
   165 		prop = list_next(prop);
   166 	}
   167 }
   168 
   169 RAZOR_EXPORT struct razor_transaction *
   170 razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
   171 {
   172 	struct razor_transaction *trans;
   173 	struct razor_package *p, *spkgs, *pend;
   174 
   175 	trans = zalloc(sizeof *trans);
   176 	transaction_set_init(&trans->system, system);
   177 	transaction_set_init(&trans->upstream, upstream);
   178 
   179 	spkgs = trans->system.set->packages.data;
   180 	pend = trans->system.set->packages.data +
   181 		trans->system.set->packages.size;
   182 	for (p = spkgs; p < pend; p++)
   183 		transaction_set_install_package(&trans->system, p);
   184 
   185 	return trans;
   186 }
   187 
   188 RAZOR_EXPORT void
   189 razor_transaction_install_package(struct razor_transaction *trans,
   190 				  struct razor_package *package)
   191 {
   192 	assert (trans != NULL);
   193 	assert (package != NULL);
   194 
   195 	transaction_set_install_package(&trans->upstream, package);
   196 	trans->changes++;
   197 }
   198 
   199 RAZOR_EXPORT void
   200 razor_transaction_remove_package(struct razor_transaction *trans,
   201 				 struct razor_package *package)
   202 {
   203 	assert (trans != NULL);
   204 	assert (package != NULL);
   205 
   206 	transaction_set_remove_package(&trans->system, package);
   207 	trans->changes++;
   208 }
   209 
   210 RAZOR_EXPORT void
   211 razor_transaction_update_package(struct razor_transaction *trans,
   212 				  struct razor_package *package)
   213 {
   214 	struct razor_package *spkgs, *upkgs, *end;
   215 
   216 	assert (trans != NULL);
   217 	assert (package != NULL);
   218 
   219 	spkgs = trans->system.set->packages.data;
   220 	upkgs = trans->upstream.set->packages.data;
   221 	end = trans->system.set->packages.data +
   222 		trans->system.set->packages.size;
   223 	if (spkgs <= package && package < end)
   224 		trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE;
   225 	else
   226 		trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE;
   227 }
   228 
   229 struct prop_iter {
   230 	struct razor_property *p, *start, *end;
   231 	const char *pool;
   232 	uint32_t *present;
   233 };
   234 
   235 static void
   236 prop_iter_init(struct prop_iter *pi, struct transaction_set *ts)
   237 {
   238 	pi->p = ts->set->properties.data;
   239 	pi->start = ts->set->properties.data;
   240 	pi->end = ts->set->properties.data + ts->set->properties.size;
   241 	pi->pool = ts->set->string_pool.data;
   242 	pi->present = ts->properties;
   243 }
   244 
   245 static int
   246 prop_iter_next(struct prop_iter *pi, uint32_t flags, struct razor_property **p)
   247 {
   248 	while (pi->p < pi->end) {
   249 		if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) &&
   250 		    (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) == flags) {
   251 			*p = pi->p++;
   252 			return 1;
   253 		}
   254 		pi->p++;
   255 	}
   256 
   257 	return 0;
   258 }
   259 
   260 static struct razor_property *
   261 prop_iter_seek_to(struct prop_iter *pi,
   262 		  uint32_t flags, const char *match)
   263 {
   264 	uint32_t name;
   265 
   266 	while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0)
   267 		pi->p++;
   268 
   269 	if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0)
   270 		return NULL;
   271 
   272 	name = pi->p->name;
   273 	while (pi->p < pi->end &&
   274 	       pi->p->name == name &&
   275 	       (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) != flags)
   276 		pi->p++;
   277 
   278 	if (pi->p == pi->end || pi->p->name != name)
   279 		return NULL;
   280 
   281 	return pi->p;
   282 }
   283 
   284 /* Remove packages from set that provide any of the matching (same
   285  * name and type) providers from ppi onwards that match the
   286  * requirement that rpi points to. */
   287 static void
   288 remove_matching_providers(struct razor_transaction *trans,
   289 			  struct prop_iter *ppi,
   290 			  uint32_t flags,
   291 			  const char *version)
   292 {
   293 	struct razor_property *p;
   294 	struct razor_package *pkg, *pkgs;
   295 	struct razor_package_iterator pkg_iter;
   296 	struct razor_set *set;
   297 	const char *n, *v;
   298 	uint32_t type;
   299 
   300 	if (ppi->present == trans->system.properties)
   301 		set = trans->system.set;
   302 	else
   303 		set = trans->upstream.set;
   304 
   305 	pkgs = (struct razor_package *) set->packages.data;
   306 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   307 	for (p = ppi->p;
   308 	     p < ppi->end &&
   309 	     p->name == ppi->p->name &&
   310 	     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   311 	     p++) {
   312 		if (!ppi->present[p - ppi->start])
   313 			continue;
   314 		if (!provider_satisfies_requirement(p, ppi->pool,
   315 						    flags, version))
   316 			continue;
   317 
   318 		razor_package_iterator_init_for_property(&pkg_iter, set, p);
   319 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   320 						   RAZOR_DETAIL_NAME, &n,
   321 						   RAZOR_DETAIL_VERSION, &v,
   322 						   RAZOR_DETAIL_LAST)) {
   323 			fprintf(stderr, "removing %s-%s\n", n, v);
   324 			razor_transaction_remove_package(trans, pkg);
   325 		}
   326 	}
   327 }
   328 
   329 static void
   330 flag_matching_providers(struct razor_transaction *trans,
   331 			struct prop_iter *ppi,
   332 			struct razor_property *r,
   333 			struct prop_iter *rpi,
   334 			unsigned int flag)
   335 {
   336 	struct razor_property *p;
   337 	struct razor_package *pkg, *pkgs;
   338 	struct razor_package_iterator pkg_iter;
   339 	struct razor_set *set;
   340 	const char *name, *version;
   341 	uint32_t *flags, type;
   342 
   343 	if (ppi->present == trans->system.properties) {
   344 		set = trans->system.set;
   345 		flags = trans->system.packages;
   346 	} else {
   347 		set = trans->upstream.set;
   348 		flags = trans->upstream.packages;
   349 	}
   350 
   351 	pkgs = (struct razor_package *) set->packages.data;
   352 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   353 	for (p = ppi->p;
   354 	     p < ppi->end &&
   355 		     p->name == ppi->p->name &&
   356 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   357 	     p++) {
   358 		if (!ppi->present[p - ppi->start])
   359 			continue;
   360 		if (!provider_satisfies_requirement(p, ppi->pool,
   361 						    r->flags,
   362 						    &rpi->pool[r->version]))
   363 			continue;
   364 
   365 		razor_package_iterator_init_for_property(&pkg_iter, set, p);
   366 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   367 						   RAZOR_DETAIL_NAME, &name,
   368 						   RAZOR_DETAIL_VERSION, &version,
   369 						   RAZOR_DETAIL_LAST)) {
   370 
   371 			fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
   372 				name, version,
   373 				ppi->pool + p->name,
   374 				rpi->pool + r->name,
   375 				rpi->pool + r->version);
   376 			flags[pkg - pkgs] |= flag;
   377 		}
   378 	}
   379 }
   380 
   381 static struct razor_package *
   382 pick_matching_provider(struct razor_set *set,
   383 		       struct prop_iter *ppi,
   384 		       uint32_t flags,
   385 		       const char *version)
   386 {
   387 	struct razor_property *p;
   388 	struct razor_package *pkgs;
   389 	struct list *i;
   390 	uint32_t type;
   391 
   392 	/* This is where we decide which pkgs to pull in to satisfy a
   393 	 * requirement.  There may be several different providers
   394 	 * (different versions) and each version of a provider may
   395 	 * come from a number of packages.  We pick the first package
   396 	 * from the first provider that matches. */
   397 
   398 	pkgs = set->packages.data;
   399 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   400 	for (p = ppi->p;
   401 	     p < ppi->end &&
   402 		     p->name == ppi->p->name &&
   403 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type &&
   404 		     ppi->present[p - ppi->start] == 0;
   405 	     p++) {
   406 		if (!provider_satisfies_requirement(p, ppi->pool,
   407 						    flags, version))
   408 			continue;
   409 
   410 		i = list_first(&p->packages, &set->package_pool);
   411 
   412 		return &pkgs[i->data];
   413 	}
   414 
   415 	return NULL;
   416 }
   417 
   418 static void
   419 remove_obsoleted_packages(struct razor_transaction *trans)
   420 {
   421 	struct razor_property *up;
   422 	struct razor_package *spkgs;
   423 	struct prop_iter spi, upi;
   424 
   425 	spkgs = trans->system.set->packages.data;
   426 	prop_iter_init(&spi, &trans->system);
   427 	prop_iter_init(&upi, &trans->upstream);
   428 
   429 	while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
   430 		if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
   431 				       &upi.pool[up->name]))
   432 			continue;
   433 		remove_matching_providers(trans, &spi, up->flags,
   434 					  &upi.pool[up->version]);
   435 	}
   436 }
   437 
   438 static int
   439 any_provider_satisfies_requirement(struct prop_iter *ppi,
   440 				   uint32_t flags,
   441 				   const char *version)
   442 {
   443 	struct razor_property *p;
   444 	uint32_t type;
   445 
   446 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   447 	for (p = ppi->p;
   448 	     p < ppi->end &&
   449 		     p->name == ppi->p->name &&
   450 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   451 	     p++) {
   452 		if (ppi->present[p - ppi->start] > 0 &&
   453 		    provider_satisfies_requirement(p, ppi->pool,
   454 						   flags, version))
   455 			return 1;
   456 	}
   457 
   458 	return 0;
   459 }
   460 
   461 static void
   462 clear_requires_flags(struct transaction_set *ts)
   463 {
   464 	struct razor_property *p;
   465 	const char *pool;
   466 	int i, count;
   467 
   468 	count = ts->set->properties.size / sizeof *p;
   469 	p = ts->set->properties.data;
   470 	pool = ts->set->string_pool.data;
   471 	for (i = 0; i < count; i++) {
   472 		ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
   473 		if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
   474 			ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
   475 	}
   476 }
   477 
   478 static void
   479 mark_satisfied_requires(struct razor_transaction *trans,
   480 			struct transaction_set *rts,
   481 			struct transaction_set *pts)
   482 {
   483 	struct prop_iter rpi, ppi;
   484 	struct razor_property *rp;
   485 
   486 	prop_iter_init(&rpi, rts);
   487 	prop_iter_init(&ppi, pts);
   488 
   489 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   490 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
   491 				       &rpi.pool[rp->name]))
   492 			continue;
   493 
   494 		if (any_provider_satisfies_requirement(&ppi, rp->flags,
   495 						       &rpi.pool[rp->version]))
   496 			rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
   497 	}
   498 }
   499 
   500 static void
   501 mark_all_satisfied_requires(struct razor_transaction *trans)
   502 {
   503 	clear_requires_flags(&trans->system);
   504 	clear_requires_flags(&trans->upstream);
   505 	mark_satisfied_requires(trans, &trans->system, &trans->system);
   506 	mark_satisfied_requires(trans, &trans->system, &trans->upstream);
   507 	mark_satisfied_requires(trans, &trans->upstream, &trans->system);
   508 	mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
   509 }
   510 
   511 static void
   512 update_unsatisfied_packages(struct razor_transaction *trans)
   513 {
   514 	struct razor_package *spkgs, *pkg;
   515 	struct razor_property *sp;
   516 	struct prop_iter spi;
   517 	struct razor_package_iterator pkg_iter;
   518 	const char *name;
   519 
   520 	spkgs = trans->system.set->packages.data;
   521 	prop_iter_init(&spi, &trans->system);
   522 
   523 	while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
   524 		if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
   525 			continue;
   526 
   527 		razor_package_iterator_init_for_property(&pkg_iter,
   528 							 trans->system.set,
   529 							 sp);
   530 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   531 						   RAZOR_DETAIL_NAME, &name,
   532 						   RAZOR_DETAIL_LAST)) {
   533 			fprintf(stderr, "updating %s because %s %s %s "
   534 				"isn't satisfied\n",
   535 				name, spi.pool + sp->name,
   536 				razor_property_relation_to_string(sp),
   537 				spi.pool + sp->version);
   538 			trans->system.packages[pkg - spkgs] |=
   539 				TRANS_PACKAGE_UPDATE;
   540 		}
   541 	}
   542 }
   543 
   544 RAZOR_EXPORT void
   545 razor_transaction_update_all(struct razor_transaction *trans)
   546 {
   547 	struct razor_package *p;
   548 	int i, count;
   549 
   550 	assert (trans != NULL);
   551 
   552 	count = trans->system.set->packages.size / sizeof *p;
   553 	for (i = 0; i < count; i++)
   554 		trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
   555 }
   556 
   557 static void
   558 update_conflicted_packages(struct razor_transaction *trans)
   559 {
   560 	struct razor_package *pkg, *spkgs;
   561 	struct razor_property *up, *sp;
   562 	struct prop_iter spi, upi;
   563 	struct razor_package_iterator pkg_iter;
   564 	const char *name, *version;
   565 
   566 	spkgs = trans->system.set->packages.data;
   567 	prop_iter_init(&spi, &trans->system);
   568 	prop_iter_init(&upi, &trans->upstream);
   569 
   570 	while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
   571 		if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
   572 				       &spi.pool[sp->name]))
   573 			continue;
   574 
   575 		if (!any_provider_satisfies_requirement(&upi, sp->flags,
   576 							&spi.pool[sp->version]))
   577 			continue;
   578 
   579 		razor_package_iterator_init_for_property(&pkg_iter,
   580 							 trans->system.set,
   581 							 sp);
   582 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   583 						   RAZOR_DETAIL_NAME, &name,
   584 						   RAZOR_DETAIL_VERSION, &version,
   585 						   RAZOR_DETAIL_LAST)) {
   586 			fprintf(stderr, "updating %s %s because it "
   587 				"conflicts with %s\n",
   588 				name, version, spi.pool + sp->name);
   589 			trans->system.packages[pkg - spkgs] |=
   590 				TRANS_PACKAGE_UPDATE;
   591 		}
   592 	}
   593 
   594 	prop_iter_init(&spi, &trans->system);
   595 	prop_iter_init(&upi, &trans->upstream);
   596 
   597 	while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
   598 		sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
   599 				       &upi.pool[upi.p->name]);
   600 
   601 		if (sp)
   602 			flag_matching_providers(trans, &spi, up, &upi,
   603 						TRANS_PACKAGE_UPDATE);
   604 	}
   605 }
   606 
   607 static void
   608 pull_in_requirements(struct razor_transaction *trans,
   609 		     struct prop_iter *rpi, struct prop_iter *ppi)
   610 {
   611 	struct razor_property *rp, *pp;
   612 	struct razor_package *pkg, *upkgs;
   613 
   614 	upkgs = trans->upstream.set->packages.data;
   615 	while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   616 		if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
   617 			continue;
   618 
   619 		pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
   620 				       &rpi->pool[rp->name]);
   621 		if (pp == NULL)
   622 			continue;
   623 		pkg = pick_matching_provider(trans->upstream.set,
   624 					     ppi, rp->flags,
   625 					     &rpi->pool[rp->version]);
   626 		if (pkg == NULL)
   627 			continue;
   628 
   629 		rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
   630 
   631 		fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
   632 			"to satisfy %s %s %s\n",
   633 			ppi->pool + pkg->name,
   634 			ppi->pool + pkg->version,
   635 			ppi->pool + pkg->arch,
   636 			ppi->pool + pp->name,
   637 			razor_property_relation_to_string(pp),
   638 			ppi->pool + pp->version,
   639 			&rpi->pool[rp->name],
   640 			razor_property_relation_to_string(rp),
   641 			&rpi->pool[rp->version]);
   642 
   643 		trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
   644 	}
   645 }
   646 
   647 static void
   648 pull_in_all_requirements(struct razor_transaction *trans)
   649 {
   650 	struct prop_iter rpi, ppi;
   651 
   652 	prop_iter_init(&rpi, &trans->system);
   653 	prop_iter_init(&ppi, &trans->upstream);
   654 	pull_in_requirements(trans, &rpi, &ppi);
   655 
   656 	prop_iter_init(&rpi, &trans->upstream);
   657 	prop_iter_init(&ppi, &trans->upstream);
   658 	pull_in_requirements(trans, &rpi, &ppi);
   659 }
   660 
   661 static void
   662 flush_scheduled_system_updates(struct razor_transaction *trans)
   663 {
   664  	struct razor_package_iterator *pi;
   665  	struct razor_package *p, *pkg, *spkgs;
   666 	struct prop_iter ppi;
   667 	const char *name, *version;
   668 
   669 	spkgs = trans->system.set->packages.data;
   670 	pi = razor_package_iterator_create(trans->system.set);
   671 	prop_iter_init(&ppi, &trans->upstream);
   672 
   673 	while (razor_package_iterator_next(pi, &p,
   674 					   RAZOR_DETAIL_NAME, &name,
   675 					   RAZOR_DETAIL_VERSION, &version,
   676 					   RAZOR_DETAIL_LAST)) {
   677 		if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
   678 			continue;
   679 
   680 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
   681 			continue;
   682 
   683 		pkg = pick_matching_provider(trans->upstream.set, &ppi,
   684 					     RAZOR_PROPERTY_GREATER, version);
   685 		if (pkg == NULL)
   686 			continue;
   687 
   688 		fprintf(stderr, "updating %s-%s to %s-%s\n",
   689 			name, version,
   690 			&ppi.pool[pkg->name], &ppi.pool[pkg->version]);
   691 
   692 		razor_transaction_remove_package(trans, p);
   693 		razor_transaction_install_package(trans, pkg);
   694 	}
   695 
   696 	razor_package_iterator_destroy(pi);
   697 }
   698 
   699 static void
   700 flush_scheduled_upstream_updates(struct razor_transaction *trans)
   701 {
   702  	struct razor_package_iterator *pi;
   703  	struct razor_package *p, *upkgs;
   704 	struct prop_iter spi;
   705 	const char *name, *version;
   706 
   707 	upkgs = trans->upstream.set->packages.data;
   708 	pi = razor_package_iterator_create(trans->upstream.set);
   709 	prop_iter_init(&spi, &trans->system);
   710 
   711 	while (razor_package_iterator_next(pi, &p,
   712 					   RAZOR_DETAIL_NAME, &name,
   713 					   RAZOR_DETAIL_VERSION, &version,
   714 					   RAZOR_DETAIL_LAST)) {
   715 		if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
   716 			continue;
   717 
   718 		if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
   719 			remove_matching_providers(trans,
   720 						  &spi,
   721 						  RAZOR_PROPERTY_LESS,
   722 						  version);
   723 		razor_transaction_install_package(trans, p);
   724 		fprintf(stderr, "installing %s-%s\n", name, version);
   725 	}
   726 }
   727 
   728 RAZOR_EXPORT int
   729 razor_transaction_resolve(struct razor_transaction *trans)
   730 {
   731 	int last = 0;
   732 
   733 	flush_scheduled_system_updates(trans);
   734 	flush_scheduled_upstream_updates(trans);
   735 
   736 	while (last < trans->changes) {
   737 		last = trans->changes;
   738 		remove_obsoleted_packages(trans);
   739 		mark_all_satisfied_requires(trans);
   740 		update_unsatisfied_packages(trans);
   741 		update_conflicted_packages(trans);
   742 		pull_in_all_requirements(trans);
   743 		flush_scheduled_system_updates(trans);
   744 		flush_scheduled_upstream_updates(trans);
   745 	}
   746 
   747 	return trans->changes;
   748 }
   749 
   750 static void
   751 describe_unsatisfied(struct razor_set *set, struct razor_property *rp)
   752 {
   753 	struct razor_package_iterator pi;
   754 	struct razor_package *pkg;
   755 	const char *name, *version, *arch, *pool;
   756 
   757 	pool = set->string_pool.data;
   758 	if (pool[rp->version] == '\0') {
   759 		razor_package_iterator_init_for_property(&pi, set, rp);
   760 		while (razor_package_iterator_next(&pi, &pkg,
   761 						   RAZOR_DETAIL_NAME, &name,
   762 						   RAZOR_DETAIL_VERSION, &version,
   763 						   RAZOR_DETAIL_ARCH, &arch,
   764 						   RAZOR_DETAIL_LAST))
   765 			fprintf(stderr, "%s is needed by %s-%s.%s\n",
   766 				&pool[rp->name],
   767 				name, version, arch);
   768 	} else {
   769 		razor_package_iterator_init_for_property(&pi, set, rp);
   770 		while (razor_package_iterator_next(&pi, &pkg,
   771 						   RAZOR_DETAIL_NAME, &name,
   772 						   RAZOR_DETAIL_VERSION, &version,
   773 						   RAZOR_DETAIL_ARCH, &arch,
   774 						   RAZOR_DETAIL_LAST))
   775 			fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n",
   776 				&pool[rp->name],
   777 				razor_property_relation_to_string(rp),
   778 				&pool[rp->version],
   779 				name, version, arch);
   780 	}
   781 }
   782 
   783 RAZOR_EXPORT int
   784 razor_transaction_describe(struct razor_transaction *trans)
   785 {
   786 	struct prop_iter rpi;
   787 	struct razor_property *rp;
   788 	int unsatisfied;
   789 
   790 	flush_scheduled_system_updates(trans);
   791 	flush_scheduled_upstream_updates(trans);
   792 	mark_all_satisfied_requires(trans);
   793 
   794 	unsatisfied = 0;
   795 	prop_iter_init(&rpi, &trans->system);
   796 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   797 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   798 			describe_unsatisfied(trans->system.set, rp);
   799 		        unsatisfied++;
   800 		}
   801 	}
   802 
   803 	prop_iter_init(&rpi, &trans->upstream);
   804 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   805 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   806 			describe_unsatisfied(trans->upstream.set, rp);
   807 			unsatisfied++;
   808 		}
   809 	}
   810 
   811 	return unsatisfied;
   812 }
   813 
   814 RAZOR_EXPORT int
   815 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
   816 				       const char *name,
   817 				       uint32_t flags,
   818 				       const char *version)
   819 {
   820 	struct prop_iter pi;
   821 	struct razor_property *p;
   822 
   823 	prop_iter_init(&pi, &trans->system);
   824 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   825 		if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   826 		    p->flags == flags &&
   827 		    strcmp(&pi.pool[p->name], name) == 0 &&
   828 		    strcmp(&pi.pool[p->version], version) == 0)
   829 
   830 			return 1;
   831 	}
   832 
   833 	prop_iter_init(&pi, &trans->upstream);
   834 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   835 		if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   836 		    p->flags == flags &&
   837 		    strcmp(&pi.pool[p->name], name) == 0 &&
   838 		    strcmp(&pi.pool[p->version], version) == 0)
   839 
   840 			return 1;
   841 	}
   842 
   843 	return 0;
   844 }
   845 
   846 RAZOR_EXPORT struct razor_set *
   847 razor_transaction_finish(struct razor_transaction *trans)
   848 {
   849 	struct razor_merger *merger;
   850 	struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
   851 	char *upool, *spool;
   852 	int cmp;
   853 
   854 	s = trans->system.set->packages.data;
   855 	spkgs = trans->system.set->packages.data;
   856 	send = trans->system.set->packages.data +
   857 		trans->system.set->packages.size;
   858 	spool = trans->system.set->string_pool.data;
   859 
   860 	u = trans->upstream.set->packages.data;
   861 	upkgs = trans->upstream.set->packages.data;
   862 	uend = trans->upstream.set->packages.data +
   863 		trans->upstream.set->packages.size;
   864 	upool = trans->upstream.set->string_pool.data;
   865 
   866 	merger = razor_merger_create(trans->system.set, trans->upstream.set);
   867 	while (s < send || u < uend) {
   868 		if (s < send && u < uend)
   869 			cmp = strcmp(&spool[s->name], &upool[u->name]);
   870 		else if (s < send)
   871 			cmp = -1;
   872 		else
   873 			cmp = 1;
   874 
   875 		if (cmp < 0) {
   876 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   877 				razor_merger_add_package(merger, s);
   878 			s++;
   879 		} else if (cmp == 0) {
   880 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   881 				razor_merger_add_package(merger, s);
   882 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   883 				razor_merger_add_package(merger, u);
   884 
   885 			s++;
   886 			u++;
   887 		} else {
   888 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   889 				razor_merger_add_package(merger, u);
   890 			u++;
   891 		}
   892 	}
   893 
   894 	razor_transaction_destroy(trans);
   895 
   896 	return razor_merger_finish(merger);
   897 }
   898 
   899 RAZOR_EXPORT void
   900 razor_transaction_destroy(struct razor_transaction *trans)
   901 {
   902 	assert (trans != NULL);
   903 
   904 	transaction_set_release(&trans->system);
   905 	transaction_set_release(&trans->upstream);
   906 	free(trans);
   907 }