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

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