rpm.c
author Kristian H?gsberg <krh@redhat.com>
Mon Apr 07 00:02:01 2008 -0400 (2008-04-07)
changeset 195 7a53d1711083
parent 185 f70e15405b5f
child 198 d26bdf77569d
permissions -rw-r--r--
Finish razor_transaction_destroy some more.
     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 (ALIGN(installer->rest, 4) > 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 = ALIGN(length, 4);
   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 create_path(struct installer *installer,
   270 	    const char *path, const char *name, unsigned int mode)
   271 {
   272 	char buffer[PATH_MAX];
   273 	struct stat buf;
   274 	int fd, ret;
   275 
   276 	if (razor_create_dir(installer->root, path) < 0)
   277 		return -1;
   278 
   279 	/* assertion: root doesn't end in a slash, path begins and end
   280 	 * with a slash, name does not begin with a slash. */
   281 	snprintf(buffer, sizeof buffer, "%s%s%s",
   282 		 installer->root, path, name);
   283 
   284 	switch (mode >> 12) {
   285 	case REG:
   286 		/* FIXME: handle the case where a file is already there. */
   287 		fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, mode & 0x1ff);
   288 		if (fd < 0){
   289 			fprintf(stderr, "failed to create file %s\n", buffer);
   290 			return -1;
   291 		}
   292 		while (installer->rest > 0) {
   293 			if (installer_inflate(installer)) {
   294 				fprintf(stderr, "failed to inflate\n");
   295 				return -1;
   296 			}
   297 			if (razor_write(fd, installer->buffer,
   298 					installer->length)) {
   299 				fprintf(stderr, "failed to write payload\n");
   300 				return -1;
   301 			}
   302 		}
   303 		if (close(fd) < 0) {
   304 			fprintf(stderr, "failed to close %s: %m\n", buffer);
   305 			return -1;
   306 		}
   307 		return 0;
   308 	case XDIR:
   309 		ret = mkdir(buffer, mode & 0x1ff);
   310 		if (ret == 0 || errno != EEXIST)
   311 			return ret;
   312 		if (stat(buffer, &buf) || !S_ISDIR(buf.st_mode)) {
   313 			/* FIXME: also check that mode match. */
   314 			fprintf(stderr,
   315 				"%s exists but is not a directory\n", buffer);
   316 			return -1;
   317 		}
   318 		return 0;
   319 	case PIPE:
   320 	case CDEV:
   321 	case BDEV:
   322 	case SOCK:
   323 		printf("%s: unhandled file type %d\n", buffer, mode >> 12);
   324 		return 0;
   325 	case LINK:
   326 		if (installer_inflate(installer)) {
   327 			fprintf(stderr, "failed to inflate\n");
   328 			return -1;
   329 		}
   330 		if (installer->length >= sizeof installer->buffer) {
   331 			fprintf(stderr, "link name too long\n");
   332 			return -1;
   333 		}
   334 		installer->buffer[installer->length] = '\0';
   335 		if (symlink((const char *) installer->buffer, buffer)) {
   336 			fprintf(stderr, "failed to create symlink, %m\n");
   337 			return -1;
   338 		}
   339 		return 0;
   340 	default:
   341 		printf("%s: unknown file type %d\n", buffer, mode >> 12);
   342 		return 0;
   343 	}
   344 }
   345 
   346 static int
   347 run_script(struct installer *installer,
   348 	   unsigned int program_tag, unsigned int script_tag)
   349 {
   350 	int pid, status, fd[2];
   351 	const char *script = NULL, *program = NULL;
   352 
   353 	program = razor_rpm_get_indirect(installer->rpm, program_tag, NULL);
   354 	script = razor_rpm_get_indirect(installer->rpm, script_tag, NULL);
   355 	if (program == NULL && script == NULL) {
   356 		printf("no script or program for tags %d and %d\n",
   357 		       program_tag, script_tag);
   358 		return -1;
   359 	} else if (program == NULL) {
   360 		program = "/bin/sh";
   361 	}
   362 
   363 	if (pipe(fd) < 0) {
   364 		fprintf(stderr, "failed to create pipe\n");
   365 		return -1;
   366 	}
   367 	pid = fork();
   368 	if (pid < 0) {
   369 		fprintf(stderr, "failed to fork, %m\n");
   370 	} else if (pid == 0) {
   371 		if (dup2(fd[0], STDIN_FILENO) < 0) {
   372 			fprintf(stderr, "failed redirect stdin, %m\n");
   373 			return -1;
   374 		}
   375 		if (close(fd[0]) < 0 || close(fd[1]) < 0) {
   376 			fprintf(stderr, "failed to close pipe, %m\n");
   377 			return -1;
   378 		}
   379 		if (chroot(installer->root) < 0) {
   380 			fprintf(stderr, "failed to chroot to %s, %m\n",
   381 				installer->root);
   382 			return -1;
   383 		}
   384 		printf("executing program %s in chroot %s\n",
   385 		       program, installer->root);
   386 		if (execl(program, program, NULL)) {
   387 			fprintf(stderr, "failed to exec %s, %m\n", program);
   388 			exit(-1);
   389 		}
   390 	} else {
   391 		if (script && razor_write(fd[1], script, strlen(script)) < 0) {
   392 			fprintf(stderr, "failed to pipe script, %m\n");
   393 			return -1;
   394 		}
   395 		if (close(fd[0]) || close(fd[1])) {
   396 			fprintf(stderr, "failed to close pipe, %m\n");
   397 			return -1;
   398 		}
   399 		if (wait(&status) < 0) {
   400 			fprintf(stderr, "wait for child failed, %m");
   401 			return -1;
   402 		}
   403 		printf("script exited with status %d\n", status);
   404 	}
   405 
   406 	return 0;
   407 }
   408 
   409 static int
   410 installer_init(struct installer *installer)
   411 {
   412 	unsigned char *gz_header;
   413 	int method, flags, err;
   414 
   415 	gz_header = installer->rpm->payload;
   416 	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
   417 		fprintf(stderr, "payload section doesn't have gz header\n");
   418 		return -1;
   419 	}
   420 
   421 	method = gz_header[2];
   422 	flags = gz_header[3];
   423 
   424 	if (method != Z_DEFLATED || flags != 0) {
   425 		fprintf(stderr,
   426 			"unknown payload compression method or flags set\n");
   427 		return -1;
   428 	}
   429 
   430 	installer->stream.zalloc = NULL;
   431 	installer->stream.zfree = NULL;
   432 	installer->stream.opaque = NULL;
   433 
   434 	installer->stream.next_in  = gz_header + 10;
   435 	installer->stream.avail_in =
   436 		(installer->rpm->map + installer->rpm->size) -
   437 		(void *) installer->stream.next_in;
   438 	installer->stream.next_out = NULL;
   439 	installer->stream.avail_out = 0;
   440 
   441 	err = inflateInit2(&installer->stream, -MAX_WBITS);
   442 	if (err != Z_OK) {
   443 		fprintf(stderr, "inflateInit error: %d\n", err);
   444 		return -1;
   445 	}
   446 
   447 	return 0;
   448 }
   449 
   450 static int
   451 installer_finish(struct installer *installer)
   452 {
   453 	int err;
   454 
   455 	err = inflateEnd(&installer->stream);
   456 
   457 	if (err != Z_OK) {
   458 		fprintf(stderr, "inflateEnd error: %d\n", err);
   459 		return -1;
   460 	}	    
   461 
   462 	return 0;
   463 }
   464 
   465 int
   466 razor_rpm_install(struct razor_rpm *rpm, const char *root)
   467 {
   468 	struct installer installer;
   469 	unsigned int count, i, length;
   470 	struct cpio_file_header *header;
   471 	const uint32_t *size, *index, *flags;
   472 	const unsigned short *mode;
   473 	const char *name, *dir;
   474 	struct stat buf;
   475 
   476 	installer.rpm = rpm;
   477 	installer.root = root;
   478 
   479 	/* FIXME: Only do this before a transaction, not per rpm. */
   480 	if (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode)) {
   481 		fprintf(stderr,
   482 			"root installation directory \"%s\" does not exist\n",
   483 			root);
   484 		return -1;
   485 	}
   486 
   487 	if (installer_init(&installer))
   488 		return -1;
   489 
   490 	run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN);
   491 
   492 	name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count);
   493 	size = razor_rpm_get_indirect(rpm, RPMTAG_FILESIZES, &count);
   494 	index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count);
   495 	mode = razor_rpm_get_indirect(rpm, RPMTAG_FILEMODES, &count);
   496 	flags = razor_rpm_get_indirect(rpm, RPMTAG_FILEFLAGS, &count);
   497 
   498 	for (i = 0; i < count; i++) {
   499 		dir = rpm->dirs[ntohl(*index)];
   500 
   501 		/* Skip past the cpio header block unless it's a ghost file,
   502 		 * in which case doesn't appear in the cpio archive. */
   503 		if (!(ntohl(*flags) & RPMFILE_GHOST)) {
   504 			/* Plus two for the leading '.' and the terminating NUL. */
   505 			length = sizeof *header + strlen(dir) + strlen(name) + 2;
   506 			installer.rest = ALIGN(length, 4);
   507 			if (installer_inflate(&installer))
   508 				return -1;
   509 		}
   510 
   511 		installer.rest = ntohl(*size);
   512 		if (create_path(&installer, dir, name, ntohs(*mode)) < 0)
   513 			return -1;
   514 
   515 		name += strlen(name) + 1;
   516 		index++;
   517 		size++;
   518 		mode++;
   519 		flags++;
   520 	}
   521 
   522 	if (installer_finish(&installer))
   523 		return -1;
   524 
   525 	run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN);
   526 
   527 	return 0;
   528 }
   529 
   530 int
   531 razor_rpm_close(struct razor_rpm *rpm)
   532 {
   533 	int err;
   534 
   535 	free(rpm->dirs);
   536 	err = munmap(rpm->map, rpm->size);
   537 	free(rpm);
   538 
   539 	return err;
   540 }
   541 
   542 int
   543 razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
   544 {
   545 	const char *name, *version, *release, *arch;
   546 	const uint_32 *epoch;
   547 	char evr[128], buf[16];
   548 
   549 	name = razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL);
   550 	epoch = razor_rpm_get_indirect(rpm, RPMTAG_EPOCH, NULL);
   551 	version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL);
   552 	release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL);
   553 	arch = razor_rpm_get_indirect(rpm, RPMTAG_ARCH, NULL);
   554 
   555 	if (epoch) {
   556 		snprintf(buf, sizeof buf, "%u", ntohl(*epoch));
   557 		razor_build_evr(evr, sizeof evr, buf, version, release);
   558 	} else {
   559 		razor_build_evr(evr, sizeof evr, NULL, version, release);
   560 	}
   561 	razor_importer_begin_package(importer, name, evr, arch);
   562 
   563 	import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
   564 			  RPMTAG_REQUIRENAME,
   565 			  RPMTAG_REQUIREVERSION,
   566 			  RPMTAG_REQUIREFLAGS);
   567 
   568 	import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
   569 			  RPMTAG_PROVIDENAME,
   570 			  RPMTAG_PROVIDEVERSION,
   571 			  RPMTAG_PROVIDEFLAGS);
   572 
   573 	import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
   574 			  RPMTAG_OBSOLETENAME,
   575 			  RPMTAG_OBSOLETEVERSION,
   576 			  RPMTAG_OBSOLETEFLAGS);
   577 
   578 	import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
   579 			  RPMTAG_CONFLICTNAME,
   580 			  RPMTAG_CONFLICTVERSION,
   581 			  RPMTAG_CONFLICTFLAGS);
   582 
   583 	import_files(importer, rpm);
   584 
   585 	razor_importer_finish_package(importer);
   586 
   587 	return 0;
   588 }
   589 
   590 union rpm_entry {
   591 	void *p;
   592 	char *string;
   593 	char **list;
   594 	uint_32 *flags;
   595 	uint_32 integer;
   596 };
   597 
   598 static void
   599 add_properties(struct razor_importer *importer,
   600 	       enum razor_property_type property_type,
   601 	       Header h, int_32 name_tag, int_32 version_tag, int_32 flags_tag)
   602 {
   603 	union rpm_entry names, versions, flags;
   604 	int_32 i, type, count;
   605 
   606 	headerGetEntry(h, name_tag, &type, &names.p, &count);
   607 	headerGetEntry(h, version_tag, &type, &versions.p, &count);
   608 	headerGetEntry(h, flags_tag, &type, &flags.p, &count);
   609 
   610 	for (i = 0; i < count; i++)
   611 		razor_importer_add_property(importer,
   612 					    names.list[i],
   613 					    rpm_to_razor_flags (flags.flags[i]),
   614 					    versions.list[i],
   615 					    property_type);
   616 }
   617 
   618 struct razor_set *
   619 razor_set_create_from_rpmdb(void)
   620 {
   621 	struct razor_importer *importer;
   622 	rpmdbMatchIterator iter;
   623 	Header h;
   624 	int_32 type, count, i;
   625 	union rpm_entry name, epoch, version, release, arch;
   626 	union rpm_entry basenames, dirnames, dirindexes;
   627 	char filename[PATH_MAX], evr[128], buf[16];
   628 	rpmdb db;
   629 
   630 	rpmReadConfigFiles(NULL, NULL);
   631 
   632 	if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
   633 		fprintf(stderr, "cannot open rpm database\n");
   634 		exit(1);
   635 	}
   636 
   637 	importer = razor_importer_new();
   638 
   639 	iter = rpmdbInitIterator(db, 0, NULL, 0);
   640 	while (h = rpmdbNextIterator(iter), h != NULL) {
   641 		headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count);
   642 		headerGetEntry(h, RPMTAG_EPOCH, &type, &epoch.p, &count);
   643 		headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count);
   644 		headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count);
   645 		headerGetEntry(h, RPMTAG_ARCH, &type, &arch.p, &count);
   646 
   647 		if (epoch.flags != NULL) {
   648 			snprintf(buf, sizeof buf, "%u", *epoch.flags);
   649 			razor_build_evr(evr, sizeof evr,
   650 					buf, version.string, release.string);
   651 		} else {
   652 			razor_build_evr(evr, sizeof evr,
   653 					NULL, version.string, release.string);
   654 		}
   655 
   656 		razor_importer_begin_package(importer,
   657 					     name.string, evr, arch.string);
   658 
   659 		add_properties(importer, RAZOR_PROPERTY_REQUIRES, h,
   660 			       RPMTAG_REQUIRENAME,
   661 			       RPMTAG_REQUIREVERSION,
   662 			       RPMTAG_REQUIREFLAGS);
   663 
   664 		add_properties(importer, RAZOR_PROPERTY_PROVIDES, h,
   665 			       RPMTAG_PROVIDENAME,
   666 			       RPMTAG_PROVIDEVERSION,
   667 			       RPMTAG_PROVIDEFLAGS);
   668 
   669 		add_properties(importer, RAZOR_PROPERTY_OBSOLETES, h,
   670 			       RPMTAG_OBSOLETENAME,
   671 			       RPMTAG_OBSOLETEVERSION,
   672 			       RPMTAG_OBSOLETEFLAGS);
   673 
   674 		add_properties(importer, RAZOR_PROPERTY_CONFLICTS, h,
   675 			       RPMTAG_CONFLICTNAME,
   676 			       RPMTAG_CONFLICTVERSION,
   677 			       RPMTAG_CONFLICTFLAGS);
   678 
   679 		headerGetEntry(h, RPMTAG_BASENAMES, &type,
   680 			       &basenames.p, &count);
   681 		headerGetEntry(h, RPMTAG_DIRNAMES, &type,
   682 			       &dirnames.p, &count);
   683 		headerGetEntry(h, RPMTAG_DIRINDEXES, &type,
   684 			       &dirindexes.p, &count);
   685 		for (i = 0; i < count; i++) {
   686 			snprintf(filename, sizeof filename, "%s%s",
   687 				 dirnames.list[dirindexes.flags[i]],
   688 				 basenames.list[i]);
   689 			razor_importer_add_file(importer, filename);
   690 		}
   691 
   692 		razor_importer_finish_package(importer);
   693 	}
   694 
   695 	rpmdbClose(db);
   696 
   697 	return razor_importer_finish(importer);
   698 }