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

rpmdb/header.c

Go to the documentation of this file.
00001 
00005 /* RPM - Copyright (C) 1995-2002 Red Hat Software */
00006 
00007 /* Data written to file descriptors is in network byte order.    */
00008 /* Data read from file descriptors is expected to be in          */
00009 /* network byte order and is converted on the fly to host order. */
00010 
00011 #include "system.h"
00012 
00013 #include <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 }

Generated on Mon Nov 29 2010 05:18:46 for rpm by  doxygen 1.7.2