Header headerFree(Header h) { (void) headerUnlink(h); if (h == NULL || h->nrefs > 0) return NULL; if (h->index) { indexEntry entry = h->index; int i; for (i = 0; i < h->indexUsed; i++, entry++) { if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) { if (entry->length > 0) { int32_t * ei = entry->data; if ((ei - 2) == h->blob) h->blob = _free(h->blob); entry->data = NULL; } } else if (!ENTRY_IN_REGION(entry)) { entry->data = _free(entry->data); } entry->data = NULL; } h->index = _free(h->index); } h = _free(h); return NULL; }
unsigned headerSizeof(Header h, enum hMagic magicp) { indexEntry entry; unsigned int size = 0; int i; if (h == NULL) return size; headerSort(h); switch (magicp) { case HEADER_MAGIC_YES: size += sizeof(rpm_header_magic); break; case HEADER_MAGIC_NO: break; } 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; /* XXX Legacy regions do not include the region tag and data. */ if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) size += sizeof(struct entryInfo_s) + entry->info.count; continue; } /* ... and region elements are skipped. */ if (entry->info.offset < 0) continue; /* Alignment */ type = entry->info.type; if (typeSizes[type] > 1) { unsigned diff = typeSizes[type] - (size % typeSizes[type]); if (diff != typeSizes[type]) { size += diff; } } size += sizeof(struct entryInfo_s) + entry->length; } return size; }
static indexEntry nextIndex(HeaderIterator hi) { Header h = hi->h; int slot; indexEntry entry = NULL; for (slot = hi->next_index; slot < h->indexUsed; slot++) { entry = h->index + slot; if (!ENTRY_IS_REGION(entry)) break; } hi->next_index = slot; if (entry == NULL || slot >= h->indexUsed) return NULL; hi->next_index++; return entry; }
Header headerReload(Header h, rpmTagVal tag) { Header nh; unsigned int uc = 0; void * uh = headerExport(h, &uc); h = headerFree(h); if (uh == NULL) return NULL; nh = headerImport(uh, uc, 0); if (nh == NULL) { uh = _free(uh); return NULL; } if (ENTRY_IS_REGION(nh->index)) { if (tag == RPMTAG_HEADERSIGNATURES || tag == RPMTAG_HEADERIMMUTABLE) nh->index[0].info.tag = tag; } return nh; }
Header headerReload(Header h, rpmTag tag) { Header nh; size_t length; void * uh = doHeaderUnload(h, &length); h = headerFree(h); if (uh == NULL) return NULL; nh = headerLoad(uh); if (nh == NULL) { uh = _free(uh); return NULL; } if (ENTRY_IS_REGION(nh->index)) { if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE) nh->index[0].info.tag = tag; } return nh; }
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; }
/** \ingroup header * Retrieve data from header entry. * Relevant flags (others are ignored), if neither is set allocation * behavior depends on data type(!) * HEADERGET_MINMEM: return pointers to header memory * HEADERGET_ALLOC: always return malloced memory, overrides MINMEM * * @todo Permit retrieval of regions other than HEADER_IMUTABLE. * @param entry header entry * @param td tag data container * @param minMem string pointers refer to header memory? * @param flags flags to control memory allocation * @return 1 on success, otherwise error. */ static int copyTdEntry(const indexEntry entry, rpmtd td, headerGetFlags flags) { rpm_count_t count = entry->info.count; int rc = 1; /* XXX 1 on success. */ /* ALLOC overrides MINMEM */ int allocMem = flags & HEADERGET_ALLOC; int minMem = allocMem ? 0 : flags & HEADERGET_MINMEM; int argvArray = (flags & HEADERGET_ARGV) ? 1 : 0; assert(td != NULL); td->flags = RPMTD_IMMUTABLE; switch (entry->info.type) { case RPM_BIN_TYPE: /* * XXX This only works for * XXX "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE. * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e. * XXX a legacy header freshly read, but not yet unloaded to the rpmdb). */ if (ENTRY_IS_REGION(entry)) { int32_t * ei = ((int32_t *)entry->data) - 2; entryInfo pe = (entryInfo) (ei + 2); unsigned char * dataStart = (unsigned char *) (pe + ntohl(ei[0])); int32_t rdl = -entry->info.offset; /* negative offset */ int32_t ril = rdl/sizeof(*pe); rdl = entry->rdlen; count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl; if (entry->info.tag == RPMTAG_HEADERIMAGE) { ril -= 1; pe += 1; } else { count += REGION_TAG_COUNT; rdl += REGION_TAG_COUNT; } td->data = xmalloc(count); ei = (int32_t *) td->data; ei[0] = htonl(ril); ei[1] = htonl(rdl); pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe))); dataStart = (unsigned char *) memcpy(pe + ril, dataStart, rdl); 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); } /* XXX 1 on success. */ rc = (rc < 0) ? 0 : 1; } else { count = entry->length; td->data = (!minMem ? memcpy(xmalloc(count), entry->data, count) : entry->data); } break; case RPM_STRING_TYPE: /* simple string, but fallthrough if its actually an array */ if (count == 1 && !argvArray) { td->data = allocMem ? xstrdup(entry->data) : entry->data; break; } case RPM_STRING_ARRAY_TYPE: case RPM_I18NSTRING_TYPE: { const char ** ptrEntry; int tableSize = (count + argvArray) * sizeof(char *); char * t; int i; if (minMem) { td->data = xmalloc(tableSize); ptrEntry = (const char **) td->data; t = entry->data; } else { t = xmalloc(tableSize + entry->length); td->data = (void *)t; ptrEntry = (const char **) td->data; t += tableSize; memcpy(t, entry->data, entry->length); } for (i = 0; i < count; i++) { *ptrEntry++ = t; t = strchr(t, 0); t++; } if (argvArray) { *ptrEntry = NULL; td->flags |= RPMTD_ARGV; } } break; case RPM_CHAR_TYPE: case RPM_INT8_TYPE: case RPM_INT16_TYPE: case RPM_INT32_TYPE: case RPM_INT64_TYPE: if (allocMem) { td->data = xmalloc(entry->length); memcpy(td->data, entry->data, entry->length); } else { td->data = entry->data; } break; default: /* WTH? Don't mess with unknown data types... */ rc = 0; td->data = NULL; break; } td->type = entry->info.type; td->count = count; td->size = entry->length; if (td->data && entry->data != td->data) { td->flags |= RPMTD_ALLOCED; } return rc; }