rpm.c
author Kristian H?gsberg <krh@jiraiya.boston.redhat.com>
Wed Apr 09 02:41:03 2008 -0400 (2008-04-09)
changeset 211 cf0ca962262b
parent 202 e8594c82dffc
child 212 e8f493d8ff9a
permissions -rw-r--r--
Use the cpio headers instead of the rpm headers when unpacking.

The files in the cpio payload doesn't actually follow the file order
in the rpm headers, so we need to decode the cpio header and use the
information there.
     1 #include <stdio.h>
     2 #include <stddef.h>
     3 #include <string.h>
     4 #include <errno.h>
     5 #include <sys/stat.h>
     6 #include <sys/mman.h>
     7 #include <sys/types.h>
     8 #include <sys/wait.h>
     9 #include <fcntl.h>
    10 #include <unistd.h>
    11 #include <arpa/inet.h>
    12 #include <rpm/rpmlib.h>
    13 #include <rpm/rpmdb.h>
    14 #include <zlib.h>
    15 
    16 #include "razor.h"
    17 #include "razor-internal.h"
    18 
    19 #define	RPM_LEAD_SIZE 96
    20 
    21 struct rpm_header {
    22 	unsigned char magic[4];
    23 	unsigned char reserved[4];
    24 	int nindex;
    25 	int hsize;
    26 };
    27 
    28 struct rpm_header_index {
    29 	int tag;
    30 	int type;
    31 	int offset;
    32 	int count;
    33 };
    34 
    35 struct razor_rpm {
    36 	struct rpm_header *signature;
    37 	struct rpm_header *header;
    38 	const char **dirs;
    39 	const char *pool;
    40 	void *map;
    41 	size_t size;
    42 	void *payload;
    43 };
    44 
    45 static struct rpm_header_index *
    46 razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag)
    47 {
    48 	struct rpm_header_index *index, *end;
    49 
    50 	index = (struct rpm_header_index *) (rpm->header + 1);
    51 	end = index + ntohl(rpm->header->nindex);
    52 	while (index < end) {
    53 		if (ntohl(index->tag) == tag)
    54 			return index;
    55 		index++;
    56 	}
    57 
    58 	return NULL;
    59 }
    60 
    61 static const void *
    62 razor_rpm_get_indirect(struct razor_rpm *rpm,
    63 		       unsigned int tag, unsigned int *count)
    64 {
    65 	struct rpm_header_index *index;
    66 
    67 	index = razor_rpm_get_header(rpm, tag);
    68 	if (index != NULL) {
    69 		if (count)
    70 			*count = ntohl(index->count);
    71 
    72 		return rpm->pool + ntohl(index->offset);
    73 	}
    74 
    75 	return NULL;
    76 }
    77 
    78 static enum razor_version_relation
    79 rpm_to_razor_flags (uint_32 flags)
    80 {
    81 	switch (flags & (RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_GREATER)) {
    82 	case RPMSENSE_LESS:
    83 		return RAZOR_VERSION_LESS;
    84 	case RPMSENSE_LESS|RPMSENSE_EQUAL:
    85 		return RAZOR_VERSION_LESS_OR_EQUAL;
    86 	case RPMSENSE_EQUAL:
    87 		return RAZOR_VERSION_EQUAL;
    88 	case RPMSENSE_GREATER|RPMSENSE_EQUAL:
    89 		return RAZOR_VERSION_GREATER_OR_EQUAL;
    90 	case RPMSENSE_GREATER:
    91 		return RAZOR_VERSION_GREATER;
    92 	}
    93 
    94 	/* FIXME? */
    95 	return RAZOR_VERSION_EQUAL;
    96 }
    97 
    98 static void
    99 import_properties(struct razor_importer *importer, unsigned long type,
   100 		  struct razor_rpm *rpm,
   101 		  int name_tag, int version_tag, int flags_tag)
   102 {
   103 	const char *name, *version;
   104 	const uint_32 *flags;
   105 	uint_32 f;
   106 	unsigned int i, count;
   107 
   108 	name = razor_rpm_get_indirect(rpm, name_tag, &count);
   109 	if (name == NULL)
   110 		return;
   111 
   112 	flags = razor_rpm_get_indirect(rpm, flags_tag, &count);
   113 
   114 	version = razor_rpm_get_indirect(rpm, version_tag, &count);
   115 	for (i = 0; i < count; i++) {
   116 		f = rpm_to_razor_flags(ntohl(flags[i]));
   117 		razor_importer_add_property(importer, name, f, version, type);
   118 		name += strlen(name) + 1;
   119 		version += strlen(version) + 1;
   120 	}
   121 }
   122 
   123 static void
   124 import_files(struct razor_importer *importer, struct razor_rpm *rpm)
   125 {
   126 	const char *name;
   127 	const uint32_t *index;
   128 	unsigned int i, count;
   129 	char buffer[256];
   130 
   131 	/* assert: count is the same for all arrays */
   132 
   133 	index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count);
   134 	name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count);
   135 	for (i = 0; i < count; i++) {
   136 		snprintf(buffer, sizeof buffer,
   137 			 "%s%s", rpm->dirs[ntohl(*index)], name);
   138 		razor_importer_add_file(importer, buffer);
   139 		name += strlen(name) + 1;
   140 		index++;
   141 	}
   142 }
   143 
   144 struct razor_rpm *
   145 razor_rpm_open(const char *filename)
   146 {
   147 	struct razor_rpm *rpm;
   148 	struct rpm_header_index *base, *index;
   149 	struct stat buf;
   150 	unsigned int count, i, nindex, hsize;
   151 	const char *name;
   152 	int fd;
   153 
   154 	rpm = malloc(sizeof *rpm);
   155 	memset(rpm, 0, sizeof *rpm);
   156 
   157 	fd = open(filename, O_RDONLY);
   158 	if (fd < 0) {
   159 		fprintf(stderr, "couldn't open %s\n", filename);
   160 		return NULL;
   161 	}
   162 
   163 	if (fstat(fd, &buf) < 0) {
   164 		fprintf(stderr, "failed to stat %s (%m)\n", filename);
   165 		return NULL;
   166 	}
   167 
   168 	rpm->size = buf.st_size;
   169 	rpm->map = mmap(NULL, rpm->size, PROT_READ, MAP_PRIVATE, fd, 0);
   170 	if (rpm->map == MAP_FAILED) {
   171 		fprintf(stderr, "couldn't mmap %s\n", filename);
   172 		return NULL;
   173 	}
   174 	close(fd);
   175 
   176 	rpm->signature = rpm->map + RPM_LEAD_SIZE;
   177 	nindex = ntohl(rpm->signature->nindex);
   178 	hsize = ntohl(rpm->signature->hsize);
   179 	rpm->header = (void *) (rpm->signature + 1) +
   180 		ALIGN(nindex * sizeof *index + hsize, 8);
   181 	nindex = ntohl(rpm->header->nindex);
   182 	hsize = ntohl(rpm->header->hsize);
   183 	rpm->payload = (void *) (rpm->header + 1) +
   184 		nindex * sizeof *index + hsize;
   185 
   186 	base = (struct rpm_header_index *) (rpm->header + 1);
   187 	rpm->pool = (void *) base + nindex * sizeof *index;
   188 
   189 	/* Look up dir names now so we can index them directly. */
   190 	name = razor_rpm_get_indirect(rpm, RPMTAG_DIRNAMES, &count);
   191 	if (name) {
   192 		rpm->dirs = calloc(count, sizeof *rpm->dirs);
   193 		for (i = 0; i < count; i++) {
   194 			rpm->dirs[i] = name;
   195 			name += strlen(name) + 1;
   196 		}
   197 	} else {
   198 		name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES,
   199 					      &count);
   200 		if (name) {
   201 			fprintf(stderr, "old filenames not supported\n");
   202 			return NULL;
   203 		}
   204 	}
   205 
   206 	return rpm;
   207 }
   208 
   209 struct cpio_file_header {
   210 	char magic[6];
   211 	char inode[8];
   212 	char mode[8];
   213 	char uid[8];
   214 	char gid[8];
   215 	char nlink[8];
   216 	char mtime[8];
   217 	char filesize[8];
   218 	char devmajor[8];
   219 	char devminor[8];
   220 	char rdevmajor[8];
   221 	char rdevminor[8];
   222 	char namesize[8];
   223 	char checksum[8];
   224 	char filename[0];
   225 };
   226 
   227 /* gzip flags */
   228 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
   229 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
   230 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
   231 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
   232 #define COMMENT      0x10 /* bit 4 set: file comment present */
   233 #define RESERVED     0xE0 /* bits 5..7: reserved */
   234 
   235 struct installer {
   236 	const char *root;
   237 	struct razor_rpm *rpm;
   238 	z_stream stream;
   239 	unsigned char buffer[32768];
   240 	size_t rest, length;
   241 };
   242 
   243 static int
   244 installer_inflate(struct installer *installer)
   245 {
   246 	size_t length;
   247 	int err;
   248 
   249 	if (installer->rest > sizeof installer->buffer)
   250 		length = sizeof installer->buffer;
   251 	else
   252 		length = installer->rest;
   253 
   254 	installer->stream.next_out = installer->buffer;
   255 	installer->stream.avail_out = length;
   256 	err = inflate(&installer->stream, Z_SYNC_FLUSH);
   257 	if (err != Z_OK && err != Z_STREAM_END) {
   258 		fprintf(stderr, "inflate error: %d (%m)\n", err);
   259 		return -1;
   260 	}
   261 
   262 	installer->rest -= length;
   263 	installer->length = length;
   264 
   265 	return 0;
   266 }
   267 
   268 static int
   269 installer_align(struct installer *installer, size_t size)
   270 {
   271 	unsigned char buffer[4];
   272 	int err;
   273 
   274 	installer->stream.next_out = buffer;
   275 	installer->stream.avail_out =
   276 		(size - installer->stream.total_out) & (size - 1);
   277 
   278 	if (installer->stream.avail_out == 0)
   279 		return 0;
   280 
   281 	err = inflate(&installer->stream, Z_SYNC_FLUSH);
   282 	if (err != Z_OK && err != Z_STREAM_END) {
   283 		fprintf(stderr, "inflate error: %d (%m)\n", err);
   284 		return -1;
   285 	}
   286 
   287 	return 0;
   288 }
   289 
   290 static int
   291 create_path(struct installer *installer, const char *path, unsigned int mode)
   292 {
   293 	char buffer[PATH_MAX];
   294 	struct stat buf;
   295 	int fd, ret;
   296 
   297 	if (razor_create_dir(installer->root, path) < 0)
   298 		return -1;
   299 
   300 	snprintf(buffer, sizeof buffer, "%s%s", installer->root, path);
   301 
   302 	switch (mode >> 12) {
   303 	case REG:
   304 		/* FIXME: handle the case where a file is already there. */
   305 		fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, mode & 0x1ff);
   306 		if (fd < 0){
   307 			fprintf(stderr, "failed to create file %s\n", buffer);
   308 			return -1;
   309 		}
   310 		while (installer->rest > 0) {
   311 			if (installer_inflate(installer)) {
   312 				fprintf(stderr, "failed to inflate\n");
   313 				return -1;
   314 			}
   315 			if (razor_write(fd, installer->buffer,
   316 					installer->length)) {
   317 				fprintf(stderr, "failed to write payload\n");
   318 				return -1;
   319 			}
   320 		}
   321 		if (close(fd) < 0) {
   322 			fprintf(stderr, "failed to close %s: %m\n", buffer);
   323 			return -1;
   324 		}
   325 		return 0;
   326 	case XDIR:
   327 		ret = mkdir(buffer, mode & 0x1ff);
   328 		if (ret == 0 || errno != EEXIST)
   329 			return ret;
   330 		if (stat(buffer, &buf) || !S_ISDIR(buf.st_mode)) {
   331 			/* FIXME: also check that mode match. */
   332 			fprintf(stderr,
   333 				"%s exists but is not a directory\n", buffer);
   334 			return -1;
   335 		}
   336 		return 0;
   337 	case PIPE:
   338 	case CDEV:
   339 	case BDEV:
   340 	case SOCK:
   341 		printf("%s: unhandled file type %d\n", buffer, mode >> 12);
   342 		return 0;
   343 	case LINK:
   344 		if (installer_inflate(installer)) {
   345 			fprintf(stderr, "failed to inflate\n");
   346 			return -1;
   347 		}
   348 		if (installer->length >= sizeof installer->buffer) {
   349 			fprintf(stderr, "link name too long\n");
   350 			return -1;
   351 		}
   352 		installer->buffer[installer->length] = '\0';
   353 		if (symlink((const char *) installer->buffer, buffer)) {
   354 			fprintf(stderr, "failed to create symlink, %m\n");
   355 			return -1;
   356 		}
   357 		return 0;
   358 	default:
   359 		printf("%s: unknown file type %d\n", buffer, mode >> 12);
   360 		return 0;
   361 	}
   362 }
   363 
   364 static int
   365 run_script(struct installer *installer,
   366 	   unsigned int program_tag, unsigned int script_tag)
   367 {
   368 	int pid, status, fd[2];
   369 	const char *script = NULL, *program = NULL;
   370 
   371 	program = razor_rpm_get_indirect(installer->rpm, program_tag, NULL);
   372 	script = razor_rpm_get_indirect(installer->rpm, script_tag, NULL);
   373 	if (program == NULL && script == NULL) {
   374 		return 0;
   375 	} else if (program == NULL) {
   376 		program = "/bin/sh";
   377 	}
   378 
   379 	if (pipe(fd) < 0) {
   380 		fprintf(stderr, "failed to create pipe\n");
   381 		return -1;
   382 	}
   383 	pid = fork();
   384 	if (pid < 0) {
   385 		fprintf(stderr, "failed to fork, %m\n");
   386 	} else if (pid == 0) {
   387 		if (dup2(fd[0], STDIN_FILENO) < 0) {
   388 			fprintf(stderr, "failed redirect stdin, %m\n");
   389 			return -1;
   390 		}
   391 		if (close(fd[0]) < 0 || close(fd[1]) < 0) {
   392 			fprintf(stderr, "failed to close pipe, %m\n");
   393 			return -1;
   394 		}
   395 		if (chroot(installer->root) < 0) {
   396 			fprintf(stderr, "failed to chroot to %s, %m\n",
   397 				installer->root);
   398 			return -1;
   399 		}
   400 		printf("executing program %s in chroot %s\n",
   401 		       program, installer->root);
   402 		if (execl(program, program, NULL)) {
   403 			fprintf(stderr, "failed to exec %s, %m\n", program);
   404 			exit(-1);
   405 		}
   406 	} else {
   407 		if (script && razor_write(fd[1], script, strlen(script)) < 0) {
   408 			fprintf(stderr, "failed to pipe script, %m\n");
   409 			return -1;
   410 		}
   411 		if (close(fd[0]) || close(fd[1])) {
   412 			fprintf(stderr, "failed to close pipe, %m\n");
   413 			return -1;
   414 		}
   415 		if (wait(&status) < 0) {
   416 			fprintf(stderr, "wait for child failed, %m");
   417 			return -1;
   418 		}
   419 		if (status)
   420 			printf("script exited with status %d\n", status);
   421 	}
   422 
   423 	return 0;
   424 }
   425 
   426 static int
   427 installer_init(struct installer *installer)
   428 {
   429 	unsigned char *gz_header;
   430 	int method, flags, err;
   431 
   432 	gz_header = installer->rpm->payload;
   433 	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
   434 		fprintf(stderr, "payload section doesn't have gz header\n");
   435 		return -1;
   436 	}
   437 
   438 	method = gz_header[2];
   439 	flags = gz_header[3];
   440 
   441 	if (method != Z_DEFLATED || flags != 0) {
   442 		fprintf(stderr,
   443 			"unknown payload compression method or flags set\n");
   444 		return -1;
   445 	}
   446 
   447 	installer->stream.zalloc = NULL;
   448 	installer->stream.zfree = NULL;
   449 	installer->stream.opaque = NULL;
   450 
   451 	installer->stream.next_in  = gz_header + 10;
   452 	installer->stream.avail_in =
   453 		(installer->rpm->map + installer->rpm->size) -
   454 		(void *) installer->stream.next_in;
   455 	installer->stream.next_out = NULL;
   456 	installer->stream.avail_out = 0;
   457 
   458 	err = inflateInit2(&installer->stream, -MAX_WBITS);
   459 	if (err != Z_OK) {
   460 		fprintf(stderr, "inflateInit error: %d\n", err);
   461 		return -1;
   462 	}
   463 
   464 	return 0;
   465 }
   466 
   467 static int
   468 installer_finish(struct installer *installer)
   469 {
   470 	int err;
   471 
   472 	err = inflateEnd(&installer->stream);
   473 
   474 	if (err != Z_OK) {
   475 		fprintf(stderr, "inflateEnd error: %d\n", err);
   476 		return -1;
   477 	}	    
   478 
   479 	return 0;
   480 }
   481 
   482 static unsigned long
   483 fixed_hex_to_ulong(const char *hex, int length)
   484 {
   485 	long l;
   486 	int i;
   487 
   488 	for (i = 0, l = 0; i < length; i++) {
   489 		if (hex[i] < 'a')
   490 			l = l * 16 + hex[i] - '0';
   491 		else
   492 			l = l * 16 + hex[i] - 'a' + 10;
   493 	}
   494 
   495 	return l;
   496 }
   497 
   498 int
   499 razor_rpm_install(struct razor_rpm *rpm, const char *root)
   500 {
   501 	struct installer installer;
   502 	struct cpio_file_header *header;
   503 	struct stat buf;
   504 	unsigned int mode;
   505 	char *path;
   506 	size_t filesize;
   507 
   508 	installer.rpm = rpm;
   509 	installer.root = root;
   510 
   511 	/* FIXME: Only do this before a transaction, not per rpm. */
   512 	if (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode)) {
   513 		fprintf(stderr,
   514 			"root installation directory \"%s\" does not exist\n",
   515 			root);
   516 		return -1;
   517 	}
   518 
   519 	if (installer_init(&installer))
   520 		return -1;
   521 
   522 	run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN);
   523 
   524 	while (installer.stream.avail_in > 0) {
   525 		installer.rest = sizeof *header;
   526 		if (installer_inflate(&installer))
   527 			return -1;
   528 		
   529 		header = (struct cpio_file_header *) installer.buffer;
   530 		mode = fixed_hex_to_ulong(header->mode, sizeof header->mode);
   531 		filesize = fixed_hex_to_ulong(header->filesize,
   532 					      sizeof header->filesize);
   533 
   534 		installer.rest = fixed_hex_to_ulong(header->namesize,
   535 						    sizeof header->namesize);
   536 
   537 		if (installer_inflate(&installer) ||
   538 		    installer_align(&installer, 4))
   539 			return -1;
   540 
   541 		path = (char *) installer.buffer;
   542 		/* This convention is so lame... */
   543 		if (strcmp(path, "TRAILER!!!") == 0)
   544 			break;
   545 
   546 		installer.rest = filesize;
   547 		if (create_path(&installer, path + 1, mode) < 0)
   548 			return -1;
   549 		if (installer_align(&installer, 4))
   550 			return -1;
   551 	}
   552 
   553 	if (installer_finish(&installer))
   554 		return -1;
   555 
   556 	run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN);
   557 
   558 	return 0;
   559 }
   560 
   561 int
   562 razor_rpm_close(struct razor_rpm *rpm)
   563 {
   564 	int err;
   565 
   566 	free(rpm->dirs);
   567 	err = munmap(rpm->map, rpm->size);
   568 	free(rpm);
   569 
   570 	return err;
   571 }
   572 
   573 int
   574 razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
   575 {
   576 	const char *name, *version, *release, *arch;
   577 	const uint_32 *epoch;
   578 	char evr[128], buf[16];
   579 
   580 	name = razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL);
   581 	epoch = razor_rpm_get_indirect(rpm, RPMTAG_EPOCH, NULL);
   582 	version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL);
   583 	release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL);
   584 	arch = razor_rpm_get_indirect(rpm, RPMTAG_ARCH, NULL);
   585 
   586 	if (epoch) {
   587 		snprintf(buf, sizeof buf, "%u", ntohl(*epoch));
   588 		razor_build_evr(evr, sizeof evr, buf, version, release);
   589 	} else {
   590 		razor_build_evr(evr, sizeof evr, NULL, version, release);
   591 	}
   592 	razor_importer_begin_package(importer, name, evr, arch);
   593 
   594 	import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
   595 			  RPMTAG_REQUIRENAME,
   596 			  RPMTAG_REQUIREVERSION,
   597 			  RPMTAG_REQUIREFLAGS);
   598 
   599 	import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
   600 			  RPMTAG_PROVIDENAME,
   601 			  RPMTAG_PROVIDEVERSION,
   602 			  RPMTAG_PROVIDEFLAGS);
   603 
   604 	import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
   605 			  RPMTAG_OBSOLETENAME,
   606 			  RPMTAG_OBSOLETEVERSION,
   607 			  RPMTAG_OBSOLETEFLAGS);
   608 
   609 	import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
   610 			  RPMTAG_CONFLICTNAME,
   611 			  RPMTAG_CONFLICTVERSION,
   612 			  RPMTAG_CONFLICTFLAGS);
   613 
   614 	import_files(importer, rpm);
   615 
   616 	razor_importer_finish_package(importer);
   617 
   618 	return 0;
   619 }
   620 
   621 union rpm_entry {
   622 	void *p;
   623 	char *string;
   624 	char **list;
   625 	uint_32 *flags;
   626 	uint_32 integer;
   627 };
   628 
   629 static void
   630 add_properties(struct razor_importer *importer,
   631 	       enum razor_property_type property_type,
   632 	       Header h, int_32 name_tag, int_32 version_tag, int_32 flags_tag)
   633 {
   634 	union rpm_entry names, versions, flags;
   635 	int_32 i, type, count;
   636 
   637 	headerGetEntry(h, name_tag, &type, &names.p, &count);
   638 	headerGetEntry(h, version_tag, &type, &versions.p, &count);
   639 	headerGetEntry(h, flags_tag, &type, &flags.p, &count);
   640 
   641 	for (i = 0; i < count; i++)
   642 		razor_importer_add_property(importer,
   643 					    names.list[i],
   644 					    rpm_to_razor_flags (flags.flags[i]),
   645 					    versions.list[i],
   646 					    property_type);
   647 }
   648 
   649 struct razor_set *
   650 razor_set_create_from_rpmdb(void)
   651 {
   652 	struct razor_importer *importer;
   653 	rpmdbMatchIterator iter;
   654 	Header h;
   655 	int_32 type, count, i;
   656 	union rpm_entry name, epoch, version, release, arch;
   657 	union rpm_entry basenames, dirnames, dirindexes;
   658 	char filename[PATH_MAX], evr[128], buf[16];
   659 	rpmdb db;
   660 
   661 	rpmReadConfigFiles(NULL, NULL);
   662 
   663 	if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
   664 		fprintf(stderr, "cannot open rpm database\n");
   665 		exit(1);
   666 	}
   667 
   668 	importer = razor_importer_new();
   669 
   670 	iter = rpmdbInitIterator(db, 0, NULL, 0);
   671 	while (h = rpmdbNextIterator(iter), h != NULL) {
   672 		headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count);
   673 		headerGetEntry(h, RPMTAG_EPOCH, &type, &epoch.p, &count);
   674 		headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count);
   675 		headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count);
   676 		headerGetEntry(h, RPMTAG_ARCH, &type, &arch.p, &count);
   677 
   678 		if (epoch.flags != NULL) {
   679 			snprintf(buf, sizeof buf, "%u", *epoch.flags);
   680 			razor_build_evr(evr, sizeof evr,
   681 					buf, version.string, release.string);
   682 		} else {
   683 			razor_build_evr(evr, sizeof evr,
   684 					NULL, version.string, release.string);
   685 		}
   686 
   687 		razor_importer_begin_package(importer,
   688 					     name.string, evr, arch.string);
   689 
   690 		add_properties(importer, RAZOR_PROPERTY_REQUIRES, h,
   691 			       RPMTAG_REQUIRENAME,
   692 			       RPMTAG_REQUIREVERSION,
   693 			       RPMTAG_REQUIREFLAGS);
   694 
   695 		add_properties(importer, RAZOR_PROPERTY_PROVIDES, h,
   696 			       RPMTAG_PROVIDENAME,
   697 			       RPMTAG_PROVIDEVERSION,
   698 			       RPMTAG_PROVIDEFLAGS);
   699 
   700 		add_properties(importer, RAZOR_PROPERTY_OBSOLETES, h,
   701 			       RPMTAG_OBSOLETENAME,
   702 			       RPMTAG_OBSOLETEVERSION,
   703 			       RPMTAG_OBSOLETEFLAGS);
   704 
   705 		add_properties(importer, RAZOR_PROPERTY_CONFLICTS, h,
   706 			       RPMTAG_CONFLICTNAME,
   707 			       RPMTAG_CONFLICTVERSION,
   708 			       RPMTAG_CONFLICTFLAGS);
   709 
   710 		headerGetEntry(h, RPMTAG_BASENAMES, &type,
   711 			       &basenames.p, &count);
   712 		headerGetEntry(h, RPMTAG_DIRNAMES, &type,
   713 			       &dirnames.p, &count);
   714 		headerGetEntry(h, RPMTAG_DIRINDEXES, &type,
   715 			       &dirindexes.p, &count);
   716 		for (i = 0; i < count; i++) {
   717 			snprintf(filename, sizeof filename, "%s%s",
   718 				 dirnames.list[dirindexes.flags[i]],
   719 				 basenames.list[i]);
   720 			razor_importer_add_file(importer, filename);
   721 		}
   722 
   723 		razor_importer_finish_package(importer);
   724 	}
   725 
   726 	rpmdbClose(db);
   727 
   728 	return razor_importer_finish(importer);
   729 }