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