src/import-yum.c
author J. Ali Harlow <ali@juiblex.co.uk>
Tue Mar 06 12:39:15 2018 +0000 (2018-03-06)
changeset 495 5196f8110473
parent 455 df914f383f5c
permissions -rw-r--r--
Release 0.6.3.111
rhughes@241
     1
/*
rhughes@241
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
rhughes@241
     3
 * Copyright (C) 2008  Red Hat, Inc
rhughes@241
     4
 *
rhughes@241
     5
 * This program is free software; you can redistribute it and/or modify
rhughes@241
     6
 * it under the terms of the GNU General Public License as published by
rhughes@241
     7
 * the Free Software Foundation; either version 2 of the License, or
rhughes@241
     8
 * (at your option) any later version.
rhughes@241
     9
 *
rhughes@241
    10
 * This program is distributed in the hope that it will be useful,
rhughes@241
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rhughes@241
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
rhughes@241
    13
 * GNU General Public License for more details.
rhughes@241
    14
 *
rhughes@241
    15
 * You should have received a copy of the GNU General Public License along
rhughes@241
    16
 * with this program; if not, write to the Free Software Foundation, Inc.,
rhughes@241
    17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
rhughes@241
    18
 */
rhughes@241
    19
rhughes@241
    20
#define _GNU_SOURCE
rhughes@241
    21
ali@438
    22
#include "config.h"
rhughes@241
    23
#include <string.h>
rhughes@241
    24
#include <stdio.h>
krh@247
    25
#include <stdint.h>
ali@476
    26
#include <assert.h>
rhughes@241
    27
#include <sys/stat.h>
rhughes@241
    28
#include <unistd.h>
rhughes@241
    29
#include <fcntl.h>
rhughes@241
    30
#include <errno.h>
rhughes@241
    31
rhughes@241
    32
#include <expat.h>
rhughes@241
    33
#include <zlib.h>
rhughes@241
    34
#include "razor.h"
ali@476
    35
#include "import.h"
rhughes@241
    36
rhughes@241
    37
/* Import a yum filelist as a razor package set. */
rhughes@241
    38
rhughes@241
    39
enum {
rhughes@241
    40
	YUM_STATE_BEGIN,
rhughes@241
    41
	YUM_STATE_PACKAGE_NAME,
rhughes@241
    42
	YUM_STATE_PACKAGE_ARCH,
jbowes@258
    43
	YUM_STATE_SUMMARY,
jbowes@258
    44
	YUM_STATE_DESCRIPTION,
jbowes@258
    45
	YUM_STATE_URL,
jbowes@258
    46
	YUM_STATE_LICENSE,
rhughes@241
    47
	YUM_STATE_CHECKSUM,
rhughes@241
    48
	YUM_STATE_REQUIRES,
rhughes@241
    49
	YUM_STATE_PROVIDES,
rhughes@241
    50
	YUM_STATE_OBSOLETES,
rhughes@241
    51
	YUM_STATE_CONFLICTS,
rhughes@241
    52
	YUM_STATE_FILE
rhughes@241
    53
};
rhughes@241
    54
rhughes@241
    55
struct yum_context {
rhughes@241
    56
	XML_Parser primary_parser;
rhughes@241
    57
	XML_Parser filelists_parser;
rhughes@241
    58
	XML_Parser current_parser;
rhughes@241
    59
rhughes@241
    60
	struct razor_importer *importer;
rhughes@241
    61
	struct import_property_context *current_property_context;
jbowes@258
    62
	char name[256], arch[64], summary[512], description[4096];
jbowes@258
    63
	char url[256], license[64], buffer[512], *p;
rhughes@241
    64
	char pkgid[128];
krh@247
    65
	uint32_t property_type;
rhughes@241
    66
	int state;
jbowes@263
    67
jbowes@263
    68
	int total, current;
rhughes@241
    69
};
rhughes@241
    70
krh@247
    71
static uint32_t
krh@247
    72
yum_to_razor_relation (const char *flags)
rhughes@241
    73
{
rhughes@241
    74
	if (flags[0] == 'L') {
rhughes@241
    75
		if (flags[1] == 'T')
krh@247
    76
			return RAZOR_PROPERTY_LESS;
rhughes@241
    77
		else
krh@247
    78
			return RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL;
rhughes@241
    79
	} else if (flags[0] == 'G') {
rhughes@241
    80
		if (flags[1] == 'T')
krh@247
    81
			return RAZOR_PROPERTY_GREATER;
rhughes@241
    82
		else
krh@247
    83
			return RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL;
rhughes@241
    84
	} else
krh@247
    85
		return RAZOR_PROPERTY_EQUAL;
rhughes@241
    86
}
rhughes@241
    87
rhughes@241
    88
static void
rhughes@241
    89
yum_primary_start_element(void *data, const char *name, const char **atts)
rhughes@241
    90
{
rhughes@241
    91
	struct yum_context *ctx = data;
krh@247
    92
	const char *n, *epoch, *version, *release;
rhughes@241
    93
	char buffer[128];
krh@247
    94
	uint32_t pre, relation, flags;
rhughes@241
    95
	int i;
rhughes@241
    96
jbowes@263
    97
	if (strcmp(name, "metadata") == 0) {
jbowes@263
    98
		for (i = 0; atts[i]; i += 2) {
jbowes@263
    99
			if (strcmp(atts[i], "packages") == 0)
jbowes@263
   100
				ctx->total = atoi(atts[i + 1]);
jbowes@263
   101
		}
jbowes@263
   102
	} else if (strcmp(name, "name") == 0) {
rhughes@241
   103
		ctx->state = YUM_STATE_PACKAGE_NAME;
rhughes@241
   104
		ctx->p = ctx->name;
rhughes@241
   105
	} else if (strcmp(name, "arch") == 0) {
rhughes@241
   106
		ctx->state = YUM_STATE_PACKAGE_ARCH;
rhughes@241
   107
		ctx->p = ctx->arch;
rhughes@241
   108
	} else if (strcmp(name, "version") == 0) {
rhughes@241
   109
		epoch = NULL;
rhughes@241
   110
		version = NULL;
rhughes@241
   111
		release = NULL;
rhughes@241
   112
		for (i = 0; atts[i]; i += 2) {
rhughes@241
   113
			if (strcmp(atts[i], "epoch") == 0)
rhughes@241
   114
				epoch = atts[i + 1];
rhughes@241
   115
			else if (strcmp(atts[i], "ver") == 0)
rhughes@241
   116
				version = atts[i + 1];
rhughes@241
   117
			else if (strcmp(atts[i], "rel") == 0)
rhughes@241
   118
				release = atts[i + 1];
rhughes@241
   119
		}
rhughes@241
   120
		if (version == NULL || release == NULL) {
rhughes@241
   121
			fprintf(stderr, "invalid version tag, "
rhughes@241
   122
				"missing version or  release attribute\n");
rhughes@241
   123
			return;
rhughes@241
   124
		}
rhughes@241
   125
rhughes@241
   126
		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
rhughes@241
   127
		razor_importer_begin_package(ctx->importer,
rhughes@241
   128
					     ctx->name, buffer, ctx->arch);
jbowes@258
   129
	} else if (strcmp(name, "summary") == 0) {
jbowes@258
   130
		ctx->p = ctx->summary;
jbowes@258
   131
		ctx->state = YUM_STATE_SUMMARY;
jbowes@258
   132
	} else if (strcmp(name, "description") == 0) {
jbowes@258
   133
		ctx->p = ctx->description;
jbowes@258
   134
		ctx->state = YUM_STATE_DESCRIPTION;
jbowes@258
   135
	} else if (strcmp(name, "url") == 0) {
jbowes@258
   136
		ctx->p = ctx->url;
jbowes@258
   137
		ctx->state = YUM_STATE_URL;
rhughes@241
   138
	} else if (strcmp(name, "checksum") == 0) {
rhughes@241
   139
		ctx->p = ctx->pkgid;
rhughes@241
   140
		ctx->state = YUM_STATE_CHECKSUM;
jbowes@258
   141
	} else if (strcmp(name, "rpm:license") == 0) {
jbowes@258
   142
		ctx->p = ctx->license;
jbowes@258
   143
		ctx->state = YUM_STATE_LICENSE;
rhughes@241
   144
	} else if (strcmp(name, "rpm:requires") == 0) {
rhughes@241
   145
		ctx->state = YUM_STATE_REQUIRES;
krh@247
   146
		ctx->property_type = RAZOR_PROPERTY_REQUIRES;
rhughes@241
   147
	} else if (strcmp(name, "rpm:provides") == 0) {
rhughes@241
   148
		ctx->state = YUM_STATE_PROVIDES;
krh@247
   149
		ctx->property_type = RAZOR_PROPERTY_PROVIDES;
rhughes@241
   150
	} else if (strcmp(name, "rpm:obsoletes") == 0) {
rhughes@241
   151
		ctx->state = YUM_STATE_OBSOLETES;
krh@247
   152
		ctx->property_type = RAZOR_PROPERTY_OBSOLETES;
rhughes@241
   153
	} else if (strcmp(name, "rpm:conflicts") == 0) {
rhughes@241
   154
		ctx->state = YUM_STATE_CONFLICTS;
krh@247
   155
		ctx->property_type = RAZOR_PROPERTY_CONFLICTS;
rhughes@241
   156
	} else if (strcmp(name, "rpm:entry") == 0 &&
rhughes@241
   157
		   ctx->state != YUM_STATE_BEGIN) {
rhughes@241
   158
		n = NULL;
rhughes@241
   159
		epoch = NULL;
rhughes@241
   160
		version = NULL;
rhughes@241
   161
		release = NULL;
krh@247
   162
		relation = RAZOR_PROPERTY_EQUAL;
krh@247
   163
		pre = 0;
rhughes@241
   164
		for (i = 0; atts[i]; i += 2) {
rhughes@241
   165
			if (strcmp(atts[i], "name") == 0)
rhughes@241
   166
				n = atts[i + 1];
rhughes@241
   167
			else if (strcmp(atts[i], "epoch") == 0)
rhughes@241
   168
				epoch = atts[i + 1];
rhughes@241
   169
			else if (strcmp(atts[i], "ver") == 0)
rhughes@241
   170
				version = atts[i + 1];
rhughes@241
   171
			else if (strcmp(atts[i], "rel") == 0)
rhughes@241
   172
				release = atts[i + 1];
rhughes@241
   173
			else if (strcmp(atts[i], "flags") == 0)
krh@247
   174
				relation = yum_to_razor_relation(atts[i + 1]);
krh@247
   175
			else if (strcmp(atts[i], "pre") == 0)
ali@418
   176
				pre = RAZOR_PROPERTY_PRE;
rhughes@241
   177
		}
rhughes@241
   178
rhughes@241
   179
		if (n == NULL) {
rhughes@241
   180
			fprintf(stderr, "invalid rpm:entry, "
rhughes@241
   181
				"missing name or version attributes\n");
rhughes@241
   182
			return;
rhughes@241
   183
		}
rhughes@241
   184
rhughes@241
   185
		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
krh@247
   186
		flags = ctx->property_type | relation | pre;
krh@247
   187
		razor_importer_add_property(ctx->importer, n, flags, buffer);
rhughes@241
   188
	}
rhughes@241
   189
}
rhughes@241
   190
rhughes@241
   191
static void
rhughes@241
   192
yum_primary_end_element (void *data, const char *name)
rhughes@241
   193
{
rhughes@241
   194
	struct yum_context *ctx = data;
rhughes@241
   195
rhughes@241
   196
	switch (ctx->state) {
rhughes@241
   197
	case YUM_STATE_PACKAGE_NAME:
rhughes@241
   198
	case YUM_STATE_PACKAGE_ARCH:
jbowes@258
   199
	case YUM_STATE_SUMMARY:
jbowes@258
   200
	case YUM_STATE_DESCRIPTION:
jbowes@258
   201
	case YUM_STATE_URL:
jbowes@258
   202
	case YUM_STATE_LICENSE:
rhughes@241
   203
	case YUM_STATE_CHECKSUM:
rhughes@241
   204
	case YUM_STATE_FILE:
rhughes@241
   205
		ctx->state = YUM_STATE_BEGIN;
rhughes@241
   206
		break;
rhughes@241
   207
	}
rhughes@241
   208
rhughes@241
   209
	if (strcmp(name, "package") == 0) {
jbowes@258
   210
		razor_importer_add_details(ctx->importer, ctx->summary,
jbowes@258
   211
					   ctx->description, ctx->url,
jbowes@258
   212
					   ctx->license);
jbowes@258
   213
rhughes@241
   214
		XML_StopParser(ctx->current_parser, XML_TRUE);
rhughes@241
   215
		ctx->current_parser = ctx->filelists_parser;
jbowes@263
   216
jbowes@263
   217
		printf("\rimporting %d/%d", ++ctx->current, ctx->total);
jbowes@263
   218
		fflush(stdout);
rhughes@241
   219
	}
rhughes@241
   220
}
rhughes@241
   221
rhughes@241
   222
static void
rhughes@241
   223
yum_character_data (void *data, const XML_Char *s, int len)
rhughes@241
   224
{
rhughes@241
   225
	struct yum_context *ctx = data;
rhughes@241
   226
rhughes@241
   227
	switch (ctx->state) {
rhughes@241
   228
	case YUM_STATE_PACKAGE_NAME:
rhughes@241
   229
	case YUM_STATE_PACKAGE_ARCH:
jbowes@258
   230
	case YUM_STATE_SUMMARY:
jbowes@258
   231
	case YUM_STATE_DESCRIPTION:
jbowes@258
   232
	case YUM_STATE_URL:
jbowes@258
   233
	case YUM_STATE_LICENSE:
rhughes@241
   234
	case YUM_STATE_CHECKSUM:
rhughes@241
   235
	case YUM_STATE_FILE:
rhughes@241
   236
		memcpy(ctx->p, s, len);
rhughes@241
   237
		ctx->p += len;
rhughes@241
   238
		*ctx->p = '\0';
rhughes@241
   239
		break;
rhughes@241
   240
	}
rhughes@241
   241
}
rhughes@241
   242
rhughes@241
   243
static void
rhughes@241
   244
yum_filelists_start_element(void *data, const char *name, const char **atts)
rhughes@241
   245
{
rhughes@241
   246
	struct yum_context *ctx = data;
rhughes@241
   247
	const char *pkg, *pkgid;
rhughes@241
   248
	int i;
rhughes@241
   249
rhughes@241
   250
	if (strcmp(name, "package") == 0) {
rhughes@241
   251
		pkg = NULL;
rhughes@241
   252
		pkgid = NULL;
rhughes@241
   253
		for (i = 0; atts[i]; i += 2) {
rhughes@241
   254
			if (strcmp(atts[i], "name") == 0)
rhughes@241
   255
				pkg = atts[i + 1];
rhughes@241
   256
			else if (strcmp(atts[i], "pkgid") == 0)
rhughes@241
   257
				pkgid = atts[i + 1];
rhughes@241
   258
		}
rhughes@241
   259
		if (strcmp(pkgid, ctx->pkgid) != 0)
rhughes@241
   260
			fprintf(stderr, "primary.xml and filelists.xml "
rhughes@241
   261
				"mismatch for %s: %s vs %s",
rhughes@241
   262
				pkg, pkgid, ctx->pkgid);
rhughes@241
   263
	} else if (strcmp(name, "file") == 0) {
rhughes@241
   264
		ctx->state = YUM_STATE_FILE;
rhughes@241
   265
		ctx->p = ctx->buffer;
rhughes@241
   266
	}
rhughes@241
   267
}
rhughes@241
   268
rhughes@241
   269
rhughes@241
   270
static void
rhughes@241
   271
yum_filelists_end_element (void *data, const char *name)
rhughes@241
   272
{
rhughes@241
   273
	struct yum_context *ctx = data;
rhughes@241
   274
rhughes@241
   275
	ctx->state = YUM_STATE_BEGIN;
rhughes@241
   276
	if (strcmp(name, "package") == 0) {
rhughes@241
   277
		XML_StopParser(ctx->current_parser, XML_TRUE);
rhughes@241
   278
		ctx->current_parser = ctx->primary_parser;
rhughes@241
   279
		razor_importer_finish_package(ctx->importer);
rhughes@241
   280
	} else if (strcmp(name, "file") == 0)
rhughes@241
   281
		razor_importer_add_file(ctx->importer, ctx->buffer);
rhughes@241
   282
rhughes@241
   283
}
rhughes@241
   284
rhughes@241
   285
#define XML_BUFFER_SIZE 4096
rhughes@241
   286
ali@476
   287
struct razor_stream {
ali@476
   288
	z_stream strm;
ali@476
   289
	void *in;
ali@476
   290
	size_t in_length;
ali@476
   291
};
ali@476
   292
ali@476
   293
static int razor_stream_open(struct razor_stream *rs, const char *uri,
ali@476
   294
			     struct razor_error **error)
ali@476
   295
{
ali@476
   296
	rs->strm.zalloc = Z_NULL;
ali@476
   297
	rs->strm.zfree = Z_NULL;
ali@476
   298
	rs->strm.opaque = Z_NULL;
ali@476
   299
	rs->strm.avail_in = 0;
ali@476
   300
	rs->strm.next_in = Z_NULL;
ali@476
   301
ali@476
   302
	if (inflateInit2(&rs->strm, 15 + 16) != Z_OK) {
ali@476
   303
		razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@476
   304
				RAZOR_GENERAL_ERROR_FAILED, uri,
ali@476
   305
				"Failed to initialize inflator");
ali@476
   306
		return -1;
ali@476
   307
	}
ali@476
   308
ali@476
   309
	rs->in = razor_uri_get_contents(uri, &rs->in_length, 0, error);
ali@476
   310
	if (!rs->in) {
ali@476
   311
		(void)inflateEnd(&rs->strm);
ali@476
   312
		return -1;
ali@476
   313
	}
ali@476
   314
ali@476
   315
	rs->strm.avail_in = rs->in_length;
ali@476
   316
	rs->strm.next_in = rs->in;
ali@476
   317
ali@476
   318
	return 0;
ali@476
   319
}
ali@476
   320
ali@476
   321
static ssize_t
ali@476
   322
razor_stream_read(struct razor_stream *rs, unsigned char *buf, size_t len)
ali@476
   323
{
ali@476
   324
	int r;
ali@476
   325
ali@476
   326
	rs->strm.avail_out = len;
ali@476
   327
	rs->strm.next_out = buf;
ali@476
   328
ali@476
   329
	r = inflate(&rs->strm, Z_NO_FLUSH);
ali@476
   330
	assert(r != Z_STREAM_ERROR);  /* state not clobbered */
ali@476
   331
	switch (r) {
ali@476
   332
	case Z_NEED_DICT:
ali@476
   333
	case Z_DATA_ERROR:
ali@476
   334
	case Z_MEM_ERROR:
ali@476
   335
		return -1;
ali@476
   336
	}
ali@476
   337
ali@476
   338
	return len - rs->strm.avail_out;
ali@476
   339
}
ali@476
   340
ali@476
   341
static void razor_stream_close(struct razor_stream *rs)
ali@476
   342
{
ali@476
   343
	(void)inflateEnd(&rs->strm);
ali@476
   344
	(void)razor_uri_free_contents(rs->in, rs->in_length);
ali@476
   345
}
ali@476
   346
rhughes@241
   347
struct razor_set *
ali@476
   348
razor_set_create_from_yum(const char *yum_uri)
rhughes@241
   349
{
ali@394
   350
	struct yum_context ctx={0};
ali@476
   351
	char *uri;
rhughes@241
   352
	void *buf;
ali@476
   353
	ssize_t len;
rhughes@241
   354
	XML_ParsingStatus status;
ali@476
   355
	struct razor_error *error = NULL;
ali@476
   356
	struct razor_stream primary, filelists;
rhughes@241
   357
krh@249
   358
	ctx.importer = razor_importer_create();
rhughes@241
   359
	ctx.state = YUM_STATE_BEGIN;
rhughes@241
   360
rhughes@241
   361
	ctx.primary_parser = XML_ParserCreate(NULL);
rhughes@241
   362
	XML_SetUserData(ctx.primary_parser, &ctx);
rhughes@241
   363
	XML_SetElementHandler(ctx.primary_parser,
rhughes@241
   364
			      yum_primary_start_element,
rhughes@241
   365
			      yum_primary_end_element);
rhughes@241
   366
	XML_SetCharacterDataHandler(ctx.primary_parser,
rhughes@241
   367
				    yum_character_data);
rhughes@241
   368
rhughes@241
   369
	ctx.filelists_parser = XML_ParserCreate(NULL);
rhughes@241
   370
	XML_SetUserData(ctx.filelists_parser, &ctx);
rhughes@241
   371
	XML_SetElementHandler(ctx.filelists_parser,
rhughes@241
   372
			      yum_filelists_start_element,
rhughes@241
   373
			      yum_filelists_end_element);
rhughes@241
   374
	XML_SetCharacterDataHandler(ctx.filelists_parser,
rhughes@241
   375
				    yum_character_data);
rhughes@241
   376
ali@476
   377
	uri = razor_path_relative_to_uri(yum_uri, "repodata/primary.xml.gz",
ali@476
   378
					 &error);
ali@476
   379
	if (!uri) {
ali@476
   380
		fprintf(stderr, "%s: %s\n", yum_uri,
ali@476
   381
			razor_error_get_msg(error));
ali@476
   382
		razor_error_free(error);
rhughes@241
   383
		return NULL;
ali@455
   384
	}
ali@476
   385
	if (razor_stream_open(&primary, uri, &error)) {
ali@476
   386
		fprintf(stderr, "%s: %s\n", uri, razor_error_get_msg(error));
ali@476
   387
		free(uri);
rhughes@241
   388
		return NULL;
ali@455
   389
	}
ali@476
   390
	free(uri);
ali@476
   391
ali@476
   392
	uri = razor_path_relative_to_uri(yum_uri, "repodata/filelists.xml.gz",
ali@476
   393
					 &error);
ali@476
   394
	if (!uri) {
ali@476
   395
		razor_stream_close(&primary);
ali@476
   396
		fprintf(stderr, "%s: %s\n", yum_uri,
ali@476
   397
			razor_error_get_msg(error));
ali@476
   398
		razor_error_free(error);
ali@476
   399
		return NULL;
ali@476
   400
	}
ali@476
   401
	if (razor_stream_open(&filelists, uri, &error)) {
ali@476
   402
		razor_stream_close(&primary);
ali@476
   403
		fprintf(stderr, "%s: %s\n", uri, razor_error_get_msg(error));
ali@476
   404
		free(uri);
ali@476
   405
		return NULL;
ali@476
   406
	}
ali@476
   407
	free(uri);
rhughes@241
   408
rhughes@241
   409
	ctx.current_parser = ctx.primary_parser;
rhughes@241
   410
jbowes@263
   411
	ctx.current = 0;
jbowes@263
   412
rhughes@241
   413
	do {
rhughes@241
   414
		XML_GetParsingStatus(ctx.current_parser, &status);
rhughes@241
   415
		switch (status.parsing) {
rhughes@241
   416
		case XML_SUSPENDED:
ali@442
   417
			XML_ResumeParser(ctx.current_parser);
rhughes@241
   418
			break;
rhughes@241
   419
		case XML_PARSING:
rhughes@241
   420
		case XML_INITIALIZED:
rhughes@241
   421
			buf = XML_GetBuffer(ctx.current_parser,
rhughes@241
   422
					    XML_BUFFER_SIZE);
rhughes@241
   423
			if (ctx.current_parser == ctx.primary_parser)
ali@476
   424
				len = razor_stream_read(&primary, buf,
ali@476
   425
							XML_BUFFER_SIZE);
rhughes@241
   426
			else
ali@476
   427
				len = razor_stream_read(&filelists, buf,
ali@476
   428
							XML_BUFFER_SIZE);
rhughes@241
   429
			if (len < 0) {
rhughes@241
   430
				fprintf(stderr,
rhughes@241
   431
					"couldn't read input: %s\n",
rhughes@241
   432
					strerror(errno));
rhughes@241
   433
				return NULL;
rhughes@241
   434
			}
rhughes@241
   435
rhughes@241
   436
			XML_ParseBuffer(ctx.current_parser, len, len == 0);
rhughes@241
   437
			break;
rhughes@241
   438
		case XML_FINISHED:
rhughes@241
   439
			break;
rhughes@241
   440
		}
rhughes@241
   441
	} while (status.parsing != XML_FINISHED);
rhughes@241
   442
rhughes@241
   443
rhughes@241
   444
	XML_ParserFree(ctx.primary_parser);
rhughes@241
   445
	XML_ParserFree(ctx.filelists_parser);
rhughes@241
   446
ali@476
   447
	razor_stream_close(&primary);
ali@476
   448
	razor_stream_close(&filelists);
rhughes@241
   449
jbowes@263
   450
	printf ("\nsaving\n");
rhughes@241
   451
	return razor_importer_finish(ctx.importer);
rhughes@241
   452
}