Modify eu-strip option to perform strip in post script of rpm package & add option...
[platform/upstream/rpm.git] / lib / header.c
index 20ef3c6..90079f3 100644 (file)
@@ -9,15 +9,16 @@
 /* network byte order and is converted on the fly to host order. */
 
 #include "system.h"
-
+#include <netdb.h>
+#include <errno.h>
 #include <rpm/rpmtypes.h>
 #include <rpm/rpmstring.h>
 #include "lib/header_internal.h"
+#include "lib/misc.h"                  /* tag function proto */
 
+#include <errno.h>
 #include "debug.h"
 
-int _hdr_debug = 0;
-
 /** \ingroup header
  */
 const unsigned char rpm_header_magic[8] = {
@@ -68,40 +69,61 @@ static const int typeSizes[16] =  {
     0
 };
 
+enum headerFlags_e {
+    HEADERFLAG_SORTED    = (1 << 0), /*!< Are header entries sorted? */
+    HEADERFLAG_ALLOCATED = (1 << 1), /*!< Is 1st header region allocated? */
+    HEADERFLAG_LEGACY    = (1 << 2), /*!< Header came from legacy source? */
+    HEADERFLAG_DEBUG     = (1 << 3), /*!< Debug this header? */
+};
+
+typedef rpmFlags headerFlags;
+
 /** \ingroup header
- * Maximum no. of bytes permitted in a header.
+ * The Header data structure.
  */
-static const size_t headerMaxbytes = (32*1024*1024);
+struct headerToken_s {
+    void * blob;               /*!< Header region blob. */
+    indexEntry index;          /*!< Array of tags. */
+    int indexUsed;             /*!< Current size of tag array. */
+    int indexAlloced;          /*!< Allocated size of tag array. */
+    unsigned int instance;     /*!< Rpmdb instance (offset) */
+    headerFlags flags;
+    int nrefs;                 /*!< Reference count. */
+};
 
 /** \ingroup header
- * HEADER_EXT_TAG format function prototype.
- * This is allowed to fail, which indicates the tag doesn't exist.
- *
- * @param h            header
- * @retval td          tag data container
- * @return             0 on success
+ * Maximum no. of bytes permitted in a header.
  */
-typedef int (*headerTagTagFunction) (Header h, rpmtd td);
+static const size_t headerMaxbytes = (32*1024*1024);
 
-extern void *rpmHeaderTagFunc(rpmTag tag);
+#define        INDEX_MALLOC_SIZE       8
 
-Header headerLink(Header h)
-{
-    if (h == NULL) return NULL;
+#define        ENTRY_IS_REGION(_e) \
+       (((_e)->info.tag >= RPMTAG_HEADERIMAGE) && ((_e)->info.tag < RPMTAG_HEADERREGIONS))
+#define        ENTRY_IN_REGION(_e)     ((_e)->info.offset < 0)
 
-    h->nrefs++;
-if (_hdr_debug)
-fprintf(stderr, "--> h  %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
+/* Convert a 64bit value to network byte order. */
+RPM_GNUC_CONST
+static uint64_t htonll(uint64_t n)
+{
+    uint32_t *i = (uint32_t*)&n;
+    uint32_t b = i[0];
+    i[0] = htonl(i[1]);
+    i[1] = htonl(b);
+    return n;
+}
 
+Header headerLink(Header h)
+{
+    if (h != NULL)
+       h->nrefs++;
     return h;
 }
 
-Header headerUnlink(Header h)
+static Header headerUnlink(Header h)
 {
-    if (h == NULL) return NULL;
-if (_hdr_debug)
-fprintf(stderr, "--> h  %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
-    h->nrefs--;
+    if (h != NULL)
+       h->nrefs--;
     return NULL;
 }
 
@@ -110,7 +132,7 @@ Header headerFree(Header h)
     (void) headerUnlink(h);
 
     if (h == NULL || h->nrefs > 0)
-       return NULL;    /* XXX return previous header? */
+       return NULL;
 
     if (h->index) {
        indexEntry entry = h->index;
@@ -131,16 +153,20 @@ Header headerFree(Header h)
     }
 
     h = _free(h);
-    return h;
+    return NULL;
 }
 
-Header headerNew(void)
+static Header headerCreate(void *blob, unsigned int pvlen, int32_t indexLen)
 {
     Header h = xcalloc(1, sizeof(*h));
-
-    h->blob = NULL;
-    h->indexAlloced = INDEX_MALLOC_SIZE;
-    h->indexUsed = 0;
+    if (blob) {
+       h->blob = (pvlen > 0) ? memcpy(xmalloc(pvlen), blob, pvlen) : blob;
+       h->indexAlloced = indexLen + 1;
+       h->indexUsed = indexLen;
+    } else {
+       h->indexAlloced = INDEX_MALLOC_SIZE;
+       h->indexUsed = 0;
+    }
     h->instance = 0;
     h->flags |= HEADERFLAG_SORTED;
 
@@ -152,6 +178,11 @@ Header headerNew(void)
     return headerLink(h);
 }
 
+Header headerNew(void)
+{
+    return headerCreate(NULL, 0, 0);
+}
+
 int headerVerifyInfo(int il, int dl, const void * pev, void * iv, int negate)
 {
     entryInfo pe = (entryInfo) pev;
@@ -170,7 +201,7 @@ int headerVerifyInfo(int il, int dl, const void * pev, void * iv, int negate)
            return i;
        if (hdrchkAlign(info->type, info->offset))
            return i;
-       if (!negate && hdrchkRange(dl, info->offset))
+       if (hdrchkRange(dl, info->offset))
            return i;
        if (hdrchkData(info->count))
            return i;
@@ -179,8 +210,6 @@ int headerVerifyInfo(int il, int dl, const void * pev, void * iv, int negate)
     return -1;
 }
 
-/**
- */
 static int indexCmp(const void * avp, const void * bvp)
 {
     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
@@ -195,8 +224,6 @@ void headerSort(Header h)
     }
 }
 
-/**
- */
 static int offsetCmp(const void * avp, const void * bvp) 
 {
     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
@@ -212,20 +239,30 @@ static int offsetCmp(const void * avp, const void * bvp)
     return rc;
 }
 
-/** \ingroup header
- * Restore tags in header to original ordering.
- * @param h            header
- */
 void headerUnsort(Header h)
 {
-    qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
+    if (h->flags & HEADERFLAG_SORTED) {
+       qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
+       h->flags &= ~HEADERFLAG_SORTED;
+    }
+}
+
+static inline unsigned int alignDiff(rpm_tagtype_t type, unsigned int alignsize)
+{
+    int typesize = typeSizes[type];
+
+    if (typesize > 1) {
+       unsigned int diff = typesize - (alignsize % typesize);
+       if (diff != typesize)
+           return diff;
+    }
+    return 0;
 }
 
-unsigned headerSizeof(Header h, enum hMagic magicp)
+unsigned headerSizeof(Header h, int magicp)
 {
     indexEntry entry;
     unsigned int size = 0;
-    unsigned int pad = 0;
     int i;
 
     if (h == NULL)
@@ -244,9 +281,6 @@ unsigned headerSizeof(Header h, enum hMagic magicp)
     size += 2 * sizeof(int32_t);       /* count of index entries */
 
     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
-       unsigned diff;
-       rpmTagType type;
-
        /* Regions go in as is ... */
         if (ENTRY_IS_REGION(entry)) {
            size += entry->length;
@@ -261,14 +295,7 @@ unsigned headerSizeof(Header h, enum hMagic magicp)
            continue;
 
        /* Alignment */
-       type = entry->info.type;
-       if (typeSizes[type] > 1) {
-           diff = typeSizes[type] - (size % typeSizes[type]);
-           if (diff != typeSizes[type]) {
-               size += diff;
-               pad += diff;
-           }
-       }
+       size += alignDiff(entry->info.type, size);
 
        size += sizeof(struct entryInfo_s) + entry->length;
     }
@@ -276,6 +303,31 @@ unsigned headerSizeof(Header h, enum hMagic magicp)
     return size;
 }
 
+/*
+ * Header string (array) size calculation, bounded if end is non-NULL.
+ * Return length (including \0 termination) on success, -1 on error.
+ */
+static inline int strtaglen(const char *str, rpm_count_t c, const char *end)
+{
+    const char *start = str;
+    const char *s;
+
+    if (end) {
+       while ((s = memchr(start, '\0', end-start))) {
+           if (--c == 0 || s > end)
+               break;
+           start = s + 1;
+       }
+    } else {
+       while ((s = strchr(start, '\0'))) {
+           if (--c == 0)
+               break;
+           start = s + 1;
+       }
+    }
+    return (c > 0) ? -1 : (s - str + 1);
+}
+
 /**
  * Return length of entry data.
  * @param type         entry data type
@@ -285,23 +337,18 @@ unsigned headerSizeof(Header h, enum hMagic magicp)
  * @param pend         pointer to end of data (or NULL)
  * @return             no. bytes in data, -1 on failure
  */
-static int dataLength(rpmTagType type, rpm_constdata_t p, rpm_count_t count,
+static int dataLength(rpm_tagtype_t type, rpm_constdata_t p, rpm_count_t count,
                         int onDisk, rpm_constdata_t pend)
 {
-    const unsigned char * s = p;
-    const unsigned char * se = pend;
+    const char * s = p;
+    const char * se = pend;
     int length = 0;
 
     switch (type) {
     case RPM_STRING_TYPE:
        if (count != 1)
            return -1;
-       while (*s++) {
-           if (se && s > se)
-               return -1;
-           length++;
-       }
-       length++;       /* count nul terminator too. */
+       length = strtaglen(s, 1, se);
        break;
 
     case RPM_STRING_ARRAY_TYPE:
@@ -310,14 +357,7 @@ static int dataLength(rpmTagType type, rpm_constdata_t p, rpm_count_t count,
        /* Compute sum of length of all strings, including nul terminators */
 
        if (onDisk) {
-           while (count--) {
-               length++;       /* count nul terminator too */
-               while (*s++) {
-                   if (se && s > se)
-                       return -1;
-                   length++;
-               }
-           }
+           length = strtaglen(s, count, se);
        } else {
            const char ** av = (const char **)p;
            while (count--) {
@@ -342,19 +382,8 @@ static int dataLength(rpmTagType type, rpm_constdata_t p, rpm_count_t count,
 /** \ingroup header
  * Swap int32_t and int16_t 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.
+ * If a header region tag is in the set to be swabbed, as the data for a
+ * a header region is located after all other tag data.
  *
  * @param entry                header entry
  * @param il           no. of entries
@@ -363,24 +392,20 @@ static int dataLength(rpmTagType type, rpm_constdata_t p, rpm_count_t count,
  * @param dataStart    header data start
  * @param dataEnd      header data end
  * @param regionid     region offset
+ * @param fast         use offsets for data sizes if possible
  * @return             no. bytes of data in region, -1 on error
  */
 static int regionSwab(indexEntry entry, int il, int dl,
                entryInfo pe,
                unsigned char * dataStart,
                const unsigned char * dataEnd,
-               int regionid)
+               int regionid, int fast)
 {
-    unsigned char * tprev = NULL;
-    unsigned char * t = NULL;
-    int tdel = 0;
-    int tl = dl;
-    struct indexEntry_s ieprev;
+    if ((entry != NULL && regionid >= 0) || (entry == NULL && regionid != 0))
+       return -1;
 
-    memset(&ieprev, 0, sizeof(ieprev));
     for (; il > 0; il--, pe++) {
        struct indexEntry_s ie;
-       rpmTagType type;
 
        ie.info.tag = ntohl(pe->tag);
        ie.info.type = ntohl(pe->type);
@@ -396,11 +421,16 @@ static int regionSwab(indexEntry entry, int il, int dl,
        if (hdrchkAlign(ie.info.type, ie.info.offset))
            return -1;
 
-       ie.data = t = dataStart + ie.info.offset;
-       if (dataEnd && t >= dataEnd)
+       ie.data = dataStart + ie.info.offset;
+       if (dataEnd && (unsigned char *)ie.data >= dataEnd)
            return -1;
 
-       ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
+       if (fast && il > 1) {
+           ie.length = ntohl(pe[1].offset) - ie.info.offset;
+       } else {
+           ie.length = dataLength(ie.info.type, ie.data, ie.info.count,
+                                  1, dataEnd);
+       }
        if (ie.length < 0 || hdrchkData(ie.length))
            return -1;
 
@@ -413,112 +443,62 @@ static int regionSwab(indexEntry entry, int il, int dl,
        }
 
        /* 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. */
-           if (ie.info.tag == HEADER_IMAGE)
-               tprev -= REGION_TAG_COUNT;
-       }
+       dl += alignDiff(ie.info.type, dl);
 
        /* Perform endian conversions */
        switch (ntohl(pe->type)) {
        case RPM_INT64_TYPE:
-       {   uint64_t * it = (uint64_t *)t;
+       {   uint64_t * it = ie.data;
            for (; ie.info.count > 0; ie.info.count--, it += 1) {
                if (dataEnd && ((unsigned char *)it) >= dataEnd)
                    return -1;
                *it = htonll(*it);
            }
-           t = (unsigned char *) it;
        }   break;
        case RPM_INT32_TYPE:
-       {   int32_t * it = (int32_t *)t;
+       {   int32_t * it = ie.data;
            for (; ie.info.count > 0; ie.info.count--, it += 1) {
                if (dataEnd && ((unsigned char *)it) >= dataEnd)
                    return -1;
                *it = htonl(*it);
            }
-           t = (unsigned char *) it;
        }   break;
        case RPM_INT16_TYPE:
-       {   int16_t * it = (int16_t *) t;
+       {   int16_t * it = ie.data;
            for (; ie.info.count > 0; ie.info.count--, it += 1) {
                if (dataEnd && ((unsigned char *)it) >= dataEnd)
                    return -1;
                *it = htons(*it);
            }
-           t = (unsigned char *) it;
        }   break;
-       default:
-           t += ie.length;
-           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.
-     */
-    if (tl+REGION_TAG_COUNT == dl)
-       tl += REGION_TAG_COUNT;
 
     return dl;
 }
 
-/** \ingroup header
- * doHeaderUnload.
- * @param h            header
- * @retval *lengthPtr  no. bytes in unloaded header blob
- * @return             unloaded header blob (NULL on error)
- */
-static void * doHeaderUnload(Header h,
-               size_t * lengthPtr)
+void * headerExport(Header h, unsigned int *bsize)
 {
     int32_t * ei = NULL;
     entryInfo pe;
     char * dataStart;
     char * te;
-    unsigned pad;
-    unsigned len;
+    unsigned len, diff;
     int32_t il = 0;
     int32_t dl = 0;
     indexEntry entry; 
-    rpmTagType type;
     int i;
     int drlen, ndribbles;
-    int driplen, ndrips;
-    int legacy = 0;
+
+    if (h == NULL) return NULL;
 
     /* Sort entries by (offset,tag). */
     headerUnsort(h);
 
     /* Compute (il,dl) for all tags, including those deleted in region. */
-    pad = 0;
-    drlen = ndribbles = driplen = ndrips = 0;
+    drlen = ndribbles = 0;
     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
        if (ENTRY_IS_REGION(entry)) {
            int32_t rdl = -entry->info.offset;  /* negative offset */
@@ -537,15 +517,10 @@ static void * doHeaderUnload(Header h,
                    continue;
 
                /* Alignment */
-               type = entry->info.type;
-               if (typeSizes[type] > 1) {
-                   unsigned diff;
-                   diff = typeSizes[type] - (dl % typeSizes[type]);
-                   if (diff != typeSizes[type]) {
-                       drlen += diff;
-                       pad += diff;
-                       dl += diff;
-                   }
+               diff = alignDiff(entry->info.type, dl);
+               if (diff) {
+                   drlen += diff;
+                   dl += diff;    
                }
 
                ndribbles++;
@@ -563,21 +538,9 @@ static void * doHeaderUnload(Header h,
            continue;
 
        /* Alignment */
-       type = entry->info.type;
-       if (typeSizes[type] > 1) {
-           unsigned diff;
-           diff = typeSizes[type] - (dl % typeSizes[type]);
-           if (diff != typeSizes[type]) {
-               driplen += diff;
-               pad += diff;
-               dl += diff;
-           } else
-               diff = 0;
-       }
+       dl += alignDiff(entry->info.type, dl);
 
-       ndrips++;
        il++;
-       driplen += entry->length;
        dl += entry->length;
     }
 
@@ -594,12 +557,12 @@ static void * doHeaderUnload(Header h,
     pe = (entryInfo) &ei[2];
     dataStart = te = (char *) (pe + il);
 
-    pad = 0;
     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
        const char * src;
        unsigned char *t;
        int count;
        int rdlen;
+       unsigned int diff;
 
        if (entry->data == NULL || entry->length <= 0)
            continue;
@@ -621,7 +584,6 @@ static void * doHeaderUnload(Header h,
            if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
                int32_t stei[4];
 
-               legacy = 1;
                memcpy(pe+1, src, rdl);
                memcpy(te, src + rdl, rdlen);
                te += rdlen;
@@ -636,7 +598,7 @@ static void * doHeaderUnload(Header h,
                ril++;
                rdlen += entry->info.count;
 
-               count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
+               count = regionSwab(NULL, ril, 0, pe, t, NULL, 0, 0);
                if (count != rdlen)
                    goto errxit;
 
@@ -652,7 +614,7 @@ static void * doHeaderUnload(Header h,
                }
                te += entry->info.count + drlen;
 
-               count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
+               count = regionSwab(NULL, ril, 0, pe, t, NULL, 0, 0);
                if (count != (rdlen + entry->info.count + drlen))
                    goto errxit;
            }
@@ -673,15 +635,10 @@ static void * doHeaderUnload(Header h,
            continue;
 
        /* Alignment */
-       type = entry->info.type;
-       if (typeSizes[type] > 1) {
-           unsigned diff;
-           diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
-           if (diff != typeSizes[type]) {
-               memset(te, 0, diff);
-               te += diff;
-               pad += diff;
-           }
+       diff = alignDiff(entry->info.type, (te - dataStart));
+       if (diff) {
+           memset(te, 0, diff);
+           te += diff;
        }
 
        pe->offset = htonl(te - dataStart);
@@ -732,24 +689,21 @@ static void * doHeaderUnload(Header h,
     if ((((char *)ei)+len) != te)
        goto errxit;
 
-    if (lengthPtr)
-       *lengthPtr = len;
+    if (bsize)
+       *bsize = len;
 
-    h->flags &= ~HEADERFLAG_SORTED;
     headerSort(h);
 
     return (void *) ei;
 
 errxit:
-    ei = _free(ei);
-    return (void *) ei;
+    free(ei);
+    return NULL;
 }
 
 void * headerUnload(Header h)
 {
-    size_t length;
-    void * uh = doHeaderUnload(h, &length);
-    return uh;
+    return headerExport(h, NULL);
 }
 
 /**
@@ -760,9 +714,9 @@ void * headerUnload(Header h)
  * @return             header entry
  */
 static
-indexEntry findEntry(Header h, rpmTag tag, rpmTagType type)
+indexEntry findEntry(Header h, rpmTagVal tag, rpm_tagtype_t type)
 {
-    indexEntry entry, entry2, last;
+    indexEntry entry;
     struct indexEntry_s key;
 
     if (h == NULL) return NULL;
@@ -770,8 +724,7 @@ indexEntry findEntry(Header h, rpmTag tag, rpmTagType type)
 
     key.info.tag = tag;
 
-    entry2 = entry = 
-       bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
+    entry = bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
     if (entry == NULL)
        return NULL;
 
@@ -785,18 +738,10 @@ indexEntry findEntry(Header h, rpmTag tag, rpmTagType type)
     if (entry->info.tag == tag && entry->info.type == type)
        return entry;
 
-    last = h->index + h->indexUsed;
-    /* FIX: entry2 = entry. Code looks bogus as well. */
-    while (entry2->info.tag == tag && entry2->info.type != type &&
-          entry2 < last) entry2++;
-
-    if (entry->info.tag == tag && entry->info.type == type)
-       return entry;
-
     return NULL;
 }
 
-int headerDel(Header h, rpmTag tag)
+int headerDel(Header h, rpmTagVal tag)
 {
     indexEntry last = h->index + h->indexUsed;
     indexEntry entry, first;
@@ -819,7 +764,7 @@ int headerDel(Header h, rpmTag tag)
        first->length = 0;
        if (ENTRY_IN_REGION(first))
            continue;
-       data = _free(data);
+       free(data);
     }
 
     ne = (first - entry);
@@ -833,57 +778,49 @@ int headerDel(Header h, rpmTag tag)
     return 0;
 }
 
-Header headerLoad(void * uh)
+Header headerImport(void * blob, unsigned int bsize, headerImportFlags flags)
 {
-    int32_t * ei = (int32_t *) uh;
+    const int32_t * ei = (int32_t *) blob;
     int32_t il = ntohl(ei[0]);         /* index length */
     int32_t dl = ntohl(ei[1]);         /* data length */
-    size_t pvlen = sizeof(il) + sizeof(dl) +
-               (il * sizeof(struct entryInfo_s)) + dl;
-    void * pv = uh;
+    unsigned int pvlen = sizeof(il) + sizeof(dl) +
+                   (il * sizeof(struct entryInfo_s)) + dl;;
     Header h = NULL;
     entryInfo pe;
     unsigned char * dataStart;
     unsigned char * dataEnd;
     indexEntry entry; 
     int rdlen;
-    int i;
+    int fast = (flags & HEADERIMPORT_FAST);
 
     /* Sanity checks on header intro. */
-    if (hdrchkTags(il) || hdrchkData(dl))
+    if (bsize && bsize != pvlen)
+       goto errxit;
+    if (hdrchkTags(il) || hdrchkData(dl) || pvlen >= headerMaxbytes)
        goto errxit;
 
-    ei = (int32_t *) pv;
+    h = headerCreate(blob, (flags & HEADERIMPORT_COPY) ? pvlen : 0, il);
+
+    ei = h->blob; /* In case we had to copy */
     pe = (entryInfo) &ei[2];
     dataStart = (unsigned char *) (pe + il);
     dataEnd = dataStart + dl;
 
-    h = xcalloc(1, sizeof(*h));
-    h->blob = uh;
-    h->indexAlloced = il + 1;
-    h->indexUsed = il;
-    h->instance = 0;
-    h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
-    h->flags |= HEADERFLAG_SORTED;
-    h->nrefs = 0;
-    h = headerLink(h);
-
     entry = h->index;
-    i = 0;
-    if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
+    if (!(htonl(pe->tag) < RPMTAG_HEADERI18NTABLE)) {
        h->flags |= HEADERFLAG_LEGACY;
        entry->info.type = REGION_TAG_TYPE;
-       entry->info.tag = HEADER_IMAGE;
+       entry->info.tag = RPMTAG_HEADERIMAGE;
        entry->info.count = REGION_TAG_COUNT;
        entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
 
        entry->data = pe;
        entry->length = pvlen - sizeof(il) - sizeof(dl);
-       rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
+       rdlen = regionSwab(entry+1, il, 0, pe,
+                          dataStart, dataEnd, entry->info.offset, fast);
        if (rdlen != dl)
            goto errxit;
        entry->rdlen = rdlen;
-       entry++;
        h->indexUsed++;
     } else {
        int32_t rdl;
@@ -893,37 +830,40 @@ Header headerLoad(void * uh)
 
        entry->info.type = htonl(pe->type);
        entry->info.count = htonl(pe->count);
+       entry->info.tag = htonl(pe->tag);
 
-       if (hdrchkType(entry->info.type))
+       if (!ENTRY_IS_REGION(entry))
            goto errxit;
-       if (hdrchkTags(entry->info.count))
+       if (entry->info.type != REGION_TAG_TYPE)
+           goto errxit;
+       if (entry->info.count != REGION_TAG_COUNT)
            goto errxit;
 
        {   int off = ntohl(pe->offset);
 
-           if (hdrchkData(off))
-               goto errxit;
            if (off) {
                size_t nb = REGION_TAG_COUNT;
                int32_t stei[nb];
+               if (hdrchkRange(dl, (off + nb)))
+                   goto errxit;
                /* XXX Hmm, why the copy? */
                memcpy(&stei, 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;
                rdl = (ril * sizeof(struct entryInfo_s));
-               entry->info.tag = HEADER_IMAGE;
+               entry->info.tag = RPMTAG_HEADERIMAGE;
            }
        }
        entry->info.offset = -rdl;      /* negative offset */
 
        entry->data = pe;
        entry->length = pvlen - sizeof(il) - sizeof(dl);
-       rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
+       rdlen = regionSwab(entry+1, ril-1, 0, pe+1,
+                          dataStart, dataEnd, entry->info.offset, fast);
        if (rdlen < 0)
            goto errxit;
        entry->rdlen = rdlen;
@@ -932,13 +872,12 @@ Header headerLoad(void * uh)
            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, dataEnd, rid);
-           if (rc < 0)
+           rdlen = regionSwab(newEntry, ne, rdlen, pe+ril,
+                               dataStart, dataEnd, rid, fast);
+           if (rdlen < 0)
                goto errxit;
-           rdlen += rc;
 
          { indexEntry firstEntry = newEntry;
            int save = h->indexUsed;
@@ -960,6 +899,11 @@ Header headerLoad(void * uh)
            h->indexUsed += ne;
          }
        }
+
+       rdlen += REGION_TAG_COUNT;
+
+       if (rdlen != dl)
+           goto errxit;
     }
 
     h->flags &= ~HEADERFLAG_SORTED;
@@ -970,92 +914,78 @@ Header headerLoad(void * uh)
 
 errxit:
     if (h) {
-       h->index = _free(h->index);
-       h = _free(h);
+       if (flags & HEADERIMPORT_COPY)
+           free(h->blob);
+       free(h->index);
+       free(h);
     }
-    return h;
+    return NULL;
 }
 
-Header headerReload(Header h, rpmTag tag)
+Header headerReload(Header h, rpmTagVal tag)
 {
     Header nh;
-    size_t length;
-    void * uh = doHeaderUnload(h, &length);
+    unsigned int uc = 0;
+    void * uh = headerExport(h, &uc);
 
     h = headerFree(h);
     if (uh == NULL)
        return NULL;
-    nh = headerLoad(uh);
+    nh = headerImport(uh, uc, 0);
     if (nh == NULL) {
        uh = _free(uh);
        return NULL;
     }
     if (ENTRY_IS_REGION(nh->index)) {
-       if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
+       if (tag == RPMTAG_HEADERSIGNATURES || tag == RPMTAG_HEADERIMMUTABLE)
            nh->index[0].info.tag = tag;
     }
     return nh;
 }
 
-Header headerCopyLoad(const void * uh)
+Header headerLoad(void * uh)
 {
-    int32_t * ei = (int32_t *) uh;
-    int32_t il = ntohl(ei[0]);         /* index length */
-    int32_t dl = ntohl(ei[1]);         /* data length */
-    size_t pvlen = sizeof(il) + sizeof(dl) +
-                       (il * sizeof(struct entryInfo_s)) + dl;
-    void * nuh = NULL;
-    Header h = NULL;
+    return headerImport(uh, 0, 0);
+}
 
-    /* Sanity checks on header intro. */
-    if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
-       nuh = memcpy(xmalloc(pvlen), uh, pvlen);
-       if ((h = headerLoad(nuh)) == NULL)
-           nuh = _free(nuh);
-    }
-    return h;
+Header headerCopyLoad(const void * uh)
+{
+    /* Discards const but that's ok as we'll take a copy */
+    return headerImport((void *)uh, 0, HEADERIMPORT_COPY);
 }
 
-/** \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)
- */
-Header headerRead(FD_t fd, enum hMagic magicp)
+Header headerRead(FD_t fd, int magicp)
 {
     int32_t block[4];
-    int32_t reserved;
     int32_t * ei = NULL;
     int32_t il;
     int32_t dl;
-    int32_t magic;
     Header h = NULL;
-    size_t len;
-    int i;
+    unsigned int len, blen;
 
-    memset(block, 0, sizeof(block));
-    i = 2;
-    if (magicp == HEADER_MAGIC_YES)
-       i += 2;
+    if (magicp == HEADER_MAGIC_YES) {
+       int32_t magic;
 
-    /* FIX: cast? */
-    if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
-       goto exit;
+       if (Freadall(fd, block, 4*sizeof(*block)) != 4*sizeof(*block))
+           goto exit;
 
-    i = 0;
+       magic = block[0];
 
-    if (magicp == HEADER_MAGIC_YES) {
-       magic = block[i++];
        if (memcmp(&magic, rpm_header_magic, sizeof(magic)))
            goto exit;
-       reserved = block[i++];
+
+       il = ntohl(block[2]);
+       dl = ntohl(block[3]);
+    } else {
+       if (Freadall(fd, block, 2*sizeof(*block)) != 2*sizeof(*block))
+           goto exit;
+
+       il = ntohl(block[0]);
+       dl = ntohl(block[1]);
     }
-    
-    il = ntohl(block[i]);      i++;
-    dl = ntohl(block[i]);      i++;
 
-    len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
+    blen = (il * sizeof(struct entryInfo_s)) + dl;
+    len = sizeof(il) + sizeof(dl) + blen;
 
     /* Sanity checks on header intro. */
     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
@@ -1064,13 +994,11 @@ Header headerRead(FD_t fd, enum hMagic magicp)
     ei = xmalloc(len);
     ei[0] = htonl(il);
     ei[1] = htonl(dl);
-    len -= sizeof(il) + sizeof(dl);
 
-    /* FIX: cast? */
-    if (timedRead(fd, (char *)&ei[2], len) != len)
+    if (Freadall(fd, (char *)&ei[2], blen) != blen)
        goto exit;
     
-    h = headerLoad(ei);
+    h = headerImport(ei, len, 0);
 
 exit:
     if (h == NULL && ei != NULL) {
@@ -1079,15 +1007,13 @@ exit:
     return h;
 }
 
-int headerWrite(FD_t fd, Header h, enum hMagic magicp)
+int headerWrite(FD_t fd, Header h, int magicp)
 {
     ssize_t nb;
-    size_t length;
+    unsigned int length;
     void * uh;
 
-    if (h == NULL)
-       return 1;
-    uh = doHeaderUnload(h, &length);
+    uh = headerExport(h, &length);
     if (uh == NULL)
        return 1;
     switch (magicp) {
@@ -1103,11 +1029,11 @@ int headerWrite(FD_t fd, Header h, enum hMagic magicp)
     nb = Fwrite(uh, sizeof(char), length, fd);
 
 exit:
-    uh = _free(uh);
+    free(uh);
     return (nb == length ? 0 : 1);
 }
 
-int headerIsEntry(Header h, rpmTag tag)
+int headerIsEntry(Header h, rpmTagVal tag)
 {
                /* FIX: h modified by sort. */
     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
@@ -1156,7 +1082,7 @@ static int copyTdEntry(const indexEntry entry, rpmtd td, headerGetFlags flags)
 
            rdl = entry->rdlen;
            count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
-           if (entry->info.tag == HEADER_IMAGE) {
+           if (entry->info.tag == RPMTAG_HEADERIMAGE) {
                ril -= 1;
                pe += 1;
            } else {
@@ -1173,7 +1099,7 @@ static int copyTdEntry(const indexEntry entry, rpmtd td, headerGetFlags flags)
 
            dataStart = (unsigned char *) memcpy(pe + ril, dataStart, rdl);
 
-           rc = regionSwab(NULL, ril, 0, pe, dataStart, dataStart + rdl, 0);
+           rc = regionSwab(NULL, ril, 0, pe, dataStart, dataStart + rdl, 0, 0);
            /* don't return data on failure */
            if (rc < 0) {
                td->data = _free(td->data);
@@ -1188,7 +1114,8 @@ static int copyTdEntry(const indexEntry entry, rpmtd td, headerGetFlags flags)
        }
        break;
     case RPM_STRING_TYPE:
-       if (count == 1) {
+       /* simple string, but fallthrough if its actually an array */
+       if (count == 1 && !argvArray) {
            td->data = allocMem ? xstrdup(entry->data) : entry->data;
            break;
        }
@@ -1271,25 +1198,25 @@ static int headerMatchLocale(const char *td, const char *l, const char *le)
     const char *fe;
 
     /* First try a complete match. */
-    if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
+    if (strlen(td) == (le-l) && rstreqn(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)))
+    if (fe < le && rstreqn(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)))
+    if (fe < le && rstreqn(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)))
+    if (fe < le && rstreqn(td, l, (fe - l)))
        return 2;
 
     return 0;
@@ -1321,7 +1248,7 @@ static int copyI18NEntry(Header h, indexEntry entry, rpmtd td,
        (lang = getenv("LANG")) == NULL)
            goto exit;
     
-    if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
+    if ((table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
        goto exit;
 
     for (l = lang; *l != '\0'; l = le) {
@@ -1367,23 +1294,18 @@ exit:
 /**
  * Retrieve tag data from header.
  * @param h            header
- * @param tag          tag to retrieve
  * @retval td          tag data container
  * @param flags                flags to control retrieval
  * @return             1 on success, 0 on not found
  */
-static int intGetTdEntry(Header h, rpmTag tag, rpmtd td, headerGetFlags flags)
+static int intGetTdEntry(Header h, rpmtd td, headerGetFlags flags)
 {
     indexEntry entry;
     int rc;
 
-    assert(td != NULL);
-    /* ensure clean state */
-    rpmtdReset(td);
-    td->tag = tag;
     /* First find the tag */
     /* FIX: h modified by sort. */
-    entry = findEntry(h, tag, RPM_NULL_TYPE);
+    entry = findEntry(h, td->tag, RPM_NULL_TYPE);
     if (entry == NULL) {
        /* Td is zeroed above, just return... */
        return 0;
@@ -1402,39 +1324,28 @@ static int intGetTdEntry(Header h, rpmTag tag, rpmtd td, headerGetFlags flags)
        }
     }
 
+    if (rc == 0)
+       td->flags |= RPMTD_INVALID;
+
     /* XXX 1 on success */
     return ((rc == 1) ? 1 : 0);
 }
 
-/* 
- * XXX temporary kludgery until tag extensions have been converted to 
- * take rpmtd as argument
- */
-static int intGetTagExt(Header h, rpmTag tag, rpmtd td, headerTagTagFunction tagfunc)
+int headerGet(Header h, rpmTagVal tag, rpmtd td, headerGetFlags flags)
 {
     int rc;
-    rpmtdReset(td);
-    rc = tagfunc(h, td);
-    td->tag = tag;
-    return rc; 
-}
+    headerTagTagFunction tagfunc = intGetTdEntry;
 
-int headerGet(Header h, rpmTag tag, rpmtd td, headerGetFlags flags)
-{
-    int rc;
-    headerTagTagFunction tagfunc = NULL;
+    if (td == NULL) return 0;
 
-    assert(td != NULL);
+    rpmtdReset(td);
+    td->tag = tag;
 
     if (flags & HEADERGET_EXT) {
-       tagfunc = rpmHeaderTagFunc(tag);
-    }
-       
-    if (tagfunc) {
-       rc = intGetTagExt(h, tag, td, tagfunc);
-    } else {
-       rc = intGetTdEntry(h, tag, td, flags);
+       headerTagTagFunction extfunc = rpmHeaderTagFunc(tag);
+       if (extfunc) tagfunc = extfunc;
     }
+    rc = tagfunc(h, td, flags);
 
     assert(tag == td->tag);
     return rc;
@@ -1442,7 +1353,7 @@ int headerGet(Header h, rpmTag tag, rpmtd td, headerGetFlags flags)
 
 /**
  */
-static void copyData(rpmTagType type, rpm_data_t dstPtr, 
+static void copyData(rpm_tagtype_t type, rpm_data_t dstPtr, 
                rpm_constdata_t srcPtr, rpm_count_t cnt, int dataLength)
 {
     switch (type) {
@@ -1476,7 +1387,7 @@ static void copyData(rpmTagType type, rpm_data_t dstPtr,
  * @return             (malloc'ed) copy of entry data, NULL on error
  */
 static void *
-grabData(rpmTagType type, rpm_constdata_t p, rpm_count_t c, int * lengthPtr)
+grabData(rpm_tagtype_t type, rpm_constdata_t p, rpm_count_t c, int * lengthPtr)
 {
     rpm_data_t data = NULL;
     int length;
@@ -1496,7 +1407,7 @@ static int intAddEntry(Header h, rpmtd td)
 {
     indexEntry entry;
     rpm_data_t data;
-    int length;
+    int length = 0;
 
     /* Count must always be >= 1 for headerAddEntry. */
     if (td->count <= 0)
@@ -1507,9 +1418,8 @@ static int intAddEntry(Header h, rpmtd td)
     if (hdrchkData(td->count))
        return 0;
 
-    length = 0;
     data = grabData(td->type, td->data, td->count, &length);
-    if (data == NULL || length <= 0)
+    if (data == NULL)
        return 0;
 
     /* Allocate more index space if necessary */
@@ -1586,101 +1496,7 @@ int headerPut(Header h, rpmtd td, headerPutFlags flags)
     return rc;
 }
 
-/*
- * Sanity check data types against tag table before putting. Assume
- * append on all array-types.
- */
-static int headerPutType(Header h, rpmTag tag, rpmTagType reqtype,
-                       rpm_constdata_t data, rpm_count_t size)
-{
-    struct rpmtd_s td;
-    rpmTagType type = rpmTagGetType(tag);
-    headerPutFlags flags = HEADERPUT_APPEND; 
-    int valid = 1;
-
-    /* Basic sanity checks: type must match and there must be data to put */
-    if ((type & RPM_MASK_TYPE) != reqtype 
-       || size < 1 || data == NULL || h == NULL) {
-       valid = 0;
-    }
-
-    /*
-     * Non-array types can't be appended to. Binary types use size
-     * for data length, for other non-array types size must be 1.
-     */
-    if ((type & RPM_MASK_RETURN_TYPE) != RPM_ARRAY_RETURN_TYPE) {
-       flags = HEADERPUT_DEFAULT;
-       if ((type & RPM_MASK_TYPE) != RPM_BIN_TYPE && size != 1) {
-           valid = 0;
-       }
-    }
-
-    if (valid) {
-       rpmtdReset(&td);
-       td.tag = tag;
-       td.type = type & RPM_MASK_TYPE;
-       td.data = (void *) data;
-       td.count = size;
-
-       valid = headerPut(h, &td, flags);
-    }
-
-    return valid;
-}
-       
-int headerPutString(Header h, rpmTag tag, const char *val)
-{
-    rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
-    const void *sptr = NULL;
-
-    /* string arrays expect char **, arrange that */
-    if (type == RPM_STRING_ARRAY_TYPE || type == RPM_I18NSTRING_TYPE) {
-       sptr = &val;
-    } else if (type == RPM_STRING_TYPE) {
-       sptr = val;
-    } else {
-       return 0;
-    }
-
-    return headerPutType(h, tag, type, sptr, 1);
-}
-
-int headerPutStringArray(Header h, rpmTag tag, const char **array, rpm_count_t size)
-{
-    return headerPutType(h, tag, RPM_STRING_ARRAY_TYPE, array, size);
-}
-
-int headerPutChar(Header h, rpmTag tag, char *val, rpm_count_t size)
-{
-    return headerPutType(h, tag, RPM_CHAR_TYPE, val, size);
-}
-
-int headerPutUint8(Header h, rpmTag tag, uint8_t *val, rpm_count_t size)
-{
-    return headerPutType(h, tag, RPM_INT8_TYPE, val, size);
-}
-
-int headerPutUint16(Header h, rpmTag tag, uint16_t *val, rpm_count_t size)
-{
-    return headerPutType(h, tag, RPM_INT16_TYPE, val, size);
-}
-
-int headerPutUint32(Header h, rpmTag tag, uint32_t *val, rpm_count_t size)
-{
-    return headerPutType(h, tag, RPM_INT32_TYPE, val, size);
-}
-
-int headerPutUint64(Header h, rpmTag tag, uint64_t *val, rpm_count_t size)
-{
-    return headerPutType(h, tag, RPM_INT64_TYPE, val, size);
-}
-
-int headerPutBin(Header h, rpmTag tag, uint8_t *val, rpm_count_t size)
-{
-    return headerPutType(h, tag, RPM_BIN_TYPE, val, size);
-}
-
-int headerAddI18NString(Header h, rpmTag tag, const char * string,
+int headerAddI18NString(Header h, rpmTagVal tag, const char * string,
                const char * lang)
 {
     indexEntry table, entry;
@@ -1690,7 +1506,7 @@ int headerAddI18NString(Header h, rpmTag tag, const char * string,
     rpm_count_t i, langNum;
     char * buf;
 
-    table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
+    table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE);
     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
 
     if (!table && entry)
@@ -1708,13 +1524,13 @@ int headerAddI18NString(Header h, rpmTag tag, const char * string,
        }
        
        rpmtdReset(&td);
-       td.tag = HEADER_I18NTABLE;
+       td.tag = RPMTAG_HEADERI18NTABLE;
        td.type = RPM_STRING_ARRAY_TYPE;
        td.data = (void *) charArray;
        td.count = count;
        if (!headerPut(h, &td, HEADERPUT_DEFAULT))
            return 0;
-       table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
+       table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE);
     }
 
     if (!table)
@@ -1723,7 +1539,7 @@ int headerAddI18NString(Header h, rpmTag tag, const char * string,
 
     {  const char * l = table->data;
        for (langNum = 0; langNum < table->info.count; langNum++) {
-           if (!strcmp(l, lang)) break;
+           if (rstreq(l, lang)) break;
            l += strlen(l) + 1;
        }
     }
@@ -1823,16 +1639,15 @@ int headerMod(Header h, rpmtd td)
     indexEntry entry;
     rpm_data_t oldData;
     rpm_data_t data;
-    int length;
+    int length = 0;
 
     /* First find the tag */
     entry = findEntry(h, td->tag, td->type);
     if (!entry)
        return 0;
 
-    length = 0;
     data = grabData(td->type, td->data, td->count, &length);
-    if (data == NULL || length <= 0)
+    if (data == NULL)
        return 0;
 
     /* make sure entry points to the first occurence of this tag */
@@ -1851,7 +1666,7 @@ int headerMod(Header h, rpmtd td)
     if (ENTRY_IN_REGION(entry)) {
        entry->info.offset = 0;
     } else
-       oldData = _free(oldData);
+       free(oldData);
 
     return 1;
 }
@@ -1870,7 +1685,7 @@ HeaderIterator headerFreeIterator(HeaderIterator hi)
        hi->h = headerFree(hi->h);
        hi = _free(hi);
     }
-    return hi;
+    return NULL;
 }
 
 HeaderIterator headerInitIterator(Header h)
@@ -1884,15 +1699,11 @@ HeaderIterator headerInitIterator(Header h)
     return hi;
 }
 
-int headerNext(HeaderIterator hi, rpmtd td)
+static indexEntry nextIndex(HeaderIterator hi)
 {
     Header h = hi->h;
-    int slot = hi->next_index;
+    int slot;
     indexEntry entry = NULL;
-    int rc;
-
-    assert(td != NULL);
-    rpmtdReset(td);
 
     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
        entry = h->index + slot;
@@ -1901,59 +1712,29 @@ int headerNext(HeaderIterator hi, rpmtd td)
     }
     hi->next_index = slot;
     if (entry == NULL || slot >= h->indexUsed)
-       return 0;
+       return NULL;
 
-       /* LCL: no clue */
     hi->next_index++;
-
-    td->tag = entry->info.tag;
-
-    rc = copyTdEntry(entry, td, HEADERGET_DEFAULT);
-
-    /* XXX 1 on success */
-    return ((rc == 1) ? 1 : 0);
+    return entry;
 }
 
-/** \ingroup header
- * Duplicate a header.
- * @param h            header
- * @return             new header instance
- */
-Header headerCopy(Header h)
+rpmTagVal headerNextTag(HeaderIterator hi)
 {
-    Header nh = headerNew();
-    HeaderIterator hi;
-    struct rpmtd_s td;
-   
-    hi = headerInitIterator(h);
-    while (headerNext(hi, &td)) {
-       if (rpmtdCount(&td) > 0) {
-           (void) headerPut(nh, &td, HEADERPUT_DEFAULT);
-       }
-       rpmtdFreeData(&td);
-    }
-    hi = headerFreeIterator(hi);
-
-    return headerReload(nh, HEADER_IMAGE);
+    indexEntry entry = nextIndex(hi);
+    return entry ? entry->info.tag : RPMTAG_NOT_FOUND;
 }
 
-void headerCopyTags(Header headerFrom, Header headerTo, 
-                   const rpmTag * tagstocopy)
+int headerNext(HeaderIterator hi, rpmtd td)
 {
-    const rpmTag * p;
-    struct rpmtd_s td;
+    indexEntry entry = nextIndex(hi);
+    int rc = 0;
 
-    if (headerFrom == headerTo)
-       return;
-
-    for (p = tagstocopy; *p != 0; p++) {
-       if (headerIsEntry(headerTo, *p))
-           continue;
-       if (!headerGet(headerFrom, *p, &td, HEADERGET_MINMEM))
-           continue;
-       (void) headerPut(headerTo, &td, HEADERPUT_DEFAULT);
-       rpmtdFreeData(&td);
+    rpmtdReset(td);
+    if (entry) {
+       td->tag = entry->info.tag;
+       rc = copyTdEntry(entry, td, HEADERGET_DEFAULT);
     }
+    return ((rc == 1) ? 1 : 0);
 }
 
 unsigned int headerGetInstance(Header h)
@@ -1965,3 +1746,30 @@ void headerSetInstance(Header h, unsigned int instance)
 {
     h->instance = instance;
 }    
+
+#define RETRY_ERROR(_err) \
+    ((_err) == EINTR || (_err) == EAGAIN || (_err) == EWOULDBLOCK)
+
+ssize_t Freadall(FD_t fd, void * buf, ssize_t size)
+{
+    ssize_t total = 0;
+    ssize_t nb = 0;
+    char * bufp = buf;
+
+    while (total < size) {
+       nb = Fread(bufp, 1, size - total, fd);
+
+       if (nb == 0 || (nb < 0 && !RETRY_ERROR(errno))) {
+           total = nb;
+           break;
+       }
+
+       if (nb > 0) {
+           bufp += nb;
+           total += nb;
+       }
+    }
+
+    return total;
+}
+