src/import-yum.c
author James Bowes <jbowes@redhat.com>
Wed Jul 09 10:11:13 2008 -0400 (2008-07-09)
changeset 318 829d6711b316
parent 259 5b0601d184ed
child 333 1829493b5fb9
permissions -rw-r--r--
Use strings to identify section types in the on-disk repo format.

Previously, a given razor file type had a fixed number of sections in a
fixed order, identified by an integer type. Now, sections are identified
by a named string (stored in a string pool after the section lists).

This will allow for razor files to contain arbitrary sections.

For bonus points, also drop the 4k section alignment and change the
magic byte string to "RZDB".

committer: Kristian H?gsberg <krh@redhat.com>
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; either version 2 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along
    16  * with this program; if not, write to the Free Software Foundation, Inc.,
    17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    18  */
    19 
    20 #define _GNU_SOURCE
    21 
    22 #include <string.h>
    23 #include <stdio.h>
    24 #include <stdint.h>
    25 #include <sys/stat.h>
    26 #include <sys/mman.h>
    27 #include <unistd.h>
    28 #include <fcntl.h>
    29 #include <errno.h>
    30 
    31 #include <expat.h>
    32 #include <zlib.h>
    33 #include "razor.h"
    34 
    35 /* Import a yum filelist as a razor package set. */
    36 
    37 enum {
    38 	YUM_STATE_BEGIN,
    39 	YUM_STATE_PACKAGE_NAME,
    40 	YUM_STATE_PACKAGE_ARCH,
    41 	YUM_STATE_SUMMARY,
    42 	YUM_STATE_DESCRIPTION,
    43 	YUM_STATE_URL,
    44 	YUM_STATE_LICENSE,
    45 	YUM_STATE_CHECKSUM,
    46 	YUM_STATE_REQUIRES,
    47 	YUM_STATE_PROVIDES,
    48 	YUM_STATE_OBSOLETES,
    49 	YUM_STATE_CONFLICTS,
    50 	YUM_STATE_FILE
    51 };
    52 
    53 struct yum_context {
    54 	XML_Parser primary_parser;
    55 	XML_Parser filelists_parser;
    56 	XML_Parser current_parser;
    57 
    58 	struct razor_importer *importer;
    59 	struct import_property_context *current_property_context;
    60 	char name[256], arch[64], summary[512], description[4096];
    61 	char url[256], license[64], buffer[512], *p;
    62 	char pkgid[128];
    63 	uint32_t property_type;
    64 	int state;
    65 
    66 	int total, current;
    67 };
    68 
    69 static uint32_t
    70 yum_to_razor_relation (const char *flags)
    71 {
    72 	if (flags[0] == 'L') {
    73 		if (flags[1] == 'T')
    74 			return RAZOR_PROPERTY_LESS;
    75 		else
    76 			return RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL;
    77 	} else if (flags[0] == 'G') {
    78 		if (flags[1] == 'T')
    79 			return RAZOR_PROPERTY_GREATER;
    80 		else
    81 			return RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL;
    82 	} else
    83 		return RAZOR_PROPERTY_EQUAL;
    84 }
    85 
    86 static void
    87 yum_primary_start_element(void *data, const char *name, const char **atts)
    88 {
    89 	struct yum_context *ctx = data;
    90 	const char *n, *epoch, *version, *release;
    91 	char buffer[128];
    92 	uint32_t pre, relation, flags;
    93 	int i;
    94 
    95 	if (strcmp(name, "metadata") == 0) {
    96 		for (i = 0; atts[i]; i += 2) {
    97 			if (strcmp(atts[i], "packages") == 0)
    98 				ctx->total = atoi(atts[i + 1]);
    99 		}
   100 	} else if (strcmp(name, "name") == 0) {
   101 		ctx->state = YUM_STATE_PACKAGE_NAME;
   102 		ctx->p = ctx->name;
   103 	} else if (strcmp(name, "arch") == 0) {
   104 		ctx->state = YUM_STATE_PACKAGE_ARCH;
   105 		ctx->p = ctx->arch;
   106 	} else if (strcmp(name, "version") == 0) {
   107 		epoch = NULL;
   108 		version = NULL;
   109 		release = NULL;
   110 		for (i = 0; atts[i]; i += 2) {
   111 			if (strcmp(atts[i], "epoch") == 0)
   112 				epoch = atts[i + 1];
   113 			else if (strcmp(atts[i], "ver") == 0)
   114 				version = atts[i + 1];
   115 			else if (strcmp(atts[i], "rel") == 0)
   116 				release = atts[i + 1];
   117 		}
   118 		if (version == NULL || release == NULL) {
   119 			fprintf(stderr, "invalid version tag, "
   120 				"missing version or  release attribute\n");
   121 			return;
   122 		}
   123 
   124 		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
   125 		razor_importer_begin_package(ctx->importer,
   126 					     ctx->name, buffer, ctx->arch);
   127 	} else if (strcmp(name, "summary") == 0) {
   128 		ctx->p = ctx->summary;
   129 		ctx->state = YUM_STATE_SUMMARY;
   130 	} else if (strcmp(name, "description") == 0) {
   131 		ctx->p = ctx->description;
   132 		ctx->state = YUM_STATE_DESCRIPTION;
   133 	} else if (strcmp(name, "url") == 0) {
   134 		ctx->p = ctx->url;
   135 		ctx->state = YUM_STATE_URL;
   136 	} else if (strcmp(name, "checksum") == 0) {
   137 		ctx->p = ctx->pkgid;
   138 		ctx->state = YUM_STATE_CHECKSUM;
   139 	} else if (strcmp(name, "rpm:license") == 0) {
   140 		ctx->p = ctx->license;
   141 		ctx->state = YUM_STATE_LICENSE;
   142 	} else if (strcmp(name, "rpm:requires") == 0) {
   143 		ctx->state = YUM_STATE_REQUIRES;
   144 		ctx->property_type = RAZOR_PROPERTY_REQUIRES;
   145 	} else if (strcmp(name, "rpm:provides") == 0) {
   146 		ctx->state = YUM_STATE_PROVIDES;
   147 		ctx->property_type = RAZOR_PROPERTY_PROVIDES;
   148 	} else if (strcmp(name, "rpm:obsoletes") == 0) {
   149 		ctx->state = YUM_STATE_OBSOLETES;
   150 		ctx->property_type = RAZOR_PROPERTY_OBSOLETES;
   151 	} else if (strcmp(name, "rpm:conflicts") == 0) {
   152 		ctx->state = YUM_STATE_CONFLICTS;
   153 		ctx->property_type = RAZOR_PROPERTY_CONFLICTS;
   154 	} else if (strcmp(name, "rpm:entry") == 0 &&
   155 		   ctx->state != YUM_STATE_BEGIN) {
   156 		n = NULL;
   157 		epoch = NULL;
   158 		version = NULL;
   159 		release = NULL;
   160 		relation = RAZOR_PROPERTY_EQUAL;
   161 		pre = 0;
   162 		for (i = 0; atts[i]; i += 2) {
   163 			if (strcmp(atts[i], "name") == 0)
   164 				n = atts[i + 1];
   165 			else if (strcmp(atts[i], "epoch") == 0)
   166 				epoch = atts[i + 1];
   167 			else if (strcmp(atts[i], "ver") == 0)
   168 				version = atts[i + 1];
   169 			else if (strcmp(atts[i], "rel") == 0)
   170 				release = atts[i + 1];
   171 			else if (strcmp(atts[i], "flags") == 0)
   172 				relation = yum_to_razor_relation(atts[i + 1]);
   173 			else if (strcmp(atts[i], "pre") == 0)
   174 				pre = 
   175 					RAZOR_PROPERTY_PRE |
   176 					RAZOR_PROPERTY_POST |
   177 					RAZOR_PROPERTY_PREUN |
   178 					RAZOR_PROPERTY_POSTUN;
   179 		}
   180 
   181 		if (n == NULL) {
   182 			fprintf(stderr, "invalid rpm:entry, "
   183 				"missing name or version attributes\n");
   184 			return;
   185 		}
   186 
   187 		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
   188 		flags = ctx->property_type | relation | pre;
   189 		razor_importer_add_property(ctx->importer, n, flags, buffer);
   190 	}
   191 }
   192 
   193 static void
   194 yum_primary_end_element (void *data, const char *name)
   195 {
   196 	struct yum_context *ctx = data;
   197 
   198 	switch (ctx->state) {
   199 	case YUM_STATE_PACKAGE_NAME:
   200 	case YUM_STATE_PACKAGE_ARCH:
   201 	case YUM_STATE_SUMMARY:
   202 	case YUM_STATE_DESCRIPTION:
   203 	case YUM_STATE_URL:
   204 	case YUM_STATE_LICENSE:
   205 	case YUM_STATE_CHECKSUM:
   206 	case YUM_STATE_FILE:
   207 		ctx->state = YUM_STATE_BEGIN;
   208 		break;
   209 	}
   210 
   211 	if (strcmp(name, "package") == 0) {
   212 		razor_importer_add_details(ctx->importer, ctx->summary,
   213 					   ctx->description, ctx->url,
   214 					   ctx->license);
   215 
   216 		XML_StopParser(ctx->current_parser, XML_TRUE);
   217 		ctx->current_parser = ctx->filelists_parser;
   218 
   219 		printf("\rimporting %d/%d", ++ctx->current, ctx->total);
   220 		fflush(stdout);
   221 	}
   222 }
   223 
   224 static void
   225 yum_character_data (void *data, const XML_Char *s, int len)
   226 {
   227 	struct yum_context *ctx = data;
   228 
   229 	switch (ctx->state) {
   230 	case YUM_STATE_PACKAGE_NAME:
   231 	case YUM_STATE_PACKAGE_ARCH:
   232 	case YUM_STATE_SUMMARY:
   233 	case YUM_STATE_DESCRIPTION:
   234 	case YUM_STATE_URL:
   235 	case YUM_STATE_LICENSE:
   236 	case YUM_STATE_CHECKSUM:
   237 	case YUM_STATE_FILE:
   238 		memcpy(ctx->p, s, len);
   239 		ctx->p += len;
   240 		*ctx->p = '\0';
   241 		break;
   242 	}
   243 }
   244 
   245 static void
   246 yum_filelists_start_element(void *data, const char *name, const char **atts)
   247 {
   248 	struct yum_context *ctx = data;
   249 	const char *pkg, *pkgid;
   250 	int i;
   251 
   252 	if (strcmp(name, "package") == 0) {
   253 		pkg = NULL;
   254 		pkgid = NULL;
   255 		for (i = 0; atts[i]; i += 2) {
   256 			if (strcmp(atts[i], "name") == 0)
   257 				pkg = atts[i + 1];
   258 			else if (strcmp(atts[i], "pkgid") == 0)
   259 				pkgid = atts[i + 1];
   260 		}
   261 		if (strcmp(pkgid, ctx->pkgid) != 0)
   262 			fprintf(stderr, "primary.xml and filelists.xml "
   263 				"mismatch for %s: %s vs %s",
   264 				pkg, pkgid, ctx->pkgid);
   265 	} else if (strcmp(name, "file") == 0) {
   266 		ctx->state = YUM_STATE_FILE;
   267 		ctx->p = ctx->buffer;
   268 	}
   269 }
   270 
   271 
   272 static void
   273 yum_filelists_end_element (void *data, const char *name)
   274 {
   275 	struct yum_context *ctx = data;
   276 
   277 	ctx->state = YUM_STATE_BEGIN;
   278 	if (strcmp(name, "package") == 0) {
   279 		XML_StopParser(ctx->current_parser, XML_TRUE);
   280 		ctx->current_parser = ctx->primary_parser;
   281 		razor_importer_finish_package(ctx->importer);
   282 	} else if (strcmp(name, "file") == 0)
   283 		razor_importer_add_file(ctx->importer, ctx->buffer);
   284 
   285 }
   286 
   287 #define XML_BUFFER_SIZE 4096
   288 
   289 struct razor_set *
   290 razor_set_create_from_yum(void)
   291 {
   292 	struct yum_context ctx;
   293 	void *buf;
   294 	int len, ret;
   295 	gzFile primary, filelists;
   296 	XML_ParsingStatus status;
   297 
   298 	ctx.importer = razor_importer_create();
   299 	ctx.state = YUM_STATE_BEGIN;
   300 
   301 	ctx.primary_parser = XML_ParserCreate(NULL);
   302 	XML_SetUserData(ctx.primary_parser, &ctx);
   303 	XML_SetElementHandler(ctx.primary_parser,
   304 			      yum_primary_start_element,
   305 			      yum_primary_end_element);
   306 	XML_SetCharacterDataHandler(ctx.primary_parser,
   307 				    yum_character_data);
   308 
   309 	ctx.filelists_parser = XML_ParserCreate(NULL);
   310 	XML_SetUserData(ctx.filelists_parser, &ctx);
   311 	XML_SetElementHandler(ctx.filelists_parser,
   312 			      yum_filelists_start_element,
   313 			      yum_filelists_end_element);
   314 	XML_SetCharacterDataHandler(ctx.filelists_parser,
   315 				    yum_character_data);
   316 
   317 	primary = gzopen("primary.xml.gz", "rb");
   318 	if (primary == NULL)
   319 		return NULL;
   320 	filelists = gzopen("filelists.xml.gz", "rb");
   321 	if (filelists == NULL)
   322 		return NULL;
   323 
   324 	ctx.current_parser = ctx.primary_parser;
   325 
   326 	ctx.current = 0;
   327 
   328 	do {
   329 		XML_GetParsingStatus(ctx.current_parser, &status);
   330 		switch (status.parsing) {
   331 		case XML_SUSPENDED:
   332 			ret = XML_ResumeParser(ctx.current_parser);
   333 			break;
   334 		case XML_PARSING:
   335 		case XML_INITIALIZED:
   336 			buf = XML_GetBuffer(ctx.current_parser,
   337 					    XML_BUFFER_SIZE);
   338 			if (ctx.current_parser == ctx.primary_parser)
   339 				len = gzread(primary, buf, XML_BUFFER_SIZE);
   340 			else
   341 				len = gzread(filelists, buf, XML_BUFFER_SIZE);
   342 			if (len < 0) {
   343 				fprintf(stderr,
   344 					"couldn't read input: %s\n",
   345 					strerror(errno));
   346 				return NULL;
   347 			}
   348 
   349 			XML_ParseBuffer(ctx.current_parser, len, len == 0);
   350 			break;
   351 		case XML_FINISHED:
   352 			break;
   353 		}
   354 	} while (status.parsing != XML_FINISHED);
   355 
   356 
   357 	XML_ParserFree(ctx.primary_parser);
   358 	XML_ParserFree(ctx.filelists_parser);
   359 
   360 	gzclose(primary);
   361 	gzclose(filelists);
   362 
   363 	printf ("\nsaving\n");
   364 	return razor_importer_finish(ctx.importer);
   365 }