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 #define __HEADER_PROTOTYPES__
00014 
00015 #include <rpmio_internal.h>     /* XXX for fdGetOPath() */
00016 #include <header_internal.h>
00017 
00018 #include "debug.h"
00019 
00020 /*@unchecked@*/
00021 int _hdr_debug = 0;
00022 
00023 /*@access entryInfo @*/
00024 /*@access indexEntry @*/
00025 
00026 /*@access rpmec @*/
00027 /*@access sprintfTag @*/
00028 /*@access sprintfToken @*/
00029 /*@access HV_t @*/
00030 
00031 #define PARSER_BEGIN    0
00032 #define PARSER_IN_ARRAY 1
00033 #define PARSER_IN_EXPR  2
00034 
00037 /*@observer@*/ /*@unchecked@*/
00038 static unsigned char header_magic[8] = {
00039         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00040 };
00041 
00045 /*@observer@*/ /*@unchecked@*/
00046 static int typeAlign[16] =  {
00047     1,  
00048     1,  
00049     1,  
00050     2,  
00051     4,  
00052     8,  
00053     1,  
00054     1,  
00055     1,  
00056     1,  
00057     1,  
00058     1,  
00059     0,
00060     0,
00061     0,
00062     0
00063 };
00064 
00068 /*@observer@*/ /*@unchecked@*/
00069 static int typeSizes[16] =  { 
00070     0,  
00071     1,  
00072     1,  
00073     2,  
00074     4,  
00075     8,  
00076     -1, 
00077     1,  
00078     -1, 
00079     -1, 
00080     1,  
00081     1,  
00082     0,
00083     0,
00084     0,
00085     0
00086 };
00087 
00091 /*@unchecked@*/
00092 static size_t headerMaxbytes = (32*1024*1024);
00093 
00098 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00099 
00103 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00104 
00109 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
00110 
00114 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
00115 
00119 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
00120 
00121 /*@observer@*/ /*@unchecked@*/
00122 HV_t hdrVec;    /* forward reference */
00123 
00129 /*@unused@*/ static inline /*@null@*/ void *
00130 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) /*@modifies *p @*/
00131 {
00132     if (p != NULL)      free((void *)p);
00133     return NULL;
00134 }
00135 
00141 static
00142 Header headerLink(Header h)
00143         /*@modifies h @*/
00144 {
00145 /*@-nullret@*/
00146     if (h == NULL) return NULL;
00147 /*@=nullret@*/
00148 
00149     h->nrefs++;
00150 /*@-modfilesys@*/
00151 if (_hdr_debug)
00152 fprintf(stderr, "--> h  %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00153 /*@=modfilesys@*/
00154 
00155     /*@-refcounttrans @*/
00156     return h;
00157     /*@=refcounttrans @*/
00158 }
00159 
00165 static /*@null@*/
00166 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h)
00167         /*@modifies h @*/
00168 {
00169     if (h == NULL) return NULL;
00170 /*@-modfilesys@*/
00171 if (_hdr_debug)
00172 fprintf(stderr, "--> h  %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00173 /*@=modfilesys@*/
00174     h->nrefs--;
00175     return NULL;
00176 }
00177 
00183 static /*@null@*/
00184 Header headerFree(/*@killref@*/ /*@null@*/ Header h)
00185         /*@modifies h @*/
00186 {
00187     (void) headerUnlink(h);
00188 
00189     /*@-usereleased@*/
00190     if (h == NULL || h->nrefs > 0)
00191         return NULL;    /* XXX return previous header? */
00192 
00193     if (h->index) {
00194         indexEntry entry = h->index;
00195         int i;
00196         for (i = 0; i < h->indexUsed; i++, entry++) {
00197             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00198                 if (entry->length > 0) {
00199                     int_32 * ei = entry->data;
00200                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00201                     entry->data = NULL;
00202                 }
00203             } else if (!ENTRY_IN_REGION(entry)) {
00204                 entry->data = _free(entry->data);
00205             }
00206             entry->data = NULL;
00207         }
00208         h->index = _free(h->index);
00209     }
00210     h->origin = _free(h->origin);
00211 
00212     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
00213     return h;
00214     /*@=usereleased@*/
00215 }
00216 
00221 static
00222 Header headerNew(void)
00223         /*@*/
00224 {
00225     Header h = xcalloc(1, sizeof(*h));
00226 
00227 /*@-boundsread@*/
00228     /*@-assignexpose@*/
00229     h->hv = *hdrVec;            /* structure assignment */
00230     /*@=assignexpose@*/
00231 /*@=boundsread@*/
00232     h->blob = NULL;
00233     h->origin = NULL;
00234     h->instance = 0;
00235     h->indexAlloced = INDEX_MALLOC_SIZE;
00236     h->indexUsed = 0;
00237     h->flags |= HEADERFLAG_SORTED;
00238 
00239     h->index = (h->indexAlloced
00240         ? xcalloc(h->indexAlloced, sizeof(*h->index))
00241         : NULL);
00242 
00243     h->nrefs = 0;
00244     /*@-globstate -observertrans @*/
00245     return headerLink(h);
00246     /*@=globstate =observertrans @*/
00247 }
00248 
00251 static int indexCmp(const void * avp, const void * bvp)
00252         /*@*/
00253 {
00254     /*@-castexpose@*/
00255     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00256     /*@=castexpose@*/
00257     return (ap->info.tag - bp->info.tag);
00258 }
00259 
00264 static
00265 void headerSort(Header h)
00266         /*@modifies h @*/
00267 {
00268     if (!(h->flags & HEADERFLAG_SORTED)) {
00269 /*@-boundsread@*/
00270         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00271 /*@=boundsread@*/
00272         h->flags |= HEADERFLAG_SORTED;
00273     }
00274 }
00275 
00278 static int offsetCmp(const void * avp, const void * bvp) /*@*/
00279 {
00280     /*@-castexpose@*/
00281     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00282     /*@=castexpose@*/
00283     int rc = (ap->info.offset - bp->info.offset);
00284 
00285     if (rc == 0) {
00286         /* Within a region, entries sort by address. Added drips sort by tag. */
00287         if (ap->info.offset < 0)
00288             rc = (((char *)ap->data) - ((char *)bp->data));
00289         else
00290             rc = (ap->info.tag - bp->info.tag);
00291     }
00292     return rc;
00293 }
00294 
00299 static
00300 void headerUnsort(Header h)
00301         /*@modifies h @*/
00302 {
00303 /*@-boundsread@*/
00304     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00305 /*@=boundsread@*/
00306 }
00307 
00314 static
00315 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp)
00316         /*@modifies h @*/
00317 {
00318     indexEntry entry;
00319     unsigned int size = 0;
00320     unsigned int pad = 0;
00321     int i;
00322 
00323     if (h == NULL)
00324         return size;
00325 
00326     headerSort(h);
00327 
00328     switch (magicp) {
00329     case HEADER_MAGIC_YES:
00330         size += sizeof(header_magic);
00331         break;
00332     case HEADER_MAGIC_NO:
00333         break;
00334     }
00335 
00336     /*@-sizeoftype@*/
00337     size += 2 * sizeof(int_32); /* count of index entries */
00338     /*@=sizeoftype@*/
00339 
00340     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00341         unsigned diff;
00342         int_32 type;
00343 
00344         /* Regions go in as is ... */
00345         if (ENTRY_IS_REGION(entry)) {
00346             size += entry->length;
00347             /* XXX Legacy regions do not include the region tag and data. */
00348             /*@-sizeoftype@*/
00349             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00350                 size += sizeof(struct entryInfo_s) + entry->info.count;
00351             /*@=sizeoftype@*/
00352             continue;
00353         }
00354 
00355         /* ... and region elements are skipped. */
00356         if (entry->info.offset < 0)
00357             continue;
00358 
00359         /* Alignment */
00360         type = entry->info.type;
00361 /*@-boundsread@*/
00362         if (typeSizes[type] > 1) {
00363             diff = typeSizes[type] - (size % typeSizes[type]);
00364             if (diff != typeSizes[type]) {
00365                 size += diff;
00366                 pad += diff;
00367             }
00368         }
00369 /*@=boundsread@*/
00370 
00371         /*@-sizeoftype@*/
00372         size += sizeof(struct entryInfo_s) + entry->length;
00373         /*@=sizeoftype@*/
00374     }
00375 
00376     return size;
00377 }
00378 
00388 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00389                 /*@null@*/ hPTR_t pend)
00390         /*@*/
00391 {
00392     const unsigned char * s = p;
00393     const unsigned char * se = pend;
00394     int length = 0;
00395 
00396     switch (type) {
00397     case RPM_STRING_TYPE:
00398         if (count != 1)
00399             return -1;
00400 /*@-boundsread@*/
00401         while (*s++) {
00402             if (se && s > se)
00403                 return -1;
00404             length++;
00405         }
00406 /*@=boundsread@*/
00407         length++;       /* count nul terminator too. */
00408         break;
00409 
00410     case RPM_STRING_ARRAY_TYPE:
00411     case RPM_I18NSTRING_TYPE:
00412         /* These are like RPM_STRING_TYPE, except they're *always* an array */
00413         /* Compute sum of length of all strings, including nul terminators */
00414 
00415         if (onDisk) {
00416             while (count--) {
00417                 length++;       /* count nul terminator too */
00418 /*@-boundsread@*/
00419                while (*s++) {
00420                     if (se && s > se)
00421                         return -1;
00422                     length++;
00423                 }
00424 /*@=boundsread@*/
00425             }
00426         } else {
00427             const char ** av = (const char **)p;
00428 /*@-boundsread@*/
00429             while (count--) {
00430                 /* add one for null termination */
00431                 length += strlen(*av++) + 1;
00432             }
00433 /*@=boundsread@*/
00434         }
00435         break;
00436 
00437     default:
00438 /*@-boundsread@*/
00439         if (typeSizes[type] == -1)
00440             return -1;
00441         length = typeSizes[(type & 0xf)] * count;
00442 /*@=boundsread@*/
00443         if (length < 0 || (se && (s + length) > se))
00444             return -1;
00445         break;
00446     }
00447 
00448     return length;
00449 }
00450 
00477 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
00478                 entryInfo pe,
00479                 unsigned char * dataStart,
00480                 /*@null@*/ const unsigned char * dataEnd,
00481                 int regionid)
00482         /*@modifies *entry, *dataStart @*/
00483 {
00484     unsigned char * tprev = NULL;
00485     unsigned char * t = NULL;
00486     int tdel = 0;
00487     int tl = dl;
00488     struct indexEntry_s ieprev;
00489 
00490 /*@-boundswrite@*/
00491     memset(&ieprev, 0, sizeof(ieprev));
00492 /*@=boundswrite@*/
00493     for (; il > 0; il--, pe++) {
00494         struct indexEntry_s ie;
00495         int_32 type;
00496 
00497         ie.info.tag = ntohl(pe->tag);
00498         ie.info.type = ntohl(pe->type);
00499         ie.info.count = ntohl(pe->count);
00500         ie.info.offset = ntohl(pe->offset);
00501 
00502         if (hdrchkType(ie.info.type))
00503             return -1;
00504         if (hdrchkData(ie.info.count))
00505             return -1;
00506         if (hdrchkData(ie.info.offset))
00507             return -1;
00508 /*@-boundsread@*/
00509         if (hdrchkAlign(ie.info.type, ie.info.offset))
00510             return -1;
00511 /*@=boundsread@*/
00512 
00513         ie.data = t = dataStart + ie.info.offset;
00514         if (dataEnd && t >= dataEnd)
00515             return -1;
00516 
00517         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00518         if (ie.length < 0 || hdrchkData(ie.length))
00519             return -1;
00520 
00521         ie.rdlen = 0;
00522 
00523         if (entry) {
00524             ie.info.offset = regionid;
00525 /*@-boundswrite@*/
00526             *entry = ie;        /* structure assignment */
00527 /*@=boundswrite@*/
00528             entry++;
00529         }
00530 
00531         /* Alignment */
00532         type = ie.info.type;
00533 /*@-boundsread@*/
00534         if (typeSizes[type] > 1) {
00535             unsigned diff;
00536             diff = typeSizes[type] - (dl % typeSizes[type]);
00537             if (diff != typeSizes[type]) {
00538                 dl += diff;
00539                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00540                     ieprev.length += diff;
00541             }
00542         }
00543 /*@=boundsread@*/
00544         tdel = (tprev ? (t - tprev) : 0);
00545         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00546             tdel = ieprev.length;
00547 
00548         if (ie.info.tag >= HEADER_I18NTABLE) {
00549             tprev = t;
00550         } else {
00551             tprev = dataStart;
00552             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00553             /*@-sizeoftype@*/
00554             if (ie.info.tag == HEADER_IMAGE)
00555                 tprev -= REGION_TAG_COUNT;
00556             /*@=sizeoftype@*/
00557         }
00558 
00559         /* Perform endian conversions */
00560         switch (ntohl(pe->type)) {
00561 /*@-bounds@*/
00562         case RPM_INT64_TYPE:
00563         {   int_64 * it = (int_64 *)t;
00564             int_32 b[2];
00565             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00566                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00567                     return -1;
00568                 b[1] = htonl(((int_32 *)it)[0]);
00569                 b[0] = htonl(((int_32 *)it)[1]);
00570                 if (b[1] != ((int_32 *)it)[0])
00571                     memcpy(it, b, sizeof(b));
00572             }
00573             t = (char *) it;
00574         }   /*@switchbreak@*/ break;
00575         case RPM_INT32_TYPE:
00576         {   int_32 * it = (int_32 *)t;
00577             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00578                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00579                     return -1;
00580                 *it = htonl(*it);
00581             }
00582             t = (char *) it;
00583         }   /*@switchbreak@*/ break;
00584         case RPM_INT16_TYPE:
00585         {   int_16 * it = (int_16 *) t;
00586             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00587                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00588                     return -1;
00589                 *it = htons(*it);
00590             }
00591             t = (char *) it;
00592         }   /*@switchbreak@*/ break;
00593 /*@=bounds@*/
00594         default:
00595             t += ie.length;
00596             /*@switchbreak@*/ break;
00597         }
00598 
00599         dl += ie.length;
00600         if (dataEnd && dataStart + dl > dataEnd) return -1;
00601         tl += tdel;
00602         ieprev = ie;    /* structure assignment */
00603 
00604     }
00605     tdel = (tprev ? (t - tprev) : 0);
00606     tl += tdel;
00607 
00608     /* XXX
00609      * There are two hacks here:
00610      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00611      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00612      */
00613     /*@-sizeoftype@*/
00614     if (tl+REGION_TAG_COUNT == dl)
00615         tl += REGION_TAG_COUNT;
00616     /*@=sizeoftype@*/
00617 
00618     return dl;
00619 }
00620 
00626 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
00627                 /*@out@*/ int * lengthPtr)
00628         /*@modifies h, *lengthPtr @*/
00629         /*@requires maxSet(lengthPtr) >= 0 @*/
00630         /*@ensures maxRead(result) == (*lengthPtr) @*/
00631 {
00632     int_32 * ei = NULL;
00633     entryInfo pe;
00634     char * dataStart;
00635     char * te;
00636     unsigned pad;
00637     unsigned len;
00638     int_32 il = 0;
00639     int_32 dl = 0;
00640     indexEntry entry; 
00641     int_32 type;
00642     int i;
00643     int drlen, ndribbles;
00644     int driplen, ndrips;
00645     int legacy = 0;
00646 
00647     /* Sort entries by (offset,tag). */
00648     headerUnsort(h);
00649 
00650     /* Compute (il,dl) for all tags, including those deleted in region. */
00651     pad = 0;
00652     drlen = ndribbles = driplen = ndrips = 0;
00653     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00654         if (ENTRY_IS_REGION(entry)) {
00655             int_32 rdl = -entry->info.offset;   /* negative offset */
00656             int_32 ril = rdl/sizeof(*pe);
00657             int rid = entry->info.offset;
00658 
00659             il += ril;
00660             dl += entry->rdlen + entry->info.count;
00661             /* XXX Legacy regions do not include the region tag and data. */
00662             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00663                 il += 1;
00664 
00665             /* Skip rest of entries in region, but account for dribbles. */
00666             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00667                 if (entry->info.offset <= rid)
00668                     /*@innercontinue@*/ continue;
00669 
00670                 /* Alignment */
00671                 type = entry->info.type;
00672                 if (typeSizes[type] > 1) {
00673                     unsigned diff;
00674                     diff = typeSizes[type] - (dl % typeSizes[type]);
00675                     if (diff != typeSizes[type]) {
00676                         drlen += diff;
00677                         pad += diff;
00678                         dl += diff;
00679                     }
00680                 }
00681 
00682                 ndribbles++;
00683                 il++;
00684                 drlen += entry->length;
00685                 dl += entry->length;
00686             }
00687             i--;
00688             entry--;
00689             continue;
00690         }
00691 
00692         /* Ignore deleted drips. */
00693         if (entry->data == NULL || entry->length <= 0)
00694             continue;
00695 
00696         /* Alignment */
00697         type = entry->info.type;
00698         if (typeSizes[type] > 1) {
00699             unsigned diff;
00700             diff = typeSizes[type] - (dl % typeSizes[type]);
00701             if (diff != typeSizes[type]) {
00702                 driplen += diff;
00703                 pad += diff;
00704                 dl += diff;
00705             } else
00706                 diff = 0;
00707         }
00708 
00709         ndrips++;
00710         il++;
00711         driplen += entry->length;
00712         dl += entry->length;
00713     }
00714 
00715     /* Sanity checks on header intro. */
00716     if (hdrchkTags(il) || hdrchkData(dl))
00717         goto errxit;
00718 
00719     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00720 
00721 /*@-boundswrite@*/
00722     ei = xmalloc(len);
00723     ei[0] = htonl(il);
00724     ei[1] = htonl(dl);
00725 /*@=boundswrite@*/
00726 
00727     pe = (entryInfo) &ei[2];
00728     dataStart = te = (char *) (pe + il);
00729 
00730     pad = 0;
00731     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00732         const char * src;
00733 char *t;
00734         int count;
00735         int rdlen;
00736 
00737         if (entry->data == NULL || entry->length <= 0)
00738             continue;
00739 
00740 t = te;
00741         pe->tag = htonl(entry->info.tag);
00742         pe->type = htonl(entry->info.type);
00743         pe->count = htonl(entry->info.count);
00744 
00745         if (ENTRY_IS_REGION(entry)) {
00746             int_32 rdl = -entry->info.offset;   /* negative offset */
00747             int_32 ril = rdl/sizeof(*pe) + ndribbles;
00748             int rid = 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                 int_32 stei[4];
00756 
00757                 legacy = 1;
00758 /*@-boundswrite@*/
00759                 memcpy(pe+1, src, rdl);
00760                 memcpy(te, src + rdl, rdlen);
00761 /*@=boundswrite@*/
00762                 te += rdlen;
00763 
00764                 pe->offset = htonl(te - dataStart);
00765                 stei[0] = pe->tag;
00766                 stei[1] = pe->type;
00767                 stei[2] = htonl(-rdl-entry->info.count);
00768                 stei[3] = pe->count;
00769 /*@-boundswrite@*/
00770                 memcpy(te, stei, entry->info.count);
00771 /*@=boundswrite@*/
00772                 te += entry->info.count;
00773                 ril++;
00774                 rdlen += entry->info.count;
00775 
00776                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00777                 if (count != rdlen)
00778                     goto errxit;
00779 
00780             } else {
00781 
00782 /*@-boundswrite@*/
00783                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00784                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00785 /*@=boundswrite@*/
00786                 te += rdlen;
00787                 {   /*@-castexpose@*/
00788                     entryInfo se = (entryInfo)src;
00789                     /*@=castexpose@*/
00790                     int off = ntohl(se->offset);
00791                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00792                 }
00793                 te += entry->info.count + drlen;
00794 
00795                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00796                 if (count != (rdlen + entry->info.count + drlen))
00797                     goto errxit;
00798             }
00799 
00800             /* Skip rest of entries in region. */
00801             while (i < h->indexUsed && entry->info.offset <= rid+1) {
00802                 i++;
00803                 entry++;
00804             }
00805             i--;
00806             entry--;
00807             pe += ril;
00808             continue;
00809         }
00810 
00811         /* Ignore deleted drips. */
00812         if (entry->data == NULL || entry->length <= 0)
00813             continue;
00814 
00815         /* Alignment */
00816         type = entry->info.type;
00817         if (typeSizes[type] > 1) {
00818             unsigned diff;
00819             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00820             if (diff != typeSizes[type]) {
00821 /*@-boundswrite@*/
00822                 memset(te, 0, diff);
00823 /*@=boundswrite@*/
00824                 te += diff;
00825                 pad += diff;
00826             }
00827         }
00828 
00829         pe->offset = htonl(te - dataStart);
00830 
00831         /* copy data w/ endian conversions */
00832 /*@-boundswrite@*/
00833         switch (entry->info.type) {
00834         case RPM_INT64_TYPE:
00835         {   int_32 b[2];
00836             count = entry->info.count;
00837             src = entry->data;
00838             while (count--) {
00839                 b[1] = htonl(((int_32 *)src)[0]);
00840                 b[0] = htonl(((int_32 *)src)[1]);
00841                 if (b[1] == ((int_32 *)src)[0])
00842                     memcpy(te, src, sizeof(b));
00843                 else
00844                     memcpy(te, b, sizeof(b));
00845                 te += sizeof(b);
00846                 src += sizeof(b);
00847             }
00848         }   /*@switchbreak@*/ break;
00849 
00850         case RPM_INT32_TYPE:
00851             count = entry->info.count;
00852             src = entry->data;
00853             while (count--) {
00854                 *((int_32 *)te) = htonl(*((int_32 *)src));
00855                 /*@-sizeoftype@*/
00856                 te += sizeof(int_32);
00857                 src += sizeof(int_32);
00858                 /*@=sizeoftype@*/
00859             }
00860             /*@switchbreak@*/ break;
00861 
00862         case RPM_INT16_TYPE:
00863             count = entry->info.count;
00864             src = entry->data;
00865             while (count--) {
00866                 *((int_16 *)te) = htons(*((int_16 *)src));
00867                 /*@-sizeoftype@*/
00868                 te += sizeof(int_16);
00869                 src += sizeof(int_16);
00870                 /*@=sizeoftype@*/
00871             }
00872             /*@switchbreak@*/ break;
00873 
00874         default:
00875             memcpy(te, entry->data, entry->length);
00876             te += entry->length;
00877             /*@switchbreak@*/ break;
00878         }
00879 /*@=boundswrite@*/
00880         pe++;
00881     }
00882    
00883     /* Insure that there are no memcpy underruns/overruns. */
00884     if (((char *)pe) != dataStart)
00885         goto errxit;
00886     if ((((char *)ei)+len) != te)
00887         goto errxit;
00888 
00889     if (lengthPtr)
00890         *lengthPtr = len;
00891 
00892     h->flags &= ~HEADERFLAG_SORTED;
00893     headerSort(h);
00894 
00895     return (void *) ei;
00896 
00897 errxit:
00898     /*@-usereleased@*/
00899     ei = _free(ei);
00900     /*@=usereleased@*/
00901     return (void *) ei;
00902 }
00903 
00909 static /*@only@*/ /*@null@*/
00910 void * headerUnload(Header h)
00911         /*@modifies h @*/
00912 {
00913     int length;
00914 /*@-boundswrite@*/
00915     void * uh = doHeaderUnload(h, &length);
00916 /*@=boundswrite@*/
00917     return uh;
00918 }
00919 
00927 static /*@null@*/
00928 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
00929         /*@modifies h @*/
00930 {
00931     indexEntry entry, entry2, last;
00932     struct indexEntry_s key;
00933 
00934     if (h == NULL) return NULL;
00935     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00936 
00937     key.info.tag = tag;
00938 
00939 /*@-boundswrite@*/
00940     entry2 = entry = 
00941         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00942 /*@=boundswrite@*/
00943     if (entry == NULL)
00944         return NULL;
00945 
00946     if (type == RPM_NULL_TYPE)
00947         return entry;
00948 
00949     /* look backwards */
00950     while (entry->info.tag == tag && entry->info.type != type &&
00951            entry > h->index) entry--;
00952 
00953     if (entry->info.tag == tag && entry->info.type == type)
00954         return entry;
00955 
00956     last = h->index + h->indexUsed;
00957     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
00958     while (entry2->info.tag == tag && entry2->info.type != type &&
00959            entry2 < last) entry2++;
00960     /*@=usereleased@*/
00961 
00962     if (entry->info.tag == tag && entry->info.type == type)
00963         return entry;
00964 
00965     return NULL;
00966 }
00967 
00977 static
00978 int headerRemoveEntry(Header h, int_32 tag)
00979         /*@modifies h @*/
00980 {
00981     indexEntry last = h->index + h->indexUsed;
00982     indexEntry entry, first;
00983     int ne;
00984 
00985     entry = findEntry(h, tag, RPM_NULL_TYPE);
00986     if (!entry) return 1;
00987 
00988     /* Make sure entry points to the first occurence of this tag. */
00989     while (entry > h->index && (entry - 1)->info.tag == tag)  
00990         entry--;
00991 
00992     /* Free data for tags being removed. */
00993     for (first = entry; first < last; first++) {
00994         void * data;
00995         if (first->info.tag != tag)
00996             break;
00997         data = first->data;
00998         first->data = NULL;
00999         first->length = 0;
01000         if (ENTRY_IN_REGION(first))
01001             continue;
01002         data = _free(data);
01003     }
01004 
01005     ne = (first - entry);
01006     if (ne > 0) {
01007         h->indexUsed -= ne;
01008         ne = last - first;
01009 /*@-boundswrite@*/
01010         if (ne > 0)
01011             memmove(entry, first, (ne * sizeof(*entry)));
01012 /*@=boundswrite@*/
01013     }
01014 
01015     return 0;
01016 }
01017 
01023 static /*@null@*/
01024 Header headerLoad(/*@kept@*/ void * uh)
01025         /*@modifies uh @*/
01026 {
01027     int_32 * ei = (int_32 *) uh;
01028     int_32 il = ntohl(ei[0]);           /* index length */
01029     int_32 dl = ntohl(ei[1]);           /* data length */
01030     /*@-sizeoftype@*/
01031     size_t pvlen = sizeof(il) + sizeof(dl) +
01032                (il * sizeof(struct entryInfo_s)) + dl;
01033     /*@=sizeoftype@*/
01034     void * pv = uh;
01035     Header h = NULL;
01036     entryInfo pe;
01037     unsigned char * dataStart;
01038     unsigned char * dataEnd;
01039     indexEntry entry; 
01040     int rdlen;
01041     int i;
01042 
01043     /* Sanity checks on header intro. */
01044     if (hdrchkTags(il) || hdrchkData(dl))
01045         goto errxit;
01046 
01047     ei = (int_32 *) pv;
01048     /*@-castexpose@*/
01049     pe = (entryInfo) &ei[2];
01050     /*@=castexpose@*/
01051     dataStart = (unsigned char *) (pe + il);
01052     dataEnd = dataStart + dl;
01053 
01054     h = xcalloc(1, sizeof(*h));
01055     /*@-assignexpose@*/
01056     h->hv = *hdrVec;            /* structure assignment */
01057     /*@=assignexpose@*/
01058     /*@-assignexpose -kepttrans@*/
01059     h->blob = uh;
01060     /*@=assignexpose =kepttrans@*/
01061     h->indexAlloced = il + 1;
01062     h->indexUsed = il;
01063     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01064     h->flags |= HEADERFLAG_SORTED;
01065     h->nrefs = 0;
01066     h = headerLink(h);
01067 
01068     /*
01069      * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
01070      * %verifyscript tag that needs to be diddled.
01071      */
01072     if (ntohl(pe->tag) == 15 &&
01073         ntohl(pe->type) == RPM_STRING_TYPE &&
01074         ntohl(pe->count) == 1)
01075     {
01076         pe->tag = htonl(1079);
01077     }
01078 
01079     entry = h->index;
01080     i = 0;
01081     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01082         h->flags |= HEADERFLAG_LEGACY;
01083         entry->info.type = REGION_TAG_TYPE;
01084         entry->info.tag = HEADER_IMAGE;
01085         /*@-sizeoftype@*/
01086         entry->info.count = REGION_TAG_COUNT;
01087         /*@=sizeoftype@*/
01088         entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
01089 
01090         /*@-assignexpose@*/
01091         entry->data = pe;
01092         /*@=assignexpose@*/
01093         entry->length = pvlen - sizeof(il) - sizeof(dl);
01094         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01095 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
01096         if (rdlen != dl)
01097             goto errxit;
01098 #endif
01099         entry->rdlen = rdlen;
01100         entry++;
01101         h->indexUsed++;
01102     } else {
01103         int_32 rdl;
01104         int_32 ril;
01105 
01106         h->flags &= ~HEADERFLAG_LEGACY;
01107 
01108         entry->info.type = htonl(pe->type);
01109         entry->info.count = htonl(pe->count);
01110 
01111         if (hdrchkType(entry->info.type))
01112             goto errxit;
01113         if (hdrchkTags(entry->info.count))
01114             goto errxit;
01115 
01116         {   int off = ntohl(pe->offset);
01117 
01118             if (hdrchkData(off))
01119                 goto errxit;
01120             if (off) {
01121 /*@-sizeoftype@*/
01122                 size_t nb = REGION_TAG_COUNT;
01123 /*@=sizeoftype@*/
01124                 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01125                 rdl = -ntohl(stei[2]);  /* negative offset */
01126                 ril = rdl/sizeof(*pe);
01127                 if (hdrchkTags(ril) || hdrchkData(rdl))
01128                     goto errxit;
01129                 entry->info.tag = htonl(pe->tag);
01130             } else {
01131                 ril = il;
01132                 /*@-sizeoftype@*/
01133                 rdl = (ril * sizeof(struct entryInfo_s));
01134                 /*@=sizeoftype@*/
01135                 entry->info.tag = HEADER_IMAGE;
01136             }
01137         }
01138         entry->info.offset = -rdl;      /* negative offset */
01139 
01140         /*@-assignexpose@*/
01141         entry->data = pe;
01142         /*@=assignexpose@*/
01143         entry->length = pvlen - sizeof(il) - sizeof(dl);
01144         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01145         if (rdlen < 0)
01146             goto errxit;
01147         entry->rdlen = rdlen;
01148 
01149         if (ril < h->indexUsed) {
01150             indexEntry newEntry = entry + ril;
01151             int ne = (h->indexUsed - ril);
01152             int rid = entry->info.offset+1;
01153             int rc;
01154 
01155             /* Load dribble entries from region. */
01156             rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01157             if (rc < 0)
01158                 goto errxit;
01159             rdlen += rc;
01160 
01161           { indexEntry firstEntry = newEntry;
01162             int save = h->indexUsed;
01163             int j;
01164 
01165             /* Dribble entries replace duplicate region entries. */
01166             h->indexUsed -= ne;
01167             for (j = 0; j < ne; j++, newEntry++) {
01168                 (void) headerRemoveEntry(h, newEntry->info.tag);
01169                 if (newEntry->info.tag == HEADER_BASENAMES)
01170                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01171             }
01172 
01173             /* If any duplicate entries were replaced, move new entries down. */
01174 /*@-boundswrite@*/
01175             if (h->indexUsed < (save - ne)) {
01176                 memmove(h->index + h->indexUsed, firstEntry,
01177                         (ne * sizeof(*entry)));
01178             }
01179 /*@=boundswrite@*/
01180             h->indexUsed += ne;
01181           }
01182         }
01183     }
01184 
01185     h->flags &= ~HEADERFLAG_SORTED;
01186     headerSort(h);
01187 
01188     /*@-globstate -observertrans @*/
01189     return h;
01190     /*@=globstate =observertrans @*/
01191 
01192 errxit:
01193     /*@-usereleased@*/
01194     if (h) {
01195         h->index = _free(h->index);
01196         /*@-refcounttrans@*/
01197         h = _free(h);
01198         /*@=refcounttrans@*/
01199     }
01200     /*@=usereleased@*/
01201     /*@-refcounttrans -globstate@*/
01202     return h;
01203     /*@=refcounttrans =globstate@*/
01204 }
01205 
01211 static /*@observer@*/ /*@null@*/
01212 const char * headerGetOrigin(/*@null@*/ Header h)
01213         /*@*/
01214 {
01215     return (h != NULL ? h->origin : NULL);
01216 }
01217 
01224 static
01225 int headerSetOrigin(/*@null@*/ Header h, const char * origin)
01226         /*@modifies h @*/
01227 {
01228     if (h != NULL) {
01229         h->origin = _free(h->origin);
01230         h->origin = xstrdup(origin);
01231     }
01232     return 0;
01233 }
01234 
01240 static
01241 int headerGetInstance(/*@null@*/ Header h)
01242         /*@*/
01243 {
01244     return (h != NULL ? h->instance : 0);
01245 }
01246 
01253 static
01254 int headerSetInstance(/*@null@*/ Header h, int instance)
01255         /*@modifies h @*/
01256 {
01257     if (h != NULL)
01258         h->