librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Fri Jun 08 18:02:33 2018 +0100 (2018-06-08)
changeset 500 f98d77376544
parent 479 4204db81cdbc
permissions -rw-r--r--
Release 0.7
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@499
     4
 * Copyright (C) 2009-2012, 2016, 2018  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>
ali@475
    31
#include <fcntl.h>
rhughes@241
    32
#include <unistd.h>
rhughes@241
    33
#include <errno.h>
rhughes@241
    34
#include <ctype.h>
rhughes@241
    35
#include <fnmatch.h>
ali@369
    36
#include <limits.h>
richard@301
    37
#include <assert.h>
ali@388
    38
#ifdef MSWIN_API
ali@388
    39
#include <windows.h>
ali@388
    40
#endif
rhughes@241
    41
ali@499
    42
#include "razor.h"
ali@499
    43
#include "types/types.h"
krh@253
    44
#include "razor-internal.h"
rhughes@241
    45
ali@345
    46
#ifndef O_BINARY
ali@345
    47
#define O_BINARY	0
ali@345
    48
#endif
ali@345
    49
jbowes@318
    50
struct razor_set_section_index {
jbowes@318
    51
	const char *name;
jbowes@318
    52
	uint32_t offset;
krh@373
    53
	uint32_t flags;
jbowes@318
    54
};
jbowes@318
    55
krh@373
    56
#define MAIN(type, field) \
krh@373
    57
	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
krh@373
    58
#define FILES(type, field) \
krh@373
    59
	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
krh@373
    60
#define DETAILS(type, field) \
krh@373
    61
	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
krh@373
    62
jbowes@318
    63
struct razor_set_section_index razor_sections[] = {
krh@373
    64
	MAIN(RAZOR_STRING_POOL, string_pool),
krh@373
    65
	MAIN(RAZOR_PACKAGES, packages),
krh@373
    66
	MAIN(RAZOR_PROPERTIES, properties),
krh@373
    67
	MAIN(RAZOR_PACKAGE_POOL, package_pool),
krh@373
    68
	MAIN(RAZOR_PROPERTY_POOL, property_pool),
krh@373
    69
	MAIN(RAZOR_PREFIX_POOL, prefix_pool),
krh@373
    70
	FILES(RAZOR_FILES, files),
krh@373
    71
	FILES(RAZOR_FILE_POOL, file_pool),
krh@373
    72
	FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
krh@373
    73
	DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
jbowes@258
    74
};
krh@262
    75
krh@269
    76
RAZOR_EXPORT struct razor_set *
ali@363
    77
razor_set_create_without_root(void)
ali@363
    78
{
ali@363
    79
	struct razor_set *set;
ali@363
    80
	char *empty;
ali@363
    81
ali@363
    82
	set = zalloc(sizeof *set);
ali@363
    83
ali@403
    84
	if (set) {
ali@403
    85
		empty = array_add(&set->string_pool, 1);
ali@403
    86
		*empty = '\0';
ali@363
    87
ali@499
    88
		set->lock = -1;
ali@403
    89
ali@403
    90
		set->ref_count = 1;
ali@403
    91
ali@403
    92
		set->header_version = RAZOR_HEADER_VERSION;
ali@424
    93
ali@424
    94
		set->flags = RAZOR_SET_PRIVATE;
ali@403
    95
	}
ali@388
    96
ali@363
    97
	return set;
ali@363
    98
}
ali@363
    99
ali@363
   100
RAZOR_EXPORT struct razor_set *
rhughes@241
   101
razor_set_create(void)
rhughes@241
   102
{
rhughes@241
   103
	struct razor_set *set;
rhughes@241
   104
	struct razor_entry *e;
rhughes@241
   105
ali@363
   106
	set = razor_set_create_without_root();
rhughes@241
   107
rhughes@241
   108
	e = array_add(&set->files, sizeof *e);
rhughes@241
   109
	e->name = 0;
rhughes@241
   110
	e->flags = RAZOR_ENTRY_LAST;
rhughes@241
   111
	e->start = 0;
rhughes@241
   112
	list_set_empty(&e->packages);
rhughes@241
   113
rhughes@241
   114
	return set;
rhughes@241
   115
}
rhughes@241
   116
ali@403
   117
RAZOR_EXPORT uint32_t
ali@403
   118
razor_set_get_header_version(struct razor_set *set)
ali@403
   119
{
ali@403
   120
	return set->header_version;
ali@403
   121
}
ali@403
   122
ali@403
   123
RAZOR_EXPORT int
ali@403
   124
razor_set_set_header_version(struct razor_set *set, uint32_t header_version)
ali@403
   125
{
ali@403
   126
	if (header_version<RAZOR_HEADER_VERSION_MIN ||
ali@403
   127
	    header_version>RAZOR_HEADER_VERSION)
ali@403
   128
		return -1;
ali@403
   129
	else {
ali@403
   130
		set->header_version = header_version;
ali@403
   131
		return 0;
ali@403
   132
	}
ali@403
   133
}
ali@403
   134
krh@373
   135
struct razor_mapped_file {
krh@373
   136
	struct razor_set_header *header;
krh@373
   137
	size_t size;
krh@373
   138
	struct razor_mapped_file *next;
krh@373
   139
};
krh@373
   140
krh@373
   141
RAZOR_EXPORT int
ali@475
   142
razor_set_bind_sections(struct razor_set *set, const char *uri,
ali@424
   143
			enum razor_set_flags flags, struct razor_error **error)
rhughes@241
   144
{
jbowes@318
   145
	struct razor_set_section *s, *sections;
krh@373
   146
	struct razor_mapped_file *file;
ali@403
   147
	const char *pool, *reason;
rhughes@241
   148
	struct array *array;
ali@447
   149
	int i, j, code;
richard@301
   150
krh@373
   151
	file = zalloc(sizeof *file);
ali@403
   152
	if (file == NULL) {
ali@447
   153
		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
ali@447
   154
				"Not enough memory");
jbowes@288
   155
		return -1;
ali@403
   156
	}
jbowes@258
   157
ali@475
   158
	file->header = razor_uri_get_contents(uri, &file->size,
ali@475
   159
					      flags & RAZOR_SET_PRIVATE,
ali@475
   160
					      error);
krh@373
   161
	if (!file->header) {
krh@373
   162
		free(file);
krh@373
   163
		return -1;
krh@373
   164
	}
jbowes@318
   165
ali@447
   166
	if (file->size < sizeof *file->header) {
ali@447
   167
		code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED;
ali@403
   168
		reason = "Premature EOF";
ali@447
   169
	} else if (file->header->magic != RAZOR_MAGIC) {
ali@447
   170
		code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED;
ali@403
   171
		reason = "Bad magic number";
ali@447
   172
	} else if (file->header->version < RAZOR_HEADER_VERSION_MIN ||
ali@447
   173
		   file->header->version > RAZOR_HEADER_VERSION) {
ali@447
   174
		code = RAZOR_GENERAL_ERROR_DATABASE_INCOMPATIBLE;
ali@403
   175
		reason = "Incompatible file version";
ali@447
   176
	} else
ali@403
   177
		reason = NULL;
ali@403
   178
ali@403
   179
	if (reason) {
ali@475
   180
		razor_set_error(error, RAZOR_GENERAL_ERROR, code, uri, reason);
ali@475
   181
		razor_uri_free_contents(file->header, file->size);
ali@390
   182
		free(file);
ali@390
   183
		return -1;
ali@390
   184
	}
ali@390
   185
ali@424
   186
	set->flags = flags & RAZOR_SET_PRIVATE;
ali@424
   187
ali@403
   188
	set->header_version = file->header->version;
ali@403
   189
ali@388
   190
	if (set->mapped_files == NULL) {
ali@388
   191
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
ali@388
   192
			array = (void *) set + razor_sections[i].offset;
ali@388
   193
			array_release(array);
ali@388
   194
		}
ali@388
   195
	}
ali@388
   196
krh@373
   197
	file->next = set->mapped_files;
krh@373
   198
	set->mapped_files = file;
krh@373
   199
krh@373
   200
	sections = (void *) file->header + sizeof *file->header;
krh@373
   201
	pool = (void *) sections +
krh@373
   202
		file->header->num_sections * sizeof *sections;
krh@373
   203
krh@373
   204
	for (i = 0; i < file->header->num_sections; i++) {
jbowes@318
   205
		s = sections + i;
krh@373
   206
		for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
krh@373
   207
			if (!strcmp(razor_sections[j].name, &pool[s->name]))
jbowes@318
   208
				break;
krh@373
   209
		if (j == ARRAY_SIZE(razor_sections))
jbowes@258
   210
			continue;
krh@373
   211
		array = (void *) set + razor_sections[j].offset;
krh@373
   212
		array->data = (void *) file->header + s->offset;
jbowes@258
   213
		array->size = s->size;
jbowes@258
   214
		array->alloc = s->size;
jbowes@258
   215
	}
jbowes@288
   216
jbowes@288
   217
	return 0;
jbowes@258
   218
}
jbowes@258
   219
jbowes@318
   220
RAZOR_EXPORT struct razor_set *
ali@475
   221
razor_set_open(const char *uri, enum razor_set_flags flags,
ali@424
   222
	       struct razor_error **error)
jbowes@318
   223
{
jbowes@318
   224
	struct razor_set *set;
jbowes@318
   225
jbowes@318
   226
	set = zalloc(sizeof *set);
ali@403
   227
	if (!set) {
ali@447
   228
		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
ali@447
   229
				"Not enough memory");
ali@403
   230
		return NULL;
ali@403
   231
	}
ali@403
   232
ali@499
   233
	set->lock = -1;
ali@406
   234
	set->ref_count = 1;
ali@475
   235
	if (razor_set_bind_sections(set, uri, flags, error)) {
jbowes@318
   236
		free(set);
jbowes@318
   237
		return NULL;
jbowes@318
   238
	}
jbowes@318
   239
	return set;
jbowes@318
   240
}
jbowes@318
   241
ali@499
   242
struct razor_uri_lock {
ali@499
   243
	char *uri;
ali@499
   244
	int fd;
ali@499
   245
	int exclusive;
ali@499
   246
};
ali@499
   247
ali@499
   248
static struct array razor_uri_locks = { 0, };
ali@499
   249
ali@499
   250
/*
ali@499
   251
 * The underlying locks on MS-Windows and POSIX are different. Posix locks
ali@499
   252
 * created with fcntl(F_SETLK) only affect other processes whereas MS-Windows
ali@499
   253
 * locks affect the locking process as well. Partly because the latter is
ali@499
   254
 * preferable and partly because it makes testing easier if platforms behave
ali@499
   255
 * in the same way, we implement platform independent locks which follow the
ali@499
   256
 * MS-Windows pattern.
ali@499
   257
 *
ali@499
   258
 * Note that razor_set_aquire_lock() currently assumes that this is a private
ali@499
   259
 * helper function. Should we ever want to make this a library-wide API then
ali@499
   260
 * we should probably add a 'void *owner' parameter and add a new error code
ali@499
   261
 * (RAZOR_GENERAL_ERROR_LOCALLY_LOCKED?) if a lock is present with a different
ali@499
   262
 * owner so that razor_set_aquire_lock() can generate a different error message.
ali@499
   263
 */
ali@499
   264
ali@499
   265
static int
ali@499
   266
razor_uri_lock(const char *uri, int flags, mode_t mode, int exclusive,
ali@499
   267
	       struct razor_error **error)
ali@388
   268
{
ali@499
   269
	int fd, i;
ali@499
   270
	struct razor_uri_lock *ulock;
ali@499
   271
#ifdef MSWIN_API
ali@499
   272
	DWORD lflags = LOCKFILE_FAIL_IMMEDIATELY, err;
ali@499
   273
	OVERLAPPED lock = {0};
ali@499
   274
#else
ali@499
   275
	struct flock lock = {0};
ali@499
   276
#endif
ali@388
   277
ali@499
   278
	fd = razor_uri_open(uri, flags, mode, error);
ali@499
   279
	if (fd < 0)
ali@499
   280
		return -1;
ali@499
   281
ali@499
   282
	for (i = ptr_array_len(&razor_uri_locks) - 1; i >= 0; i--) {
ali@499
   283
		ulock = ptr_array_index(&razor_uri_locks, i);
ali@499
   284
		if (ulock && !strcmp(ulock->uri, uri)) {
ali@499
   285
			if (!ulock->exclusive && !exclusive)
ali@499
   286
				break;
ali@499
   287
			razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@499
   288
					RAZOR_GENERAL_ERROR_ALREADY_LOCKED,
ali@499
   289
					uri,
ali@499
   290
					"An existing lock is already held on this file");
ali@499
   291
			close(fd);
ali@388
   292
			return -1;
ali@499
   293
		}
ali@499
   294
	}
ali@388
   295
ali@388
   296
#ifdef MSWIN_API
ali@388
   297
	if (exclusive)
ali@499
   298
		lflags |= LOCKFILE_EXCLUSIVE_LOCK;
ali@499
   299
	if (!LockFileEx((HANDLE)_get_osfhandle(fd), lflags, 0, 1, 0, &lock)) {
ali@499
   300
		err = GetLastError();
ali@499
   301
		if (err == ERROR_IO_PENDING)
ali@499
   302
			razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@499
   303
					RAZOR_GENERAL_ERROR_EXTERNALLY_LOCKED,
ali@499
   304
					uri,
ali@499
   305
					"An existing lock is already held on this file");
ali@499
   306
		else
ali@499
   307
			razor_set_error_mswin(error, uri, err);
ali@388
   308
		close(fd);
ali@388
   309
		return -1;
ali@388
   310
	}
ali@388
   311
#else
ali@388
   312
	lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
ali@388
   313
	lock.l_whence = SEEK_SET;
ali@388
   314
	lock.l_start = 0;
ali@388
   315
	lock.l_len = 0;
ali@499
   316
	if (fcntl(fd, F_SETLK, &lock) < 0) {
ali@499
   317
		if (errno == EAGAIN || errno == EACCES)
ali@499
   318
			razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@499
   319
					RAZOR_GENERAL_ERROR_EXTERNALLY_LOCKED,
ali@499
   320
					uri,
ali@499
   321
					"An existing lock is already held on this file");
ali@499
   322
		else
ali@499
   323
			razor_set_error_posix(error, uri);
ali@388
   324
		close(fd);
ali@388
   325
		return -1;
ali@388
   326
	}
ali@388
   327
#endif
ali@388
   328
ali@499
   329
	ulock = zalloc(sizeof *ulock);
ali@499
   330
	ulock->uri = strdup(uri);
ali@499
   331
	ulock->fd = fd;
ali@499
   332
	ulock->exclusive = exclusive;
ali@499
   333
	return ptr_array_add(&razor_uri_locks, ulock);
ali@499
   334
}
ali@388
   335
ali@499
   336
static void
ali@499
   337
razor_uri_unlock(int id)
ali@499
   338
{
ali@499
   339
	struct razor_uri_lock *ulock;
ali@499
   340
#ifndef MSWIN_API
ali@499
   341
	struct flock lock = {0};
ali@499
   342
#endif
ali@499
   343
ali@499
   344
	if (id < 0 || id >= ptr_array_len(&razor_uri_locks))
ali@499
   345
		return;
ali@499
   346
ali@499
   347
	ulock = ptr_array_index(&razor_uri_locks, id);
ali@499
   348
ali@499
   349
	if (!ulock)
ali@499
   350
		return;
ali@499
   351
ali@499
   352
#ifdef MSWIN_API
ali@499
   353
	(void)UnlockFile((HANDLE)_get_osfhandle(ulock->fd), 0, 0, 1, 0);
ali@499
   354
#else
ali@499
   355
	lock.l_type = F_UNLCK;
ali@499
   356
	lock.l_whence = SEEK_SET;
ali@499
   357
	lock.l_start = 0;
ali@499
   358
	lock.l_len = 0;
ali@499
   359
	(void)fcntl(ulock->fd, F_SETLK, &lock);
ali@499
   360
#endif
ali@499
   361
ali@499
   362
	ptr_array_remove_index(&razor_uri_locks, id);
ali@499
   363
	free(ulock->uri);
ali@499
   364
	close(ulock->fd);
ali@499
   365
	free(ulock);
ali@499
   366
}
ali@499
   367
ali@499
   368
int
ali@499
   369
razor_set_acquire_lock(struct razor_set *set, const char *uri, int exclusive,
ali@499
   370
		       struct razor_error **error)
ali@499
   371
{
ali@499
   372
	int lock;
ali@499
   373
	const char *errstr = NULL;
ali@499
   374
	assert(set != NULL);
ali@499
   375
ali@499
   376
	if (!uri) {
ali@499
   377
		razor_uri_unlock(set->lock);
ali@499
   378
		set->lock = -1;
ali@499
   379
		return 0;
ali@499
   380
	}
ali@499
   381
ali@499
   382
	lock = razor_uri_lock(uri,
ali@499
   383
			      O_CREAT | O_RDWR | O_TRUNC | O_BINARY,
ali@499
   384
			      0666, exclusive, error);
ali@499
   385
ali@499
   386
	if (lock >= 0) {
ali@499
   387
		set->lock = lock;
ali@499
   388
		return 0;
ali@499
   389
	}
ali@499
   390
ali@499
   391
	if (!error)
ali@499
   392
		return -1;
ali@499
   393
		
ali@499
   394
	if (razor_error_matches(*error, RAZOR_GENERAL_ERROR,
ali@499
   395
				RAZOR_GENERAL_ERROR_ALREADY_LOCKED)) {
ali@499
   396
		/*
ali@499
   397
		 * This represents a design flaw in the caller.
ali@499
   398
		 */
ali@499
   399
		if (exclusive)
ali@499
   400
			errstr = "Database is in use and cannot be locked";
ali@499
   401
		else
ali@499
   402
			errstr = "Database is being updated and cannot be locked";
ali@499
   403
	} else if (razor_error_matches(*error, RAZOR_GENERAL_ERROR,
ali@499
   404
				       RAZOR_GENERAL_ERROR_EXTERNALLY_LOCKED)) {
ali@499
   405
		/*
ali@499
   406
		 * This is probably caused by another application holding
ali@499
   407
		 * the lock, but under MS-Windows the file could in theory
ali@499
   408
		 * be locked by this application outside of razor_set.
ali@499
   409
		 */
ali@499
   410
		if (exclusive)
ali@499
   411
			errstr = "Database is in use. Please try again later";
ali@499
   412
		else
ali@499
   413
			errstr = "Database is being updated. Please try again later";
ali@499
   414
	}
ali@499
   415
ali@499
   416
	if (errstr) {
ali@499
   417
		razor_error_free(*error);
ali@499
   418
		razor_set_error(error,
ali@499
   419
				RAZOR_GENERAL_ERROR,
ali@499
   420
				RAZOR_GENERAL_ERROR_DATABASE_LOCKED,
ali@499
   421
				uri, errstr);
ali@499
   422
	}
ali@499
   423
ali@499
   424
	return -1;
ali@388
   425
}
ali@388
   426
ali@403
   427
static void
rhughes@241
   428
razor_set_destroy(struct razor_set *set)
rhughes@241
   429
{
krh@373
   430
	struct razor_mapped_file *file, *next;
krh@373
   431
	struct array *array;
rhughes@241
   432
	int i;
rhughes@241
   433
richard@301
   434
	assert (set != NULL);
richard@301
   435
krh@373
   436
	if (set->mapped_files == NULL) {
krh@373
   437
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@373
   438
			array = (void *) set + razor_sections[i].offset;
krh@373
   439
			array_release(array);
krh@373
   440
		}
rhughes@241
   441
	} else {
krh@373
   442
		for (file = set->mapped_files; file != NULL; file = next) {
krh@373
   443
			next = file->next;
ali@475
   444
			razor_uri_free_contents(file->header, file->size);
krh@373
   445
			free(file);
jbowes@258
   446
		}
jbowes@258
   447
	}
jbowes@258
   448
ali@499
   449
	razor_set_acquire_lock(set, NULL, 0, NULL);
rhughes@241
   450
	free(set);
rhughes@241
   451
}
rhughes@241
   452
ali@403
   453
RAZOR_EXPORT void
ali@403
   454
razor_set_unref(struct razor_set *set)
ali@403
   455
{
ali@403
   456
	if (set && !--set->ref_count)
ali@403
   457
		razor_set_destroy(set);
ali@403
   458
}
ali@403
   459
ali@403
   460
RAZOR_EXPORT struct razor_set *
ali@403
   461
razor_set_ref(struct razor_set *set)
ali@403
   462
{
ali@403
   463
	if (set)
ali@403
   464
		set->ref_count++;
ali@403
   465
	return set;
ali@403
   466
}
ali@403
   467
ali@403
   468
RAZOR_EXPORT void
ali@403
   469
razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic,
ali@403
   470
			  int handle, uint32_t section_mask)
rhughes@241
   471
{
jbowes@318
   472
	struct razor_set_header header;
krh@373
   473
	struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
jbowes@318
   474
	struct hashtable table;
krh@373
   475
	struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
rhughes@241
   476
	uint32_t offset;
krh@373
   477
	int count, i, j;
krh@373
   478
	static const char padding[4];
jbowes@318
   479
jbowes@318
   480
	array_init(&pool);
jbowes@318
   481
	hashtable_init(&table, &pool);
jbowes@318
   482
krh@373
   483
	j = 0;
krh@373
   484
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@373
   485
		if ((razor_sections[i].flags & section_mask) == 0)
krh@373
   486
			continue;
jbowes@318
   487
krh@373
   488
		arrays[j] = (void *) set + razor_sections[i].offset;
krh@373
   489
		sections[j].name =
krh@373
   490
			hashtable_tokenize(&table, razor_sections[i].name);
krh@373
   491
		j++;
krh@373
   492
	}
rhughes@241
   493
krh@373
   494
	count = j;
krh@373
   495
	header.magic = RAZOR_MAGIC;
ali@403
   496
	header.version = set->header_version;
krh@373
   497
	header.num_sections = count;
krh@373
   498
	offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
krh@373
   499
krh@373
   500
	for (i = 0; i < count; i++) {
krh@373
   501
		sections[i].offset = offset;
krh@373
   502
		sections[i].size = arrays[i]->size;
krh@373
   503
		offset += ALIGN(arrays[i]->size, 4);
rhughes@241
   504
	}
rhughes@241
   505
ali@403
   506
	razor_atomic_write(atomic, handle, &header, sizeof header);
ali@403
   507
	razor_atomic_write(atomic, handle, sections, count * sizeof *sections);
ali@403
   508
	razor_atomic_write(atomic, handle, pool.data, pool.size);
ali@403
   509
	razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4));
rhughes@241
   510
krh@373
   511
	for (i = 0; i < count; i++) {
ali@403
   512
		razor_atomic_write(atomic, handle, arrays[i]->data,
ali@403
   513
				   arrays[i]->size);
ali@403
   514
		razor_atomic_write(atomic, handle, padding,
ali@403
   515
				   PADDING(arrays[i]->size, 4));
rhughes@241
   516
	}
rhughes@241
   517
krh@373
   518
	array_release(&pool);
krh@373
   519
	hashtable_release(&table);
rhughes@241
   520
}
rhughes@241
   521
krh@269
   522
RAZOR_EXPORT int
ali@403
   523
razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
ali@475
   524
		const char *uri, uint32_t sections)
rhughes@241
   525
{
ali@403
   526
	int h;
rhughes@241
   527
ali@475
   528
	h = razor_atomic_create_file(atomic, uri,
ali@403
   529
				     S_IRWXU | S_IRWXG | S_IRWXO);
ali@403
   530
	if (h < 0)
rhughes@241
   531
		return -1;
rhughes@241
   532
ali@403
   533
	razor_set_write_to_handle(set, atomic, h, sections);
rhughes@241
   534
ali@403
   535
	return razor_atomic_close(atomic, h);
rhughes@241
   536
}
krh@269
   537
krh@269
   538
RAZOR_EXPORT void
rhughes@241
   539
razor_build_evr(char *evr_buf, int size, const char *epoch,
rhughes@241
   540
		const char *version, const char *release)
rhughes@241
   541
{
rhughes@241
   542
	int len;
rhughes@241
   543
rhughes@241
   544
	if (!version || !*version) {
rhughes@241
   545
		*evr_buf = '\0';
rhughes@241
   546
		return;
rhughes@241
   547
	}
rhughes@241
   548
rhughes@241
   549
	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
rhughes@241
   550
		len = snprintf(evr_buf, size, "%s:", epoch);
rhughes@241
   551
		evr_buf += len;
rhughes@241
   552
		size -= len;
rhughes@241
   553
	}
rhughes@241
   554
	len = snprintf(evr_buf, size, "%s", version);
rhughes@241
   555
	evr_buf += len;
rhughes@241
   556
	size -= len;
rhughes@241
   557
	if (release && *release)
rhughes@241
   558
		snprintf(evr_buf, size, "-%s", release);
rhughes@241
   559
}
rhughes@241
   560
krh@269
   561
RAZOR_EXPORT int
krh@248
   562
razor_versioncmp(const char *s1, const char *s2)
rhughes@241
   563
{
rhughes@241
   564
	const char *p1, *p2;
rhughes@241
   565
	long n1, n2;
rhughes@241
   566
	int res;
rhughes@241
   567
richard@301
   568
	assert (s1 != NULL);
richard@301
   569
	assert (s2 != NULL);
richard@301
   570
rhughes@241
   571
	n1 = strtol(s1, (char **) &p1, 10);
rhughes@241
   572
	n2 = strtol(s2, (char **) &p2, 10);
rhughes@241
   573
rhughes@241
   574
	/* Epoch; if one but not the other has an epoch set, default
rhughes@241
   575
	 * the epoch-less version to 0. */
rhughes@241
   576
	res = (*p1 == ':') - (*p2 == ':');
rhughes@241
   577
	if (res < 0) {
rhughes@241
   578
		n1 = 0;
rhughes@241
   579
		p1 = s1;
rhughes@241
   580
		p2++;
rhughes@241
   581
	} else if (res > 0) {
rhughes@241
   582
		p1++;
rhughes@241
   583
		n2 = 0;
rhughes@241
   584
		p2 = s2;
rhughes@241
   585
	}
rhughes@241
   586
rhughes@241
   587
	if (n1 != n2)
rhughes@241
   588
		return n1 - n2;
rhughes@241
   589
	while (*p1 && *p2) {
rhughes@241
   590
		if (*p1 != *p2)
rhughes@241
   591
			return *p1 - *p2;
rhughes@241
   592
		p1++;
rhughes@241
   593
		p2++;
rhughes@241
   594
		if (isdigit(*p1) && isdigit(*p2))
krh@248
   595
			return razor_versioncmp(p1, p2);
rhughes@241
   596
	}
rhughes@241
   597
rhughes@241
   598
	return *p1 - *p2;
rhughes@241
   599
}
rhughes@241
   600
richard@302
   601
static const char *
ali@372
   602
razor_package_get_details_string(struct razor_set *set,
ali@372
   603
				 struct razor_package *package,
ali@372
   604
				 enum razor_detail_type type)
richard@302
   605
{
richard@302
   606
	const char *pool;
richard@302
   607
richard@302
   608
	switch (type) {
richard@302
   609
	case RAZOR_DETAIL_NAME:
richard@302
   610
		pool = set->string_pool.data;
richard@302
   611
		return &pool[package->name];
richard@302
   612
richard@302
   613
	case RAZOR_DETAIL_VERSION:
richard@302
   614
		pool = set->string_pool.data;
richard@302
   615
		return &pool[package->version];
richard@302
   616
richard@302
   617
	case RAZOR_DETAIL_ARCH:
richard@302
   618
		pool = set->string_pool.data;
richard@302
   619
		return &pool[package->arch];
richard@302
   620
richard@302
   621
	case RAZOR_DETAIL_SUMMARY:
ali@395
   622
		if (!set->details_string_pool.size)
ali@395
   623
			return "";
richard@302
   624
		pool = set->details_string_pool.data;
richard@302
   625
		return &pool[package->summary];
richard@302
   626
richard@302
   627
	case RAZOR_DETAIL_DESCRIPTION:
ali@395
   628
		if (!set->details_string_pool.size)
ali@395
   629
			return "";
richard@302
   630
		pool = set->details_string_pool.data;
richard@302
   631
		return &pool[package->description];
richard@302
   632
richard@302
   633
	case RAZOR_DETAIL_URL:
ali@395
   634
		if (!set->details_string_pool.size)
ali@395
   635
			return "";
richard@302
   636
		pool = set->details_string_pool.data;
richard@302
   637
		return &pool[package->url];
richard@302
   638
richard@302
   639
	case RAZOR_DETAIL_LICENSE:
ali@395
   640
		if (!set->details_string_pool.size)
ali@395
   641
			return "";
richard@302
   642
		pool = set->details_string_pool.data;
richard@302
   643
		return &pool[package->license];
richard@302
   644
ali@369
   645
	case RAZOR_DETAIL_PREUNPROG:
ali@369
   646
		pool = set->string_pool.data;
ali@369
   647
		return &pool[package->preun.program];
ali@369
   648
ali@369
   649
	case RAZOR_DETAIL_PREUN:
ali@369
   650
		pool = set->string_pool.data;
ali@369
   651
		return &pool[package->preun.body];
ali@369
   652
ali@369
   653
	case RAZOR_DETAIL_POSTUNPROG:
ali@369
   654
		pool = set->string_pool.data;
ali@369
   655
		return &pool[package->postun.program];
ali@369
   656
ali@369
   657
	case RAZOR_DETAIL_POSTUN:
ali@369
   658
		pool = set->string_pool.data;
ali@369
   659
		return &pool[package->postun.body];
ali@369
   660
richard@302
   661
	default:
richard@302
   662
		fprintf(stderr, "type %u not found\n", type);
richard@302
   663
		return NULL;
richard@302
   664
	}
richard@302
   665
}
richard@302
   666
ali@372
   667
static const char *const *
ali@372
   668
razor_package_get_details_array(struct razor_set *set,
ali@372
   669
				struct razor_package *package,
ali@372
   670
				enum razor_detail_type type)
ali@372
   671
{
ali@372
   672
	switch (type) {
ali@372
   673
	case RAZOR_DETAIL_PREFIXES:
ali@462
   674
		/* We don't track prefixes in packages. Install
ali@462
   675
		 * prefixes are tracked, and made available via
ali@462
   676
		 * razor_install_prefix_iterator_create().
ali@372
   677
		 */
ali@372
   678
		return NULL;
ali@372
   679
ali@372
   680
	default:
ali@372
   681
		fprintf(stderr, "type %u not found\n", type);
ali@372
   682
		return NULL;
ali@372
   683
	}
ali@372
   684
}
ali@372
   685
richard@302
   686
/**
richard@302
   687
 * razor_package_get_details_varg:
richard@302
   688
 * @set: a %razor_set
richard@302
   689
 * @package: a %razor_package
richard@302
   690
 * @args: a va_list of arguments to set
richard@302
   691
 **/
richard@302
   692
void
richard@302
   693
razor_package_get_details_varg(struct razor_set *set,
richard@302
   694
			       struct razor_package *package,
richard@302
   695
			       va_list args)
richard@302
   696
{
richard@302
   697
	int i;
richard@302
   698
	enum razor_detail_type type;
ali@372
   699
	const char **string;
ali@372
   700
	const char *const **array;
richard@302
   701
richard@302
   702
	for (i = 0;; i += 2) {
richard@302
   703
		type = va_arg(args, enum razor_detail_type);
richard@307
   704
		if (type == RAZOR_DETAIL_LAST)
richard@302
   705
			break;
ali@372
   706
		if (type == RAZOR_DETAIL_PREFIXES) {
ali@372
   707
			array = va_arg(args, const char *const **);
ali@372
   708
			*array = razor_package_get_details_array(set, package,
ali@372
   709
								 type);
ali@372
   710
		} else {
ali@372
   711
			string = va_arg(args, const char **);
ali@372
   712
			*string = razor_package_get_details_string(set, package,
ali@372
   713
								   type);
ali@372
   714
		}
richard@302
   715
	}
richard@302
   716
richard@302
   717
}
richard@302
   718
richard@302
   719
/**
richard@302
   720
 * razor_package_get_details:
richard@302
   721
 * @set: a %razor_set
richard@302
   722
 * @package: a %razor_package
richard@302
   723
 *
richard@302
   724
 * Gets details about a package using a varg interface
krh@308
   725
 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
richard@302
   726
 *
richard@307
   727
 * Example: razor_package_get_details (set, package,
richard@307
   728
 *				       RAZOR_DETAIL_URL, &url,
richard@307
   729
 *				       RAZOR_DETAIL_LAST);
richard@302
   730
 **/
krh@269
   731
RAZOR_EXPORT void
richard@302
   732
razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
jbowes@258
   733
{
richard@302
   734
	va_list args;
jbowes@258
   735
richard@301
   736
	assert (set != NULL);
richard@301
   737
	assert (package != NULL);
richard@301
   738
richard@302
   739
	va_start(args, NULL);
richard@302
   740
	razor_package_get_details_varg (set, package, args);
richard@302
   741
	va_end (args);
jbowes@258
   742
}
jbowes@258
   743
ali@369
   744
/**
ali@369
   745
 * razor_package_remove:
ali@382
   746
 * @prev: The %razor_set before the current transaction
ali@382
   747
 * @next: The %razor_set after the current transaction is applied
ali@369
   748
 * @package: a %razor_package
ali@369
   749
 * @root: the root into which the package is currently installed
ali@376
   750
 * @install_count: the value to pass to uninstall scripts
ali@403
   751
 * @stage: Limit the removal to just the scripts or the files
ali@369
   752
 *
ali@369
   753
 * Removes an installed package.
ali@369
   754
 **/
ali@369
   755
RAZOR_EXPORT int
ali@382
   756
razor_package_remove(struct razor_set *prev, struct razor_set *next,
ali@403
   757
		     struct razor_atomic *atomic, struct razor_package *package,
ali@479
   758
		     const char *root_uri, int install_count,
ali@403
   759
		     enum razor_stage_type stage)
ali@369
   760
{
ali@369
   761
	struct razor_file_iterator *fi;
ali@369
   762
	struct razor_package_iterator *pi;
ali@369
   763
	struct razor_package *p;
ali@479
   764
	char *uri, *relative, *buffer, buf[32];
ali@369
   765
	const char *name, *program, *script;
ali@422
   766
	int i, count, retval = 0;
ali@372
   767
	struct environment env;
ali@372
   768
	struct list *link;
ali@372
   769
	const char *prefix;
ali@475
   770
	struct razor_error *tmp_error = NULL;
ali@369
   771
ali@403
   772
	if (stage & RAZOR_STAGE_SCRIPTS) {
ali@403
   773
		environment_init(&env);
ali@403
   774
		link = list_first(&package->install_prefixes,
ali@403
   775
				  &prev->prefix_pool);
ali@403
   776
		for (i = 0; link; i++) {
ali@403
   777
			prefix = (const char *)prev->string_pool.data +
ali@403
   778
				 link->data;
ali@411
   779
			sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
ali@411
   780
			environment_add_variable(&env, buf, prefix);
ali@403
   781
			link = list_next(link);
ali@403
   782
		}
ali@403
   783
		environment_set(&env);
ali@375
   784
	}
ali@375
   785
ali@403
   786
	if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
ali@403
   787
		razor_package_get_details(prev, package,
ali@403
   788
					  RAZOR_DETAIL_PREUNPROG, &program,
ali@403
   789
					  RAZOR_DETAIL_PREUN, &script,
ali@403
   790
					  RAZOR_DETAIL_LAST);
ali@369
   791
ali@479
   792
		retval = razor_run_script(root_uri, RAZOR_PROPERTY_PREUN,
ali@479
   793
					  program, script, install_count,
ali@479
   794
					  &tmp_error);
ali@475
   795
ali@475
   796
		if (retval < 0) {
ali@475
   797
			razor_atomic_propagate_error(atomic, tmp_error, NULL);
ali@475
   798
			tmp_error = NULL;
ali@475
   799
		}
ali@403
   800
	}
ali@375
   801
ali@422
   802
	if (!retval && (stage & RAZOR_STAGE_FILES)) {
ali@403
   803
		fi = razor_file_iterator_create(prev, package, 1);
ali@369
   804
ali@403
   805
		while (razor_file_iterator_next(fi, &name)) {
ali@403
   806
			pi = razor_package_iterator_create_for_file(next, name);
ali@403
   807
			count = 0;
ali@403
   808
			while (razor_package_iterator_next(pi, &p,
ali@403
   809
							   RAZOR_DETAIL_LAST))
ali@403
   810
				count++;
ali@403
   811
			razor_package_iterator_destroy(pi);
ali@403
   812
			if (count <= 0) {
ali@479
   813
				uri = razor_path_to_uri(name);
ali@479
   814
ali@479
   815
				if (str_has_prefix(uri, "file:///"))
ali@479
   816
					relative = uri + 8;
ali@479
   817
				else if (str_has_prefix(uri, "file:/"))
ali@479
   818
					relative = uri + 6;
ali@479
   819
				else if (str_has_prefix(uri, "file:"))
ali@479
   820
					relative = uri + 5;
ali@479
   821
				else if (str_has_prefix(uri, "/"))
ali@479
   822
					relative = uri + 1;
ali@479
   823
				else
ali@479
   824
					relative = uri;
ali@479
   825
ali@479
   826
				buffer = razor_resolve_uri_root(root_uri,
ali@479
   827
								relative, 1,
ali@479
   828
								&tmp_error);
ali@479
   829
				free(uri);
ali@479
   830
ali@479
   831
				if (buffer) {
ali@479
   832
					razor_atomic_remove(atomic, buffer);
ali@479
   833
					free(buffer);
ali@479
   834
				} else {
ali@479
   835
					razor_atomic_propagate_error(atomic,
ali@479
   836
								     tmp_error,
ali@479
   837
								     NULL);
ali@479
   838
					tmp_error = NULL;
ali@479
   839
					break;
ali@479
   840
				}
ali@377
   841
			}
ali@369
   842
		}
ali@403
   843
ali@403
   844
		razor_file_iterator_destroy(fi);
ali@422
   845
ali@422
   846
		retval = razor_atomic_in_error_state(atomic);
ali@369
   847
	}
ali@369
   848
ali@422
   849
	if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST)) {
ali@403
   850
		razor_package_get_details(prev, package,
ali@403
   851
					  RAZOR_DETAIL_POSTUNPROG, &program,
ali@403
   852
					  RAZOR_DETAIL_POSTUN, &script,
ali@403
   853
					  RAZOR_DETAIL_LAST);
ali@369
   854
ali@479
   855
		retval |= razor_run_script(root_uri, RAZOR_PROPERTY_POSTUN,
ali@479
   856
					   program, script, install_count,
ali@479
   857
					   &tmp_error);
ali@475
   858
ali@475
   859
		if (retval < 0) {
ali@475
   860
			razor_atomic_propagate_error(atomic, tmp_error, NULL);
ali@475
   861
			tmp_error = NULL;
ali@475
   862
		}
ali@403
   863
	}
ali@369
   864
ali@403
   865
	if (stage & RAZOR_STAGE_SCRIPTS) {
ali@403
   866
		environment_unset(&env);
ali@403
   867
		environment_release(&env);
ali@403
   868
	}
ali@377
   869
ali@422
   870
	return retval;
ali@369
   871
}
ali@369
   872
krh@270
   873
RAZOR_EXPORT const char *
krh@270
   874
razor_property_relation_to_string(struct razor_property *p)
krh@270
   875
{
richard@301
   876
	assert (p != NULL);
richard@301
   877
krh@270
   878
	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
krh@270
   879
	case RAZOR_PROPERTY_LESS:
krh@270
   880
		return "<";
krh@270
   881
krh@270
   882
	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
krh@270
   883
		return "<=";
krh@270
   884
krh@270
   885
	case RAZOR_PROPERTY_EQUAL:
krh@270
   886
		return "=";
krh@270
   887
krh@270
   888
	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
krh@270
   889
		return ">=";
krh@270
   890
krh@270
   891
	case RAZOR_PROPERTY_GREATER:
krh@270
   892
		return ">";
krh@270
   893
krh@270
   894
	default:
krh@270
   895
		return "?";
krh@270
   896
	}
krh@270
   897
}
krh@270
   898
krh@270
   899
RAZOR_EXPORT const char *
krh@270
   900
razor_property_type_to_string(struct razor_property *p)
krh@270
   901
{
richard@301
   902
	assert (p != NULL);
richard@301
   903
krh@270
   904
	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
krh@270
   905
	case RAZOR_PROPERTY_REQUIRES:
krh@270
   906
		return "requires";
krh@270
   907
	case RAZOR_PROPERTY_PROVIDES:
krh@270
   908
		return "provides";
krh@270
   909
	case RAZOR_PROPERTY_CONFLICTS:
krh@270
   910
		return "conflicts";
krh@270
   911
	case RAZOR_PROPERTY_OBSOLETES:
krh@270
   912
		return "obsoletes";
krh@270
   913
	default:
krh@270
   914
		return NULL;
krh@270
   915
	}
krh@270
   916
}
krh@270
   917
krh@269
   918
RAZOR_EXPORT struct razor_entry *
krh@248
   919
razor_set_find_entry(struct razor_set *set,
krh@248
   920
		     struct razor_entry *dir, const char *pattern)
rhughes@241
   921
{
ali@359
   922
	struct razor_entry *e, *subdir;
jbowes@264
   923
	const char *n, *pool = set->file_string_pool.data;
rhughes@241
   924
	int len;
rhughes@241
   925
richard@301
   926
	assert (set != NULL);
richard@301
   927
	assert (pattern != NULL);
richard@301
   928
ali@383
   929
	if (dir == NULL)
ali@383
   930
		return NULL;
ali@383
   931
ali@359
   932
	e = dir;
rhughes@241
   933
	do {
rhughes@241
   934
		n = pool + e->name;
ali@359
   935
		if (strcmp(pattern, n) == 0)
rhughes@241
   936
			return e;
rhughes@241
   937
		len = strlen(n);
ali@359
   938
		if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
ali@359
   939
		    pattern[len] == '/') {
ali@359
   940
			subdir = (struct razor_entry *) set->files.data +
ali@359
   941
				 e->start;
ali@359
   942
			return razor_set_find_entry(set, subdir,
ali@359
   943
						    pattern + len + 1);
rhughes@241
   944
		}
rhughes@241
   945
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   946
rhughes@241
   947
	return NULL;
rhughes@241
   948
}
rhughes@241
   949
rhughes@241
   950
static void
rhughes@241
   951
list_dir(struct razor_set *set, struct razor_entry *dir,
rhughes@241
   952
	 char *prefix, const char *pattern)
rhughes@241
   953
{
ali@359
   954
	struct razor_entry *e, *subdir;
jbowes@274
   955
	const char *n, *pool = set->file_string_pool.data;
rhughes@241
   956
ali@359
   957
	e = dir;
rhughes@241
   958
	do {
rhughes@241
   959
		n = pool + e->name;
rhughes@241
   960
		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
rhughes@241
   961
			continue;
rhughes@241
   962
		printf("%s/%s\n", prefix, n);
rhughes@241
   963
		if (e->start) {
rhughes@241
   964
			char *sub = prefix + strlen (prefix);
rhughes@241
   965
			*sub = '/';
rhughes@241
   966
			strcpy (sub + 1, n);
ali@359
   967
			subdir = (struct razor_entry *) set->files.data +
ali@359
   968
				 e->start;
ali@359
   969
			list_dir(set, subdir, prefix, pattern);
rhughes@241
   970
			*sub = '\0';
rhughes@241
   971
		}
rhughes@241
   972
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   973
}
rhughes@241
   974
krh@269
   975
RAZOR_EXPORT void
rhughes@241
   976
razor_set_list_files(struct razor_set *set, const char *pattern)
rhughes@241
   977
{
ali@359
   978
	struct razor_entry *root, *e;
rhughes@241
   979
	char buffer[512], *p, *base;
rhughes@241
   980
richard@301
   981
	assert (set != NULL);
richard@301
   982
ali@359
   983
	root = (struct razor_entry *) set->files.data;
ali@359
   984
ali@359
   985
	if (pattern == NULL) {
ali@359
   986
		p = set->file_string_pool.data;
ali@359
   987
		e = root;
ali@359
   988
		do {
ali@359
   989
			if (e->start) {
ali@359
   990
				strcpy(buffer, p + e->name);
ali@359
   991
				list_dir(set, root + e->start, buffer, NULL);
ali@359
   992
			}
ali@359
   993
		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   994
		return;
rhughes@241
   995
	}
rhughes@241
   996
rhughes@241
   997
	strcpy(buffer, pattern);
ali@359
   998
	e = razor_set_find_entry(set, root, buffer);
ali@359
   999
	if (e && e->start) {
rhughes@241
  1000
		base = NULL;
rhughes@241
  1001
	} else {
rhughes@241
  1002
		p = strrchr(buffer, '/');
rhughes@241
  1003
		if (p) {
rhughes@241
  1004
			*p = '\0';
rhughes@241
  1005
			base = p + 1;
rhughes@241
  1006
		} else {
rhughes@241
  1007
			base = NULL;
rhughes@241
  1008
		}
rhughes@241
  1009
	}
ali@359
  1010
	e = razor_set_find_entry(set, root, buffer);
ali@359
  1011
	if (e && e->start)
ali@359
  1012
		list_dir(set, root + e->start, buffer, base);
rhughes@241
  1013
}
rhughes@241
  1014
krh@269
  1015
RAZOR_EXPORT void
krh@306
  1016
razor_set_list_package_files(struct razor_set *set,
krh@306
  1017
			     struct razor_package *package)
rhughes@241
  1018
{
ali@351
  1019
	struct razor_file_iterator *fi;
ali@351
  1020
	const char *name;
rhughes@241
  1021
richard@301
  1022
	assert (set != NULL);
krh@306
  1023
	assert (package != NULL);
rhughes@241
  1024
ali@377
  1025
	fi = razor_file_iterator_create(set, package, 0);
ali@351
  1026
ali@351
  1027
	while (razor_file_iterator_next(fi, &name))
ali@351
  1028
		printf("%s\n", name);
ali@351
  1029
ali@351
  1030
	razor_file_iterator_destroy(fi);
rhughes@241
  1031
}
rhughes@241
  1032
ali@387
  1033
/*
ali@387
  1034
 * Package data can potentially come from two places. The so-called
ali@387
  1035
 * metadata (eg., from comps.xml) and from an RPM file. We consider
ali@387
  1036
 * a package which has additional data from an RPM file as "fixed".
ali@387
  1037
 * If a package needs fixing, then razor_transaction_fixup_package()
ali@387
  1038
 * will do so. When considering what packages to add and to remove
ali@387
  1039
 * we need to take this into account since we always want to add
ali@387
  1040
 * unfixed packages (otherwise we have a potential conflict between
ali@387
  1041
 * the existing package data and that present in the RPM).
ali@387
  1042
 */
ali@387
  1043
static int
ali@387
  1044
razor_package_is_fixed(struct razor_set *set, struct razor_package *p)
ali@387
  1045
{
ali@387
  1046
	const char *preunprog, *preun, *postunprog, *postun;
ali@387
  1047
ali@387
  1048
	if (!p)
ali@387
  1049
		return 0;
ali@387
  1050
	razor_package_get_details(set, p,
ali@387
  1051
				  RAZOR_DETAIL_PREUNPROG, &preunprog,
ali@387
  1052
				  RAZOR_DETAIL_PREUN, &preun,
ali@387
  1053
				  RAZOR_DETAIL_POSTUNPROG, &postunprog,
ali@387
  1054
				  RAZOR_DETAIL_POSTUN, &postun,
ali@387
  1055
				  RAZOR_DETAIL_LAST);
ali@387
  1056
	return *preunprog || *preun || *postunprog || *postun;
ali@387
  1057
}
ali@387
  1058
krh@269
  1059
RAZOR_EXPORT void
rhughes@241
  1060
razor_set_diff(struct razor_set *set, struct razor_set *upstream,
krh@253
  1061
	       razor_diff_callback_t callback, void *data)
rhughes@241
  1062
{
rhughes@241
  1063
 	struct razor_package_iterator *pi1, *pi2;
rhughes@241
  1064
 	struct razor_package *p1, *p2;
rhughes@241
  1065
	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
ali@387
  1066
	int res, is_fixed1, is_fixed2;
rhughes@241
  1067
richard@301
  1068
	assert (set != NULL);
richard@301
  1069
	assert (upstream != NULL);
richard@301
  1070
rhughes@241
  1071
	pi1 = razor_package_iterator_create(set);
rhughes@241
  1072
	pi2 = razor_package_iterator_create(upstream);
rhughes@241
  1073
richard@302
  1074
	razor_package_iterator_next(pi1, &p1,
richard@302
  1075
				    RAZOR_DETAIL_NAME, &name1,
richard@302
  1076
				    RAZOR_DETAIL_VERSION, &version1,
richard@302
  1077
				    RAZOR_DETAIL_ARCH, &arch1,
richard@307
  1078
				    RAZOR_DETAIL_LAST);
ali@387
  1079
	is_fixed1 = razor_package_is_fixed(set, p1);
richard@302
  1080
	razor_package_iterator_next(pi2, &p2,
richard@302
  1081
				    RAZOR_DETAIL_NAME, &name2,
richard@302
  1082
				    RAZOR_DETAIL_VERSION, &version2,
richard@302
  1083
				    RAZOR_DETAIL_ARCH, &arch2,
richard@307
  1084
				    RAZOR_DETAIL_LAST);
ali@387
  1085
	is_fixed2 = razor_package_is_fixed(upstream, p2);
rhughes@241
  1086
rhughes@241
  1087
	while (p1 || p2) {
rhughes@241
  1088
		if (p1 && p2) {
rhughes@241
  1089
			res = strcmp(name1, name2);
rhughes@241
  1090
			if (res == 0)
krh@248
  1091
				res = razor_versioncmp(version1, version2);
ali@387
  1092
			if (res == 0)
ali@387
  1093
				res = is_fixed1 - is_fixed2;
rhughes@241
  1094
		} else {
rhughes@241
  1095
			res = 0;
rhughes@241
  1096
		}
rhughes@241
  1097
rhughes@241
  1098
		if (p2 == NULL || res < 0)
krh@253
  1099
			callback(RAZOR_DIFF_ACTION_REMOVE,
krh@253
  1100
				 p1, name1, version1, arch1, data);
rhughes@241
  1101
		else if (p1 == NULL || res > 0)
krh@253
  1102
			callback(RAZOR_DIFF_ACTION_ADD,
krh@253
  1103
				 p2, name2, version2, arch2, data);
rhughes@241
  1104
ali@387
  1105
		if (p1 != NULL && res <= 0) {
rhughes@241
  1106
			razor_package_iterator_next(pi1, &p1,
richard@302
  1107
						    RAZOR_DETAIL_NAME, &name1,
richard@302
  1108
						    RAZOR_DETAIL_VERSION, &version1,
richard@302
  1109
						    RAZOR_DETAIL_ARCH, &arch1,
richard@307
  1110
						    RAZOR_DETAIL_LAST);
ali@387
  1111
			is_fixed1 = razor_package_is_fixed(set, p1);
ali@387
  1112
		}
ali@387
  1113
		if (p2 != NULL && res >= 0) {
rhughes@241
  1114
			razor_package_iterator_next(pi2, &p2,
richard@302
  1115
						    RAZOR_DETAIL_NAME, &name2,
richard@302
  1116
						    RAZOR_DETAIL_VERSION, &version2,
richard@302
  1117
						    RAZOR_DETAIL_ARCH, &arch2,
richard@307
  1118
						    RAZOR_DETAIL_LAST);
ali@387
  1119
			is_fixed2 = razor_package_is_fixed(upstream, p2);
ali@387
  1120
		}
rhughes@241
  1121
	}
rhughes@241
  1122
rhughes@241
  1123
	razor_package_iterator_destroy(pi1);
rhughes@241
  1124
	razor_package_iterator_destroy(pi2);
rhughes@241
  1125
}
krh@254
  1126
krh@316
  1127
struct install_action {
krh@316
  1128
	enum razor_install_action action;
krh@316
  1129
	struct razor_package *package;
krh@316
  1130
};
krh@316
  1131
krh@316
  1132
struct razor_install_iterator {
krh@316
  1133
	struct razor_set *set;
krh@316
  1134
	struct razor_set *next;
krh@316
  1135
	struct array actions;
ali@403
  1136
	struct deque *order, *left;
krh@316
  1137
};
krh@316
  1138
krh@254
  1139
static void
krh@316
  1140
add_action(enum razor_diff_action action,
krh@316
  1141
	   struct razor_package *package,
krh@316
  1142
	   const char *name,
krh@316
  1143
	   const char *version,
krh@316
  1144
	   const char *arch,
krh@316
  1145
	   void *data)
krh@254
  1146
{
krh@316
  1147
	struct razor_install_iterator *ii = data;
krh@316
  1148
	struct install_action *a;
krh@316
  1149
krh@316
  1150
	a = array_add(&ii->actions, sizeof *a);
krh@316
  1151
	a->package = package;
krh@316
  1152
krh@316
  1153
	switch (action) {
krh@316
  1154
	case RAZOR_DIFF_ACTION_ADD:
krh@316
  1155
		a->action = RAZOR_INSTALL_ACTION_ADD;
krh@316
  1156
		break;
krh@316
  1157
	case RAZOR_DIFF_ACTION_REMOVE:
krh@316
  1158
		a->action = RAZOR_INSTALL_ACTION_REMOVE;
krh@316
  1159
		break;
krh@316
  1160
	}
krh@254
  1161
}
krh@254
  1162
ali@418
  1163
/*
ali@418
  1164
 * Does <package> have a requirement for <script> which is
ali@418
  1165
 * satisfied by <provider> ?
ali@418
  1166
 * Note: We already know that <provider> is to be added as part of this install
ali@418
  1167
 * so there is no need to check the relation.
ali@418
  1168
 */
ali@418
  1169
static int
ali@418
  1170
package_script_requires(struct razor_set *set, struct razor_package *package,
ali@418
  1171
			enum razor_property_flags script,
ali@418
  1172
			struct razor_package *provider)
ali@418
  1173
{
ali@418
  1174
	struct list *link;
ali@418
  1175
	struct razor_property *prop;
ali@418
  1176
ali@418
  1177
	link = list_first(&package->properties, &set->property_pool);
ali@418
  1178
	for(; link; link = list_next(link)) {
ali@418
  1179
		prop = set->properties.data;
ali@418
  1180
		prop += link->data;
ali@418
  1181
		if ((prop->flags & RAZOR_PROPERTY_SCRIPT_MASK) & script &&
ali@418
  1182
		    (prop->flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES &&
ali@418
  1183
		    provider->name == prop->name)
ali@418
  1184
			return 1;
ali@418
  1185
	}
ali@418
  1186
	return 0;
ali@418
  1187
}
ali@418
  1188
krh@316
  1189
RAZOR_EXPORT struct razor_install_iterator *
krh@316
  1190
razor_set_create_install_iterator(struct razor_set *set,
krh@316
  1191
				  struct razor_set *next)
krh@254
  1192
{
krh@316
  1193
	struct razor_install_iterator *ii;
ali@367
  1194
	struct razor_property *prop;
ali@367
  1195
	/* A graph of the actions to be perfomed where
ali@367
  1196
	 * A->B means action A should follow action B.
ali@367
  1197
	 */
ali@367
  1198
	struct graph follows;
ali@418
  1199
	struct install_action *actions, *ai, *aj, *an;
ali@367
  1200
	int i, j, count, vertex_added;
ali@367
  1201
	struct list *link;
ali@367
  1202
	struct razor_set *rs;
ali@418
  1203
	struct deque *order;
ali@418
  1204
	int barrier_needed;
krh@254
  1205
richard@301
  1206
	assert (set != NULL);
richard@301
  1207
	assert (next != NULL);
richard@301
  1208
krh@316
  1209
	ii = zalloc(sizeof *ii);
krh@316
  1210
	ii->set = set;
krh@316
  1211
	ii->next = next;
krh@316
  1212
	
krh@316
  1213
	razor_set_diff(set, next, add_action, ii);
krh@254
  1214
ali@367
  1215
	actions = ii->actions.data;
ali@367
  1216
	count = ii->actions.size / sizeof (struct install_action);
krh@254
  1217
ali@367
  1218
	graph_init(&follows);
ali@367
  1219
ali@367
  1220
	for(i = 0; i < count; i++) {
ali@367
  1221
		ai = actions + i;
ali@367
  1222
		rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
ali@367
  1223
		vertex_added = 0;
ali@367
  1224
		link = list_first(&ai->package->properties, &rs->property_pool);
ali@367
  1225
		for(; link; link = list_next(link)) {
ali@367
  1226
			prop = rs->properties.data;
ali@367
  1227
			prop += link->data;
ali@367
  1228
			switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
ali@367
  1229
			case RAZOR_PROPERTY_REQUIRES:
ali@367
  1230
			case RAZOR_PROPERTY_CONFLICTS:
ali@367
  1231
				for(j = 0; j < count; j++) {
ali@367
  1232
					if (j == i)
ali@367
  1233
						continue;
ali@367
  1234
					aj = actions + j;
ali@367
  1235
					if (aj->package->name == prop->name) {
ali@367
  1236
						if (ai->action ==
ali@367
  1237
						    RAZOR_INSTALL_ACTION_ADD)
ali@367
  1238
							graph_add_edge(&follows,
ali@367
  1239
								       i, j);
ali@367
  1240
						else
ali@367
  1241
							graph_add_edge(&follows,
ali@367
  1242
								       j, i);
ali@367
  1243
						vertex_added++;
ali@367
  1244
					}
ali@367
  1245
				}
ali@367
  1246
				break;
ali@367
  1247
			}
ali@367
  1248
		}
ali@367
  1249
		if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
ali@367
  1250
			for(j = 0; j < count; j++) {
ali@367
  1251
				if (j == i)
ali@367
  1252
					continue;
ali@367
  1253
				aj = actions + j;
ali@367
  1254
				if (aj->package == ai->package &&
ali@367
  1255
				    aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
ali@367
  1256
					graph_add_edge(&follows, i, j);
ali@367
  1257
					vertex_added++;
ali@367
  1258
				}
ali@367
  1259
			}
ali@367
  1260
		}
ali@367
  1261
		if (!vertex_added)
ali@367
  1262
			graph_add_edge(&follows, i, i);
ali@367
  1263
	}
ali@367
  1264
ali@418
  1265
	/*
ali@418
  1266
	 * Because files are installed and removed using razor_atomic,
ali@418
  1267
	 * but scripts are run with no regard for these, we need some
ali@418
  1268
	 * means for synchronisation between the two. We support this
ali@418
  1269
	 * via transaction barriers which are points where
ali@418
  1270
	 * razor_atomic_commit() should be called so that scripts can
ali@418
  1271
	 * rely on the files they need being present.
ali@418
  1272
	 *
ali@418
  1273
	 * Rules:
ali@418
  1274
	 *   1)	Transaction barriers never occur within a dependency
ali@418
  1275
	 *	loop. Since we can't guarantee any ordering of actions
ali@418
  1276
	 *	within such a loop, they make no sense.
ali@418
  1277
	 *   2) Otherwise the following table applies:
ali@418
  1278
	 *	Action I    Action J	Barrier between I and J iff
ali@418
  1279
	 *	ADD P	    ADD Q	%pre(Q) requires P
ali@418
  1280
	 *	ADD P	    REMOVE Q	%preun(Q) requires P
ali@418
  1281
	 *	REMOVE P    ADD Q	never
ali@418
  1282
	 *	REMOVE P    REMOVE Q	%postun(P) requires Q
ali@418
  1283
	 *
ali@418
  1284
	 * FIXME:
ali@418
  1285
	 *	This should take account of conflicts somehow.
ali@418
  1286
	 */
ali@418
  1287
	order = graph_sort(&follows);
ali@418
  1288
	ii->order = deque_new(0);
ali@418
  1289
	if (!deque_empty(order)) {
ali@418
  1290
		j = deque_pop(order);
ali@418
  1291
		deque_unshift(ii->order, j);
ali@418
  1292
	}
ali@418
  1293
	while (!deque_empty(order)) {
ali@418
  1294
		i = j;
ali@418
  1295
		j = deque_pop(order);
ali@418
  1296
		ai = actions + i;
ali@418
  1297
		aj = actions + j;
ali@418
  1298
		if (graph_is_connected(&follows, i, j) &&
ali@418
  1299
		    graph_is_connected(&follows, j, i))
ali@418
  1300
			barrier_needed = 0;
ali@418
  1301
		else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
ali@418
  1302
			 aj->action == RAZOR_INSTALL_ACTION_ADD &&
ali@418
  1303
			 package_script_requires(next, aj->package,
ali@418
  1304
						 RAZOR_PROPERTY_PRE,
ali@418
  1305
						 ai->package))
ali@418
  1306
			barrier_needed = 1;
ali@418
  1307
		else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
ali@418
  1308
			 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
ali@418
  1309
			 package_script_requires(set, aj->package,
ali@418
  1310
						 RAZOR_PROPERTY_PREUN,
ali@418
  1311
						 ai->package))
ali@418
  1312
			barrier_needed = 1;
ali@418
  1313
		else if (ai->action == RAZOR_INSTALL_ACTION_REMOVE &&
ali@418
  1314
			 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
ali@418
  1315
			 package_script_requires(set, ai->package,
ali@418
  1316
						 RAZOR_PROPERTY_POSTUN,
ali@418
  1317
						 aj->package))
ali@418
  1318
			barrier_needed = 1;
ali@418
  1319
		else
ali@418
  1320
			barrier_needed = 0;
ali@418
  1321
		if (barrier_needed) {
ali@418
  1322
			an = array_add(&ii->actions, sizeof *an);
ali@418
  1323
			actions = ii->actions.data;
ali@418
  1324
			an->package = NULL;
ali@418
  1325
			an->action = RAZOR_INSTALL_ACTION_COMMIT;
ali@418
  1326
			deque_unshift(ii->order, an - actions);
ali@418
  1327
		}
ali@418
  1328
		deque_unshift(ii->order, j);
ali@418
  1329
	}
ali@418
  1330
	deque_free(order);
ali@418
  1331
ali@403
  1332
	ii->left = deque_dup(ii->order);
ali@367
  1333
	graph_release(&follows);
krh@254
  1334
krh@316
  1335
	return ii;
krh@254
  1336
}
krh@254
  1337
krh@316
  1338
RAZOR_EXPORT int
krh@316
  1339
razor_install_iterator_next(struct razor_install_iterator *ii,
krh@316
  1340
			    struct razor_package **package,
krh@316
  1341
			    enum razor_install_action *action,
krh@316
  1342
			    int *count)
krh@254
  1343
{
ali@367
  1344
	struct install_action *a;
ali@382
  1345
	struct razor_package_iterator *pi;
ali@382
  1346
	struct razor_package *pkg;
ali@382
  1347
	const char *removing, *name;
ali@382
  1348
ali@403
  1349
	if (deque_empty(ii->left))
krh@316
  1350
		return 0;
krh@254
  1351
ali@403
  1352
	a = (struct install_action *)ii->actions.data + deque_pop(ii->left);
ali@367
  1353
	*package = a->package;
ali@367
  1354
	*action = a->action;
krh@316
  1355
	*count = 0;
krh@254
  1356
ali@382
  1357
	if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
ali@382
  1358
		razor_package_get_details(ii->set, a->package,
ali@382
  1359
					  RAZOR_DETAIL_NAME, &removing,
ali@382
  1360
					  RAZOR_DETAIL_LAST);
ali@382
  1361
ali@382
  1362
		pi = razor_package_iterator_create(ii->next);
ali@382
  1363
		while (razor_package_iterator_next(pi, &pkg,
ali@382
  1364
						   RAZOR_DETAIL_NAME, &name,
ali@382
  1365
						   RAZOR_DETAIL_LAST)) {
ali@382
  1366
			if (!strcmp(name, removing))
ali@382
  1367
				(*count)++;
ali@382
  1368
		}
ali@382
  1369
		razor_package_iterator_destroy(pi);
ali@418
  1370
	} else if (a->action == RAZOR_INSTALL_ACTION_ADD)
ali@403
  1371
		*count = 1;
ali@382
  1372
krh@316
  1373
	return 1;
krh@316
  1374
}
krh@254
  1375
ali@418
  1376
static int
ali@418
  1377
action_is_included(struct razor_install_iterator *ii, struct deque *done,
ali@418
  1378
		   struct razor_package *package,
ali@418
  1379
		   enum razor_install_action action)
ali@418
  1380
{
ali@418
  1381
	struct deque *t;
ali@418
  1382
	struct install_action *a;
ali@418
  1383
	int retval;
ali@418
  1384
ali@418
  1385
	t = deque_dup(done);
ali@418
  1386
ali@418
  1387
	while(!deque_empty(t)) {
ali@418
  1388
		a = (struct install_action *)ii->actions.data + deque_pop(t);
ali@418
  1389
		if (a->package == package && a->action == action)
ali@418
  1390
			break;
ali@418
  1391
	}
ali@418
  1392
	retval = !deque_empty(t);
ali@418
  1393
ali@418
  1394
	deque_free(t);
ali@418
  1395
ali@418
  1396
	return retval;
ali@418
  1397
}
ali@418
  1398
ali@418
  1399
RAZOR_EXPORT struct razor_set *
ali@418
  1400
razor_install_iterator_commit_set(struct razor_install_iterator *ii)
ali@418
  1401
{
ali@418
  1402
	struct razor_merger *merger;
ali@418
  1403
	struct razor_set *set;
ali@442
  1404
	struct razor_package *n, *nend, *s, *send;
ali@418
  1405
	struct deque *done;
ali@418
  1406
	size_t pos;
ali@418
  1407
	char *npool, *spool;
ali@418
  1408
	int cmp;
ali@418
  1409
ali@418
  1410
	done = deque_dup(ii->order);
ali@418
  1411
	pos = razor_install_iterator_tell(ii);
ali@418
  1412
	while(deque_length(done) > pos)
ali@418
  1413
		deque_shift(done);
ali@418
  1414
ali@418
  1415
	s = ii->set->packages.data;
ali@418
  1416
	send = ii->set->packages.data + ii->set->packages.size;
ali@418
  1417
	spool = ii->set->string_pool.data;
ali@418
  1418
ali@418
  1419
	n = ii->next->packages.data;
ali@418
  1420
	nend = ii->next->packages.data + ii->next->packages.size;
ali@418
  1421
	npool = ii->next->string_pool.data;
ali@418
  1422
ali@418
  1423
	merger = razor_merger_create(ii->set, ii->next);
ali@418
  1424
	while (s < send || n < nend) {
ali@418
  1425
		if (s < send && n < nend)
ali@418
  1426
			cmp = strcmp(&spool[s->name], &npool[n->name]);
ali@418
  1427
		else if (s < send)
ali@418
  1428
			cmp = -1;
ali@418
  1429
		else
ali@418
  1430
			cmp = 1;
ali@418
  1431
ali@418
  1432
		if (cmp < 0) {
ali@418
  1433
			if (!action_is_included(ii, done, s,
ali@418
  1434
						RAZOR_INSTALL_ACTION_REMOVE))
ali@418
  1435
				razor_merger_add_package(merger, s);
ali@418
  1436
			s++;
ali@418
  1437
		} else if (cmp == 0) {
ali@418
  1438
			if (!action_is_included(ii, done, s,
ali@418
  1439
						RAZOR_INSTALL_ACTION_REMOVE))
ali@418
  1440
				razor_merger_add_package(merger, s);
ali@418
  1441
			if (action_is_included(ii, done, n,
ali@418
  1442
					       RAZOR_INSTALL_ACTION_ADD))
ali@418
  1443
				razor_merger_add_package(merger, n);
ali@418
  1444
ali@418
  1445
			s++;
ali@418
  1446
			n++;
ali@418
  1447
		} else {
ali@418
  1448
			if (action_is_included(ii, done, n,
ali@418
  1449
					       RAZOR_INSTALL_ACTION_ADD))
ali@418
  1450
				razor_merger_add_package(merger, n);
ali@418
  1451
			n++;
ali@418
  1452
		}
ali@418
  1453
	}
ali@418
  1454
ali@418
  1455
	set = razor_merger_commit(merger);
ali@418
  1456
	razor_merger_destroy(merger);
ali@458
  1457
	deque_free(done);
ali@418
  1458
ali@418
  1459
	return set;
ali@418
  1460
}
ali@418
  1461
krh@316
  1462
RAZOR_EXPORT void
ali@403
  1463
razor_install_iterator_rewind(struct razor_install_iterator *ii)
ali@403
  1464
{
ali@403
  1465
	deque_free(ii->left);
ali@403
  1466
	ii->left=deque_dup(ii->order);
ali@403
  1467
}
ali@403
  1468
ali@418
  1469
RAZOR_EXPORT size_t
ali@418
  1470
razor_install_iterator_tell(struct razor_install_iterator *ii)
ali@418
  1471
{
ali@418
  1472
	return deque_length(ii->order) - deque_length(ii->left);
ali@418
  1473
}
ali@418
  1474
ali@418
  1475
RAZOR_EXPORT size_t
ali@418
  1476
razor_install_iterator_seek(struct razor_install_iterator *ii, size_t pos)
ali@418
  1477
{
ali@418
  1478
	size_t current_pos;
ali@418
  1479
ali@418
  1480
	if (pos > deque_length(ii->order))
ali@418
  1481
		pos = deque_length(ii->order);
ali@418
  1482
ali@418
  1483
	current_pos = razor_install_iterator_tell(ii);
ali@418
  1484
ali@418
  1485
	if (pos < current_pos) {
ali@418
  1486
		razor_install_iterator_rewind(ii);
ali@418
  1487
		current_pos = 0;
ali@418
  1488
	}
ali@418
  1489
ali@418
  1490
	while(current_pos < pos) {
ali@418
  1491
		(void) deque_pop(ii->left);
ali@418
  1492
		current_pos++;
ali@418
  1493
	}
ali@418
  1494
ali@418
  1495
	return current_pos;
ali@418
  1496
}
ali@418
  1497
ali@403
  1498
RAZOR_EXPORT void
krh@316
  1499
razor_install_iterator_destroy(struct razor_install_iterator *ii)
krh@316
  1500
{
krh@316
  1501
	array_release(&ii->actions);
ali@367
  1502
	deque_free(ii->order);
ali@403
  1503
	deque_free(ii->left);
krh@316
  1504
	free(ii);
krh@254
  1505
}