• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

rpmdb/header.c

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

Generated on Fri Dec 3 2010 20:54:05 for rpm by  doxygen 1.7.2