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