razor.c
author Kristian H?gsberg <krh@jiraiya.boston.redhat.com>
Wed Apr 09 02:41:03 2008 -0400 (2008-04-09)
changeset 211 cf0ca962262b
parent 209 78afac5bb7b8
child 212 e8f493d8ff9a
permissions -rw-r--r--
Use the cpio headers instead of the rpm headers when unpacking.

The files in the cpio payload doesn't actually follow the file order
in the rpm headers, so we need to decode the cpio header and use the
information there.
krh@15
     1
#define _GNU_SOURCE
krh@15
     2
krh@0
     3
#include <stdlib.h>
krh@19
     4
#include <stddef.h>
danw@108
     5
#include <stdint.h>
krh@0
     6
#include <stdio.h>
krh@0
     7
#include <string.h>
krh@0
     8
#include <sys/types.h>
krh@0
     9
#include <sys/stat.h>
krh@0
    10
#include <sys/mman.h>
krh@0
    11
#include <unistd.h>
krh@0
    12
#include <fcntl.h>
krh@15
    13
#include <errno.h>
krh@35
    14
#include <ctype.h>
krh@54
    15
#include <fnmatch.h>
krh@0
    16
krh@27
    17
#include "razor.h"
krh@91
    18
#include "razor-internal.h"
danw@115
    19
#include "types.h"
krh@30
    20
krh@30
    21
struct razor_set_section {
danw@108
    22
	uint32_t type;
danw@108
    23
	uint32_t offset;
danw@108
    24
	uint32_t size;
krh@30
    25
};
krh@30
    26
krh@30
    27
struct razor_set_header {
danw@108
    28
	uint32_t magic;
danw@108
    29
	uint32_t version;
krh@30
    30
	struct razor_set_section sections[0];
krh@30
    31
};
krh@30
    32
krh@30
    33
#define RAZOR_MAGIC 0x7a7a7a7a
krh@30
    34
#define RAZOR_VERSION 1
krh@30
    35
krh@66
    36
#define RAZOR_STRING_POOL	0
krh@66
    37
#define RAZOR_PACKAGES		1
krh@66
    38
#define RAZOR_PROPERTIES	2
krh@66
    39
#define RAZOR_FILES		3
krh@66
    40
#define RAZOR_PACKAGE_POOL	4
krh@66
    41
#define RAZOR_PROPERTY_POOL	5
krh@66
    42
#define RAZOR_FILE_POOL		6
krh@30
    43
krh@30
    44
struct razor_package {
danw@120
    45
	uint name  : 24;
danw@120
    46
	uint flags : 8;
danw@108
    47
	uint32_t version;
krh@192
    48
	uint32_t arch;
danw@117
    49
	struct list_head properties;
danw@117
    50
	struct list_head files;
krh@30
    51
};
krh@30
    52
krh@30
    53
struct razor_property {
danw@119
    54
	uint name  : 24;
danw@119
    55
	uint flags : 6;
danw@162
    56
	enum razor_property_type type : 2;
danw@162
    57
	enum razor_version_relation relation : 32;
danw@108
    58
	uint32_t version;
danw@117
    59
	struct list_head packages;
krh@30
    60
};
krh@30
    61
krh@48
    62
struct razor_entry {
danw@120
    63
	uint name  : 24;
danw@120
    64
	uint flags : 8;
danw@108
    65
	uint32_t start;
danw@117
    66
	struct list_head packages;
krh@48
    67
};
krh@48
    68
danw@120
    69
#define RAZOR_ENTRY_LAST	0x80
danw@120
    70
krh@30
    71
struct razor_set {
krh@30
    72
	struct array string_pool;
krh@30
    73
 	struct array packages;
krh@66
    74
 	struct array properties;
krh@56
    75
 	struct array files;
krh@56
    76
	struct array package_pool;
krh@66
    77
 	struct array property_pool;
krh@56
    78
 	struct array file_pool;
krh@30
    79
	struct razor_set_header *header;
krh@30
    80
};
krh@30
    81
krh@52
    82
struct import_entry {
danw@108
    83
	uint32_t package;
krh@52
    84
	char *name;
krh@52
    85
};
krh@52
    86
krh@52
    87
struct import_directory {
danw@108
    88
	uint32_t name, count;
krh@52
    89
	struct array files;
krh@52
    90
	struct array packages;
krh@52
    91
	struct import_directory *last;
krh@52
    92
};
krh@52
    93
krh@30
    94
struct razor_importer {
krh@30
    95
	struct razor_set *set;
krh@78
    96
	struct hashtable table;
krh@30
    97
	struct razor_package *package;
krh@66
    98
	struct array properties;
krh@48
    99
	struct array files;
danw@159
   100
	struct array file_requires;
krh@30
   101
};
krh@30
   102
krh@0
   103
static void *
krh@0
   104
zalloc(size_t size)
krh@0
   105
{
krh@0
   106
	void *p;
krh@0
   107
krh@0
   108
	p = malloc(size);
krh@0
   109
	memset(p, 0, size);
krh@0
   110
krh@0
   111
	return p;
krh@0
   112
}
krh@0
   113
krh@19
   114
struct razor_set_section razor_sections[] = {
krh@56
   115
	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
krh@19
   116
	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
krh@66
   117
	{ RAZOR_PROPERTIES,	offsetof(struct razor_set, properties) },
krh@56
   118
	{ RAZOR_FILES,		offsetof(struct razor_set, files) },
krh@39
   119
	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
krh@66
   120
	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
krh@56
   121
	{ RAZOR_FILE_POOL,	offsetof(struct razor_set, file_pool) },
krh@19
   122
};
krh@19
   123
krh@4
   124
struct razor_set *
krh@4
   125
razor_set_create(void)
krh@0
   126
{
krh@150
   127
	struct razor_set *set;
krh@150
   128
	struct razor_entry *e;
danw@167
   129
	char *empty;
krh@150
   130
krh@150
   131
	set = zalloc(sizeof *set);
krh@150
   132
krh@150
   133
	e = array_add(&set->files, sizeof *e);
danw@167
   134
	empty = array_add(&set->string_pool, 1);
danw@167
   135
	*empty = '\0';
krh@150
   136
	e->name = 0;
krh@150
   137
	e->flags = RAZOR_ENTRY_LAST;
krh@150
   138
	e->start = 0;
krh@150
   139
	list_set_empty(&e->packages);
krh@150
   140
krh@150
   141
	return set;
krh@0
   142
}
krh@0
   143
krh@4
   144
struct razor_set *
krh@4
   145
razor_set_open(const char *filename)
krh@0
   146
{
krh@4
   147
	struct razor_set *set;
krh@19
   148
	struct razor_set_section *s;
krh@0
   149
	struct stat stat;
krh@19
   150
	struct array *array;
krh@19
   151
	int fd;
krh@0
   152
krh@4
   153
	set = zalloc(sizeof *set);
krh@0
   154
	fd = open(filename, O_RDONLY);
krh@0
   155
	if (fstat(fd, &stat) < 0)
krh@0
   156
		return NULL;
krh@4
   157
	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
krh@4
   158
	if (set->header == MAP_FAILED) {
krh@4
   159
		free(set);
krh@0
   160
		return NULL;
krh@0
   161
	}
krh@0
   162
krh@19
   163
	for (s = set->header->sections; ~s->type; s++) {
krh@19
   164
		if (s->type >= ARRAY_SIZE(razor_sections))
krh@19
   165
			continue;
krh@19
   166
		if (s->type != razor_sections[s->type].type)
krh@19
   167
			continue;
krh@19
   168
		array = (void *) set + razor_sections[s->type].offset;
krh@19
   169
		array->data = (void *) set->header + s->offset;
krh@19
   170
		array->size = s->size;
krh@19
   171
		array->alloc = s->size;
krh@0
   172
	}
krh@0
   173
	close(fd);
krh@0
   174
krh@4
   175
	return set;
krh@0
   176
}
krh@0
   177
krh@0
   178
void
krh@4
   179
razor_set_destroy(struct razor_set *set)
krh@0
   180
{
krh@0
   181
	unsigned int size;
krh@19
   182
	struct array *a;
krh@0
   183
	int i;
krh@0
   184
krh@4
   185
	if (set->header) {
krh@4
   186
		for (i = 0; set->header->sections[i].type; i++)
krh@0
   187
			;
krh@4
   188
		size = set->header->sections[i].type;
krh@4
   189
		munmap(set->header, size);
krh@0
   190
	} else {
krh@19
   191
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   192
			a = (void *) set + razor_sections[i].offset;
krh@19
   193
			free(a->data);
krh@19
   194
		}
krh@0
   195
	}
krh@0
   196
krh@4
   197
	free(set);
krh@0
   198
}
krh@0
   199
krh@43
   200
int
krh@197
   201
razor_set_write_to_fd(struct razor_set *set, int fd)
krh@0
   202
{
krh@0
   203
	char data[4096];
krh@4
   204
	struct razor_set_header *header = (struct razor_set_header *) data;
krh@19
   205
	struct array *a;
danw@108
   206
	uint32_t offset;
krh@197
   207
	int i;
krh@0
   208
krh@0
   209
	memset(data, 0, sizeof data);
krh@4
   210
	header->magic = RAZOR_MAGIC;
krh@4
   211
	header->version = RAZOR_VERSION;
krh@17
   212
	offset = sizeof data;
krh@0
   213
krh@19
   214
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   215
		if (razor_sections[i].type != i)
krh@19
   216
			continue;
krh@19
   217
		a = (void *) set + razor_sections[i].offset;
krh@19
   218
		header->sections[i].type = i;
krh@17
   219
		header->sections[i].offset = offset;
krh@19
   220
		header->sections[i].size = a->size;
krh@91
   221
		offset += ALIGN(a->size, 4096);
krh@17
   222
	}
krh@0
   223
krh@19
   224
	header->sections[i].type = ~0;
krh@17
   225
	header->sections[i].offset = 0;
krh@17
   226
	header->sections[i].size = 0;
krh@10
   227
krh@91
   228
	razor_write(fd, data, sizeof data);
danw@113
   229
	memset(data, 0, sizeof data);
krh@19
   230
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   231
		if (razor_sections[i].type != i)
krh@19
   232
			continue;
krh@19
   233
		a = (void *) set + razor_sections[i].offset;
danw@113
   234
		razor_write(fd, a->data, a->size);
danw@113
   235
		razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
krh@19
   236
	}
krh@17
   237
krh@0
   238
	return 0;
krh@0
   239
}
krh@0
   240
krh@197
   241
int
krh@197
   242
razor_set_write(struct razor_set *set, const char *filename)
krh@197
   243
{
krh@197
   244
	int fd, status;
krh@197
   245
krh@197
   246
	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
krh@197
   247
	if (fd < 0)
krh@197
   248
		return -1;
krh@197
   249
krh@197
   250
	status = razor_set_write_to_fd(set, fd);
krh@197
   251
	if (status) {
krh@197
   252
	    close(fd);
krh@197
   253
	    return status;
krh@197
   254
	}
krh@197
   255
krh@197
   256
	return close(fd);
krh@197
   257
}
krh@197
   258
krh@27
   259
void
danw@143
   260
razor_build_evr(char *evr_buf, int size, const char *epoch,
danw@143
   261
		const char *version, const char *release)
danw@143
   262
{
danw@143
   263
	int len;
danw@143
   264
danw@143
   265
	if (!version || !*version) {
danw@143
   266
		*evr_buf = '\0';
danw@143
   267
		return;
danw@143
   268
	}
danw@143
   269
danw@143
   270
	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
danw@143
   271
		len = snprintf(evr_buf, size, "%s:", epoch);
danw@143
   272
		evr_buf += len;
danw@143
   273
		size -= len;
danw@143
   274
	}
danw@143
   275
	len = snprintf(evr_buf, size, "%s", version);
danw@143
   276
	evr_buf += len;
danw@143
   277
	size -= len;
danw@143
   278
	if (release && *release)
danw@143
   279
		snprintf(evr_buf, size, "-%s", release);
danw@143
   280
}
danw@143
   281
danw@143
   282
void
krh@30
   283
razor_importer_begin_package(struct razor_importer *importer,
krh@192
   284
			     const char *name,
krh@192
   285
			     const char *version,
krh@192
   286
			     const char *arch)
krh@13
   287
{
krh@25
   288
	struct razor_package *p;
krh@13
   289
krh@30
   290
	p = array_add(&importer->set->packages, sizeof *p);
krh@95
   291
	p->name = hashtable_tokenize(&importer->table, name);
danw@120
   292
	p->flags = 0;
krh@95
   293
	p->version = hashtable_tokenize(&importer->table, version);
krh@192
   294
	p->arch = hashtable_tokenize(&importer->table, arch);
krh@13
   295
krh@30
   296
	importer->package = p;
krh@66
   297
	array_init(&importer->properties);
krh@13
   298
}
krh@13
   299
krh@13
   300
void
krh@30
   301
razor_importer_finish_package(struct razor_importer *importer)
krh@13
   302
{
danw@117
   303
	list_set_array(&importer->package->properties,
danw@117
   304
		       &importer->set->property_pool,
danw@124
   305
		       &importer->properties,
danw@124
   306
		       1);
krh@13
   307
krh@66
   308
	array_release(&importer->properties);
krh@13
   309
}
krh@13
   310
krh@66
   311
void
krh@30
   312
razor_importer_add_property(struct razor_importer *importer,
danw@109
   313
			    const char *name,
danw@109
   314
			    enum razor_version_relation relation,
danw@109
   315
			    const char *version,
krh@66
   316
			    enum razor_property_type type)
krh@13
   317
{
krh@25
   318
	struct razor_property *p;
danw@108
   319
	uint32_t *r;
krh@13
   320
krh@66
   321
	p = array_add(&importer->set->properties, sizeof *p);
danw@119
   322
	p->name = hashtable_tokenize(&importer->table, name);
danw@119
   323
	p->flags = 0;
danw@119
   324
	p->type = type;
danw@109
   325
	p->relation = relation;
krh@95
   326
	p->version = hashtable_tokenize(&importer->table, version);
danw@117
   327
	list_set_ptr(&p->packages, importer->package -
danw@117
   328
		     (struct razor_package *) importer->set->packages.data);
krh@13
   329
krh@66
   330
	r = array_add(&importer->properties, sizeof *r);
krh@66
   331
	*r = p - (struct razor_property *) importer->set->properties.data;
danw@159
   332
danw@159
   333
	if (type == RAZOR_PROPERTY_REQUIRES && *name == '/') {
danw@159
   334
		r = array_add(&importer->file_requires, sizeof *r);
danw@159
   335
		*r = p->name;
danw@159
   336
	}
krh@30
   337
}
krh@30
   338
krh@46
   339
void
krh@46
   340
razor_importer_add_file(struct razor_importer *importer, const char *name)
krh@46
   341
{
krh@52
   342
	struct import_entry *e;
krh@48
   343
krh@52
   344
	e = array_add(&importer->files, sizeof *e);
krh@52
   345
krh@52
   346
	e->package = importer->package -
krh@52
   347
		(struct razor_package *) importer->set->packages.data;
krh@52
   348
	e->name = strdup(name);
krh@46
   349
}
krh@46
   350
krh@30
   351
struct razor_importer *
krh@30
   352
razor_importer_new(void)
krh@30
   353
{
krh@30
   354
	struct razor_importer *importer;
krh@30
   355
krh@30
   356
	importer = zalloc(sizeof *importer);
krh@30
   357
	importer->set = razor_set_create();
krh@78
   358
	hashtable_init(&importer->table, &importer->set->string_pool);
krh@30
   359
krh@30
   360
	return importer;
krh@9
   361
}
krh@9
   362
krh@75
   363
/* Destroy an importer without creating the set. */
krh@75
   364
void
krh@75
   365
razor_importer_destroy(struct razor_importer *importer)
krh@75
   366
{
krh@75
   367
	/* FIXME: write this */
krh@75
   368
}
krh@75
   369
krh@9
   370
static int
krh@35
   371
versioncmp(const char *s1, const char *s2)
krh@35
   372
{
krh@35
   373
	const char *p1, *p2;
krh@35
   374
	long n1, n2;
krh@35
   375
	int res;
krh@35
   376
danw@153
   377
	n1 = strtol(s1, (char **) &p1, 10);
danw@153
   378
	n2 = strtol(s2, (char **) &p2, 10);
krh@35
   379
krh@35
   380
	/* Epoch; if one but not the other has an epoch set, default
krh@35
   381
	 * the epoch-less version to 0. */
krh@35
   382
	res = (*p1 == ':') - (*p2 == ':');
krh@35
   383
	if (res < 0) {
krh@35
   384
		n1 = 0;
krh@35
   385
		p1 = s1;
krh@35
   386
		p2++;
krh@35
   387
	} else if (res > 0) {
krh@35
   388
		p1++;
krh@35
   389
		n2 = 0;
krh@35
   390
		p2 = s2;
krh@35
   391
	}
krh@35
   392
krh@35
   393
	if (n1 != n2)
krh@35
   394
		return n1 - n2;
krh@35
   395
	while (*p1 && *p2) {
krh@35
   396
		if (*p1 != *p2)
krh@35
   397
			return *p1 - *p2;
krh@35
   398
		p1++;
krh@35
   399
		p2++;
krh@35
   400
		if (isdigit(*p1) && isdigit(*p2))
krh@35
   401
			return versioncmp(p1, p2);
krh@35
   402
	}
krh@35
   403
krh@35
   404
	return *p1 - *p2;
krh@35
   405
}
krh@35
   406
krh@35
   407
static int
krh@22
   408
compare_packages(const void *p1, const void *p2, void *data)
krh@9
   409
{
krh@25
   410
	const struct razor_package *pkg1 = p1, *pkg2 = p2;
krh@22
   411
	struct razor_set *set = data;
krh@22
   412
	char *pool = set->string_pool.data;
krh@9
   413
danw@120
   414
	/* FIXME: what if the flags are different? */
krh@23
   415
	if (pkg1->name == pkg2->name)
krh@35
   416
		return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
krh@23
   417
	else
krh@23
   418
		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
krh@9
   419
}
krh@9
   420
krh@9
   421
static int
krh@22
   422
compare_properties(const void *p1, const void *p2, void *data)
krh@9
   423
{
krh@25
   424
	const struct razor_property *prop1 = p1, *prop2 = p2;
krh@22
   425
	struct razor_set *set = data;
krh@22
   426
	char *pool = set->string_pool.data;
krh@9
   427
danw@119
   428
	if (prop1->name != prop2->name) 
danw@119
   429
		return strcmp(&pool[prop1->name], &pool[prop2->name]);
danw@119
   430
	else if (prop1->type != prop2->type)
danw@119
   431
		return prop1->type - prop2->type;
danw@119
   432
	else if (prop1->relation != prop2->relation)
danw@119
   433
		return prop1->relation - prop2->relation;
krh@12
   434
	else
danw@119
   435
		return versioncmp(&pool[prop1->version], &pool[prop2->version]);
krh@9
   436
}
krh@9
   437
danw@108
   438
static uint32_t *
krh@66
   439
uniqueify_properties(struct razor_set *set)
krh@9
   440
{
krh@25
   441
	struct razor_property *rp, *up, *rp_end;
krh@18
   442
	struct array *pkgs, *p;
danw@117
   443
	struct list_head *r;
danw@117
   444
	uint32_t *map, *rmap;
krh@18
   445
	int i, count, unique;
krh@9
   446
krh@66
   447
	count = set->properties.size / sizeof(struct razor_property);
krh@186
   448
	map = razor_qsort_with_data(set->properties.data,
krh@186
   449
				    count,
krh@186
   450
				    sizeof(struct razor_property),
krh@186
   451
				    compare_properties,
krh@186
   452
				    set);
krh@9
   453
krh@66
   454
	rp_end = set->properties.data + set->properties.size;
krh@25
   455
	rmap = malloc(count * sizeof *map);
krh@25
   456
	pkgs = zalloc(count * sizeof *pkgs);
krh@66
   457
	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
danw@119
   458
		if (rp->name != up->name || rp->type != up->type ||
danw@119
   459
		    rp->relation != up->relation || rp->version != up->version) {
krh@25
   460
			up++;
krh@25
   461
			up->name = rp->name;
danw@119
   462
			up->flags = 0;
danw@119
   463
			up->type = rp->type;
danw@109
   464
			up->relation = rp->relation;
krh@25
   465
			up->version = rp->version;
krh@10
   466
		}
krh@25
   467
krh@66
   468
		unique = up - (struct razor_property *) set->properties.data;
krh@25
   469
		rmap[map[i]] = unique;
krh@25
   470
		r = array_add(&pkgs[unique], sizeof *r);
krh@25
   471
		*r = rp->packages;
krh@10
   472
	}
krh@25
   473
	free(map);
krh@9
   474
danw@124
   475
	if (up != rp)
danw@124
   476
		up++;
krh@66
   477
	set->properties.size = (void *) up - set->properties.data;
krh@25
   478
	rp_end = up;
krh@66
   479
	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
danw@124
   480
		list_set_array(&rp->packages, &set->package_pool, p, 0);
krh@25
   481
		array_release(p);
krh@18
   482
	}
krh@18
   483
krh@18
   484
	free(pkgs);
krh@18
   485
krh@25
   486
	return rmap;
krh@10
   487
}
krh@10
   488
krh@48
   489
static int
krh@48
   490
compare_filenames(const void *p1, const void *p2, void *data)
krh@48
   491
{
krh@52
   492
	const struct import_entry *e1 = p1;
krh@52
   493
	const struct import_entry *e2 = p2;
danw@126
   494
	const char *n1 = e1->name;
danw@126
   495
	const char *n2 = e2->name;
krh@48
   496
danw@126
   497
	/* Need to make sure that the contents of a directory
danw@126
   498
	 * are sorted immediately after it. So "foo/bar" has to
danw@126
   499
	 * sort before "foo.conf"
danw@126
   500
	 *
danw@126
   501
	 * FIXME: this is about 60% slower than strcmp
danw@126
   502
	 */
danw@126
   503
	while (*n1 && *n2) {
danw@126
   504
		if (*n1 < *n2)
danw@126
   505
			return *n2 == '/' ? 1 : -1;
danw@126
   506
		else if (*n1 > *n2)
danw@126
   507
			return *n1 == '/' ? -1 : 1;
danw@126
   508
		n1++;
danw@126
   509
		n2++;
danw@126
   510
	}
danw@126
   511
	if (*n1)
danw@126
   512
		return 1;
danw@126
   513
	else if (*n2)
danw@126
   514
		return -1;
danw@126
   515
	else
danw@126
   516
		return 0;
krh@48
   517
}
krh@48
   518
krh@48
   519
static void
krh@52
   520
count_entries(struct import_directory *d)
krh@48
   521
{
krh@52
   522
	struct import_directory *p, *end;
krh@48
   523
krh@48
   524
	p = d->files.data;
krh@48
   525
	end = d->files.data + d->files.size;
krh@48
   526
	d->count = 0;
krh@48
   527
	while (p < end) {
krh@48
   528
		count_entries(p);
krh@48
   529
		d->count += p->count + 1;
krh@48
   530
		p++;
krh@48
   531
	}		
krh@48
   532
}
krh@48
   533
krh@48
   534
static void
krh@52
   535
serialize_files(struct razor_set *set,
krh@52
   536
		struct import_directory *d, struct array *array)
krh@48
   537
{
krh@52
   538
	struct import_directory *p, *end;
krh@56
   539
	struct razor_entry *e = NULL;
danw@114
   540
	uint32_t s;
krh@48
   541
krh@48
   542
	p = d->files.data;
krh@48
   543
	end = d->files.data + d->files.size;
krh@48
   544
	s = array->size / sizeof *e + d->files.size / sizeof *p;
krh@48
   545
	while (p < end) {
krh@48
   546
		e = array_add(array, sizeof *e);
krh@48
   547
		e->name = p->name;
danw@120
   548
		e->flags = 0;
krh@56
   549
		e->start = p->count > 0 ? s : 0;
krh@48
   550
		s += p->count;
krh@60
   551
danw@124
   552
		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
krh@52
   553
		array_release(&p->packages);
krh@48
   554
		p++;
krh@48
   555
	}		
krh@56
   556
	if (e != NULL)
danw@120
   557
		e->flags |= RAZOR_ENTRY_LAST;
krh@48
   558
krh@48
   559
	p = d->files.data;
krh@48
   560
	end = d->files.data + d->files.size;
krh@48
   561
	while (p < end) {
krh@52
   562
		serialize_files(set, p, array);
krh@48
   563
		p++;
krh@48
   564
	}
krh@48
   565
}
krh@48
   566
krh@48
   567
static void
danw@108
   568
remap_property_package_links(struct array *properties, uint32_t *rmap)
krh@61
   569
{
krh@61
   570
	struct razor_property *p, *end;
krh@61
   571
krh@61
   572
	end = properties->data + properties->size;
krh@61
   573
	for (p = properties->data; p < end; p++)
danw@117
   574
		list_remap_head(&p->packages, rmap);
krh@61
   575
}
krh@61
   576
krh@61
   577
static void
krh@48
   578
build_file_tree(struct razor_importer *importer)
krh@48
   579
{
krh@48
   580
	int count, i, length;
krh@52
   581
	struct import_entry *filenames;
krh@52
   582
	char *f, *end;
danw@108
   583
	uint32_t name, *r;
krh@48
   584
	char dirname[256];
krh@52
   585
	struct import_directory *d, root;
krh@48
   586
	struct razor_entry *e;
krh@48
   587
krh@52
   588
	count = importer->files.size / sizeof (struct import_entry);
krh@186
   589
	razor_qsort_with_data(importer->files.data,
krh@186
   590
			      count,
krh@186
   591
			      sizeof (struct import_entry),
krh@186
   592
			      compare_filenames,
krh@186
   593
			      NULL);
krh@48
   594
krh@95
   595
	root.name = hashtable_tokenize(&importer->table, "");
krh@48
   596
	array_init(&root.files);
krh@52
   597
	array_init(&root.packages);
krh@48
   598
	root.last = NULL;
krh@48
   599
krh@48
   600
	filenames = importer->files.data;
krh@48
   601
	for (i = 0; i < count; i++) {
krh@52
   602
		f = filenames[i].name;
krh@48
   603
		if (*f != '/')
krh@48
   604
			continue;
krh@57
   605
		f++;
krh@48
   606
krh@48
   607
		d = &root;
krh@48
   608
		while (*f) {
krh@57
   609
			end = strchr(f, '/');
krh@48
   610
			if (end == NULL)
krh@48
   611
				end = f + strlen(f);
krh@57
   612
			length = end - f;
krh@57
   613
			memcpy(dirname, f, length);
krh@48
   614
			dirname[length] ='\0';
krh@95
   615
			name = hashtable_tokenize(&importer->table, dirname);
krh@48
   616
			if (d->last == NULL || d->last->name != name) {
krh@48
   617
				d->last = array_add(&d->files, sizeof *d);
krh@48
   618
				d->last->name = name;
krh@48
   619
				d->last->last = NULL;
krh@48
   620
				array_init(&d->last->files);
krh@52
   621
				array_init(&d->last->packages);
krh@48
   622
			}
krh@48
   623
			d = d->last;				
krh@57
   624
			f = end + 1;
krh@57
   625
			if (*end == '\0')
krh@57
   626
				break;
krh@48
   627
		}
krh@48
   628
krh@52
   629
		r = array_add(&d->packages, sizeof *r);
krh@52
   630
		*r = filenames[i].package;
krh@52
   631
		free(filenames[i].name);
krh@48
   632
	}
krh@48
   633
krh@48
   634
	count_entries(&root);
krh@150
   635
	e = importer->set->files.data;
danw@120
   636
	e->name = root.name;
danw@120
   637
	e->flags = RAZOR_ENTRY_LAST;
danw@129
   638
	e->start = importer->files.size ? 1 : 0;
danw@117
   639
	list_set_empty(&e->packages);
krh@48
   640
krh@56
   641
	serialize_files(importer->set, &root, &importer->set->files);
krh@48
   642
krh@48
   643
	array_release(&importer->files);
krh@48
   644
}
krh@48
   645
danw@159
   646
static struct razor_entry *
danw@159
   647
find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern);
danw@159
   648
danw@159
   649
static void
danw@159
   650
list_to_array(struct list *list, struct array *array)
danw@159
   651
{
danw@159
   652
	uint32_t *item;
danw@159
   653
danw@159
   654
	while (list) {
danw@159
   655
		 item = array_add(array, sizeof *item);
danw@159
   656
		 *item = list->data;
danw@159
   657
		 list = list_next(list);
danw@159
   658
	}
danw@159
   659
}
danw@159
   660
danw@159
   661
static int
danw@159
   662
compare_file_requires(const void *p1, const void *p2, void *data)
danw@159
   663
{
danw@159
   664
	uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
danw@159
   665
	const char *pool = data;
danw@159
   666
danw@159
   667
	return strcmp(&pool[*f1], &pool[*f2]);
danw@159
   668
}
danw@159
   669
danw@159
   670
static void
danw@159
   671
find_file_provides(struct razor_importer *importer)
danw@159
   672
{
danw@159
   673
	struct razor_property *prop;
danw@159
   674
	struct razor_entry *top, *entry;
danw@159
   675
	struct razor_package *packages;
danw@163
   676
	struct array pkgprops;
danw@163
   677
	struct list *pkg;
danw@163
   678
	uint32_t *req, *req_start, *req_end;
danw@163
   679
	uint32_t *map, *newprop;
danw@159
   680
	char *pool;
danw@159
   681
danw@159
   682
	pool = importer->set->string_pool.data;
danw@159
   683
	packages = importer->set->packages.data;
danw@159
   684
	top = importer->set->files.data;
danw@159
   685
danw@159
   686
	req = req_start = importer->file_requires.data;
danw@159
   687
	req_end = importer->file_requires.data + importer->file_requires.size;
krh@186
   688
	map = razor_qsort_with_data(req, req_end - req, sizeof *req,
krh@186
   689
				    compare_file_requires, pool);
danw@159
   690
	free(map);
danw@159
   691
danw@159
   692
	for (req = req_start; req < req_end; req++) {
danw@159
   693
		if (req > req_start && req[0] == req[-1])
danw@159
   694
			continue;
danw@159
   695
		entry = find_entry(importer->set, top, &pool[*req]);
danw@163
   696
		if (!entry)
danw@163
   697
			continue;
danw@163
   698
danw@163
   699
		for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
danw@159
   700
			prop = array_add(&importer->set->properties, sizeof *prop);
danw@159
   701
			prop->name = *req;
danw@159
   702
			prop->type = RAZOR_PROPERTY_PROVIDES;
danw@159
   703
			prop->relation = RAZOR_VERSION_EQUAL;
danw@159
   704
			prop->version = hashtable_tokenize(&importer->table, "");
danw@163
   705
			list_set_ptr(&prop->packages, pkg->data);
danw@163
   706
danw@163
   707
			/* Update property list of pkg */
danw@163
   708
			array_init(&pkgprops);
danw@163
   709
			list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
danw@163
   710
			newprop = array_add(&pkgprops, sizeof *newprop);
danw@163
   711
			*newprop = prop - (struct razor_property *)importer->set->properties.data;
danw@163
   712
			list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
danw@163
   713
			array_release(&pkgprops);
danw@159
   714
		}
danw@159
   715
	}
danw@159
   716
danw@159
   717
	array_release(&importer->file_requires);
danw@159
   718
}
danw@159
   719
krh@56
   720
static void
danw@108
   721
build_package_file_lists(struct razor_set *set, uint32_t *rmap)
krh@54
   722
{
krh@56
   723
	struct razor_package *p, *packages;
krh@56
   724
	struct array *pkgs;
krh@54
   725
	struct razor_entry *e, *end;
danw@117
   726
	struct list *r;
danw@117
   727
	uint32_t *q;
krh@56
   728
	int i, count;
krh@54
   729
krh@56
   730
	count = set->packages.size / sizeof *p;
krh@56
   731
	pkgs = zalloc(count * sizeof *pkgs);
krh@54
   732
krh@56
   733
	end = set->files.data + set->files.size;
krh@92
   734
	for (e = set->files.data; e < end; e++) {
danw@117
   735
		list_remap_head(&e->packages, rmap);
danw@116
   736
		r = list_first(&e->packages, &set->package_pool);
danw@116
   737
		while (r) {
danw@117
   738
			q = array_add(&pkgs[r->data], sizeof *q);
krh@56
   739
			*q = e - (struct razor_entry *) set->files.data;
danw@116
   740
			r = list_next(r);
krh@54
   741
		}
krh@54
   742
	}
krh@54
   743
krh@56
   744
	packages = set->packages.data;
krh@56
   745
	for (i = 0; i < count; i++) {
danw@124
   746
		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
krh@56
   747
		array_release(&pkgs[i]);
krh@48
   748
	}
krh@56
   749
	free(pkgs);
krh@52
   750
}
krh@52
   751
krh@27
   752
struct razor_set *
krh@30
   753
razor_importer_finish(struct razor_importer *importer)
krh@9
   754
{
krh@30
   755
	struct razor_set *set;
danw@108
   756
	uint32_t *map, *rmap;
krh@39
   757
	int i, count;
krh@18
   758
danw@159
   759
	build_file_tree(importer);
danw@159
   760
	find_file_provides(importer);
danw@159
   761
krh@66
   762
	map = uniqueify_properties(importer->set);
danw@116
   763
	list_remap_pool(&importer->set->property_pool, map);
krh@39
   764
	free(map);
krh@25
   765
krh@30
   766
	count = importer->set->packages.size / sizeof(struct razor_package);
krh@186
   767
	map = razor_qsort_with_data(importer->set->packages.data,
krh@186
   768
				    count,
krh@186
   769
				    sizeof(struct razor_package),
krh@186
   770
				    compare_packages,
krh@186
   771
				    importer->set);
krh@39
   772
krh@39
   773
	rmap = malloc(count * sizeof *rmap);
krh@39
   774
	for (i = 0; i < count; i++)
krh@39
   775
		rmap[map[i]] = i;
krh@25
   776
	free(map);
krh@13
   777
danw@116
   778
	list_remap_pool(&importer->set->package_pool, rmap);
krh@60
   779
	build_package_file_lists(importer->set, rmap);
krh@66
   780
	remap_property_package_links(&importer->set->properties, rmap);
krh@52
   781
	free(rmap);
krh@48
   782
krh@30
   783
	set = importer->set;
krh@78
   784
	hashtable_release(&importer->table);
krh@30
   785
	free(importer);
krh@30
   786
krh@30
   787
	return set;
krh@9
   788
}
krh@9
   789
krh@92
   790
struct razor_package_iterator {
krh@92
   791
	struct razor_set *set;
krh@92
   792
	struct razor_package *package, *end;
danw@117
   793
	struct list *index;
krh@92
   794
};
krh@92
   795
danw@137
   796
static struct razor_package_iterator *
krh@101
   797
razor_package_iterator_create_with_index(struct razor_set *set,
danw@117
   798
					 struct list *index)
krh@3
   799
{
krh@92
   800
	struct razor_package_iterator *pi;
krh@92
   801
krh@92
   802
	pi = zalloc(sizeof *pi);
krh@92
   803
	pi->set = set;
krh@101
   804
	pi->index = index;
krh@92
   805
krh@92
   806
	return pi;
krh@92
   807
}
krh@92
   808
krh@101
   809
struct razor_package_iterator *
krh@101
   810
razor_package_iterator_create(struct razor_set *set)
krh@101
   811
{
danw@116
   812
	struct razor_package_iterator *pi;
danw@116
   813
danw@116
   814
	pi = zalloc(sizeof *pi);
danw@116
   815
	pi->set = set;
danw@116
   816
	pi->end = set->packages.data + set->packages.size;
danw@116
   817
	pi->package = set->packages.data;
danw@116
   818
danw@116
   819
	return pi;
krh@101
   820
}
krh@101
   821
krh@101
   822
struct razor_package_iterator *
krh@101
   823
razor_package_iterator_create_for_property(struct razor_set *set,
krh@101
   824
					   struct razor_property *property)
krh@101
   825
{
danw@117
   826
	struct list *index;
krh@101
   827
danw@116
   828
	index = list_first(&property->packages, &set->package_pool);
krh@101
   829
	return razor_package_iterator_create_with_index(set, index);
krh@101
   830
}
krh@101
   831
krh@92
   832
int
krh@92
   833
razor_package_iterator_next(struct razor_package_iterator *pi,
krh@92
   834
			    struct razor_package **package,
krh@192
   835
			    const char **name,
krh@192
   836
			    const char **version,
krh@192
   837
			    const char **arch)
krh@92
   838
{
krh@6
   839
	char *pool;
krh@101
   840
	int valid;
krh@101
   841
	struct razor_package *p, *packages;
krh@3
   842
danw@116
   843
	if (pi->package) {
krh@101
   844
		p = pi->package++;
krh@101
   845
		valid = p < pi->end;
danw@116
   846
	} else if (pi->index) {
danw@116
   847
		packages = pi->set->packages.data;
danw@117
   848
		p = &packages[pi->index->data];
danw@116
   849
		pi->index = list_next(pi->index);
danw@116
   850
		valid = 1;
danw@116
   851
	} else
danw@116
   852
		valid = 0;
krh@92
   853
krh@101
   854
	if (valid) {
krh@101
   855
		pool = pi->set->string_pool.data;
krh@101
   856
		*package = p;
danw@120
   857
		*name = &pool[p->name];
krh@101
   858
		*version = &pool[p->version];
krh@192
   859
		*arch = &pool[p->arch];
krh@101
   860
	} else {
krh@101
   861
		*package = NULL;
krh@101
   862
	}
krh@101
   863
krh@101
   864
	return valid;
krh@92
   865
}
krh@92
   866
krh@92
   867
void
krh@92
   868
razor_package_iterator_destroy(struct razor_package_iterator *pi)
krh@92
   869
{
krh@92
   870
	free(pi);
krh@3
   871
}
krh@3
   872
krh@10
   873
struct razor_package *
krh@10
   874
razor_set_get_package(struct razor_set *set, const char *package)
krh@10
   875
{
krh@97
   876
	struct razor_package_iterator *pi;
krh@97
   877
	struct razor_package *p;
krh@192
   878
	const char *name, *version, *arch;
krh@97
   879
krh@97
   880
	pi = razor_package_iterator_create(set);
krh@192
   881
	while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
krh@97
   882
		if (strcmp(package, name) == 0)
krh@97
   883
			break;
krh@97
   884
	}
krh@97
   885
	razor_package_iterator_destroy(pi);
krh@97
   886
krh@97
   887
	return p;
krh@10
   888
}
krh@10
   889
krh@92
   890
struct razor_property_iterator {
krh@92
   891
	struct razor_set *set;
krh@92
   892
	struct razor_property *property, *end;
danw@117
   893
	struct list *index;
krh@92
   894
};
krh@92
   895
krh@92
   896
struct razor_property_iterator *
krh@92
   897
razor_property_iterator_create(struct razor_set *set,
krh@92
   898
			       struct razor_package *package)
krh@92
   899
{
krh@92
   900
	struct razor_property_iterator *pi;
krh@92
   901
krh@92
   902
	pi = zalloc(sizeof *pi);
krh@92
   903
	pi->set = set;
krh@98
   904
danw@116
   905
	if (package) {
danw@117
   906
		pi->index = list_first(&package->properties,
danw@117
   907
				       &set->property_pool);
danw@116
   908
	} else {
danw@116
   909
		pi->property = set->properties.data;
danw@116
   910
		pi->end = set->properties.data + set->properties.size;
danw@116
   911
	}
krh@92
   912
krh@92
   913
	return pi;
krh@92
   914
}
krh@92
   915
krh@92
   916
int
krh@92
   917
razor_property_iterator_next(struct razor_property_iterator *pi,
krh@92
   918
			     struct razor_property **property,
danw@109
   919
			     const char **name,
danw@109
   920
			     enum razor_version_relation *relation,
danw@109
   921
			     const char **version,
krh@92
   922
			     enum razor_property_type *type)
krh@92
   923
{
krh@92
   924
	char *pool;
krh@92
   925
	int valid;
krh@92
   926
	struct razor_property *p, *properties;
krh@92
   927
danw@116
   928
	if (pi->property) {
krh@92
   929
		p = pi->property++;
krh@92
   930
		valid = p < pi->end;
danw@116
   931
	} else if (pi->index) {
danw@116
   932
		properties = pi->set->properties.data;
danw@117
   933
		p = &properties[pi->index->data];
danw@116
   934
		pi->index = list_next(pi->index);
danw@116
   935
		valid = 1;
danw@116
   936
	} else
danw@116
   937
		valid = 0;
krh@92
   938
krh@96
   939
	if (valid) {
krh@96
   940
		pool = pi->set->string_pool.data;
krh@96
   941
		*property = p;
danw@119
   942
		*name = &pool[p->name];
danw@109
   943
		*relation = p->relation;
krh@96
   944
		*version = &pool[p->version];
danw@119
   945
		*type = p->type;
krh@96
   946
	} else {
krh@96
   947
		*property = NULL;
krh@96
   948
	}
krh@92
   949
krh@92
   950
	return valid;
krh@92
   951
}
krh@92
   952
krh@66
   953
void
krh@92
   954
razor_property_iterator_destroy(struct razor_property_iterator *pi)
krh@8
   955
{
krh@92
   956
	free(pi);
krh@10
   957
}
krh@10
   958
krh@56
   959
static struct razor_entry *
krh@56
   960
find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
krh@56
   961
{
krh@56
   962
	struct razor_entry *e;
krh@56
   963
	const char *n, *pool = set->string_pool.data;
krh@56
   964
	int len;
krh@56
   965
krh@56
   966
	e = (struct razor_entry *) set->files.data + dir->start;
krh@56
   967
	do {
danw@120
   968
		n = pool + e->name;
krh@56
   969
		if (strcmp(pattern + 1, n) == 0)
krh@56
   970
			return e;
krh@57
   971
		len = strlen(n);
krh@56
   972
		if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
krh@56
   973
		    pattern[len + 1] == '/') {
krh@56
   974
			return find_entry(set, e, pattern + len + 1);
krh@56
   975
		}
danw@120
   976
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
krh@56
   977
krh@56
   978
	return NULL;
krh@56
   979
}
krh@56
   980
krh@56
   981
static void
krh@56
   982
list_dir(struct razor_set *set, struct razor_entry *dir,
danw@127
   983
	 char *prefix, const char *pattern)
krh@56
   984
{
krh@56
   985
	struct razor_entry *e;
krh@56
   986
	const char *n, *pool = set->string_pool.data;
krh@56
   987
krh@56
   988
	e = (struct razor_entry *) set->files.data + dir->start;
krh@56
   989
	do {
danw@120
   990
		n = pool + e->name;
krh@56
   991
		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
krh@56
   992
			continue;
danw@127
   993
		printf("%s/%s\n", prefix, n);
danw@127
   994
		if (e->start) {
danw@127
   995
			char *sub = prefix + strlen (prefix);
danw@127
   996
			*sub = '/';
danw@127
   997
			strcpy (sub + 1, n);
danw@127
   998
			list_dir(set, e, prefix, pattern);
danw@127
   999
			*sub = '\0';
danw@127
  1000
		}
danw@120
  1001
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
krh@56
  1002
}
krh@56
  1003
krh@56
  1004
void
krh@56
  1005
razor_set_list_files(struct razor_set *set, const char *pattern)
krh@56
  1006
{
krh@56
  1007
	struct razor_entry *e;
krh@56
  1008
	char buffer[512], *p, *base;
krh@56
  1009
danw@127
  1010
	if (pattern == NULL || !strcmp (pattern, "/")) {
danw@127
  1011
		buffer[0] = '\0';
danw@127
  1012
		list_dir(set, set->files.data, buffer, NULL);
danw@127
  1013
		return;
danw@127
  1014
	}
krh@56
  1015
krh@56
  1016
	strcpy(buffer, pattern);
krh@56
  1017
	e = find_entry(set, set->files.data, buffer);
krh@56
  1018
	if (e && e->start > 0) {
krh@56
  1019
		base = NULL;
krh@56
  1020
	} else {
krh@56
  1021
		p = strrchr(buffer, '/');
krh@56
  1022
		if (p) {
krh@56
  1023
			*p = '\0';
krh@56
  1024
			base = p + 1;
krh@56
  1025
		} else {
krh@56
  1026
			base = NULL;
krh@56
  1027
		}
krh@56
  1028
	}
krh@56
  1029
	e = find_entry(set, set->files.data, buffer);
krh@56
  1030
	if (e->start != 0)
krh@56
  1031
		list_dir(set, e, buffer, base);
krh@56
  1032
}
krh@56
  1033
krh@102
  1034
struct razor_package_iterator *
krh@102
  1035
razor_package_iterator_create_for_file(struct razor_set *set,
krh@102
  1036
				       const char *filename)
krh@56
  1037
{
krh@102
  1038
	struct razor_entry *entry;
danw@117
  1039
	struct list *index;
krh@56
  1040
krh@102
  1041
	entry = find_entry(set, set->files.data, filename);
krh@102
  1042
	if (entry == NULL)
krh@102
  1043
		return NULL;
krh@56
  1044
	
danw@116
  1045
	index = list_first(&entry->packages, &set->package_pool);
krh@102
  1046
	return razor_package_iterator_create_with_index(set, index);
krh@56
  1047
}
krh@56
  1048
danw@117
  1049
static struct list *
danw@117
  1050
list_package_files(struct razor_set *set, struct list *r,
danw@108
  1051
		   struct razor_entry *dir, uint32_t end,
krh@56
  1052
		   char *prefix)
krh@56
  1053
{
krh@56
  1054
	struct razor_entry *e, *f, *entries;
danw@108
  1055
	uint32_t next, file;
krh@56
  1056
	char *pool;
krh@56
  1057
	int len;
krh@56
  1058
	
krh@56
  1059
	entries = (struct razor_entry *) set->files.data;
krh@56
  1060
	pool = set->string_pool.data;
krh@56
  1061
krh@56
  1062
	e = entries + dir->start;
krh@56
  1063
	do {
danw@117
  1064
		if (entries + r->data == e) {
danw@120
  1065
			printf("%s/%s\n", prefix, pool + e->name);
danw@116
  1066
			r = list_next(r);
danw@116
  1067
			if (!r)
krh@83
  1068
				return NULL;
danw@117
  1069
			if (r->data >= end)
krh@83
  1070
				return r;
krh@56
  1071
		}
danw@120
  1072
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
krh@56
  1073
krh@56
  1074
	e = entries + dir->start;
krh@56
  1075
	do {
krh@56
  1076
		if (e->start == 0)
krh@56
  1077
			continue;
krh@56
  1078
danw@120
  1079
		if (e->flags & RAZOR_ENTRY_LAST)
krh@56
  1080
			next = end;
krh@56
  1081
		else {
krh@56
  1082
			f = e + 1; 
danw@120
  1083
			while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
krh@56
  1084
				f++;
krh@56
  1085
			if (f->start == 0)
krh@56
  1086
				next = end;
krh@56
  1087
			else
krh@56
  1088
				next = f->start;
krh@56
  1089
		}
krh@56
  1090
danw@117
  1091
		file = r->data;
krh@83
  1092
		if (e->start <= file && file < next) {
krh@56
  1093
			len = strlen(prefix);
krh@56
  1094
			prefix[len] = '/';
danw@120
  1095
			strcpy(prefix + len + 1, pool + e->name);
krh@56
  1096
			r = list_package_files(set, r, e, next, prefix);
krh@56
  1097
			prefix[len] = '\0';
krh@56
  1098
		}
danw@120
  1099
	} while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
krh@56
  1100
krh@56
  1101
	return r;
krh@56
  1102
}
krh@56
  1103
krh@56
  1104
void
krh@56
  1105
razor_set_list_package_files(struct razor_set *set, const char *name)
krh@56
  1106
{
krh@56
  1107
	struct razor_package *package;
danw@117
  1108
	struct list *r;
danw@117
  1109
	uint32_t end;
krh@56
  1110
	char buffer[512];
krh@56
  1111
krh@56
  1112
	package = razor_set_get_package(set, name);
krh@56
  1113
danw@116
  1114
	r = list_first(&package->files, &set->file_pool);
krh@56
  1115
	end = set->files.size / sizeof (struct razor_entry);
krh@56
  1116
	buffer[0] = '\0';
krh@56
  1117
	list_package_files(set, r, set->files.data, end, buffer);
krh@56
  1118
}
krh@56
  1119
krh@43
  1120
static void
krh@21
  1121
razor_set_validate(struct razor_set *set, struct array *unsatisfied)
krh@21
  1122
{
krh@66
  1123
	struct razor_property *r, *p, *end;
danw@108
  1124
	uint32_t *u;
krh@21
  1125
	char *pool;
krh@21
  1126
krh@66
  1127
	end = set->properties.data + set->properties.size;
krh@21
  1128
	pool = set->string_pool.data;
krh@21
  1129
	
krh@66
  1130
	for (r = set->properties.data, p = r; r < end; r++) {
danw@119
  1131
		if (r->type != RAZOR_PROPERTY_REQUIRES)
krh@66
  1132
			continue;
krh@66
  1133
danw@129
  1134
		p = r;
danw@129
  1135
		while (p < end && p->name == r->name &&
danw@129
  1136
		       p->type == r->type)
danw@129
  1137
			p++;
krh@37
  1138
krh@35
  1139
		/* If there is more than one version of a provides,
krh@35
  1140
		 * seek to the end for the highest version. */
krh@66
  1141
		/* FIXME: This doesn't work if we have a series of
krh@66
  1142
		 * requires a = 1, provides a = 1, requires a = 2,
krh@66
  1143
		 * provides a = 2, as the kernel and kernel-devel
krh@66
  1144
		 * does.*/
danw@119
  1145
		while (p + 1 < end && p->name == (p + 1)->name &&
danw@119
  1146
		       p->type == (p + 1)->type)
krh@35
  1147
			p++;
krh@37
  1148
krh@37
  1149
		/* FIXME: We need to track property flags (<, <=, =
krh@37
  1150
		 * etc) to properly determine if a requires is
krh@37
  1151
		 * satisfied.  The current code doesn't track that the
krh@37
  1152
		 * requires a = 1 isn't satisfied by a = 2 provides. */
krh@37
  1153
krh@66
  1154
		if (p == end ||
danw@119
  1155
		    p->type != RAZOR_PROPERTY_PROVIDES ||
danw@119
  1156
		    r->name != p->name ||
krh@35
  1157
		    versioncmp(&pool[r->version], &pool[p->version]) > 0) {
krh@35
  1158
			/* FIXME: We ignore file requires for now. */
danw@119
  1159
			if (pool[r->name] == '/')
krh@35
  1160
				continue;
krh@21
  1161
			u = array_add(unsatisfied, sizeof *u);
krh@66
  1162
			*u = r - (struct razor_property *) set->properties.data;
krh@21
  1163
		}
krh@21
  1164
	}
krh@21
  1165
}
krh@21
  1166
krh@21
  1167
void
krh@21
  1168
razor_set_list_unsatisfied(struct razor_set *set)
krh@21
  1169
{
krh@21
  1170
	struct array unsatisfied;
krh@66
  1171
	struct razor_property *properties, *r;
danw@108
  1172
	uint32_t *u, *end;
krh@21
  1173
	char *pool;
krh@21
  1174
krh@21
  1175
	array_init(&unsatisfied);
krh@21
  1176
	razor_set_validate(set, &unsatisfied);
krh@21
  1177
krh@21
  1178
	end = unsatisfied.data + unsatisfied.size;
krh@66
  1179
	properties = set->properties.data;
krh@21
  1180
	pool = set->string_pool.data;
krh@21
  1181
krh@21
  1182
	for (u = unsatisfied.data; u < end; u++) {
krh@66
  1183
		r = properties + *u;
krh@66
  1184
		if (pool[r->version] == '\0')
krh@66
  1185
			printf("%ss not satisfied\n",
danw@119
  1186
			       &pool[r->name]);
krh@66
  1187
		else
krh@66
  1188
			printf("%s-%s not satisfied\n",
danw@119
  1189
			       &pool[r->name],
krh@66
  1190
			       &pool[r->version]);
krh@21
  1191
	}
krh@21
  1192
krh@21
  1193
	array_release(&unsatisfied);
krh@21
  1194
}
krh@21
  1195
danw@120
  1196
#define UPSTREAM_SOURCE 0x80
krh@41
  1197
krh@41
  1198
struct source {
krh@41
  1199
	struct razor_set *set;
danw@108
  1200
	uint32_t *property_map;
danw@127
  1201
	uint32_t *file_map;
krh@41
  1202
};
krh@41
  1203
krh@79
  1204
struct razor_merger {
krh@79
  1205
	struct razor_set *set;
krh@79
  1206
	struct hashtable table;
krh@79
  1207
	struct source source1;
krh@79
  1208
	struct source source2;
krh@79
  1209
};
krh@79
  1210
krh@79
  1211
static struct razor_merger *
krh@79
  1212
razor_merger_create(struct razor_set *set1, struct razor_set *set2)
krh@41
  1213
{
krh@79
  1214
	struct razor_merger *merger;
krh@41
  1215
	int count;
krh@41
  1216
	size_t size;
krh@41
  1217
krh@79
  1218
	merger = zalloc(sizeof *merger);
krh@79
  1219
	merger->set = razor_set_create();
krh@79
  1220
	hashtable_init(&merger->table, &merger->set->string_pool);
krh@41
  1221
danw@127
  1222
	merger->source1.set = set1;
krh@79
  1223
	count = set1->properties.size / sizeof (struct razor_property);
krh@79
  1224
	size = count * sizeof merger->source1.property_map[0];
krh@79
  1225
	merger->source1.property_map = zalloc(size);
danw@127
  1226
	count = set1->files.size / sizeof (struct razor_entry);
danw@127
  1227
	size = count * sizeof merger->source1.file_map[0];
danw@127
  1228
	merger->source1.file_map = zalloc(size);
krh@79
  1229
danw@127
  1230
	merger->source2.set = set2;
krh@79
  1231
	count = set2->properties.size / sizeof (struct razor_property);
krh@79
  1232
	size = count * sizeof merger->source2.property_map[0];
krh@79
  1233
	merger->source2.property_map = zalloc(size);
danw@127
  1234
	count = set2->files.size / sizeof (struct razor_entry);
danw@127
  1235
	size = count * sizeof merger->source2.file_map[0];
danw@127
  1236
	merger->source2.file_map = zalloc(size);
krh@79
  1237
krh@79
  1238
	return merger;
krh@41
  1239
}
krh@41
  1240
krh@33
  1241
static void
krh@79
  1242
add_package(struct razor_merger *merger,
krh@41
  1243
	    struct razor_package *package, struct source *source,
danw@108
  1244
	    uint32_t flags)
krh@33
  1245
{
krh@33
  1246
	char *pool;
danw@117
  1247
	struct list *r;
krh@41
  1248
	struct razor_package *p;
krh@33
  1249
krh@41
  1250
	pool = source->set->string_pool.data;
krh@79
  1251
	p = array_add(&merger->set->packages, sizeof *p);
krh@79
  1252
	p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
danw@120
  1253
	p->flags = flags;
krh@79
  1254
	p->version = hashtable_tokenize(&merger->table,
krh@79
  1255
					&pool[package->version]);
krh@192
  1256
	p->arch = hashtable_tokenize(&merger->table,
krh@192
  1257
				     &pool[package->arch]);
danw@127
  1258
krh@66
  1259
	p->properties = package->properties;
danw@116
  1260
	r = list_first(&package->properties, &source->set->property_pool);
danw@116
  1261
	while (r) {
danw@117
  1262
		source->property_map[r->data] = 1;
danw@116
  1263
		r = list_next(r);
krh@64
  1264
	}
danw@127
  1265
danw@127
  1266
	p->files = package->files;
danw@127
  1267
	r = list_first(&package->files, &source->set->file_pool);
danw@127
  1268
	while (r) {
danw@127
  1269
		source->file_map[r->data] = 1;
danw@127
  1270
		r = list_next(r);
danw@127
  1271
	}
krh@41
  1272
}
krh@41
  1273
danw@108
  1274
static uint32_t
krh@79
  1275
add_property(struct razor_merger *merger,
danw@109
  1276
	     const char *name, enum razor_version_relation relation,
danw@109
  1277
	     const char *version, int type)
krh@41
  1278
{
krh@41
  1279
	struct razor_property *p;
krh@41
  1280
krh@79
  1281
	p = array_add(&merger->set->properties, sizeof *p);
danw@119
  1282
	p->name = hashtable_tokenize(&merger->table, name);
danw@119
  1283
	p->flags = 0;
danw@119
  1284
	p->type = type;
danw@109
  1285
	p->relation = relation;
krh@79
  1286
	p->version = hashtable_tokenize(&merger->table, version);
krh@41
  1287
krh@79
  1288
	return p - (struct razor_property *) merger->set->properties.data;
krh@41
  1289
}
krh@41
  1290
krh@41
  1291
static void
krh@79
  1292
merge_properties(struct razor_merger *merger)
krh@41
  1293
{
krh@41
  1294
	struct razor_property *p1, *p2;
krh@79
  1295
	struct razor_set *set1, *set2;
danw@108
  1296
	uint32_t *map1, *map2;
krh@41
  1297
	int i, j, cmp, count1, count2;
krh@41
  1298
	char *pool1, *pool2;
krh@41
  1299
krh@79
  1300
	set1 = merger->source1.set;
krh@79
  1301
	set2 = merger->source2.set;
krh@79
  1302
	map1 = merger->source1.property_map;
krh@79
  1303
	map2 = merger->source2.property_map;
krh@79
  1304
krh@41
  1305
	i = 0;
krh@41
  1306
	j = 0;
krh@41
  1307
	pool1 = set1->string_pool.data;
krh@41
  1308
	pool2 = set2->string_pool.data;
krh@41
  1309
krh@66
  1310
	count1 = set1->properties.size / sizeof *p1;
krh@66
  1311
	count2 = set2->properties.size / sizeof *p2;
krh@41
  1312
	while (i < count1 || j < count2) {
krh@41
  1313
		if (i < count1 && map1[i] == 0) {
krh@41
  1314
			i++;
krh@41
  1315
			continue;
krh@41
  1316
		}
krh@41
  1317
		if (j < count2 && map2[j] == 0) {
krh@41
  1318
			j++;
krh@41
  1319
			continue;
krh@41
  1320
		}
krh@66
  1321
		p1 = (struct razor_property *) set1->properties.data + i;
krh@66
  1322
		p2 = (struct razor_property *) set2->properties.data + j;
krh@41
  1323
		if (i < count1 && j < count2)
danw@119
  1324
			cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
krh@41
  1325
		else if (i < count1)
krh@41
  1326
			cmp = -1;
krh@41
  1327
		else
krh@41
  1328
			cmp = 1;
krh@41
  1329
		if (cmp == 0)
danw@121
  1330
			cmp = p1->type - p2->type;
danw@121
  1331
		if (cmp == 0)
danw@109
  1332
			cmp = p1->relation - p2->relation;
danw@109
  1333
		if (cmp == 0)
krh@41
  1334
			cmp = versioncmp(&pool1[p1->version],
krh@41
  1335
					 &pool2[p2->version]);
krh@41
  1336
		if (cmp < 0) {
krh@79
  1337
			map1[i++] = add_property(merger,
danw@119
  1338
						 &pool1[p1->name],
danw@109
  1339
						 p1->relation,
krh@69
  1340
						 &pool1[p1->version],
danw@119
  1341
						 p1->type);
krh@41
  1342
		} else if (cmp > 0) {
krh@79
  1343
			map2[j++] = add_property(merger,
danw@119
  1344
						 &pool2[p2->name],
danw@109
  1345
						 p2->relation,
krh@69
  1346
						 &pool2[p2->version],
danw@119
  1347
						 p2->type);
krh@41
  1348
		} else  {
krh@79
  1349
			map1[i++] = map2[j++] = add_property(merger,
danw@119
  1350
							     &pool1[p1->name],
danw@109
  1351
							     p1->relation,
krh@69
  1352
							     &pool1[p1->version],
danw@119
  1353
							     p1->type);
krh@41
  1354
		}
krh@41
  1355
	}
krh@41
  1356
}
krh@41
  1357
danw@116
  1358
static void
danw@117
  1359
emit_properties(struct list_head *properties, struct array *source_pool,
danw@108
  1360
		uint32_t *map, struct array *pool)
krh@41
  1361
{
danw@117
  1362
	uint32_t r;
danw@117
  1363
	struct list *p, *q;
krh@41
  1364
krh@41
  1365
	r = pool->size / sizeof *q;
danw@116
  1366
	p = list_first(properties, source_pool);
danw@116
  1367
	while (p) {
krh@41
  1368
		q = array_add(pool, sizeof *q);
danw@117
  1369
		q->data = map[p->data];
danw@117
  1370
		q->flags = p->flags;
danw@116
  1371
		p = list_next(p);
krh@33
  1372
	}
krh@33
  1373
danw@117
  1374
	list_set_ptr(properties, r);
krh@41
  1375
}
danw@127
  1376
danw@127
  1377
static uint32_t
danw@127
  1378
add_file(struct razor_merger *merger, const char *name)
danw@127
  1379
{
danw@127
  1380
	struct razor_entry *e;
danw@127
  1381
danw@127
  1382
	e = array_add(&merger->set->files, sizeof *e);
danw@127
  1383
	e->name = hashtable_tokenize(&merger->table, name);
danw@127
  1384
	e->flags = 0;
danw@127
  1385
	e->start = 0;
danw@127
  1386
danw@127
  1387
	return e - (struct razor_entry *)merger->set->files.data;
danw@127
  1388
}
danw@127
  1389
danw@129
  1390
/* FIXME. Blah */
danw@127
  1391
static int
danw@127
  1392
fix_file_map(uint32_t *map,
danw@127
  1393
	     struct razor_entry *files,
danw@127
  1394
	     struct razor_entry *top)
danw@127
  1395
{
danw@127
  1396
	uint32_t e;
danw@127
  1397
	int found_file = 0;
danw@127
  1398
danw@127
  1399
	e = top->start;
danw@127
  1400
	do {
danw@127
  1401
		if (files[e].start)
danw@127
  1402
			fix_file_map(map, files, &files[e]);
danw@127
  1403
		if (map[e])
danw@127
  1404
			found_file = 1;
danw@127
  1405
	} while (!(files[e++].flags & RAZOR_ENTRY_LAST));
danw@127
  1406
danw@127
  1407
	if (found_file)
danw@127
  1408
		map[top - files] = 1;
danw@127
  1409
	return found_file;
danw@127
  1410
}
danw@127
  1411
danw@127
  1412
struct merge_directory {
danw@127
  1413
	uint32_t merged, dir1, dir2;
danw@127
  1414
};
danw@127
  1415
danw@127
  1416
static void
danw@127
  1417
merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
danw@127
  1418
{
danw@127
  1419
	struct razor_entry *root1, *root2, *mroot, *e1, *e2;
danw@127
  1420
	struct razor_set *set1, *set2;
danw@127
  1421
	struct array merge_stack;
danw@127
  1422
	struct merge_directory *child_md, *end_md;
danw@127
  1423
	uint32_t *map1, *map2, start, last;
danw@127
  1424
	int cmp;
danw@127
  1425
	char *pool1, *pool2;
danw@127
  1426
danw@127
  1427
	set1 = merger->source1.set;
danw@127
  1428
	set2 = merger->source2.set;
danw@127
  1429
	map1 = merger->source1.file_map;
danw@127
  1430
	map2 = merger->source2.file_map;
danw@127
  1431
	pool1 = set1->string_pool.data;
danw@127
  1432
	pool2 = set2->string_pool.data;
danw@127
  1433
	root1 = (struct razor_entry *) set1->files.data;
danw@127
  1434
	root2 = (struct razor_entry *) set2->files.data;
danw@127
  1435
danw@127
  1436
	array_init(&merge_stack);
danw@127
  1437
danw@127
  1438
	start = merger->set->files.size / sizeof (struct razor_entry);
danw@127
  1439
	last = 0;
danw@127
  1440
	e1 = md->dir1 ? root1 + md->dir1 : NULL;
danw@127
  1441
	e2 = md->dir2 ? root2 + md->dir2 : NULL;
danw@127
  1442
	while (e1 || e2) {
danw@127
  1443
		if (!e2 && !map1[e1 - root1]) {
danw@127
  1444
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1445
				e1 = NULL;
danw@127
  1446
			continue;
danw@127
  1447
		}
danw@127
  1448
		if (!e1 && !map2[e2 - root2]) {
danw@127
  1449
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1450
				e2 = NULL;
danw@127
  1451
			continue;
danw@127
  1452
		}
danw@127
  1453
		if (e1 && !map1[e1 - root1] &&
danw@127
  1454
		    e2 && !map1[e2 - root2]) {
danw@127
  1455
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1456
				e1 = NULL;
danw@127
  1457
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1458
				e2 = NULL;
danw@127
  1459
			continue;
danw@127
  1460
		}
danw@127
  1461
danw@127
  1462
		if (!e1)
danw@127
  1463
			cmp = 1;
danw@127
  1464
		else if (!e2)
danw@127
  1465
			cmp = -1;
danw@127
  1466
		else {
danw@127
  1467
			cmp = strcmp (&pool1[e1->name],
danw@127
  1468
				      &pool2[e2->name]);
danw@127
  1469
		}
danw@127
  1470
danw@127
  1471
		if (cmp < 0) {
danw@127
  1472
			if (map1[e1 - root1]) {
danw@127
  1473
				map1[e1 - root1] = last =
danw@127
  1474
					add_file(merger, &pool1[e1->name]);
danw@127
  1475
				if (e1->start) {
danw@127
  1476
					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
danw@127
  1477
					child_md->merged = last;
danw@127
  1478
					child_md->dir1 = e1->start;
danw@127
  1479
					child_md->dir2 = 0;
danw@127
  1480
				}
danw@127
  1481
			}
danw@127
  1482
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1483
				e1 = NULL;
danw@127
  1484
		} else if (cmp > 0) {
danw@127
  1485
			if (map2[e2 - root2]) {
danw@127
  1486
				map2[e2 - root2] = last =
danw@127
  1487
					add_file(merger, &pool2[e2->name]);
danw@127
  1488
				if (e2->start) {
danw@127
  1489
					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
danw@127
  1490
					child_md->merged = last;
danw@127
  1491
					child_md->dir1 = 0;
danw@127
  1492
					child_md->dir2 = e2->start;
danw@127
  1493
				}
danw@127
  1494
			}
danw@127
  1495
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1496
				e2 = NULL;
danw@127
  1497
		} else {
danw@127
  1498
			map1[e1 - root1] = map2[e2- root2] = last =
danw@127
  1499
				add_file(merger, &pool1[e1->name]);
danw@127
  1500
			if (e1->start || e2->start) {
danw@127
  1501
				child_md = array_add(&merge_stack, sizeof (struct merge_directory));
danw@127
  1502
				child_md->merged = last;
danw@127
  1503
				child_md->dir1 = e1->start;
danw@127
  1504
				child_md->dir2 = e2->start;
danw@127
  1505
			}
danw@127
  1506
			if ((e1++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1507
				e1 = NULL;
danw@127
  1508
			if ((e2++)->flags & RAZOR_ENTRY_LAST)
danw@127
  1509
				e2 = NULL;
danw@127
  1510
		}
danw@127
  1511
	}
danw@127
  1512
danw@127
  1513
	mroot = (struct razor_entry *)merger->set->files.data;
danw@127
  1514
	if (last) {
danw@127
  1515
		mroot[last].flags = RAZOR_ENTRY_LAST;
danw@127
  1516
		mroot[md->merged].start = start;
danw@127
  1517
	} else
danw@127
  1518
		mroot[md->merged].start = 0;
danw@127
  1519
danw@127
  1520
	end_md = merge_stack.data + merge_stack.size;
danw@127
  1521
	for (child_md = merge_stack.data; child_md < end_md; child_md++)
danw@127
  1522
		merge_one_directory(merger, child_md);
danw@127
  1523
	array_release(&merge_stack);
danw@127
  1524
}
danw@127
  1525
danw@127
  1526
static void
danw@127
  1527
merge_files(struct razor_merger *merger)
danw@127
  1528
{
danw@129
  1529
	struct razor_entry *root;
danw@127
  1530
	struct merge_directory md;
danw@127
  1531
	uint32_t *map1, *map2;
danw@127
  1532
danw@127
  1533
	map1 = merger->source1.file_map;
danw@127
  1534
	map2 = merger->source2.file_map;
danw@127
  1535
danw@164
  1536
	md.merged = 0;
danw@129
  1537
danw@129
  1538
	if (merger->source1.set->files.size) {
danw@129
  1539
		root = (struct razor_entry *) merger->source1.set->files.data;
danw@129
  1540
		if (root->start)
danw@129
  1541
			fix_file_map(map1, root, root);
danw@129
  1542
		md.dir1 = root->start;
danw@129
  1543
	} else
danw@129
  1544
		md.dir1 = 0;
danw@129
  1545
danw@129
  1546
	if (merger->source2.set->files.size) {
danw@129
  1547
		root = (struct razor_entry *) merger->source2.set->files.data;
danw@129
  1548
		if (root->start)
danw@129
  1549
			fix_file_map(map2, root, root);
danw@129
  1550
		md.dir2 = root->start;
danw@129
  1551
	} else
danw@129
  1552
		md.dir2 = 0;
danw@129
  1553
danw@127
  1554
	merge_one_directory(merger, &md);
danw@127
  1555
}
danw@127
  1556
danw@127
  1557
static void
danw@127
  1558
emit_files(struct list_head *files, struct array *source_pool,
danw@127
  1559
	   uint32_t *map, struct array *pool)
danw@127
  1560
{
danw@127
  1561
	uint32_t r;
danw@127
  1562
	struct list *p, *q;
danw@127
  1563
danw@127
  1564
	r = pool->size / sizeof *q;
danw@127
  1565
	p = list_first(files, source_pool);
danw@127
  1566
	while (p) {
danw@127
  1567
		q = array_add(pool, sizeof *q);
danw@127
  1568
		q->data = map[p->data];
danw@127
  1569
		q->flags = p->flags;
danw@127
  1570
		p = list_next(p);
danw@127
  1571
	}
danw@127
  1572
danw@127
  1573
	list_set_ptr(files, r);
danw@127
  1574
}
danw@127
  1575
krh@41
  1576
/* Rebuild property->packages maps.  We can't just remap these, as a
krh@41
  1577
 * property may have lost or gained a number of packages.  Allocate an
krh@41
  1578
 * array per property and loop through the packages and add them to
krh@41
  1579
 * the arrays for their properties. */
krh@41
  1580
static void
danw@127
  1581
rebuild_property_package_lists(struct razor_set *set)
krh@41
  1582
{
krh@66
  1583
	struct array *pkgs, *a;
krh@41
  1584
	struct razor_package *pkg, *pkg_end;
krh@41
  1585
	struct razor_property *prop, *prop_end;
danw@117
  1586
	struct list *r;
danw@117
  1587
	uint32_t *q;
krh@66
  1588
	int count;
krh@41
  1589
krh@66
  1590
	count = set->properties.size / sizeof (struct razor_property);
krh@66
  1591
	pkgs = zalloc(count * sizeof *pkgs);
krh@41
  1592
	pkg_end = set->packages.data + set->packages.size;
krh@41
  1593
krh@41
  1594
	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
danw@128
  1595
		r = list_first(&pkg->properties, &set->property_pool);
danw@116
  1596
		while (r) {
danw@117
  1597
			q = array_add(&pkgs[r->data], sizeof *q);
krh@41
  1598
			*q = pkg - (struct razor_package *) set->packages.data;
danw@116
  1599
			r = list_next(r);
krh@41
  1600
		}
krh@33
  1601
	}
krh@33
  1602
krh@66
  1603
	prop_end = set->properties.data + set->properties.size;
krh@66
  1604
	a = pkgs;
krh@66
  1605
	for (prop = set->properties.data; prop < prop_end; prop++, a++) {
danw@128
  1606
		list_set_array(&prop->packages, &set->package_pool, a, 0);
krh@41
  1607
		array_release(a);
krh@41
  1608
	}
krh@66
  1609
	free(pkgs);
krh@33
  1610
}
krh@33
  1611
danw@127
  1612
static void
danw@127
  1613
rebuild_file_package_lists(struct razor_set *set)
danw@127
  1614
{
danw@127
  1615
	struct array *pkgs, *a;
danw@127
  1616
	struct razor_package *pkg, *pkg_end;
danw@127
  1617
	struct razor_entry *entry, *entry_end;
danw@127
  1618
	struct list *r;
danw@127
  1619
	uint32_t *q;
danw@127
  1620
	int count;
danw@127
  1621
danw@127
  1622
	count = set->files.size / sizeof (struct razor_entry);
danw@127
  1623
	pkgs = zalloc(count * sizeof *pkgs);
danw@127
  1624
	pkg_end = set->packages.data + set->packages.size;
danw@127
  1625
danw@127
  1626
	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
danw@128
  1627
		r = list_first(&pkg->files, &set->file_pool);
danw@127
  1628
		while (r) {
danw@127
  1629
			q = array_add(&pkgs[r->data], sizeof *q);
danw@127
  1630
			*q = pkg - (struct razor_package *) set->packages.data;
danw@127
  1631
			r = list_next(r);
danw@127
  1632
		}
danw@127
  1633
	}
danw@127
  1634
danw@127
  1635
	entry_end = set->files.data + set->files.size;
danw@127
  1636
	a = pkgs;
danw@127
  1637
	for (entry = set->files.data; entry < entry_end; entry++, a++) {
danw@128
  1638
		list_set_array(&entry->packages, &set->package_pool, a, 0);
danw@127
  1639
		array_release(a);
danw@127
  1640
	}
danw@127
  1641
	free(pkgs);
danw@127
  1642
}
danw@127
  1643
danw@137
  1644
static struct razor_set *
krh@79
  1645
razor_merger_finish(struct razor_merger *merger)
krh@79
  1646
{
krh@79
  1647
	struct razor_set *result;
krh@41
  1648
	struct razor_package *p, *pend;
krh@33
  1649
krh@41
  1650
	/* As we built the package list, we filled out a bitvector of
krh@41
  1651
	 * the properties that are referenced by the packages in the
krh@41
  1652
	 * new set.  Now we do a parallel loop through the properties
krh@41
  1653
	 * and emit those marked in the bit vector to the new set.  In
krh@41
  1654
	 * the process, we update the bit vector to actually map from
krh@41
  1655
	 * indices in the old property list to indices in the new
krh@41
  1656
	 * property list for both sets. */
krh@41
  1657
krh@79
  1658
	merge_properties(merger);
danw@127
  1659
	merge_files(merger);
krh@41
  1660
krh@41
  1661
	/* Now we loop through the packages again and emit the
krh@41
  1662
	 * property lists, remapped to point to the new properties. */
krh@41
  1663
krh@79
  1664
	pend = merger->set->packages.data + merger->set->packages.size;
krh@79
  1665
	for (p = merger->set->packages.data; p < pend; p++) {
krh@41
  1666
		struct source *src;
krh@41
  1667
danw@120
  1668
		if (p->flags & UPSTREAM_SOURCE)
krh@79
  1669
			src = &merger->source2;
krh@41
  1670
		else
krh@79
  1671
			src = &merger->source1;
krh@41
  1672
danw@116
  1673
		emit_properties(&p->properties,
danw@116
  1674
				&src->set->property_pool,
danw@116
  1675
				src->property_map,
danw@116
  1676
				&merger->set->property_pool);
danw@127
  1677
		emit_files(&p->files,
danw@127
  1678
			   &src->set->file_pool,
danw@127
  1679
			   src->file_map,
danw@127
  1680
			   &merger->set->file_pool);
danw@120
  1681
		p->flags &= ~UPSTREAM_SOURCE;
krh@33
  1682
	}
krh@33
  1683
danw@127
  1684
	rebuild_property_package_lists(merger->set);
danw@127
  1685
	rebuild_file_package_lists(merger->set);
krh@41
  1686
danw@129
  1687
	result = merger->set;
danw@129
  1688
	hashtable_release(&merger->table);
danw@129
  1689
	free(merger);
danw@129
  1690
danw@129
  1691
	return result;
danw@129
  1692
}
danw@129
  1693
danw@146
  1694
/* The diff order matters.  We should sort the packages so that a
danw@146
  1695
 * REMOVE of a package comes before the INSTALL, and so that all
danw@146
  1696
 * requires for a package have been installed before the package.
danw@146
  1697
 **/
danw@146
  1698
danw@146
  1699
void
danw@146
  1700
razor_set_diff(struct razor_set *set, struct razor_set *upstream,
danw@146
  1701
	       razor_package_callback_t callback, void *data)
danw@146
  1702
{
danw@146
  1703
	struct razor_package_iterator *pi1, *pi2;
danw@146
  1704
	struct razor_package *p1, *p2;
krh@192
  1705
	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
danw@146
  1706
	int res;
danw@146
  1707
danw@146
  1708
	pi1 = razor_package_iterator_create(set);
danw@146
  1709
	pi2 = razor_package_iterator_create(upstream);
danw@146
  1710
krh@192
  1711
	razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
krh@192
  1712
	razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
danw@146
  1713
danw@146
  1714
	while (p1 || p2) {
danw@146
  1715
		if (p1 && p2) {
danw@146
  1716
			res = strcmp(name1, name2);
danw@146
  1717
			if (res == 0)
danw@146
  1718
				res = versioncmp(version1, version2);
danw@146
  1719
		} else {
danw@146
  1720
			res = 0;
danw@146
  1721
		}
danw@146
  1722
danw@146
  1723
		if (p2 == NULL || res < 0)
krh@192
  1724
			callback(name1, version1, NULL, arch1, data);
danw@146
  1725
		else if (p1 == NULL || res > 0)
krh@192
  1726
			callback(name2, NULL, version2, arch2, data);
danw@146
  1727
danw@146
  1728
		if (p1 != NULL && res <= 0)
danw@146
  1729
			razor_package_iterator_next(pi1, &p1,
krh@192
  1730
						    &name1, &version1, &arch1);
danw@146
  1731
		if (p2 != NULL && res >= 0)
danw@146
  1732
			razor_package_iterator_next(pi2, &p2,
krh@192
  1733
						    &name2, &version2, &arch2);
danw@146
  1734
	}
danw@146
  1735
danw@146
  1736
	razor_package_iterator_destroy(pi1);
danw@146
  1737
	razor_package_iterator_destroy(pi2);
danw@146
  1738
}
danw@146
  1739
krh@190
  1740
struct razor_transaction;
krh@190
  1741
struct razor_transaction_package;
krh@190
  1742
struct razor_transaction_resolver;
krh@190
  1743
krh@190
  1744
struct razor_transaction {
krh@190
  1745
	int package_count, errors;
krh@190
  1746
	struct razor_set *system, *upstream;
krh@191
  1747
krh@191
  1748
	struct bitarray syspkgs, uppkgs;
krh@191
  1749
	struct array packages;
krh@190
  1750
};
krh@190
  1751
krh@190
  1752
struct razor_transaction_package {
krh@190
  1753
	const char *name, *old_version, *new_version;
krh@190
  1754
	struct razor_package *old_package, *new_package;
krh@190
  1755
	enum razor_transaction_package_state state;
krh@190
  1756
krh@190
  1757
	/* dep_package is the name of the package that resulted in
krh@190
  1758
	 * this entry being created (or NULL if the user requested the
krh@190
  1759
	 * install/remove), with the other dep_ fields providing
krh@190
  1760
	 * additional information.
krh@190
  1761
	 *
krh@190
  1762
	 * For INSTALL, if dep_type is REQUIRES, then dep_package
krh@190
  1763
	 * required something that this package provides. If dep_type
krh@190
  1764
	 * is CONFLICTS, then dep_package is a package that conflicted
krh@190
  1765
	 * with an older version of this package, forcing an upgrade.
krh@190
  1766
	 *
krh@190
  1767
	 * For REMOVE, if dep_type is REQUIRES, then dep_package is a
krh@190
  1768
	 * package that is being removed. If dep_type is OBSOLETES,
krh@190
  1769
	 * then dep_package is a package that obsoletes this one.
krh@190
  1770
	 *
krh@190
  1771
	 * For OLD_CONFLICT or NEW_CONFLICT, dep_package is an
krh@190
  1772
	 * existing package that conflicts with this one. The
krh@190
  1773
	 * conflicting property comes from the already-installed
krh@190
  1774
	 * package for OLD_CONFLICT, or the to-be-installed package
krh@190
  1775
	 * for NEW_CONFLICT.
krh@190
  1776
	 *
krh@190
  1777
	 * For UNSATISFIABLE, the dep_ fields are as for an INSTALL,
krh@190
  1778
	 * but the name field will be NULL.
krh@190
  1779
	 */
krh@190
  1780
	const char *dep_package;
krh@190
  1781
	enum razor_property_type dep_type;
krh@190
  1782
	const char *dep_property;
krh@190
  1783
	enum razor_version_relation dep_relation;
krh@190
  1784
	const char *dep_version;
krh@190
  1785
};
danw@141
  1786
danw@144
  1787
static int
danw@144
  1788
package_in_set(void *package, struct razor_set *set)
danw@144
  1789
{
danw@144
  1790
	return package >= set->packages.data &&
danw@144
  1791
		package < set->packages.data + set->packages.size;
danw@144
  1792
}
danw@144
  1793
danw@144
  1794
static int
danw@144
  1795
property_in_set(void *property, struct razor_set *set)
danw@144
  1796
{
danw@144
  1797
	return property >= set->properties.data &&
danw@144
  1798
		property < set->properties.data + set->properties.size;
danw@144
  1799
}
danw@144
  1800
danw@168
  1801
static struct razor_package *
krh@191
  1802
property_provider_package(struct razor_transaction *trans,
danw@168
  1803
			  struct razor_property *prop,
danw@168
  1804
			  int installed)
danw@168
  1805
{
danw@168
  1806
	struct razor_set *set;
danw@168
  1807
	struct bitarray *pkgbits;
danw@168
  1808
	struct razor_package *pkgs;
danw@168
  1809
	struct list *p;
danw@168
  1810
danw@168
  1811
	if (installed && prop->type != RAZOR_PROPERTY_PROVIDES)
danw@168
  1812
		return NULL;
danw@168
  1813
	else if (!installed &&
danw@168
  1814
		 prop->type != RAZOR_PROPERTY_PROVIDES &&
danw@168
  1815
		 prop->type != RAZOR_PROPERTY_OBSOLETES)
danw@168
  1816
		return NULL;
danw@168
  1817
danw@168
  1818
	if (property_in_set(prop, trans->system)) {
danw@168
  1819
		set = trans->system;
danw@168
  1820
		pkgbits = &trans->syspkgs;
danw@168
  1821
	} else {
danw@168
  1822
		set = trans->upstream;
danw@168
  1823
		pkgbits = &trans->uppkgs;
danw@168
  1824
	}
danw@168
  1825
	pkgs = set->packages.data;
danw@168
  1826
danw@168
  1827
	for (p = list_first(&prop->packages, &set->package_pool); p; p = list_next(p)) {
danw@168
  1828
		if (bitarray_get(pkgbits, p->data) != installed)
danw@168
  1829
			continue;
danw@168
  1830
		if (prop->type == RAZOR_PROPERTY_OBSOLETES ||
danw@168
  1831
		    pkgs[p->data].name == prop->name)
danw@168
  1832
			return &pkgs[p->data];
danw@168
  1833
	}
danw@168
  1834
	return NULL;
danw@168
  1835
}
danw@168
  1836
danw@144
  1837
static int
danw@144
  1838
compare_transaction_packages(const void *one, const void *two)
danw@144
  1839
{
danw@160
  1840
	struct razor_transaction_package **tp1 = (void *)one;
danw@160
  1841
	struct razor_transaction_package **tp2 = (void *)two;
danw@160
  1842
danw@160
  1843
	if (!(*tp1)->name)
danw@160
  1844
		return 1;
danw@160
  1845
	else if (!(*tp2)->name)
danw@160
  1846
		return -1;
danw@160
  1847
	else
danw@160
  1848
		return strcmp((*tp1)->name, (*tp2)->name);
danw@144
  1849
}
danw@144
  1850
danw@168
  1851
/* FIXME: merge this into the other property loop in razor_transaction_satisfy */
danw@141
  1852
static void
krh@191
  1853
resolve_new_packages(struct razor_transaction *trans,
danw@160
  1854
		     int start, int end)
krh@38
  1855
{
danw@168
  1856
	struct razor_property *sp, *up, *sp_end, *up_end;
danw@168
  1857
	struct razor_package *spkg, *spkgs, *upkg, *upkgs;
danw@160
  1858
	struct razor_transaction_package **packages;
danw@144
  1859
	const char *spool, *upool;
danw@144
  1860
	int i;
danw@144
  1861
danw@168
  1862
	sp_end = trans->system->properties.data + trans->system->properties.size;
danw@168
  1863
	spool = trans->system->string_pool.data;
danw@144
  1864
	spkgs = trans->system->packages.data;
danw@168
  1865
	up_end = trans->upstream->properties.data + trans->upstream->properties.size;
danw@168
  1866
	upool = trans->upstream->string_pool.data;
danw@144
  1867
	upkgs = trans->upstream->packages.data;
danw@168
  1868
danw@168
  1869
	/* FIXME, check if sorting the packages directly (rather than
danw@168
  1870
	 * sorting pointers-to-packages) still results in confusing
danw@168
  1871
	 * descriptions.
danw@168
  1872
	 */
danw@160
  1873
	packages = calloc(end - start, sizeof *packages);
danw@160
  1874
	for (i = start; i < end; i++)
danw@160
  1875
		packages[i - start] = ((struct razor_transaction_package *)trans->packages.data) + i;
danw@160
  1876
	qsort(packages, end - start, sizeof *packages,
danw@160
  1877
	      compare_transaction_packages);
danw@144
  1878
danw@168
  1879
	sp = trans->system->properties.data;
danw@168
  1880
	up = trans->upstream->properties.data;
danw@160
  1881
	for (i = 0; i < end - start; i++) {
danw@169
  1882
		if (!packages[i]->name ||
danw@169
  1883
		    packages[i]->state >= RAZOR_PACKAGE_FIRST_ERROR_STATE)
danw@160
  1884
			continue;
danw@168
  1885
danw@168
  1886
		spkg = NULL;
danw@168
  1887
		while (sp < sp_end &&
danw@168
  1888
		       strcmp(&spool[sp->name], packages[i]->name) < 0)
danw@144
  1889
			sp++;
danw@168
  1890
		while (sp < sp_end &&
danw@168
  1891
		       strcmp(&spool[sp->name], packages[i]->name) == 0 &&
danw@168
  1892
		       !(spkg = property_provider_package(trans, sp, 1)))
danw@168
  1893
			sp++;
danw@168
  1894
danw@168
  1895
		upkg = NULL;
danw@168
  1896
		while (up < up_end &&
danw@168
  1897
		       strcmp(&upool[up->name], packages[i]->name) < 0)
danw@168
  1898
			up++;
danw@168
  1899
		while (up < up_end &&
danw@168
  1900
		       strcmp(&upool[up->name], packages[i]->name) == 0 &&
danw@168
  1901
		       !(upkg = property_provider_package(trans, up, 0)))
danw@144
  1902
			up++;
danw@144
  1903
danw@160
  1904
		if (packages[i]->state == RAZOR_PACKAGE_REMOVE ||
danw@160
  1905
		    packages[i]->state == RAZOR_PACKAGE_OBSOLETED) {
danw@168
  1906
			if (spkg) {
danw@168
  1907
				packages[i]->old_package = spkg;
danw@168
  1908
				packages[i]->name = &spool[spkg->name];
danw@168
  1909
				packages[i]->old_version = &spool[spkg->version];
danw@168
  1910
				bitarray_set(&trans->syspkgs, spkg - spkgs, 0);
danw@169
  1911
			}
danw@169
  1912
			if (!packages[i]->old_package) {
danw@160
  1913
				packages[i]->name = strdup(packages[i]->name);
danw@169
  1914
				packages[i]->state |= RAZOR_PACKAGE_UNAVAILABLE_FLAG;
danw@144
  1915
				trans->errors++;
danw@144
  1916
			}
danw@144
  1917
		} else {
danw@168
  1918
			if (upkg) {
danw@168
  1919
				packages[i]->new_package = upkg;
danw@168
  1920
				packages[i]->name = &upool[upkg->name];
danw@168
  1921
				packages[i]->new_version = &upool[upkg->version];
danw@168
  1922
danw@168
  1923
				if (up->name != upkg->name) {
danw@168
  1924
					packages[i]->dep_package = &upool[upkg->name];
danw@168
  1925
					packages[i]->dep_type = up->type;
danw@168
  1926
					packages[i]->dep_property = &upool[up->name];
danw@168
  1927
					packages[i]->dep_relation = up->relation;
danw@168
  1928
					packages[i]->dep_version = &upool[up->version];
danw@168
  1929
				}
danw@168
  1930
danw@168
  1931
				if (spkg) {
danw@168
  1932
					packages[i]->old_package = spkg;
danw@168
  1933
					packages[i]->old_version = &spool[spkg->version];
danw@168
  1934
					if (versioncmp(&spool[spkg->version], &upool[up->version]) >= 0) {
danw@160
  1935
						packages[i]->state = RAZOR_PACKAGE_UP_TO_DATE;
danw@144
  1936
						trans->errors++;
danw@144
  1937
						continue;
danw@144
  1938
					}
danw@168
  1939
					bitarray_set(&trans->syspkgs, spkg - spkgs, 0);
danw@144
  1940
				}
danw@168
  1941
				bitarray_set(&trans->uppkgs, upkg - upkgs, 1);
danw@169
  1942
			}
danw@169
  1943
			if (!packages[i]->new_package) {
danw@160
  1944
				packages[i]->name = strdup(packages[i]->name);
danw@169
  1945
				packages[i]->state |= RAZOR_PACKAGE_UNAVAILABLE_FLAG;
danw@144
  1946
				trans->errors++;
krh@105
  1947
			}
krh@105
  1948
		}
krh@38
  1949
	}
krh@38
  1950
}
krh@38
  1951
danw@137
  1952
static int
danw@137
  1953
provider_satisfies_requirement(struct razor_property *provider,
danw@137
  1954
			       const char *provider_strings,
danw@137
  1955
			       struct razor_property *requirement,
danw@137
  1956
			       const char *requirement_strings)
danw@137
  1957
{
danw@137
  1958
	int cmp, len;
danw@137
  1959
	const char *provided = &provider_strings[provider->version];
danw@137
  1960
	const char *required = &requirement_strings[requirement->version];
danw@137
  1961
danw@137
  1962
	if (!*required)
danw@137
  1963
		return 1;
danw@170
  1964
	if (!*provided) {
danw@170
  1965
		if (requirement->relation >= RAZOR_VERSION_EQUAL)
danw@170
  1966
			return 1;
danw@170
  1967
		else
danw@170
  1968
			return 0;
danw@170
  1969
	}
danw@137
  1970
danw@137
  1971
	cmp = versioncmp(provided, required);
danw@137
  1972
danw@137
  1973
	switch (requirement->relation) {
danw@137
  1974
	case RAZOR_VERSION_LESS:
danw@137
  1975
		return cmp < 0;
danw@137
  1976
danw@137
  1977
	case RAZOR_VERSION_LESS_OR_EQUAL:
danw@137
  1978
		if (cmp <= 0)
danw@137
  1979
			return 1;
danw@137
  1980
		/* fall through: FIXME, make sure this is correct */
danw@137
  1981
danw@137
  1982
	case RAZOR_VERSION_EQUAL:
danw@137
  1983
		if (cmp == 0)
danw@137
  1984
			return 1;
danw@137
  1985
danw@137
  1986
		/* "foo == 1.1" is satisfied by "foo 1.1-2" */
danw@137
  1987
		len = strlen(required);
danw@137
  1988
		if (!strncmp(required, provided, len) && provided[len] == '-')
danw@137
  1989
			return 1;
danw@137
  1990
		return 0;
danw@137
  1991
danw@137
  1992
	case RAZOR_VERSION_GREATER_OR_EQUAL:
danw@137
  1993
		return cmp >= 0;
danw@137
  1994
danw@137
  1995
	case RAZOR_VERSION_GREATER:
danw@137
  1996
		return cmp > 0;
danw@137
  1997
	}
danw@137
  1998
danw@137
  1999
	/* shouldn't happen */
danw@137
  2000
	return 0;
danw@137
  2001
}
danw@137
  2002
danw@142
  2003
static struct razor_package *
danw@144
  2004
find_package_for_file(struct razor_set *set, struct bitarray *pkgbits,
danw@144
  2005
		      const char *filename, int installed)
danw@134
  2006
{
danw@142
  2007
	struct razor_package *pkgs = set->packages.data;
danw@140
  2008
	struct razor_entry *entry;
danw@140
  2009
	struct list *p;
danw@134
  2010
danw@140
  2011
	if (filename[0] != '/')
danw@140
  2012
		return 0;
danw@140
  2013
danw@142
  2014
	entry = find_entry(set, set->files.data, filename);
danw@140
  2015
	if (!entry)
danw@140
  2016
		return 0;
danw@140
  2017
danw@142
  2018
	for (p = list_first(&entry->packages, &set->package_pool); p; p = list_next(p)) {
danw@142
  2019
		if (bitarray_get(pkgbits, p->data) == installed)
danw@142
  2020
			return &pkgs[p->data];
danw@134
  2021
	}
danw@142
  2022
	return NULL;
danw@142
  2023
}
danw@142
  2024
danw@142
  2025
static struct razor_package *
krh@191
  2026
find_installed_package_for_file(struct razor_transaction *trans,
danw@144
  2027
				const char *filename)
danw@142
  2028
{
danw@144
  2029
	struct razor_package *pkg;
danw@144
  2030
danw@144
  2031
	pkg = find_package_for_file(trans->system, &trans->syspkgs,
danw@144
  2032
				    filename, 1);
danw@144
  2033
	if (!pkg)
danw@144
  2034
		pkg = find_package_for_file(trans->upstream, &trans->uppkgs,
danw@144
  2035
					    filename, 1);
danw@144
  2036
	return pkg;
danw@142
  2037
}
danw@142
  2038
danw@142
  2039
static struct razor_package *
krh@191
  2040
find_uninstalled_package_for_file(struct razor_transaction *trans,
danw@144
  2041
				  const char *filename)
danw@142
  2042
{
danw@144
  2043
	struct razor_package *pkg;
danw@144
  2044
danw@144
  2045
	pkg = find_package_for_file(trans->upstream, &trans->uppkgs,
danw@144
  2046
				    filename, 0);
danw@144
  2047
	if (!pkg)
danw@144
  2048
		pkg = find_package_for_file(trans->system, &trans->syspkgs,
danw@144
  2049
					    filename, 0);
danw@144
  2050
	return pkg;
danw@134
  2051
}
danw@134
  2052
danw@154
  2053
static struct razor_property *
krh@191
  2054
skip_to_matching_property(struct razor_transaction *trans,
danw@154
  2055
			  struct razor_property *match,
danw@154
  2056
			  struct razor_property *prop)
danw@154
  2057
{
danw@154
  2058
	struct razor_set *mset, *pset;
danw@154
  2059
	const char *ppool, *mpool;
danw@154
  2060
	struct razor_property *prop_end;
danw@154
  2061
danw@154
  2062
	if (property_in_set(match, trans->system))
danw@154
  2063
		mset = trans->system;
danw@154
  2064
	else
danw@154
  2065
		mset = trans->upstream;
danw@154
  2066
danw@154
  2067
	if (property_in_set(prop, trans->system))
danw@154
  2068
		pset = trans->system;
danw@154
  2069
	else if (property_in_set(prop, trans->upstream))
danw@154
  2070
		pset = trans->upstream;
danw@154
  2071
	else
danw@154
  2072
		return prop;
danw@154
  2073
danw@154
  2074
	prop_end = pset->properties.data + pset->properties.size;
danw@154
  2075
	ppool = pset->string_pool.data;
danw@154
  2076
	mpool = mset->string_pool.data;
danw@154
  2077
danw@154
  2078
	while (prop < prop_end &&
danw@154
  2079
	       strcmp(&ppool[prop->name], &mpool[match->name]) < 0)
danw@154
  2080
		prop++;
danw@154
  2081
	return prop;
danw@154
  2082
}
danw@154
  2083
danw@140
  2084
static struct razor_package *
krh@191
  2085
find_package_matching(struct razor_transaction *trans, int installed,
danw@154
  2086
		      struct razor_property *prop,
danw@144
  2087
		      struct razor_property *req,
danw@144
  2088
		      struct razor_set *req_set)
danw@138
  2089
{
danw@144
  2090
	struct razor_set *set;
danw@144
  2091
	struct bitarray *pkgbits;
danw@144
  2092
	struct razor_package *pkgs;
danw@154
  2093
	struct razor_property *props, *prop_end;
danw@144
  2094
	enum razor_property_type match_type;
danw@144
  2095
	const char *pool;
danw@154
  2096
	const char *rpool;
danw@154
  2097
	int match_name = (req->type == RAZOR_PROPERTY_OBSOLETES);
danw@144
  2098
	int match;
danw@144
  2099
danw@144
  2100
	if (property_in_set(prop, trans->system)) {
danw@144
  2101
		set = trans->system;
danw@144
  2102
		pkgbits = &trans->syspkgs;
danw@144
  2103
	} else if (property_in_set(prop, trans->upstream)) {
danw@144
  2104
		set = trans->upstream;
danw@144
  2105
		pkgbits = &trans->uppkgs;
danw@144
  2106
	} else
danw@144
  2107
		return NULL;
danw@144
  2108
danw@154
  2109
	if (!req_set) {
danw@154
  2110
		if (property_in_set(req, trans->system))
danw@154
  2111
			req_set = trans->system;
danw@154
  2112
		else
danw@154
  2113
			req_set = trans->upstream;
danw@154
  2114
	}
danw@154
  2115
	rpool = req_set->string_pool.data;
danw@154
  2116
danw@144
  2117
	if (req->type == RAZOR_PROPERTY_PROVIDES)
danw@144
  2118
		match_type = RAZOR_PROPERTY_CONFLICTS;
danw@144
  2119
	else
danw@144
  2120
		match_type = RAZOR_PROPERTY_PROVIDES;
danw@144
  2121
danw@144
  2122
	pkgs = set->packages.data;
danw@144
  2123
	props = set->properties.data;
danw@144
  2124
	prop_end = set->properties.data + set->properties.size;
danw@144
  2125
	pool = set->string_pool.data;
danw@144
  2126
danw@144
  2127
	/* Find first matching property */
danw@144
  2128
	while (prop < prop_end &&
danw@144
  2129
	       strcmp(&pool[prop->name], &rpool[req->name]) < 0)
danw@144
  2130
		prop++;
danw@144
  2131
	if (prop == prop_end ||
danw@144
  2132
	    strcmp(&pool[prop->name], &rpool[req->name]) > 0)
danw@144
  2133
		return NULL;
danw@144
  2134
danw@144
  2135
	if (prop->type < match_type) {
danw@144
  2136
		while (prop < prop_end && prop->type != match_type)
danw@144
  2137
			prop++;
danw@144
  2138
	} else {
danw@144
  2139
		while (prop >= props && prop->type != match_type)
danw@144
  2140
			prop--;
danw@183
  2141
		while (prop > props + 1 && (prop - 1)->name == prop->name &&
danw@183
  2142
		       (prop - 1)->type == match_type)
danw@144
  2143
			prop--;
danw@144
  2144
	}
danw@144
  2145
danw@153
  2146
	/* Scan matching properties */
danw@144
  2147
	while (prop < prop_end && prop->type == match_type &&
danw@144
  2148
	       strcmp(&pool[prop->name], &rpool[req->name]) == 0) {
danw@144
  2149
		if (match_type == RAZOR_PROPERTY_PROVIDES)
danw@144
  2150
			match = provider_satisfies_requirement(prop, pool, req, rpool);
danw@144
  2151
		else
danw@144
  2152
			match = provider_satisfies_requirement(req, rpool, prop, pool);
danw@144
  2153
		if (match) {
danw@140
  2154
			struct list *pkg;
danw@140
  2155
danw@144
  2156
			for (pkg = list_first(&prop->packages, &set->package_pool); pkg; pkg = list_next(pkg)) {
danw@144
  2157
				if (bitarray_get(pkgbits, pkg->data) != installed)
danw@140
  2158
					continue;
danw@140
  2159
				if (!match_name ||
danw@144
  2160
				    strcmp(&pool[pkgs[pkg->data].name],
danw@144
  2161
					   &rpool[req->name]) == 0)
danw@144
  2162
					return &pkgs[pkg->data];
danw@140
  2163
			}
danw@140
  2164
		}
danw@144
  2165
		prop++;
danw@140
  2166
	}
danw@140
  2167
danw@140
  2168
	return NULL;
danw@138
  2169
}
danw@138
  2170
danw@140
  2171
static struct razor_package *
krh@191
  2172
find_installed_package_for_property(struct razor_transaction *trans,
danw@154
  2173
				    struct razor_property *sys_start,
danw@154
  2174
				    struct razor_property *up_start,
danw@144
  2175
				    struct razor_property *req)
danw@138
  2176
{
danw@144
  2177
	struct razor_package *pkg;
danw@144
  2178
danw@154
  2179
	pkg = find_package_matching(trans, 1, sys_start, req, NULL);
danw@144
  2180
	if (!pkg)
danw@154
  2181
		pkg = find_package_matching(trans, 1, up_start, req, NULL);
danw@144
  2182
	return pkg;
danw@144
  2183
}
danw@144
  2184
danw@144
  2185
static struct razor_package *
krh@191
  2186
find_uninstalled_package_for_property(struct razor_transaction *trans,
danw@154
  2187
				      struct razor_property *sys_start,
danw@154
  2188
				      struct razor_property *up_start,
danw@144
  2189
				      struct razor_property *req)
danw@144
  2190
{
danw@144
  2191
	struct razor_package *pkg;
danw@144
  2192
danw@154
  2193
	pkg = find_package_matching(trans, 0, up_start, req, NULL);
danw@144
  2194
	if (!pkg)
danw@154
  2195
		pkg = find_package_matching(trans, 0, sys_start, req, NULL);
danw@144
  2196
	return pkg;
danw@140
  2197
}
danw@140
  2198
danw@147
  2199
static struct razor_transaction_package *
krh@191
  2200
find_transaction_package(struct razor_transaction *trans, const char *name)
danw@147
  2201
{
danw@147
  2202
	struct razor_transaction_package *packages;
danw@147
  2203
	int count, i;
danw@147
  2204
danw@147
  2205
	packages = trans->packages.data;
danw@147
  2206
	count = trans->packages.size / sizeof *packages;
danw@147
  2207
	for (i = 0; i < count; i++) {
danw@147
  2208
		if (packages[i].name && !strcmp(packages[i].name, name))
danw@147
  2209
			return &packages[i];
danw@147
  2210
	}
danw@147
  2211
	return NULL;
danw@147
  2212
}
danw@147
  2213
danw@160
  2214
/* FIXME? */
danw@160
  2215
static int
krh@191
  2216
prop_is_being_installed(struct razor_transaction *trans,
danw@160
  2217
			struct razor_property *prop)
danw@160
  2218
{
danw@160
  2219
	struct list *pkg;
danw@160
  2220
danw@160
  2221
	for (pkg = list_first(&prop->packages, &trans->upstream->package_pool); pkg; pkg = list_next(pkg)) {
danw@160
  2222
		if (bitarray_get(&trans->uppkgs, pkg->data))
danw@160
  2223
			return 1;
danw@160
  2224
	}
danw@160
  2225
	return 0;
danw@160
  2226
}
danw@160
  2227
danw@160
  2228
static int
krh@191
  2229
prop_is_being_removed(struct razor_transaction *trans,
danw@160
  2230
		      struct razor_property *prop)
danw@160
  2231
{
danw@160
  2232
	struct list *pkg;
danw@160
  2233
danw@160
  2234
	for (pkg = list_first(&prop->packages, &trans->system->package_pool); pkg; pkg = list_next(pkg)) {
danw@160
  2235
		if (bitarray_get(&trans->syspkgs, pkg->data))
danw@160
  2236
			return 0;
danw@160
  2237
	}
danw@160
  2238
	return 1;
danw@160
  2239
}
danw@160
  2240
danw@160
  2241
static int
krh@191
  2242
prop_is_being_updated(struct razor_transaction *trans,
danw@160
  2243
		      struct razor_property *prop)
danw@160
  2244
{
danw@160
  2245
	struct razor_package *packages = trans->system->packages.data;
danw@160
  2246
	const char *pool = trans->system->string_pool.data;
danw@160
  2247
	struct razor_transaction_package *tp;
danw@160
  2248
	struct list *pkg;
danw@160
  2249
danw@160
  2250
	/* Assumes prop_is_being_removed returns true */
danw@160
  2251
danw@160
  2252
	for (pkg = list_first(&prop->packages, &trans->system->package_pool); pkg; pkg = list_next(pkg)) {
danw@160
  2253
		tp = find_transaction_package(trans, &pool[packages[pkg->data].name]);
danw@160
  2254
		if (tp && tp->state == RAZOR_PACKAGE_REMOVE)
danw@160
  2255
			return 0;
danw@160
  2256
	}
danw@160
  2257
	return 1;
danw@160
  2258
}
danw@160
  2259
danw@131
  2260
static void
krh@191
  2261
add_transaction_package(struct razor_transaction *trans,
danw@147
  2262
			struct razor_package *new_package,
danw@147
  2263
			struct razor_package *old_package,
danw@140
  2264
			enum razor_transaction_package_state state,
danw@144
  2265
			const char *req_package,
danw@144
  2266
			struct razor_property *req_prop)
danw@131
  2267
{
danw@147
  2268
	struct razor_set *new_package_set, *old_package_set, *req_set;
danw@160
  2269
	struct bitarray *reqpkgbits;
danw@147
  2270
	struct razor_transaction_package *tp, *already;
danw@140
  2271
	const char *pool;
danw@140
  2272
	struct razor_package *pkgs;
danw@140
  2273
	struct list *pkg;
danw@147
  2274
	int contradiction = 0;
danw@147
  2275
danw@160
  2276
	if (package_in_set(new_package, trans->system))
danw@147
  2277
		new_package_set = trans->system;
danw@160
  2278
	else
danw@147
  2279
		new_package_set = trans->upstream;
danw@160
  2280
	if (package_in_set(old_package, trans->system))
danw@147
  2281
		old_package_set = trans->system;
danw@160
  2282
	else
danw@147
  2283
		old_package_set = trans->upstream;
danw@145
  2284
	if (property_in_set(req_prop, trans->system)) {
danw@145
  2285
		req_set = trans->system;
danw@145
  2286
		reqpkgbits = &trans->syspkgs;
danw@145
  2287
	} else {
danw@145
  2288
		req_set = trans->upstream;
danw@145
  2289
		reqpkgbits = &trans->uppkgs;
danw@145
  2290
	}
danw@144
  2291
danw@147
  2292
	if (new_package) {
danw@147
  2293
		pool = new_package_set->string_pool.data;
danw@147
  2294
		already = find_transaction_package(trans, &pool[new_package->name]);
danw@147
  2295
		if (already) {
danw@147
  2296
			if (already->new_package == new_package) {
danw@147
  2297
				/* Already taken care of */
danw@147
  2298
				return;
danw@166
  2299
			} else if (new_package_set == trans->upstream &&
danw@166
  2300
				   already->state == RAZOR_PACKAGE_FORCED_UPDATE) {
danw@166
  2301
				already->new_package = new_package;
danw@166
  2302
				return;
krh@209
  2303
			} else if (new_package_set == trans->upstream) {
krh@209
  2304
				return;
danw@147
  2305
			}
danw@166
  2306
danw@147
  2307
			/* Oops. We lose */
danw@147
  2308
			if (state != RAZOR_PACKAGE_CONTRADICTION)
danw@147
  2309
				contradiction = 1;
danw@147
  2310
		}
danw@147
  2311
	} else if (old_package) {
danw@147
  2312
		pool = old_package_set->string_pool.data;
danw@147
  2313
		already = find_transaction_package(trans, &pool[old_package->name]);
danw@147
  2314
		if (already) {
danw@147
  2315
			if (already->old_package == old_package) {
danw@147
  2316
				/* Already taken care of */
danw@147
  2317
				return;
danw@166
  2318
			} else if (old_package_set == trans->system) {
danw@166
  2319
				already->old_package = old_package;
danw@166
  2320
				return;
danw@147
  2321
			}
danw@166
  2322
danw@147
  2323
			/* Oops. We lose */
danw@147
  2324
			if (state != RAZOR_PACKAGE_CONTRADICTION)
danw@147
  2325
				contradiction = 1;
danw@147
  2326
		}
danw@147
  2327
	} else
danw@147
  2328
		state = RAZOR_PACKAGE_UNSATISFIABLE;
danw@147
  2329
danw@141
  2330
	tp = array_add(&trans->packages, sizeof *tp);
danw@140
  2331
	memset(tp, 0, sizeof *tp);
danw@131
  2332
danw@147
  2333
	if (new_package) {
danw@147
  2334
		pool = new_package_set->string_pool.data;
danw@147
  2335
		tp->new_package = new_package;
danw@147
  2336
		tp->name = &pool[new_package->name];
danw@147
  2337
		tp->new_version = &pool[new_package->version];
danw@147
  2338
danw@147
  2339
		pkgs = new_package_set->packages.data;
danw@147
  2340
	}
danw@147
  2341
	if (old_package) {
danw@147
  2342
		pool = old_package_set->string_pool.data;
danw@147
  2343
		tp->old_package = old_package;
danw@147
  2344
		tp->name = &pool[old_package->name];
danw@147
  2345
		tp->old_version = &pool[old_package->version];
danw@147
  2346
danw@147
  2347
		pkgs = old_package_set->packages.data;
danw@147
  2348
	}
danw@147
  2349
danw@147
  2350
	tp->state = state;
danw@147
  2351
	if (state != RAZOR_PACKAGE_INSTALL &&
danw@154
  2352
	    state != RAZOR_PACKAGE_FORCED_UPDATE &&
danw@154
  2353
	    state != RAZOR_PACKAGE_REMOVE &&
danw@154
  2354
	    state != RAZOR_PACKAGE_OBSOLETED)
danw@145
  2355
		trans->errors++;
danw@147
  2356
danw@147
  2357
	if (contradiction) {
danw@147
  2358
		/* Do this now, after adding tp, so that it ends up
danw@147
  2359
		 * after both the INSTALL and the REMOVE in the array.
danw@147
  2360
		 */
danw@147
  2361
		add_transaction_package(trans, new_package, old_package,
danw@147
  2362
					RAZOR_PACKAGE_CONTRADICTION,
danw@147
  2363
					NULL, NULL);
danw@145
  2364
	}
danw@140
  2365
danw@144
  2366
	if (req_package)
danw@145
  2367
		tp->dep_package = req_package;
danw@145
  2368
	if (!req_prop)
danw@145
  2369
		return;
danw@145
  2370
danw@145
  2371
	pool = req_set->string_pool.data;
danw@145
  2372
	pkgs = req_set->packages.data;
danw@145
  2373
	if (!req_package) {
danw@145
  2374
		for (pkg = list_first(&req_prop->packages, &req_set->package_pool); pkg; pkg = list_next(pkg)) {
danw@145
  2375
			if (bitarray_get(reqpkgbits, pkg->data))
danw@144
  2376
				break;
danw@144
  2377
		}
danw@145
  2378
		if (pkg)
danw@145
  2379
			tp->dep_package = &pool[pkgs[pkg->data].name];
danw@131
  2380
	}
danw@144
  2381
danw@145
  2382
	tp->dep_type = req_prop->type;
danw@145
  2383
	tp->dep_property = &pool[req_prop->name];
danw@145
  2384
	tp->dep_relation = req_prop->relation;
danw@145
  2385
	tp->dep_version = &pool[req_prop->version];
danw@140
  2386
}
danw@140
  2387
danw@160
  2388
static void
krh@191
  2389
razor_transaction_satisfy(struct razor_transaction *trans)
danw@147
  2390
{
danw@160
  2391
	struct razor_package *spkgs, *upkgs, *pkg;
danw@144
  2392
	struct razor_property *sp, *sprops, *sprop_end;
danw@144
  2393
	struct razor_property *up, *uprops, *uprop_end;
danw@160
  2394
	struct razor_property *sr, *ur, *first_up;
danw@160
  2395
	const char *spool, *upool, *removed_package;
danw@160
  2396
	struct list *reqpkg;
danw@134
  2397
danw@140
  2398
	spkgs = trans->system->packages.data;
danw@140
  2399
	sprops = trans->system->properties.data;
danw@144
  2400
	sprop_end = trans->system->properties.data + trans->system->properties.size;
danw@145
  2401
	spool = trans->system->string_pool.data;
danw@140
  2402
	upkgs = trans->upstream->packages.data;
danw@140
  2403
	uprops = trans->upstream->properties.data;
danw@144
  2404
	uprop_end = trans->upstream->properties.data + trans->upstream->properties.size;
danw@140
  2405
	upool = trans->upstream->string_pool.data;
krh@33
  2406
danw@144
  2407
	sp = sprops;
danw@160
  2408
	for (up = uprops; up < uprop_end; up++) {
danw@140
  2409
		/* Skip 'up' ahead to a property of a package which is
danw@140
  2410
		 * to-be-installed.
danw@140
  2411
		 */
danw@144
  2412
		while (up < uprop_end &&
danw@144
  2413
		       !prop_is_being_installed(trans, up))
danw@140
  2414
			up++;
danw@144
  2415
		if (up == uprop_end)
danw@140
  2416
			break;
danw@154
  2417
		sp = skip_to_matching_property(trans, up, sp);
krh@33
  2418
danw@144
  2419
		switch (up->type) {
danw@140
  2420
		case RAZOR_PROPERTY_REQUIRES:
danw@144
  2421
			if (!strncmp(&upool[up->name], "rpmlib(", 7))
danw@140
  2422
				break;
danw@131
  2423
danw@154
  2424
			if (find_installed_package_for_property(trans, sp, up, up) ||
danw@144
  2425
			    find_installed_package_for_file(trans, &upool[up->name])) {
danw@140
  2426
				/* Requires something that is either installed
danw@140
  2427
				 * or to-be-installed.
danw@140
  2428
				 */
danw@140
  2429
				break;
danw@137
  2430
			}
danw@137
  2431
danw@140
  2432
			/* See if we can install a new upstream provider */
danw@154
  2433
			pkg = find_uninstalled_package_for_property(trans, sp, up, up);
danw@154
  2434
			if (!pkg)
danw@144
  2435
				pkg = find_uninstalled_package_for_file(trans, &upool[up->name]);
danw@160
  2436
			add_transaction_package(trans, pkg, NULL,
danw@144
  2437
						RAZOR_PACKAGE_INSTALL,
danw@144
  2438
						NULL, up);
danw@144
  2439
			break;
danw@144
  2440
danw@144
  2441
		case RAZOR_PROPERTY_PROVIDES:
danw@144
  2442
			/* find_installed_package_for_property works backwards
danw@144
  2443
			 * here, finding a *conflicting* installed package.
danw@144
  2444
			 */
danw@154
  2445
			pkg = find_installed_package_for_property(trans, sp, up, up);
danw@140
  2446
			if (!pkg)
danw@144
  2447
				break;
danw@144
  2448
danw@145
  2449
			if (package_in_set(pkg, trans->system)) {
danw@145
  2450
				/* pkg CONFLICTS with what 'up' PROVIDES. Try
danw@145
  2451
				 * finding an upgrade
danw@145
  2452
				 */
danw@160
  2453
				add_transaction_package(trans, NULL, pkg,
danw@160
  2454
							RAZOR_PACKAGE_FORCED_UPDATE,
danw@165
  2455
							&upool[up->name], sp);
danw@160
  2456
			} else {
danw@160
  2457
				add_transaction_package(trans, NULL, pkg,
danw@160
  2458
							RAZOR_PACKAGE_CONTRADICTION,
danw@160
  2459
							NULL, up);
danw@144
  2460
			}
danw@140
  2461
			break;
danw@140
  2462
danw@140
  2463
		case RAZOR_PROPERTY_CONFLICTS:
danw@154
  2464
			pkg = find_installed_package_for_property(trans, sp, up, up);
danw@144
  2465
			if (!pkg)
danw@144
  2466
				break;
danw@144
  2467
danw@144
  2468
			if (package_in_set(pkg, trans->system)) {
danw@140
  2469
				/* Conflicts with something already installed.
danw@140
  2470
				 * Try to upgrade out.
danw@140
  2471
				 */
danw@160
  2472
				add_transaction_package(trans, NULL, pkg,
danw@160
  2473
							RAZOR_PACKAGE_FORCED_UPDATE,
danw@160
  2474
							NULL, up);
danw@160
  2475
			} else {
danw@160
  2476
				add_transaction_package(trans, pkg, NULL,
danw@160
  2477
							RAZOR_PACKAGE_CONTRADICTION,
danw@160
  2478
							NULL, up);
danw@140
  2479
			}
danw@140
  2480
			break;
danw@140
  2481
danw@140
  2482
		case RAZOR_PROPERTY_OBSOLETES:
danw@154
  2483
			pkg = find_installed_package_for_property(trans, sp, up, up);
danw@145
  2484
			if (pkg) {
danw@145
  2485
				/* If pkg is to-be-installed, this
danw@145
  2486
				 * will add a CONTRADICTION error as well.
danw@145
  2487
				 */
danw@147
  2488
				add_transaction_package(trans, NULL, pkg,
danw@154
  2489
							RAZOR_PACKAGE_OBSOLETED,
danw@144
  2490
							NULL, up);
danw@140
  2491
			}
danw@140
  2492
			break;
danw@140
  2493
danw@140
  2494
		default:
danw@140
  2495
			/* can't happen */
danw@140
  2496
			break;
danw@131
  2497
		}
krh@37
  2498
	}
danw@154
  2499
danw@154
  2500
	up = uprops;
danw@154
  2501
	for (sp = sprops; sp < sprop_end; sp++) {
danw@154
  2502
		/* Skip 'sp' ahead to a PROVIDES of a package which is
danw@154
  2503
		 * to-be-removed.
danw@154
  2504
		 */
danw@154
  2505
		while (sp < sprop_end &&
danw@154
  2506
		       (sp->type != RAZOR_PROPERTY_PROVIDES ||
danw@154
  2507
			!prop_is_being_removed(trans, sp)))
danw@154
  2508
			sp++;
danw@154
  2509
		if (sp == sprop_end)
danw@154
  2510
			break;
danw@154
  2511
danw@154
  2512
		removed_package = &spool[spkgs[list_first(&sp->packages, &trans->system->package_pool)->data].name];
danw@154
  2513
danw@154
  2514
		/* Skip 'up' to match */
danw@154
  2515
		up = skip_to_matching_property(trans, sp, up);
danw@154
  2516
		ur = first_up = up;
danw@154
  2517
danw@154
  2518
		/* If the package is just being upgraded, we may
danw@154
  2519
		 * already be installing an identical PROVIDES, so
danw@154
  2520
		 * check for that.
danw@154
  2521
		 */
danw@154
  2522
		while (up < uprop_end &&
danw@154
  2523
		       strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
danw@154
  2524
		       (up->type != RAZOR_PROPERTY_PROVIDES || 
danw@154
  2525
			sp->relation != up->relation ||
danw@154
  2526
			strcmp(&spool[sp->name], &upool[up->name]) != 0))
danw@154
  2527
			up++;
danw@154
  2528
		if (up < uprop_end &&
danw@154
  2529
		    up->type == RAZOR_PROPERTY_PROVIDES &&
danw@154
  2530
		    strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
danw@154
  2531
		    sp->relation == up->relation &&
danw@154
  2532
		    strcmp(&spool[sp->version], &upool[up->version]) == 0 &&
danw@154
  2533
		    prop_is_being_installed(trans, up)) {
danw@154
  2534
			up = first_up;
danw@154
  2535
			continue;
danw@154
  2536
		}
danw@154
  2537
		up = first_up;
danw@154
  2538
danw@154
  2539
		/* For all still-installed packages that require
danw@154
  2540
		 * sp->name, see if they are satisfied by any other
danw@154
  2541
		 * still-installed or to-be-installed property. If
danw@154
  2542
		 * not, either remove or attempt to update the
danw@154
  2543
		 * package, depending on why the required property has
danw@154
  2544
		 * disappeared
danw@154
  2545
		 */
danw@154
  2546
		sr = sp;
danw@154
  2547
		while (sr > sprops + 1 && (sr - 1)->name == sr->name)
danw@154
  2548
			sr--;
danw@154
  2549
		for (; sr->type == RAZOR_PROPERTY_REQUIRES; sr++) {
danw@154
  2550
			if (prop_is_being_removed(trans, sr))
danw@154
  2551
				continue;
danw@154
  2552
			if (find_installed_package_for_property(trans, sp, up, sr))
danw@154
  2553
				continue;
danw@154
  2554
danw@154
  2555
			for (reqpkg = list_first(&sr->packages, &trans->system->package_pool); reqpkg; reqpkg = list_next(reqpkg)) {
danw@154
  2556
				if (!bitarray_get(&trans->syspkgs, reqpkg->data))
danw@154
  2557
					continue;
danw@154
  2558
				pkg = &spkgs[reqpkg->data];
danw@154
  2559
				if (prop_is_being_updated(trans, sp)) {
danw@160
  2560
					add_transaction_package(trans, NULL, pkg,
danw@160
  2561
								RAZOR_PACKAGE_FORCED_UPDATE,
danw@160
  2562
								removed_package, NULL);
danw@154
  2563
				} else {
danw@154
  2564
					add_transaction_package(trans, NULL, pkg,
danw@154
  2565
								RAZOR_PACKAGE_REMOVE,
danw@154
  2566
								removed_package, sr);
danw@154
  2567
				}
danw@154
  2568
			}
danw@154
  2569
		}
danw@154
  2570
	}
danw@154
  2571
}
danw@129
  2572
krh@208
  2573
void
krh@208
  2574
razor_transaction_install_package(struct razor_transaction *transaction,
krh@208
  2575
				  struct razor_package *package)
krh@208
  2576
{
krh@208
  2577
	add_transaction_package(transaction, package, NULL,
krh@208
  2578
				RAZOR_PACKAGE_INSTALL, NULL, NULL);
krh@208
  2579
}
krh@208
  2580
krh@208
  2581
void
krh@208
  2582
razor_transaction_remove_package(struct razor_transaction *transaction,
krh@208
  2583
				 struct razor_package *package)
krh@208
  2584
{
krh@208
  2585
	add_transaction_package(transaction, NULL, package,
krh@208
  2586
				RAZOR_PACKAGE_REMOVE, NULL, NULL);
krh@208
  2587
}
krh@208
  2588
krh@208
  2589
void
krh@208
  2590
razor_transaction_update_all(struct razor_transaction *trans)
krh@208
  2591
{
krh@208
  2592
	struct razor_package *sp, *spkgs, *send, *up, *upkgs, *uend;
krh@208
  2593
	const char *spool, *upool;
krh@208
  2594
krh@208
  2595
	spkgs = trans->system->packages.data;
krh@208
  2596
	send = trans->system->packages.data + trans->system->packages.size;
krh@208
  2597
	spool = trans->system->string_pool.data;
krh@208
  2598
	up = upkgs = trans->upstream->packages.data;
krh@208
  2599
	uend = trans->upstream->packages.data + trans->upstream->packages.size;
krh@208
  2600
	upool = trans->upstream->string_pool.data;
krh@208
  2601
krh@208
  2602
	for (sp = spkgs; sp < send; sp++) {
krh@208
  2603
		while (up < uend && strcmp(&spool[sp->name], &upool[up->name]) > 0)
krh@208
  2604
			up++;
krh@208
  2605
		if (strcmp(&spool[sp->name], &upool[up->name]) == 0 &&
krh@208
  2606
		    versioncmp(&spool[sp->version], &upool[up->version]) < 0) {
krh@208
  2607
			add_transaction_package(trans, up, sp,
krh@208
  2608
						RAZOR_PACKAGE_INSTALL,
krh@208
  2609
						NULL, NULL);
krh@208
  2610
		}
krh@208
  2611
	}
krh@208
  2612
}
krh@208
  2613
danw@137
  2614
struct razor_transaction *
krh@208
  2615
razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
danw@137
  2616
{
krh@191
  2617
	struct razor_transaction *trans;
krh@208
  2618
	int count;
danw@137
  2619
krh@191
  2620
	trans = zalloc(sizeof *trans);
krh@191
  2621
krh@191
  2622
	trans->system = system;
krh@191
  2623
	trans->upstream = upstream ? upstream : razor_set_create();
krh@191
  2624
	array_init(&trans->packages);
krh@208
  2625
	count = trans->system->packages.size / sizeof (struct razor_package);
krh@208
  2626
	bitarray_init(&trans->syspkgs, count, 1);
krh@208
  2627
	count = trans->upstream->packages.size / sizeof (struct razor_package);
krh@208
  2628
	bitarray_init(&trans->uppkgs, count, 0);
krh@208
  2629
krh@208
  2630
	return trans;
krh@208
  2631
}
krh@208
  2632
krh@208
  2633
static void
krh@208
  2634
resolve_transaction(struct razor_transaction *trans)
krh@208
  2635
{
krh@208
  2636
	int start, end;
krh@208
  2637
krh@208
  2638
	if (trans->package_count > 0)
krh@208
  2639
		/* Already did this, return. */
krh@208
  2640
		return;
danw@137
  2641
danw@137
  2642
	start = 0;
krh@191
  2643
	end = trans->packages.size / sizeof (struct razor_transaction_package);
danw@137
  2644
danw@160
  2645
	while (start != end) {
krh@191
  2646
		resolve_new_packages(trans, start, end);
krh@191
  2647
		if (trans->errors)
danw@160
  2648
			break;
danw@160
  2649
krh@191
  2650
		razor_transaction_satisfy(trans);
danw@137
  2651
danw@137
  2652
		start = end;
krh@191
  2653
		end = trans->packages.size / sizeof (struct razor_transaction_package);
danw@137
  2654
	}
danw@137
  2655
krh@191
  2656
	trans->package_count = end;
danw@137
  2657
}
danw@137
  2658
danw@137
  2659
const char * const razor_version_relations[] = {
danw@137
  2660
	/* same order as enum razor_version_relation */
danw@137
  2661
	"<", "<=", "=", ">=", ">"
danw@137
  2662
};
danw@137
  2663
danw@140
  2664
const char * const razor_property_types[] = {
danw@140
  2665
	/* same order as enum razor_property_type */
danw@140
  2666
	"requires", "provides", "conflicts with", "obsoletes"
danw@140
  2667
};
danw@140
  2668
danw@169
  2669
static void
danw@169
  2670
print_requirement(struct razor_transaction_package *p)
danw@169
  2671
{
danw@169
  2672
	if (p->dep_type == RAZOR_PROPERTY_CONFLICTS &&
danw@169
  2673
	    !strcmp(p->dep_package, p->name)) {
danw@169
  2674
		printf(" because %s %s conflicts with %s",
danw@169
  2675
		       p->name, p->old_version, p->dep_property);
danw@169
  2676
		if (*p->dep_version) {
danw@169
  2677
			printf(" %s %s",
danw@169
  2678
			       razor_version_relations[p->dep_relation],
danw@169
  2679
			       p->dep_version);
danw@169
  2680
		}
danw@169
  2681
	} else {
danw@169
  2682
		if (strcmp(p->name, p->dep_package) != 0)
danw@169
  2683
			printf(" for %s", p->dep_package);
danw@169
  2684
		if (*p->dep_version) {
danw@169
  2685
			printf(", which %s %s %s %s",
danw@169
  2686
			       razor_property_types[p->dep_type],
danw@169
  2687
			       p->dep_property,
danw@169
  2688
			       razor_version_relations[p->dep_relation],
danw@169
  2689
			       p->dep_version);
danw@169
  2690
		} else if (strcmp(p->dep_property, p->name) != 0) {
danw@169
  2691
			printf(", which %s %s",
danw@169
  2692
			       razor_property_types[p->dep_type],
danw@169
  2693
			       p->dep_property);
danw@169
  2694
		}
danw@169
  2695
	}
danw@169
  2696
}
danw@169
  2697
krh@190
  2698
int
krh@210
  2699
razor_transaction_resolve(struct razor_transaction *trans)
danw@137
  2700
{
danw@137
  2701
	struct razor_transaction_package *p, *pend, *tps;
danw@137
  2702
	int errors_only = 0;
danw@137
  2703
krh@208
  2704
	resolve_transaction(trans);
krh@208
  2705
krh@191
  2706
	tps = trans->packages.data;
krh@191
  2707
	pend = trans->packages.data + trans->packages.size;
krh@191
  2708
	for (p = trans->packages.data; p < pend; p++) {
danw@137
  2709
		switch (p->state) {
danw@137
  2710
		case RAZOR_PACKAGE_INSTALL:
danw@137
  2711
			if (errors_only)
danw@137
  2712
				break;
danw@137
  2713
danw@147
  2714
			printf("Installing %s %s", p->name, p->new_version);
danw@169
  2715
			if (p->dep_package)
danw@169
  2716
				print_requirement(p);
danw@137
  2717
			printf("\n");
danw@137
  2718
			break;
danw@137
  2719
danw@154
  2720
		case RAZOR_PACKAGE_FORCED_UPDATE:
danw@154
  2721
			if (errors_only)
danw@154
  2722
				break;
danw@154
  2723
danw@154
  2724
			printf("Updating %s to %s due to update of %s\n",
danw@154
  2725
			       p->name, p->new_version, p->dep_package);
danw@154
  2726
			break;
danw@154
  2727
danw@137
  2728
		case RAZOR_PACKAGE_REMOVE:
danw@137
  2729
			if (errors_only)
danw@137
  2730
				break;
danw@147
  2731
			printf("Removing %s %s", p->name, p->old_version);
danw@145
  2732
			if (p->dep_package) {
danw@154
  2733
				printf(" which required %s",
danw@154
  2734
				       p->dep_package);
danw@162
  2735
				if (strcmp(p->dep_property, p->dep_package) != 0)
danw@154
  2736
					printf(" for %s", p->dep_property);
danw@154
  2737
			}
danw@154
  2738
			printf("\n");
danw@154
  2739
			break;
danw@154
  2740
danw@154
  2741
		case RAZOR_PACKAGE_OBSOLETED:
danw@154
  2742
			if (errors_only)
danw@154
  2743
				break;
danw@154
  2744
			printf("Removing %s %s", p->name, p->old_version);
danw@154
  2745
			if (p->dep_package) {
danw@154
  2746
				printf(" which is obsoleted by %s",
danw@154
  2747
				       p->dep_package);
danw@137
  2748
			}
danw@137
  2749
			printf("\n");
danw@137
  2750
			break;
danw@137
  2751
danw@145
  2752
		case RAZOR_PACKAGE_INSTALL_UNAVAILABLE:
danw@169
  2753
			printf("Error: can't find %s", p->name);
danw@169
  2754
			if (p->dep_package) {
danw@169
  2755
				printf(" (which is required");
danw@169
  2756
				print_requirement(p);
danw@169
  2757
				printf(")");
danw@169
  2758
			}
danw@169
  2759
			printf("\n");
danw@169
  2760
			errors_only = 1;
danw@169
  2761
			break;
danw@169
  2762
danw@169
  2763
		case RAZOR_PACKAGE_UPDATE_UNAVAILABLE:
danw@169
  2764
			printf("Error: can't find an updated version of %s (which must be updated due to update of %s)\n",
danw@169
  2765
			       p->name, p->dep_package);
danw@137
  2766
			errors_only = 1;
danw@137
  2767
			break;
danw@137
  2768
danw@145
  2769
		case RAZOR_PACKAGE_REMOVE_NOT_INSTALLED:
danw@145
  2770
			printf("Error: can't remove %s: not installed\n", p->name);
danw@137
  2771
			errors_only = 1;
danw@137
  2772
			break;
danw@137
  2773
danw@145
  2774
		case RAZOR_PACKAGE_UP_TO_DATE:
danw@169
  2775
			printf("Error: can't update %s", p->name);
danw@169
  2776
			if (p->dep_package)
danw@169
  2777
				printf(" (which must be updated due to update of %s)", p->dep_package);
danw@169
  2778
			printf(": %s is most recent version\n", p->old_version);
danw@145
  2779
			errors_only = 1;
danw@145
  2780
			break;
danw@145
  2781
danw@145
  2782
		case RAZOR_PACKAGE_CONTRADICTION:
danw@147
  2783
			printf("Error: package %s is marked for both installation and removal\n", p->name);
danw@145
  2784
			errors_only = 1;
danw@145
  2785
			break;
danw@145
  2786
danw@145
  2787
		case RAZOR_PACKAGE_OLD_CONFLICT:
danw@145
  2788
			printf("Error: can't install %s, because installed package %s conflicts with ",
danw@145
  2789
			       p->name, p->dep_package);
danw@145
  2790
			if (*p->dep_version) {
danw@145
  2791
				printf("%s %s %s",
danw@145
  2792
				       p->dep_property,
danw@145
  2793
				       razor_version_relations[p->dep_relation],
danw@145
  2794
				       p->dep_version);
danw@145
  2795
			} else
danw@145
  2796
				printf("it");
danw@145
  2797
			printf("\n");
danw@145
  2798
danw@145
  2799
			errors_only = 1;
danw@145
  2800
			break;
danw@145
  2801
danw@145
  2802
		case RAZOR_PACKAGE_NEW_CONFLICT:
danw@145
  2803
			printf("Error: can't install %s, because it conflicts with %s",
danw@145
  2804
			       p->name, p->dep_package);
danw@145
  2805
			if (*p->dep_version) {
danw@145
  2806
				printf(" %s %s",
danw@145
  2807
				       razor_version_relations[p->dep_relation],
danw@145
  2808
				       p->dep_version);
danw@145
  2809
			}
danw@145
  2810
			printf("\n");
danw@145
  2811
danw@145
  2812
			errors_only = 1;
danw@145
  2813
			break;
danw@145
  2814
danw@145
  2815
		case RAZOR_PACKAGE_UNSATISFIABLE:
danw@145
  2816
			printf("Error: can't find package for %s", p->dep_property);
danw@145
  2817
			if (*p->dep_version) {
danw@145
  2818
				printf(" %s %s",
danw@145
  2819
					razor_version_relations[p->dep_relation],
danw@145
  2820
					p->dep_version);
danw@145
  2821
			}
danw@145
  2822
			printf(" which is required by %s\n",
danw@145
  2823
				p->dep_package);
danw@140
  2824
			errors_only = 1;
danw@140
  2825
			break;
danw@140
  2826
danw@137
  2827
		default:
danw@137
  2828
			/* Shouldn't actually happen */
danw@137
  2829
			break;
danw@137
  2830
		}
danw@137
  2831
	}
krh@190
  2832
krh@190
  2833
	return trans->errors;
krh@190
  2834
}
krh@190
  2835
krh@190
  2836
int
krh@190
  2837
razor_transaction_unsatisfied_property(struct razor_transaction *trans,
krh@190
  2838
				       const char *name,
krh@190
  2839
				       enum razor_version_relation rel,
krh@190
  2840
				       const char *version)
krh@190
  2841
{
krh@190
  2842
	struct razor_transaction_package *p, *end;
krh@190
  2843
krh@191
  2844
	end = trans->packages.data + trans->packages.size;
krh@191
  2845
	for (p = trans->packages.data; p < end; p++) {
krh@190
  2846
		if (p->state != RAZOR_PACKAGE_UNSATISFIABLE)
krh@190
  2847
			continue;
krh@190
  2848
		if (strcmp(name, p->dep_property) != 0 ||
krh@190
  2849
		    rel != p->dep_relation ||
krh@190
  2850
		    strcmp(version, p->dep_version) != 0)
krh@190
  2851
			continue;
krh@190
  2852
krh@190
  2853
		return 1;
krh@190
  2854
	}
krh@190
  2855
krh@190
  2856
	return 0;
danw@137
  2857
}
danw@137
  2858
danw@137
  2859
struct razor_set *
krh@196
  2860
razor_transaction_finish(struct razor_transaction *trans)
danw@137
  2861
{
danw@137
  2862
	struct array install_packages, remove_packages;
danw@137
  2863
	struct razor_merger *merger;
danw@137
  2864
	struct razor_package *pkg, *i, *iend, *r, *rend, *s, *send;
krh@196
  2865
	struct razor_set *set;
danw@137
  2866
	struct source *source1, *source2;
danw@137
  2867
	char *spool, *ipool, *rpool;
danw@137
  2868
	uint32_t *map;
krh@191
  2869
	struct razor_transaction_package *p, *end;
krh@191
  2870
	int cmp;
danw@137
  2871
danw@137
  2872
	/* FIXME */
danw@137
  2873
	if (trans->errors)
danw@137
  2874
		return NULL;
danw@137
  2875
danw@137
  2876
	/* Sort the transaction packages into two arrays */
danw@137
  2877
	array_init(&install_packages);
danw@137
  2878
	array_init(&remove_packages);
krh@191
  2879
krh@191
  2880
	end = trans->packages.data + trans->packages.size;
krh@191
  2881
	for (p = trans->packages.data; p < end; p++) {
krh@191
  2882
		if (p->new_package) {
danw@137
  2883
			pkg = array_add(&install_packages, sizeof *pkg);
krh@191
  2884
			*pkg = *p->new_package;
danw@147
  2885
		} else {
danw@137
  2886
			pkg = array_add(&remove_packages, sizeof *pkg);
krh@191
  2887
			*pkg = *p->old_package;
danw@147
  2888
		}
danw@137
  2889
	}
krh@186
  2890
	map = razor_qsort_with_data(install_packages.data,
krh@186
  2891
				    install_packages.size / sizeof *pkg,
krh@186
  2892
				    sizeof *pkg,
krh@186
  2893
				    compare_packages,
krh@186
  2894
				    trans->upstream);
danw@137
  2895
	free(map);
krh@186
  2896
	map = razor_qsort_with_data(remove_packages.data,
krh@186
  2897
				    remove_packages.size / sizeof *pkg,
krh@186
  2898
				    sizeof *pkg,
krh@186
  2899
				    compare_packages,
krh@186
  2900
				    trans->system);
danw@137
  2901
	free(map);
danw@137
  2902
danw@137
  2903
	merger = razor_merger_create(trans->system, trans->upstream);
danw@137
  2904
danw@137
  2905
	source1 = &merger->source1;
danw@137
  2906
	source2 = &merger->source2;
danw@137
  2907
danw@137
  2908
	i = install_packages.data;
danw@137
  2909
	iend = install_packages.data + install_packages.size;
danw@137
  2910
	ipool = trans->upstream->string_pool.data;
danw@137
  2911
danw@137
  2912
	r = remove_packages.data;
danw@137
  2913
	rend = remove_packages.data + remove_packages.size;
danw@137
  2914
	rpool = trans->system->string_pool.data;
danw@137
  2915
danw@137
  2916
	s = trans->system->packages.data;
danw@137
  2917
	send = trans->system->packages.data + trans->system->packages.size;
danw@137
  2918
	spool = trans->system->string_pool.data;
danw@137
  2919
danw@137
  2920
	while (s < send || i < iend) {
danw@137
  2921
		/* Check if s is being removed */
danw@137
  2922
		if (s < send && r < rend &&
danw@137
  2923
		    s->name == r->name && s->version && r->version) {
danw@137
  2924
			s++;
danw@137
  2925
			r++;
danw@137
  2926
			continue;
danw@137
  2927
		}
danw@137
  2928
danw@137
  2929
		if (s < send && i < iend)
danw@137
  2930
			cmp = strcmp(&spool[s->name], &ipool[i->name]);
danw@137
  2931
		else if (s < send)
danw@137
  2932
			cmp = -1;
danw@137
  2933
		else
danw@137
  2934
			cmp = 1;
danw@137
  2935
		if (cmp < 0) {
danw@137
  2936
			add_package(merger, s, source1, 0);
danw@137
  2937
			s++;
danw@137
  2938
		} else if (cmp == 0) {
danw@137
  2939
			add_package(merger, i, source2, UPSTREAM_SOURCE);
danw@137
  2940
			s++;
danw@137
  2941
			i++;
danw@137
  2942
		} else {
danw@137
  2943
			add_package(merger, i, source2, UPSTREAM_SOURCE);
danw@137
  2944
			i++;
danw@137
  2945
		}
danw@137
  2946
	}
danw@137
  2947
danw@137
  2948
	array_release(&install_packages);
danw@137
  2949
	array_release(&remove_packages);
danw@137
  2950
krh@196
  2951
	set = razor_merger_finish(merger);
krh@196
  2952
	razor_transaction_destroy(trans);
krh@196
  2953
krh@196
  2954
	return set;
danw@137
  2955
}
danw@137
  2956
danw@137
  2957
void
danw@137
  2958
razor_transaction_destroy(struct razor_transaction *trans)
danw@137
  2959
{
krh@191
  2960
	struct razor_transaction_package *p, *end;
krh@191
  2961
krh@191
  2962
	end = trans->packages.data + trans->packages.size;
krh@191
  2963
	for (p = trans->packages.data; p < end; p++) {
krh@191
  2964
		if (!p->dep_package &&
krh@191
  2965
		    (p->state == RAZOR_PACKAGE_INSTALL_UNAVAILABLE ||
krh@191
  2966
		     p->state == RAZOR_PACKAGE_REMOVE_NOT_INSTALLED))
krh@191
  2967
			free((char *)p->name);
danw@137
  2968
	}
krh@195
  2969
krh@195
  2970
	array_release(&trans->packages);
krh@195
  2971
	bitarray_release(&trans->syspkgs);
krh@195
  2972
	bitarray_release(&trans->uppkgs);
danw@137
  2973
	free(trans);
danw@137
  2974
danw@137
  2975
	/* FIXME: free upstream if it was created as an empty set */
danw@137
  2976
}