libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

commit a3dd5dda7b0815165822611d755b39008e1d531c
parent 8d6bfc09d4cd977eac92a5cf7011e07ffe31bbf8
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue, 22 Jul 2008 08:56:49 +0000

use librpm

Diffstat:
MChangeLog | 4++++
MREADME.debian | 1+
Mconfigure.ac | 5+++++
Msrc/main/extractor.c | 14++++++++++++++
Msrc/plugins/Makefile.am | 6+++++-
Msrc/plugins/rpm/Makefile.am | 1+
Msrc/plugins/rpm/rpmextractor.c | 3233+++----------------------------------------------------------------------------
Msrc/plugins/thumbnailextractorqt.cc | 50++++++++++++++++++++++++++++++++++++++++++++------
Msrc/test/fuzz_default.sh | 2+-
Msrc/test/fuzz_thumbnail.sh | 2+-
Msrc/test/mt_plugintest2.c | 22++++++++++++++--------
11 files changed, 180 insertions(+), 3160 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,7 @@ +Tue Jul 22 02:51:33 MDT 2008 + Changed RPM extractor to use librpm. + Fixed crash in OpenOffice extractor. + Sun Jul 13 19:31:35 MDT 2008 Fixed endianess issues in mp3 extractor. Fixed build issues (need to link C++ code explicitly against diff --git a/README.debian b/README.debian @@ -18,6 +18,7 @@ libbz2-dev libgsf-1-dev libmpeg2-4-dev libqt4-dev +librpm-dev For Subversion access and compilation: diff --git a/configure.ac b/configure.ac @@ -194,6 +194,11 @@ AC_CHECK_LIB(z, inflate, AC_DEFINE(HAVE_ZLIB,1,[Have zlib])], [AM_CONDITIONAL(HAVE_ZLIB, false)]) +AC_CHECK_LIB(rpm, rpmReadPackageFile, + [AM_CONDITIONAL(HAVE_LIBRPM, true) + AC_DEFINE(HAVE_LIBRPM,1,[Have librpm])], + [AM_CONDITIONAL(HAVE_LIBRPM, false)]) + AC_CHECK_LIB(bz2, BZ2_decompress, [AM_CONDITIONAL(HAVE_BZ2, true) AC_DEFINE(HAVE_LIBBZ2,1,[Have libbz2])], diff --git a/src/main/extractor.c b/src/main/extractor.c @@ -787,8 +787,20 @@ loadLibrary (const char *name, void **libHandle, ExtractMethod * method) { +#if 0 + lt_dladvise advise; +#endif + LTDL_MUTEX_LOCK +#if 0 + lt_dladvise_init(&advise); + lt_dladvise_ext(&advise); + lt_dladvise_local(&advise); + *libHandle = lt_dlopenadvise (name, &advise); + lt_dladvise_destroy(&advise); +#else *libHandle = lt_dlopenext (name); +#endif if (*libHandle == NULL) { #if DEBUG @@ -1725,6 +1737,8 @@ int EXTRACTOR_binaryDecode(const char * in, } buf = malloc(inSize); /* slightly more than needed ;-) */ + if (buf == NULL) + return 1; /* error */ *out = buf; pos = 0; diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am @@ -6,6 +6,10 @@ if HAVE_FFMPEG thumbffmpeg=thumbnailffmpeg endif +if HAVE_LIBRPM +rpm=rpm +endif + if HAVE_GLIB if WITH_GSF oledir=ole2 @@ -56,7 +60,7 @@ endif # toggle for development # SUBDIRS = . -SUBDIRS = $(thumbgtk) $(thumbffmpeg) . $(oodir) $(printdir) hash $(oledir) rpm $(xpdfdir) $(exiv2dir) +SUBDIRS = $(thumbgtk) $(thumbffmpeg) . $(oodir) $(printdir) hash $(oledir) $(rpm) $(xpdfdir) $(exiv2dir) if HAVE_VORBISFILE diff --git a/src/plugins/rpm/Makefile.am b/src/plugins/rpm/Makefile.am @@ -12,5 +12,6 @@ plugin_LTLIBRARIES = \ libextractor_rpm_la_SOURCES = \ rpmextractor.c libextractor_rpm_la_LDFLAGS = \ + -lrpm \ $(PLUGINFLAGS) $(retaincommand) \ $(WINFLAGS) diff --git a/src/plugins/rpm/rpmextractor.c b/src/plugins/rpm/rpmextractor.c @@ -1,6 +1,6 @@ /* This file is part of libextractor. - (C) 2002, 2003 Vidyut Samanta and Christian Grothoff + (C) 2002, 2003, 2008 Vidyut Samanta and Christian Grothoff libextractor is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -20,3136 +20,48 @@ #include "platform.h" #include "extractor.h" +#include <rpm/rpmlib.h> +#include <rpm/rpmts.h> +#include <pthread.h> +#include <sys/types.h> +#include <signal.h> -/* someone was using this non-portable function. Mac OS X - * doesn't have it so rpmextractor wouldn't load. I rewrite - * the function so that it will now work. below is the - * original FIXME notice. -- Filip Pizlo 2003 */ -/* FIXME: replace use of stpcpy to increase portability */ -static char * -my_stpcpy (char *dest, const char *src) -{ - strcpy (dest, src); - return dest + strlen (src); -} - -/* **************** buffer-based IO ************** */ - -typedef struct -{ - char *data; - size_t pos; - size_t len; -} fdStruct; - -typedef fdStruct *FD_t; - -static int -timedRead (FD_t f, void *dst, size_t n) -{ - size_t min; - - if (f->len - f->pos >= n) - min = n; - else - min = f->len - f->pos; - memcpy (dst, &f->data[f->pos], min); - f->pos += min; - return min; -} - -/* *************** RPM types ************************ */ - -typedef int int_32; -typedef unsigned int uint_32; - - -/** - * Header private tags. - * @note General use tags should start at 1000 (RPM's tag space starts there). - */ -#define HEADER_IMAGE 61 -#define HEADER_SIGNATURES 62 -#define HEADER_IMMUTABLE 63 -#define HEADER_REGIONS 64 -#define HEADER_I18NTABLE 100 -#define HEADER_SIGBASE 256 -#define HEADER_TAGBASE 1000 - -/** - * Tags identify data in package headers. - * @note tags should not have value 0! - */ -typedef enum rpmTag_e -{ - - RPMTAG_HEADERIMAGE = HEADER_IMAGE, /*!< Current image. */ - RPMTAG_HEADERSIGNATURES = HEADER_SIGNATURES, /*!< Signatures. */ - RPMTAG_HEADERIMMUTABLE = HEADER_IMMUTABLE, /*!< Original image. */ -/*@-enummemuse@*/ - RPMTAG_HEADERREGIONS = HEADER_REGIONS, /*!< Regions. */ - - RPMTAG_HEADERI18NTABLE = HEADER_I18NTABLE, /*!< I18N string locales. */ -/*@=enummemuse@*/ - -/* Retrofit (and uniqify) signature tags for use by tagName() and rpmQuery. */ -/* the md5 sum was broken *twice* on big endian machines */ -/* XXX 2nd underscore prevents tagTable generation */ - RPMTAG_SIG_BASE = HEADER_SIGBASE, - RPMTAG_SIGSIZE = RPMTAG_SIG_BASE + 1, - RPMTAG_SIGLEMD5_1 = RPMTAG_SIG_BASE + 2, /*!< internal - obsolate */ - RPMTAG_SIGPGP = RPMTAG_SIG_BASE + 3, - RPMTAG_SIGLEMD5_2 = RPMTAG_SIG_BASE + 4, /*!< internal - obsolate */ - RPMTAG_SIGMD5 = RPMTAG_SIG_BASE + 5, - RPMTAG_SIGGPG = RPMTAG_SIG_BASE + 6, - RPMTAG_SIGPGP5 = RPMTAG_SIG_BASE + 7, /*!< internal - obsolate */ - - RPMTAG_BADSHA1_1 = RPMTAG_SIG_BASE + 8, /*!< internal - obsolate */ - RPMTAG_BADSHA1_2 = RPMTAG_SIG_BASE + 9, /*!< internal - obsolate */ - - RPMTAG_PUBKEYS = RPMTAG_SIG_BASE + 10, - RPMTAG_DSAHEADER = RPMTAG_SIG_BASE + 11, - RPMTAG_RSAHEADER = RPMTAG_SIG_BASE + 12, - RPMTAG_SHA1HEADER = RPMTAG_SIG_BASE + 13, - - RPMTAG_NAME = 1000, - RPMTAG_VERSION = 1001, - RPMTAG_RELEASE = 1002, - RPMTAG_EPOCH = 1003, -#define RPMTAG_SERIAL RPMTAG_EPOCH /* backward comaptibility */ - RPMTAG_SUMMARY = 1004, - RPMTAG_DESCRIPTION = 1005, - RPMTAG_BUILDTIME = 1006, - RPMTAG_BUILDHOST = 1007, - RPMTAG_INSTALLTIME = 1008, - RPMTAG_SIZE = 1009, - RPMTAG_DISTRIBUTION = 1010, - RPMTAG_VENDOR = 1011, - RPMTAG_GIF = 1012, - RPMTAG_XPM = 1013, - RPMTAG_LICENSE = 1014, -#define RPMTAG_COPYRIGHT RPMTAG_LICENSE /* backward comaptibility */ - RPMTAG_PACKAGER = 1015, - RPMTAG_GROUP = 1016, -/*@-enummemuse@*/ - RPMTAG_CHANGELOG = 1017, /*!< internal */ -/*@=enummemuse@*/ - RPMTAG_SOURCE = 1018, - RPMTAG_PATCH = 1019, - RPMTAG_URL = 1020, - RPMTAG_OS = 1021, - RPMTAG_ARCH = 1022, - RPMTAG_PREIN = 1023, - RPMTAG_POSTIN = 1024, - RPMTAG_PREUN = 1025, - RPMTAG_POSTUN = 1026, - RPMTAG_OLDFILENAMES = 1027, /* obsolete */ - RPMTAG_FILESIZES = 1028, - RPMTAG_FILESTATES = 1029, - RPMTAG_FILEMODES = 1030, - RPMTAG_FILEUIDS = 1031, /*!< internal */ - RPMTAG_FILEGIDS = 1032, /*!< internal */ - RPMTAG_FILERDEVS = 1033, - RPMTAG_FILEMTIMES = 1034, - RPMTAG_FILEMD5S = 1035, - RPMTAG_FILELINKTOS = 1036, - RPMTAG_FILEFLAGS = 1037, -/*@-enummemuse@*/ - RPMTAG_ROOT = 1038, /*!< internal - obsolete */ -/*@=enummemuse@*/ - RPMTAG_FILEUSERNAME = 1039, - RPMTAG_FILEGROUPNAME = 1040, -/*@-enummemuse@*/ - RPMTAG_EXCLUDE = 1041, /*!< internal - obsolete */ - RPMTAG_EXCLUSIVE = 1042, /*!< internal - obsolete */ -/*@=enummemuse@*/ - RPMTAG_ICON = 1043, - RPMTAG_SOURCERPM = 1044, - RPMTAG_FILEVERIFYFLAGS = 1045, - RPMTAG_ARCHIVESIZE = 1046, - RPMTAG_PROVIDENAME = 1047, -#define RPMTAG_PROVIDES RPMTAG_PROVIDENAME /* backward comaptibility */ - RPMTAG_REQUIREFLAGS = 1048, - RPMTAG_REQUIRENAME = 1049, - RPMTAG_REQUIREVERSION = 1050, - RPMTAG_NOSOURCE = 1051, /*!< internal */ - RPMTAG_NOPATCH = 1052, /*!< internal */ - RPMTAG_CONFLICTFLAGS = 1053, - RPMTAG_CONFLICTNAME = 1054, - RPMTAG_CONFLICTVERSION = 1055, - RPMTAG_DEFAULTPREFIX = 1056, /*!< internal - deprecated */ - RPMTAG_BUILDROOT = 1057, /*!< internal */ - RPMTAG_INSTALLPREFIX = 1058, /*!< internal - deprecated */ - RPMTAG_EXCLUDEARCH = 1059, - RPMTAG_EXCLUDEOS = 1060, - RPMTAG_EXCLUSIVEARCH = 1061, - RPMTAG_EXCLUSIVEOS = 1062, - RPMTAG_AUTOREQPROV = 1063, /*!< internal */ - RPMTAG_RPMVERSION = 1064, - RPMTAG_TRIGGERSCRIPTS = 1065, - RPMTAG_TRIGGERNAME = 1066, - RPMTAG_TRIGGERVERSION = 1067, - RPMTAG_TRIGGERFLAGS = 1068, - RPMTAG_TRIGGERINDEX = 1069, - RPMTAG_VERIFYSCRIPT = 1079, - RPMTAG_CHANGELOGTIME = 1080, - RPMTAG_CHANGELOGNAME = 1081, - RPMTAG_CHANGELOGTEXT = 1082, -/*@-enummemuse@*/ - RPMTAG_BROKENMD5 = 1083, /*!< internal */ -/*@=enummemuse@*/ - RPMTAG_PREREQ = 1084, /*!< internal */ - RPMTAG_PREINPROG = 1085, - RPMTAG_POSTINPROG = 1086, - RPMTAG_PREUNPROG = 1087, - RPMTAG_POSTUNPROG = 1088, - RPMTAG_BUILDARCHS = 1089, - RPMTAG_OBSOLETENAME = 1090, -#define RPMTAG_OBSOLETES RPMTAG_OBSOLETENAME /* backward comaptibility */ - RPMTAG_VERIFYSCRIPTPROG = 1091, - RPMTAG_TRIGGERSCRIPTPROG = 1092, - RPMTAG_DOCDIR = 1093, /*!< internal */ - RPMTAG_COOKIE = 1094, - RPMTAG_FILEDEVICES = 1095, - RPMTAG_FILEINODES = 1096, - RPMTAG_FILELANGS = 1097, - RPMTAG_PREFIXES = 1098, - RPMTAG_INSTPREFIXES = 1099, - RPMTAG_TRIGGERIN = 1100, /*!< internal */ - RPMTAG_TRIGGERUN = 1101, /*!< internal */ - RPMTAG_TRIGGERPOSTUN = 1102, /*!< internal */ - RPMTAG_AUTOREQ = 1103, /*!< internal */ - RPMTAG_AUTOPROV = 1104, /*!< internal */ -/*@-enummemuse@*/ - RPMTAG_CAPABILITY = 1105, /*!< internal - obsolete */ -/*@=enummemuse@*/ - RPMTAG_SOURCEPACKAGE = 1106, /*!< internal */ -/*@-enummemuse@*/ - RPMTAG_OLDORIGFILENAMES = 1107, /*!< internal - obsolete */ -/*@=enummemuse@*/ - RPMTAG_BUILDPREREQ = 1108, /*!< internal */ - RPMTAG_BUILDREQUIRES = 1109, /*!< internal */ - RPMTAG_BUILDCONFLICTS = 1110, /*!< internal */ -/*@-enummemuse@*/ - RPMTAG_BUILDMACROS = 1111, /*!< internal */ -/*@=enummemuse@*/ - RPMTAG_PROVIDEFLAGS = 1112, - RPMTAG_PROVIDEVERSION = 1113, - RPMTAG_OBSOLETEFLAGS = 1114, - RPMTAG_OBSOLETEVERSION = 1115, - RPMTAG_DIRINDEXES = 1116, - RPMTAG_BASENAMES = 1117, - RPMTAG_DIRNAMES = 1118, - RPMTAG_ORIGDIRINDEXES = 1119, /*!< internal */ - RPMTAG_ORIGBASENAMES = 1120, /*!< internal */ - RPMTAG_ORIGDIRNAMES = 1121, /*!< internal */ - RPMTAG_OPTFLAGS = 1122, - RPMTAG_DISTURL = 1123, - RPMTAG_PAYLOADFORMAT = 1124, - RPMTAG_PAYLOADCOMPRESSOR = 1125, - RPMTAG_PAYLOADFLAGS = 1126, - RPMTAG_MULTILIBS = 1127, - RPMTAG_INSTALLTID = 1128, - RPMTAG_REMOVETID = 1129, - RPMTAG_SHA1RHN = 1130, /*!< internal */ - RPMTAG_RHNPLATFORM = 1131, - RPMTAG_PLATFORM = 1132, -/*@-enummemuse@*/ - RPMTAG_FIRSTFREE_TAG /*!< internal */ -/*@=enummemuse@*/ -} rpmTag; - -#define RPMTAG_EXTERNAL_TAG 1000000 - -/** \ingroup signature - * Tags found in signature header from package. - */ -enum rpmtagSignature -{ - RPMSIGTAG_SIZE = 1000, /*!< Header+Payload size in bytes. */ -/* the md5 sum was broken *twice* on big endian machines */ - RPMSIGTAG_LEMD5_1 = 1001, /*!< Broken MD5, take 1 */ - RPMSIGTAG_PGP = 1002, /*!< PGP 2.6.3 signature. */ - RPMSIGTAG_LEMD5_2 = 1003, /*!< Broken MD5, take 2 */ - RPMSIGTAG_MD5 = 1004, /*!< MD5 signature. */ - RPMSIGTAG_GPG = 1005, /*!< GnuPG signature. */ - RPMSIGTAG_PGP5 = 1006, /*!< PGP5 signature @deprecated legacy. */ - RPMSIGTAG_PAYLOADSIZE = 1007, - /*!< uncompressed payload size in bytes. */ - RPMSIGTAG_BADSHA1_1 = RPMTAG_BADSHA1_1, /*!< Broken SHA1, take 1. */ - RPMSIGTAG_BADSHA1_2 = RPMTAG_BADSHA1_2, /*!< Broken SHA1, take 2. */ - RPMSIGTAG_SHA1 = RPMTAG_SHA1HEADER, /*!< sha1 header digest. */ - RPMSIGTAG_DSA = RPMTAG_DSAHEADER, /*!< DSA header signature. */ - RPMSIGTAG_RSA = RPMTAG_RSAHEADER /*!< RSA header signature. */ -}; - -/** - * Dependency Attributes. - */ -typedef enum rpmsenseFlags_e -{ - RPMSENSE_ANY = 0, -/*@-enummemuse@*/ - RPMSENSE_SERIAL = (1 << 0), /*!< @todo Legacy. */ -/*@=enummemuse@*/ - RPMSENSE_LESS = (1 << 1), - RPMSENSE_GREATER = (1 << 2), - RPMSENSE_EQUAL = (1 << 3), - RPMSENSE_PROVIDES = (1 << 4), /* only used internally by builds */ - RPMSENSE_CONFLICTS = (1 << 5), /* only used internally by builds */ - RPMSENSE_PREREQ = (1 << 6), /*!< @todo Legacy. */ - RPMSENSE_OBSOLETES = (1 << 7), /* only used internally by builds */ - RPMSENSE_INTERP = (1 << 8), /*!< Interpreter used by scriptlet. */ - RPMSENSE_SCRIPT_PRE = ((1 << 9) | RPMSENSE_PREREQ), /*!< %pre dependency. */ - RPMSENSE_SCRIPT_POST = ((1 << 10) | RPMSENSE_PREREQ), /*!< %post dependency. */ - RPMSENSE_SCRIPT_PREUN = ((1 << 11) | RPMSENSE_PREREQ), /*!< %preun dependency. */ - RPMSENSE_SCRIPT_POSTUN = ((1 << 12) | RPMSENSE_PREREQ), /*!< %postun dependency. */ - RPMSENSE_SCRIPT_VERIFY = (1 << 13), /*!< %verify dependency. */ - RPMSENSE_FIND_REQUIRES = (1 << 14), /*!< find-requires generated dependency. */ - RPMSENSE_FIND_PROVIDES = (1 << 15), /*!< find-provides generated dependency. */ - - RPMSENSE_TRIGGERIN = (1 << 16), /*!< %triggerin dependency. */ - RPMSENSE_TRIGGERUN = (1 << 17), /*!< %triggerun dependency. */ - RPMSENSE_TRIGGERPOSTUN = (1 << 18), /*!< %triggerpostun dependency. */ - RPMSENSE_MULTILIB = (1 << 19), - RPMSENSE_SCRIPT_PREP = (1 << 20), /*!< %prep build dependency. */ - RPMSENSE_SCRIPT_BUILD = (1 << 21), /*!< %build build dependency. */ - RPMSENSE_SCRIPT_INSTALL = (1 << 22), /*!< %install build dependency. */ - RPMSENSE_SCRIPT_CLEAN = (1 << 23), /*!< %clean build dependency. */ - RPMSENSE_RPMLIB = ((1 << 24) | RPMSENSE_PREREQ), /*!< rpmlib(feature) dependency. */ -/*@-enummemuse@*/ - RPMSENSE_TRIGGERPREIN = (1 << 25), /*!< @todo Implement %triggerprein. */ -/*@=enummemuse@*/ - -/*@-enummemuse@*/ - RPMSENSE_KEYRING = (1 << 26) -/*@=enummemuse@*/ -} rpmsenseFlags; - -/** \ingroup header - * Include calculation for 8 bytes of (magic, 0)? - */ -enum hMagic -{ - HEADER_MAGIC_NO = 0, - HEADER_MAGIC_YES = 1 -}; - -/** - * Package read return codes. - */ -typedef enum rpmRC_e -{ - RPMRC_OK = 0, - RPMRC_BADMAGIC = 1, - RPMRC_FAIL = 2, - RPMRC_BADSIZE = 3, - RPMRC_SHORTREAD = 4 -} rpmRC; - -/** \ingroup header - * The basic types of data in tags from headers. - */ -typedef enum rpmTagType_e -{ -#define RPM_MIN_TYPE 0 - RPM_NULL_TYPE = 0, - RPM_CHAR_TYPE = 1, - RPM_INT8_TYPE = 2, - RPM_INT16_TYPE = 3, - RPM_INT32_TYPE = 4, -/* RPM_INT64_TYPE = 5, ---- These aren't supported (yet) */ - RPM_STRING_TYPE = 6, - RPM_BIN_TYPE = 7, - RPM_STRING_ARRAY_TYPE = 8, - RPM_I18NSTRING_TYPE = 9 -#define RPM_MAX_TYPE 9 -} rpmTagType; - -/* - * Teach header.c about legacy tags. - */ -#define HEADER_OLDFILENAMES 1027 -#define HEADER_BASENAMES 1117 - -#define REGION_TAG_TYPE RPM_BIN_TYPE -#define REGION_TAG_COUNT sizeof(struct entryInfo) - -#define RPMLEAD_BINARY 0 -#define RPMLEAD_SOURCE 1 - -#define RPMLEAD_MAGIC0 0xed -#define RPMLEAD_MAGIC1 0xab -#define RPMLEAD_MAGIC2 0xee -#define RPMLEAD_MAGIC3 0xdb - -#define RPMLEAD_SIZE 96 /*!< Don't rely on sizeof(struct) */ - -/** \ingroup header - * Maximum no. of bytes permitted in a header. - */ -/*@unchecked@*/ -static size_t headerMaxbytes = (32 * 1024 * 1024); - -/** \ingroup lead - * The lead data structure. - * The lead needs to be 8 byte aligned. - * @deprecated The lead (except for signature_type) is legacy. - * @todo Don't use any information from lead. - */ -struct rpmlead -{ - unsigned char magic[4]; - unsigned char major, minor; - short type; - short archnum; - char name[66]; - short osnum; - short signature_type; /*!< Signature header type (RPMSIG_HEADERSIG) */ - /*@unused@*/ char reserved[16]; - /*!< Pad to 96 bytes -- 8 byte aligned */ -}; - -/** \ingroup header - * Alignment needs (and sizeof scalars types) for internal rpm data types. - */ - /*@observer@*//*@unchecked@ */ -static int typeSizes[] = { - 0, /*!< RPM_NULL_TYPE */ - 1, /*!< RPM_CHAR_TYPE */ - 1, /*!< RPM_INT8_TYPE */ - 2, /*!< RPM_INT16_TYPE */ - 4, /*!< RPM_INT32_TYPE */ - -1, /*!< RPM_INT64_TYPE */ - -1, /*!< RPM_STRING_TYPE */ - 1, /*!< RPM_BIN_TYPE */ - -1, /*!< RPM_STRING_ARRAY_TYPE */ - -1 /*!< RPM_I18NSTRING_TYPE */ -}; - -/** \ingroup header - */ -enum headerSprintfExtenstionType -{ - HEADER_EXT_LAST = 0, /*!< End of extension chain. */ - HEADER_EXT_FORMAT, /*!< headerTagFormatFunction() extension */ - HEADER_EXT_MORE, /*!< Chain to next table. */ - HEADER_EXT_TAG /*!< headerTagTagFunction() extension */ -}; - -/** \ingroup signature - * Signature types stored in rpm lead. - */ -typedef enum sigType_e -{ - RPMSIGTYPE_NONE = 0, /*!< unused, legacy. */ - RPMSIGTYPE_PGP262_1024 = 1, /*!< unused, legacy. */ -/*@-enummemuse@*/ - RPMSIGTYPE_BAD = 2, /*!< Unknown signature type. */ -/*@=enummemuse@*/ - RPMSIGTYPE_MD5 = 3, /*!< unused, legacy. */ - RPMSIGTYPE_MD5_PGP = 4, /*!< unused, legacy. */ - RPMSIGTYPE_HEADERSIG = 5, /*!< Header style signature */ - RPMSIGTYPE_DISABLE = 6 /*!< Disable verification (debugging only) */ -} sigType; - -/** \ingroup header - * HEADER_EXT_TAG format function prototype. - * This will only ever be passed RPM_INT32_TYPE or RPM_STRING_TYPE to - * help keep things simple. - * - * @param type tag type - * @param data tag value - * @param formatPrefix - * @param padding - * @param element - * @return formatted string - */ -typedef /*only@ */ char *(*headerTagFormatFunction) (int_32 type, - const void *data, - char *formatPrefix, - int padding, - int element); - - -/** \ingroup header - * Associate tag names with numeric values. - */ -typedef /*@abstract@ */ struct headerTagTableEntry_s *headerTagTableEntry; -struct headerTagTableEntry_s -{ - /*@observer@*//*@null@ */ const char *name; - /*!< Tag name. */ - int val; /*!< Tag numeric value. */ -}; - -/** \ingroup header - */ -typedef /*@abstract@ */ struct headerIteratorS *HeaderIterator; - -/** \ingroup header - */ -typedef /*@abstract@ *//*@refcounted@ */ struct headerToken *Header; - - -typedef int_32 *hTYP_t; -typedef const void *hPTR_t; -typedef int_32 *hCNT_t; - -/** \ingroup header - * HEADER_EXT_FORMAT format function prototype. - * This is allowed to fail, which indicates the tag doesn't exist. - * - * @param h header - * @retval type address of tag type - * @retval data address of tag value pointer - * @retval count address of no. of data items - * @retval freedata address of data-was-malloc'ed indicator - * @return 0 on success - */ -typedef int (*headerTagTagFunction) (Header h, - /*@null@ *//*@out@ */ hTYP_t type, - /*@null@ *//*@out@ */ hPTR_t * data, - /*@null@ *//*@out@ */ hCNT_t count, - /*@null@ *//*@out@ */ int *freeData); - -/** \ingroup header - * Define header tag output formats. - */ -typedef /*@abstract@ */ struct headerSprintfExtension_s - *headerSprintfExtension; -struct headerSprintfExtension_s -{ - enum headerSprintfExtenstionType type; /*!< Type of extension. */ - /*@observer@*//*@null@ */ - const char *name; /*!< Name of extension. */ - union - { - /*@observer@*//*@null@ */ - void *generic; /*!< Private extension. */ - headerTagFormatFunction formatFunction; /*!< HEADER_EXT_TAG extension. */ - headerTagTagFunction tagFunction; /*!< HEADER_EXT_FORMAT extension. */ - struct headerSprintfExtension_s *more; /*!< Chained table extension. */ - } u; -}; - -/** \ingroup header - * Create new (empty) header instance. - * @return header - */ -typedef Header (*HDRnew) (void) - /*@ */ ; - -/** \ingroup header - * Dereference a header instance. - * @param h header - * @return NULL always - */ -typedef -/*@null@*/ Header (*HDRfree) ( /*@null@ *//*@killref@ */ Header h) - /*@modifies h @ */ ; - -/** \ingroup header - * Reference a header instance. - * @param h header - * @return referenced header instance - */ -typedef Header (*HDRlink) (Header h) - /*@modifies h @ */ ; - -/** \ingroup header - * Dereference a header instance. - * @param h header - * @return NULL always - */ -typedef Header (*HDRunlink) ( /*@killref@ *//*@null@ */ Header h) - /*@modifies h @ */ ; - -/** \ingroup header - * Sort tags in header. - * @todo Eliminate from API. - * @param h header - */ -typedef void (*HDRsort) (Header h) - /*@modifies h @ */ ; - -/** \ingroup header - * Restore tags in header to original ordering. - * @todo Eliminate from API. - * @param h header - */ -typedef void (*HDRunsort) (Header h) - /*@modifies h @ */ ; - -/** \ingroup header - * Return size of on-disk header representation in bytes. - * @param h header - * @param magicp include size of 8 bytes for (magic, 0)? - * @return size of on-disk header - */ -typedef unsigned int (*HDRsizeof) ( /*@null@ */ Header h, enum hMagic magicp) - /*@modifies h @ */ ; - -/** \ingroup header - * Convert header to on-disk representation. - * @param h header (with pointers) - * @return on-disk header blob (i.e. with offsets) - */ -typedef - /*@only@*//*@null@ */ void *(*HDRunload) (Header h) - /*@modifies h @ */ ; - -/** \ingroup header - * Convert header to on-disk representation, and then reload. - * This is used to insure that all header data is in one chunk. - * @param h header (with pointers) - * @param tag region tag - * @return on-disk header (with offsets) - */ -typedef -/*@null@*/ Header (*HDRreload) ( /*@only@ */ Header h, int tag) - /*@modifies h @ */ ; - -/** \ingroup header - * Duplicate a header. - * @param h header - * @return new header instance - */ -typedef Header (*HDRcopy) (Header h) - /*@modifies h @ */ ; - -/** \ingroup header - * Convert header to in-memory representation. - * @param uh on-disk header blob (i.e. with offsets) - * @return header - */ -typedef -/*@null@*/ Header (*HDRload) ( /*@kept@ */ void *uh) - /*@modifies uh @ */ ; - -/** \ingroup header - * Make a copy and convert header to in-memory representation. - * @param uh on-disk header blob (i.e. with offsets) - * @return header - */ -typedef -/*@null@*/ Header (*HDRcopyload) (const void *uh) - /*@ */ ; - -/** \ingroup header - * Read (and load) header from file handle. - * @param fd file handle - * @param magicp read (and verify) 8 bytes of (magic, 0)? - * @return header (or NULL on error) - */ -typedef -/*@null@*/ Header (*HDRhdrread) (FD_t fd, enum hMagic magicp) - /*@modifies fd @ */ ; - -/** \ingroup header - * Write (with unload) header to file handle. - * @param fd file handle - * @param h header - * @param magicp prefix write with 8 bytes of (magic, 0)? - * @return 0 on success, 1 on error - */ -typedef int (*HDRhdrwrite) (FD_t fd, /*@null@ */ Header h, enum hMagic magicp) - /*@globals fileSystem @ */ - /*@modifies fd, h, fileSystem @ */ ; - -/** \ingroup header - * Check if tag is in header. - * @param h header - * @param tag tag - * @return 1 on success, 0 on failure - */ -typedef int (*HDRisentry) ( /*@null@ */ Header h, int_32 tag) - /*@ */ ; - -/** \ingroup header - * Free data allocated when retrieved from header. - * @param h header - * @param data address of data (or NULL) - * @param type type of data (or -1 to force free) - * @return NULL always - */ -typedef -/*@null@*/ void *(*HDRfreetag) (Header h, - /*@only@ *//*@null@ */ const void *data, - rpmTagType type) - /*@modifies data @ */ ; - -/** \ingroup header - * Retrieve tag value. - * Will never return RPM_I18NSTRING_TYPE! RPM_STRING_TYPE elements with - * RPM_I18NSTRING_TYPE equivalent entries are translated (if HEADER_I18NTABLE - * entry is present). - * - * @param h header - * @param tag tag - * @retval type address of tag value data type (or NULL) - * @retval p address of pointer to tag value(s) (or NULL) - * @retval c address of number of values (or NULL) - * @return 1 on success, 0 on failure - */ -typedef int (*HDRget) (Header h, int_32 tag, - /*@null@ *//*@out@ */ hTYP_t type, - /*@null@ *//*@out@ */ void **p, - /*@null@ *//*@out@ */ hCNT_t c) - /*@modifies *type, *p, *c @ */ ; - -/** \ingroup header - * Retrieve tag value using header internal array. - * Get an entry using as little extra RAM as possible to return the tag value. - * This is only an issue for RPM_STRING_ARRAY_TYPE. - * - * @param h header - * @param tag tag - * @retval type address of tag value data type (or NULL) - * @retval p address of pointer to tag value(s) (or NULL) - * @retval c address of number of values (or NULL) - * @return 1 on success, 0 on failure - */ -typedef int (*HDRgetmin) (Header h, int_32 tag, - /*@null@ *//*@out@ */ hTYP_t type, - /*@null@ *//*@out@ */ hPTR_t * p, - /*@null@ *//*@out@ */ hCNT_t c) - /*@modifies *type, *p, *c @ */ ; - -/** \ingroup header - * Add tag to header. - * Duplicate tags are okay, but only defined for iteration (with the - * exceptions noted below). While you are allowed to add i18n string - * arrays through this function, you probably don't mean to. See - * headerAddI18NString() instead. - * - * @param h header - * @param tag tag - * @param type tag value data type - * @param p pointer to tag value(s) - * @param c number of values - * @return 1 on success, 0 on failure - */ -typedef - int (*HDRadd) (Header h, int_32 tag, int_32 type, const void *p, int_32 c) - /*@modifies h @ */ ; - -/** \ingroup header - * Append element to tag array in header. - * Appends item p to entry w/ tag and type as passed. Won't work on - * RPM_STRING_TYPE. Any pointers into header memory returned from - * headerGetEntryMinMemory() for this entry are invalid after this - * call has been made! - * - * @param h header - * @param tag tag - * @param type tag value data type - * @param p pointer to tag value(s) - * @param c number of values - * @return 1 on success, 0 on failure - */ -typedef - int (*HDRappend) (Header h, int_32 tag, int_32 type, const void *p, - int_32 c) - /*@modifies h @ */ ; - -/** \ingroup header - * Add or append element to tag array in header. - * @todo Arg "p" should have const. - * @param h header - * @param tag tag - * @param type tag value data type - * @param p pointer to tag value(s) - * @param c number of values - * @return 1 on success, 0 on failure - */ -typedef - int (*HDRaddorappend) (Header h, int_32 tag, int_32 type, const void *p, - int_32 c) - /*@modifies h @ */ ; - -/** \ingroup header - * Add locale specific tag to header. - * A NULL lang is interpreted as the C locale. Here are the rules: - * \verbatim - * - If the tag isn't in the header, it's added with the passed string - * as new value. - * - If the tag occurs multiple times in entry, which tag is affected - * by the operation is undefined. - * - If the tag is in the header w/ this language, the entry is - * *replaced* (like headerModifyEntry()). - * \endverbatim - * This function is intended to just "do the right thing". If you need - * more fine grained control use headerAddEntry() and headerModifyEntry(). - * - * @param h header - * @param tag tag - * @param string tag value - * @param lang locale - * @return 1 on success, 0 on failure - */ -typedef - int (*HDRaddi18n) (Header h, int_32 tag, const char *string, - const char *lang) - /*@modifies h @ */ ; - -/** \ingroup header - * Modify tag in header. - * If there are multiple entries with this tag, the first one gets replaced. - * @param h header - * @param tag tag - * @param type tag value data type - * @param p pointer to tag value(s) - * @param c number of values - * @return 1 on success, 0 on failure - */ -typedef - int (*HDRmodify) (Header h, int_32 tag, int_32 type, const void *p, - int_32 c) - /*@modifies h @ */ ; - -/** \ingroup header - * Delete tag in header. - * Removes all entries of type tag from the header, returns 1 if none were - * found. - * - * @param h header - * @param tag tag - * @return 0 on success, 1 on failure (INCONSISTENT) - */ -typedef int (*HDRremove) (Header h, int_32 tag) - /*@modifies h @ */ ; - - /*@-redef@*//* LCL: no clue */ -/** \ingroup header - */ -typedef const char *errmsg_t; -typedef int_32 *hTAG_t; - -/** \ingroup header - * Return formatted output string from header tags. - * The returned string must be free()d. - * - * @param h header - * @param fmt format to use - * @param tags array of tag name/value pairs - * @param extensions chained table of formatting extensions. - * @retval errmsg error message (if any) - * @return formatted output string (malloc'ed) - */ -typedef -/*@only@*/ char *(*HDRhdrsprintf) (Header h, const char *fmt, - const struct headerTagTableEntry_s * tags, - const struct headerSprintfExtension_s * - extensions, - /*@null@ *//*@out@ */ errmsg_t * errmsg) - /*@modifies *errmsg @ */ ; - -/** \ingroup header - * Duplicate tag values from one header into another. - * @param headerFrom source header - * @param headerTo destination header - * @param tagstocopy array of tags that are copied - */ -typedef - void (*HDRcopytags) (Header headerFrom, Header headerTo, hTAG_t tagstocopy) - /*@modifies headerFrom, headerTo @ */ ; - -/** \ingroup header - * Destroy header tag iterator. - * @param hi header tag iterator - * @return NULL always - */ -typedef HeaderIterator (*HDRfreeiter) ( /*@only@ */ HeaderIterator hi) - /*@modifies hi @ */ ; - -/** \ingroup header - * Create header tag iterator. - * @param h header - * @return header tag iterator - */ -typedef HeaderIterator (*HDRinititer) (Header h) - /*@modifies h */ ; - -/** \ingroup header - * Return next tag from header. - * @param hi header tag iterator - * @retval tag address of tag - * @retval type address of tag value data type - * @retval p address of pointer to tag value(s) - * @retval c address of number of values - * @return 1 on success, 0 on failure - */ -typedef int (*HDRnextiter) (HeaderIterator hi, - /*@null@ *//*@out@ */ hTAG_t tag, - /*@null@ *//*@out@ */ hTYP_t type, - /*@null@ *//*@out@ */ hPTR_t * p, - /*@null@ *//*@out@ */ hCNT_t c) - /*@modifies hi, *tag, *type, *p, *c @ */ ; - -/** \ingroup header - * Header method vectors. - */ -typedef /*@abstract@ */ struct HV_s *HV_t; -struct HV_s -{ - HDRnew hdrnew; - HDRfree hdrfree; - HDRlink hdrlink; - HDRsort hdrsort; - HDRunsort hdrunsort; - HDRsizeof hdrsizeof; - HDRunload hdrunload; - HDRreload hdrreload; - HDRcopy hdrcopy; - HDRload hdrload; - HDRcopyload hdrcopyload; - HDRhdrread hdrread; - HDRhdrwrite hdrwrite; - HDRisentry hdrisentry; - HDRfreetag hdrfreetag; - HDRget hdrget; - HDRgetmin hdrgetmin; - HDRadd hdradd; - HDRappend hdrappend; - HDRaddorappend hdraddorappend; - HDRaddi18n hdraddi18n; - HDRmodify hdrmodify; - HDRremove hdrremove; - HDRhdrsprintf hdrsprintf; - HDRcopytags hdrcopytags; - HDRfreeiter hdrfreeiter; - HDRinititer hdrinititer; - HDRnextiter hdrnextiter; - HDRunlink hdrunlink; -/*@null@*/ - void *hdrvecs; -/*@null@*/ - void *hdrdata; - int hdrversion; -}; - -/** \ingroup header - * Description of tag data. - */ -typedef /*@abstract@ */ struct entryInfo *entryInfo; -struct entryInfo -{ - int_32 tag; /*!< Tag identifier. */ - int_32 type; /*!< Tag data type. */ - int_32 offset; /*!< Offset into data segment (ondisk only). */ - int_32 count; /*!< Number of tag elements. */ -}; - -/** \ingroup header - * A single tag from a Header. - */ -typedef /*@abstract@ */ struct indexEntry *indexEntry; -struct indexEntry -{ - struct entryInfo info; /*!< Description of tag data. */ - /*@owned@*/ void *data; - /*!< Location of tag data. */ - int length; /*!< No. bytes of data. */ - int rdlen; /*!< No. bytes of data in region. */ -}; - -/** \ingroup header - * The Header data structure. - */ -struct headerToken -{ - /*@unused@*/ struct HV_s hv; - /*!< Header public methods. */ - void *blob; /*!< Header region blob. */ - /*@owned@*/ indexEntry index; - /*!< Array of tags. */ - int indexUsed; /*!< Current size of tag array. */ - int indexAlloced; /*!< Allocated size of tag array. */ - int flags; -#define HEADERFLAG_SORTED (1 << 0) /*!< Are header entries sorted? */ -#define HEADERFLAG_ALLOCATED (1 << 1) /*!< Is 1st header region allocated? */ -#define HEADERFLAG_LEGACY (1 << 2) /*!< Header came from legacy source? */ - /*@refs@*/ int nrefs; - /*!< Reference count. */ -}; - -/** - * Header tag iterator data structure. - */ -struct headerIteratorS -{ - /*@unused@*/ Header h; - /*!< Header being iterated. */ - /*@unused@*/ int next_index; - /*!< Next tag index. */ -}; - -/*@}*/ -/* ==================================================================== */ -/** \name RPMTS */ -/*@{*/ -/** - * Prototype for headerFreeData() vector. - * @param data address of data (or NULL) - * @param type type of data (or -1 to force free) - * @return NULL always - */ -typedef /*@null@ */ -void *(*HFD_t) ( /*@only@ *//*@null@ */ const void *data, rpmTagType type) - /*@modifies data @ */ ; - -/** - * Prototype for headerAddEntry() vector. - * Duplicate tags are okay, but only defined for iteration (with the - * exceptions noted below). While you are allowed to add i18n string - * arrays through this function, you probably don't mean to. See - * headerAddI18NString() instead. - * - * @param h header - * @param tag tag - * @param type tag value data type - * @param p pointer to tag value(s) - * @param c number of values - * @return 1 on success, 0 on failure - */ -typedef int (*HAE_t) (Header h, rpmTag tag, rpmTagType type, - const void *p, int_32 c) - /*@modifies h @ */ ; - -/** - * Prototype for headerGetEntry() vector. - * Will never return RPM_I18NSTRING_TYPE! RPM_STRING_TYPE elements with - * RPM_I18NSTRING_TYPE equivalent entries are translated (if HEADER_I18NTABLE - * entry is present). - * - * @param h header - * @param tag tag - * @retval type address of tag value data type (or NULL) - * @retval p address of pointer to tag value(s) (or NULL) - * @retval c address of number of values (or NULL) - * @return 1 on success, 0 on failure - */ -typedef int (*HGE_t) (Header h, rpmTag tag, - /*@null@ *//*@out@ */ rpmTagType * type, - /*@null@ *//*@out@ */ void **p, - /*@null@ *//*@out@ */ int_32 * c) - /*@modifies *type, *p, *c @ */ ; - -/** - * Prototype for headerRemoveEntry() vector. - * Delete tag in header. - * Removes all entries of type tag from the header, returns 1 if none were - * found. - * - * @param h header - * @param tag tag - * @return 0 on success, 1 on failure (INCONSISTENT) - */ -typedef int (*HRE_t) (Header h, int_32 tag) - /*@modifies h @ */ ; - -#define ENTRY_IS_REGION(_e) \ - (((_e)->info.tag >= HEADER_IMAGE) && ((_e)->info.tag < HEADER_REGIONS)) - - -#define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s)) - -/** - * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL. - * @param p memory to free - * @return NULL always - */ -/*@unused@*/ static /*@null@ */ void * -_free ( /*@only@ *//*@null@ *//*@out@ */ const void *p) /*@modifies *p @ */ -{ - if (p != NULL) - free ((void *) p); - return NULL; -} - -/** - */ -static int -indexCmp (const void *avp, const void *bvp) /*@ */ -{ - /*@-castexpose@ */ - indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp; - /*@=castexpose@ */ - return (ap->info.tag - bp->info.tag); -} - -/** \ingroup header - * Sort tags in header. - * @param h header - */ -static void -headerSort (Header h) - /*@modifies h @ */ -{ - if (!(h->flags & HEADERFLAG_SORTED)) - { - qsort (h->index, h->indexUsed, sizeof (*h->index), indexCmp); - h->flags |= HEADERFLAG_SORTED; - } -} - -/** - * Remove occurences of trailing character from string. - * @param s string - * @param c character to strip - * @return string - */ -/*@unused@*/ static inline -/*@only@*/ char * -stripTrailingChar ( /*@only@ */ char *s, char c) - /*@modifies *s */ -{ - char *t; - for (t = s + strlen (s) - 1; *t == c && t >= s; t--) - *t = '\0'; - return s; -} - -/** \ingroup header - * Free data allocated when retrieved from header. - * @deprecated Use headerFreeTag() instead. - * @todo Remove from API. - * - * @param data address of data (or NULL) - * @param type type of data (or -1 to force free) - * @return NULL always - */ - /*@unused@*/ static - /*@null@ */ -void * -headerFreeData ( /*@only@ *//*@null@ */ const void *data, rpmTagType type) - /*@modifies data @ */ -{ - if (data) - { - /*@-branchstate@ */ - if (type == -1 || - type == RPM_STRING_ARRAY_TYPE || - type == RPM_I18NSTRING_TYPE || type == RPM_BIN_TYPE) - free ((void *) data); - /*@=branchstate@ */ - } - return NULL; -} - - -/** - * Return length of entry data. - * @todo Remove sanity check exit's. - * @param type entry data type - * @param p entry data - * @param count entry item count - * @param onDisk data is concatenated strings (with NUL's))? - * @return no. bytes in data - */ -/*@mayexit@*/ -static int -dataLength (int_32 type, hPTR_t p, int_32 count, int onDisk) - /*@ */ -{ - int length = 0; - - switch (type) - { - case RPM_STRING_TYPE: - if (count == 1) - { /* Special case -- p is just the string */ - length = strlen (p) + 1; - break; - } - /* This should not be allowed */ - /*@-modfilesys@ */ - /*@=modfilesys@ */ - exit (EXIT_FAILURE); - /*@notreached@ */ break; - - case RPM_STRING_ARRAY_TYPE: - case RPM_I18NSTRING_TYPE: - { - int i; - - /* This is like RPM_STRING_TYPE, except it's *always* an array */ - /* Compute sum of length of all strings, including null terminators */ - i = count; - - if (onDisk) - { - const char *chptr = p; - int thisLen; - - while (i--) - { - thisLen = strlen (chptr) + 1; - length += thisLen; - chptr += thisLen; - } - } - else - { - const char **src = (const char **) p; - while (i--) - { - /* add one for null termination */ - length += strlen (*src++) + 1; - } - } - } - break; - - default: - if (typeSizes[type] != -1) - { - length = typeSizes[type] * count; - break; - } - /*@-modfilesys@ */ - /*@=modfilesys@ */ - exit (EXIT_FAILURE); - /*@notreached@ */ break; - } - - return length; -} - -/** - */ -static void -copyData (int_32 type, /*@out@ */ void *dstPtr, const void *srcPtr, - int_32 c, int dataLengtha) - /*@modifies *dstPtr @ */ -{ - const char **src; - char *dst; - int i; - - switch (type) - { - case RPM_STRING_ARRAY_TYPE: - case RPM_I18NSTRING_TYPE: - /* Otherwise, p is char** */ - i = c; - src = (const char **) srcPtr; - dst = dstPtr; - while (i--) - { - if (*src) - { - int len = strlen (*src) + 1; - memcpy (dst, *src, len); - dst += len; - } - src++; - } - break; - - default: - memmove (dstPtr, srcPtr, dataLengtha); - break; - } -} - -/** - * Return (malloc'ed) copy of entry data. - * @param type entry data type - * @param p entry data - * @param c entry item count - * @retval lengthPtr no. bytes in returned data - * @return (malloc'ed) copy of entry data - */ -static void * -grabData (int_32 type, hPTR_t p, int_32 c, - /*@out@ */ int *lengthPtr) - /*@modifies *lengthPtr @ */ -{ - int length = dataLength (type, p, c, 0); - void *data = malloc (length); - - copyData (type, data, p, c, length); - - if (lengthPtr) - *lengthPtr = length; - return data; -} - - -#define INDEX_MALLOC_SIZE 8 - -/** \ingroup header - * Add tag to header. - * Duplicate tags are okay, but only defined for iteration (with the - * exceptions noted below). While you are allowed to add i18n string - * arrays through this function, you probably don't mean to. See - * headerAddI18NString() instead. - * - * @param h header - * @param tag tag - * @param type tag value data type - * @param p pointer to tag value(s) - * @param c number of values - * @return 1 on success, 0 on failure - */ -static int -headerAddEntry (Header h, int_32 tag, int_32 type, const void *p, int_32 c) - /*@modifies h @ */ -{ - indexEntry entry; - - /* Count must always be >= 1 for headerAddEntry. */ - if (c <= 0) - return 0; - - /* Allocate more index space if necessary */ - if (h->indexUsed == h->indexAlloced) - { - h->indexAlloced += INDEX_MALLOC_SIZE; - h->index = realloc (h->index, h->indexAlloced * sizeof (*h->index)); - } - - /* Fill in the index */ - entry = h->index + h->indexUsed; - entry->info.tag = tag; - entry->info.type = type; - entry->info.count = c; - entry->info.offset = 0; - entry->data = grabData (type, p, c, &entry->length); - - if (h->indexUsed > 0 && tag < h->index[h->indexUsed - 1].info.tag) - h->flags &= ~HEADERFLAG_SORTED; - h->indexUsed++; - - return 1; -} - -/** \ingroup header - * Dereference a header instance. - * @param h header - * @return NULL always - */ -static /*@null@ */ -Header headerFree ( /*@killref@ *//*@null@ */ Header h); - /*@modifies h @ */ - - -/** \ingroup header - * Destroy header tag iterator. - * @param hi header tag iterator - * @return NULL always - */ -static /*@null@ */ - HeaderIterator -headerFreeIterator ( /*@only@ */ HeaderIterator hi) - /*@modifies hi @ */ -{ - hi->h = headerFree (hi->h); - hi = _free (hi); - return hi; -} - -/** - * Find matching (tag,type) entry in header. - * @param h header - * @param tag entry tag - * @param type entry type - * @return header entry - */ -static /*@null@ */ - indexEntry -findEntry ( /*@null@ */ Header h, int_32 tag, int_32 type) - /*@modifies h @ */ -{ - indexEntry entry, entry2, last; - struct indexEntry key; - - if (h == NULL) - return NULL; - if (!(h->flags & HEADERFLAG_SORTED)) - headerSort (h); - - key.info.tag = tag; - - entry2 = entry = - bsearch (&key, h->index, h->indexUsed, sizeof (*h->index), indexCmp); - if (entry == NULL) - return NULL; - - if (type == RPM_NULL_TYPE) - return entry; - - /* look backwards */ - while (entry->info.tag == tag && entry->info.type != type && - entry > h->index) - entry--; - - if (entry->info.tag == tag && entry->info.type == type) - return entry; - - last = h->index + h->indexUsed; - /*@-usereleased@ *//* FIX: entry2 = entry. Code looks bogus as well. */ - while (entry2->info.tag == tag && entry2->info.type != type && - entry2 < last) - entry2++; - /*@=usereleased@ */ - - if (entry->info.tag == tag && entry->info.type == type) - return entry; - - return NULL; -} - -static int regionSwab ( /*@null@ */ indexEntry entry, int il, int dl, - entryInfo pe, char *dataStart, int regionid); - /*@modifies *entry, *dataStart @ */ - -/** \ingroup header - * Retrieve data from header entry. - * @todo Permit retrieval of regions other than HEADER_IMUTABLE. - * @param entry header entry - * @retval type address of type (or NULL) - * @retval p address of data (or NULL) - * @retval c address of count (or NULL) - * @param minMem string pointers refer to header memory? - * @return 1 on success, otherwise error. - */ -static int -copyEntry (const indexEntry entry, - /*@null@ *//*@out@ */ hTYP_t type, - /*@null@ *//*@out@ */ hPTR_t * p, - /*@null@ *//*@out@ */ hCNT_t c, - int minMem) - /*@modifies *type, *p, *c @ */ -{ - int_32 count = entry->info.count; - int rc = 1; /* XXX 1 on success. */ - - if (p) - switch (entry->info.type) - { - case RPM_BIN_TYPE: - /* - * XXX This only works for - * XXX "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE. - * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e. - * XXX a legacy header freshly read, but not yet unloaded to the rpmdb). - */ - if (ENTRY_IS_REGION (entry)) - { - int_32 *ei = ((int_32 *) entry->data) - 2; - /*@-castexpose@ */ - entryInfo pe = (entryInfo) (ei + 2); - /*@=castexpose@ */ - char *dataStart = (char *) (pe + ntohl (ei[0])); - int_32 rdl = -entry->info.offset; /* negative offset */ - int_32 ril = rdl / sizeof (*pe); - - /*@-sizeoftype@ */ - rdl = entry->rdlen; - count = 2 * sizeof (*ei) + (ril * sizeof (*pe)) + rdl; - if (entry->info.tag == HEADER_IMAGE) - { - ril -= 1; - pe += 1; - } - else - { - count += REGION_TAG_COUNT; - rdl += REGION_TAG_COUNT; - } - - *p = malloc (count); - ei = (int_32 *) * p; - ei[0] = htonl (ril); - ei[1] = htonl (rdl); - - /*@-castexpose@ */ - pe = (entryInfo) memcpy (ei + 2, pe, (ril * sizeof (*pe))); - /*@=castexpose@ */ - - dataStart = (char *) memcpy (pe + ril, dataStart, rdl); - /*@=sizeoftype@ */ - - rc = regionSwab (NULL, ril, 0, pe, dataStart, 0); - /* XXX 1 on success. */ - rc = (rc < 0) ? 0 : 1; - } - else - { - count = entry->length; - *p = (!minMem - ? memcpy (malloc (count), entry->data, count) - : entry->data); - } - break; - case RPM_STRING_TYPE: - if (count == 1) - { - *p = entry->data; - break; - } - /*@fallthrough@ */ - case RPM_STRING_ARRAY_TYPE: - case RPM_I18NSTRING_TYPE: - { - const char **ptrEntry; - /*@-sizeoftype@ */ - int tableSize = count * sizeof (char *); - /*@=sizeoftype@ */ - char *t; - int i; - - /*@-mods@ */ - if (minMem) - { - *p = malloc (tableSize); - ptrEntry = (const char **) *p; - t = entry->data; - } - else - { - t = malloc (tableSize + entry->length); - *p = (void *) t; - ptrEntry = (const char **) *p; - t += tableSize; - memcpy (t, entry->data, entry->length); - } - /*@=mods@ */ - for (i = 0; i < count; i++) - { - *ptrEntry++ = t; - t = strchr (t, 0); - t++; - } - } - break; - - default: - *p = entry->data; - break; - } - if (type) - *type = entry->info.type; - if (c) - *c = count; - return rc; -} - -#define ENTRY_IN_REGION(_e) ((_e)->info.offset < 0) - -/** \ingroup header - * Append element to tag array in header. - * Appends item p to entry w/ tag and type as passed. Won't work on - * RPM_STRING_TYPE. Any pointers into header memory returned from - * headerGetEntryMinMemory() for this entry are invalid after this - * call has been made! - * - * @param h header - * @param tag tag - * @param type tag value data type - * @param p pointer to tag value(s) - * @param c number of values - * @return 1 on success, 0 on failure - */ -static int -headerAppendEntry (Header h, int_32 tag, int_32 type, const void *p, int_32 c) - /*@modifies h @ */ -{ - indexEntry entry; - int length; - - /* First find the tag */ - entry = findEntry (h, tag, type); - if (!entry) - return 0; - - if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) - { - /* we can't do this */ - return 0; - } - - length = dataLength (type, p, c, 0); - - if (ENTRY_IN_REGION (entry)) - { - char *t = malloc (entry->length + length); - memcpy (t, entry->data, entry->length); - entry->data = t; - entry->info.offset = 0; - } - else - entry->data = realloc (entry->data, entry->length + length); - - copyData (type, ((char *) entry->data) + entry->length, p, c, length); - - entry->length += length; - - entry->info.count += c; - - return 1; -} - -/** \ingroup header - * Add or append element to tag array in header. - * @todo Arg "p" should have const. - * @param h header - * @param tag tag - * @param type tag value data type - * @param p pointer to tag value(s) - * @param c number of values - * @return 1 on success, 0 on failure - */ -static int -headerAddOrAppendEntry (Header h, int_32 tag, int_32 type, - const void *p, int_32 c) - /*@modifies h @ */ -{ - return (findEntry (h, tag, type) - ? headerAppendEntry (h, tag, type, p, c) - : headerAddEntry (h, tag, type, p, c)); -} - -/** - * Does locale match entry in header i18n table? - * - * \verbatim - * The range [l,le) contains the next locale to match: - * ll[_CC][.EEEEE][@dddd] - * where - * ll ISO language code (in lowercase). - * CC (optional) ISO coutnry code (in uppercase). - * EEEEE (optional) encoding (not really standardized). - * dddd (optional) dialect. - * \endverbatim - * - * @param td header i18n table data, NUL terminated - * @param l start of locale to match - * @param le end of locale to match - * @return 1 on match, 0 on no match - */ -static int -headerMatchLocale (const char *td, const char *l, const char *le) - /*@ */ -{ - const char *fe; - - -#if 0 - { - const char *s, *ll, *CC, *EE, *dd; - char *lbuf, *t. - /* Copy the buffer and parse out components on the fly. */ - lbuf = alloca (le - l + 1); - for (s = l, ll = t = lbuf; *s; s++, t++) - { - switch (*s) - { - case '_': - *t = '\0'; - CC = t + 1; - break; - case '.': - *t = '\0'; - EE = t + 1; - break; - case '@': - *t = '\0'; - dd = t + 1; - break; - default: - *t = *s; - break; - } - } - - if (ll) /* ISO language should be lower case */ - for (t = ll; *t; t++) - *t = tolower (*t); - if (CC) /* ISO country code should be upper case */ - for (t = CC; *t; t++) - *t = toupper (*t); - - /* There are a total of 16 cases to attempt to match. */ - } -#endif - - /* First try a complete match. */ - if (strlen (td) == (le - l) && !strncmp (td, l, (le - l))) - return 1; - - /* Next, try stripping optional dialect and matching. */ - for (fe = l; fe < le && *fe != '@'; fe++) - { - }; - if (fe < le && !strncmp (td, l, (fe - l))) - return 1; - - /* Next, try stripping optional codeset and matching. */ - for (fe = l; fe < le && *fe != '.'; fe++) - { - }; - if (fe < le && !strncmp (td, l, (fe - l))) - return 1; - - /* Finally, try stripping optional country code and matching. */ - for (fe = l; fe < le && *fe != '_'; fe++) - { - }; - if (fe < le && !strncmp (td, l, (fe - l))) - return 1; - - return 0; -} - -/** - * Return i18n string from header that matches locale. - * @param h header - * @param entry i18n string data - * @return matching i18n string (or 1st string if no match) - */ - /*@dependent@*//*@exposed@ */ static char * -headerFindI18NString (Header h, indexEntry entry) - /*@ */ -{ - const char *lang, *l, *le; - indexEntry table; - - /* XXX Drepper sez' this is the order. */ - if ((lang = getenv ("LANGUAGE")) == NULL && - (lang = getenv ("LC_ALL")) == NULL && - (lang = getenv ("LC_MESSAGES")) == NULL && - (lang = getenv ("LANG")) == NULL) - return entry->data; - - /*@-mods@ */ - if ((table = - findEntry (h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL) - return entry->data; - /*@=mods@ */ - - for (l = lang; *l != '\0'; l = le) - { - const char *td; - char *ed; - int langNum; - - while (*l && *l == ':') /* skip leading colons */ - l++; - if (*l == '\0') - break; - for (le = l; *le && *le != ':'; le++) /* find end of this locale */ - { - }; - - /* For each entry in the header ... */ - for (langNum = 0, td = table->data, ed = entry->data; - langNum < entry->info.count; - langNum++, td += strlen (td) + 1, ed += strlen (ed) + 1) - { - - if (headerMatchLocale (td, l, le)) - return ed; - - } - } - - return entry->data; -} - -/** - * Retrieve tag data from header. - * @param h header - * @param tag tag to retrieve - * @retval type address of type (or NULL) - * @retval p address of data (or NULL) - * @retval c address of count (or NULL) - * @param minMem string pointers reference header memory? - * @return 1 on success, 0 on not found - */ -static int -intGetEntry (Header h, int_32 tag, - /*@null@ *//*@out@ */ hTAG_t type, - /*@null@ *//*@out@ */ hPTR_t * p, - /*@null@ *//*@out@ */ hCNT_t c, - int minMem) - /*@modifies *type, *p, *c @ */ -{ - indexEntry entry; - int rc; - - /* First find the tag */ - /*@-mods@ *//*@ FIX: h modified by sort. */ - entry = findEntry (h, tag, RPM_NULL_TYPE); - /*@mods@ */ - if (entry == NULL) - { - if (type) - type = 0; - if (p) - *p = NULL; - if (c) - *c = 0; - return 0; - } - - switch (entry->info.type) - { - case RPM_I18NSTRING_TYPE: - rc = 1; - if (type) - *type = RPM_STRING_TYPE; - if (c) - *c = 1; - /*@-dependenttrans@ */ - if (p) - *p = headerFindI18NString (h, entry); - /*@=dependenttrans@ */ - break; - default: - rc = copyEntry (entry, type, p, c, minMem); - break; - } - - /* XXX 1 on success */ - return ((rc == 1) ? 1 : 0); -} - -/** \ingroup header - * Retrieve tag value. - * Will never return RPM_I18NSTRING_TYPE! RPM_STRING_TYPE elements with - * RPM_I18NSTRING_TYPE equivalent entries are translated (if HEADER_I18NTABLE - * entry is present). - * - * @param h header - * @param tag tag - * @retval type address of tag value data type (or NULL) - * @retval p address of pointer to tag value(s) (or NULL) - * @retval c address of number of values (or NULL) - * @return 1 on success, 0 on failure - */ -static int -headerGetEntry (Header h, int_32 tag, - /*@null@ *//*@out@ */ hTYP_t type, - /*@null@ *//*@out@ */ void **p, - /*@null@ *//*@out@ */ hCNT_t c) - /*@modifies *type, *p, *c @ */ -{ - return intGetEntry (h, tag, type, (hPTR_t *) p, c, 0); -} - -/** \ingroup header - */ - /*@observer@*//*@unchecked@ */ -static unsigned char header_magic[8] = { - 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00 -}; - -/** \ingroup header - * Return size of on-disk header representation in bytes. - * @param h header - * @param magicp include size of 8 bytes for (magic, 0)? - * @return size of on-disk header - */ -static unsigned int -headerSizeof ( /*@null@ */ Header h, enum hMagic magicp) - /*@modifies h @ */ -{ - indexEntry entry; - unsigned int size = 0; - int i; - - if (h == NULL) - return size; - - headerSort (h); - - switch (magicp) - { - case HEADER_MAGIC_YES: - size += sizeof (header_magic); - break; - case HEADER_MAGIC_NO: - break; - } - - /*@-sizeoftype@ */ - size += 2 * sizeof (int_32); /* count of index entries */ - /*@=sizeoftype@ */ - - for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) - { - unsigned diff; - int_32 type; - - /* Regions go in as is ... */ - if (ENTRY_IS_REGION (entry)) - { - size += entry->length; - /* XXX Legacy regions do not include the region tag and data. */ - /*@-sizeoftype@ */ - if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) - size += sizeof (struct entryInfo) + entry->info.count; - /*@=sizeoftype@ */ - continue; - } - - /* ... and region elements are skipped. */ - if (entry->info.offset < 0) - continue; - - /* Alignment */ - type = entry->info.type; - if (typeSizes[type] > 1) - { - diff = typeSizes[type] - (size % typeSizes[type]); - if (diff != typeSizes[type]) - { - size += diff; - } - } - - /*@-sizeoftype@ */ - size += sizeof (struct entryInfo) + entry->length; - /*@=sizeoftype@ */ - } - - return size; -} - -/** \ingroup header - * Reference a header instance. - * @param h header - * @return referenced header instance - */ -static Header -headerLink (Header h) - /*@modifies h @ */ -{ - if (h != NULL) - h->nrefs++; - /*@-refcounttrans -nullret @ */ - return h; - /*@=refcounttrans =nullret @ */ -} - -/** \ingroup header - * Create header tag iterator. - * @param h header - * @return header tag iterator - */ -static HeaderIterator -headerInitIterator (Header h) - /*@modifies h */ -{ - HeaderIterator hi = malloc (sizeof (*hi)); - - headerSort (h); - - hi->h = headerLink (h); - hi->next_index = 0; - return hi; -} - -/** \ingroup header - * Check if tag is in header. - * @param h header - * @param tag tag - * @return 1 on success, 0 on failure - */ -static int -headerIsEntry ( /*@null@ */ Header h, int_32 tag) - /*@ */ -{ - /*@-mods@ *//*@ FIX: h modified by sort. */ - return (findEntry (h, tag, RPM_NULL_TYPE) ? 1 : 0); - /*@=mods@ */ -} - -/** \ingroup header - * Return next tag from header. - * @param hi header tag iterator - * @retval tag address of tag - * @retval type address of tag value data type - * @retval p address of pointer to tag value(s) - * @retval c address of number of values - * @return 1 on success, 0 on failure - */ -static int -headerNextIterator (HeaderIterator hi, - /*@null@ *//*@out@ */ hTAG_t tag, - /*@null@ *//*@out@ */ hTYP_t type, - /*@null@ *//*@out@ */ hPTR_t * p, - /*@null@ *//*@out@ */ hCNT_t c, - int do_copy) - /*@modifies hi, *tag, *type, *p, *c @ */ -{ - Header h = hi->h; - int slot = hi->next_index; - indexEntry entry = NULL; - int rc; - - for (slot = hi->next_index; slot < h->indexUsed; slot++) - { - entry = h->index + slot; - if (!ENTRY_IS_REGION (entry)) - break; - } - hi->next_index = slot; - if (entry == NULL || slot >= h->indexUsed) - return 0; - /*@-noeffect@ *//* LCL: no clue */ - hi->next_index++; - /*@=noeffect@ */ - - if (tag) - *tag = entry->info.tag; - - rc = copyEntry (entry, type, p, c, do_copy); - - /* XXX 1 on success */ - return ((rc == 1) ? 1 : 0); -} - -/** \ingroup header - * Dereference a header instance. - * @param h header - * @return NULL always - */ -static /*@null@ */ - Header -headerUnlink ( /*@killref@ *//*@null@ */ Header h) - /*@modifies h @ */ -{ - if (h != NULL) - h->nrefs--; - return NULL; -} - -/** \ingroup header - * Dereference a header instance. - * @param h header - * @return NULL always - */ -static /*@null@ */ - Header -headerFree ( /*@killref@ *//*@null@ */ Header h) - /*@modifies h @ */ -{ - (void) headerUnlink (h); - - /*@-usereleased@ */ - if (h == NULL || h->nrefs > 0) - return NULL; /* XXX return previous header? */ - - if (h->index) - { - indexEntry entry = h->index; - int i; - for (i = 0; i < h->indexUsed; i++, entry++) - { - if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION (entry)) - { - if (entry->length > 0) - { - int_32 *ei = entry->data; - if ((ei - 2) == h->blob) - h->blob = _free (h->blob); - entry->data = NULL; - } - } - else if (!ENTRY_IN_REGION (entry)) - { - entry->data = _free (entry->data); - } - entry->data = NULL; - } - h->index = _free (h->index); - } - - /*@-refcounttrans@ */ h = _free (h); - /*@=refcounttrans@ */ - return h; - /*@=usereleased@ */ -} - -/** - * Sanity check on no. of tags. - * This check imposes a limit of 65K tags, more than enough. - */ -#define hdrchkTags(_ntags) ((_ntags) & 0xffff0000) - -/** - * Sanity check on data size and/or offset. - * This check imposes a limit of 16Mb, more than enough. - */ -#define hdrchkData(_nbytes) ((_nbytes) & 0xff000000) - - - -/** \ingroup header - * Swap int_32 and int_16 arrays within header region. - * - * This code is way more twisty than I would like. - * - * A bug with RPM_I18NSTRING_TYPE in rpm-2.5.x (fixed in August 1998) - * causes the offset and length of elements in a header region to disagree - * regarding the total length of the region data. - * - * The "fix" is to compute the size using both offset and length and - * return the larger of the two numbers as the size of the region. - * Kinda like computing left and right Riemann sums of the data elements - * to determine the size of a data structure, go figger :-). - * - * There's one other twist if a header region tag is in the set to be swabbed, - * as the data for a header region is located after all other tag data. - * - * @param entry header entry - * @param il no. of entries - * @param dl start no. bytes of data - * @param pe header physical entry pointer (swapped) - * @param dataStart header data - * @param regionid region offset - * @return no. bytes of data in region, -1 on error - */ -static int -regionSwab ( /*@null@ */ indexEntry entry, int il, int dl, - entryInfo pe, char *dataStart, int regionid) - /*@modifies *entry, *dataStart @ */ -{ - char *tprev = NULL; - char *t = NULL; - int tdel, tl = dl; - struct indexEntry ieprev; - - memset (&ieprev, 0, sizeof (ieprev)); - for (; il > 0; il--, pe++) - { - struct indexEntry ie; - int_32 type; - - ie.info.tag = ntohl (pe->tag); - ie.info.type = ntohl (pe->type); - if (ie.info.type < RPM_MIN_TYPE || ie.info.type > RPM_MAX_TYPE) - return -1; - ie.info.count = ntohl (pe->count); - ie.info.offset = ntohl (pe->offset); - ie.data = t = dataStart + ie.info.offset; - ie.length = dataLength (ie.info.type, ie.data, ie.info.count, 1); - ie.rdlen = 0; - - if (entry) - { - ie.info.offset = regionid; - *entry = ie; /* structure assignment */ - entry++; - } - - /* Alignment */ - type = ie.info.type; - if (typeSizes[type] > 1) - { - unsigned diff; - diff = typeSizes[type] - (dl % typeSizes[type]); - if (diff != typeSizes[type]) - { - dl += diff; - if (ieprev.info.type == RPM_I18NSTRING_TYPE) - ieprev.length += diff; - } - } - tdel = (tprev ? (t - tprev) : 0); - if (ieprev.info.type == RPM_I18NSTRING_TYPE) - tdel = ieprev.length; - - if (ie.info.tag >= HEADER_I18NTABLE) - { - tprev = t; - } - else - { - tprev = dataStart; - /* XXX HEADER_IMAGE tags don't include region sub-tag. */ - /*@-sizeoftype@ */ - if (ie.info.tag == HEADER_IMAGE) - tprev -= REGION_TAG_COUNT; - /*@=sizeoftype@ */ - } - - /* Perform endian conversions */ - switch (ntohl (pe->type)) - { - case RPM_INT32_TYPE: - { - int_32 *it = (int_32 *) t; - for (; ie.info.count > 0; ie.info.count--, it += 1) - *it = htonl (*it); - t = (char *) it; - } /*@switchbreak@ */ break; - case RPM_INT16_TYPE: - { - unsigned short *it = (unsigned short *) t; - for (; ie.info.count > 0; ie.info.count--, it += 1) - *it = htons (*it); - t = (char *) it; - } /*@switchbreak@ */ break; - default: - t += ie.length; - /*@switchbreak@ */ break; - } - - dl += ie.length; - tl += tdel; - ieprev = ie; /* structure assignment */ - - } - tdel = (tprev ? (t - tprev) : 0); - tl += tdel; - - /* XXX - * There are two hacks here: - * 1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload(). - * 2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl. - */ - /*@-sizeoftype@ */ - if (tl + REGION_TAG_COUNT == dl) - tl += REGION_TAG_COUNT; - /*@=sizeoftype@ */ - - return dl; -} - -static int headerRemoveEntry (Header h, int_32 tag); - -/** \ingroup header - * Convert header to in-memory representation. - * @param uh on-disk header blob (i.e. with offsets) - * @return header - */ -static /*@null@ */ - Header -headerLoad ( /*@kept@ */ void *uh) - /*@modifies uh @ */ -{ - int_32 *ei = (int_32 *) uh; - int_32 il = ntohl (ei[0]); /* index length */ - int_32 dl = ntohl (ei[1]); /* data length */ - /*@-sizeoftype@ */ - size_t pvlen = sizeof (il) + sizeof (dl) + - (il * sizeof (struct entryInfo)) + dl; - /*@=sizeoftype@ */ - void *pv = uh; - Header h = NULL; - entryInfo pe; - char *dataStart; - indexEntry entry; - int rdlen; - - /* Sanity checks on header intro. */ - if (hdrchkTags (il) || hdrchkData (dl)) - goto errxit; - - ei = (int_32 *) pv; - /*@-castexpose@ */ - pe = (entryInfo) & ei[2]; - /*@=castexpose@ */ - dataStart = (char *) (pe + il); - - h = calloc (1, sizeof (*h)); - memset (h, 0, sizeof (*h)); - /*@-assignexpose@ */ - /*@=assignexpose@ */ - /*@-assignexpose -kepttrans@ */ - h->blob = uh; - /*@=assignexpose =kepttrans@ */ - h->indexAlloced = il + 1; - h->indexUsed = il; - h->index = calloc (h->indexAlloced, sizeof (*h->index)); - h->flags = HEADERFLAG_SORTED; - h->nrefs = 0; - h = headerLink (h); - - /* - * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus - * %verifyscript tag that needs to be diddled. - */ - if (ntohl (pe->tag) == 15 && - ntohl (pe->type) == RPM_STRING_TYPE && ntohl (pe->count) == 1) - { - pe->tag = htonl (1079); - } - - entry = h->index; - if (!(htonl (pe->tag) < HEADER_I18NTABLE)) - { - h->flags |= HEADERFLAG_LEGACY; - entry->info.type = REGION_TAG_TYPE; - entry->info.tag = HEADER_IMAGE; - /*@-sizeoftype@ */ - entry->info.count = REGION_TAG_COUNT; - /*@=sizeoftype@ */ - entry->info.offset = ((char *) pe - dataStart); /* negative offset */ - - /*@-assignexpose@ */ - entry->data = pe; - /*@=assignexpose@ */ - entry->length = pvlen - sizeof (il) - sizeof (dl); - rdlen = - regionSwab (entry + 1, il, 0, pe, dataStart, entry->info.offset); -#if 0 /* XXX don't check, the 8/98 i18n bug fails here. */ - if (rdlen != dl) - goto errxit; -#endif - entry->rdlen = rdlen; - entry++; - h->indexUsed++; - } - else - { - int nb = ntohl (pe->count); - int_32 rdl; - int_32 ril; - - h->flags &= ~HEADERFLAG_LEGACY; - - entry->info.type = htonl (pe->type); - if (entry->info.type < RPM_MIN_TYPE || entry->info.type > RPM_MAX_TYPE) - goto errxit; - entry->info.count = htonl (pe->count); - - if (hdrchkTags (entry->info.count)) - goto errxit; - - { - int off = ntohl (pe->offset); - - if (hdrchkData (off)) - goto errxit; - if (off) - { - int_32 *stei = memcpy (alloca (nb), dataStart + off, nb); - rdl = -ntohl (stei[2]); /* negative offset */ - ril = rdl / sizeof (*pe); - if (hdrchkTags (ril) || hdrchkData (rdl)) - goto errxit; - entry->info.tag = htonl (pe->tag); - } - else - { - ril = il; - /*@-sizeoftype@ */ - rdl = (ril * sizeof (struct entryInfo)); - /*@=sizeoftype@ */ - entry->info.tag = HEADER_IMAGE; - } - } - entry->info.offset = -rdl; /* negative offset */ - - /*@-assignexpose@ */ - entry->data = pe; - /*@=assignexpose@ */ - entry->length = pvlen - sizeof (il) - sizeof (dl); - rdlen = - regionSwab (entry + 1, ril - 1, 0, pe + 1, dataStart, - entry->info.offset); - if (rdlen < 0) - goto errxit; - entry->rdlen = rdlen; - - if (ril < h->indexUsed) - { - indexEntry newEntry = entry + ril; - int ne = (h->indexUsed - ril); - int rid = entry->info.offset + 1; - int rc; - - /* Load dribble entries from region. */ - rc = regionSwab (newEntry, ne, 0, pe + ril, dataStart, rid); - if (rc < 0) - goto errxit; - rdlen += rc; - - { - indexEntry firstEntry = newEntry; - int save = h->indexUsed; - int j; - - /* Dribble entries replace duplicate region entries. */ - h->indexUsed -= ne; - for (j = 0; j < ne; j++, newEntry++) - { - (void) headerRemoveEntry (h, newEntry->info.tag); - if (newEntry->info.tag == HEADER_BASENAMES) - (void) headerRemoveEntry (h, HEADER_OLDFILENAMES); - } - - /* If any duplicate entries were replaced, move new entries down. */ - if (h->indexUsed < (save - ne)) - { - memmove (h->index + h->indexUsed, firstEntry, - (ne * sizeof (*entry))); - } - h->indexUsed += ne; - } - } - } - - h->flags &= ~HEADERFLAG_SORTED; - headerSort (h); - - /*@-globstate -observertrans @ */ - return h; - /*@=globstate =observertrans @ */ - -errxit: - /*@-usereleased@ */ - if (h) - { - h->index = _free (h->index); - /*@-refcounttrans@ */ - h = _free (h); - /*@=refcounttrans@ */ - } - /*@=usereleased@ */ - /*@-refcounttrans -globstate@ */ - return h; - /*@=refcounttrans =globstate@ */ -} - -/** \ingroup header - * Read (and load) header from file handle. - * @param fd file handle - * @param magicp read (and verify) 8 bytes of (magic, 0)? - * @return header (or NULL on error) - */ -static /*@null@ */ - Header -headerRead (FD_t fd, enum hMagic magicp) - /*@modifies fd @ */ -{ - int_32 block[4]; - int_32 *ei = NULL; - int_32 il; - int_32 dl; - int_32 magic; - Header h = NULL; - size_t len; - int i; - - memset (block, 0, sizeof (block)); - i = 2; - if (magicp == HEADER_MAGIC_YES) - i += 2; - - /*@-type@ *//* FIX: cast? */ - if (timedRead (fd, (char *) block, i * sizeof (*block)) != - (i * sizeof (*block))) - goto exit; - /*@=type@ */ - - i = 0; - - if (magicp == HEADER_MAGIC_YES) - { - magic = block[i++]; - if (memcmp (&magic, header_magic, sizeof (magic))) - goto exit; - i++; - } - - il = ntohl (block[i]); - i++; - dl = ntohl (block[i]); - i++; - - /*@-sizeoftype@ */ - len = sizeof (il) + sizeof (dl) + (il * sizeof (struct entryInfo)) + dl; - /*@=sizeoftype@ */ - - /* Sanity checks on header intro. */ - if (hdrchkTags (il) || hdrchkData (dl) || len > headerMaxbytes) - goto exit; - - ei = malloc (len); - ei[0] = htonl (il); - ei[1] = htonl (dl); - len -= sizeof (il) + sizeof (dl); - - /*@-type@ *//* FIX: cast? */ - if (timedRead (fd, (char *) &ei[2], len) != len) - goto exit; - /*@=type@ */ - - h = headerLoad (ei); - -exit: - if (h) - { - if (h->flags & HEADERFLAG_ALLOCATED) - ei = _free (ei); - h->flags |= HEADERFLAG_ALLOCATED; - } - else if (ei) - ei = _free (ei); - /*@-mustmod@ *//* FIX: timedRead macro obscures annotation */ - return h; - /*@-mustmod@ */ -} - -/** - * Check package size. - * @todo rpmio: use fdSize rather than fstat(2) to get file size. - * @param fd package file handle - * @param siglen signature header size - * @param pad signature padding - * @param datalen length of header+payload - * @return rpmRC return code - */ -static rpmRC -checkSize (FD_t fd, int siglen, int pad, int datalen) - /*@globals fileSystem @ */ - /*@modifies fileSystem @ */ -{ - rpmRC rc; - - rc = (((sizeof (struct rpmlead) + siglen + pad + datalen) - fd->len) - ? RPMRC_BADSIZE : RPMRC_OK); - - return rc; -} - -/** \ingroup header - * Create new (empty) header instance. - * @return header - */ -static Header -headerNew (void) - /*@ */ -{ - Header h = calloc (1, sizeof (*h)); - - memset (h, 0, sizeof (*h)); - /*@-assignexpose@ */ - /*@=assignexpose@ */ - h->blob = NULL; - h->indexAlloced = INDEX_MALLOC_SIZE; - h->indexUsed = 0; - h->flags = HEADERFLAG_SORTED; - - h->index = (h->indexAlloced - ? calloc (h->indexAlloced, sizeof (*h->index)) : NULL); - - /*@-globstate -observertrans @ */ - h->nrefs = 0; - return headerLink (h); - /*@=globstate =observertrans @ */ -} - -typedef unsigned char byte; - -static rpmRC -rpmReadSignature (FD_t fd, Header * headerp, sigType sig_type) -{ - byte buf[2048]; - int sigSize, pad; - int_32 type, count; - int_32 *archSize; - Header h = NULL; - rpmRC rc = RPMRC_FAIL; /* assume failure */ - - if (headerp) - *headerp = NULL; - - buf[0] = 0; - switch (sig_type) - { - case RPMSIGTYPE_NONE: - rc = RPMRC_OK; - break; - case RPMSIGTYPE_PGP262_1024: - /* These are always 256 bytes */ - if (timedRead (fd, buf, 256) != 256) - break; - h = headerNew (); - (void) headerAddEntry (h, RPMSIGTAG_PGP, RPM_BIN_TYPE, buf, 152); - rc = RPMRC_OK; - break; - case RPMSIGTYPE_MD5: - case RPMSIGTYPE_MD5_PGP: - break; - case RPMSIGTYPE_HEADERSIG: - case RPMSIGTYPE_DISABLE: - /* This is a new style signature */ - h = headerRead (fd, HEADER_MAGIC_YES); - if (h == NULL) - break; - - rc = RPMRC_OK; - sigSize = headerSizeof (h, HEADER_MAGIC_YES); - - /* XXX Legacy headers have a HEADER_IMAGE tag added. */ - if (headerIsEntry (h, RPMTAG_HEADERIMAGE)) - sigSize -= (16 + 16); - - pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */ - if (sig_type == RPMSIGTYPE_HEADERSIG) - { - if (!headerGetEntry (h, RPMSIGTAG_SIZE, &type, - (void **) &archSize, &count)) - break; - rc = checkSize (fd, sigSize, pad, *archSize); - } - if (pad && timedRead (fd, buf, pad) != pad) - rc = RPMRC_SHORTREAD; - break; - default: - break; - } - - if (rc == 0 && headerp) - /*@-nullderef@ */ - *headerp = h; - /*@=nullderef@ */ - else if (h) - h = headerFree (h); - - return rc; -} - - -static int -readLead (FD_t fd, struct rpmlead *lead) -{ - memset (lead, 0, sizeof (*lead)); - /*@-type@ *//* FIX: remove timed read */ - if (timedRead (fd, (char *) lead, sizeof (*lead)) != sizeof (*lead)) - { - return 1; - } - /*@=type@ */ - - lead->type = ntohs (lead->type); - lead->archnum = ntohs (lead->archnum); - lead->osnum = ntohs (lead->osnum); - - if (lead->major >= 2) - lead->signature_type = ntohs (lead->signature_type); - - return 0; -} - -/** \ingroup header - * Retrieve tag value using header internal array. - * Get an entry using as little extra RAM as possible to return the tag value. - * This is only an issue for RPM_STRING_ARRAY_TYPE. - * - * @param h header - * @param tag tag - * @retval type address of tag value data type (or NULL) - * @retval p address of pointer to tag value(s) (or NULL) - * @retval c address of number of values (or NULL) - * @return 1 on success, 0 on failure - */ -static int -headerGetEntryMinMemory (Header h, int_32 tag, - /*@null@ *//*@out@ */ hTYP_t type, - /*@null@ *//*@out@ */ hPTR_t * p, - /*@null@ *//*@out@ */ hCNT_t c) - /*@modifies *type, *p, *c @ */ -{ - return intGetEntry (h, tag, type, p, c, 1); -} - -/** \ingroup header - * Delete tag in header. - * Removes all entries of type tag from the header, returns 1 if none were - * found. - * - * @param h header - * @param tag tag - * @return 0 on success, 1 on failure (INCONSISTENT) - */ -static int -headerRemoveEntry (Header h, int_32 tag) - /*@modifies h @ */ -{ - indexEntry last = h->index + h->indexUsed; - indexEntry entry, first; - int ne; - - entry = findEntry (h, tag, RPM_NULL_TYPE); - if (!entry) - return 1; - - /* Make sure entry points to the first occurence of this tag. */ - while (entry > h->index && (entry - 1)->info.tag == tag) - entry--; - - /* Free data for tags being removed. */ - for (first = entry; first < last; first++) - { - void *data; - if (first->info.tag != tag) - break; - data = first->data; - first->data = NULL; - first->length = 0; - if (ENTRY_IN_REGION (first)) - continue; - data = _free (data); - } - - ne = (first - entry); - if (ne > 0) - { - h->indexUsed -= ne; - ne = last - first; - if (ne > 0) - memmove (entry, first, (ne * sizeof (*entry))); - } - - return 0; -} - -static int -dncmp (const void *a, const void *b) -{ - const char *const *first = a; - const char *const *second = b; - return strcmp (*first, *second); -} - -static void -compressFilelist (Header h) -{ - HGE_t hge = (HGE_t) headerGetEntryMinMemory; - HAE_t hae = (HAE_t) headerAddEntry; - HRE_t hre = (HRE_t) headerRemoveEntry; - HFD_t hfd = headerFreeData; - char **fileNames; - const char **dirNames; - const char **baseNames; - int_32 *dirIndexes; - rpmTagType fnt; - int count; - int i; - int dirIndex = -1; - - /* - * This assumes the file list is already sorted, and begins with a - * single '/'. That assumption isn't critical, but it makes things go - * a bit faster. - */ - - if (headerIsEntry (h, RPMTAG_DIRNAMES)) - { - (void) hre (h, RPMTAG_OLDFILENAMES); - return; /* Already converted. */ - } - - if (!hge (h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count)) - return; /* no file list */ - if (fileNames == NULL || count <= 0) - return; - - dirNames = alloca (sizeof (*dirNames) * count); /* worst case */ - baseNames = alloca (sizeof (*dirNames) * count); - dirIndexes = alloca (sizeof (*dirIndexes) * count); - - if (fileNames[0][0] != '/') - { - /* HACK. Source RPM, so just do things differently */ - dirIndex = 0; - dirNames[dirIndex] = ""; - for (i = 0; i < count; i++) - { - dirIndexes[i] = dirIndex; - baseNames[i] = fileNames[i]; - } - goto exit; - } - - for (i = 0; i < count; i++) - { - const char **needle; - char savechar; - char *baseName; - int len; - - if (fileNames[i] == NULL) /* XXX can't happen */ - continue; - baseName = strrchr (fileNames[i], '/') + 1; - len = baseName - fileNames[i]; - needle = dirNames; - savechar = *baseName; - *baseName = '\0'; - if (dirIndex < 0 || - (needle = - bsearch (&fileNames[i], dirNames, dirIndex + 1, - sizeof (dirNames[0]), dncmp)) == NULL) - { - char *s = alloca (len + 1); - memcpy (s, fileNames[i], len + 1); - s[len] = '\0'; - dirIndexes[i] = ++dirIndex; - dirNames[dirIndex] = s; - } - else - dirIndexes[i] = needle - dirNames; - - *baseName = savechar; - baseNames[i] = baseName; - } - -exit: - if (count > 0) - { - (void) hae (h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count); - (void) hae (h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE, - baseNames, count); - (void) hae (h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE, - dirNames, dirIndex + 1); - } - - fileNames = hfd (fileNames, fnt); - - (void) hre (h, RPMTAG_OLDFILENAMES); -} - -static int -headerNVR (Header h, const char **np, const char **vp, const char **rp) -{ - int type; - int count; - - if (np) - { - if (!(headerGetEntry (h, RPMTAG_NAME, &type, (void **) np, &count) - && type == RPM_STRING_TYPE && count == 1)) - *np = NULL; - } - if (vp) - { - if (!(headerGetEntry (h, RPMTAG_VERSION, &type, (void **) vp, &count) - && type == RPM_STRING_TYPE && count == 1)) - *vp = NULL; - } - if (rp) - { - if (!(headerGetEntry (h, RPMTAG_RELEASE, &type, (void **) rp, &count) - && type == RPM_STRING_TYPE && count == 1)) - *rp = NULL; - } - return 0; -} - -/* - * Up to rpm 3.0.4, packages implicitly provided their own name-version-release. - * Retrofit an explicit "Provides: name = epoch:version-release. - */ -static void -providePackageNVR (Header h) -{ - HGE_t hge = (HGE_t) headerGetEntryMinMemory; - HFD_t hfd = headerFreeData; - const char *name, *version, *release; - int_32 *epoch; - const char *pEVR; - char *p; - int_32 pFlags = RPMSENSE_EQUAL; - const char **provides = NULL; - const char **providesEVR = NULL; - rpmTagType pnt, pvt = RPM_NULL_TYPE; - int_32 *provideFlags = NULL; - int providesCount; - int i; - int bingo = 1; - - /* Generate provides for this package name-version-release. */ - (void) headerNVR (h, &name, &version, &release); - if (!(name && version && release)) - return; - pEVR = p = alloca (21 + strlen (version) + 1 + strlen (release) + 1); - *p = '\0'; - if (hge (h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) - { - sprintf (p, "%d:", *epoch); - while (*p != '\0') - p++; - } - (void) my_stpcpy (my_stpcpy (my_stpcpy (p, version), "-"), release); - - /* - * Rpm prior to 3.0.3 does not have versioned provides. - * If no provides at all are available, we can just add. - */ - if (!hge (h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount)) - goto exit; - - /* - * Otherwise, fill in entries on legacy packages. - */ - if (!hge (h, RPMTAG_PROVIDEVERSION, &pvt, (void **) &providesEVR, NULL)) - { - for (i = 0; i < providesCount; i++) - { - char *vdummy = ""; - int_32 fdummy = RPMSENSE_ANY; - (void) headerAddOrAppendEntry (h, RPMTAG_PROVIDEVERSION, - RPM_STRING_ARRAY_TYPE, &vdummy, 1); - (void) headerAddOrAppendEntry (h, RPMTAG_PROVIDEFLAGS, - RPM_INT32_TYPE, &fdummy, 1); - } - goto exit; - } - - (void) hge (h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL); - - if (provides && providesEVR && provideFlags) - for (i = 0; i < providesCount; i++) - { - if (!(provides[i] && providesEVR[i])) - continue; - if (!(provideFlags[i] == RPMSENSE_EQUAL && - !strcmp (name, provides[i]) && !strcmp (pEVR, providesEVR[i]))) - continue; - bingo = 0; - break; - } +/* ******************** pipe feeder ************************ */ -exit: - provides = hfd (provides, pnt); - providesEVR = hfd (providesEVR, pvt); - - if (bingo) - { - (void) headerAddOrAppendEntry (h, RPMTAG_PROVIDENAME, - RPM_STRING_ARRAY_TYPE, &name, 1); - (void) headerAddOrAppendEntry (h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE, - &pFlags, 1); - (void) headerAddOrAppendEntry (h, RPMTAG_PROVIDEVERSION, - RPM_STRING_ARRAY_TYPE, &pEVR, 1); - } -} - -static Header rpmFreeSignature (Header h); +struct PipeArgs { + const char * data; + size_t pos; + size_t size; + int pi[2]; + int shutdown; +}; -/** - * Retrieve package components from file handle. - * @param fd file handle - * @param leadPtr address of lead (or NULL) - * @param sigs address of signatures (or NULL) - * @param hdrPtr address of header (or NULL) - * @return rpmRC return code - */ -static rpmRC -readPackageHeaders (FD_t fd, - /*@null@ *//*@out@ */ struct rpmlead *leadPtr, - /*@null@ *//*@out@ */ Header * sigs, - /*@null@ *//*@out@ */ Header * hdrPtr) - /*@modifies fd, *leadPtr, *sigs, *hdrPtr @ */ +static void * +pipe_feeder(void * args) { - Header hdrBlock; - struct rpmlead leadBlock; - Header *hdr = NULL; - struct rpmlead *lead; - char *defaultPrefix; - rpmRC rc; - - hdr = hdrPtr ? hdrPtr : &hdrBlock; - lead = leadPtr ? leadPtr : &leadBlock; - - if (readLead (fd, lead)) - return RPMRC_FAIL; - - if (lead->magic[0] != RPMLEAD_MAGIC0 || lead->magic[1] != RPMLEAD_MAGIC1 || - lead->magic[2] != RPMLEAD_MAGIC2 || lead->magic[3] != RPMLEAD_MAGIC3) - { - return RPMRC_BADMAGIC; - } - - switch (lead->major) - { - case 1: - return RPMRC_FAIL; - /*@notreached@ */ break; - case 2: - case 3: - case 4: - rc = rpmReadSignature (fd, sigs, lead->signature_type); - if (rc == RPMRC_FAIL) - return rc; - *hdr = headerRead (fd, (lead->major >= 3) - ? HEADER_MAGIC_YES : HEADER_MAGIC_NO); - if (*hdr == NULL) - { - if (sigs != NULL) - *sigs = rpmFreeSignature (*sigs); - return RPMRC_FAIL; - } - - /* - * We don't use these entries (and rpm >= 2 never has) and they are - * pretty misleading. Let's just get rid of them so they don't confuse - * anyone. - */ - if (headerIsEntry (*hdr, RPMTAG_FILEUSERNAME)) - (void) headerRemoveEntry (*hdr, RPMTAG_FILEUIDS); - if (headerIsEntry (*hdr, RPMTAG_FILEGROUPNAME)) - (void) headerRemoveEntry (*hdr, RPMTAG_FILEGIDS); - - /* - * We switched the way we do relocateable packages. We fix some of - * it up here, though the install code still has to be a bit - * careful. This fixup makes queries give the new values though, - * which is quite handy. - */ - if (headerGetEntry (*hdr, RPMTAG_DEFAULTPREFIX, NULL, - (void **) &defaultPrefix, NULL)) - { - defaultPrefix = - stripTrailingChar (alloca_strdup (defaultPrefix), '/'); - (void) headerAddEntry (*hdr, RPMTAG_PREFIXES, RPM_STRING_ARRAY_TYPE, - &defaultPrefix, 1); - } - - /* - * The file list was moved to a more compressed format which not - * only saves memory (nice), but gives fingerprinting a nice, fat - * speed boost (very nice). Go ahead and convert old headers to - * the new style (this is a noop for new headers). - */ - if (lead->major < 4) - compressFilelist (*hdr); - - /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */ - if (lead->type == RPMLEAD_SOURCE) - { - int_32 one = 1; - if (!headerIsEntry (*hdr, RPMTAG_SOURCEPACKAGE)) - (void) headerAddEntry (*hdr, RPMTAG_SOURCEPACKAGE, RPM_INT32_TYPE, - &one, 1); - } - else if (lead->major < 4) - { - /* Retrofit "Provide: name = EVR" for binary packages. */ - providePackageNVR (*hdr); - } - break; - - default: - return RPMRC_FAIL; - /*@notreached@ */ break; - } - - if (hdrPtr == NULL) - *hdr = headerFree (*hdr); + ssize_t ret; + struct PipeArgs * p = args; - return RPMRC_OK; + while ( (p->shutdown == 0) && + (0 < (ret = WRITE(p->pi[1], + &p->data[p->pos], + p->size - p->pos))) ) + p->pos += ret; + return NULL; } static void -headerMergeLegacySigs (Header h, const Header sig) -{ - HFD_t hfd = (HFD_t) headerFreeData; - HAE_t hae = (HAE_t) headerAddEntry; - HeaderIterator hi; - int_32 tag, type, count; - const void *ptr; - - /*@-mods@ *//* FIX: undocumented modification of sig */ - for (hi = headerInitIterator (sig); - /*@=mods@ */ - headerNextIterator (hi, &tag, &type, &ptr, &count, 0); - ptr = hfd (ptr, type)) - { - switch (tag) - { - case RPMSIGTAG_SIZE: - tag = RPMTAG_SIGSIZE; - /*@switchbreak@ */ break; - case RPMSIGTAG_LEMD5_1: - tag = RPMTAG_SIGLEMD5_1; - /*@switchbreak@ */ break; - case RPMSIGTAG_PGP: - tag = RPMTAG_SIGPGP; - /*@switchbreak@ */ break; - case RPMSIGTAG_LEMD5_2: - tag = RPMTAG_SIGLEMD5_2; - /*@switchbreak@ */ break; - case RPMSIGTAG_MD5: - tag = RPMTAG_SIGMD5; - /*@switchbreak@ */ break; - case RPMSIGTAG_GPG: - tag = RPMTAG_SIGGPG; - /*@switchbreak@ */ break; - case RPMSIGTAG_PGP5: - tag = RPMTAG_SIGPGP5; - /*@switchbreak@ */ break; - case RPMSIGTAG_PAYLOADSIZE: - tag = RPMTAG_ARCHIVESIZE; - /*@switchbreak@ */ break; - case RPMSIGTAG_SHA1: - case RPMSIGTAG_DSA: - case RPMSIGTAG_RSA: - default: - if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE)) - continue; - /*@switchbreak@ */ break; - } - if (ptr == NULL) - continue; /* XXX can't happen */ - if (!headerIsEntry (h, tag)) - hae (h, tag, type, ptr, count); - } - hi = headerFreeIterator (hi); -} - -static Header -rpmFreeSignature (Header h) -{ - return headerFree (h); -} - -static rpmRC -rpmReadPackageHeader (FD_t fd, Header * hdrp, int *isSource, int *major, - int *minor) +sigalrmHandler (int sig) { - struct rpmlead lead; - Header sig = NULL; - rpmRC rc = readPackageHeaders (fd, &lead, &sig, hdrp); - - if (rc != RPMRC_OK) - goto exit; - - if (hdrp && *hdrp && sig) - { - headerMergeLegacySigs (*hdrp, sig); - sig = rpmFreeSignature (sig); - } - - if (isSource) - *isSource = lead.type == RPMLEAD_SOURCE; - /*@-mods@ */ - if (major) - *major = lead.major; - if (minor) - *minor = lead.minor; - /*@=mods@ */ - -exit: - return rc; + /* do nothing */ } -/* ******************** real libextractor stuff ************************ */ +/* *************** real libextractor stuff ***************** */ static struct EXTRACTOR_Keywords * addKeyword (EXTRACTOR_KeywordType type, - char *keyword, struct EXTRACTOR_Keywords *next) + const char *keyword, struct EXTRACTOR_Keywords *next) { EXTRACTOR_KeywordList *result; @@ -3168,8 +80,6 @@ typedef struct EXTRACTOR_KeywordType type; } Matches; -/* SEE: - http://rikers.org/rpmbook/node119.html#SECTION031425200000000000000 */ static Matches tests[] = { {RPMTAG_NAME, EXTRACTOR_TITLE}, {RPMTAG_VERSION, EXTRACTOR_VERSIONNUMBER}, @@ -3190,42 +100,67 @@ static Matches tests[] = { {0, 0}, }; -/* mimetype = application/rpm */ +static void discardCB() { + /* do nothing! */ +} + +/* mimetype = application/x-rpm */ struct EXTRACTOR_Keywords * -libextractor_rpm_extract (char *filename, - char *data, +libextractor_rpm_extract (const char *filename, + const char *data, size_t size, struct EXTRACTOR_Keywords *prev) { - fdStruct handle; + struct PipeArgs parg; + pthread_t pthr; + void * unused; Header hdr; HeaderIterator hi; int_32 tag; int_32 type; int_32 c; hPTR_t p; - int isSource; - int major; - int minor; int i; - char verb[40]; - - handle.data = data; - handle.pos = 0; - handle.len = size; - if (0 != rpmReadPackageHeader (&handle, &hdr, &isSource, &major, &minor)) - { + FD_t fdi; + rpmRC rc; + rpmts ts; + struct sigaction sig; + struct sigaction old; + + if (0 != pipe(parg.pi)) + return prev; + fdi = NULL; + parg.data = data; + parg.pos = 0; + parg.size = size; + parg.shutdown = 0; + if (0 != pthread_create(&pthr, + NULL, + &pipe_feeder, + &parg)) + { + CLOSE(parg.pi[0]); + CLOSE(parg.pi[1]); return prev; } + rpmlogSetCallback(&discardCB); + fdi = fdDup(parg.pi[0]); + ts = rpmtsCreate(); + rc = rpmReadPackageFile (ts, fdi, "GNU libextractor", &hdr); + switch (rc) + { + case RPMRC_OK: + case RPMRC_NOKEY: + case RPMRC_NOTTRUSTED: + break; + case RPMRC_NOTFOUND: + case RPMRC_FAIL: + default: + goto END; + } prev = addKeyword (EXTRACTOR_MIMETYPE, - "application/x-redhat-package-manager", prev); - /* FIXME: add platform! */ - if (isSource) - sprintf (verb, _("Source RPM %d.%d"), major, minor); - else - sprintf (verb, _("Binary RPM %d.%d"), major, minor); - prev = addKeyword (EXTRACTOR_UNKNOWN, verb, prev); + "application/x-rpm", prev); hi = headerInitIterator (hdr); - while (1 == headerNextIterator (hi, &tag, &type, &p, &c, 0)) + while (1 == headerNextIterator (hi, &tag, &type, &p, &c)) { i = 0; while (tests[i].rtype != 0) @@ -3330,10 +265,22 @@ libextractor_rpm_extract (char *filename, } headerFreeIterator (hi); headerFree (hdr); + rpmtsFree(ts); + END: + /* make sure SIGALRM does not kill us */ + memset (&sig, 0, sizeof (struct sigaction)); + memset (&old, 0, sizeof (struct sigaction)); + sig.sa_flags = SA_NODEFER; + sig.sa_handler = &sigalrmHandler; + sigaction (SIGALRM, &sig, &old); + parg.shutdown = 1; + CLOSE(parg.pi[1]); + pthread_kill(pthr, SIGALRM); + pthread_join(pthr, &unused); + sigaction (SIGALRM, &old, &sig); + Fclose(fdi); + CLOSE(parg.pi[0]); return prev; } - - - /* end of rpmextractor.c */ diff --git a/src/plugins/thumbnailextractorqt.cc b/src/plugins/thumbnailextractorqt.cc @@ -42,6 +42,8 @@ extern "C" { + +#if 0 QApplication *app; char *argv; @@ -59,6 +61,7 @@ void __attribute__ ((destructor)) thumnailextractorqt_done() delete app; free(argv); } +#endif static EXTRACTOR_KeywordList * addKeyword(EXTRACTOR_KeywordType type, char * keyword, @@ -98,12 +101,11 @@ static char * whitelist[] = { NULL }; -struct EXTRACTOR_Keywords * -libextractor_thumbnailqt_extract(const char * filename, - const unsigned char * data, - size_t size, - struct EXTRACTOR_Keywords * prev, - const char * options) { +static struct EXTRACTOR_Keywords * +extract(const unsigned char * data, + size_t size, + struct EXTRACTOR_Keywords * prev, + const char * options) { QImage *img; QByteArray bytes; QBuffer buffer; @@ -237,6 +239,42 @@ libextractor_thumbnailqt_extract(const char * filename, prev); } +/* create new thread for C++ code (see Mantis #905) */ + +struct X { + const unsigned char * data; + size_t size; + struct EXTRACTOR_Keywords * prev; + const char * options; +}; + +static void * run(void * arg) { + struct X * x = (struct X*) arg; + return extract(x->data, x->size, x->prev, + x->options); +} + +struct EXTRACTOR_Keywords * +libextractor_thumbnailqt_extract(const char * filename, + const unsigned char * data, + size_t size, + struct EXTRACTOR_Keywords * prev, + const char * options) { + pthread_t pt; + struct X cls; + + void * ret; + cls.data = data; + cls.size = size; + cls.prev = prev; + cls.options = options; + if (0 == pthread_create(&pt, NULL, &run, &cls)) + if (0 == pthread_join(pt, &ret)) + return (struct EXTRACTOR_Keywords*) ret; + return prev; +} + + struct EXTRACTOR_Keywords * libextractor_thumbnail_extract(const char * filename, const unsigned char * data, diff --git a/src/test/fuzz_default.sh b/src/test/fuzz_default.sh @@ -24,7 +24,7 @@ do trap "echo $tmpfile caused SIGSEGV ; exit 1" SEGV while [ $seed -lt $ZZSTOPSEED ] do - echo "file $file seed $seed" +# echo "file $file seed $seed" zzuf -c -s $seed cat "$file" > "$tmpfile" if ! "$bindir/extract" "$tmpfile" > /dev/null then diff --git a/src/test/fuzz_thumbnail.sh b/src/test/fuzz_thumbnail.sh @@ -24,7 +24,7 @@ do trap "echo $tmpfile caused SIGSEGV ; exit 1" SEGV while [ $seed -lt $ZZSTOPSEED ] do - echo "file $file seed $seed" +# echo "file $file seed $seed" zzuf -c -s $seed cat "$file" > "$tmpfile" if ! "$bindir/extract" -n -l libextractor_thumbnail:libextractor_mime "$tmpfile" > /dev/null then diff --git a/src/test/mt_plugintest2.c b/src/test/mt_plugintest2.c @@ -14,6 +14,7 @@ struct TaskData }; static volatile int done = 0; + static volatile int failed = 0; static void * @@ -52,34 +53,39 @@ test_plugins (void *arg) #define TEST_SECS 10 +#define NUM_TASKS 10 + int main (int argc, char *argv[]) { - int num_tasks = 10; - pthread_t task_list[num_tasks]; - struct TaskData td[num_tasks]; + pthread_t task_list[NUM_TASKS]; + struct TaskData td[NUM_TASKS]; int ret = 0; int i; + int max = NUM_TASKS; + void * unused; printf("testing for %d seconds\n", TEST_SECS); - for (i = 0; i < num_tasks; i++) + for (i = 0; i < NUM_TASKS; i++) { td[i].id = i; - ret = pthread_create (&task_list[i], NULL, test_plugins, &td[i]); + ret = pthread_create (&task_list[i], NULL, &test_plugins, &td[i]); if (ret != 0) { printf ("ERROR: pthread_create failed for thread %d\n", i); - num_tasks = i; + max = i; done = 1; break; } } + printf("Threads running!\n"); if (!done) sleep (TEST_SECS); + printf("Shutting down...\n"); done = 1; - for (i = 0; i < num_tasks; i++) + for (i = 0; i < max; i++) { - if (pthread_join (task_list[i], NULL) != 0) + if (pthread_join (task_list[i], &unused) != 0) printf ("WARNING: pthread_join failed for thread %d\n", i); }