librazor/importer.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
parent 369 f8c27fe9fe63
child 438 fab0b8a61dcb
permissions -rw-r--r--
Add transaction barriers
These allow packages to be installed and removed which have scripts
that depend on each other when atomic transactions are involved.
Note that yum supports pre, but not other requires flags. post will
need similar support to the post scripts themselves pulling in the
requires flags from the rpms. Likewise preun and postun will need
similar handling to those scrips since the requires flags will need
to be stored in the razor database.
krh@248
     1
/*
krh@248
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
krh@248
     3
 * Copyright (C) 2008  Red Hat, Inc
ali@369
     4
 * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
krh@248
     5
 *
krh@248
     6
 * This program is free software; you can redistribute it and/or modify
krh@248
     7
 * it under the terms of the GNU General Public License as published by
krh@248
     8
 * the Free Software Foundation; either version 2 of the License, or
krh@248
     9
 * (at your option) any later version.
krh@248
    10
 *
krh@248
    11
 * This program is distributed in the hope that it will be useful,
krh@248
    12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
krh@248
    13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
krh@248
    14
 * GNU General Public License for more details.
krh@248
    15
 *
krh@248
    16
 * You should have received a copy of the GNU General Public License along
krh@248
    17
 * with this program; if not, write to the Free Software Foundation, Inc.,
krh@248
    18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
krh@248
    19
 */
krh@248
    20
krh@248
    21
#define _GNU_SOURCE
krh@248
    22
krh@248
    23
#include <string.h>
krh@248
    24
#include "razor-internal.h"
krh@248
    25
#include "razor.h"
krh@248
    26
krh@309
    27
/**
krh@309
    28
 * razor_importer_create:
krh@309
    29
 *
krh@309
    30
 * Create a new %razor_importer.
krh@309
    31
 *
krh@309
    32
 * Returns: the new %razor_importer.
krh@309
    33
 **/
krh@309
    34
RAZOR_EXPORT struct razor_importer *
krh@309
    35
razor_importer_create(void)
krh@309
    36
{
krh@309
    37
	struct razor_importer *importer;
krh@309
    38
krh@309
    39
	importer = zalloc(sizeof *importer);
krh@309
    40
	importer->set = razor_set_create();
krh@309
    41
	hashtable_init(&importer->table, &importer->set->string_pool);
krh@309
    42
	hashtable_init(&importer->details_table,
krh@309
    43
		       &importer->set->details_string_pool);
krh@309
    44
	hashtable_init(&importer->file_table,
krh@309
    45
		       &importer->set->file_string_pool);
krh@309
    46
krh@309
    47
	return importer;
krh@309
    48
}
krh@309
    49
krh@309
    50
/**
krh@309
    51
 * razor_importer_destroy:
krh@309
    52
 * @importer: the %razor_importer
krh@309
    53
 *
krh@309
    54
 * Destroy an importer without creating a %razor_set.  Normally,
krh@309
    55
 * %razor_importer_finish will create a new %razor_set and destroy the
krh@309
    56
 * importer.  If the import must be aborted without creating the set,
krh@309
    57
 * just destroy the import using this function.
krh@309
    58
 **/
krh@309
    59
RAZOR_EXPORT void
krh@309
    60
razor_importer_destroy(struct razor_importer *importer)
krh@309
    61
{
krh@309
    62
	/* FIXME: write this */
krh@309
    63
}
krh@309
    64
krh@309
    65
krh@309
    66
/**
krh@309
    67
 * razor_importer_begin_package:
krh@309
    68
 * @importer: the %razor_importer
krh@309
    69
 * @name: the name of the new package
krh@309
    70
 * @version: the version of the new package
krh@309
    71
 * @arch: the architechture of the new package.
krh@309
    72
 *
krh@309
    73
 * Begin describing a new package to the importer.  This creates a new
krh@309
    74
 * package and sets the %name, %version and %arch.  Subsequent calls
krh@309
    75
 * to %razor_importer_add_details, %razor_importer_add_property and
krh@309
    76
 * %razor_importer_add_file further describe this package and
krh@309
    77
 * %razor_importer_finish_package marks the end of meta data for this
krh@309
    78
 * package.
krh@309
    79
 **/
krh@269
    80
RAZOR_EXPORT void
krh@248
    81
razor_importer_begin_package(struct razor_importer *importer,
krh@248
    82
			     const char *name,
krh@248
    83
			     const char *version,
krh@248
    84
			     const char *arch)
krh@248
    85
{
ali@369
    86
	uint32_t empty;
krh@248
    87
	struct razor_package *p;
krh@248
    88
krh@248
    89
	p = array_add(&importer->set->packages, sizeof *p);
krh@248
    90
	p->name = hashtable_tokenize(&importer->table, name);
krh@248
    91
	p->flags = 0;
krh@248
    92
	p->version = hashtable_tokenize(&importer->table, version);
krh@248
    93
	p->arch = hashtable_tokenize(&importer->table, arch);
krh@248
    94
krh@248
    95
	importer->package = p;
krh@248
    96
	array_init(&importer->properties);
ali@372
    97
	array_init(&importer->install_prefixes);
ali@369
    98
ali@369
    99
	empty = hashtable_tokenize(&importer->details_table, "");
ali@369
   100
	importer->package->preun.program = empty;
ali@369
   101
	importer->package->preun.body = empty;
ali@369
   102
	importer->package->postun.program = empty;
ali@369
   103
	importer->package->postun.body = empty;
krh@248
   104
}
krh@248
   105
krh@309
   106
/**
krh@309
   107
 * razor_importer_finish_package:
krh@309
   108
 * @importer: the %razor_importer
krh@309
   109
 *
krh@309
   110
 * Tells the importer that the current package is complete.
krh@309
   111
 **/
krh@269
   112
RAZOR_EXPORT void
krh@248
   113
razor_importer_finish_package(struct razor_importer *importer)
krh@248
   114
{
krh@248
   115
	list_set_array(&importer->package->properties,
krh@248
   116
		       &importer->set->property_pool,
krh@248
   117
		       &importer->properties,
krh@248
   118
		       1);
krh@248
   119
ali@372
   120
	list_set_array(&importer->package->install_prefixes,
ali@372
   121
		       &importer->set->prefix_pool,
ali@372
   122
		       &importer->install_prefixes,
ali@372
   123
		       0);
ali@372
   124
krh@248
   125
	array_release(&importer->properties);
ali@372
   126
	array_release(&importer->install_prefixes);
krh@248
   127
}
krh@248
   128
krh@309
   129
/**
krh@309
   130
 * razor_importer_add_details:
krh@309
   131
 * @importer: the %razor_importer
krh@309
   132
 * @summary: the package summary
krh@309
   133
 * @description: the package description
krh@309
   134
 * @url: the package url
krh@309
   135
 * @license: the package license
krh@309
   136
 *
krh@309
   137
 * Provide additional information for the current package.
krh@309
   138
 **/
krh@269
   139
RAZOR_EXPORT void
jbowes@258
   140
razor_importer_add_details(struct razor_importer *importer,
jbowes@258
   141
			   const char *summary,
jbowes@258
   142
			   const char *description,
jbowes@258
   143
			   const char *url,
jbowes@258
   144
			   const char *license)
jbowes@258
   145
{
jbowes@258
   146
	importer->package->summary = hashtable_tokenize(&importer->details_table, summary);
jbowes@258
   147
	importer->package->description = hashtable_tokenize(&importer->details_table, description);
jbowes@258
   148
	importer->package->url = hashtable_tokenize(&importer->details_table, url);
jbowes@258
   149
	importer->package->license = hashtable_tokenize(&importer->details_table, license);
jbowes@258
   150
}
jbowes@258
   151
krh@309
   152
/**
ali@369
   153
 * razor_importer_add_script:
ali@369
   154
 * @importer: the %razor_importer
ali@369
   155
 * @script: either %RAZOR_PROPERTY_PREUN or %RAZOR_PROPERTY_POSTUN
ali@369
   156
 * @program: the program to run the script
ali@369
   157
 * @body: the body of the script
ali@369
   158
 *
ali@369
   159
 * Provide a script to use when uninstalling the current package.
ali@369
   160
 **/
ali@369
   161
RAZOR_EXPORT void
ali@369
   162
razor_importer_add_script(struct razor_importer *importer,
ali@369
   163
			  enum razor_property_flags script,
ali@369
   164
			  const char *program,
ali@369
   165
			  const char *body)
ali@369
   166
{
ali@369
   167
	switch (script) {
ali@369
   168
	case RAZOR_PROPERTY_PREUN:
ali@369
   169
		importer->package->preun.program =
ali@369
   170
			hashtable_tokenize(&importer->table, program);
ali@369
   171
		importer->package->preun.body =
ali@369
   172
			hashtable_tokenize(&importer->table, body);
ali@369
   173
		break;
ali@369
   174
	case RAZOR_PROPERTY_POSTUN:
ali@369
   175
		importer->package->postun.program =
ali@369
   176
			hashtable_tokenize(&importer->table, program);
ali@369
   177
		importer->package->postun.body =
ali@369
   178
			hashtable_tokenize(&importer->table, body);
ali@369
   179
		break;
ali@369
   180
	default:
ali@369
   181
		break;
ali@369
   182
	}
ali@369
   183
}
ali@369
   184
ali@369
   185
/**
ali@372
   186
 * razor_importer_add_install_prefixes:
ali@372
   187
 * @importer: the %razor_importer
ali@372
   188
 * @install_prefix: the relocated prefix
ali@372
   189
 *
ali@372
   190
 * Adds a relocated prefix for the current package.
ali@372
   191
 **/
ali@372
   192
RAZOR_EXPORT void
ali@372
   193
razor_importer_add_install_prefix(struct razor_importer *importer,
ali@372
   194
				  const char *install_prefix)
ali@372
   195
{
ali@372
   196
	uint32_t *r;
ali@372
   197
ali@372
   198
	r = array_add(&importer->install_prefixes, sizeof *r);
ali@372
   199
	*r = hashtable_tokenize(&importer->table, install_prefix);
ali@372
   200
}
ali@372
   201
ali@372
   202
/**
krh@309
   203
 * razor_importer_add_property:
krh@309
   204
 * @importer: the %razor_importer
krh@309
   205
 * @name: name of the property
krh@309
   206
 * @flags: property flags
krh@309
   207
 * @version: version of the property or %NULL
krh@309
   208
 *
krh@309
   209
 * Add a property for the current package.  The %flags parameter
krh@309
   210
 * determines the type of the property and optionally the relation to
krh@309
   211
 * the specified version and the availability constraint.  See
krh@309
   212
 * %razor_property_flags for further information about the flag
krh@309
   213
 * parameter.
krh@309
   214
 **/
krh@269
   215
RAZOR_EXPORT void
krh@248
   216
razor_importer_add_property(struct razor_importer *importer,
krh@248
   217
			    const char *name,
krh@248
   218
			    uint32_t flags,
krh@248
   219
			    const char *version)
krh@248
   220
{
krh@248
   221
	struct razor_property *p;
krh@248
   222
	uint32_t *r;
krh@248
   223
krh@248
   224
	p = array_add(&importer->set->properties, sizeof *p);
krh@248
   225
	p->name = hashtable_tokenize(&importer->table, name);
krh@248
   226
	p->flags = flags;
krh@248
   227
	p->version = hashtable_tokenize(&importer->table, version);
krh@248
   228
	list_set_ptr(&p->packages, importer->package -
krh@248
   229
		     (struct razor_package *) importer->set->packages.data);
krh@248
   230
krh@248
   231
	r = array_add(&importer->properties, sizeof *r);
krh@248
   232
	*r = p - (struct razor_property *) importer->set->properties.data;
krh@248
   233
krh@248
   234
	if (((flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES) &&
krh@248
   235
	    *name == '/') {
krh@248
   236
		r = array_add(&importer->file_requires, sizeof *r);
krh@248
   237
		*r = p->name;
krh@248
   238
	}
krh@248
   239
}
krh@248
   240
krh@309
   241
/**
krh@309
   242
 * razor_importer_add_file:
krh@309
   243
 * @importer: the %razor_importer
krh@309
   244
 * @name: name of the file
krh@309
   245
 *
krh@309
   246
 * Add a file to the current package.
krh@309
   247
 **/
krh@269
   248
RAZOR_EXPORT void
krh@248
   249
razor_importer_add_file(struct razor_importer *importer, const char *name)
krh@248
   250
{
krh@248
   251
	struct import_entry *e;
krh@248
   252
krh@248
   253
	e = array_add(&importer->files, sizeof *e);
krh@248
   254
krh@248
   255
	e->package = importer->package -
krh@248
   256
		(struct razor_package *) importer->set->packages.data;
krh@248
   257
	e->name = strdup(name);
krh@248
   258
}
krh@248
   259
krh@248
   260
static int
krh@248
   261
compare_packages(const void *p1, const void *p2, void *data)
krh@248
   262
{
krh@248
   263
	const struct razor_package *pkg1 = p1, *pkg2 = p2;
krh@248
   264
	struct razor_set *set = data;
krh@248
   265
	char *pool = set->string_pool.data;
krh@248
   266
krh@248
   267
	/* FIXME: what if the flags are different? */
krh@248
   268
	if (pkg1->name == pkg2->name)
krh@248
   269
		return razor_versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
krh@248
   270
	else
krh@248
   271
		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
krh@248
   272
}
krh@248
   273
krh@248
   274
static int
krh@248
   275
compare_properties(const void *p1, const void *p2, void *data)
krh@248
   276
{
krh@248
   277
	const struct razor_property *prop1 = p1, *prop2 = p2;
krh@248
   278
	struct razor_set *set = data;
krh@248
   279
	char *pool = set->string_pool.data;
krh@248
   280
krh@248
   281
	if (prop1->name != prop2->name)
krh@248
   282
		return strcmp(&pool[prop1->name], &pool[prop2->name]);
krh@248
   283
	else if (prop1->flags != prop2->flags)
krh@248
   284
		return prop1->flags - prop2->flags;
krh@257
   285
	else if (prop1->version != prop2->version)
krh@257
   286
		return razor_versioncmp(&pool[prop1->version], &pool[prop2->version]);
krh@248
   287
	else
krh@257
   288
		return prop1->packages.list_ptr - prop2->packages.list_ptr;
krh@248
   289
}
krh@248
   290
krh@248
   291
static uint32_t *
krh@248
   292
uniqueify_properties(struct razor_set *set)
krh@248
   293
{
krh@248
   294
	struct razor_property *rp, *up, *rp_end;
krh@248
   295
	struct array *pkgs, *p;
krh@248
   296
	struct list_head *r;
krh@248
   297
	uint32_t *map, *rmap;
krh@248
   298
	int i, count, unique;
krh@248
   299
krh@248
   300
	count = set->properties.size / sizeof(struct razor_property);
krh@248
   301
	map = razor_qsort_with_data(set->properties.data,
krh@248
   302
				    count,
krh@248
   303
				    sizeof(struct razor_property),
krh@248
   304
				    compare_properties,
krh@248
   305
				    set);
krh@248
   306
krh@248
   307
	rp_end = set->properties.data + set->properties.size;
krh@248
   308
	rmap = malloc(count * sizeof *map);
krh@248
   309
	pkgs = zalloc(count * sizeof *pkgs);
krh@248
   310
	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
krh@248
   311
		if (rp->name != up->name ||
krh@248
   312
		    rp->flags != up->flags ||
krh@248
   313
		    rp->version != up->version) {
krh@248
   314
			up++;
krh@248
   315
			up->name = rp->name;
krh@248
   316
			up->flags = rp->flags;
krh@248
   317
			up->version = rp->version;
krh@248
   318
		}
krh@248
   319
krh@248
   320
		unique = up - (struct razor_property *) set->properties.data;
krh@248
   321
		rmap[map[i]] = unique;
krh@248
   322
		r = array_add(&pkgs[unique], sizeof *r);
krh@248
   323
		*r = rp->packages;
krh@248
   324
	}
krh@248
   325
	free(map);
krh@248
   326
krh@248
   327
	if (up != rp)
krh@248
   328
		up++;
krh@248
   329
	set->properties.size = (void *) up - set->properties.data;
krh@248
   330
	rp_end = up;
krh@248
   331
	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
krh@248
   332
		list_set_array(&rp->packages, &set->package_pool, p, 0);
krh@248
   333
		array_release(p);
krh@248
   334
	}
krh@248
   335
krh@248
   336
	free(pkgs);
krh@248
   337
krh@248
   338
	return rmap;
krh@248
   339
}
krh@248
   340
krh@248
   341
static int
krh@248
   342
compare_filenames(const void *p1, const void *p2, void *data)
krh@248
   343
{
krh@248
   344
	const struct import_entry *e1 = p1;
krh@248
   345
	const struct import_entry *e2 = p2;
krh@248
   346
	const char *n1 = e1->name;
krh@248
   347
	const char *n2 = e2->name;
krh@248
   348
krh@248
   349
	/* Need to make sure that the contents of a directory
krh@248
   350
	 * are sorted immediately after it. So "foo/bar" has to
krh@248
   351
	 * sort before "foo.conf"
krh@248
   352
	 *
krh@248
   353
	 * FIXME: this is about 60% slower than strcmp
krh@248
   354
	 */
krh@248
   355
	while (*n1 && *n2) {
krh@248
   356
		if (*n1 < *n2)
krh@248
   357
			return *n2 == '/' ? 1 : -1;
krh@248
   358
		else if (*n1 > *n2)
krh@248
   359
			return *n1 == '/' ? -1 : 1;
krh@248
   360
		n1++;
krh@248
   361
		n2++;
krh@248
   362
	}
krh@248
   363
	if (*n1)
krh@248
   364
		return 1;
krh@248
   365
	else if (*n2)
krh@248
   366
		return -1;
krh@248
   367
	else
krh@248
   368
		return 0;
krh@248
   369
}
krh@248
   370
krh@248
   371
static void
krh@248
   372
count_entries(struct import_directory *d)
krh@248
   373
{
krh@248
   374
	struct import_directory *p, *end;
krh@248
   375
krh@248
   376
	p = d->files.data;
krh@248
   377
	end = d->files.data + d->files.size;
krh@248
   378
	d->count = 0;
krh@248
   379
	while (p < end) {
krh@248
   380
		count_entries(p);
krh@248
   381
		d->count += p->count + 1;
krh@248
   382
		p++;
krh@248
   383
	}
krh@248
   384
}
krh@248
   385
krh@248
   386
static void
krh@248
   387
serialize_files(struct razor_set *set,
krh@248
   388
		struct import_directory *d, struct array *array)
krh@248
   389
{
krh@248
   390
	struct import_directory *p, *end;
krh@248
   391
	struct razor_entry *e = NULL;
krh@248
   392
	uint32_t s;
krh@248
   393
krh@248
   394
	p = d->files.data;
krh@248
   395
	end = d->files.data + d->files.size;
krh@248
   396
	s = array->size / sizeof *e + d->files.size / sizeof *p;
krh@248
   397
	while (p < end) {
krh@248
   398
		e = array_add(array, sizeof *e);
krh@248
   399
		e->name = p->name;
krh@248
   400
		e->flags = 0;
krh@248
   401
		e->start = p->count > 0 ? s : 0;
krh@248
   402
		s += p->count;
krh@248
   403
krh@248
   404
		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
krh@248
   405
		array_release(&p->packages);
krh@248
   406
		p++;
krh@248
   407
	}
krh@248
   408
	if (e != NULL)
krh@248
   409
		e->flags |= RAZOR_ENTRY_LAST;
krh@248
   410
krh@248
   411
	p = d->files.data;
krh@248
   412
	end = d->files.data + d->files.size;
krh@248
   413
	while (p < end) {
krh@248
   414
		serialize_files(set, p, array);
krh@248
   415
		p++;
krh@248
   416
	}
krh@248
   417
}
krh@248
   418
krh@248
   419
static void
krh@248
   420
remap_property_package_links(struct array *properties, uint32_t *rmap)
krh@248
   421
{
krh@248
   422
	struct razor_property *p, *end;
krh@248
   423
krh@248
   424
	end = properties->data + properties->size;
krh@248
   425
	for (p = properties->data; p < end; p++)
krh@248
   426
		list_remap_head(&p->packages, rmap);
krh@248
   427
}
krh@248
   428
krh@248
   429
static void
krh@248
   430
build_file_tree(struct razor_importer *importer)
krh@248
   431
{
krh@248
   432
	int count, i, length;
krh@248
   433
	struct import_entry *filenames;
krh@248
   434
	char *f, *end;
ali@359
   435
	uint32_t name, *r, s;
ali@359
   436
	char rootname[256], dirname[256];
ali@359
   437
	struct import_directory *d, *last_root;
ali@359
   438
	struct array roots;
krh@248
   439
	struct razor_entry *e;
krh@248
   440
krh@248
   441
	count = importer->files.size / sizeof (struct import_entry);
ali@359
   442
	filenames = importer->files.data;
ali@359
   443
	razor_qsort_with_data(filenames,
krh@248
   444
			      count,
krh@248
   445
			      sizeof (struct import_entry),
krh@248
   446
			      compare_filenames,
krh@248
   447
			      NULL);
krh@248
   448
ali@359
   449
	array_init(&roots);
ali@359
   450
	last_root = NULL;
krh@248
   451
krh@248
   452
	for (i = 0; i < count; i++) {
krh@248
   453
		f = filenames[i].name;
ali@359
   454
		d = NULL;
krh@248
   455
		while (*f) {
krh@248
   456
			end = strchr(f, '/');
krh@248
   457
			if (end == NULL)
krh@248
   458
				end = f + strlen(f);
krh@248
   459
			length = end - f;
krh@248
   460
			memcpy(dirname, f, length);
ali@359
   461
			dirname[length] = '\0';
jbowes@264
   462
			name = hashtable_tokenize(&importer->file_table,
jbowes@264
   463
						  dirname);
ali@359
   464
			if (!d) {
ali@359
   465
				if (!last_root || last_root->name != name) {
ali@359
   466
					d = array_add(&roots, sizeof *d);
ali@359
   467
					d->name = name;
ali@359
   468
					d->last = NULL;
ali@359
   469
					array_init(&d->files);
ali@359
   470
					array_init(&d->packages);
ali@359
   471
					last_root = d;
ali@359
   472
				}
ali@359
   473
				d = last_root;
ali@359
   474
			} else {
ali@359
   475
				if (!d->last || d->last->name != name) {
ali@359
   476
					d->last = array_add(&d->files,
ali@359
   477
							    sizeof *d);
ali@359
   478
					d->last->name = name;
ali@359
   479
					d->last->last = NULL;
ali@359
   480
					array_init(&d->last->files);
ali@359
   481
					array_init(&d->last->packages);
ali@359
   482
				}
ali@359
   483
				d = d->last;
krh@248
   484
			}
krh@248
   485
			f = end + 1;
krh@248
   486
			if (*end == '\0')
krh@248
   487
				break;
krh@248
   488
		}
krh@248
   489
krh@248
   490
		r = array_add(&d->packages, sizeof *r);
krh@248
   491
		*r = filenames[i].package;
krh@248
   492
		free(filenames[i].name);
krh@248
   493
	}
krh@248
   494
ali@359
   495
	count = roots.size / sizeof (struct import_directory);
ali@359
   496
	d = roots.data;
ali@359
   497
	s = count;
ali@359
   498
	for (i = 0; i < count; i++) {
ali@359
   499
		count_entries(d);
ali@359
   500
		if (i)
ali@359
   501
			e = array_add(&importer->set->files, sizeof *e);
ali@359
   502
		else
ali@359
   503
			e = importer->set->files.data;
ali@359
   504
		e->name = d->name;
ali@359
   505
		e->flags = 0;
ali@359
   506
		e->start = d->count > 0 ? s : 0;
ali@359
   507
		s += d->count;
ali@359
   508
		list_set_empty(&e->packages);
ali@359
   509
		d++;
ali@359
   510
	}
ali@359
   511
	if (count)
ali@359
   512
		e->flags |= RAZOR_ENTRY_LAST;
krh@248
   513
ali@359
   514
	d = roots.data;
ali@359
   515
	for (i = 0; i < count; i++) {
ali@359
   516
		serialize_files(importer->set, d, &importer->set->files);
ali@359
   517
		d++;
ali@359
   518
	}
krh@248
   519
krh@248
   520
	array_release(&importer->files);
ali@359
   521
	array_release(&roots);
krh@248
   522
}
krh@248
   523
krh@248
   524
static void
krh@248
   525
list_to_array(struct list *list, struct array *array)
krh@248
   526
{
krh@248
   527
	uint32_t *item;
krh@248
   528
krh@248
   529
	while (list) {
krh@248
   530
		 item = array_add(array, sizeof *item);
krh@248
   531
		 *item = list->data;
krh@248
   532
		 list = list_next(list);
krh@248
   533
	}
krh@248
   534
}
krh@248
   535
krh@248
   536
static int
krh@248
   537
compare_file_requires(const void *p1, const void *p2, void *data)
krh@248
   538
{
krh@248
   539
	uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
krh@248
   540
	const char *pool = data;
krh@248
   541
krh@248
   542
	return strcmp(&pool[*f1], &pool[*f2]);
krh@248
   543
}
krh@248
   544
krh@248
   545
static void
krh@248
   546
find_file_provides(struct razor_importer *importer)
krh@248
   547
{
krh@248
   548
	struct razor_property *prop;
krh@248
   549
	struct razor_entry *top, *entry;
krh@248
   550
	struct razor_package *packages;
krh@248
   551
	struct array pkgprops;
krh@248
   552
	struct list *pkg;
krh@248
   553
	uint32_t *req, *req_start, *req_end;
krh@248
   554
	uint32_t *map, *newprop;
krh@248
   555
	char *pool;
krh@248
   556
krh@248
   557
	pool = importer->set->string_pool.data;
krh@248
   558
	packages = importer->set->packages.data;
krh@248
   559
	top = importer->set->files.data;
krh@248
   560
krh@248
   561
	req = req_start = importer->file_requires.data;
krh@248
   562
	req_end = importer->file_requires.data + importer->file_requires.size;
krh@248
   563
	map = razor_qsort_with_data(req, req_end - req, sizeof *req,
krh@248
   564
				    compare_file_requires, pool);
krh@248
   565
	free(map);
krh@248
   566
krh@248
   567
	for (req = req_start; req < req_end; req++) {
krh@248
   568
		if (req > req_start && req[0] == req[-1])
krh@248
   569
			continue;
krh@248
   570
		entry = razor_set_find_entry(importer->set, top, &pool[*req]);
krh@248
   571
		if (!entry)
krh@248
   572
			continue;
krh@248
   573
krh@248
   574
		for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
krh@248
   575
			prop = array_add(&importer->set->properties, sizeof *prop);
krh@248
   576
			prop->name = *req;
krh@248
   577
			prop->flags =
krh@248
   578
				RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL;
krh@248
   579
			prop->version = hashtable_tokenize(&importer->table, "");
krh@248
   580
			list_set_ptr(&prop->packages, pkg->data);
krh@248
   581
krh@248
   582
			/* Update property list of pkg */
krh@248
   583
			array_init(&pkgprops);
krh@248
   584
			list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
krh@248
   585
			newprop = array_add(&pkgprops, sizeof *newprop);
krh@248
   586
			*newprop = prop - (struct razor_property *)importer->set->properties.data;
krh@248
   587
			list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
krh@248
   588
			array_release(&pkgprops);
krh@248
   589
		}
krh@248
   590
	}
krh@248
   591
krh@248
   592
	array_release(&importer->file_requires);
krh@248
   593
}
krh@248
   594
krh@248
   595
static void
krh@248
   596
build_package_file_lists(struct razor_set *set, uint32_t *rmap)
krh@248
   597
{
krh@248
   598
	struct razor_package *p, *packages;
krh@248
   599
	struct array *pkgs;
krh@248
   600
	struct razor_entry *e, *end;
krh@248
   601
	struct list *r;
krh@248
   602
	uint32_t *q;
krh@248
   603
	int i, count;
krh@248
   604
krh@248
   605
	count = set->packages.size / sizeof *p;
krh@248
   606
	pkgs = zalloc(count * sizeof *pkgs);
krh@248
   607
krh@248
   608
	end = set->files.data + set->files.size;
krh@248
   609
	for (e = set->files.data; e < end; e++) {
krh@248
   610
		list_remap_head(&e->packages, rmap);
krh@248
   611
		r = list_first(&e->packages, &set->package_pool);
krh@248
   612
		while (r) {
krh@248
   613
			q = array_add(&pkgs[r->data], sizeof *q);
krh@248
   614
			*q = e - (struct razor_entry *) set->files.data;
krh@248
   615
			r = list_next(r);
krh@248
   616
		}
krh@248
   617
	}
krh@248
   618
krh@248
   619
	packages = set->packages.data;
krh@248
   620
	for (i = 0; i < count; i++) {
krh@248
   621
		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
krh@248
   622
		array_release(&pkgs[i]);
krh@248
   623
	}
krh@248
   624
	free(pkgs);
krh@248
   625
}
krh@248
   626
krh@309
   627
/**
krh@309
   628
 * razor_importer_finish:
krh@309
   629
 * @importer: the %razor_importer
krh@309
   630
 *
krh@309
   631
 * Finish importing packages and create the package set.  This sorts
krh@309
   632
 * and indexes all the packages, properties and files in the importer
krh@309
   633
 * and creates a new %razor_set.  After creating the new package set,
krh@309
   634
 * the importer is destroyed.
krh@309
   635
 *
krh@309
   636
 * Returns: the new %razor_set
krh@309
   637
 **/
krh@269
   638
RAZOR_EXPORT struct razor_set *
krh@248
   639
razor_importer_finish(struct razor_importer *importer)
krh@248
   640
{
krh@248
   641
	struct razor_set *set;
krh@248
   642
	uint32_t *map, *rmap;
krh@248
   643
	int i, count;
krh@248
   644
krh@248
   645
	build_file_tree(importer);
krh@248
   646
	find_file_provides(importer);
krh@248
   647
krh@248
   648
	map = uniqueify_properties(importer->set);
krh@248
   649
	list_remap_pool(&importer->set->property_pool, map);
krh@248
   650
	free(map);
krh@248
   651
krh@248
   652
	count = importer->set->packages.size / sizeof(struct razor_package);
krh@248
   653
	map = razor_qsort_with_data(importer->set->packages.data,
krh@248
   654
				    count,
krh@248
   655
				    sizeof(struct razor_package),
krh@248
   656
				    compare_packages,
krh@248
   657
				    importer->set);
krh@248
   658
krh@248
   659
	rmap = malloc(count * sizeof *rmap);
krh@248
   660
	for (i = 0; i < count; i++)
krh@248
   661
		rmap[map[i]] = i;
krh@248
   662
	free(map);
krh@248
   663
krh@248
   664
	list_remap_pool(&importer->set->package_pool, rmap);
krh@248
   665
	build_package_file_lists(importer->set, rmap);
krh@248
   666
	remap_property_package_links(&importer->set->properties, rmap);
krh@248
   667
	free(rmap);
krh@248
   668
krh@248
   669
	set = importer->set;
krh@248
   670
	hashtable_release(&importer->table);
jbowes@264
   671
	hashtable_release(&importer->details_table);
jbowes@264
   672
	hashtable_release(&importer->file_table);
krh@248
   673
	free(importer);
krh@248
   674
krh@248
   675
	return set;
krh@248
   676
}