librazor/razor.c
author James Bowes <jbowes@redhat.com>
Wed Jul 09 10:11:13 2008 -0400 (2008-07-09)
changeset 318 829d6711b316
parent 316 5ebed314390c
child 322 66c281524c98
permissions -rw-r--r--
Use strings to identify section types in the on-disk repo format.

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

This will allow for razor files to contain arbitrary sections.

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

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