rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmdb/header.c
Go to the documentation of this file.

    00001
    00005 /* RPM - Copyright (C) 1995-2002 Red Hat Software */
    00006
    00007 /* Data written to file descriptors is in network byte order.    */
    00008 /* Data read from file descriptors is expected to be in          */
    00009 /* network byte order and is converted on the fly to host order. */
    00010
    00011 #include "system.h"
    00012
    00013 #include <rpmiotypes.h>
    00014 #include <rpmio.h>              /* XXX for rpmioPool et al */
    00015 #define _RPMTAG_INTERNAL
    00016 #include <header_internal.h>
    00017
    00018 #include "debug.h"
    00019
    00020 /*@unchecked@*/
    00021 int _hdr_debug = 0;
    00022
    00023 /*@access Header @*/
    00024 /*@access HeaderIterator @*/
    00025 /*@access headerSprintfExtension @*/
    00026 /*@access headerTagTableEntry @*/
    00027
    00028 /*@access entryInfo @*/
    00029 /*@access indexEntry @*/
    00030
    00033 /*@-type@*/
    00034 /*@observer@*/ /*@unchecked@*/
    00035 static unsigned char header_magic[8] = {
    00036         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
    00037 };
    00038 /*@=type@*/
    00039
    00043 /*@observer@*/ /*@unchecked@*/
    00044 static int typeSizes[16] =  {
    00045     0,
    00046     1,
    00047     1,
    00048     2,
    00049     4,
    00050     8,
    00051     -1,
    00052     1,
    00053     -1,
    00054     -1,
    00055     0,
    00056     0,
    00057     0,
    00058     0,
    00059     0,
    00060     0
    00061 };
    00062
    00066 /*@unchecked@*/
    00067 static size_t headerMaxbytes = (1024*1024*1024);
    00068
    00072 /*@unchecked@*/
    00073 int _hdr_stats = 0;
    00074
    00075 /*@-compmempass@*/
    00076 /*@unchecked@*/
    00077 static struct rpmop_s hdr_loadops;
    00078 /*@unchecked@*/ /*@relnull@*/
    00079 rpmop _hdr_loadops = &hdr_loadops;
    00080 /*@unchecked@*/
    00081 static struct rpmop_s hdr_getops;
    00082 /*@unchecked@*/ /*@relnull@*/
    00083 rpmop _hdr_getops = &hdr_getops;
    00084 /*@=compmempass@*/
    00085
    00086 void * headerGetStats(Header h, int opx)
    00087 {
    00088     rpmop op = NULL;
    00089     if (_hdr_stats)
    00090     switch (opx) {
    00091     case 18:    op = &h->h_loadops;     break;  /* RPMTS_OP_HDRLOAD */
    00092     case 19:    op = &h->h_getops;      break;  /* RPMTS_OP_HDRGET */
    00093     }
    00094     return op;
    00095 }
    00096
    00097 /*@-mustmod@*/
    00098 static void headerScrub(void * _h)      /* XXX headerFini already in use */
    00099         /*@modifies *_h @*/
    00100 {
    00101     Header h = _h;
    00102
    00103     if (h->index != NULL) {
    00104         int mask = (HEADERFLAG_ALLOCATED | HEADERFLAG_MAPPED);
    00105         indexEntry entry = h->index;
    00106         size_t i;
    00107         for (i = 0; i < h->indexUsed; i++, entry++) {
    00108             if ((h->flags & mask) && ENTRY_IS_REGION(entry)) {
    00109                 if (entry->length > 0) {
    00110                     rpmuint32_t * ei = entry->data;
    00111                     if ((ei - 2) == h->blob) {
    00112                         if (h->flags & HEADERFLAG_MAPPED) {
    00113                             if (munmap(h->blob, h->bloblen) != 0)
    00114                                 fprintf(stderr,
    00115                                         "==> munmap(%p[%u]) error(%d): %s\n",
    00116                                         h->blob, h->bloblen,
    00117                                         errno, strerror(errno));
    00118                             h->blob = NULL;
    00119                         } else
    00120                             h->blob = _free(h->blob);
    00121                         h->bloblen = 0;
    00122                     }
    00123                     entry->data = NULL;
    00124                 }
    00125             } else if (!ENTRY_IN_REGION(entry)) {
    00126                 entry->data = _free(entry->data);
    00127             }
    00128             entry->data = NULL;
    00129             entry->length = 0;
    00130         }
    00131         h->index = _free(h->index);
    00132     }
    00133     h->origin = _free(h->origin);
    00134     h->baseurl = _free(h->baseurl);
    00135     h->digest = _free(h->digest);
    00136
    00137 /*@-nullstate@*/
    00138     if (_hdr_stats) {
    00139         if (_hdr_loadops)       /* RPMTS_OP_HDRLOAD */
    00140             (void) rpmswAdd(_hdr_loadops, headerGetStats(h, 18));
    00141         if (_hdr_getops)        /* RPMTS_OP_HDRGET */
    00142             (void) rpmswAdd(_hdr_getops, headerGetStats(h, 19));
    00143     }
    00144 /*@=nullstate@*/
    00145 }
    00146 /*@=mustmod@*/
    00147
    00148 /*@unchecked@*/ /*@only@*/ /*@null@*/
    00149 rpmioPool _headerPool;
    00150
    00151 static Header headerGetPool(/*@null@*/ rpmioPool pool)
    00152         /*@globals _headerPool, fileSystem @*/
    00153         /*@modifies pool, _headerPool, fileSystem @*/
    00154 {
    00155     Header h;
    00156
    00157     if (_headerPool == NULL) {
    00158         _headerPool = rpmioNewPool("h", sizeof(*h), -1, _hdr_debug,
    00159                         NULL, NULL, headerScrub);
    00160         pool = _headerPool;
    00161     }
    00162     return (Header) rpmioGetPool(pool, sizeof(*h));
    00163 }
    00164
    00165 Header headerNew(void)
    00166 {
    00167     Header h = headerGetPool(_headerPool);
    00168
    00169     (void) memcpy(h->magic, header_magic, sizeof(h->magic));
    00170     h->blob = NULL;
    00171     h->bloblen = 0;
    00172     h->origin = NULL;
    00173     h->baseurl = NULL;
    00174     h->digest = NULL;
    00175     h->rpmdb = NULL;
    00176     memset(&h->sb, 0, sizeof(h->sb));
    00177     h->instance = 0;
    00178     h->startoff = 0;
    00179     h->endoff = 0;
    00180     memset(&h->h_loadops, 0, sizeof(h->h_loadops));
    00181     memset(&h->h_getops, 0, sizeof(h->h_getops));
    00182     h->indexAlloced = INDEX_MALLOC_SIZE;
    00183     h->indexUsed = 0;
    00184     h->flags = HEADERFLAG_SORTED;
    00185
    00186     h->index = (h->indexAlloced
    00187         ? xcalloc(h->indexAlloced, sizeof(*h->index))
    00188         : NULL);
    00189
    00190 /*@-globstate -nullret -observertrans @*/
    00191     return headerLink(h);
    00192 /*@=globstate =nullret =observertrans @*/
    00193 }
    00194
    00197 static int indexCmp(const void * avp, const void * bvp)
    00198         /*@*/
    00199 {
    00200     /*@-castexpose@*/
    00201     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
    00202     /*@=castexpose@*/
    00203     return ((int)ap->info.tag - (int)bp->info.tag);
    00204 }
    00205
    00210 static
    00211 void headerSort(Header h)
    00212         /*@modifies h @*/
    00213 {
    00214     if (!(h->flags & HEADERFLAG_SORTED)) {
    00215         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
    00216         h->flags |= HEADERFLAG_SORTED;
    00217     }
    00218 }
    00219
    00222 static int offsetCmp(const void * avp, const void * bvp) /*@*/
    00223 {
    00224     /*@-castexpose@*/
    00225     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
    00226     /*@=castexpose@*/
    00227     int rc = ((int)ap->info.offset - (int)bp->info.offset);
    00228
    00229     if (rc == 0) {
    00230         /* Within a region, entries sort by address. Added drips sort by tag. */
    00231         if (ap->info.offset < 0)
    00232             rc = (((char *)ap->data) - ((char *)bp->data));
    00233         else
    00234             rc = ((int)ap->info.tag - (int)bp->info.tag);
    00235     }
    00236     return rc;
    00237 }
    00238
    00243 static
    00244 void headerUnsort(Header h)
    00245         /*@modifies h @*/
    00246 {
    00247     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
    00248 }
    00249
    00250 size_t headerSizeof(Header h)
    00251 {
    00252     indexEntry entry;
    00253     size_t size = 0;
    00254     size_t pad = 0;
    00255     size_t i;
    00256
    00257     if (h == NULL)
    00258         return size;
    00259
    00260     headerSort(h);
    00261
    00262     size += sizeof(header_magic);       /* XXX HEADER_MAGIC_YES */
    00263
    00264     /*@-sizeoftype@*/
    00265     size += 2 * sizeof(rpmuint32_t);    /* count of index entries */
    00266     /*@=sizeoftype@*/
    00267
    00268     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
    00269         size_t diff;
    00270         rpmTagType type;
    00271
    00272         /* Regions go in as is ... */
    00273         if (ENTRY_IS_REGION(entry)) {
    00274             size += entry->length;
    00275             /* XXX Legacy regions do not include the region tag and data. */
    00276             /*@-sizeoftype@*/
    00277             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
    00278                 size += sizeof(struct entryInfo_s) + entry->info.count;
    00279             /*@=sizeoftype@*/
    00280             continue;
    00281         }
    00282
    00283         /* ... and region elements are skipped. */
    00284         if (entry->info.offset < 0)
    00285             continue;
    00286
    00287         /* Alignment */
    00288         type = entry->info.type;
    00289         if (typeSizes[type] > 1) {
    00290             diff = typeSizes[type] - (size % typeSizes[type]);
    00291             if ((int)diff != typeSizes[type]) {
    00292                 size += diff;
    00293                 pad += diff;
    00294             }
    00295         }
    00296
    00297         /*@-sizeoftype@*/
    00298         size += sizeof(struct entryInfo_s) + entry->length;
    00299         /*@=sizeoftype@*/
    00300     }
    00301
    00302     return size;
    00303 }
    00304
    00314 static size_t dataLength(rpmTagType type, rpmTagData * p, rpmTagCount count,
    00315                 int onDisk, /*@null@*/ rpmTagData * pend)
    00316         /*@*/
    00317 {
    00318     const unsigned char * s = (unsigned char *) (*p).ui8p;
    00319     const unsigned char * se = (unsigned char *) (pend ? (*pend).ui8p : NULL);
    00320     size_t length = 0;
    00321
    00322     switch (type) {
    00323     case RPM_STRING_TYPE:
    00324         if (count != 1)
    00325             return 0;
    00326         while (*s++ != '\0') {
    00327             if (se && s > se)
    00328                 return 0;
    00329             length++;
    00330         }
    00331         length++;       /* count nul terminator too. */
    00332         break;
    00333         /* These are like RPM_STRING_TYPE, except they're *always* an array */
    00334         /* Compute sum of length of all strings, including nul terminators */
    00335     case RPM_I18NSTRING_TYPE:
    00336     case RPM_STRING_ARRAY_TYPE:
    00337         if (onDisk) {
    00338             while (count--) {
    00339                 length++;       /* count nul terminator too */
    00340                 while (*s++ != '\0') {
    00341                     if (se && s > se)
    00342                         return 0;
    00343                     length++;
    00344                 }
    00345             }
    00346         } else {
    00347             const char ** av = (*p).argv;
    00348             while (count--) {
    00349                 /* add one for null termination */
    00350                 length += strlen(*av++) + 1;
    00351             }
    00352         }
    00353         break;
    00354     default:
    00355         if (typeSizes[type] == -1)
    00356             return 0;
    00357         length = typeSizes[(type & 0xf)] * count;
    00358         if ((se && (s + length) > se))
    00359             return 0;
    00360         break;
    00361     }
    00362
    00363     return length;
    00364 }
    00365
    00370 static unsigned char * tagSwab(/*@out@*/ /*@returned@*/ unsigned char * t,
    00371                 const HE_t he, size_t nb)
    00372         /*@modifies *t @*/
    00373 {
    00374     rpmuint32_t i;
    00375
    00376     switch (he->t) {
    00377     case RPM_UINT64_TYPE:
    00378     {   rpmuint32_t * tt = (rpmuint32_t *)t;
    00379 assert(nb == (he->c * sizeof(*tt)));
    00380         for (i = 0; i < he->c; i++) {
    00381             rpmuint32_t j = 2 * i;
    00382             rpmuint32_t b = (rpmuint32_t) htonl(he->p.ui32p[j]);
    00383             tt[j  ] = (rpmuint32_t) htonl(he->p.ui32p[j+1]);
    00384             tt[j+1] = b;
    00385         }
    00386     }   break;
    00387     case RPM_UINT32_TYPE:
    00388     {   rpmuint32_t * tt = (rpmuint32_t *)t;
    00389 assert(nb == (he->c * sizeof(*tt)));
    00390         for (i = 0; i < he->c; i++)
    00391             tt[i] = (rpmuint32_t) htonl(he->p.ui32p[i]);
    00392     }   break;
    00393     case RPM_UINT16_TYPE:
    00394     {   rpmuint16_t * tt = (rpmuint16_t *)t;
    00395 assert(nb == (he->c * sizeof(*tt)));
    00396         for (i = 0; i < he->c; i++)
    00397             tt[i] = (rpmuint16_t) htons(he->p.ui16p[i]);
    00398     }   break;
    00399     default:
    00400 assert(he->p.ptr != NULL);
    00401         if ((void *)t != he->p.ptr && nb)
    00402             memcpy(t, he->p.ptr, nb);
    00403         t += nb;
    00404         break;
    00405     }
    00406 /*@-compdef@*/
    00407     return t;
    00408 /*@=compdef@*/
    00409 }
    00410
    00416 static int rpmheRealloc(HE_t he)
    00417         /*@modifies he @*/
    00418 {
    00419     size_t nb = 0;
    00420     int rc = 1;         /* assume success */
    00421
    00422     switch (he->t) {
    00423     default:
    00424 assert(0);      /* XXX stop unimplemented oversights. */
    00425         break;
    00426     case RPM_BIN_TYPE:
    00427         he->freeData = 1;       /* XXX RPM_BIN_TYPE is malloc'd */
    00428         /*@fallthrough@*/
    00429     case RPM_UINT8_TYPE:
    00430         nb = he->c * sizeof(*he->p.ui8p);
    00431         break;
    00432     case RPM_UINT16_TYPE:
    00433         nb = he->c * sizeof(*he->p.ui16p);
    00434         break;
    00435     case RPM_UINT32_TYPE:
    00436         nb = he->c * sizeof(*he->p.ui32p);
    00437         break;
    00438     case RPM_UINT64_TYPE:
    00439         nb = he->c * sizeof(*he->p.ui64p);
    00440         break;
    00441     case RPM_STRING_TYPE:
    00442         if (he->p.str)
    00443             nb = strlen(he->p.str) + 1;
    00444         else
    00445             rc = 0;
    00446         break;
    00447     case RPM_I18NSTRING_TYPE:
    00448     case RPM_STRING_ARRAY_TYPE:
    00449         break;
    00450     }
    00451
    00452     /* Allocate all returned storage (if not already). */
    00453     if (he->p.ptr && nb && !he->freeData) {
    00454         void * ptr = xmalloc(nb);
    00455         if (tagSwab(ptr, he, nb) != NULL)
    00456             he->p.ptr = ptr;
    00457         else {
    00458             ptr = _free(ptr);
    00459             rc = 0;
    00460         }
    00461     }
    00462
    00463     if (rc)
    00464         he->freeData = 1;
    00465
    00466     return rc;
    00467 }
    00468
    00495 /*@-globs@*/    /* XXX rpm_typeAlign usage */
    00496 static rpmuint32_t regionSwab(/*@null@*/ indexEntry entry, rpmuint32_t il, rpmuint32_t dl,
    00497                 entryInfo pe,
    00498                 unsigned char * dataStart,
    00499                 /*@null@*/ const unsigned char * dataEnd,
    00500                 rpmint32_t regionid)
    00501         /*@modifies *entry, *dataStart @*/
    00502 {
    00503     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00504     rpmTagData p;
    00505     rpmTagData pend;
    00506     unsigned char * tprev = NULL;
    00507     unsigned char * t = NULL;
    00508     size_t tdel = 0;
    00509     size_t tl = dl;
    00510     struct indexEntry_s ieprev;
    00511
    00512 assert(dataEnd != NULL);
    00513 assert(entry != NULL);
    00514 assert(dl == 0);        /* XXX eliminate dl argument (its always 0) */
    00515
    00516     memset(&ieprev, 0, sizeof(ieprev));
    00517     for (; il > 0; il--, pe++) {
    00518         struct indexEntry_s ie;
    00519         rpmTagType type;
    00520
    00521         ie.info.tag = (rpmuint32_t) ntohl(pe->tag);
    00522         ie.info.type = (rpmuint32_t) ntohl(pe->type);
    00523         ie.info.count = (rpmuint32_t) ntohl(pe->count);
    00524         ie.info.offset = (rpmint32_t) ntohl(pe->offset);
    00525 assert(ie.info.offset >= 0);    /* XXX insurance */
    00526
    00527         if (hdrchkType(ie.info.type))
    00528             return 0;
    00529         if (hdrchkData(ie.info.count))
    00530             return 0;
    00531         if (hdrchkData(ie.info.offset))
    00532             return 0;
    00533         if (hdrchkAlign(ie.info.type, ie.info.offset))
    00534             return 0;
    00535
    00536         ie.data = t = dataStart + ie.info.offset;
    00537         if (dataEnd && t >= dataEnd)
    00538             return 0;
    00539
    00540         p.ptr = ie.data;
    00541         pend.ui8p = (rpmuint8_t *) dataEnd;
    00542
    00543         /* Compute the tag data store length using offsets. */
    00544         if (il > 1)
    00545             ie.length = ((rpmuint32_t)ntohl(pe[1].offset) - ie.info.offset);
    00546         else {
    00547             /* XXX (dataEnd - t) +/- REGION_TAG_COUNT forces dataLength() */
    00548             ie.length = dataLength(ie.info.type, &p, ie.info.count, 1, &pend);
    00549         }
    00550
    00551         if (ie.length == 0 || hdrchkData(ie.length))
    00552             return 0;
    00553
    00554         ie.rdlen = 0;
    00555
    00556         if (entry) {
    00557             ie.info.offset = regionid;
    00558 /*@-kepttrans@*/        /* entry->data is kept */
    00559             *entry = ie;        /* structure assignment */
    00560 /*@=kepttrans@*/
    00561             entry++;
    00562         }
    00563
    00564         /* Alignment */
    00565         type = ie.info.type;
    00566         if (typeSizes[type] > 1) {
    00567             size_t diff = typeSizes[type] - (dl % typeSizes[type]);
    00568             if ((int)diff != typeSizes[type]) {
    00569                 dl += diff;
    00570 #ifdef  DYING
    00571                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
    00572                     ieprev.length += diff;
    00573 #endif
    00574             }
    00575         }
    00576         tdel = (tprev ? (t - tprev) : 0);
    00577 #ifdef  DYING
    00578         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
    00579             tdel = ieprev.length;
    00580 #endif
    00581
    00582         if (ie.info.tag >= HEADER_I18NTABLE) {
    00583             tprev = t;
    00584         } else {
    00585             tprev = dataStart;
    00586             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
    00587             /*@-sizeoftype@*/
    00588             if (ie.info.tag == HEADER_IMAGE)
    00589                 tprev -= REGION_TAG_COUNT;
    00590             /*@=sizeoftype@*/
    00591         }
    00592
    00593         t += ie.length;
    00594
    00595         dl += ie.length;
    00596         if (dataEnd && (dataStart + dl) > dataEnd) return 0;
    00597         tl += tdel;
    00598         ieprev = ie;    /* structure assignment */
    00599
    00600     }
    00601     tdel = (tprev ? (t - tprev) : 0);
    00602     tl += tdel;
    00603
    00604     /* XXX
    00605      * There are two hacks here:
    00606      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
    00607      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
    00608      */
    00609     /*@-sizeoftype@*/
    00610     if (tl+REGION_TAG_COUNT == dl)
    00611         tl += REGION_TAG_COUNT;
    00612     /*@=sizeoftype@*/
    00613
    00614     return dl;
    00615 }
    00616 /*@=globs@*/
    00617
    00618 void * headerUnload(Header h, size_t * lenp)
    00619 {
    00620     void * sw;
    00621     rpmuint32_t * ei = NULL;
    00622     entryInfo pe;
    00623     unsigned char * dataStart;
    00624     unsigned char * te;
    00625     unsigned pad;
    00626     size_t len = 0;
    00627     rpmuint32_t il = 0;
    00628     rpmuint32_t dl = 0;
    00629     indexEntry entry;
    00630     rpmTagType type;
    00631     size_t i;
    00632     size_t drlen;
    00633     size_t ndribbles;
    00634     size_t driplen;
    00635     size_t ndrips;
    00636     int legacy = 0;
    00637
    00638     if ((sw = headerGetStats(h, 18)) != NULL)   /* RPMTS_OP_HDRLOAD */
    00639         (void) rpmswEnter(sw, 0);
    00640
    00641     /* Sort entries by (offset,tag). */
    00642     headerUnsort(h);
    00643
    00644     /* Compute (il,dl) for all tags, including those deleted in region. */
    00645     pad = 0;
    00646     drlen = ndribbles = driplen = ndrips = 0;
    00647     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
    00648         if (ENTRY_IS_REGION(entry)) {
    00649             rpmuint32_t rdl;
    00650             rpmuint32_t ril;
    00651             rpmint32_t rid;
    00652
    00653 assert(entry->info.offset <= 0);        /* XXX insurance */
    00654             rdl = (rpmuint32_t)-entry->info.offset;     /* negative offset */
    00655             ril = (rpmuint32_t)(rdl/sizeof(*pe));
    00656             rid = (rpmuint32_t)entry->info.offset;
    00657
    00658             il += ril;
    00659             dl += entry->rdlen + entry->info.count;
    00660             /* XXX Legacy regions do not include the region tag and data. */
    00661             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
    00662                 il += 1;
    00663
    00664             /* Skip rest of entries in region, but account for dribbles. */
    00665             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
    00666                 if (entry->info.offset <= rid)
    00667                     /*@innercontinue@*/ continue;
    00668
    00669                 /* Alignment */
    00670                 type = entry->info.type;
    00671                 if (typeSizes[type] > 1) {
    00672                     size_t diff = typeSizes[type] - (dl % typeSizes[type]);
    00673                     if ((int)diff != typeSizes[type]) {
    00674                         drlen += diff;
    00675                         pad += diff;
    00676                         dl += diff;
    00677                     }
    00678                 }
    00679
    00680                 ndribbles++;
    00681                 il++;
    00682                 drlen += entry->length;
    00683                 dl += entry->length;
    00684             }
    00685             i--;
    00686             entry--;
    00687             continue;
    00688         }
    00689
    00690         /* Ignore deleted drips. */
    00691         if (entry->data == NULL || entry->length == 0)
    00692             continue;
    00693
    00694         /* Alignment */
    00695         type = entry->info.type;
    00696         if (typeSizes[type] > 1) {
    00697             size_t diff = typeSizes[type] - (dl % typeSizes[type]);
    00698             if ((int)diff != typeSizes[type]) {
    00699                 driplen += diff;
    00700                 pad += diff;
    00701                 dl += diff;
    00702             } else
    00703                 diff = 0;
    00704         }
    00705
    00706         ndrips++;
    00707         il++;
    00708         driplen += entry->length;
    00709         dl += entry->length;
    00710     }
    00711
    00712     /* Sanity checks on header intro. */
    00713     if (hdrchkTags(il) || hdrchkData(dl))
    00714         goto errxit;
    00715
    00716     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
    00717
    00718     ei = xmalloc(len);
    00719     ei[0] = (rpmuint32_t) htonl(il);
    00720     ei[1] = (rpmuint32_t) htonl(dl);
    00721
    00722     pe = (entryInfo) &ei[2];
    00723     dataStart = te = (unsigned char *) (pe + il);
    00724
    00725     pad = 0;
    00726     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
    00727         const char * src;
    00728         unsigned char *t;
    00729         size_t rdlen;
    00730
    00731         if (entry->data == NULL || entry->length == 0)
    00732             continue;
    00733
    00734         t = te;
    00735         pe->tag = (rpmuint32_t) htonl(entry->info.tag);
    00736         pe->type = (rpmuint32_t) htonl(entry->info.type);
    00737         pe->count = (rpmuint32_t) htonl(entry->info.count);
    00738
    00739         if (ENTRY_IS_REGION(entry)) {
    00740             rpmuint32_t rdl;
    00741             rpmuint32_t ril;
    00742             rpmint32_t rid;
    00743
    00744 assert(entry->info.offset <= 0);        /* XXX insurance */
    00745
    00746             rdl = (rpmuint32_t)-entry->info.offset;     /* negative offset */
    00747             ril = (rpmuint32_t)(rdl/sizeof(*pe) + ndribbles);
    00748             rid = (rpmuint32_t)entry->info.offset;
    00749
    00750             src = (char *)entry->data;
    00751             rdlen = entry->rdlen;
    00752
    00753             /* XXX Legacy regions do not include the region tag and data. */
    00754             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
    00755                 rpmuint32_t stei[4];
    00756
    00757                 legacy = 1;
    00758                 memcpy(pe+1, src, rdl);
    00759                 memcpy(te, src + rdl, rdlen);
    00760                 te += rdlen;
    00761
    00762                 pe->offset = (rpmint32_t) htonl(te - dataStart);
    00763                 stei[0] = (rpmuint32_t) pe->tag;
    00764                 stei[1] = (rpmuint32_t) pe->type;
    00765                 stei[2] = (rpmuint32_t) htonl(-rdl-entry->info.count);
    00766                 stei[3] = (rpmuint32_t) pe->count;
    00767                 memcpy(te, stei, entry->info.count);
    00768                 te += entry->info.count;
    00769                 ril++;
    00770                 rdlen += entry->info.count;
    00771
    00772             } else {
    00773
    00774                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
    00775                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
    00776                 te += rdlen;
    00777                 {   /*@-castexpose@*/
    00778                     entryInfo se = (entryInfo)src;
    00779                     /*@=castexpose@*/
    00780                     rpmint32_t off = (rpmint32_t) ntohl(se->offset);
    00781                     pe->offset = (rpmint32_t)((off)
    00782                         ? htonl(te - dataStart) : htonl(off));
    00783                 }
    00784                 te += entry->info.count + drlen;
    00785
    00786             }
    00787
    00788             /* Skip rest of entries in region. */
    00789             while (i < h->indexUsed && entry->info.offset <= rid+1) {
    00790                 i++;
    00791                 entry++;
    00792             }
    00793             i--;
    00794             entry--;
    00795             pe += ril;
    00796             continue;
    00797         }
    00798
    00799         /* Ignore deleted drips. */
    00800         if (entry->data == NULL || entry->length == 0)
    00801             continue;
    00802
    00803         /* Alignment */
    00804         type = entry->info.type;
    00805         if (typeSizes[type] > 1) {
    00806             size_t diff;
    00807             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
    00808             if ((int)diff != typeSizes[type]) {
    00809                 memset(te, 0, diff);
    00810                 te += diff;
    00811                 pad += diff;
    00812             }
    00813         }
    00814
    00815         /* Move tag data into header data store. */
    00816         pe->offset = (rpmint32_t) htonl(te - dataStart);
    00817         memcpy(te, entry->data, entry->length);
    00818         te += entry->length;
    00819         pe++;
    00820     }
    00821
    00822     /* Insure that there are no memcpy underruns/overruns. */
    00823     if (((unsigned char *)pe) != dataStart)
    00824         goto errxit;
    00825     if ((((unsigned char *)ei)+len) != te)
    00826         goto errxit;
    00827
    00828     if (lenp)
    00829         *lenp = len;
    00830
    00831     h->flags &= ~HEADERFLAG_SORTED;
    00832     headerSort(h);
    00833
    00834     if (sw != NULL)     (void) rpmswExit(sw, len);
    00835
    00836     return (void *) ei;
    00837
    00838 errxit:
    00839     if (sw != NULL)     (void) rpmswExit(sw, len);
    00840     /*@-usereleased@*/
    00841     ei = _free(ei);
    00842     /*@=usereleased@*/
    00843     return (void *) ei;
    00844 }
    00845
    00853 static /*@null@*/
    00854 indexEntry findEntry(/*@null@*/ Header h, rpmTag tag, rpmTagType type)
    00855         /*@modifies h @*/
    00856 {
    00857     indexEntry entry, entry2, last;
    00858     struct indexEntry_s key;
    00859
    00860     if (h == NULL) return NULL;
    00861     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
    00862
    00863     key.info.tag = tag;
    00864
    00865     entry2 = entry =
    00866         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
    00867     if (entry == NULL)
    00868         return NULL;
    00869
    00870     if (type == 0)
    00871         return entry;
    00872
    00873     /* look backwards */
    00874     while (entry->info.tag == tag && entry->info.type != type &&
    00875            entry > h->index) entry--;
    00876
    00877     if (entry->info.tag == tag && entry->info.type == type)
    00878         return entry;
    00879
    00880     last = h->index + h->indexUsed;
    00881     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
    00882     while (entry2->info.tag == tag && entry2->info.type != type &&
    00883            entry2 < last) entry2++;
    00884     /*@=usereleased@*/
    00885
    00886     if (entry->info.tag == tag && entry->info.type == type)
    00887         return entry;
    00888
    00889     return NULL;
    00890 }
    00891
    00901 static
    00902 int headerRemoveEntry(Header h, rpmTag tag)
    00903         /*@modifies h @*/
    00904 {
    00905     indexEntry last = h->index + h->indexUsed;
    00906     indexEntry entry, first;
    00907     int ne;
    00908
    00909     entry = findEntry(h, tag, 0);
    00910     if (!entry) return 1;
    00911
    00912     /* Make sure entry points to the first occurence of this tag. */
    00913     while (entry > h->index && (entry - 1)->info.tag == tag)
    00914         entry--;
    00915
    00916     /* Free data for tags being removed. */
    00917     for (first = entry; first < last; first++) {
    00918         void * data;
    00919         if (first->info.tag != tag)
    00920             break;
    00921         data = first->data;
    00922         first->data = NULL;
    00923         first->length = 0;
    00924         if (ENTRY_IN_REGION(first))
    00925             continue;
    00926         data = _free(data);
    00927     }
    00928
    00929     ne = (first - entry);
    00930     if (ne > 0) {
    00931         h->indexUsed -= ne;
    00932         ne = last - first;
    00933         if (ne > 0)
    00934             memmove(entry, first, (ne * sizeof(*entry)));
    00935     }
    00936
    00937     return 0;
    00938 }
    00939
    00940 Header headerLoad(void * uh)
    00941 {
    00942     void * sw = NULL;
    00943     rpmuint32_t * ei = (rpmuint32_t *) uh;
    00944     rpmuint32_t il = (rpmuint32_t) ntohl(ei[0]);                /* index length */
    00945     rpmuint32_t dl = (rpmuint32_t) ntohl(ei[1]);                /* data length */
    00946     /*@-sizeoftype@*/
    00947     size_t pvlen = sizeof(il) + sizeof(dl) +
    00948                (il * sizeof(struct entryInfo_s)) + dl;
    00949     /*@=sizeoftype@*/
    00950     void * pv = uh;
    00951     Header h = NULL;
    00952     entryInfo pe;
    00953     unsigned char * dataStart;
    00954     unsigned char * dataEnd;
    00955     indexEntry entry;
    00956     rpmuint32_t rdlen;
    00957     int i;
    00958
    00959     /* Sanity checks on header intro. */
    00960     if (hdrchkTags(il) || hdrchkData(dl))
    00961         goto errxit;
    00962
    00963     ei = (rpmuint32_t *) pv;
    00964     /*@-castexpose@*/
    00965     pe = (entryInfo) &ei[2];
    00966     /*@=castexpose@*/
    00967     dataStart = (unsigned char *) (pe + il);
    00968     dataEnd = dataStart + dl;
    00969
    00970     h = headerGetPool(_headerPool);
    00971     memset(&h->h_loadops, 0, sizeof(h->h_loadops));
    00972     if ((sw = headerGetStats(h, 18)) != NULL)   /* RPMTS_OP_HDRLOAD */
    00973         (void) rpmswEnter(sw, 0);
    00974     {   unsigned char * hmagic = header_magic;
    00975         (void) memcpy(h->magic, hmagic, sizeof(h->magic));
    00976     }
    00977     /*@-assignexpose -kepttrans@*/
    00978     h->blob = uh;
    00979     h->bloblen = pvlen;
    00980     /*@=assignexpose =kepttrans@*/
    00981     h->origin = NULL;
    00982     h->baseurl = NULL;
    00983     h->digest = NULL;
    00984     h->rpmdb = NULL;
    00985     memset(&h->sb, 0, sizeof(h->sb));
    00986     h->instance = 0;
    00987     h->startoff = 0;
    00988     h->endoff = (rpmuint32_t) pvlen;
    00989     memset(&h->h_getops, 0, sizeof(h->h_getops));
    00990     h->indexAlloced = il + 1;
    00991     h->indexUsed = il;
    00992     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
    00993     h->flags = HEADERFLAG_SORTED;
    00994     h = headerLink(h);
    00995 assert(h != NULL);
    00996
    00997     entry = h->index;
    00998     i = 0;
    00999     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
    01000         h->flags |= HEADERFLAG_LEGACY;
    01001         entry->info.type = REGION_TAG_TYPE;
    01002         entry->info.tag = HEADER_IMAGE;
    01003         /*@-sizeoftype@*/
    01004         entry->info.count = (rpmTagCount)REGION_TAG_COUNT;
    01005         /*@=sizeoftype@*/
    01006         entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
    01007
    01008         /*@-assignexpose@*/
    01009         entry->data = pe;
    01010         /*@=assignexpose@*/
    01011         entry->length = pvlen - sizeof(il) - sizeof(dl);
    01012         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
    01013 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
    01014         if (rdlen != dl)
    01015             goto errxit;
    01016 #endif
    01017         entry->rdlen = rdlen;
    01018         entry++;
    01019         h->indexUsed++;
    01020     } else {
    01021         rpmuint32_t rdl;
    01022         rpmuint32_t ril;
    01023
    01024         h->flags &= ~HEADERFLAG_LEGACY;
    01025
    01026         entry->info.type = (rpmuint32_t) htonl(pe->type);
    01027         entry->info.count = (rpmuint32_t) htonl(pe->count);
    01028
    01029         if (hdrchkType(entry->info.type))
    01030             goto errxit;
    01031         if (hdrchkTags(entry->info.count))
    01032             goto errxit;
    01033
    01034         {   rpmint32_t off = (rpmint32_t) ntohl(pe->offset);
    01035
    01036             if (hdrchkData(off))
    01037                 goto errxit;
    01038             if (off) {
    01039 /*@-sizeoftype@*/
    01040                 size_t nb = REGION_TAG_COUNT;
    01041 /*@=sizeoftype@*/
    01042                 rpmuint32_t * stei = memcpy(alloca(nb), dataStart + off, nb);
    01043                 rdl = (rpmuint32_t)-ntohl(stei[2]);     /* negative offset */
    01044 assert((rpmint32_t)rdl >= 0);   /* XXX insurance */
    01045                 ril = (rpmuint32_t)(rdl/sizeof(*pe));
    01046                 if (hdrchkTags(ril) || hdrchkData(rdl))
    01047                     goto errxit;
    01048                 entry->info.tag = (rpmuint32_t) htonl(pe->tag);
    01049             } else {
    01050                 ril = il;
    01051                 /*@-sizeoftype@*/
    01052                 rdl = (rpmuint32_t)(ril * sizeof(struct entryInfo_s));
    01053                 /*@=sizeoftype@*/
    01054                 entry->info.tag = HEADER_IMAGE;
    01055             }
    01056         }
    01057         entry->info.offset = (rpmint32_t) -rdl; /* negative offset */
    01058
    01059         /*@-assignexpose@*/
    01060         entry->data = pe;
    01061         /*@=assignexpose@*/
    01062         entry->length = pvlen - sizeof(il) - sizeof(dl);
    01063         rdlen = regionSwab(entry+1, (ril-1), 0, pe+1, dataStart, dataEnd, entry->info.offset);
    01064         if (rdlen == 0)
    01065             goto errxit;
    01066         entry->rdlen = rdlen;
    01067
    01068         if (ril < (rpmuint32_t)h->indexUsed) {
    01069             indexEntry newEntry = entry + ril;
    01070             size_t ne = (h->indexUsed - ril);
    01071             rpmint32_t rid = entry->info.offset+1;
    01072             rpmuint32_t rc;
    01073
    01074             /* Load dribble entries from region. */
    01075             rc = regionSwab(newEntry, (rpmuint32_t)ne, 0, pe+ril, dataStart, dataEnd, rid);
    01076             if (rc == 0)
    01077                 goto errxit;
    01078             rdlen += rc;
    01079
    01080           { indexEntry firstEntry = newEntry;
    01081             size_t save = h->indexUsed;
    01082             size_t j;
    01083
    01084             /* Dribble entries replace duplicate region entries. */
    01085             h->indexUsed -= ne;
    01086             for (j = 0; j < ne; j++, newEntry++) {
    01087                 (void) headerRemoveEntry(h, newEntry->info.tag);
    01088                 if (newEntry->info.tag == HEADER_BASENAMES)
    01089                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
    01090             }
    01091
    01092             /* If any duplicate entries were replaced, move new entries down. */
    01093             if (h->indexUsed < (save - ne)) {
    01094                 memmove(h->index + h->indexUsed, firstEntry,
    01095                         (ne * sizeof(*entry)));
    01096             }
    01097             h->indexUsed += ne;
    01098           }
    01099         }
    01100     }
    01101
    01102     h->flags &= ~HEADERFLAG_SORTED;
    01103     headerSort(h);
    01104
    01105     if (sw != NULL)     (void) rpmswExit(sw, pvlen);
    01106
    01107     /*@-globstate -observertrans @*/
    01108     return h;
    01109     /*@=globstate =observertrans @*/
    01110
    01111 errxit:
    01112     if (sw != NULL)     (void) rpmswExit(sw, pvlen);
    01113     /*@-usereleased@*/
    01114     if (h) {
    01115         h->index = _free(h->index);
    01116         yarnPossess(h->_item.use);      /* XXX rpmioPutItem expects locked. */
    01117         h = (Header) rpmioPutPool((rpmioItem)h);
    01118     }
    01119     /*@=usereleased@*/
    01120     /*@-refcounttrans -globstate@*/
    01121     return h;
    01122     /*@=refcounttrans =globstate@*/
    01123 }
    01124
    01125 int headerGetMagic(Header h, unsigned char ** magicp, size_t * nmagicp)
    01126 {
    01127     unsigned char * hmagic = header_magic;
    01128     if (magicp)
    01129         *magicp = (h ? h->magic : hmagic);
    01130     if (nmagicp)
    01131         *nmagicp = (h ? sizeof(h->magic) : sizeof(header_magic));
    01132     return 0;
    01133 }
    01134
    01135 int headerSetMagic(Header h, unsigned char * magic, size_t nmagic)
    01136 {
    01137     if (nmagic > sizeof(h->magic))
    01138         nmagic = sizeof(h->magic);
    01139     if (h) {
    01140         memset(h->magic, 0, sizeof(h->magic));
    01141         if (nmagic > 0)
    01142             memmove(h->magic, magic, nmagic);
    01143     }
    01144     return 0;
    01145 }
    01146
    01147 const char * headerGetOrigin(Header h)
    01148 {
    01149     return (h != NULL ? h->origin : NULL);
    01150 }
    01151
    01152 int headerSetOrigin(Header h, const char * origin)
    01153 {
    01154     if (h != NULL) {
    01155         h->origin = _free(h->origin);
    01156         h->origin = xstrdup(origin);
    01157     }
    01158     return 0;
    01159 }
    01160
    01161 const char * headerGetBaseURL(Header h)
    01162 {
    01163 /*@-retexpose@*/
    01164     return (h != NULL ? h->baseurl : NULL);
    01165 /*@=retexpose@*/
    01166 }
    01167
    01168 int headerSetBaseURL(Header h, const char * baseurl)
    01169 {
    01170     if (h != NULL) {
    01171         h->baseurl = _free(h->baseurl);
    01172         h->baseurl = xstrdup(baseurl);
    01173     }
    01174     return 0;
    01175 }
    01176
    01177 struct stat * headerGetStatbuf(Header h)
    01178 {
    01179 /*@-immediatetrans -retexpose@*/
    01180     return (h != NULL ? &h->sb : NULL);
    01181 /*@=immediatetrans =retexpose@*/
    01182 }
    01183
    01184 int headerSetStatbuf(Header h, struct stat * st)
    01185 {
    01186     if (h != NULL && st != NULL)
    01187         memcpy(&h->sb, st, sizeof(h->sb));
    01188     return 0;
    01189 }
    01190
    01191 const char * headerGetDigest(Header h)
    01192 {
    01193 /*@-compdef -retexpose -usereleased @*/
    01194     return (h != NULL ? h->digest : NULL);
    01195 /*@=compdef =retexpose =usereleased @*/
    01196 }
    01197
    01198 int headerSetDigest(Header h, const char * digest)
    01199 {
    01200     if (h != NULL) {
    01201         h->digest = _free(h->digest);
    01202         h->digest = xstrdup(digest);
    01203     }
    01204     return 0;
    01205 }
    01206
    01207 void * headerGetRpmdb(Header h)
    01208 {
    01209 /*@-compdef -retexpose -usereleased @*/
    01210     return (h != NULL ? h->rpmdb : NULL);
    01211 /*@=compdef =retexpose =usereleased @*/
    01212 }
    01213
    01214 void * headerSetRpmdb(Header h, void * rpmdb)
    01215 {
    01216 /*@-assignexpose -temptrans @*/
    01217     if (h != NULL)
    01218         h->rpmdb = rpmdb;
    01219 /*@=assignexpose =temptrans @*/
    01220     return NULL;
    01221 }
    01222
    01223 rpmuint32_t headerGetInstance(Header h)
    01224 {
    01225     return (h != NULL ? h->instance : 0);
    01226 }
    01227
    01228 rpmuint32_t headerSetInstance(Header h, rpmuint32_t instance)
    01229 {
    01230     if (h != NULL)
    01231         h->instance = instance;
    01232     return 0;
    01233 }
    01234
    01235 rpmuint32_t headerGetStartOff(Header h)
    01236 {
    01237     return (h != NULL ? h->startoff : 0);
    01238 }
    01239
    01240 rpmuint32_t headerSetStartOff(Header h, rpmuint32_t startoff)
    01241 {
    01242     if (h != NULL)
    01243         h->startoff = startoff;
    01244     return 0;
    01245 }
    01246
    01247 rpmuint32_t headerGetEndOff(Header h)
    01248 {
    01249     return (h != NULL ? h->endoff : 0);
    01250 }
    01251
    01252 rpmuint32_t headerSetEndOff(Header h, rpmuint32_t endoff)
    01253 {
    01254     if (h != NULL)
    01255         h->endoff = endoff;
    01256     return 0;
    01257 }
    01258
    01259 Header headerReload(Header h, int tag)
    01260 {
    01261     Header nh;
    01262     void * uh;
    01263     const char * origin = (h->origin != NULL ? xstrdup(h->origin) : NULL);
    01264     const char * baseurl = (h->baseurl != NULL ? xstrdup(h->baseurl) : NULL);
    01265     const char * digest = (h->digest != NULL ? xstrdup(h->digest) : NULL);
    01266     struct stat sb = h->sb;     /* structure assignment */
    01267     void * rpmdb = h->rpmdb;
    01268     rpmuint32_t instance = h->instance;
    01269     int xx;
    01270
    01271 /*@-onlytrans@*/
    01272     uh = headerUnload(h, NULL);
    01273     (void)headerFree(h);
    01274     h = NULL ;
    01275 /*@=onlytrans@*/
    01276     if (uh == NULL)
    01277         return NULL;
    01278     nh = headerLoad(uh);
    01279     if (nh == NULL) {
    01280         uh = _free(uh);
    01281         return NULL;
    01282     }
    01283     nh->flags |= HEADERFLAG_ALLOCATED;
    01284     if (ENTRY_IS_REGION(nh->index)) {
    01285         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
    01286             nh->index[0].info.tag = tag;
    01287     }
    01288     if (origin != NULL) {
    01289         xx = headerSetOrigin(nh, origin);
    01290         origin = _free(origin);
    01291     }
    01292     if (baseurl != NULL) {
    01293         xx = headerSetBaseURL(nh, baseurl);
    01294         baseurl = _free(baseurl);
    01295     }
    01296     if (digest != NULL) {
    01297         xx = headerSetDigest(nh, digest);
    01298         digest = _free(digest);
    01299     }
    01300 /*@-assignexpose@*/
    01301     nh->sb = sb;        /* structure assignment */
    01302 /*@=assignexpose@*/
    01303     (void) headerSetRpmdb(nh, rpmdb);
    01304     xx = (int) headerSetInstance(nh, instance);
    01305     return nh;
    01306 }
    01307
    01308 static Header headerMap(const void * uh, int map)
    01309         /*@*/
    01310 {
    01311     rpmuint32_t * ei = (rpmuint32_t *) uh;
    01312     rpmuint32_t il = (rpmuint32_t) ntohl(ei[0]);        /* index length */
    01313     rpmuint32_t dl = (rpmuint32_t) ntohl(ei[1]);        /* data length */
    01314     /*@-sizeoftype@*/
    01315     size_t pvlen = sizeof(il) + sizeof(dl) +
    01316                         (il * sizeof(struct entryInfo_s)) + dl;
    01317     /*@=sizeoftype@*/
    01318     void * nuh = NULL;
    01319     Header nh = NULL;
    01320
    01321     /* Sanity checks on header intro. */
    01322     if (hdrchkTags(il) || hdrchkData(dl) || pvlen >= headerMaxbytes)
    01323         return NULL;
    01324
    01325     if (map) {
    01326         static const int prot = PROT_READ | PROT_WRITE;
    01327         static const int flags = MAP_PRIVATE| MAP_ANONYMOUS;
    01328         static const int fdno = -1;
    01329         static const off_t off = 0;
    01330         nuh = mmap(NULL, pvlen, prot, flags, fdno, off);
    01331         if (nuh == NULL || nuh == (void *)-1)
    01332             fprintf(stderr,
    01333                 "==> mmap(%p[%u], 0x%x, 0x%x, %d, 0x%x) error(%d): %s\n",
    01334                 NULL, pvlen, prot, flags, fdno, (unsigned)off,
    01335                 errno, strerror(errno));
    01336         memcpy(nuh, uh, pvlen);
    01337         if (mprotect(nuh, pvlen, PROT_READ) != 0)
    01338             fprintf(stderr, "==> mprotect(%p[%u],0x%x) error(%d): %s\n",
    01339                         nuh, pvlen, PROT_READ,
    01340                         errno, strerror(errno));
    01341         nh = headerLoad(nuh);
    01342         if (nh != NULL) {
    01343 assert(nh->bloblen == pvlen);
    01344             nh->flags |= HEADERFLAG_MAPPED;
    01345             nh->flags |= HEADERFLAG_RDONLY;
    01346         } else {
    01347             if (munmap(nuh, pvlen) != 0)
    01348                 fprintf(stderr, "==> munmap(%p[%u]) error(%d): %s\n",
    01349                 nuh, pvlen, errno, strerror(errno));
    01350         }
    01351     } else {
    01352         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
    01353         if ((nh = headerLoad(nuh)) != NULL)
    01354             nh->flags |= HEADERFLAG_ALLOCATED;
    01355         else
    01356             nuh = _free(nuh);
    01357     }
    01358
    01359     return nh;
    01360 }
    01361
    01362 Header headerCopyLoad(const void * uh)
    01363 {
    01364     static const int map = 1;
    01365     return headerMap(uh, map);
    01366 }
    01367
    01368 int headerIsEntry(Header h, rpmTag tag)
    01369 {
    01370     /*@-mods@*/         /*@ FIX: h modified by sort. */
    01371     return (findEntry(h, tag, 0) ? 1 : 0);
    01372     /*@=mods@*/
    01373 }
    01374
    01383 static int copyEntry(const indexEntry entry, HE_t he, int minMem)
    01384         /*@modifies he @*/
    01385 {
    01386     rpmTagCount count = entry->info.count;
    01387     int rc = 1;         /* XXX 1 on success. */
    01388
    01389     switch (entry->info.type) {
    01390     case RPM_BIN_TYPE:
    01391         /*
    01392          * XXX This only works for
    01393          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
    01394          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
    01395          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
    01396          */
    01397         if (ENTRY_IS_REGION(entry)) {
    01398             rpmuint32_t * ei = ((rpmuint32_t *)entry->data) - 2;
    01399             /*@-castexpose@*/
    01400             entryInfo pe = (entryInfo) (ei + 2);
    01401             /*@=castexpose@*/
    01402             unsigned char * dataStart = (unsigned char *) (pe + ntohl(ei[0]));
    01403             rpmuint32_t rdl;
    01404             rpmuint32_t ril;
    01405
    01406 assert(entry->info.offset <= 0);                /* XXX insurance */
    01407             rdl = (rpmuint32_t)-entry->info.offset;     /* negative offset */
    01408             ril = (rpmuint32_t)(rdl/sizeof(*pe));
    01409             /*@-sizeoftype@*/
    01410             rdl = (rpmuint32_t)entry->rdlen;
    01411             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
    01412             if (entry->info.tag == HEADER_IMAGE) {
    01413                 ril -= 1;
    01414                 pe += 1;
    01415             } else {
    01416                 count += REGION_TAG_COUNT;
    01417                 rdl += REGION_TAG_COUNT;
    01418             }
    01419
    01420             he->p.ui32p = ei = xmalloc(count);
    01421             ei[0] = (rpmuint32_t)htonl(ril);
    01422             ei[1] = (rpmuint32_t)htonl(rdl);
    01423
    01424             /*@-castexpose@*/
    01425             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
    01426             /*@=castexpose@*/
    01427
    01428             (void) memcpy(pe + ril, dataStart, rdl);
    01429         } else {
    01430             count = (rpmTagCount)entry->length;
    01431             he->p.ptr = (!minMem
    01432                 ? memcpy(xmalloc(count), entry->data, count)
    01433                 : entry->data);
    01434         }
    01435         break;
    01436     case RPM_STRING_TYPE:
    01437         if (count == 1) {
    01438             he->p.str = entry->data;
    01439             break;
    01440         }
    01441         /*@fallthrough@*/
    01442     case RPM_I18NSTRING_TYPE:
    01443     case RPM_STRING_ARRAY_TYPE:
    01444     {   const char ** argv;
    01445         size_t nb = count * sizeof(*argv);
    01446         char * t;
    01447         unsigned i;
    01448
    01449         /*@-mods@*/
    01450         if (minMem) {
    01451             he->p.argv = argv = xmalloc(nb);
    01452             t = entry->data;
    01453         } else {
    01454             he->p.argv = argv = xmalloc(nb + entry->length);
    01455             t = (char *) &argv[count];
    01456             memcpy(t, entry->data, entry->length);
    01457         }
    01458         /*@=mods@*/
    01459         for (i = 0; i < (unsigned) count; i++) {
    01460             argv[i] = t;
    01461             t = strchr(t, 0);
    01462             t++;
    01463         }
    01464     }   break;
    01465
    01466     default:
    01467         he->p.ptr = entry->data;
    01468         break;
    01469     }
    01470     he->t = entry->info.type;
    01471     he->c = count;
    01472     return rc;
    01473 }
    01474
    01493 static int headerMatchLocale(const char *td, const char *l, const char *le)
    01494         /*@*/
    01495 {
    01496     const char *fe;
    01497
    01498
    01499 #if 0
    01500   { const char *s, *ll, *CC, *EE, *dd;
    01501     char *lbuf, *t.
    01502
    01503     /* Copy the buffer and parse out components on the fly. */
    01504     lbuf = alloca(le - l + 1);
    01505     for (s = l, ll = t = lbuf; *s; s++, t++) {
    01506         switch (*s) {
    01507         case '_':
    01508             *t = '\0';
    01509             CC = t + 1;
    01510             break;
    01511         case '.':
    01512             *t = '\0';
    01513             EE = t + 1;
    01514             break;
    01515         case '@':
    01516             *t = '\0';
    01517             dd = t + 1;
    01518             break;
    01519         default:
    01520             *t = *s;
    01521             break;
    01522         }
    01523     }
    01524
    01525     if (ll)     /* ISO language should be lower case */
    01526         for (t = ll; *t; t++)   *t = tolower(*t);
    01527     if (CC)     /* ISO country code should be upper case */
    01528         for (t = CC; *t; t++)   *t = toupper(*t);
    01529
    01530     /* There are a total of 16 cases to attempt to match. */
    01531   }
    01532 #endif
    01533
    01534     /* First try a complete match. */
    01535     if (strlen(td) == (size_t)(le - l) && !strncmp(td, l, (size_t)(le - l)))
    01536         return 1;
    01537
    01538     /* Next, try stripping optional dialect and matching.  */
    01539     for (fe = l; fe < le && *fe != '@'; fe++)
    01540         {};
    01541     if (fe < le && !strncmp(td, l, (fe - l)))
    01542         return 1;
    01543
    01544     /* Next, try stripping optional codeset and matching.  */
    01545     for (fe = l; fe < le && *fe != '.'; fe++)
    01546         {};
    01547     if (fe < le && !strncmp(td, l, (fe - l)))
    01548         return 1;
    01549
    01550     /* Finally, try stripping optional country code and matching. */
    01551     for (fe = l; fe < le && *fe != '_'; fe++)
    01552         {};
    01553     if (fe < le && !strncmp(td, l, (fe - l)))
    01554         return 2;
    01555
    01556     return 0;
    01557 }
    01558
    01565 /*@dependent@*/ /*@exposed@*/ static char *
    01566 headerFindI18NString(Header h, indexEntry entry)
    01567         /*@*/
    01568 {
    01569     const char *lang, *l, *le;
    01570     indexEntry table;
    01571
    01572     /* XXX Drepper sez' this is the order. */
    01573     if ((lang = getenv("LANGUAGE")) == NULL &&
    01574         (lang = getenv("LC_ALL")) == NULL &&
    01575         (lang = getenv("LC_MESSAGES")) == NULL &&
    01576         (lang = getenv("LANG")) == NULL)
    01577             return entry->data;
    01578
    01579     /*@-mods@*/
    01580     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
    01581         return entry->data;
    01582     /*@=mods@*/
    01583
    01584     for (l = lang; *l != '\0'; l = le) {
    01585         const char *td;
    01586         char *ed, *ed_weak = NULL;
    01587         rpmuint32_t langNum;
    01588
    01589         while (*l && *l == ':')                 /* skip leading colons */
    01590             l++;
    01591         if (*l == '\0')
    01592             break;
    01593         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
    01594             {};
    01595
    01596         /* For each entry in the header ... */
    01597         for (langNum = 0, td = table->data, ed = entry->data;
    01598              langNum < entry->info.count;
    01599              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1)
    01600         {
    01601                 int match = headerMatchLocale(td, l, le);
    01602                 if (match == 1) return ed;
    01603                 else if (match == 2) ed_weak = ed;
    01604         }
    01605         if (ed_weak) return ed_weak;
    01606     }
    01607
    01608     return entry->data;
    01609 }
    01610
    01618 static int intGetEntry(Header h, HE_t he, int flags)
    01619         /*@modifies he @*/
    01620 {
    01621     int minMem = 0;
    01622     indexEntry entry;
    01623     int rc;
    01624
    01625     /* First find the tag */
    01626 /*@-mods@*/             /*@ FIX: h modified by sort. */
    01627     entry = findEntry(h, he->tag, 0);
    01628 /*@=mods@*/
    01629     if (entry == NULL) {
    01630         he->t = 0;
    01631         he->p.ptr = NULL;
    01632         he->c = 0;
    01633         return 0;
    01634     }
    01635
    01636     switch (entry->info.type) {
    01637     case RPM_I18NSTRING_TYPE:
    01638         if (!(flags & HEADERGET_NOI18NSTRING)) {
    01639             rc = 1;
    01640             he->t = RPM_STRING_TYPE;
    01641             he->c = 1;
    01642 /*@-dependenttrans@*/
    01643             he->p.str = headerFindI18NString(h, entry);
    01644 /*@=dependenttrans@*/
    01645             break;
    01646         }
    01647         /*@fallthrough@*/
    01648     default:
    01649         rc = copyEntry(entry, he, minMem);
    01650         break;
    01651     }
    01652
    01653     /* XXX 1 on success */
    01654     return (rc == 1 ? 1 : 0);
    01655 }
    01656
    01664 static int copyData(char * t, const HE_t he, size_t nb)
    01665         /*@modifies *t @*/
    01666 {
    01667     int rc = 0;         /* assume success */
    01668
    01669     switch (he->t) {
    01670     case RPM_I18NSTRING_TYPE:
    01671     case RPM_STRING_ARRAY_TYPE:
    01672     {   const char ** av = he->p.argv;
    01673         rpmTagCount cnt = he->c;
    01674         const char * s;
    01675
    01676         while (cnt-- > 0 && nb > 0) {
    01677             if ((s = *av++) != NULL)
    01678             do {
    01679                 *t++ = *s++;
    01680             } while (s[-1] && --nb > 0);
    01681         }
    01682     }   break;
    01683     default:
    01684         if (tagSwab((unsigned char *)t, he, nb) == NULL)
    01685             rc = 1;
    01686         break;
    01687     }
    01688     return rc;
    01689 }
    01690
    01697 /*@null@*/
    01698 static void *
    01699 grabData(HE_t he, /*@out@*/ size_t * lenp)
    01700         /*@modifies *lenp @*/
    01701 {
    01702     size_t nb = dataLength(he->t, &he->p, he->c, 0, NULL);
    01703     char * t = NULL;
    01704
    01705     if (nb > 0) {
    01706         t = xmalloc(nb);
    01707         if (copyData(t, he, nb)) {
    01708             t = _free(t);
    01709             nb = 0;
    01710         }
    01711     }
    01712     if (lenp)
    01713         *lenp = nb;
    01714     return t;
    01715 }
    01716
    01728 static
    01729 int headerAddEntry(Header h, HE_t he)
    01730         /*@modifies h @*/
    01731 {
    01732     indexEntry entry;
    01733     rpmTagData data;
    01734     size_t length = 0;
    01735     int rc = 0;         /* assume failure */
    01736
    01737     /* Count must always be >= 1 for headerAddEntry. */
    01738     if (he->c == 0)
    01739         return rc;
    01740
    01741     if (hdrchkType(he->t))
    01742         return rc;
    01743     if (hdrchkData(he->c))
    01744         return rc;
    01745
    01746     data.ptr = grabData(he, &length);
    01747     if (data.ptr == NULL || length == 0)
    01748         return rc;
    01749
    01750     /* Allocate more index space if necessary */
    01751     if (h->indexUsed == h->indexAlloced) {
    01752         h->indexAlloced += INDEX_MALLOC_SIZE;
    01753         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
    01754     }
    01755
    01756     /* Fill in the index */
    01757     entry = h->index + h->indexUsed;
    01758     entry->info.tag = he->tag;
    01759     entry->info.type = he->t;
    01760     entry->info.count = he->c;
    01761     entry->info.offset = 0;
    01762     entry->data = data.ptr;
    01763     entry->length = length;
    01764
    01765     if (h->indexUsed > 0 && he->tag < h->index[h->indexUsed-1].info.tag)
    01766         h->flags &= ~HEADERFLAG_SORTED;
    01767     h->indexUsed++;
    01768     rc = 1;
    01769
    01770     return rc;
    01771 }
    01772
    01782 static
    01783 int headerAppendEntry(Header h, HE_t he)
    01784         /*@modifies h @*/
    01785 {
    01786     rpmTagData src = { .ptr = he->p.ptr };
    01787     char * t;
    01788     indexEntry entry;
    01789     size_t length;
    01790     int rc = 0;         /* assume failure */
    01791
    01792     if (he->t == RPM_STRING_TYPE || he->t == RPM_I18NSTRING_TYPE) {
    01793         /* we can't do this */
    01794         return rc;
    01795     }
    01796
    01797     /* Find the tag entry in the header. */
    01798     entry = findEntry(h, he->tag, he->t);
    01799     if (!entry)
    01800         return rc;
    01801
    01802     length = dataLength(he->t, &src, he->c, 0, NULL);
    01803     if (length == 0)
    01804         return rc;
    01805
    01806     if (ENTRY_IN_REGION(entry)) {
    01807         char * t = xmalloc(entry->length + length);
    01808         memcpy(t, entry->data, entry->length);
    01809         entry->data = t;
    01810         entry->info.offset = 0;
    01811     } else
    01812         entry->data = xrealloc(entry->data, entry->length + length);
    01813
    01814     t = ((char *) entry->data) + entry->length;
    01815     if (!copyData(t, he, length))
    01816         rc = 1;
    01817
    01818     entry->length += length;
    01819
    01820     entry->info.count += he->c;
    01821
    01822     return rc;
    01823 }
    01824
    01831 static
    01832 int headerAddOrAppendEntry(Header h, HE_t he)
    01833         /*@modifies h @*/
    01834 {
    01835     return (findEntry(h, he->tag, he->t)
    01836         ? headerAppendEntry(h, he)
    01837         : headerAddEntry(h, he));
    01838 }
    01839
    01840 int headerAddI18NString(Header h, rpmTag tag, const char * string,
    01841                 const char * lang)
    01842 {
    01843     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    01844     indexEntry table, entry;
    01845     rpmTagData p;
    01846     size_t length;
    01847     size_t ghosts;
    01848     rpmuint32_t i;
    01849     rpmuint32_t langNum;
    01850     char * buf;
    01851     int xx;
    01852
    01853     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
    01854     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
    01855
    01856     if (!table && entry)
    01857         return 0;               /* this shouldn't ever happen!! */
    01858
    01859     if (!table && !entry) {
    01860         const char * argv[2];
    01861         int count = 0;
    01862         p.argv = argv;
    01863         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
    01864             /*@-observertrans -readonlytrans@*/
    01865             p.argv[count++] = "C";
    01866             /*@=observertrans =readonlytrans@*/
    01867         } else {
    01868             /*@-observertrans -readonlytrans@*/
    01869             p.argv[count++] = "C";
    01870             /*@=observertrans =readonlytrans@*/
    01871             p.argv[count++] = lang;
    01872         }
    01873         he->tag = HEADER_I18NTABLE;
    01874         he->t = RPM_STRING_ARRAY_TYPE;
    01875         he->p.ptr = p.ptr;
    01876         he->c = count;
    01877         xx = headerAddEntry(h, he);
    01878         if (!xx)
    01879             return 0;
    01880         table = findEntry(h, he->tag, he->t);
    01881     }
    01882
    01883     if (!table)
    01884         return 0;
    01885     if (!lang) lang = "C";
    01886
    01887     {   const char * l = table->data;
    01888         for (langNum = 0; langNum < table->info.count; langNum++) {
    01889             if (!strcmp(l, lang)) break;
    01890             l += strlen(l) + 1;
    01891         }
    01892     }
    01893
    01894     if (langNum >= table->info.count) {
    01895         length = strlen(lang) + 1;
    01896         if (ENTRY_IN_REGION(table)) {
    01897             char * t = xmalloc(table->length + length);
    01898             memcpy(t, table->data, table->length);
    01899             table->data = t;
    01900             table->info.offset = 0;
    01901         } else
    01902             table->data = xrealloc(table->data, table->length + length);
    01903         memmove(((char *)table->data) + table->length, lang, length);
    01904         table->length += length;
    01905         table->info.count++;
    01906     }
    01907
    01908     if (!entry) {
    01909         p.argv = alloca(sizeof(*p.argv) * (langNum + 1));
    01910 /*@-observertrans -readonlytrans@*/
    01911         for (i = 0; i < langNum; i++)
    01912             p.argv[i] = "";
    01913 /*@=observertrans =readonlytrans@*/
    01914         p.argv[langNum] = string;
    01915         he->tag = tag;
    01916         he->t = RPM_I18NSTRING_TYPE;
    01917         he->p.ptr = p.ptr;
    01918         he->c = langNum + 1;
    01919 /*@-compmempass@*/
    01920         xx = headerAddEntry(h, he);
    01921 /*@=compmempass@*/
    01922         return xx;
    01923     } else if (langNum >= entry->info.count) {
    01924         ghosts = langNum - entry->info.count;
    01925
    01926         length = strlen(string) + 1 + ghosts;
    01927         if (ENTRY_IN_REGION(entry)) {
    01928             char * t = xmalloc(entry->length + length);
    01929             memcpy(t, entry->data, entry->length);
    01930             entry->data = t;
    01931             entry->info.offset = 0;
    01932         } else
    01933             entry->data = xrealloc(entry->data, entry->length + length);
    01934
    01935         memset(((char *)entry->data) + entry->length, 0, ghosts);
    01936         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
    01937
    01938         entry->length += length;
    01939         entry->info.count = langNum + 1;
    01940     } else {
    01941         char *b, *be, *e, *ee, *t;
    01942         size_t bn, sn, en;
    01943
    01944         /* Set beginning/end pointers to previous data */
    01945         b = be = e = ee = entry->data;
    01946         for (i = 0; i < table->info.count; i++) {
    01947             if (i == langNum)
    01948                 be = ee;
    01949             ee += strlen(ee) + 1;
    01950             if (i == langNum)
    01951                 e  = ee;
    01952         }
    01953
    01954         /* Get storage for new buffer */
    01955         bn = (be-b);
    01956         sn = strlen(string) + 1;
    01957         en = (ee-e);
    01958         length = bn + sn + en;
    01959         t = buf = xmalloc(length);
    01960
    01961         /* Copy values into new storage */
    01962         memcpy(t, b, bn);
    01963         t += bn;
    01964 /*@-mayaliasunique@*/
    01965         memcpy(t, string, sn);
    01966         t += sn;
    01967         memcpy(t, e, en);
    01968         t += en;
    01969 /*@=mayaliasunique@*/
    01970
    01971         /* Replace i18N string array */
    01972         entry->length -= strlen(be) + 1;
    01973         entry->length += sn;
    01974
    01975         if (ENTRY_IN_REGION(entry)) {
    01976             entry->info.offset = 0;
    01977         } else
    01978             entry->data = _free(entry->data);
    01979         /*@-dependenttrans@*/
    01980         entry->data = buf;
    01981         /*@=dependenttrans@*/
    01982     }
    01983
    01984     return 0;
    01985 }
    01986
    01994 static
    01995 int headerModifyEntry(Header h, HE_t he)
    01996         /*@modifies h @*/
    01997 {
    01998     indexEntry entry;
    01999     rpmTagData oldData;
    02000     rpmTagData newData;
    02001     size_t length = 0;
    02002
    02003     /* First find the tag */
    02004     entry = findEntry(h, he->tag, he->t);
    02005     if (!entry)
    02006         return 0;
    02007
    02008     newData.ptr = grabData(he, &length);
    02009     if (newData.ptr == NULL || length == 0)
    02010         return 0;
    02011
    02012     /* make sure entry points to the first occurence of this tag */
    02013     while (entry > h->index && (entry - 1)->info.tag == he->tag)
    02014         entry--;
    02015
    02016     /* free after we've grabbed the new data in case the two are intertwined;
    02017        that's a bad idea but at least we won't break */
    02018     oldData.ptr = entry->data;
    02019
    02020     entry->info.count = he->c;
    02021     entry->info.type = he->t;
    02022     entry->data = newData.ptr;
    02023     entry->length = length;
    02024
    02025     if (ENTRY_IN_REGION(entry)) {
    02026         entry->info.offset = 0;
    02027     } else
    02028         oldData.ptr = _free(oldData.ptr);
    02029
    02030     return 1;
    02031 }
    02032
    02036 struct headerIterator_s {
    02037     Header h;
    02038     size_t next_index;
    02039 };
    02040
    02041 HeaderIterator headerFini(/*@only@*/ HeaderIterator hi)
    02042 {
    02043     if (hi != NULL) {
    02044         (void)headerFree(hi->h);
    02045         hi->h = NULL;
    02046         hi = _free(hi);
    02047     }
    02048     return hi;
    02049 }
    02050
    02051 HeaderIterator headerInit(Header h)
    02052 {
    02053     HeaderIterator hi = xmalloc(sizeof(*hi));
    02054
    02055     headerSort(h);
    02056
    02057 /*@-assignexpose -castexpose @*/
    02058     hi->h = headerLink(h);
    02059 /*@=assignexpose =castexpose @*/
    02060 assert(hi->h != NULL);
    02061     hi->next_index = 0;
    02062     return hi;
    02063 }
    02064
    02065 int headerNext(HeaderIterator hi, HE_t he, /*@unused@*/ unsigned int flags)
    02066 {
    02067     void * sw;
    02068     Header h = hi->h;
    02069     size_t slot = hi->next_index;
    02070     indexEntry entry = NULL;
    02071     int rc;
    02072
    02073     /* Insure that *he is reliably initialized. */
    02074     memset(he, 0, sizeof(*he));
    02075
    02076     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
    02077         entry = h->index + slot;
    02078         if (!ENTRY_IS_REGION(entry))
    02079             break;
    02080     }
    02081     hi->next_index = slot;
    02082     if (entry == NULL || slot >= h->indexUsed)
    02083         return 0;
    02084
    02085     hi->next_index++;
    02086
    02087     if ((sw = headerGetStats(h, 19)) != NULL)   /* RPMTS_OP_HDRGET */
    02088         (void) rpmswEnter(sw, 0);
    02089
    02090     he->tag = entry->info.tag;
    02091     rc = copyEntry(entry, he, 0);
    02092     if (rc)
    02093         rc = rpmheRealloc(he);
    02094
    02095     if (sw != NULL)     (void) rpmswExit(sw, 0);
    02096
    02097     /* XXX 1 on success */
    02098     return ((rc == 1) ? 1 : 0);
    02099 }
    02100
    02101 Header headerCopy(Header h)
    02102 {
    02103     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    02104     Header nh = headerNew();
    02105     HeaderIterator hi;
    02106
    02107     for (hi = headerInit(h);
    02108         headerNext(hi, he, 0);
    02109         he->p.ptr = _free(he->p.ptr))
    02110     {
    02111         if (he->p.ptr) (void) headerAddEntry(nh, he);
    02112     }
    02113     hi = headerFini(hi);
    02114
    02115     return headerReload(nh, HEADER_IMAGE);
    02116 }
    02117
    02118 void headerCopyTags(Header headerFrom, Header headerTo, rpmTag * tagstocopy)
    02119 {
    02120     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    02121     rpmTag * tagno;
    02122     int xx;
    02123
    02124     if (headerFrom == headerTo)
    02125         return;
    02126
    02127     for (tagno = tagstocopy; *tagno != 0; tagno++) {
    02128         if (headerIsEntry(headerTo, *tagno))
    02129             continue;
    02130         he->tag = *tagno;
    02131         if (!headerGet(headerFrom, he, 0))
    02132             continue;
    02133         xx = headerPut(headerTo, he, 0);
    02134         he->p.ptr = _free(he->p.ptr);
    02135     }
    02136 }
    02137
    02138 int headerGet(Header h, HE_t he, unsigned int flags)
    02139 {
    02140     void * sw;
    02141     const char * name;
    02142     headerSprintfExtension exts = headerCompoundFormats;
    02143     headerSprintfExtension ext = NULL;
    02144     int extNum;
    02145     int rc;
    02146
    02147     if (h == NULL || he == NULL)        return 0;       /* XXX this is nutty. */
    02148
    02149     /* Insure that *he is reliably initialized. */
    02150     {   rpmTag tag = he->tag;
    02151         memset(he, 0, sizeof(*he));
    02152         he->tag = tag;
    02153     }
    02154     name = tagName(he->tag);
    02155
    02156     if ((sw = headerGetStats(h, 19)) != NULL)   /* RPMTS_OP_HDRGET */
    02157         (void) rpmswEnter(sw, 0);
    02158
    02159     /* Search extensions for specific tag override. */
    02160     if (!(flags & HEADERGET_NOEXTENSION))
    02161     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
    02162         ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
    02163     {
    02164         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
    02165             continue;
    02166         if (!xstrcasecmp(ext->name + (sizeof("RPMTAG_")-1), name))
    02167             break;
    02168     }
    02169
    02170     if (ext && ext->name != NULL && ext->type == HEADER_EXT_TAG) {
    02171         rc = ext->u.tagFunction(h, he);
    02172         rc = (rc == 0);         /* XXX invert extension return. */
    02173     } else
    02174         rc = intGetEntry(h, he, flags);
    02175
    02176     if (rc)
    02177         rc = rpmheRealloc(he);
    02178
    02179     if (sw != NULL)     (void) rpmswExit(sw, 0);
    02180
    02181 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
    02182 /*@-modfilesys@*/
    02183     /* XXX verify that explicit and implicit types are identical. */
    02184     if (rc)
    02185         tagTypeValidate(he);
    02186 /*@=modfilesys@*/
    02187 #endif
    02188
    02189 /*@-modfilesys@*/
    02190     if (!((rc == 0 && he->freeData == 0 && he->p.ptr == NULL) ||
    02191           (rc == 1 && he->freeData == 1 && he->p.ptr != NULL)))
    02192     {
    02193 if (_hdr_debug)
    02194 fprintf(stderr, "==> %s(%u) %u %p[%u] free %u rc %d\n", name, (unsigned) he->tag, (unsigned) he->t, he->p.ptr, (unsigned) he->c, he->freeData, rc);
    02195     }
    02196 /*@=modfilesys@*/
    02197
    02198     return rc;
    02199 }
    02200
    02201 int headerPut(Header h, HE_t he, /*@unused@*/ unsigned int flags)
    02202 {
    02203     int rc;
    02204
    02205 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
    02206 /*@-modfilesys@*/
    02207     /* XXX verify that explicit and implicit types are identical. */
    02208     tagTypeValidate(he);
    02209 /*@=modfilesys@*/
    02210 #endif
    02211
    02212     if (he->append)
    02213         rc = headerAddOrAppendEntry(h, he);
    02214     else
    02215         rc = headerAddEntry(h, he);
    02216
    02217     return rc;
    02218 }
    02219
    02220 int headerDel(Header h, HE_t he, /*@unused@*/ unsigned int flags)
    02221         /*@modifies h @*/
    02222 {
    02223     return headerRemoveEntry(h, he->tag);
    02224 }
    02225
    02226 int headerMod(Header h, HE_t he, /*@unused@*/ unsigned int flags)
    02227         /*@modifies h @*/
    02228 {
    02229
    02230 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
    02231 /*@-modfilesys@*/
    02232     /* XXX verify that explicit and implicit types are identical. */
    02233     tagTypeValidate(he);
    02234 /*@=modfilesys@*/
    02235 #endif
    02236
    02237     return headerModifyEntry(h, he);
    02238 }