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