rpm.c
author Dan Winship <danw@gnome.org>
Fri Feb 29 12:45:08 2008 -0500 (2008-02-29)
changeset 138 49deac048d07
parent 91 6884cefd1b8c
child 143 59a9513fac54
permissions -rw-r--r--
implement file dependencies for installs

removes are trickier because there are no backlinks from the files array
the properties array, so there's currently no way to efficiently determine
what packages are affected by the removal of a particular file
     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 	/* FIXME: Concat version and release. */
   113 	version = razor_rpm_get_indirect(rpm, version_tag, &count);
   114 	for (i = 0; i < count; i++) {
   115 		razor_importer_add_property(importer, name,
   116 					    rpm_to_razor_flags (flags),
   117 					    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 unsigned long *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 == NULL) {
   192 		fprintf(stderr, "old filename style not handled\n");
   193 		return NULL;
   194 	}
   195 
   196 	rpm->dirs = calloc(count, sizeof *rpm->dirs);
   197 	for (i = 0; i < count; i++) {
   198 		rpm->dirs[i] = name;
   199 		name += strlen(name) + 1;
   200 	}
   201 
   202 	return rpm;
   203 }
   204 
   205 struct cpio_file_header {
   206 	char magic[6];
   207 	char inode[8];
   208 	char mode[8];
   209 	char uid[8];
   210 	char gid[8];
   211 	char nlink[8];
   212 	char mtime[8];
   213 	char filesize[8];
   214 	char devmajor[8];
   215 	char devminor[8];
   216 	char rdevmajor[8];
   217 	char rdevminor[8];
   218 	char namesize[8];
   219 	char checksum[8];
   220 	char filename[0];
   221 };
   222 
   223 /* gzip flags */
   224 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
   225 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
   226 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
   227 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
   228 #define COMMENT      0x10 /* bit 4 set: file comment present */
   229 #define RESERVED     0xE0 /* bits 5..7: reserved */
   230 
   231 struct installer {
   232 	const char *root;
   233 	struct razor_rpm *rpm;
   234 	z_stream stream;
   235 	unsigned char buffer[32768];
   236 	size_t rest, length;
   237 };
   238 
   239 static int
   240 installer_inflate(struct installer *installer)
   241 {
   242 	size_t length;
   243 	int err;
   244 
   245 	if (ALIGN(installer->rest, 4) > sizeof installer->buffer)
   246 		length = sizeof installer->buffer;
   247 	else
   248 		length = installer->rest;
   249 
   250 	installer->stream.next_out = installer->buffer;
   251 	installer->stream.avail_out = ALIGN(length, 4);
   252 	err = inflate(&installer->stream, Z_SYNC_FLUSH);
   253 	if (err != Z_OK && err != Z_STREAM_END) {
   254 		fprintf(stderr, "inflate error: %d (%m)\n", err);
   255 		return -1;
   256 	}
   257 
   258 	installer->rest -= length;
   259 	installer->length = length;
   260 
   261 	return 0;
   262 }
   263 
   264 static int
   265 create_path(struct installer *installer,
   266 	    const char *path, const char *name, unsigned int mode)
   267 {
   268 	char buffer[PATH_MAX];
   269 	int fd;
   270 
   271 	if (razor_create_dir(installer->root, path) < 0)
   272 		return -1;
   273 
   274 	snprintf(buffer, sizeof buffer, "%s%s/%s",
   275 		 installer->root, path, name);
   276 
   277 	switch (mode >> 12) {
   278 	case REG:
   279 		fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, mode & 0x1ff);
   280 		if (fd < 0){
   281 			fprintf(stderr, "failed to create file %s\n", buffer);
   282 			return -1;
   283 		}
   284 		while (installer->rest > 0) {
   285 			if (installer_inflate(installer)) {
   286 				fprintf(stderr, "failed to inflate\n");
   287 				return -1;
   288 			}
   289 			if (razor_write(fd, installer->buffer,
   290 					installer->length)) {
   291 				fprintf(stderr, "failed to write payload\n");
   292 				return -1;
   293 			}
   294 		}
   295 		if (close(fd) < 0) {
   296 			fprintf(stderr, "failed to close %s: %m\n", buffer);
   297 			return -1;
   298 		}
   299 		return 0;
   300 	case XDIR:
   301 		return mkdir(buffer, mode & 0x1ff);
   302 	case PIPE:
   303 	case CDEV:
   304 	case BDEV:
   305 	case SOCK:
   306 		printf("%s: unhandled file type %d\n", buffer, mode >> 12);
   307 		return 0;
   308 	case LINK:
   309 		if (installer_inflate(installer)) {
   310 			fprintf(stderr, "failed to inflate\n");
   311 			return -1;
   312 		}
   313 		if (installer->length >= sizeof installer->buffer) {
   314 			fprintf(stderr, "link name too long\n");
   315 			return -1;
   316 		}
   317 		installer->buffer[installer->length] = '\0';
   318 		if (symlink((const char *) installer->buffer, buffer)) {
   319 			fprintf(stderr, "failed to create symlink, %m\n");
   320 			return -1;
   321 		}
   322 		return 0;
   323 	default:
   324 		printf("%s: unknown file type %d\n", buffer, mode >> 12);
   325 		return 0;
   326 	}
   327 }
   328 
   329 static int
   330 run_script(struct installer *installer,
   331 	   unsigned int program_tag, unsigned int script_tag)
   332 {
   333 	int pid, status, fd[2];
   334 	const char *script = NULL, *program = NULL;
   335 
   336 	program = razor_rpm_get_indirect(installer->rpm, program_tag, NULL);
   337 	script = razor_rpm_get_indirect(installer->rpm, script_tag, NULL);
   338 	if (program == NULL && script == NULL) {
   339 		printf("no script or program for tags %d and %d\n",
   340 		       program_tag, script_tag);
   341 		return -1;
   342 	} else if (program == NULL) {
   343 		program = "/bin/sh";
   344 	}
   345 
   346 	if (pipe(fd) < 0) {
   347 		fprintf(stderr, "failed to create pipe\n");
   348 		return -1;
   349 	}
   350 	pid = fork();
   351 	if (pid < 0) {
   352 		fprintf(stderr, "failed to fork, %m\n");
   353 	} else if (pid == 0) {
   354 		if (dup2(fd[0], STDIN_FILENO) < 0) {
   355 			fprintf(stderr, "failed redirect stdin, %m\n");
   356 			return -1;
   357 		}
   358 		if (close(fd[0]) < 0 || close(fd[1]) < 0) {
   359 			fprintf(stderr, "failed to close pipe, %m\n");
   360 			return -1;
   361 		}
   362 		if (chroot(installer->root) < 0) {
   363 			fprintf(stderr, "failed to chroot to %s, %m\n",
   364 				installer->root);
   365 			return -1;
   366 		}
   367 		printf("executing program %s in chroot %s\n",
   368 		       program, installer->root);
   369 		if (execl(program, program, NULL)) {
   370 			fprintf(stderr, "failed to exec %s, %m\n", program);
   371 			exit(-1);
   372 		}
   373 	} else {
   374 		if (script && write(fd[1], script, strlen(script)) < 0) {
   375 			fprintf(stderr, "failed to pipe script, %m\n");
   376 			return -1;
   377 		}
   378 		if (close(fd[0]) || close(fd[1])) {
   379 			fprintf(stderr, "failed to close pipe, %m\n");
   380 			return -1;
   381 		}
   382 		if (wait(&status) < 0) {
   383 			fprintf(stderr, "wait for child failed, %m");
   384 			return -1;
   385 		}
   386 		printf("script exited with status %d\n", status);
   387 	}
   388 
   389 	return 0;
   390 }
   391 
   392 static int
   393 installer_init(struct installer *installer)
   394 {
   395 	unsigned char *gz_header;
   396 	int method, flags, err;
   397 
   398 	gz_header = installer->rpm->payload;
   399 	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
   400 		fprintf(stderr, "payload section doesn't have gz header\n");
   401 		return -1;
   402 	}
   403 
   404 	method = gz_header[2];
   405 	flags = gz_header[3];
   406 
   407 	if (method != Z_DEFLATED || flags != 0) {
   408 		fprintf(stderr,
   409 			"unknown payload compression method or flags set\n");
   410 		return -1;
   411 	}
   412 
   413 	installer->stream.zalloc = NULL;
   414 	installer->stream.zfree = NULL;
   415 	installer->stream.opaque = NULL;
   416 
   417 	installer->stream.next_in  = gz_header + 10;
   418 	installer->stream.avail_in =
   419 		(installer->rpm->map + installer->rpm->size) -
   420 		(void *) installer->stream.next_in;
   421 	installer->stream.next_out = NULL;
   422 	installer->stream.avail_out = 0;
   423 
   424 	err = inflateInit2(&installer->stream, -MAX_WBITS);
   425 	if (err != Z_OK) {
   426 		fprintf(stderr, "inflateInit error: %d\n", err);
   427 		return -1;
   428 	}
   429 
   430 	return 0;
   431 }
   432 
   433 static int
   434 installer_finish(struct installer *installer)
   435 {
   436 	int err;
   437 
   438 	err = inflateEnd(&installer->stream);
   439 
   440 	if (err != Z_OK) {
   441 		fprintf(stderr, "inflateEnd error: %d\n", err);
   442 		return -1;
   443 	}	    
   444 
   445 	return 0;
   446 }
   447 
   448 int
   449 razor_rpm_install(struct razor_rpm *rpm, const char *root)
   450 {
   451 	struct installer installer;
   452 	unsigned int count, i, length;
   453 	struct cpio_file_header *header;
   454 	const unsigned long *size, *index, *flags;
   455 	const unsigned short *mode;
   456 	const char *name, *dir;
   457 	struct stat buf;
   458 
   459 	installer.rpm = rpm;
   460 	installer.root = root;
   461 
   462 	/* FIXME: Only do this before a transaction, not per rpm. */
   463 	if (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode)) {
   464 		fprintf(stderr,
   465 			"root installation directory \"%s\" does not exist\n",
   466 			root);
   467 		return -1;
   468 	}
   469 
   470 	if (installer_init(&installer))
   471 		return -1;
   472 
   473 	run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN);
   474 
   475 	name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count);
   476 	size = razor_rpm_get_indirect(rpm, RPMTAG_FILESIZES, &count);
   477 	index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count);
   478 	mode = razor_rpm_get_indirect(rpm, RPMTAG_FILEMODES, &count);
   479 	flags = razor_rpm_get_indirect(rpm, RPMTAG_FILEFLAGS, &count);
   480 
   481 	for (i = 0; i < count; i++) {
   482 		dir = rpm->dirs[ntohl(*index)];
   483 
   484 		/* Skip past the cpio header block unless it's a ghost file,
   485 		 * in which case doesn't appear in the cpio archive. */
   486 		if (!(ntohl(*flags) & RPMFILE_GHOST)) {
   487 			/* Plus two for the leading '.' and the terminating NUL. */
   488 			length = sizeof *header + strlen(dir) + strlen(name) + 2;
   489 			installer.rest = ALIGN(length, 4);
   490 			if (installer_inflate(&installer))
   491 				return -1;
   492 		}
   493 
   494 		installer.rest = ntohl(*size);
   495 		if (create_path(&installer, dir, name, ntohs(*mode)) < 0)
   496 			return -1;
   497 
   498 		name += strlen(name) + 1;
   499 		index++;
   500 		size++;
   501 		mode++;
   502 		flags++;
   503 	}
   504 
   505 	if (installer_finish(&installer))
   506 		return -1;
   507 
   508 	run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN);
   509 
   510 	return 0;
   511 }
   512 
   513 int
   514 razor_rpm_close(struct razor_rpm *rpm)
   515 {
   516 	int err;
   517 
   518 	free(rpm->dirs);
   519 	err = munmap(rpm->map, rpm->size);
   520 	free(rpm);
   521 
   522 	return err;
   523 }
   524 
   525 int
   526 razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
   527 {
   528 	const char *name, *version, *release;
   529 
   530 	name = razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL);
   531 	version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL);
   532 	release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL);
   533 
   534 	/* FIXME: Concatenate version and release. */
   535 	razor_importer_begin_package(importer, name, version);
   536 
   537 	import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
   538 			  RPMTAG_REQUIRENAME,
   539 			  RPMTAG_REQUIREVERSION,
   540 			  RPMTAG_REQUIREFLAGS);
   541 
   542 	import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
   543 			  RPMTAG_PROVIDENAME,
   544 			  RPMTAG_PROVIDEVERSION,
   545 			  RPMTAG_PROVIDEFLAGS);
   546 
   547 	import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
   548 			  RPMTAG_OBSOLETENAME,
   549 			  RPMTAG_OBSOLETEVERSION,
   550 			  RPMTAG_OBSOLETEFLAGS);
   551 
   552 	import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
   553 			  RPMTAG_CONFLICTNAME,
   554 			  RPMTAG_CONFLICTVERSION,
   555 			  RPMTAG_CONFLICTFLAGS);
   556 
   557 	import_files(importer, rpm);
   558 
   559 	razor_importer_finish_package(importer);
   560 
   561 	return 0;
   562 }
   563 
   564 union rpm_entry {
   565 	void *p;
   566 	char *string;
   567 	char **list;
   568 	uint_32 *flags;
   569 };
   570 
   571 static void
   572 add_properties(struct razor_importer *importer,
   573 	       enum razor_property_type property_type,
   574 	       Header h, int_32 name_tag, int_32 version_tag, int_32 flags_tag)
   575 {
   576 	union rpm_entry names, versions, flags;
   577 	int_32 i, type, count;
   578 
   579 	headerGetEntry(h, name_tag, &type, &names.p, &count);
   580 	headerGetEntry(h, version_tag, &type, &versions.p, &count);
   581 	headerGetEntry(h, flags_tag, &type, &flags.p, &count);
   582 
   583 	for (i = 0; i < count; i++)
   584 		razor_importer_add_property(importer,
   585 					    names.list[i],
   586 					    rpm_to_razor_flags (flags.flags[i]),
   587 					    versions.list[i],
   588 					    property_type);
   589 }
   590 
   591 struct razor_set *
   592 razor_set_create_from_rpmdb(void)
   593 {
   594 	struct razor_importer *importer;
   595 	rpmdbMatchIterator iter;
   596 	Header h;
   597 	int_32 type, count, i;
   598 	union rpm_entry name, version, release;
   599 	union rpm_entry basenames, dirnames, dirindexes;
   600 	char filename[PATH_MAX];
   601 	rpmdb db;
   602 
   603 	rpmReadConfigFiles(NULL, NULL);
   604 
   605 	if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
   606 		fprintf(stderr, "cannot open rpm database\n");
   607 		exit(1);
   608 	}
   609 
   610 	importer = razor_importer_new();
   611 
   612 	iter = rpmdbInitIterator(db, 0, NULL, 0);
   613 	while (h = rpmdbNextIterator(iter), h != NULL) {
   614 		headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count);
   615 		headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count);
   616 		headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count);
   617 		snprintf(filename, sizeof filename, "%s-%s",
   618 			 version.string, release.string);
   619 		razor_importer_begin_package(importer, name.string, filename);
   620 
   621 		add_properties(importer, RAZOR_PROPERTY_REQUIRES, h,
   622 			       RPMTAG_REQUIRENAME,
   623 			       RPMTAG_REQUIREVERSION,
   624 			       RPMTAG_REQUIREFLAGS);
   625 
   626 		add_properties(importer, RAZOR_PROPERTY_PROVIDES, h,
   627 			       RPMTAG_PROVIDENAME,
   628 			       RPMTAG_PROVIDEVERSION,
   629 			       RPMTAG_PROVIDEFLAGS);
   630 
   631 		add_properties(importer, RAZOR_PROPERTY_OBSOLETES, h,
   632 			       RPMTAG_OBSOLETENAME,
   633 			       RPMTAG_OBSOLETEVERSION,
   634 			       RPMTAG_OBSOLETEFLAGS);
   635 
   636 		add_properties(importer, RAZOR_PROPERTY_CONFLICTS, h,
   637 			       RPMTAG_CONFLICTNAME,
   638 			       RPMTAG_CONFLICTVERSION,
   639 			       RPMTAG_CONFLICTFLAGS);
   640 
   641 		headerGetEntry(h, RPMTAG_BASENAMES, &type,
   642 			       &basenames.p, &count);
   643 		headerGetEntry(h, RPMTAG_DIRNAMES, &type,
   644 			       &dirnames.p, &count);
   645 		headerGetEntry(h, RPMTAG_DIRINDEXES, &type,
   646 			       &dirindexes.p, &count);
   647 		for (i = 0; i < count; i++) {
   648 			snprintf(filename, sizeof filename, "%s%s",
   649 				 dirnames.list[dirindexes.flags[i]],
   650 				 basenames.list[i]);
   651 			razor_importer_add_file(importer, filename);
   652 		}
   653 
   654 		razor_importer_finish_package(importer);
   655 	}
   656 
   657 	rpmdbClose(db);
   658 
   659 	return razor_importer_finish(importer);
   660 }