librazor/rpm.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
parent 376 d15a16347c77
child 422 6fa783097ca1
permissions -rw-r--r--
Add transaction barriers
These allow packages to be installed and removed which have scripts
that depend on each other when atomic transactions are involved.
Note that yum supports pre, but not other requires flags. post will
need similar support to the post scripts themselves pulling in the
requires flags from the rpms. Likewise preun and postun will need
similar handling to those scrips since the requires flags will need
to be stored in the razor database.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #include "config.h"
    22 
    23 #include <stdio.h>
    24 #include <stddef.h>
    25 #include <stdlib.h>
    26 #include <string.h>
    27 #include <errno.h>
    28 #include <sys/stat.h>
    29 #include <sys/types.h>
    30 #if HAVE_SYS_WAIT_H
    31 #include <sys/wait.h>
    32 #endif
    33 #include <fcntl.h>
    34 #include <dirent.h>
    35 #include <unistd.h>
    36 #if MSWIN_API
    37 #include <winsock2.h>	/* For ntohl() */
    38 #else
    39 #include <arpa/inet.h>
    40 #endif
    41 #include <limits.h>
    42 #include <zlib.h>
    43 #include <assert.h>
    44 
    45 #include "razor.h"
    46 #include "razor-internal.h"
    47 
    48 #ifndef O_BINARY
    49 #define O_BINARY	0
    50 #endif
    51 
    52 #define	RPM_LEAD_SIZE 96
    53 
    54 enum {
    55     PIPE	=  1,	/*!< pipe/fifo */
    56     CDEV	=  2,	/*!< character device */
    57     XDIR	=  4,	/*!< directory */
    58     BDEV	=  6,	/*!< block device */
    59     REG		=  8,	/*!< regular file */
    60     LINK	= 10,	/*!< hard link */
    61     SOCK	= 12	/*!< socket */
    62 };
    63 
    64 enum {
    65     RPMSENSE_LESS		= 1 << 1,
    66     RPMSENSE_GREATER		= 1 << 2,
    67     RPMSENSE_EQUAL		= 1 << 3,
    68     RPMSENSE_PREREQ		= 1 << 6,
    69     RPMSENSE_SCRIPT_PRE		= 1 << 9,
    70     RPMSENSE_SCRIPT_POST	= 1 << 10,
    71     RPMSENSE_SCRIPT_PREUN	= 1 << 11,
    72     RPMSENSE_SCRIPT_POSTUN	= 1 << 12,
    73 };
    74 
    75 enum {
    76     RPMTAG_NAME  		= 1000,	/* s */
    77     RPMTAG_VERSION		= 1001,	/* s */
    78     RPMTAG_RELEASE		= 1002,	/* s */
    79     RPMTAG_EPOCH   		= 1003,	/* i */
    80     RPMTAG_SUMMARY		= 1004,	/* s{} */
    81     RPMTAG_DESCRIPTION		= 1005,	/* s{} */
    82     RPMTAG_BUILDTIME		= 1006,	/* i */
    83     RPMTAG_BUILDHOST		= 1007,	/* s */
    84     RPMTAG_INSTALLTIME		= 1008,	/* i */
    85     RPMTAG_SIZE			= 1009,	/* i */
    86     RPMTAG_DISTRIBUTION		= 1010,	/* s */
    87     RPMTAG_VENDOR		= 1011,	/* s */
    88     RPMTAG_GIF			= 1012,	/* x */
    89     RPMTAG_XPM			= 1013,	/* x */
    90     RPMTAG_LICENSE		= 1014,	/* s */
    91     RPMTAG_PACKAGER		= 1015,	/* s */
    92     RPMTAG_GROUP		= 1016,	/* s{} */
    93     RPMTAG_CHANGELOG		= 1017, /*!< s[] internal */
    94     RPMTAG_SOURCE		= 1018,	/* s[] */
    95     RPMTAG_PATCH		= 1019,	/* s[] */
    96     RPMTAG_URL			= 1020,	/* s */
    97     RPMTAG_OS			= 1021,	/* s legacy used int */
    98     RPMTAG_ARCH			= 1022,	/* s legacy used int */
    99     RPMTAG_PREIN		= 1023,	/* s */
   100     RPMTAG_POSTIN		= 1024,	/* s */
   101     RPMTAG_PREUN		= 1025,	/* s */
   102     RPMTAG_POSTUN		= 1026,	/* s */
   103     RPMTAG_OLDFILENAMES		= 1027, /* s[] obsolete */
   104     RPMTAG_FILESIZES		= 1028,	/* i */
   105     RPMTAG_FILESTATES		= 1029, /* c */
   106     RPMTAG_FILEMODES		= 1030,	/* h */
   107     RPMTAG_FILEUIDS		= 1031, /*!< internal */
   108     RPMTAG_FILEGIDS		= 1032, /*!< internal */
   109     RPMTAG_FILERDEVS		= 1033,	/* h */
   110     RPMTAG_FILEMTIMES		= 1034, /* i */
   111     RPMTAG_FILEMD5S		= 1035,	/* s[] */
   112     RPMTAG_FILELINKTOS		= 1036,	/* s[] */
   113     RPMTAG_FILEFLAGS		= 1037,	/* i */
   114     RPMTAG_ROOT			= 1038, /*!< internal - obsolete */
   115     RPMTAG_FILEUSERNAME		= 1039,	/* s[] */
   116     RPMTAG_FILEGROUPNAME	= 1040,	/* s[] */
   117     RPMTAG_EXCLUDE		= 1041, /*!< internal - obsolete */
   118     RPMTAG_EXCLUSIVE		= 1042, /*!< internal - obsolete */
   119     RPMTAG_ICON			= 1043,
   120     RPMTAG_SOURCERPM		= 1044,	/* s */
   121     RPMTAG_FILEVERIFYFLAGS	= 1045,	/* i */
   122     RPMTAG_ARCHIVESIZE		= 1046,	/* i */
   123     RPMTAG_PROVIDENAME		= 1047,	/* s[] */
   124     RPMTAG_REQUIREFLAGS		= 1048,	/* i */
   125     RPMTAG_REQUIRENAME		= 1049,	/* s[] */
   126     RPMTAG_REQUIREVERSION	= 1050,	/* s[] */
   127     RPMTAG_NOSOURCE		= 1051, /*!< internal */
   128     RPMTAG_NOPATCH		= 1052, /*!< internal */
   129     RPMTAG_CONFLICTFLAGS	= 1053, /* i */
   130     RPMTAG_CONFLICTNAME		= 1054,	/* s[] */
   131     RPMTAG_CONFLICTVERSION	= 1055,	/* s[] */
   132     RPMTAG_DEFAULTPREFIX	= 1056, /*!< internal - deprecated */
   133     RPMTAG_BUILDROOT		= 1057, /*!< internal */
   134     RPMTAG_INSTALLPREFIX	= 1058, /*!< internal - deprecated */
   135     RPMTAG_EXCLUDEARCH		= 1059,
   136     RPMTAG_EXCLUDEOS		= 1060,
   137     RPMTAG_EXCLUSIVEARCH	= 1061,
   138     RPMTAG_EXCLUSIVEOS		= 1062,
   139     RPMTAG_AUTOREQPROV		= 1063, /*!< internal */
   140     RPMTAG_RPMVERSION		= 1064,	/* s */
   141     RPMTAG_TRIGGERSCRIPTS	= 1065,	/* s[] */
   142     RPMTAG_TRIGGERNAME		= 1066,	/* s[] */
   143     RPMTAG_TRIGGERVERSION	= 1067,	/* s[] */
   144     RPMTAG_TRIGGERFLAGS		= 1068,	/* i */
   145     RPMTAG_TRIGGERINDEX		= 1069,	/* i */
   146     RPMTAG_VERIFYSCRIPT		= 1079,	/* s */
   147     RPMTAG_CHANGELOGTIME	= 1080,	/* i */
   148     RPMTAG_CHANGELOGNAME	= 1081,	/* s[] */
   149     RPMTAG_CHANGELOGTEXT	= 1082,	/* s[] */
   150     RPMTAG_BROKENMD5		= 1083, /*!< internal - obsolete */
   151     RPMTAG_PREREQ		= 1084, /*!< internal */
   152     RPMTAG_PREINPROG		= 1085,	/* s */
   153     RPMTAG_POSTINPROG		= 1086,	/* s */
   154     RPMTAG_PREUNPROG		= 1087,	/* s */
   155     RPMTAG_POSTUNPROG		= 1088,	/* s */
   156     RPMTAG_BUILDARCHS		= 1089,
   157     RPMTAG_OBSOLETENAME		= 1090,	/* s[] */
   158     RPMTAG_VERIFYSCRIPTPROG	= 1091,	/* s */
   159     RPMTAG_TRIGGERSCRIPTPROG	= 1092,	/* s */
   160     RPMTAG_DOCDIR		= 1093, /*!< internal */
   161     RPMTAG_COOKIE		= 1094,	/* s */
   162     RPMTAG_FILEDEVICES		= 1095,	/* i */
   163     RPMTAG_FILEINODES		= 1096,	/* i */
   164     RPMTAG_FILELANGS		= 1097,	/* s[] */
   165     RPMTAG_PREFIXES		= 1098,	/* s[] */
   166     RPMTAG_INSTPREFIXES		= 1099,	/* s[] */
   167     RPMTAG_TRIGGERIN		= 1100, /*!< internal */
   168     RPMTAG_TRIGGERUN		= 1101, /*!< internal */
   169     RPMTAG_TRIGGERPOSTUN	= 1102, /*!< internal */
   170     RPMTAG_AUTOREQ		= 1103, /*!< internal */
   171     RPMTAG_AUTOPROV		= 1104, /*!< internal */
   172     RPMTAG_CAPABILITY		= 1105, /*!< internal - obsolete */
   173     RPMTAG_SOURCEPACKAGE	= 1106, /*!< i src.rpm header marker */
   174     RPMTAG_OLDORIGFILENAMES	= 1107, /*!< internal - obsolete */
   175     RPMTAG_BUILDPREREQ		= 1108, /*!< internal */
   176     RPMTAG_BUILDREQUIRES	= 1109, /*!< internal */
   177     RPMTAG_BUILDCONFLICTS	= 1110, /*!< internal */
   178     RPMTAG_BUILDMACROS		= 1111, /*!< internal - unused */
   179     RPMTAG_PROVIDEFLAGS		= 1112,	/* i */
   180     RPMTAG_PROVIDEVERSION	= 1113,	/* s[] */
   181     RPMTAG_OBSOLETEFLAGS	= 1114,	/* i */
   182     RPMTAG_OBSOLETEVERSION	= 1115,	/* s[] */
   183     RPMTAG_DIRINDEXES		= 1116,	/* i */
   184     RPMTAG_BASENAMES		= 1117,	/* s[] */
   185     RPMTAG_DIRNAMES		= 1118,	/* s[] */
   186     RPMTAG_ORIGDIRINDEXES	= 1119, /*!< internal */
   187     RPMTAG_ORIGBASENAMES	= 1120, /*!< internal */
   188     RPMTAG_ORIGDIRNAMES		= 1121, /*!< internal */
   189     RPMTAG_OPTFLAGS		= 1122,	/* s */
   190     RPMTAG_DISTURL		= 1123,	/* s */
   191     RPMTAG_PAYLOADFORMAT	= 1124,	/* s */
   192     RPMTAG_PAYLOADCOMPRESSOR	= 1125,	/* s */
   193     RPMTAG_PAYLOADFLAGS		= 1126,	/* s */
   194     RPMTAG_INSTALLCOLOR		= 1127, /*!< i transaction color when installed */
   195     RPMTAG_INSTALLTID		= 1128,	/* i */
   196     RPMTAG_REMOVETID		= 1129,	/* i */
   197     RPMTAG_SHA1RHN		= 1130, /*!< internal - obsolete */
   198     RPMTAG_RHNPLATFORM		= 1131,	/* s */
   199     RPMTAG_PLATFORM		= 1132,	/* s */
   200     RPMTAG_PATCHESNAME		= 1133, /*!< placeholder (SuSE) */
   201     RPMTAG_PATCHESFLAGS		= 1134, /*!< placeholder (SuSE) */
   202     RPMTAG_PATCHESVERSION	= 1135, /*!< placeholder (SuSE) */
   203     RPMTAG_CACHECTIME		= 1136,	/* i */
   204     RPMTAG_CACHEPKGPATH		= 1137,	/* s */
   205     RPMTAG_CACHEPKGSIZE		= 1138,	/* i */
   206     RPMTAG_CACHEPKGMTIME	= 1139,	/* i */
   207     RPMTAG_FILECOLORS		= 1140,	/* i */
   208     RPMTAG_FILECLASS		= 1141,	/* i */
   209     RPMTAG_CLASSDICT		= 1142,	/* s[] */
   210     RPMTAG_FILEDEPENDSX		= 1143,	/* i */
   211     RPMTAG_FILEDEPENDSN		= 1144,	/* i */
   212     RPMTAG_DEPENDSDICT		= 1145,	/* i */
   213     RPMTAG_SOURCEPKGID		= 1146,	/* x */
   214     RPMTAG_FILECONTEXTS		= 1147,	/* s[] */
   215     RPMTAG_FSCONTEXTS		= 1148,	/*!< s[] extension */
   216     RPMTAG_RECONTEXTS		= 1149,	/*!< s[] extension */
   217     RPMTAG_POLICIES		= 1150,	/*!< s[] selinux *.te policy file. */
   218     RPMTAG_PRETRANS		= 1151,	/* s */
   219     RPMTAG_POSTTRANS		= 1152,	/* s */
   220     RPMTAG_PRETRANSPROG		= 1153,	/* s */
   221     RPMTAG_POSTTRANSPROG	= 1154,	/* s */
   222     RPMTAG_DISTTAG		= 1155,	/* s */
   223     RPMTAG_SUGGESTSNAME		= 1156,	/* s[] extension placeholder */
   224     RPMTAG_SUGGESTSVERSION	= 1157,	/* s[] extension placeholder */
   225     RPMTAG_SUGGESTSFLAGS	= 1158,	/* i   extension placeholder */
   226     RPMTAG_ENHANCESNAME		= 1159,	/* s[] extension placeholder */
   227     RPMTAG_ENHANCESVERSION	= 1160,	/* s[] extension placeholder */
   228     RPMTAG_ENHANCESFLAGS	= 1161,	/* i   extension placeholder */
   229     RPMTAG_PRIORITY		= 1162, /* i   extension placeholder */
   230     RPMTAG_CVSID		= 1163, /* s */
   231     RPMTAG_TRIGGERPREIN		= 1171, /*!< internal */
   232 };
   233 
   234 struct rpm_header {
   235 	unsigned char magic[4];
   236 	unsigned char reserved[4];
   237 	int nindex;
   238 	int hsize;
   239 };
   240 
   241 struct rpm_header_index {
   242 	int tag;
   243 	int type;
   244 	int offset;
   245 	int count;
   246 };
   247 
   248 struct razor_rpm {
   249 	struct rpm_header *signature;
   250 	struct rpm_header *header;
   251 	const char **dirs;
   252 	unsigned int n_prefixes;
   253 	const char **prefixes;
   254 	const char *pool;
   255 	void *map;
   256 	size_t size;
   257 	void *payload;
   258 	struct razor_relocations *relocations;
   259 	char *evr;
   260 };
   261 
   262 enum razor_relocation_flags {
   263 	RAZOR_RELOCATION_ACTIVE		= 1 << 0,
   264 };
   265 
   266 struct razor_relocation {
   267 	enum razor_relocation_flags flags;
   268 	size_t oldlen;
   269 	size_t newlen;
   270 	char *oldpath;
   271 	char *newpath;
   272 };
   273 
   274 struct razor_relocations {
   275 	/* Ordered such that if oldpath 1 starts with oldpath 2, then
   276 	 * oldpath 1 is listed first (ie., /usr/bin comes before /usr)
   277 	 * and terminated with a NULL oldpath.
   278 	 */
   279 	struct razor_relocation *relocations;
   280 	int n_relocations;
   281 	char *path;
   282 };
   283 
   284 RAZOR_EXPORT struct razor_relocations *razor_relocations_create(void)
   285 {
   286 	return calloc(1, sizeof(struct razor_relocations));
   287 }
   288 
   289 RAZOR_EXPORT void razor_relocations_add(struct razor_relocations *rr,
   290 			   const char *oldpath, const char *newpath)
   291 {
   292 	int i, found = 0;
   293 	size_t len;
   294 
   295 	if (newpath && !strcmp(oldpath, newpath))
   296 		newpath = NULL;
   297 
   298 	for (i = 0; i < rr->n_relocations; i++) {
   299 		len = rr->relocations[i].oldlen;
   300 		if (!strncmp(rr->relocations[i].oldpath, oldpath, len)) {
   301 			found = !strcmp(rr->relocations[i].oldpath, oldpath);
   302 			break;
   303 		}
   304 	}
   305 
   306 	if (!newpath) {
   307 		if (found) {
   308 			free(rr->relocations[i].oldpath);
   309 			free(rr->relocations[i].newpath);
   310 			do {
   311 				rr->relocations[i] = rr->relocations[i + 1];
   312 			} while (rr->relocations[++i].oldpath);
   313 		}
   314 		return;
   315 	}
   316 
   317 	if (found) {
   318 		free(rr->relocations[i].newpath);
   319 		rr->relocations[i].newpath = strdup(newpath);
   320 		rr->relocations[i].newlen = strlen(newpath);
   321 		return;
   322 	}
   323 
   324 	if (!rr->n_relocations++)
   325 		rr->relocations = calloc(1, sizeof *rr->relocations);
   326 	else {
   327 		rr->relocations = realloc(rr->relocations,
   328 					  rr->n_relocations * sizeof *rr->relocations);
   329 		memmove(rr->relocations + i + 1, rr->relocations + i,
   330 			(rr->n_relocations - i - 1) * sizeof *rr->relocations);
   331 	}
   332 
   333 	rr->relocations[i].flags = 0;
   334 	rr->relocations[i].oldpath = strdup(oldpath);
   335 	rr->relocations[i].newpath = strdup(newpath);
   336 	rr->relocations[i].oldlen = strlen(oldpath);
   337 	rr->relocations[i].newlen = strlen(newpath);
   338 }
   339 
   340 RAZOR_EXPORT void
   341 razor_relocations_set_rpm(struct razor_relocations *rr, struct razor_rpm *rpm)
   342 {
   343 	int i, j;
   344 
   345 	for (i = 0; i < rr->n_relocations; i++) {
   346 		rr->relocations[i].flags &= ~RAZOR_RELOCATION_ACTIVE;
   347 		for (j = 0; j < rpm->n_prefixes; j++)
   348 			if (!strcmp(rpm->prefixes[j],
   349 				    rr->relocations[i].oldpath)) {
   350 				rr->relocations[i].flags |= RAZOR_RELOCATION_ACTIVE;
   351 				break;
   352 			}
   353 	}
   354 }
   355 
   356 RAZOR_EXPORT const char *
   357 razor_relocations_apply(struct razor_relocations *rr, const char *path)
   358 {
   359 	int i;
   360 	size_t len;
   361 
   362 	for (i = 0; i < rr->n_relocations; i++)
   363 		if (rr->relocations[i].flags & RAZOR_RELOCATION_ACTIVE &&
   364 		    !strncmp(path, rr->relocations[i].oldpath,
   365 			     rr->relocations[i].oldlen))
   366 			break;
   367 
   368 	if (i < rr->n_relocations) {
   369 		free(rr->path);
   370 		len = strlen(path + rr->relocations[i].oldlen) +
   371 		      rr->relocations[i].newlen;
   372 		rr->path = malloc(len + 1);
   373 		memcpy(rr->path, rr->relocations[i].newpath,
   374 		       rr->relocations[i].newlen);
   375 		strcpy(rr->path + rr->relocations[i].newlen,
   376 		       path + rr->relocations[i].oldlen);
   377 		return rr->path;
   378 	} else
   379 		return path;
   380 }
   381 
   382 RAZOR_EXPORT void razor_relocations_destroy(struct razor_relocations *rr)
   383 {
   384 	free(rr->path);
   385 	free(rr->relocations);
   386 	free(rr);
   387 }
   388 
   389 static struct rpm_header_index *
   390 razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag)
   391 {
   392 	struct rpm_header_index *index, *end;
   393 
   394 	index = (struct rpm_header_index *) (rpm->header + 1);
   395 	end = index + ntohl(rpm->header->nindex);
   396 	while (index < end) {
   397 		if (ntohl(index->tag) == tag)
   398 			return index;
   399 		index++;
   400 	}
   401 
   402 	return NULL;
   403 }
   404 
   405 static const void *
   406 razor_rpm_get_indirect(struct razor_rpm *rpm,
   407 		       unsigned int tag, unsigned int *count)
   408 {
   409 	struct rpm_header_index *index;
   410 
   411 	index = razor_rpm_get_header(rpm, tag);
   412 	if (index != NULL) {
   413 		if (count)
   414 			*count = ntohl(index->count);
   415 
   416 		return rpm->pool + ntohl(index->offset);
   417 	}
   418 
   419 	return NULL;
   420 }
   421 
   422 static uint32_t
   423 rpm_to_razor_flags(uint32_t flags)
   424 {
   425 	uint32_t razor_flags;
   426 
   427 	razor_flags = 0;
   428 	if (flags & RPMSENSE_LESS)
   429 		razor_flags |= RAZOR_PROPERTY_LESS;
   430 	if (flags & RPMSENSE_EQUAL)
   431 		razor_flags |= RAZOR_PROPERTY_EQUAL;
   432 	if (flags & RPMSENSE_GREATER)
   433 		razor_flags |= RAZOR_PROPERTY_GREATER;
   434 
   435 	if (flags & RPMSENSE_SCRIPT_PRE)
   436 		razor_flags |= RAZOR_PROPERTY_PRE;
   437 	if (flags & RPMSENSE_SCRIPT_POST)
   438 		razor_flags |= RAZOR_PROPERTY_POST;
   439 	if (flags & RPMSENSE_SCRIPT_PREUN)
   440 		razor_flags |= RAZOR_PROPERTY_PREUN;
   441 	if (flags & RPMSENSE_SCRIPT_POSTUN)
   442 		razor_flags |= RAZOR_PROPERTY_POSTUN;
   443 	
   444 	return razor_flags;
   445 }
   446 
   447 static void
   448 import_properties(struct razor_importer *importer, uint32_t type,
   449 		  struct razor_rpm *rpm,
   450 		  int name_tag, int version_tag, int flags_tag)
   451 {
   452 	const char *name, *version;
   453 	const uint32_t *flags;
   454 	uint32_t f;
   455 	unsigned int i, count;
   456 
   457 	name = razor_rpm_get_indirect(rpm, name_tag, &count);
   458 	if (name == NULL)
   459 		return;
   460 
   461 	flags = razor_rpm_get_indirect(rpm, flags_tag, &count);
   462 
   463 	version = razor_rpm_get_indirect(rpm, version_tag, &count);
   464 	for (i = 0; i < count; i++) {
   465 		f = rpm_to_razor_flags(ntohl(flags[i]));
   466 		razor_importer_add_property(importer, name, f | type, version);
   467 		name += strlen(name) + 1;
   468 		version += strlen(version) + 1;
   469 	}
   470 }
   471 
   472 static void
   473 import_files(struct razor_importer *importer, struct razor_rpm *rpm)
   474 {
   475 	const char *name;
   476 	const uint32_t *index;
   477 	unsigned int i, count;
   478 	char buffer[256];
   479 
   480 	if (rpm->dirs == NULL)
   481 		return;
   482 
   483 	/* assert: count is the same for all arrays */
   484 	index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count);
   485 	name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count);
   486 	for (i = 0; i < count; i++) {
   487 		snprintf(buffer, sizeof buffer,
   488 			 "%s%s", rpm->dirs[ntohl(*index)], name);
   489 		razor_importer_add_file(importer, buffer);
   490 		name += strlen(name) + 1;
   491 		index++;
   492 	}
   493 }
   494 
   495 static void
   496 razor_rpm_build_evr(struct razor_rpm *rpm)
   497 {
   498 	const char *version, *release;
   499 	const uint32_t *epoch;
   500 	char evr[128], buf[16];
   501 
   502 	epoch = razor_rpm_get_indirect(rpm, RPMTAG_EPOCH, NULL);
   503 	version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL);
   504 	release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL);
   505 	if (epoch)
   506 		snprintf(buf, sizeof buf, "%lu", (unsigned long)ntohl(*epoch));
   507 	razor_build_evr(evr, sizeof evr, epoch ? buf : NULL, version, release);
   508 	rpm->evr = strdup(evr);
   509 }
   510 
   511 static const char *
   512 razor_rpm_get_details_string(struct razor_rpm *rpm, enum razor_detail_type type)
   513 {
   514 	switch(type) {
   515 	case RAZOR_DETAIL_NAME:
   516 		return razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL);
   517 
   518 	case RAZOR_DETAIL_VERSION:
   519 		if (!rpm->evr)
   520 			razor_rpm_build_evr(rpm);
   521 		return rpm->evr;
   522 
   523 	case RAZOR_DETAIL_ARCH:
   524 		return razor_rpm_get_indirect(rpm, RPMTAG_ARCH, NULL);
   525 
   526 	case RAZOR_DETAIL_SUMMARY:
   527 		return razor_rpm_get_indirect(rpm, RPMTAG_SUMMARY, NULL);
   528 
   529 	case RAZOR_DETAIL_DESCRIPTION:
   530 		return razor_rpm_get_indirect(rpm, RPMTAG_DESCRIPTION, NULL);
   531 
   532 	case RAZOR_DETAIL_URL:
   533 		return razor_rpm_get_indirect(rpm, RPMTAG_URL, NULL);
   534 
   535 	case RAZOR_DETAIL_LICENSE:
   536 		return razor_rpm_get_indirect(rpm, RPMTAG_LICENSE, NULL);
   537 
   538 	case RAZOR_DETAIL_PREUNPROG:
   539 		return razor_rpm_get_indirect(rpm, RPMTAG_PREUNPROG, NULL);
   540 
   541 	case RAZOR_DETAIL_PREUN:
   542 		return razor_rpm_get_indirect(rpm, RPMTAG_PREUN, NULL);
   543 
   544 	case RAZOR_DETAIL_POSTUNPROG:
   545 		return razor_rpm_get_indirect(rpm, RPMTAG_POSTUNPROG, NULL);
   546 
   547 	case RAZOR_DETAIL_POSTUN:
   548 		return razor_rpm_get_indirect(rpm, RPMTAG_POSTUN, NULL);
   549 
   550 	default:
   551 		fprintf(stderr, "type %u not found\n", type);
   552 		return NULL;
   553 	}
   554 }
   555 
   556 static const char *const *
   557 razor_rpm_get_details_array(struct razor_rpm *rpm, enum razor_detail_type type)
   558 {
   559 	switch(type) {
   560 	case RAZOR_DETAIL_PREFIXES:
   561 		return rpm->prefixes;
   562 
   563 	default:
   564 		/* Impossible */
   565 		fprintf(stderr, "type %u not found\n", type);
   566 		return NULL;
   567 	}
   568 }
   569 
   570 void
   571 razor_rpm_get_details_varg(struct razor_rpm *rpm, va_list args)
   572 {
   573 	int i;
   574 	enum razor_detail_type type;
   575 	const char **string;
   576 	const char *const **array;
   577 
   578 	for (i = 0;; i += 2) {
   579 		type = va_arg(args, enum razor_detail_type);
   580 		if (type == RAZOR_DETAIL_LAST)
   581 			break;
   582 		if (type == RAZOR_DETAIL_PREFIXES) {
   583 			array = va_arg(args, const char *const **);
   584 			*array = razor_rpm_get_details_array(rpm, type);
   585 		} else {
   586 			string = va_arg(args, const char **);
   587 			*string = razor_rpm_get_details_string(rpm, type);
   588 		}
   589         }
   590 }
   591 
   592 RAZOR_EXPORT void
   593 razor_rpm_get_details(struct razor_rpm *rpm, ...)
   594 {
   595 	va_list args;
   596 
   597 	assert(rpm != NULL);
   598 
   599 	va_start(args, rpm);
   600 	razor_rpm_get_details_varg(rpm, args);
   601 	va_end(args);
   602 }
   603 
   604 RAZOR_EXPORT struct razor_rpm *
   605 razor_rpm_open(const char *filename, struct razor_atomic *atomic)
   606 {
   607 	struct razor_rpm *rpm;
   608 	struct rpm_header_index *base, *index;
   609 	unsigned int count, i, nindex, hsize;
   610 	const char *name, *prefix;
   611 	char *s;
   612 
   613 	assert (filename != NULL);
   614 
   615 	rpm = zalloc(sizeof *rpm);
   616 	if (rpm == NULL) {
   617 		razor_atomic_abort(atomic, "Not enough memory");
   618 		return NULL;
   619 	}
   620 	memset(rpm, 0, sizeof *rpm);
   621 
   622 	rpm->map = razor_file_get_contents(filename, &rpm->size);
   623 	if (!rpm->map) {
   624 		s = razor_concat(filename, ": ", strerror(errno), NULL);
   625 		razor_atomic_abort(atomic, s);
   626 		free(s);
   627 		free(rpm);
   628 		return NULL;
   629 	}
   630 
   631 	rpm->signature = rpm->map + RPM_LEAD_SIZE;
   632 	nindex = ntohl(rpm->signature->nindex);
   633 	hsize = ntohl(rpm->signature->hsize);
   634 	rpm->header = (void *) (rpm->signature + 1) +
   635 		ALIGN(nindex * sizeof *index + hsize, 8);
   636 	nindex = ntohl(rpm->header->nindex);
   637 	hsize = ntohl(rpm->header->hsize);
   638 	rpm->payload = (void *) (rpm->header + 1) +
   639 		nindex * sizeof *index + hsize;
   640 
   641 	base = (struct rpm_header_index *) (rpm->header + 1);
   642 	rpm->pool = (void *) base + nindex * sizeof *index;
   643 
   644 	/* Look up dir names now so we can index them directly. */
   645 	name = razor_rpm_get_indirect(rpm, RPMTAG_DIRNAMES, &count);
   646 	if (name) {
   647 		rpm->dirs = calloc(count, sizeof *rpm->dirs);
   648 		for (i = 0; i < count; i++) {
   649 			rpm->dirs[i] = name;
   650 			name += strlen(name) + 1;
   651 		}
   652 	} else {
   653 		name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES,
   654 					      &count);
   655 		if (name) {
   656 			razor_rpm_close(rpm);
   657 			s = razor_concat(filename,
   658 					 ": Old filenames not supported", NULL);
   659 			razor_atomic_abort(atomic, s);
   660 			free(s);
   661 			return NULL;
   662 		}
   663 	}
   664 
   665 	prefix = razor_rpm_get_indirect(rpm, RPMTAG_PREFIXES, &count);
   666 	if (prefix) {
   667 		rpm->prefixes = calloc(count + 1, sizeof *rpm->prefixes);
   668 		for (i = 0; i < count; i++) {
   669 			rpm->prefixes[i] = prefix;
   670 			prefix += strlen(prefix) + 1;
   671 		}
   672 		rpm->prefixes[i] = NULL;
   673 		rpm->n_prefixes = count;
   674 	} else {
   675 		prefix = razor_rpm_get_indirect(rpm, RPMTAG_DEFAULTPREFIX,
   676 						&count);
   677 		if (prefix) {
   678 			razor_rpm_close(rpm);
   679 			s = razor_concat(filename,
   680 					 ": Default prefix not supported",
   681 					 NULL);
   682 			razor_atomic_abort(atomic, s);
   683 			free(s);
   684 			return NULL;
   685 		}
   686 	}
   687 
   688 	return rpm;
   689 }
   690 
   691 RAZOR_EXPORT void razor_rpm_set_relocations(struct razor_rpm *rpm,
   692 					    struct razor_relocations *rr)
   693 {
   694 	assert (rpm != NULL);
   695 
   696 	rpm->relocations = rr;
   697 }
   698 
   699 struct cpio_file_header {
   700 	char magic[6];
   701 	char inode[8];
   702 	char mode[8];
   703 	char uid[8];
   704 	char gid[8];
   705 	char nlink[8];
   706 	char mtime[8];
   707 	char filesize[8];
   708 	char devmajor[8];
   709 	char devminor[8];
   710 	char rdevmajor[8];
   711 	char rdevminor[8];
   712 	char namesize[8];
   713 	char checksum[8];
   714 	char filename[0];
   715 };
   716 
   717 /* gzip flags */
   718 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
   719 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
   720 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
   721 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
   722 #define COMMENT      0x10 /* bit 4 set: file comment present */
   723 #define RESERVED     0xE0 /* bits 5..7: reserved */
   724 
   725 struct installer {
   726 	const char *root;
   727 	struct razor_rpm *rpm;
   728 	struct razor_atomic *atomic;
   729 	z_stream stream;
   730 	unsigned char buffer[32768];
   731 	size_t rest, length;
   732 };
   733 
   734 static int
   735 installer_inflate(struct installer *installer)
   736 {
   737 	size_t length;
   738 	int err;
   739 
   740 	if (installer->rest > sizeof installer->buffer)
   741 		length = sizeof installer->buffer;
   742 	else
   743 		length = installer->rest;
   744 
   745 	installer->stream.next_out = installer->buffer;
   746 	installer->stream.avail_out = length;
   747 	err = inflate(&installer->stream, Z_SYNC_FLUSH);
   748 	if (err != Z_OK && err != Z_STREAM_END) {
   749 		razor_atomic_abort(installer->atomic, "Failed to inflate");
   750 		return -1;
   751 	}
   752 
   753 	installer->rest -= length;
   754 	installer->length = length;
   755 
   756 	return 0;
   757 }
   758 
   759 static int
   760 installer_align(struct installer *installer, size_t size)
   761 {
   762 	unsigned char buffer[4];
   763 	int err;
   764 
   765 	installer->stream.next_out = buffer;
   766 	installer->stream.avail_out =
   767 		(size - installer->stream.total_out) & (size - 1);
   768 
   769 	if (installer->stream.avail_out == 0)
   770 		return 0;
   771 
   772 	err = inflate(&installer->stream, Z_SYNC_FLUSH);
   773 	if (err != Z_OK && err != Z_STREAM_END) {
   774 		razor_atomic_abort(installer->atomic, "Failed to inflate");
   775 		return -1;
   776 	}
   777 
   778 	return 0;
   779 }
   780 
   781 static int
   782 create_path(struct installer *installer, const char *path, unsigned int mode)
   783 {
   784 	char *s, *buffer;
   785 	int h, ret;
   786 
   787 	if (razor_atomic_make_dirs(installer->atomic, installer->root, path))
   788 		return -1;
   789 
   790 	buffer = razor_concat(installer->root, path, NULL);
   791 
   792 	switch (mode >> 12) {
   793 	case REG:
   794 		/* FIXME: handle the case where a file is already there. */
   795 		h = razor_atomic_create_file(installer->atomic, buffer, mode);
   796 		free(buffer);
   797 		if (h < 0)
   798 			return -1;
   799 		while (installer->rest > 0) {
   800 			if (installer_inflate(installer))
   801 				return -1;
   802 			if (razor_atomic_write(installer->atomic, h,
   803 					       installer->buffer,
   804 					       installer->length))
   805 				return -1;
   806 		}
   807 		return razor_atomic_close(installer->atomic, h);
   808 	case XDIR:
   809 		ret = razor_atomic_create_dir(installer->atomic, buffer, mode);
   810 		free(buffer);
   811 		return ret;
   812 	case LINK:
   813 #if HAVE_SYMLINK
   814 		if (installer_inflate(installer))
   815 			return -1;
   816 		if (installer->length >= sizeof installer->buffer) {
   817 			razor_atomic_abort(installer->atomic,
   818 			  "Link target too long");
   819 			return -1;
   820 		}
   821 		installer->buffer[installer->length] = '\0';
   822 		ret = razor_atomic_create_symlink(installer->atomic,
   823 		  (const char *)installer->buffer, buffer);
   824 		free(buffer);
   825 		return ret;
   826 #else
   827 		s = "Symbolic links";
   828 		goto unsupported;
   829 #endif
   830 	case PIPE:
   831 		s = "Named pipes";
   832 unsupported:
   833 		free(buffer);
   834 		buffer = razor_concat(s, " are not supported on this platform",
   835 		  NULL);
   836 		razor_atomic_abort(installer->atomic, buffer);
   837 		free(buffer);
   838 		return -1;
   839 	case CDEV:
   840 		s = "Character devices";
   841 		goto unsupported;
   842 	case BDEV:
   843 		s = "Block devices";
   844 		goto unsupported;
   845 	case SOCK:
   846 		s = "Named sockets";
   847 		goto unsupported;
   848 	default:
   849 		free(buffer);
   850 		razor_atomic_abort(installer->atomic, "Unknown file type");
   851 		return -1;
   852 	}
   853 }
   854 
   855 static int chroot_push(const char *root)
   856 {
   857 	int fd;
   858 #if HAVE_CHROOT
   859 	if (geteuid() == 0) {
   860 		fd = open("/", O_RDONLY, 0);
   861 		if (chroot(root) < 0) {
   862 			fprintf(stderr, "failed to chroot to %s: %s\n",
   863 				root, strerror(errno));
   864 			exit(-1);
   865 		}
   866 	} else
   867 #endif
   868 		fd = -1;
   869 	return fd;
   870 }
   871 
   872 static void chroot_pop(int fd)
   873 {
   874 #if HAVE_CHROOT
   875 	if (fd >= 0) {
   876 		fchdir(fd);
   877 		close(fd);
   878 		chroot(".");
   879 	}
   880 #endif
   881 }
   882 
   883 static int
   884 run_script_lua(const char *root, unsigned int script_tag, const char *script,
   885 	       int arg1)
   886 {
   887 	int root_fd, retval;
   888 #if HAVE_LUA
   889 	const char *name;
   890 
   891 	switch(script_tag) {
   892 		case RPMTAG_PREIN:
   893 			name = "%pre";
   894 			break;
   895 		case RPMTAG_POSTIN:
   896 			name = "%post";
   897 			break;
   898 		case RPMTAG_PREUN:
   899 			name = "%preun";
   900 			break;
   901 		case RPMTAG_POSTUN:
   902 			name = "%postun";
   903 			break;
   904 		default:
   905 			name = "script";
   906 			break;
   907 	}
   908 	root_fd = chroot_push(root);
   909 	retval = run_lua_script(root_fd < 0 ? root : NULL, name, script, -1,
   910 				arg1);
   911 	chroot_pop(root_fd);
   912 #else	/* HAVE_LUA */
   913 	fprintf(stderr, "lua not available to run script\n");
   914 	retval = -1;
   915 #endif	/* HAVE_LUA */
   916 
   917 	return retval;
   918 }
   919 
   920 static int
   921 run_script_external(const char *root, const char *program, const char *script,
   922 		    int arg1)
   923 {
   924 	int root_fd, retval;
   925 	FILE *fp;
   926 	char buf[32], *command;
   927 
   928 	if (program == NULL) {
   929 #if MSWIN_API
   930 		program = getenv("COMSPEC");
   931 		if (program) {
   932 			program = strchr(program, '=');
   933 			if (program)
   934 				program++;
   935 		}
   936 		if (!program)
   937 			program = "c:\\windows\\system32\\cmd.exe";
   938 #else
   939 		program = "/bin/sh";
   940 #endif
   941 	}
   942 
   943 	root_fd = chroot_push(root);
   944 	if (arg1 >= 0) {
   945 		sprintf(buf, "%d", arg1);
   946 		command = malloc(strlen(program) + strlen(buf) + 2);
   947 		sprintf(command, "%s %s", program, buf);
   948 	} else
   949 		command = strdup(program);
   950 	fp = popen(command, "w");
   951 	free(command);
   952 
   953 	if (!fp) {
   954 		perror(program);
   955 		retval = -1;
   956 	} else if (script && fwrite(script, strlen(script), 1, fp) != 1) {
   957 		perror("failed to write script to program");
   958 		retval = -1;
   959 	} else
   960 		retval = 0;
   961 
   962 	if (fp)
   963 		pclose(fp);
   964 	chroot_pop(root_fd);
   965 
   966 	return retval;
   967 }
   968 
   969 static int
   970 run_script(struct installer *installer,
   971 	   unsigned int program_tag, unsigned int script_tag, int arg1)
   972 {
   973 	int i, retval;
   974 	struct razor_rpm *rpm = installer->rpm;
   975 	const char *script = NULL, *program = NULL, *prefix;
   976 	char buf[32];
   977 	struct environment env;
   978 
   979 	program = razor_rpm_get_indirect(rpm, program_tag, NULL);
   980 	script = razor_rpm_get_indirect(rpm, script_tag, NULL);
   981 	if (program == NULL && script == NULL)
   982 		return 0;
   983 
   984 	if (rpm->relocations) {
   985 		environment_init(&env);
   986 		for(i = 0; i < rpm->n_prefixes; i++) {
   987 			prefix = razor_relocations_apply(rpm->relocations,
   988 							 rpm->prefixes[i]);
   989 			sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
   990 			environment_add_variable(&env, buf, prefix);
   991 		}
   992 		environment_set(&env);
   993 	}
   994 
   995 	if (program && strcmp(program, "<lua>") == 0)
   996 		retval = run_script_lua(installer->root, script_tag, script,
   997 					arg1);
   998 	else
   999 		retval = run_script_external(installer->root, program, script,
  1000 					     arg1);
  1001 
  1002 	if (rpm->relocations) {
  1003 		environment_unset(&env);
  1004 		environment_release(&env);
  1005 	}
  1006 
  1007 	return retval;
  1008 }
  1009 
  1010 int
  1011 razor_run_script(const char *root, enum razor_property_flags script,
  1012 		 const char *program, const char *body, int arg1)
  1013 {
  1014 	int retval;
  1015 	unsigned int script_tag;
  1016 
  1017 	if (program && !*program)
  1018 		program = NULL;
  1019 	if (body && !*body)
  1020 		body = NULL;
  1021 	if (program == NULL && body == NULL)
  1022 		return 0;
  1023 
  1024 	if (program && strcmp(program, "<lua>") == 0)
  1025 	{
  1026 		switch(script) {
  1027 		case RAZOR_PROPERTY_PRE:
  1028 			script_tag = RPMTAG_PREIN;
  1029 			break;
  1030 		case RAZOR_PROPERTY_POST:
  1031 			script_tag = RPMTAG_POSTIN;
  1032 			break;
  1033 		case RAZOR_PROPERTY_PREUN:
  1034 			script_tag = RPMTAG_PREUN;
  1035 			break;
  1036 		case RAZOR_PROPERTY_POSTUN:
  1037 			script_tag = RPMTAG_POSTUN;
  1038 			break;
  1039 		default:
  1040 			script_tag = 0;
  1041 			break;
  1042 		}
  1043 		retval = run_script_lua(root, script_tag, body, arg1);
  1044 	}
  1045 	else
  1046 		retval = run_script_external(root, program, body, arg1);
  1047 
  1048 	return retval;
  1049 }
  1050 
  1051 static int
  1052 installer_init(struct installer *installer)
  1053 {
  1054 	unsigned char *gz_header;
  1055 	int method, flags, err;
  1056 	char buffer[32], *s;
  1057 
  1058 	gz_header = installer->rpm->payload;
  1059 	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
  1060 		razor_atomic_abort(installer->atomic, 
  1061 				   "Payload section doesn't have gz header");
  1062 		return -1;
  1063 	}
  1064 
  1065 	method = gz_header[2];
  1066 	flags = gz_header[3];
  1067 
  1068 	if (method != Z_DEFLATED || flags != 0) {
  1069 		razor_atomic_abort(installer->atomic, 
  1070 				   "Unknown payload compression method or "
  1071 				   "flags set");
  1072 		return -1;
  1073 	}
  1074 
  1075 	installer->stream.zalloc = NULL;
  1076 	installer->stream.zfree = NULL;
  1077 	installer->stream.opaque = NULL;
  1078 
  1079 	installer->stream.next_in  = gz_header + 10;
  1080 	installer->stream.avail_in =
  1081 		(installer->rpm->map + installer->rpm->size) -
  1082 		(void *) installer->stream.next_in;
  1083 	installer->stream.next_out = NULL;
  1084 	installer->stream.avail_out = 0;
  1085 
  1086 	err = inflateInit2(&installer->stream, -MAX_WBITS);
  1087 	if (err != Z_OK) {
  1088 		sprintf(buffer, "%d", err);
  1089 		s = razor_concat("inflateEnd error: ", s, NULL);
  1090 		razor_atomic_abort(installer->atomic, s);
  1091 		free(s);
  1092 		return -1;
  1093 	}
  1094 
  1095 	return 0;
  1096 }
  1097 
  1098 static int
  1099 installer_finish(struct installer *installer)
  1100 {
  1101 	int err;
  1102 	char buffer[32], *s;
  1103 
  1104 	err = inflateEnd(&installer->stream);
  1105 
  1106 	if (err != Z_OK) {
  1107 		sprintf(buffer, "%d", err);
  1108 		s = razor_concat("inflateEnd error: ", s, NULL);
  1109 		razor_atomic_abort(installer->atomic, s);
  1110 		free(s);
  1111 	}
  1112 
  1113 	return razor_atomic_in_error_state(installer->atomic);
  1114 }
  1115 
  1116 static unsigned long
  1117 fixed_hex_to_ulong(const char *hex, int length)
  1118 {
  1119 	long l;
  1120 	int i;
  1121 
  1122 	for (i = 0, l = 0; i < length; i++) {
  1123 		if (hex[i] < 'a')
  1124 			l = l * 16 + hex[i] - '0';
  1125 		else
  1126 			l = l * 16 + hex[i] - 'a' + 10;
  1127 	}
  1128 
  1129 	return l;
  1130 }
  1131 
  1132 RAZOR_EXPORT int
  1133 razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic,
  1134 		  const char *root, int install_count,
  1135 		  enum razor_stage_type stage)
  1136 {
  1137 	struct installer installer;
  1138 	struct cpio_file_header *header;
  1139 	struct stat buf;
  1140 	unsigned int mode;
  1141 	const char *path, *name;
  1142 	size_t filesize;
  1143 	char *s;
  1144 
  1145 	assert (rpm != NULL);
  1146 	assert (root != NULL);
  1147 
  1148 	installer.rpm = rpm;
  1149 	installer.root = root;
  1150 	installer.atomic = atomic;
  1151 
  1152 	/* FIXME: Only do this before a transaction, not per rpm. */
  1153 	if (*root && (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode))) {
  1154 		s = razor_concat(root, ": Directory does not exist", NULL);
  1155 		razor_atomic_abort(stderr, s);
  1156 		free(s);
  1157 		return -1;
  1158 	}
  1159 
  1160 	if (rpm->relocations)
  1161 		razor_relocations_set_rpm(rpm->relocations, rpm);
  1162 
  1163 	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
  1164 		run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN,
  1165 			   install_count);
  1166 
  1167 	if (stage & RAZOR_STAGE_FILES) {
  1168 		if (installer_init(&installer))
  1169 			return -1;
  1170 
  1171 		while (installer.stream.avail_in > 0) {
  1172 			installer.rest = sizeof *header;
  1173 			if (installer_inflate(&installer))
  1174 				break;
  1175 
  1176 			header = (struct cpio_file_header *) installer.buffer;
  1177 			mode = fixed_hex_to_ulong(header->mode,
  1178 						  sizeof header->mode);
  1179 			filesize = fixed_hex_to_ulong(header->filesize,
  1180 						      sizeof header->filesize);
  1181 
  1182 			installer.rest =
  1183 			  fixed_hex_to_ulong(header->namesize,
  1184 					     sizeof header->namesize);
  1185 
  1186 			if (installer_inflate(&installer) ||
  1187 			    installer_align(&installer, 4))
  1188 				break;
  1189 
  1190 			path = (const char *) installer.buffer;
  1191 			/* This convention is so lame... */
  1192 			if (strcmp(path, "TRAILER!!!") == 0)
  1193 				break;
  1194 
  1195 			installer.rest = filesize;
  1196 			path++;
  1197 			if (rpm->relocations)
  1198 				path = razor_relocations_apply(rpm->relocations,
  1199 							       path);
  1200 			if (create_path(&installer, path, mode))
  1201 				break;
  1202 			if (installer_align(&installer, 4))
  1203 				break;
  1204 		}
  1205 
  1206 		if (installer_finish(&installer))
  1207 			return -1;
  1208 	}
  1209 
  1210 	if (stage & RAZOR_STAGE_SCRIPTS_POST)
  1211 		run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN,
  1212 			   install_count);
  1213 
  1214 	return 0;
  1215 }
  1216 
  1217 RAZOR_EXPORT int
  1218 razor_rpm_close(struct razor_rpm *rpm)
  1219 {
  1220 	int err;
  1221 
  1222 	assert (rpm != NULL);
  1223 
  1224 	free(rpm->dirs);
  1225 	free(rpm->prefixes);
  1226 	err = razor_file_free_contents(rpm->map, rpm->size);
  1227 	free(rpm->evr);
  1228 	free(rpm);
  1229 
  1230 	return err;
  1231 }
  1232 
  1233 RAZOR_EXPORT int
  1234 razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
  1235 {
  1236 	const char *name, *version, *arch;
  1237 	const char *summary, *description, *url, *license;
  1238 
  1239 	assert (importer != NULL);
  1240 	assert (rpm != NULL);
  1241 
  1242 	razor_rpm_get_details(rpm,
  1243 			      RAZOR_DETAIL_NAME, &name,
  1244 			      RAZOR_DETAIL_VERSION, &version,
  1245 			      RAZOR_DETAIL_ARCH, &arch,
  1246 			      RAZOR_DETAIL_SUMMARY, &summary,
  1247 			      RAZOR_DETAIL_DESCRIPTION, &description,
  1248 			      RAZOR_DETAIL_URL, &url,
  1249 			      RAZOR_DETAIL_LICENSE, &license,
  1250 			      RAZOR_DETAIL_LAST);
  1251 
  1252 	razor_importer_begin_package(importer, name, version, arch);
  1253 
  1254 	razor_importer_add_details(importer, summary, description, url,
  1255 				   license);
  1256 
  1257 	import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
  1258 			  RPMTAG_REQUIRENAME,
  1259 			  RPMTAG_REQUIREVERSION,
  1260 			  RPMTAG_REQUIREFLAGS);
  1261 
  1262 	import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
  1263 			  RPMTAG_PROVIDENAME,
  1264 			  RPMTAG_PROVIDEVERSION,
  1265 			  RPMTAG_PROVIDEFLAGS);
  1266 
  1267 	import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
  1268 			  RPMTAG_OBSOLETENAME,
  1269 			  RPMTAG_OBSOLETEVERSION,
  1270 			  RPMTAG_OBSOLETEFLAGS);
  1271 
  1272 	import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
  1273 			  RPMTAG_CONFLICTNAME,
  1274 			  RPMTAG_CONFLICTVERSION,
  1275 			  RPMTAG_CONFLICTFLAGS);
  1276 
  1277 	import_files(importer, rpm);
  1278 
  1279 	razor_importer_finish_package(importer);
  1280 
  1281 	return 0;
  1282 }