/* 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] = {
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;
}
(void) headerUnlink(h);
if (h == NULL || h->nrefs > 0)
- return NULL; /* XXX return previous header? */
+ return NULL;
if (h->index) {
indexEntry entry = h->index;
}
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;
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;
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;
return -1;
}
-/**
- */
static int indexCmp(const void * avp, const void * bvp)
{
indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
}
}
-/**
- */
static int offsetCmp(const void * avp, const void * bvp)
{
indexEntry ap = (indexEntry) avp, bp = (indexEntry) 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)
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;
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;
}
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
* @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:
/* 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--) {
/** \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
* @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);
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;
}
/* 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 */
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++;
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;
}
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;
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;
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;
}
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;
}
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);
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);
}
/**
* @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;
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;
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;
first->length = 0;
if (ENTRY_IN_REGION(first))
continue;
- data = _free(data);
+ free(data);
}
ne = (first - entry);
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;
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;
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;
h->indexUsed += ne;
}
}
+
+ rdlen += REGION_TAG_COUNT;
+
+ if (rdlen != dl)
+ goto errxit;
}
h->flags &= ~HEADERFLAG_SORTED;
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)
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) {
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) {
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);
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 {
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);
}
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;
}
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;
(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) {
/**
* 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;
}
}
+ 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;
/**
*/
-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) {
* @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;
{
indexEntry entry;
rpm_data_t data;
- int length;
+ int length = 0;
/* Count must always be >= 1 for headerAddEntry. */
if (td->count <= 0)
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 */
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;
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)
}
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)
{ 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;
}
}
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 */
if (ENTRY_IN_REGION(entry)) {
entry->info.offset = 0;
} else
- oldData = _free(oldData);
+ free(oldData);
return 1;
}
hi->h = headerFree(hi->h);
hi = _free(hi);
}
- return hi;
+ return NULL;
}
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;
}
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)
{
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;
+}
+