librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 29 17:00:01 2009 +0100 (2009-04-29)
changeset 361 2523d03a840e
parent 351 48b0adfe3059
child 363 c75a2d5caae9
permissions -rw-r--r--
Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
rhughes@241
     1
/*
rhughes@241
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
rhughes@241
     3
 * Copyright (C) 2008  Red Hat, Inc
rhughes@241
     4
 *
rhughes@241
     5
 * This program is free software; you can redistribute it and/or modify
rhughes@241
     6
 * it under the terms of the GNU General Public License as published by
rhughes@241
     7
 * the Free Software Foundation; either version 2 of the License, or
rhughes@241
     8
 * (at your option) any later version.
rhughes@241
     9
 *
rhughes@241
    10
 * This program is distributed in the hope that it will be useful,
rhughes@241
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rhughes@241
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
rhughes@241
    13
 * GNU General Public License for more details.
rhughes@241
    14
 *
rhughes@241
    15
 * You should have received a copy of the GNU General Public License along
rhughes@241
    16
 * with this program; if not, write to the Free Software Foundation, Inc.,
rhughes@241
    17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
rhughes@241
    18
 */
rhughes@241
    19
rhughes@241
    20
#define _GNU_SOURCE
rhughes@241
    21
ali@334
    22
#include "config.h"
ali@334
    23
rhughes@241
    24
#include <stdlib.h>
rhughes@241
    25
#include <stddef.h>
rhughes@241
    26
#include <stdint.h>
rhughes@241
    27
#include <stdio.h>
richard@302
    28
#include <stdarg.h>
rhughes@241
    29
#include <string.h>
rhughes@241
    30
#include <sys/types.h>
rhughes@241
    31
#include <sys/stat.h>
rhughes@241
    32
#include <unistd.h>
rhughes@241
    33
#include <fcntl.h>
rhughes@241
    34
#include <errno.h>
rhughes@241
    35
#include <ctype.h>
rhughes@241
    36
#include <fnmatch.h>
richard@301
    37
#include <assert.h>
rhughes@241
    38
krh@253
    39
#include "razor-internal.h"
rhughes@241
    40
#include "razor.h"
rhughes@241
    41
ali@345
    42
#ifndef O_BINARY
ali@345
    43
#define O_BINARY	0
ali@345
    44
#endif
ali@345
    45
krh@248
    46
void *
rhughes@241
    47
zalloc(size_t size)
rhughes@241
    48
{
rhughes@241
    49
	void *p;
rhughes@241
    50
rhughes@241
    51
	p = malloc(size);
rhughes@241
    52
	memset(p, 0, size);
rhughes@241
    53
rhughes@241
    54
	return p;
rhughes@241
    55
}
rhughes@241
    56
jbowes@318
    57
struct razor_set_section_index {
jbowes@318
    58
	const char *name;
jbowes@318
    59
	uint32_t offset;
jbowes@318
    60
};
jbowes@318
    61
jbowes@318
    62
struct razor_set_section_index razor_sections[] = {
rhughes@241
    63
	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
rhughes@241
    64
	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
rhughes@241
    65
	{ RAZOR_PROPERTIES,	offsetof(struct razor_set, properties) },
rhughes@241
    66
	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
rhughes@241
    67
	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
rhughes@241
    68
};
rhughes@241
    69
jbowes@318
    70
struct razor_set_section_index razor_files_sections[] = {
jbowes@258
    71
	{ RAZOR_FILES,			offsetof(struct razor_set, files) },
jbowes@258
    72
	{ RAZOR_FILE_POOL,		offsetof(struct razor_set, file_pool) },
jbowes@258
    73
	{ RAZOR_FILE_STRING_POOL,	offsetof(struct razor_set, file_string_pool) },
jbowes@258
    74
};
jbowes@258
    75
jbowes@318
    76
struct razor_set_section_index razor_details_sections[] = {
jbowes@258
    77
	{ RAZOR_DETAILS_STRING_POOL,	offsetof(struct razor_set, details_string_pool) },
jbowes@258
    78
};
krh@262
    79
krh@269
    80
RAZOR_EXPORT struct razor_set *
rhughes@241
    81
razor_set_create(void)
rhughes@241
    82
{
rhughes@241
    83
	struct razor_set *set;
rhughes@241
    84
	struct razor_entry *e;
rhughes@241
    85
	char *empty;
rhughes@241
    86
rhughes@241
    87
	set = zalloc(sizeof *set);
rhughes@241
    88
rhughes@241
    89
	e = array_add(&set->files, sizeof *e);
rhughes@241
    90
	empty = array_add(&set->string_pool, 1);
rhughes@241
    91
	*empty = '\0';
rhughes@241
    92
	e->name = 0;
rhughes@241
    93
	e->flags = RAZOR_ENTRY_LAST;
rhughes@241
    94
	e->start = 0;
rhughes@241
    95
	list_set_empty(&e->packages);
rhughes@241
    96
rhughes@241
    97
	return set;
rhughes@241
    98
}
rhughes@241
    99
jbowes@318
   100
static int
jbowes@318
   101
razor_set_bind_sections(struct razor_set *set,
jbowes@318
   102
			struct razor_set_header **header,
jbowes@318
   103
			size_t *header_size,
jbowes@318
   104
			struct razor_set_section_index section_index[],
jbowes@318
   105
			int section_index_size,
jbowes@318
   106
			const char *filename)
rhughes@241
   107
{
jbowes@318
   108
	struct razor_set_section *s, *sections;
rhughes@241
   109
	struct array *array;
jbowes@318
   110
	const char *pool;
ali@322
   111
	int i;
richard@301
   112
ali@322
   113
	*header = razor_file_get_contents(filename, header_size);
ali@322
   114
	if (!*header)
jbowes@288
   115
		return -1;
jbowes@258
   116
jbowes@318
   117
	sections = (void *) *header + sizeof **header;
jbowes@318
   118
	pool = (void *) sections + (*header)->num_sections * sizeof *sections;
jbowes@318
   119
jbowes@318
   120
	for (i = 0; i < (*header)->num_sections; i++) {
jbowes@318
   121
		int j;
jbowes@318
   122
		s = sections + i;
jbowes@318
   123
		for (j = 0; j < section_index_size; j++)
jbowes@318
   124
			if (!strcmp(section_index[j].name,
jbowes@318
   125
				    &pool[s->name]))
jbowes@318
   126
				break;
jbowes@318
   127
		if (j == section_index_size)
jbowes@258
   128
			continue;
jbowes@318
   129
		array = (void *) set + section_index[j].offset;
jbowes@318
   130
		array->data = (void *) *header + s->offset;
jbowes@258
   131
		array->size = s->size;
jbowes@258
   132
		array->alloc = s->size;
jbowes@258
   133
	}
jbowes@288
   134
jbowes@288
   135
	return 0;
jbowes@258
   136
}
jbowes@258
   137
jbowes@318
   138
RAZOR_EXPORT struct razor_set *
jbowes@318
   139
razor_set_open(const char *filename)
jbowes@318
   140
{
jbowes@318
   141
	struct razor_set *set;
jbowes@318
   142
jbowes@318
   143
	set = zalloc(sizeof *set);
jbowes@318
   144
	if (razor_set_bind_sections(set, &set->header, &set->header_size,
jbowes@318
   145
				    razor_sections, ARRAY_SIZE(razor_sections),
jbowes@318
   146
				    filename)){
jbowes@318
   147
		free(set);
jbowes@318
   148
		return NULL;
jbowes@318
   149
	}
jbowes@318
   150
	return set;
jbowes@318
   151
}
jbowes@318
   152
jbowes@318
   153
RAZOR_EXPORT int
jbowes@318
   154
razor_set_open_details(struct razor_set *set, const char *filename)
jbowes@318
   155
{
jbowes@318
   156
	return razor_set_bind_sections(set, &set->details_header,
jbowes@318
   157
				       &set->details_header_size,
jbowes@318
   158
				       razor_details_sections,
jbowes@318
   159
				       ARRAY_SIZE(razor_details_sections),
jbowes@318
   160
				       filename);
jbowes@318
   161
}
jbowes@318
   162
jbowes@288
   163
RAZOR_EXPORT int
jbowes@258
   164
razor_set_open_files(struct razor_set *set, const char *filename)
jbowes@258
   165
{
jbowes@318
   166
	return razor_set_bind_sections(set, &set->files_header,
jbowes@318
   167
				       &set->files_header_size,
jbowes@318
   168
				       razor_files_sections,
jbowes@318
   169
				       ARRAY_SIZE(razor_files_sections),
jbowes@318
   170
				       filename);
jbowes@258
   171
}
jbowes@258
   172
krh@269
   173
RAZOR_EXPORT void
rhughes@241
   174
razor_set_destroy(struct razor_set *set)
rhughes@241
   175
{
rhughes@241
   176
	struct array *a;
rhughes@241
   177
	int i;
rhughes@241
   178
richard@301
   179
	assert (set != NULL);
richard@301
   180
rhughes@241
   181
	if (set->header) {
ali@322
   182
		razor_file_free_contents(set->header, set->header_size);
rhughes@241
   183
	} else {
rhughes@241
   184
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
rhughes@241
   185
			a = (void *) set + razor_sections[i].offset;
rhughes@241
   186
			free(a->data);
rhughes@241
   187
		}
rhughes@241
   188
	}
rhughes@241
   189
jbowes@258
   190
	if (set->details_header) {
ali@322
   191
		razor_file_free_contents(set->details_header,
ali@322
   192
			set->details_header_size);
jbowes@258
   193
	} else {
jbowes@258
   194
		for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
jbowes@258
   195
			a = (void *) set + razor_details_sections[i].offset;
jbowes@258
   196
			free(a->data);
jbowes@258
   197
		}
jbowes@258
   198
	}
jbowes@258
   199
jbowes@258
   200
	if (set->files_header) {
ali@322
   201
		razor_file_free_contents(set->files_header,
ali@322
   202
			set->files_header_size);
jbowes@258
   203
	} else {
jbowes@258
   204
		for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
jbowes@258
   205
			a = (void *) set + razor_files_sections[i].offset;
jbowes@258
   206
			free(a->data);
jbowes@258
   207
		}
jbowes@258
   208
	}
jbowes@258
   209
rhughes@241
   210
	free(set);
rhughes@241
   211
}
rhughes@241
   212
jbowes@258
   213
static int
jbowes@318
   214
razor_set_write_sections_to_fd(struct razor_set *set, int fd,
jbowes@318
   215
			       struct razor_set_section_index *sections,
jbowes@258
   216
			       size_t array_size)
rhughes@241
   217
{
jbowes@318
   218
	struct razor_set_header header;
jbowes@318
   219
	struct razor_set_section *out_sections =
jbowes@318
   220
		malloc(array_size * sizeof *out_sections);
jbowes@318
   221
	struct hashtable table;
jbowes@318
   222
	struct array *a, pool;
rhughes@241
   223
	uint32_t offset;
rhughes@241
   224
	int i;
rhughes@241
   225
jbowes@318
   226
	header.magic = RAZOR_MAGIC;
jbowes@318
   227
	header.version = RAZOR_VERSION;
jbowes@318
   228
	header.num_sections = array_size;
jbowes@318
   229
	offset = sizeof header + array_size * sizeof *out_sections;
jbowes@318
   230
jbowes@318
   231
	array_init(&pool);
jbowes@318
   232
	hashtable_init(&table, &pool);
jbowes@318
   233
jbowes@318
   234
	for (i = 0; i < array_size; i++)
jbowes@318
   235
		out_sections[i].name =
jbowes@318
   236
			hashtable_tokenize(&table, sections[i].name);
jbowes@318
   237
jbowes@318
   238
	offset += pool.size;
rhughes@241
   239
jbowes@258
   240
	for (i = 0; i < array_size; i++) {
jbowes@258
   241
		a = (void *) set + sections[i].offset;
jbowes@318
   242
		out_sections[i].offset = offset;
jbowes@318
   243
		out_sections[i].size = a->size;
jbowes@318
   244
		offset += a->size;
rhughes@241
   245
	}
rhughes@241
   246
jbowes@318
   247
	razor_write(fd, &header, sizeof header);
jbowes@318
   248
	razor_write(fd, out_sections, array_size * sizeof *out_sections);
jbowes@318
   249
	razor_write(fd, pool.data, pool.size);
rhughes@241
   250
jbowes@258
   251
	for (i = 0; i < array_size; i++) {
jbowes@258
   252
		a = (void *) set + sections[i].offset;
rhughes@241
   253
		razor_write(fd, a->data, a->size);
rhughes@241
   254
	}
rhughes@241
   255
jbowes@318
   256
	free(out_sections);
jbowes@318
   257
rhughes@241
   258
	return 0;
rhughes@241
   259
}
rhughes@241
   260
krh@269
   261
RAZOR_EXPORT int
jbowes@258
   262
razor_set_write_to_fd(struct razor_set *set, int fd,
jbowes@258
   263
		      enum razor_repo_file_type type)
jbowes@258
   264
{
jbowes@258
   265
	switch (type) {
jbowes@258
   266
	case RAZOR_REPO_FILE_MAIN:
jbowes@318
   267
		return razor_set_write_sections_to_fd(set, fd,
jbowes@258
   268
						      razor_sections,
jbowes@258
   269
						      ARRAY_SIZE(razor_sections));
jbowes@258
   270
jbowes@258
   271
	case RAZOR_REPO_FILE_DETAILS:
jbowes@318
   272
		return razor_set_write_sections_to_fd(set, fd,
jbowes@258
   273
						      razor_details_sections,
jbowes@258
   274
						      ARRAY_SIZE(razor_details_sections));
jbowes@258
   275
	case RAZOR_REPO_FILE_FILES:
jbowes@318
   276
		return razor_set_write_sections_to_fd(set, fd,
jbowes@258
   277
						      razor_files_sections,
jbowes@258
   278
						      ARRAY_SIZE(razor_files_sections));
jbowes@258
   279
	default:
jbowes@258
   280
		return -1;
jbowes@258
   281
	}
jbowes@258
   282
}
jbowes@258
   283
krh@269
   284
RAZOR_EXPORT int
jbowes@258
   285
razor_set_write(struct razor_set *set, const char *filename,
jbowes@258
   286
		enum razor_repo_file_type type)
rhughes@241
   287
{
rhughes@241
   288
	int fd, status;
rhughes@241
   289
ali@345
   290
	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
rhughes@241
   291
	if (fd < 0)
rhughes@241
   292
		return -1;
rhughes@241
   293
jbowes@258
   294
	status = razor_set_write_to_fd(set, fd, type);
rhughes@241
   295
	if (status) {
rhughes@241
   296
	    close(fd);
rhughes@241
   297
	    return status;
rhughes@241
   298
	}
rhughes@241
   299
rhughes@241
   300
	return close(fd);
rhughes@241
   301
}
krh@269
   302
krh@269
   303
RAZOR_EXPORT void
rhughes@241
   304
razor_build_evr(char *evr_buf, int size, const char *epoch,
rhughes@241
   305
		const char *version, const char *release)
rhughes@241
   306
{
rhughes@241
   307
	int len;
rhughes@241
   308
rhughes@241
   309
	if (!version || !*version) {
rhughes@241
   310
		*evr_buf = '\0';
rhughes@241
   311
		return;
rhughes@241
   312
	}
rhughes@241
   313
rhughes@241
   314
	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
rhughes@241
   315
		len = snprintf(evr_buf, size, "%s:", epoch);
rhughes@241
   316
		evr_buf += len;
rhughes@241
   317
		size -= len;
rhughes@241
   318
	}
rhughes@241
   319
	len = snprintf(evr_buf, size, "%s", version);
rhughes@241
   320
	evr_buf += len;
rhughes@241
   321
	size -= len;
rhughes@241
   322
	if (release && *release)
rhughes@241
   323
		snprintf(evr_buf, size, "-%s", release);
rhughes@241
   324
}
rhughes@241
   325
krh@269
   326
RAZOR_EXPORT int
krh@248
   327
razor_versioncmp(const char *s1, const char *s2)
rhughes@241
   328
{
rhughes@241
   329
	const char *p1, *p2;
rhughes@241
   330
	long n1, n2;
rhughes@241
   331
	int res;
rhughes@241
   332
richard@301
   333
	assert (s1 != NULL);
richard@301
   334
	assert (s2 != NULL);
richard@301
   335
rhughes@241
   336
	n1 = strtol(s1, (char **) &p1, 10);
rhughes@241
   337
	n2 = strtol(s2, (char **) &p2, 10);
rhughes@241
   338
rhughes@241
   339
	/* Epoch; if one but not the other has an epoch set, default
rhughes@241
   340
	 * the epoch-less version to 0. */
rhughes@241
   341
	res = (*p1 == ':') - (*p2 == ':');
rhughes@241
   342
	if (res < 0) {
rhughes@241
   343
		n1 = 0;
rhughes@241
   344
		p1 = s1;
rhughes@241
   345
		p2++;
rhughes@241
   346
	} else if (res > 0) {
rhughes@241
   347
		p1++;
rhughes@241
   348
		n2 = 0;
rhughes@241
   349
		p2 = s2;
rhughes@241
   350
	}
rhughes@241
   351
rhughes@241
   352
	if (n1 != n2)
rhughes@241
   353
		return n1 - n2;
rhughes@241
   354
	while (*p1 && *p2) {
rhughes@241
   355
		if (*p1 != *p2)
rhughes@241
   356
			return *p1 - *p2;
rhughes@241
   357
		p1++;
rhughes@241
   358
		p2++;
rhughes@241
   359
		if (isdigit(*p1) && isdigit(*p2))
krh@248
   360
			return razor_versioncmp(p1, p2);
rhughes@241
   361
	}
rhughes@241
   362
rhughes@241
   363
	return *p1 - *p2;
rhughes@241
   364
}
rhughes@241
   365
richard@302
   366
static const char *
richard@302
   367
razor_package_get_details_type(struct razor_set *set,
richard@302
   368
			       struct razor_package *package,
richard@302
   369
			       enum razor_detail_type type)
richard@302
   370
{
richard@302
   371
	const char *pool;
richard@302
   372
richard@302
   373
	switch (type) {
richard@302
   374
	case RAZOR_DETAIL_NAME:
richard@302
   375
		pool = set->string_pool.data;
richard@302
   376
		return &pool[package->name];
richard@302
   377
richard@302
   378
	case RAZOR_DETAIL_VERSION:
richard@302
   379
		pool = set->string_pool.data;
richard@302
   380
		return &pool[package->version];
richard@302
   381
richard@302
   382
	case RAZOR_DETAIL_ARCH:
richard@302
   383
		pool = set->string_pool.data;
richard@302
   384
		return &pool[package->arch];
richard@302
   385
richard@302
   386
	case RAZOR_DETAIL_SUMMARY:
richard@302
   387
		pool = set->details_string_pool.data;
richard@302
   388
		return &pool[package->summary];
richard@302
   389
richard@302
   390
	case RAZOR_DETAIL_DESCRIPTION:
richard@302
   391
		pool = set->details_string_pool.data;
richard@302
   392
		return &pool[package->description];
richard@302
   393
richard@302
   394
	case RAZOR_DETAIL_URL:
richard@302
   395
		pool = set->details_string_pool.data;
richard@302
   396
		return &pool[package->url];
richard@302
   397
richard@302
   398
	case RAZOR_DETAIL_LICENSE:
richard@302
   399
		pool = set->details_string_pool.data;
richard@302
   400
		return &pool[package->license];
richard@302
   401
richard@302
   402
	default:
richard@302
   403
		fprintf(stderr, "type %u not found\n", type);
richard@302
   404
		return NULL;
richard@302
   405
	}
richard@302
   406
}
richard@302
   407
richard@302
   408
/**
richard@302
   409
 * razor_package_get_details_varg:
richard@302
   410
 * @set: a %razor_set
richard@302
   411
 * @package: a %razor_package
richard@302
   412
 * @args: a va_list of arguments to set
richard@302
   413
 **/
richard@302
   414
void
richard@302
   415
razor_package_get_details_varg(struct razor_set *set,
richard@302
   416
			       struct razor_package *package,
richard@302
   417
			       va_list args)
richard@302
   418
{
richard@302
   419
	int i;
richard@302
   420
	enum razor_detail_type type;
richard@302
   421
	const char **data;
richard@302
   422
richard@302
   423
	for (i = 0;; i += 2) {
richard@302
   424
		type = va_arg(args, enum razor_detail_type);
richard@307
   425
		if (type == RAZOR_DETAIL_LAST)
richard@302
   426
			break;
richard@302
   427
		data = va_arg(args, const char **);
richard@302
   428
		*data = razor_package_get_details_type(set, package, type);
richard@302
   429
	}
richard@302
   430
richard@302
   431
}
richard@302
   432
richard@302
   433
/**
richard@302
   434
 * razor_package_get_details:
richard@302
   435
 * @set: a %razor_set
richard@302
   436
 * @package: a %razor_package
richard@302
   437
 *
richard@302
   438
 * Gets details about a package using a varg interface
krh@308
   439
 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
richard@302
   440
 *
richard@307
   441
 * Example: razor_package_get_details (set, package,
richard@307
   442
 *				       RAZOR_DETAIL_URL, &url,
richard@307
   443
 *				       RAZOR_DETAIL_LAST);
richard@302
   444
 **/
krh@269
   445
RAZOR_EXPORT void
richard@302
   446
razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
jbowes@258
   447
{
richard@302
   448
	va_list args;
jbowes@258
   449
richard@301
   450
	assert (set != NULL);
richard@301
   451
	assert (package != NULL);
richard@301
   452
richard@302
   453
	va_start(args, NULL);
richard@302
   454
	razor_package_get_details_varg (set, package, args);
richard@302
   455
	va_end (args);
jbowes@258
   456
}
jbowes@258
   457
krh@270
   458
RAZOR_EXPORT const char *
krh@270
   459
razor_property_relation_to_string(struct razor_property *p)
krh@270
   460
{
richard@301
   461
	assert (p != NULL);
richard@301
   462
krh@270
   463
	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
krh@270
   464
	case RAZOR_PROPERTY_LESS:
krh@270
   465
		return "<";
krh@270
   466
krh@270
   467
	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
krh@270
   468
		return "<=";
krh@270
   469
krh@270
   470
	case RAZOR_PROPERTY_EQUAL:
krh@270
   471
		return "=";
krh@270
   472
krh@270
   473
	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
krh@270
   474
		return ">=";
krh@270
   475
krh@270
   476
	case RAZOR_PROPERTY_GREATER:
krh@270
   477
		return ">";
krh@270
   478
krh@270
   479
	default:
krh@270
   480
		return "?";
krh@270
   481
	}
krh@270
   482
}
krh@270
   483
krh@270
   484
RAZOR_EXPORT const char *
krh@270
   485
razor_property_type_to_string(struct razor_property *p)
krh@270
   486
{
richard@301
   487
	assert (p != NULL);
richard@301
   488
krh@270
   489
	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
krh@270
   490
	case RAZOR_PROPERTY_REQUIRES:
krh@270
   491
		return "requires";
krh@270
   492
	case RAZOR_PROPERTY_PROVIDES:
krh@270
   493
		return "provides";
krh@270
   494
	case RAZOR_PROPERTY_CONFLICTS:
krh@270
   495
		return "conflicts";
krh@270
   496
	case RAZOR_PROPERTY_OBSOLETES:
krh@270
   497
		return "obsoletes";
krh@270
   498
	default:
krh@270
   499
		return NULL;
krh@270
   500
	}
krh@270
   501
}
krh@270
   502
krh@269
   503
RAZOR_EXPORT struct razor_entry *
krh@248
   504
razor_set_find_entry(struct razor_set *set,
krh@248
   505
		     struct razor_entry *dir, const char *pattern)
rhughes@241
   506
{
ali@359
   507
	struct razor_entry *e, *subdir;
jbowes@264
   508
	const char *n, *pool = set->file_string_pool.data;
rhughes@241
   509
	int len;
rhughes@241
   510
richard@301
   511
	assert (set != NULL);
richard@301
   512
	assert (dir != NULL);
richard@301
   513
	assert (pattern != NULL);
richard@301
   514
ali@359
   515
	e = dir;
rhughes@241
   516
	do {
rhughes@241
   517
		n = pool + e->name;
ali@359
   518
		if (strcmp(pattern, n) == 0)
rhughes@241
   519
			return e;
rhughes@241
   520
		len = strlen(n);
ali@359
   521
		if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
ali@359
   522
		    pattern[len] == '/') {
ali@359
   523
			subdir = (struct razor_entry *) set->files.data +
ali@359
   524
				 e->start;
ali@359
   525
			return razor_set_find_entry(set, subdir,
ali@359
   526
						    pattern + len + 1);
rhughes@241
   527
		}
rhughes@241
   528
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   529
rhughes@241
   530
	return NULL;
rhughes@241
   531
}
rhughes@241
   532
rhughes@241
   533
static void
rhughes@241
   534
list_dir(struct razor_set *set, struct razor_entry *dir,
rhughes@241
   535
	 char *prefix, const char *pattern)
rhughes@241
   536
{
ali@359
   537
	struct razor_entry *e, *subdir;
jbowes@274
   538
	const char *n, *pool = set->file_string_pool.data;
rhughes@241
   539
ali@359
   540
	e = dir;
rhughes@241
   541
	do {
rhughes@241
   542
		n = pool + e->name;
rhughes@241
   543
		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
rhughes@241
   544
			continue;
rhughes@241
   545
		printf("%s/%s\n", prefix, n);
rhughes@241
   546
		if (e->start) {
rhughes@241
   547
			char *sub = prefix + strlen (prefix);
rhughes@241
   548
			*sub = '/';
rhughes@241
   549
			strcpy (sub + 1, n);
ali@359
   550
			subdir = (struct razor_entry *) set->files.data +
ali@359
   551
				 e->start;
ali@359
   552
			list_dir(set, subdir, prefix, pattern);
rhughes@241
   553
			*sub = '\0';
rhughes@241
   554
		}
rhughes@241
   555
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   556
}
rhughes@241
   557
krh@269
   558
RAZOR_EXPORT void
rhughes@241
   559
razor_set_list_files(struct razor_set *set, const char *pattern)
rhughes@241
   560
{
ali@359
   561
	struct razor_entry *root, *e;
rhughes@241
   562
	char buffer[512], *p, *base;
rhughes@241
   563
richard@301
   564
	assert (set != NULL);
richard@301
   565
ali@359
   566
	root = (struct razor_entry *) set->files.data;
ali@359
   567
ali@359
   568
	if (pattern == NULL) {
ali@359
   569
		p = set->file_string_pool.data;
ali@359
   570
		e = root;
ali@359
   571
		do {
ali@359
   572
			if (e->start) {
ali@359
   573
				strcpy(buffer, p + e->name);
ali@359
   574
				list_dir(set, root + e->start, buffer, NULL);
ali@359
   575
			}
ali@359
   576
		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   577
		return;
rhughes@241
   578
	}
rhughes@241
   579
rhughes@241
   580
	strcpy(buffer, pattern);
ali@359
   581
	e = razor_set_find_entry(set, root, buffer);
ali@359
   582
	if (e && e->start) {
rhughes@241
   583
		base = NULL;
rhughes@241
   584
	} else {
rhughes@241
   585
		p = strrchr(buffer, '/');
rhughes@241
   586
		if (p) {
rhughes@241
   587
			*p = '\0';
rhughes@241
   588
			base = p + 1;
rhughes@241
   589
		} else {
rhughes@241
   590
			base = NULL;
rhughes@241
   591
		}
rhughes@241
   592
	}
ali@359
   593
	e = razor_set_find_entry(set, root, buffer);
ali@359
   594
	if (e && e->start)
ali@359
   595
		list_dir(set, root + e->start, buffer, base);
rhughes@241
   596
}
rhughes@241
   597
krh@269
   598
RAZOR_EXPORT void
krh@306
   599
razor_set_list_package_files(struct razor_set *set,
krh@306
   600
			     struct razor_package *package)
rhughes@241
   601
{
ali@351
   602
	struct razor_file_iterator *fi;
ali@351
   603
	const char *name;
rhughes@241
   604
richard@301
   605
	assert (set != NULL);
krh@306
   606
	assert (package != NULL);
rhughes@241
   607
ali@351
   608
	fi = razor_file_iterator_create(set, package);
ali@351
   609
ali@351
   610
	while (razor_file_iterator_next(fi, &name))
ali@351
   611
		printf("%s\n", name);
ali@351
   612
ali@351
   613
	razor_file_iterator_destroy(fi);
rhughes@241
   614
}
rhughes@241
   615
rhughes@241
   616
/* The diff order matters.  We should sort the packages so that a
rhughes@241
   617
 * REMOVE of a package comes before the INSTALL, and so that all
rhughes@241
   618
 * requires for a package have been installed before the package.
rhughes@241
   619
 **/
rhughes@241
   620
krh@269
   621
RAZOR_EXPORT void
rhughes@241
   622
razor_set_diff(struct razor_set *set, struct razor_set *upstream,
krh@253
   623
	       razor_diff_callback_t callback, void *data)
rhughes@241
   624
{
rhughes@241
   625
 	struct razor_package_iterator *pi1, *pi2;
rhughes@241
   626
 	struct razor_package *p1, *p2;
rhughes@241
   627
	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
rhughes@241
   628
	int res;
rhughes@241
   629
richard@301
   630
	assert (set != NULL);
richard@301
   631
	assert (upstream != NULL);
richard@301
   632
rhughes@241
   633
	pi1 = razor_package_iterator_create(set);
rhughes@241
   634
	pi2 = razor_package_iterator_create(upstream);
rhughes@241
   635
richard@302
   636
	razor_package_iterator_next(pi1, &p1,
richard@302
   637
				    RAZOR_DETAIL_NAME, &name1,
richard@302
   638
				    RAZOR_DETAIL_VERSION, &version1,
richard@302
   639
				    RAZOR_DETAIL_ARCH, &arch1,
richard@307
   640
				    RAZOR_DETAIL_LAST);
richard@302
   641
	razor_package_iterator_next(pi2, &p2,
richard@302
   642
				    RAZOR_DETAIL_NAME, &name2,
richard@302
   643
				    RAZOR_DETAIL_VERSION, &version2,
richard@302
   644
				    RAZOR_DETAIL_ARCH, &arch2,
richard@307
   645
				    RAZOR_DETAIL_LAST);
rhughes@241
   646
rhughes@241
   647
	while (p1 || p2) {
rhughes@241
   648
		if (p1 && p2) {
rhughes@241
   649
			res = strcmp(name1, name2);
rhughes@241
   650
			if (res == 0)
krh@248
   651
				res = razor_versioncmp(version1, version2);
rhughes@241
   652
		} else {
rhughes@241
   653
			res = 0;
rhughes@241
   654
		}
rhughes@241
   655
rhughes@241
   656
		if (p2 == NULL || res < 0)
krh@253
   657
			callback(RAZOR_DIFF_ACTION_REMOVE,
krh@253
   658
				 p1, name1, version1, arch1, data);
rhughes@241
   659
		else if (p1 == NULL || res > 0)
krh@253
   660
			callback(RAZOR_DIFF_ACTION_ADD,
krh@253
   661
				 p2, name2, version2, arch2, data);
rhughes@241
   662
rhughes@241
   663
		if (p1 != NULL && res <= 0)
rhughes@241
   664
			razor_package_iterator_next(pi1, &p1,
richard@302
   665
						    RAZOR_DETAIL_NAME, &name1,
richard@302
   666
						    RAZOR_DETAIL_VERSION, &version1,
richard@302
   667
						    RAZOR_DETAIL_ARCH, &arch1,
richard@307
   668
						    RAZOR_DETAIL_LAST);
rhughes@241
   669
		if (p2 != NULL && res >= 0)
rhughes@241
   670
			razor_package_iterator_next(pi2, &p2,
richard@302
   671
						    RAZOR_DETAIL_NAME, &name2,
richard@302
   672
						    RAZOR_DETAIL_VERSION, &version2,
richard@302
   673
						    RAZOR_DETAIL_ARCH, &arch2,
richard@307
   674
						    RAZOR_DETAIL_LAST);
rhughes@241
   675
	}
rhughes@241
   676
rhughes@241
   677
	razor_package_iterator_destroy(pi1);
rhughes@241
   678
	razor_package_iterator_destroy(pi2);
rhughes@241
   679
}
krh@254
   680
krh@316
   681
struct install_action {
krh@316
   682
	enum razor_install_action action;
krh@316
   683
	struct razor_package *package;
krh@316
   684
};
krh@316
   685
krh@316
   686
struct razor_install_iterator {
krh@316
   687
	struct razor_set *set;
krh@316
   688
	struct razor_set *next;
krh@316
   689
	struct array actions;
krh@316
   690
	struct install_action *a, *end;
krh@316
   691
};
krh@316
   692
krh@254
   693
static void
krh@316
   694
add_action(enum razor_diff_action action,
krh@316
   695
	   struct razor_package *package,
krh@316
   696
	   const char *name,
krh@316
   697
	   const char *version,
krh@316
   698
	   const char *arch,
krh@316
   699
	   void *data)
krh@254
   700
{
krh@316
   701
	struct razor_install_iterator *ii = data;
krh@316
   702
	struct install_action *a;
krh@316
   703
krh@316
   704
	a = array_add(&ii->actions, sizeof *a);
krh@316
   705
	a->package = package;
krh@316
   706
krh@316
   707
	switch (action) {
krh@316
   708
	case RAZOR_DIFF_ACTION_ADD:
krh@316
   709
		a->action = RAZOR_INSTALL_ACTION_ADD;
krh@316
   710
		break;
krh@316
   711
	case RAZOR_DIFF_ACTION_REMOVE:
krh@316
   712
		a->action = RAZOR_INSTALL_ACTION_REMOVE;
krh@316
   713
		break;
krh@316
   714
	}
krh@254
   715
}
krh@254
   716
krh@316
   717
RAZOR_EXPORT struct razor_install_iterator *
krh@316
   718
razor_set_create_install_iterator(struct razor_set *set,
krh@316
   719
				  struct razor_set *next)
krh@254
   720
{
krh@316
   721
	struct razor_install_iterator *ii;
krh@254
   722
richard@301
   723
	assert (set != NULL);
richard@301
   724
	assert (next != NULL);
richard@301
   725
krh@316
   726
	ii = zalloc(sizeof *ii);
krh@316
   727
	ii->set = set;
krh@316
   728
	ii->next = next;
krh@316
   729
	
krh@316
   730
	razor_set_diff(set, next, add_action, ii);
krh@254
   731
krh@316
   732
	ii->a = ii->actions.data;
krh@316
   733
	ii->end = ii->actions.data + ii->actions.size;
krh@254
   734
krh@254
   735
	/* FIXME: We need to figure out the right install order here,
krh@254
   736
	 * so the post and pre scripts can run. */
krh@254
   737
krh@316
   738
	return ii;
krh@254
   739
}
krh@254
   740
krh@316
   741
RAZOR_EXPORT int
krh@316
   742
razor_install_iterator_next(struct razor_install_iterator *ii,
krh@316
   743
			    struct razor_set **set,
krh@316
   744
			    struct razor_package **package,
krh@316
   745
			    enum razor_install_action *action,
krh@316
   746
			    int *count)
krh@254
   747
{
krh@316
   748
	if (ii->a == ii->end)
krh@316
   749
		return 0;
krh@254
   750
krh@316
   751
	switch (ii->a->action) {
krh@316
   752
	case RAZOR_INSTALL_ACTION_ADD:
krh@316
   753
		*set = ii->next;
krh@316
   754
		break;
krh@316
   755
	case RAZOR_INSTALL_ACTION_REMOVE:
krh@316
   756
		*set = ii->set;
krh@316
   757
		break;
krh@316
   758
	}
richard@301
   759
krh@316
   760
	*package = ii->a->package;
krh@316
   761
	*action = ii->a->action;
krh@316
   762
	*count = 0;
krh@316
   763
	ii->a++;
krh@254
   764
krh@316
   765
	return 1;
krh@316
   766
}
krh@254
   767
krh@316
   768
RAZOR_EXPORT void
krh@316
   769
razor_install_iterator_destroy(struct razor_install_iterator *ii)
krh@316
   770
{
krh@316
   771
	array_release(&ii->actions);
krh@316
   772
	free(ii);
krh@254
   773
}