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