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