librazor/rpm.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Oct 04 18:12:58 2014 +0100 (2014-10-04)
changeset 454 56ff755c268c
parent 442 c4bcba8023a9
child 458 3f841a46eab5
permissions -rw-r--r--
Only export symbols starting with razor_ in dynamic library.

Apart from being good practice to avoid clashes with higher-level
libraries and the application, this also fixes an obscure bug: The
gnulib library is used both by librazor (the dynamic library) and
by razor (the executable). In doing so, we want to have two separate
copies of the library despite the code duplication this involves.
Without the explicit limit to export only razor_ symbols, the razor
executable under mingw64 was picking up the getopt_long function
from librazor and the optind variable from libgnu which meant that
it did not see optind changing. Hiding librazor's copy of getopt
causes the linker to find libgnu's copy and everything works.

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