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