Modify eu-strip option to perform strip in post script of rpm package & add option...
[platform/upstream/rpm.git] / lib / header.c
index f4578de..90079f3 100644 (file)
 
 #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"
 
 /** \ingroup header
@@ -66,12 +69,14 @@ static const int typeSizes[16] =  {
     0
 };
 
-typedef enum headerFlags_e {
+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? */
-} headerFlags;
+};
+
+typedef rpmFlags headerFlags;
 
 /** \ingroup header
  * The Header data structure.
@@ -94,24 +99,13 @@ static const size_t headerMaxbytes = (32*1024*1024);
 #define        INDEX_MALLOC_SIZE       8
 
 #define        ENTRY_IS_REGION(_e) \
-       (((_e)->info.tag >= HEADER_IMAGE) && ((_e)->info.tag < HEADER_REGIONS))
+       (((_e)->info.tag >= RPMTAG_HEADERIMAGE) && ((_e)->info.tag < RPMTAG_HEADERREGIONS))
 #define        ENTRY_IN_REGION(_e)     ((_e)->info.offset < 0)
 
-/** \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
- * @param flags                modifier flags
- * @return             0 on success
- */
-typedef int (*headerTagTagFunction) (Header h, rpmtd td, headerGetFlags hgflags);
-
-extern void *rpmHeaderTagFunc(rpmTag tag);
-
 /* Convert a 64bit value to network byte order. */
-static uint64_t htonll( uint64_t n ) {
+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]);
@@ -126,7 +120,7 @@ Header headerLink(Header h)
     return h;
 }
 
-Header headerUnlink(Header h)
+static Header headerUnlink(Header h)
 {
     if (h != NULL)
        h->nrefs--;
@@ -138,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;
@@ -159,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;
 
@@ -180,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;
@@ -198,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;
@@ -207,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;
@@ -223,8 +224,6 @@ void headerSort(Header h)
     }
 }
 
-/**
- */
 static int offsetCmp(const void * avp, const void * bvp) 
 {
     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
@@ -240,16 +239,27 @@ 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;
@@ -271,8 +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++) {
-       rpmTagType type;
-
        /* Regions go in as is ... */
         if (ENTRY_IS_REGION(entry)) {
            size += entry->length;
@@ -287,13 +295,7 @@ unsigned headerSizeof(Header h, enum hMagic magicp)
            continue;
 
        /* Alignment */
-       type = entry->info.type;
-       if (typeSizes[type] > 1) {
-           unsigned diff = typeSizes[type] - (size % typeSizes[type]);
-           if (diff != typeSizes[type]) {
-               size += diff;
-           }
-       }
+       size += alignDiff(entry->info.type, size);
 
        size += sizeof(struct entryInfo_s) + entry->length;
     }
@@ -301,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
@@ -310,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:
@@ -335,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--) {
@@ -377,17 +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)
 {
+    if ((entry != NULL && regionid >= 0) || (entry == NULL && regionid != 0))
+       return -1;
+
     for (; il > 0; il--, pe++) {
        struct indexEntry_s ie;
-       rpmTagType type;
 
        ie.info.tag = ntohl(pe->tag);
        ie.info.type = ntohl(pe->type);
@@ -407,7 +425,12 @@ static int regionSwab(indexEntry entry, int il, int dl,
        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;
 
@@ -420,13 +443,7 @@ static int regionSwab(indexEntry entry, int il, int dl,
        }
 
        /* Alignment */
-       type = ie.info.type;
-       if (typeSizes[type] > 1) {
-           unsigned diff = typeSizes[type] - (dl % typeSizes[type]);
-           if (diff != typeSizes[type]) {
-               dl += diff;
-           }
-       }
+       dl += alignDiff(ie.info.type, dl);
 
        /* Perform endian conversions */
        switch (ntohl(pe->type)) {
@@ -462,24 +479,16 @@ static int regionSwab(indexEntry entry, int il, int dl,
     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 len;
+    unsigned len, diff;
     int32_t il = 0;
     int32_t dl = 0;
     indexEntry entry; 
-    rpmTagType type;
     int i;
     int drlen, ndribbles;
 
@@ -508,13 +517,10 @@ static void * doHeaderUnload(Header h,
                    continue;
 
                /* Alignment */
-               type = entry->info.type;
-               if (typeSizes[type] > 1) {
-                   unsigned diff = typeSizes[type] - (dl % typeSizes[type]);
-                   if (diff != typeSizes[type]) {
-                       drlen += diff;
-                       dl += diff;
-                   }
+               diff = alignDiff(entry->info.type, dl);
+               if (diff) {
+                   drlen += diff;
+                   dl += diff;    
                }
 
                ndribbles++;
@@ -532,13 +538,7 @@ static void * doHeaderUnload(Header h,
            continue;
 
        /* Alignment */
-       type = entry->info.type;
-       if (typeSizes[type] > 1) {
-           unsigned diff = typeSizes[type] - (dl % typeSizes[type]);
-           if (diff != typeSizes[type]) {
-               dl += diff;
-           }
-       }
+       dl += alignDiff(entry->info.type, dl);
 
        il++;
        dl += entry->length;
@@ -562,6 +562,7 @@ static void * doHeaderUnload(Header h,
        unsigned char *t;
        int count;
        int rdlen;
+       unsigned int diff;
 
        if (entry->data == NULL || entry->length <= 0)
            continue;
@@ -597,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;
 
@@ -613,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;
            }
@@ -634,14 +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;
-           }
+       diff = alignDiff(entry->info.type, (te - dataStart));
+       if (diff) {
+           memset(te, 0, diff);
+           te += diff;
        }
 
        pe->offset = htonl(te - dataStart);
@@ -692,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);
 }
 
 /**
@@ -720,7 +714,7 @@ 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;
     struct indexEntry_s key;
@@ -747,7 +741,7 @@ indexEntry findEntry(Header h, rpmTag tag, rpmTagType type)
     return NULL;
 }
 
-int headerDel(Header h, rpmTag tag)
+int headerDel(Header h, rpmTagVal tag)
 {
     indexEntry last = h->index + h->indexUsed;
     indexEntry entry, first;
@@ -770,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);
@@ -784,51 +778,46 @@ 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 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;
+
+    h = headerCreate(blob, (flags & HEADERIMPORT_COPY) ? pvlen : 0, il);
 
-    ei = (int32_t *) pv;
+    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;
-    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;
@@ -841,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 (entry->info.type != REGION_TAG_TYPE)
            goto errxit;
-       if (hdrchkTags(entry->info.count))
+       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;
@@ -880,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;
@@ -908,6 +899,11 @@ Header headerLoad(void * uh)
            h->indexUsed += ne;
          }
        }
+
+       rdlen += REGION_TAG_COUNT;
+
+       if (rdlen != dl)
+           goto errxit;
     }
 
     h->flags &= ~HEADERFLAG_SORTED;
@@ -918,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)
@@ -1012,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) {
@@ -1027,13 +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;
 
-    uh = doHeaderUnload(h, &length);
+    uh = headerExport(h, &length);
     if (uh == NULL)
        return 1;
     switch (magicp) {
@@ -1049,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);
@@ -1102,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 {
@@ -1119,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);
@@ -1268,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) {
@@ -1344,11 +1324,14 @@ static int intGetTdEntry(Header h, rpmtd td, headerGetFlags flags)
        }
     }
 
+    if (rc == 0)
+       td->flags |= RPMTD_INVALID;
+
     /* XXX 1 on success */
     return ((rc == 1) ? 1 : 0);
 }
 
-int headerGet(Header h, rpmTag tag, rpmtd td, headerGetFlags flags)
+int headerGet(Header h, rpmTagVal tag, rpmtd td, headerGetFlags flags)
 {
     int rc;
     headerTagTagFunction tagfunc = intGetTdEntry;
@@ -1370,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) {
@@ -1404,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;
@@ -1424,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)
@@ -1435,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 */
@@ -1514,7 +1496,7 @@ int headerPut(Header h, rpmtd td, headerPutFlags flags)
     return rc;
 }
 
-int headerAddI18NString(Header h, rpmTag tag, const char * string,
+int headerAddI18NString(Header h, rpmTagVal tag, const char * string,
                const char * lang)
 {
     indexEntry table, entry;
@@ -1524,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)
@@ -1542,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)
@@ -1657,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 */
@@ -1685,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;
 }
@@ -1704,7 +1685,7 @@ HeaderIterator headerFreeIterator(HeaderIterator hi)
        hi->h = headerFree(hi->h);
        hi = _free(hi);
     }
-    return hi;
+    return NULL;
 }
 
 HeaderIterator headerInitIterator(Header h)
@@ -1737,7 +1718,7 @@ static indexEntry nextIndex(HeaderIterator hi)
     return entry;
 }
 
-rpmTag headerNextTag(HeaderIterator hi)
+rpmTagVal headerNextTag(HeaderIterator hi)
 {
     indexEntry entry = nextIndex(hi);
     return entry ? entry->info.tag : RPMTAG_NOT_FOUND;
@@ -1766,3 +1747,29 @@ 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;
+}
+