librazor/rpm.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Aug 23 11:13:48 2014 +0100 (2014-08-23)
changeset 440 48204dea0b9f
parent 424 8cbc438cc298
child 442 c4bcba8023a9
permissions -rw-r--r--
Remove INTLLIBS from librazor_la_LIBADD.

This partially reverts 611c84a3f4b4538a65d186050608c17adbf17770.
It's not clear what motivated the initial inclusion of INTLLIBS
here since the net effect is only seen in librazor.la and not
in razor.pc and librazor.la is not normally packaged. Certainly
neither the static nor the dynamic versions of librazor currently
use libintl. At best this would cause the linker to search a
static libintl for undefined symbols without finding any; at worse
it causes a static build of plover using librazor.la to fail if
no static version of libintl is installed.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011, 2012  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_error **error)
   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 
   612 	assert (filename != NULL);
   613 
   614 	rpm = zalloc(sizeof *rpm);
   615 	if (rpm == NULL) {
   616 		razor_set_error(error, NULL, "Not enough memory");
   617 		return NULL;
   618 	}
   619 	memset(rpm, 0, sizeof *rpm);
   620 
   621 	rpm->map = razor_file_get_contents(filename, &rpm->size, 0, error);
   622 	if (!rpm->map) {
   623 		free(rpm);
   624 		return NULL;
   625 	}
   626 
   627 	rpm->signature = rpm->map + RPM_LEAD_SIZE;
   628 	nindex = ntohl(rpm->signature->nindex);
   629 	hsize = ntohl(rpm->signature->hsize);
   630 	rpm->header = (void *) (rpm->signature + 1) +
   631 		ALIGN(nindex * sizeof *index + hsize, 8);
   632 	nindex = ntohl(rpm->header->nindex);
   633 	hsize = ntohl(rpm->header->hsize);
   634 	rpm->payload = (void *) (rpm->header + 1) +
   635 		nindex * sizeof *index + hsize;
   636 
   637 	base = (struct rpm_header_index *) (rpm->header + 1);
   638 	rpm->pool = (void *) base + nindex * sizeof *index;
   639 
   640 	/* Look up dir names now so we can index them directly. */
   641 	name = razor_rpm_get_indirect(rpm, RPMTAG_DIRNAMES, &count);
   642 	if (name) {
   643 		rpm->dirs = calloc(count, sizeof *rpm->dirs);
   644 		for (i = 0; i < count; i++) {
   645 			rpm->dirs[i] = name;
   646 			name += strlen(name) + 1;
   647 		}
   648 	} else {
   649 		name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES,
   650 					      &count);
   651 		if (name) {
   652 			razor_rpm_close(rpm);
   653 			razor_set_error(error, filename,
   654 					"Old filenames not supported");
   655 			return NULL;
   656 		}
   657 	}
   658 
   659 	prefix = razor_rpm_get_indirect(rpm, RPMTAG_PREFIXES, &count);
   660 	if (prefix) {
   661 		rpm->prefixes = calloc(count + 1, sizeof *rpm->prefixes);
   662 		for (i = 0; i < count; i++) {
   663 			rpm->prefixes[i] = prefix;
   664 			prefix += strlen(prefix) + 1;
   665 		}
   666 		rpm->prefixes[i] = NULL;
   667 		rpm->n_prefixes = count;
   668 	} else {
   669 		prefix = razor_rpm_get_indirect(rpm, RPMTAG_DEFAULTPREFIX,
   670 						&count);
   671 		if (prefix) {
   672 			razor_rpm_close(rpm);
   673 			razor_set_error(error, filename,
   674 					"Default prefix not supported");
   675 			return NULL;
   676 		}
   677 	}
   678 
   679 	return rpm;
   680 }
   681 
   682 RAZOR_EXPORT void razor_rpm_set_relocations(struct razor_rpm *rpm,
   683 					    struct razor_relocations *rr)
   684 {
   685 	assert (rpm != NULL);
   686 
   687 	rpm->relocations = rr;
   688 }
   689 
   690 struct cpio_file_header {
   691 	char magic[6];
   692 	char inode[8];
   693 	char mode[8];
   694 	char uid[8];
   695 	char gid[8];
   696 	char nlink[8];
   697 	char mtime[8];
   698 	char filesize[8];
   699 	char devmajor[8];
   700 	char devminor[8];
   701 	char rdevmajor[8];
   702 	char rdevminor[8];
   703 	char namesize[8];
   704 	char checksum[8];
   705 	char filename[0];
   706 };
   707 
   708 /* gzip flags */
   709 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
   710 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
   711 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
   712 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
   713 #define COMMENT      0x10 /* bit 4 set: file comment present */
   714 #define RESERVED     0xE0 /* bits 5..7: reserved */
   715 
   716 struct installer {
   717 	const char *root;
   718 	struct razor_rpm *rpm;
   719 	struct razor_atomic *atomic;
   720 	z_stream stream;
   721 	unsigned char buffer[32768];
   722 	size_t rest, length;
   723 };
   724 
   725 static int
   726 installer_inflate(struct installer *installer)
   727 {
   728 	size_t length;
   729 	int err;
   730 
   731 	if (installer->rest > sizeof installer->buffer)
   732 		length = sizeof installer->buffer;
   733 	else
   734 		length = installer->rest;
   735 
   736 	installer->stream.next_out = installer->buffer;
   737 	installer->stream.avail_out = length;
   738 	err = inflate(&installer->stream, Z_SYNC_FLUSH);
   739 	if (err != Z_OK && err != Z_STREAM_END) {
   740 		razor_atomic_abort(installer->atomic, "Failed to inflate");
   741 		return -1;
   742 	}
   743 
   744 	installer->rest -= length;
   745 	installer->length = length;
   746 
   747 	return 0;
   748 }
   749 
   750 static int
   751 installer_align(struct installer *installer, size_t size)
   752 {
   753 	unsigned char buffer[4];
   754 	int err;
   755 
   756 	installer->stream.next_out = buffer;
   757 	installer->stream.avail_out =
   758 		(size - installer->stream.total_out) & (size - 1);
   759 
   760 	if (installer->stream.avail_out == 0)
   761 		return 0;
   762 
   763 	err = inflate(&installer->stream, Z_SYNC_FLUSH);
   764 	if (err != Z_OK && err != Z_STREAM_END) {
   765 		razor_atomic_abort(installer->atomic, "Failed to inflate");
   766 		return -1;
   767 	}
   768 
   769 	return 0;
   770 }
   771 
   772 static int
   773 create_path(struct installer *installer, const char *path, unsigned int mode)
   774 {
   775 	char *s, *buffer;
   776 	int h, ret;
   777 
   778 	if (razor_atomic_make_dirs(installer->atomic, installer->root, path))
   779 		return -1;
   780 
   781 	buffer = razor_concat(installer->root, path, NULL);
   782 
   783 	switch (mode >> 12) {
   784 	case REG:
   785 		/* FIXME: handle the case where a file is already there. */
   786 		h = razor_atomic_create_file(installer->atomic, buffer, mode);
   787 		free(buffer);
   788 		if (h < 0)
   789 			return -1;
   790 		while (installer->rest > 0) {
   791 			if (installer_inflate(installer))
   792 				return -1;
   793 			if (razor_atomic_write(installer->atomic, h,
   794 					       installer->buffer,
   795 					       installer->length))
   796 				return -1;
   797 		}
   798 		return razor_atomic_close(installer->atomic, h);
   799 	case XDIR:
   800 		ret = razor_atomic_create_dir(installer->atomic, buffer, mode);
   801 		free(buffer);
   802 		return ret;
   803 	case LINK:
   804 #if HAVE_SYMLINK
   805 		if (installer_inflate(installer))
   806 			return -1;
   807 		if (installer->length >= sizeof installer->buffer) {
   808 			razor_atomic_abort(installer->atomic,
   809 			  "Link target too long");
   810 			return -1;
   811 		}
   812 		installer->buffer[installer->length] = '\0';
   813 		ret = razor_atomic_create_symlink(installer->atomic,
   814 		  (const char *)installer->buffer, buffer);
   815 		free(buffer);
   816 		return ret;
   817 #else
   818 		s = "Symbolic links";
   819 		goto unsupported;
   820 #endif
   821 	case PIPE:
   822 		s = "Named pipes";
   823 unsupported:
   824 		free(buffer);
   825 		buffer = razor_concat(s, " are not supported on this platform",
   826 		  NULL);
   827 		razor_atomic_abort(installer->atomic, buffer);
   828 		free(buffer);
   829 		return -1;
   830 	case CDEV:
   831 		s = "Character devices";
   832 		goto unsupported;
   833 	case BDEV:
   834 		s = "Block devices";
   835 		goto unsupported;
   836 	case SOCK:
   837 		s = "Named sockets";
   838 		goto unsupported;
   839 	default:
   840 		free(buffer);
   841 		razor_atomic_abort(installer->atomic, "Unknown file type");
   842 		return -1;
   843 	}
   844 }
   845 
   846 static int chroot_push(const char *root)
   847 {
   848 	int fd;
   849 #if HAVE_CHROOT
   850 	if (geteuid() == 0) {
   851 		fd = open("/", O_RDONLY, 0);
   852 		if (chroot(root) < 0) {
   853 			fprintf(stderr, "failed to chroot to %s: %s\n",
   854 				root, strerror(errno));
   855 			exit(-1);
   856 		}
   857 	} else
   858 #endif
   859 		fd = -1;
   860 	return fd;
   861 }
   862 
   863 static void chroot_pop(int fd)
   864 {
   865 #if HAVE_CHROOT
   866 	if (fd >= 0) {
   867 		fchdir(fd);
   868 		close(fd);
   869 		chroot(".");
   870 	}
   871 #endif
   872 }
   873 
   874 static int
   875 run_script_lua(const char *root, unsigned int script_tag, const char *script,
   876 	       int arg1)
   877 {
   878 	int root_fd, retval;
   879 #if HAVE_LUA
   880 	const char *name;
   881 
   882 	switch(script_tag) {
   883 		case RPMTAG_PREIN:
   884 			name = "%pre";
   885 			break;
   886 		case RPMTAG_POSTIN:
   887 			name = "%post";
   888 			break;
   889 		case RPMTAG_PREUN:
   890 			name = "%preun";
   891 			break;
   892 		case RPMTAG_POSTUN:
   893 			name = "%postun";
   894 			break;
   895 		default:
   896 			name = "script";
   897 			break;
   898 	}
   899 	root_fd = chroot_push(root);
   900 	retval = run_lua_script(root_fd < 0 ? root : NULL, name, script, -1,
   901 				arg1);
   902 	chroot_pop(root_fd);
   903 #else	/* HAVE_LUA */
   904 	fprintf(stderr, "lua not available to run script\n");
   905 	retval = -1;
   906 #endif	/* HAVE_LUA */
   907 
   908 	return retval;
   909 }
   910 
   911 static int
   912 run_script_external(const char *root, const char *program, const char *script,
   913 		    int arg1)
   914 {
   915 	int root_fd, retval;
   916 	FILE *fp;
   917 	char buf[32], *command;
   918 
   919 	if (program == NULL) {
   920 #if MSWIN_API
   921 		program = getenv("COMSPEC");
   922 		if (program) {
   923 			program = strchr(program, '=');
   924 			if (program)
   925 				program++;
   926 		}
   927 		if (!program)
   928 			program = "c:\\windows\\system32\\cmd.exe";
   929 #else
   930 		program = "/bin/sh";
   931 #endif
   932 	}
   933 
   934 	root_fd = chroot_push(root);
   935 	if (arg1 >= 0) {
   936 		sprintf(buf, "%d", arg1);
   937 		command = malloc(strlen(program) + strlen(buf) + 2);
   938 		sprintf(command, "%s %s", program, buf);
   939 	} else
   940 		command = strdup(program);
   941 	fp = popen(command, "w");
   942 	free(command);
   943 
   944 	if (!fp) {
   945 		perror(program);
   946 		retval = -1;
   947 	} else if (script && fwrite(script, strlen(script), 1, fp) != 1) {
   948 		perror("failed to write script to program");
   949 		retval = -1;
   950 	} else
   951 		retval = 0;
   952 
   953 	if (fp)
   954 		pclose(fp);
   955 	chroot_pop(root_fd);
   956 
   957 	return retval;
   958 }
   959 
   960 static int
   961 run_script(struct installer *installer,
   962 	   unsigned int program_tag, unsigned int script_tag, int arg1)
   963 {
   964 	int i, retval;
   965 	struct razor_rpm *rpm = installer->rpm;
   966 	const char *script = NULL, *program = NULL, *prefix;
   967 	char buf[32];
   968 	struct environment env;
   969 
   970 	program = razor_rpm_get_indirect(rpm, program_tag, NULL);
   971 	script = razor_rpm_get_indirect(rpm, script_tag, NULL);
   972 	if (program == NULL && script == NULL)
   973 		return 0;
   974 
   975 	if (rpm->relocations) {
   976 		environment_init(&env);
   977 		for(i = 0; i < rpm->n_prefixes; i++) {
   978 			prefix = razor_relocations_apply(rpm->relocations,
   979 							 rpm->prefixes[i]);
   980 			sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
   981 			environment_add_variable(&env, buf, prefix);
   982 		}
   983 		environment_set(&env);
   984 	}
   985 
   986 	if (program && strcmp(program, "<lua>") == 0)
   987 		retval = run_script_lua(installer->root, script_tag, script,
   988 					arg1);
   989 	else
   990 		retval = run_script_external(installer->root, program, script,
   991 					     arg1);
   992 
   993 	if (rpm->relocations) {
   994 		environment_unset(&env);
   995 		environment_release(&env);
   996 	}
   997 
   998 	return retval;
   999 }
  1000 
  1001 int
  1002 razor_run_script(const char *root, enum razor_property_flags script,
  1003 		 const char *program, const char *body, int arg1)
  1004 {
  1005 	int retval;
  1006 	unsigned int script_tag;
  1007 
  1008 	if (program && !*program)
  1009 		program = NULL;
  1010 	if (body && !*body)
  1011 		body = NULL;
  1012 	if (program == NULL && body == NULL)
  1013 		return 0;
  1014 
  1015 	if (program && strcmp(program, "<lua>") == 0)
  1016 	{
  1017 		switch(script) {
  1018 		case RAZOR_PROPERTY_PRE:
  1019 			script_tag = RPMTAG_PREIN;
  1020 			break;
  1021 		case RAZOR_PROPERTY_POST:
  1022 			script_tag = RPMTAG_POSTIN;
  1023 			break;
  1024 		case RAZOR_PROPERTY_PREUN:
  1025 			script_tag = RPMTAG_PREUN;
  1026 			break;
  1027 		case RAZOR_PROPERTY_POSTUN:
  1028 			script_tag = RPMTAG_POSTUN;
  1029 			break;
  1030 		default:
  1031 			script_tag = 0;
  1032 			break;
  1033 		}
  1034 		retval = run_script_lua(root, script_tag, body, arg1);
  1035 	}
  1036 	else
  1037 		retval = run_script_external(root, program, body, arg1);
  1038 
  1039 	return retval;
  1040 }
  1041 
  1042 static int
  1043 installer_init(struct installer *installer)
  1044 {
  1045 	unsigned char *gz_header;
  1046 	int method, flags, err;
  1047 	char buffer[32], *s;
  1048 
  1049 	gz_header = installer->rpm->payload;
  1050 	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
  1051 		razor_atomic_abort(installer->atomic, 
  1052 				   "Payload section doesn't have gz header");
  1053 		return -1;
  1054 	}
  1055 
  1056 	method = gz_header[2];
  1057 	flags = gz_header[3];
  1058 
  1059 	if (method != Z_DEFLATED || flags != 0) {
  1060 		razor_atomic_abort(installer->atomic, 
  1061 				   "Unknown payload compression method or "
  1062 				   "flags set");
  1063 		return -1;
  1064 	}
  1065 
  1066 	installer->stream.zalloc = NULL;
  1067 	installer->stream.zfree = NULL;
  1068 	installer->stream.opaque = NULL;
  1069 
  1070 	installer->stream.next_in  = gz_header + 10;
  1071 	installer->stream.avail_in =
  1072 		(installer->rpm->map + installer->rpm->size) -
  1073 		(void *) installer->stream.next_in;
  1074 	installer->stream.next_out = NULL;
  1075 	installer->stream.avail_out = 0;
  1076 
  1077 	err = inflateInit2(&installer->stream, -MAX_WBITS);
  1078 	if (err != Z_OK) {
  1079 		sprintf(buffer, "%d", err);
  1080 		s = razor_concat("inflateEnd error: ", s, NULL);
  1081 		razor_atomic_abort(installer->atomic, s);
  1082 		free(s);
  1083 		return -1;
  1084 	}
  1085 
  1086 	return 0;
  1087 }
  1088 
  1089 static int
  1090 installer_finish(struct installer *installer)
  1091 {
  1092 	int err;
  1093 	char buffer[32], *s;
  1094 
  1095 	err = inflateEnd(&installer->stream);
  1096 
  1097 	if (err != Z_OK) {
  1098 		sprintf(buffer, "%d", err);
  1099 		s = razor_concat("inflateEnd error: ", s, NULL);
  1100 		razor_atomic_abort(installer->atomic, s);
  1101 		free(s);
  1102 	}
  1103 
  1104 	return razor_atomic_in_error_state(installer->atomic);
  1105 }
  1106 
  1107 static unsigned long
  1108 fixed_hex_to_ulong(const char *hex, int length)
  1109 {
  1110 	long l;
  1111 	int i;
  1112 
  1113 	for (i = 0, l = 0; i < length; i++) {
  1114 		if (hex[i] < 'a')
  1115 			l = l * 16 + hex[i] - '0';
  1116 		else
  1117 			l = l * 16 + hex[i] - 'a' + 10;
  1118 	}
  1119 
  1120 	return l;
  1121 }
  1122 
  1123 RAZOR_EXPORT int
  1124 razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic,
  1125 		  const char *root, int install_count,
  1126 		  enum razor_stage_type stage)
  1127 {
  1128 	struct installer installer;
  1129 	struct cpio_file_header *header;
  1130 	struct stat buf;
  1131 	unsigned int mode;
  1132 	const char *path;
  1133 	size_t filesize;
  1134 	char *s;
  1135 	int retval = 0;
  1136 
  1137 	assert (rpm != NULL);
  1138 	assert (root != NULL);
  1139 
  1140 	installer.rpm = rpm;
  1141 	installer.root = root;
  1142 	installer.atomic = atomic;
  1143 
  1144 	/* FIXME: Only do this before a transaction, not per rpm. */
  1145 	if (*root && (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode))) {
  1146 		s = razor_concat(root, ": Directory does not exist", NULL);
  1147 		razor_atomic_abort(atomic, s);
  1148 		free(s);
  1149 		return -1;
  1150 	}
  1151 
  1152 	if (rpm->relocations)
  1153 		razor_relocations_set_rpm(rpm->relocations, rpm);
  1154 
  1155 	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
  1156 		retval = run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN,
  1157 				    install_count);
  1158 
  1159 	if (!retval && (stage & RAZOR_STAGE_FILES)) {
  1160 		if (installer_init(&installer))
  1161 			return -1;
  1162 
  1163 		while (installer.stream.avail_in > 0) {
  1164 			installer.rest = sizeof *header;
  1165 			if (installer_inflate(&installer))
  1166 				break;
  1167 
  1168 			header = (struct cpio_file_header *) installer.buffer;
  1169 			mode = fixed_hex_to_ulong(header->mode,
  1170 						  sizeof header->mode);
  1171 			filesize = fixed_hex_to_ulong(header->filesize,
  1172 						      sizeof header->filesize);
  1173 
  1174 			installer.rest =
  1175 			  fixed_hex_to_ulong(header->namesize,
  1176 					     sizeof header->namesize);
  1177 
  1178 			if (installer_inflate(&installer) ||
  1179 			    installer_align(&installer, 4))
  1180 				break;
  1181 
  1182 			path = (const char *) installer.buffer;
  1183 			/* This convention is so lame... */
  1184 			if (strcmp(path, "TRAILER!!!") == 0)
  1185 				break;
  1186 
  1187 			installer.rest = filesize;
  1188 			path++;
  1189 			if (rpm->relocations)
  1190 				path = razor_relocations_apply(rpm->relocations,
  1191 							       path);
  1192 			if (create_path(&installer, path, mode))
  1193 				break;
  1194 			if (installer_align(&installer, 4))
  1195 				break;
  1196 		}
  1197 
  1198 		if (installer_finish(&installer))
  1199 			return -1;
  1200 
  1201 		retval = razor_atomic_in_error_state(atomic);
  1202 	}
  1203 
  1204 	if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST))
  1205 		retval = run_script(&installer, RPMTAG_POSTINPROG,
  1206 				    RPMTAG_POSTIN, install_count);
  1207 
  1208 	return retval;
  1209 }
  1210 
  1211 RAZOR_EXPORT int
  1212 razor_rpm_close(struct razor_rpm *rpm)
  1213 {
  1214 	int err;
  1215 
  1216 	assert (rpm != NULL);
  1217 
  1218 	free(rpm->dirs);
  1219 	free(rpm->prefixes);
  1220 	err = razor_file_free_contents(rpm->map, rpm->size);
  1221 	free(rpm->evr);
  1222 	free(rpm);
  1223 
  1224 	return err;
  1225 }
  1226 
  1227 RAZOR_EXPORT int
  1228 razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
  1229 {
  1230 	const char *name, *version, *arch;
  1231 	const char *summary, *description, *url, *license;
  1232 
  1233 	assert (importer != NULL);
  1234 	assert (rpm != NULL);
  1235 
  1236 	razor_rpm_get_details(rpm,
  1237 			      RAZOR_DETAIL_NAME, &name,
  1238 			      RAZOR_DETAIL_VERSION, &version,
  1239 			      RAZOR_DETAIL_ARCH, &arch,
  1240 			      RAZOR_DETAIL_SUMMARY, &summary,
  1241 			      RAZOR_DETAIL_DESCRIPTION, &description,
  1242 			      RAZOR_DETAIL_URL, &url,
  1243 			      RAZOR_DETAIL_LICENSE, &license,
  1244 			      RAZOR_DETAIL_LAST);
  1245 
  1246 	razor_importer_begin_package(importer, name, version, arch);
  1247 
  1248 	razor_importer_add_details(importer, summary, description, url,
  1249 				   license);
  1250 
  1251 	import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
  1252 			  RPMTAG_REQUIRENAME,
  1253 			  RPMTAG_REQUIREVERSION,
  1254 			  RPMTAG_REQUIREFLAGS);
  1255 
  1256 	import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
  1257 			  RPMTAG_PROVIDENAME,
  1258 			  RPMTAG_PROVIDEVERSION,
  1259 			  RPMTAG_PROVIDEFLAGS);
  1260 
  1261 	import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
  1262 			  RPMTAG_OBSOLETENAME,
  1263 			  RPMTAG_OBSOLETEVERSION,
  1264 			  RPMTAG_OBSOLETEFLAGS);
  1265 
  1266 	import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
  1267 			  RPMTAG_CONFLICTNAME,
  1268 			  RPMTAG_CONFLICTVERSION,
  1269 			  RPMTAG_CONFLICTFLAGS);
  1270 
  1271 	import_files(importer, rpm);
  1272 
  1273 	razor_importer_finish_package(importer);
  1274 
  1275 	return 0;
  1276 }