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