Modify eu-strip option to perform strip in post script of rpm package & add option...
[platform/upstream/rpm.git] / lib / header.c
index e1c5f2c..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
@@ -154,11 +156,11 @@ Header headerFree(Header h)
     return NULL;
 }
 
-static Header headerCreate(void *blob, int32_t indexLen)
+static Header headerCreate(void *blob, unsigned int pvlen, int32_t indexLen)
 {
     Header h = xcalloc(1, sizeof(*h));
-    h->blob = blob;
     if (blob) {
+       h->blob = (pvlen > 0) ? memcpy(xmalloc(pvlen), blob, pvlen) : blob;
        h->indexAlloced = indexLen + 1;
        h->indexUsed = indexLen;
     } else {
@@ -178,7 +180,7 @@ static Header headerCreate(void *blob, int32_t indexLen)
 
 Header headerNew(void)
 {
-    return headerCreate(NULL, 0);
+    return headerCreate(NULL, 0, 0);
 }
 
 int headerVerifyInfo(int il, int dl, const void * pev, void * iv, int negate)
@@ -199,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;
@@ -245,6 +247,18 @@ void headerUnsort(Header h)
     }
 }
 
+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, int magicp)
 {
     indexEntry entry;
@@ -267,8 +281,6 @@ unsigned headerSizeof(Header h, int magicp)
     size += 2 * sizeof(int32_t);       /* count of index entries */
 
     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
-       rpm_tagtype_t type;
-
        /* Regions go in as is ... */
         if (ENTRY_IS_REGION(entry)) {
            size += entry->length;
@@ -283,13 +295,7 @@ unsigned headerSizeof(Header h, int 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;
     }
@@ -297,6 +303,31 @@ unsigned headerSizeof(Header h, int 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
@@ -309,20 +340,15 @@ unsigned headerSizeof(Header h, int magicp)
 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:
@@ -331,14 +357,7 @@ static int dataLength(rpm_tagtype_t 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--) {
@@ -373,17 +392,20 @@ static int dataLength(rpm_tagtype_t 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;
-       rpm_tagtype_t type;
 
        ie.info.tag = ntohl(pe->tag);
        ie.info.type = ntohl(pe->type);
@@ -403,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;
 
@@ -416,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)) {
@@ -458,23 +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; 
-    rpm_tagtype_t type;
     int i;
     int drlen, ndribbles;
 
@@ -503,13 +517,10 @@ static void * doHeaderUnload(Header h, size_t * lengthPtr)
                    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++;
@@ -527,13 +538,7 @@ static void * doHeaderUnload(Header h, size_t * lengthPtr)
            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;
@@ -557,6 +562,7 @@ static void * doHeaderUnload(Header h, size_t * lengthPtr)
        unsigned char *t;
        int count;
        int rdlen;
+       unsigned int diff;
 
        if (entry->data == NULL || entry->length <= 0)
            continue;
@@ -592,7 +598,7 @@ static void * doHeaderUnload(Header h, size_t * lengthPtr)
                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;
 
@@ -608,7 +614,7 @@ static void * doHeaderUnload(Header h, size_t * lengthPtr)
                }
                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;
            }
@@ -629,14 +635,10 @@ static void * doHeaderUnload(Header h, size_t * lengthPtr)
            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);
@@ -687,21 +689,21 @@ static void * doHeaderUnload(Header h, size_t * lengthPtr)
     if ((((char *)ei)+len) != te)
        goto errxit;
 
-    if (lengthPtr)
-       *lengthPtr = len;
+    if (bsize)
+       *bsize = len;
 
     headerSort(h);
 
     return (void *) ei;
 
 errxit:
-    ei = _free(ei);
+    free(ei);
     return NULL;
 }
 
 void * headerUnload(Header h)
 {
-    return doHeaderUnload(h, NULL);
+    return headerExport(h, NULL);
 }
 
 /**
@@ -762,7 +764,7 @@ int headerDel(Header h, rpmTagVal tag)
        first->length = 0;
        if (ENTRY_IN_REGION(first))
            continue;
-       data = _free(data);
+       free(data);
     }
 
     ne = (first - entry);
@@ -776,32 +778,34 @@ int headerDel(Header h, rpmTagVal 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;
 
-    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 = headerCreate(uh, il);
-
     entry = h->index;
     if (!(htonl(pe->tag) < RPMTAG_HEADERI18NTABLE)) {
        h->flags |= HEADERFLAG_LEGACY;
@@ -812,7 +816,8 @@ Header headerLoad(void * uh)
 
        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;
@@ -825,26 +830,28 @@ 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));
@@ -855,7 +862,8 @@ Header headerLoad(void * uh)
 
        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;
@@ -864,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;
@@ -892,6 +899,11 @@ Header headerLoad(void * uh)
            h->indexUsed += ne;
          }
        }
+
+       rdlen += REGION_TAG_COUNT;
+
+       if (rdlen != dl)
+           goto errxit;
     }
 
     h->flags &= ~HEADERFLAG_SORTED;
@@ -902,8 +914,10 @@ 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 NULL;
 }
@@ -911,12 +925,13 @@ errxit:
 Header headerReload(Header h, rpmTagVal tag)
 {
     Header nh;
-    void * uh = doHeaderUnload(h, NULL);
+    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;
@@ -928,23 +943,15 @@ Header headerReload(Header h, rpmTagVal 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);
 }
 
 Header headerRead(FD_t fd, int magicp)
@@ -954,12 +961,12 @@ Header headerRead(FD_t fd, int magicp)
     int32_t il;
     int32_t dl;
     Header h = NULL;
-    size_t len;
+    unsigned int len, blen;
 
     if (magicp == HEADER_MAGIC_YES) {
        int32_t magic;
 
-       if (Fread(block, 1, 4*sizeof(*block), fd) != 4*sizeof(*block))
+       if (Freadall(fd, block, 4*sizeof(*block)) != 4*sizeof(*block))
            goto exit;
 
        magic = block[0];
@@ -970,14 +977,15 @@ Header headerRead(FD_t fd, int magicp)
        il = ntohl(block[2]);
        dl = ntohl(block[3]);
     } else {
-       if (Fread(block, 1, 2*sizeof(*block), fd) != 2*sizeof(*block))
+       if (Freadall(fd, block, 2*sizeof(*block)) != 2*sizeof(*block))
            goto exit;
 
        il = ntohl(block[0]);
        dl = ntohl(block[1]);
     }
 
-    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)
@@ -986,12 +994,11 @@ Header headerRead(FD_t fd, int magicp)
     ei = xmalloc(len);
     ei[0] = htonl(il);
     ei[1] = htonl(dl);
-    len -= sizeof(il) + sizeof(dl);
 
-    if (Fread((char *)&ei[2], 1, len, fd) != 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) {
@@ -1003,10 +1010,10 @@ exit:
 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) {
@@ -1022,7 +1029,7 @@ int headerWrite(FD_t fd, Header h, int magicp)
     nb = Fwrite(uh, sizeof(char), length, fd);
 
 exit:
-    uh = _free(uh);
+    free(uh);
     return (nb == length ? 0 : 1);
 }
 
@@ -1092,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);
@@ -1317,6 +1324,9 @@ 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);
 }
@@ -1397,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)
@@ -1408,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 */
@@ -1630,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 */
@@ -1658,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;
 }
@@ -1739,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;
+}
+