/** \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) { 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; memset(block, 0, sizeof(block)); i = 2; if (magicp == HEADER_MAGIC_YES) i += 2; /* FIX: cast? */ if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block))) goto exit; i = 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[i]); i++; dl = ntohl(block[i]); i++; len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl; /* Sanity checks on header intro. */ if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes) goto exit; 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) goto exit; h = headerLoad(ei); exit: if (h == NULL && ei != NULL) { free(ei); } return h; }
Header headerRead(FD_t fd, int magicp) { int32_t block[4]; int32_t * ei = NULL; int32_t il; int32_t dl; Header h = NULL; unsigned int len, blen; if (magicp == HEADER_MAGIC_YES) { int32_t magic; if (Freadall(fd, block, 4*sizeof(*block)) != 4*sizeof(*block)) goto exit; magic = block[0]; if (memcmp(&magic, rpm_header_magic, sizeof(magic))) goto exit; 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]); } 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) goto exit; ei = xmalloc(len); ei[0] = htonl(il); ei[1] = htonl(dl); if (Freadall(fd, (char *)&ei[2], blen) != blen) goto exit; h = headerImport(ei, len, 0); exit: if (h == NULL && ei != NULL) { free(ei); } return h; }
Header headerCopyLoad(const 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; /* 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 headerImport(void * blob, unsigned int bsize, headerImportFlags flags) { const int32_t * ei = (int32_t *) blob; int32_t il = ntohl(ei[0]); /* index length */ int32_t dl = ntohl(ei[1]); /* data length */ 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 (bsize && bsize != pvlen) goto errxit; if (hdrchkTags(il) || hdrchkData(dl) || pvlen >= headerMaxbytes) goto errxit; 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; entry = h->index; if (!(htonl(pe->tag) < RPMTAG_HEADERI18NTABLE)) { h->flags |= HEADERFLAG_LEGACY; entry->info.type = REGION_TAG_TYPE; 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, fast); if (rdlen != dl) goto errxit; entry->rdlen = rdlen; h->indexUsed++; } else { int32_t rdl; int32_t ril; h->flags &= ~HEADERFLAG_LEGACY; entry->info.type = htonl(pe->type); entry->info.count = htonl(pe->count); entry->info.tag = htonl(pe->tag); if (!ENTRY_IS_REGION(entry)) goto errxit; if (entry->info.type != REGION_TAG_TYPE) goto errxit; if (entry->info.count != REGION_TAG_COUNT) goto errxit; { int off = ntohl(pe->offset); 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; } else { ril = il; rdl = (ril * sizeof(struct entryInfo_s)); 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, fast); if (rdlen < 0) goto errxit; entry->rdlen = rdlen; if (ril < h->indexUsed) { indexEntry newEntry = entry + ril; int ne = (h->indexUsed - ril); int rid = entry->info.offset+1; /* Load dribble entries from region. */ rdlen = regionSwab(newEntry, ne, rdlen, pe+ril, dataStart, dataEnd, rid, fast); if (rdlen < 0) goto errxit; { indexEntry firstEntry = newEntry; int save = h->indexUsed; int j; /* Dribble entries replace duplicate region entries. */ h->indexUsed -= ne; for (j = 0; j < ne; j++, newEntry++) { (void) headerDel(h, newEntry->info.tag); if (newEntry->info.tag == RPMTAG_BASENAMES) (void) headerDel(h, RPMTAG_OLDFILENAMES); } /* If any duplicate entries were replaced, move new entries down. */ if (h->indexUsed < (save - ne)) { memmove(h->index + h->indexUsed, firstEntry, (ne * sizeof(*entry))); } h->indexUsed += ne; } } rdlen += REGION_TAG_COUNT; if (rdlen != dl) goto errxit; } /* Force sorting, dribble lookups can cause early sort on partial header */ h->sorted = HEADERSORT_NONE; headerSort(h); h->flags |= HEADERFLAG_ALLOCATED; return h; errxit: if (h) { if (flags & HEADERIMPORT_COPY) free(h->blob); free(h->index); free(h); } return NULL; }
void * headerExport(Header h, unsigned int *bsize) { int32_t * ei = NULL; entryInfo pe; char * dataStart; char * te; unsigned len, diff; int32_t il = 0; int32_t dl = 0; indexEntry entry; int i; int drlen, ndribbles; if (h == NULL) return NULL; /* Sort entries by (offset,tag). */ headerUnsort(h); /* Compute (il,dl) for all tags, including those deleted in region. */ 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 */ int32_t ril = rdl/sizeof(*pe); int rid = entry->info.offset; il += ril; dl += entry->rdlen + entry->info.count; /* XXX Legacy regions do not include the region tag and data. */ if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) il += 1; /* Skip rest of entries in region, but account for dribbles. */ for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) { if (entry->info.offset <= rid) continue; /* Alignment */ diff = alignDiff(entry->info.type, dl); if (diff) { drlen += diff; dl += diff; } ndribbles++; il++; drlen += entry->length; dl += entry->length; } i--; entry--; continue; } /* Ignore deleted drips. */ if (entry->data == NULL || entry->length <= 0) continue; /* Alignment */ dl += alignDiff(entry->info.type, dl); il++; dl += entry->length; } /* Sanity checks on header intro. */ if (hdrchkTags(il) || hdrchkData(dl)) goto errxit; len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl; ei = xmalloc(len); ei[0] = htonl(il); ei[1] = htonl(dl); pe = (entryInfo) &ei[2]; dataStart = te = (char *) (pe + il); 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; t = (unsigned char*)te; pe->tag = htonl(entry->info.tag); pe->type = htonl(entry->info.type); pe->count = htonl(entry->info.count); if (ENTRY_IS_REGION(entry)) { int32_t rdl = -entry->info.offset; /* negative offset */ int32_t ril = rdl/sizeof(*pe) + ndribbles; int rid = entry->info.offset; src = (char *)entry->data; rdlen = entry->rdlen; /* XXX Legacy regions do not include the region tag and data. */ if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) { int32_t stei[4]; memcpy(pe+1, src, rdl); memcpy(te, src + rdl, rdlen); te += rdlen; pe->offset = htonl(te - dataStart); stei[0] = pe->tag; stei[1] = pe->type; stei[2] = htonl(-rdl-entry->info.count); stei[3] = pe->count; memcpy(te, stei, entry->info.count); te += entry->info.count; ril++; rdlen += entry->info.count; count = regionSwab(NULL, ril, 0, pe, t, NULL, 0, 0); if (count != rdlen) goto errxit; } else { memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe))); memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen); te += rdlen; { entryInfo se = (entryInfo)src; int off = ntohl(se->offset); pe->offset = (off) ? htonl(te - dataStart) : htonl(off); } te += entry->info.count + drlen; count = regionSwab(NULL, ril, 0, pe, t, NULL, 0, 0); if (count != (rdlen + entry->info.count + drlen)) goto errxit; } /* Skip rest of entries in region. */ while (i < h->indexUsed && entry->info.offset <= rid+1) { i++; entry++; } i--; entry--; pe += ril; continue; } /* Ignore deleted drips. */ if (entry->data == NULL || entry->length <= 0) continue; /* Alignment */ diff = alignDiff(entry->info.type, (te - dataStart)); if (diff) { memset(te, 0, diff); te += diff; } pe->offset = htonl(te - dataStart); /* copy data w/ endian conversions */ switch (entry->info.type) { case RPM_INT64_TYPE: count = entry->info.count; src = entry->data; while (count--) { *((uint64_t *)te) = htonll(*((uint64_t *)src)); te += sizeof(uint64_t); src += sizeof(uint64_t); } break; case RPM_INT32_TYPE: count = entry->info.count; src = entry->data; while (count--) { *((int32_t *)te) = htonl(*((int32_t *)src)); te += sizeof(int32_t); src += sizeof(int32_t); } break; case RPM_INT16_TYPE: count = entry->info.count; src = entry->data; while (count--) { *((int16_t *)te) = htons(*((int16_t *)src)); te += sizeof(int16_t); src += sizeof(int16_t); } break; default: memcpy(te, entry->data, entry->length); te += entry->length; break; } pe++; } /* Insure that there are no memcpy underruns/overruns. */ if (((char *)pe) != dataStart) goto errxit; if ((((char *)ei)+len) != te) goto errxit; if (bsize) *bsize = len; headerSort(h); return (void *) ei; errxit: free(ei); return NULL; }
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 * pv = uh; Header h = NULL; entryInfo pe; unsigned char * dataStart; unsigned char * dataEnd; indexEntry entry; int rdlen; /* Sanity checks on header intro. */ if (hdrchkTags(il) || hdrchkData(dl)) goto errxit; ei = (int32_t *) pv; 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)) { h->flags |= HEADERFLAG_LEGACY; entry->info.type = REGION_TAG_TYPE; entry->info.tag = HEADER_IMAGE; 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); if (rdlen != dl) goto errxit; entry->rdlen = rdlen; h->indexUsed++; } else { int32_t rdl; int32_t ril; h->flags &= ~HEADERFLAG_LEGACY; entry->info.type = htonl(pe->type); entry->info.count = htonl(pe->count); if (hdrchkType(entry->info.type)) goto errxit; if (hdrchkTags(entry->info.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]; /* 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.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); if (rdlen < 0) goto errxit; entry->rdlen = rdlen; if (ril < h->indexUsed) { indexEntry newEntry = entry + ril; int ne = (h->indexUsed - ril); int rid = entry->info.offset+1; int rc; /* Load dribble entries from region. */ rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid); if (rc < 0) goto errxit; rdlen += rc; { indexEntry firstEntry = newEntry; int save = h->indexUsed; int j; /* Dribble entries replace duplicate region entries. */ h->indexUsed -= ne; for (j = 0; j < ne; j++, newEntry++) { (void) headerDel(h, newEntry->info.tag); if (newEntry->info.tag == RPMTAG_BASENAMES) (void) headerDel(h, RPMTAG_OLDFILENAMES); } /* If any duplicate entries were replaced, move new entries down. */ if (h->indexUsed < (save - ne)) { memmove(h->index + h->indexUsed, firstEntry, (ne * sizeof(*entry))); } h->indexUsed += ne; } } } h->flags &= ~HEADERFLAG_SORTED; headerSort(h); h->flags |= HEADERFLAG_ALLOCATED; return h; errxit: if (h) { h->index = _free(h->index); h = _free(h); } return h; }
static rpmRC rpmpkgReadHeader(rpmKeyring keyring, rpmVSFlags vsflags, FD_t fd, Header *hdrp, char ** msg) { char *buf = NULL; int32_t block[4]; int32_t il; int32_t dl; int32_t * ei = NULL; size_t uc; size_t nb; Header h = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ int xx; if (hdrp) *hdrp = NULL; if (msg) *msg = NULL; memset(block, 0, sizeof(block)); if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) { rasprintf(&buf, _("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx); goto exit; } if (memcmp(block, rpm_header_magic, sizeof(rpm_header_magic))) { rasprintf(&buf, _("hdr magic: BAD\n")); goto exit; } il = ntohl(block[2]); if (hdrchkTags(il)) { rasprintf(&buf, _("hdr tags: BAD, no. of tags(%d) out of range\n"), il); goto exit; } dl = ntohl(block[3]); if (hdrchkData(dl)) { rasprintf(&buf, _("hdr data: BAD, no. of bytes(%d) out of range\n"), dl); goto exit; } nb = (il * sizeof(struct entryInfo_s)) + dl; uc = sizeof(il) + sizeof(dl) + nb; ei = xmalloc(uc); ei[0] = block[2]; ei[1] = block[3]; if ((xx = timedRead(fd, (char *)&ei[2], nb)) != nb) { rasprintf(&buf, _("hdr blob(%zd): BAD, read returned %d\n"), nb, xx); goto exit; } /* Sanity check header tags */ rc = headerVerify(keyring, vsflags, ei, uc, msg); if (rc != RPMRC_OK) goto exit; /* OK, blob looks sane, load the header. */ h = headerLoad(ei); if (h == NULL) { rasprintf(&buf, _("hdr load: BAD\n")); rc = RPMRC_FAIL; goto exit; } ei = NULL; /* XXX will be freed with header */ exit: if (hdrp && h && rc == RPMRC_OK) *hdrp = headerLink(h); ei = _free(ei); h = headerFree(h); if (msg != NULL && *msg == NULL && buf != NULL) { *msg = buf; } else { free(buf); } return rc; }