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