rpmdb/header.c

Go to the documentation of this file.
00001 
00005 /* RPM - Copyright (C) 1995-2002 Red Hat Software */
00006 
00007 /* Data written to file descriptors is in network byte order.    */
00008 /* Data read from file descriptors is expected to be in          */
00009 /* network byte order and is converted on the fly to host order. */
00010 
00011 #include "system.h"
00012 
00013 #define __HEADER_PROTOTYPES__
00014 
00015 #include <rpmio_internal.h>     /* XXX for fdGetOPath() */
00016 #include <header_internal.h>
00017 
00018 #include "debug.h"
00019 
00020 /*@unchecked@*/
00021 int _hdr_debug = 0;
00022 
00023 /*@access entryInfo @*/
00024 /*@access indexEntry @*/
00025 
00026 /*@access rpmec @*/
00027 /*@access sprintfTag @*/
00028 /*@access sprintfToken @*/
00029 /*@access HV_t @*/
00030 
00031 #define PARSER_BEGIN    0
00032 #define PARSER_IN_ARRAY 1
00033 #define PARSER_IN_EXPR  2
00034 
00037 /*@observer@*/ /*@unchecked@*/
00038 static unsigned char header_magic[8] = {
00039         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00040 };
00041 
00045 /*@observer@*/ /*@unchecked@*/
00046 static int typeAlign[16] =  {
00047     1,  
00048     1,  
00049     1,  
00050     2,  
00051     4,  
00052     8,  
00053     1,  
00054     1,  
00055     1,  
00056     1,  
00057     1,  
00058     1,  
00059     0,
00060     0,
00061     0,
00062     0
00063 };
00064 
00068 /*@observer@*/ /*@unchecked@*/
00069 static int typeSizes[16] =  { 
00070     0,  
00071     1,  
00072     1,  
00073     2,  
00074     4,  
00075     8,  
00076     -1, 
00077     1,  
00078     -1, 
00079     -1, 
00080     1,  
00081     1,  
00082     0,
00083     0,
00084     0,
00085     0
00086 };
00087 
00091 /*@unchecked@*/
00092 static size_t headerMaxbytes = (32*1024*1024);
00093 
00098 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00099 
00103 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00104 
00109 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
00110 
00114 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
00115 
00119 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
00120 
00121 /*@observer@*/ /*@unchecked@*/
00122 HV_t hdrVec;    /* forward reference */
00123 
00129 /*@unused@*/ static inline /*@null@*/ void *
00130 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) /*@modifies *p @*/
00131 {
00132     if (p != NULL)      free((void *)p);
00133     return NULL;
00134 }
00135 
00141 static
00142 Header headerLink(Header h)
00143         /*@modifies h @*/
00144 {
00145 /*@-nullret@*/
00146     if (h == NULL) return NULL;
00147 /*@=nullret@*/
00148 
00149     h->nrefs++;
00150 /*@-modfilesys@*/
00151 if (_hdr_debug)
00152 fprintf(stderr, "--> h  %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00153 /*@=modfilesys@*/
00154 
00155     /*@-refcounttrans @*/
00156     return h;
00157     /*@=refcounttrans @*/
00158 }
00159 
00165 static /*@null@*/
00166 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h)
00167         /*@modifies h @*/
00168 {
00169     if (h == NULL) return NULL;
00170 /*@-modfilesys@*/
00171 if (_hdr_debug)
00172 fprintf(stderr, "--> h  %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00173 /*@=modfilesys@*/
00174     h->nrefs--;
00175     return NULL;
00176 }
00177 
00183 static /*@null@*/
00184 Header headerFree(/*@killref@*/ /*@null@*/ Header h)
00185         /*@modifies h @*/
00186 {
00187     (void) headerUnlink(h);
00188 
00189     /*@-usereleased@*/
00190     if (h == NULL || h->nrefs > 0)
00191         return NULL;    /* XXX return previous header? */
00192 
00193     if (h->index) {
00194         indexEntry entry = h->index;
00195         int i;
00196         for (i = 0; i < h->indexUsed; i++, entry++) {
00197             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00198                 if (entry->length > 0) {
00199                     int_32 * ei = entry->data;
00200                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00201                     entry->data = NULL;
00202                 }
00203             } else if (!ENTRY_IN_REGION(entry)) {
00204                 entry->data = _free(entry->data);
00205             }
00206             entry->data = NULL;
00207         }
00208         h->index = _free(h->index);
00209     }
00210     h->origin = _free(h->origin);
00211 
00212     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
00213     return h;
00214     /*@=usereleased@*/
00215 }
00216 
00221 static
00222 Header headerNew(void)
00223         /*@*/
00224 {
00225     Header h = xcalloc(1, sizeof(*h));
00226 
00227 /*@-boundsread@*/
00228     /*@-assignexpose@*/
00229     h->hv = *hdrVec;            /* structure assignment */
00230     /*@=assignexpose@*/
00231 /*@=boundsread@*/
00232     h->blob = NULL;
00233     h->origin = NULL;
00234     h->instance = 0;
00235     h->indexAlloced = INDEX_MALLOC_SIZE;
00236     h->indexUsed = 0;
00237     h->flags |= HEADERFLAG_SORTED;
00238 
00239     h->index = (h->indexAlloced
00240         ? xcalloc(h->indexAlloced, sizeof(*h->index))
00241         : NULL);
00242 
00243     h->nrefs = 0;
00244     /*@-globstate -observertrans @*/
00245     return headerLink(h);
00246     /*@=globstate =observertrans @*/
00247 }
00248 
00251 static int indexCmp(const void * avp, const void * bvp)
00252         /*@*/
00253 {
00254     /*@-castexpose@*/
00255     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00256     /*@=castexpose@*/
00257     return (ap->info.tag - bp->info.tag);
00258 }
00259 
00264 static
00265 void headerSort(Header h)
00266         /*@modifies h @*/
00267 {
00268     if (!(h->flags & HEADERFLAG_SORTED)) {
00269 /*@-boundsread@*/
00270         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00271 /*@=boundsread@*/
00272         h->flags |= HEADERFLAG_SORTED;
00273     }
00274 }
00275 
00278 static int offsetCmp(const void * avp, const void * bvp) /*@*/
00279 {
00280     /*@-castexpose@*/
00281     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00282     /*@=castexpose@*/
00283     int rc = (ap->info.offset - bp->info.offset);
00284 
00285     if (rc == 0) {
00286         /* Within a region, entries sort by address. Added drips sort by tag. */
00287         if (ap->info.offset < 0)
00288             rc = (((char *)ap->data) - ((char *)bp->data));
00289         else
00290             rc = (ap->info.tag - bp->info.tag);
00291     }
00292     return rc;
00293 }
00294 
00299 static
00300 void headerUnsort(Header h)
00301         /*@modifies h @*/
00302 {
00303 /*@-boundsread@*/
00304     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00305 /*@=boundsread@*/
00306 }
00307 
00314 static
00315 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp)
00316         /*@modifies h @*/
00317 {
00318     indexEntry entry;
00319     unsigned int size = 0;
00320     unsigned int pad = 0;
00321     int i;
00322 
00323     if (h == NULL)
00324         return size;
00325 
00326     headerSort(h);
00327 
00328     switch (magicp) {
00329     case HEADER_MAGIC_YES:
00330         size += sizeof(header_magic);
00331         break;
00332     case HEADER_MAGIC_NO:
00333         break;
00334     }
00335 
00336     /*@-sizeoftype@*/
00337     size += 2 * sizeof(int_32); /* count of index entries */
00338     /*@=sizeoftype@*/
00339 
00340     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00341         unsigned diff;
00342         int_32 type;
00343 
00344         /* Regions go in as is ... */
00345         if (ENTRY_IS_REGION(entry)) {
00346             size += entry->length;
00347             /* XXX Legacy regions do not include the region tag and data. */
00348             /*@-sizeoftype@*/
00349             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00350                 size += sizeof(struct entryInfo_s) + entry->info.count;
00351             /*@=sizeoftype@*/
00352             continue;
00353         }
00354 
00355         /* ... and region elements are skipped. */
00356         if (entry->info.offset < 0)
00357             continue;
00358 
00359         /* Alignment */
00360         type = entry->info.type;
00361 /*@-boundsread@*/
00362         if (typeSizes[type] > 1) {
00363             diff = typeSizes[type] - (size % typeSizes[type]);
00364             if (diff != typeSizes[type]) {
00365                 size += diff;
00366                 pad += diff;
00367             }
00368         }
00369 /*@=boundsread@*/
00370 
00371         /*@-sizeoftype@*/
00372         size += sizeof(struct entryInfo_s) + entry->length;
00373         /*@=sizeoftype@*/
00374     }
00375 
00376     return size;
00377 }
00378 
00388 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00389                 /*@null@*/ hPTR_t pend)
00390         /*@*/
00391 {
00392     const unsigned char * s = p;
00393     const unsigned char * se = pend;
00394     int length = 0;
00395 
00396     switch (type) {
00397     case RPM_STRING_TYPE:
00398         if (count != 1)
00399             return -1;
00400 /*@-boundsread@*/
00401         while (*s++) {
00402             if (se && s > se)
00403                 return -1;
00404             length++;
00405         }
00406 /*@=boundsread@*/
00407         length++;       /* count nul terminator too. */
00408         break;
00409 
00410     case RPM_STRING_ARRAY_TYPE:
00411     case RPM_I18NSTRING_TYPE:
00412         /* These are like RPM_STRING_TYPE, except they're *always* an array */
00413         /* Compute sum of length of all strings, including nul terminators */
00414 
00415         if (onDisk) {
00416             while (count--) {
00417                 length++;       /* count nul terminator too */
00418 /*@-boundsread@*/
00419                while (*s++) {
00420                     if (se && s > se)
00421                         return -1;
00422                     length++;
00423                 }
00424 /*@=boundsread@*/
00425             }
00426         } else {
00427             const char ** av = (const char **)p;
00428 /*@-boundsread@*/
00429             while (count--) {
00430                 /* add one for null termination */
00431                 length += strlen(*av++) + 1;
00432             }
00433 /*@=boundsread@*/
00434         }
00435         break;
00436 
00437     default:
00438 /*@-boundsread@*/
00439         if (typeSizes[type] == -1)
00440             return -1;
00441         length = typeSizes[(type & 0xf)] * count;
00442 /*@=boundsread@*/
00443         if (length < 0 || (se && (s + length) > se))
00444             return -1;
00445         break;
00446     }
00447 
00448     return length;
00449 }
00450 
00477 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
00478                 entryInfo pe,
00479                 unsigned char * dataStart,
00480                 /*@null@*/ const unsigned char * dataEnd,
00481                 int regionid)
00482         /*@modifies *entry, *dataStart @*/
00483 {
00484     unsigned char * tprev = NULL;
00485     unsigned char * t = NULL;
00486     int tdel = 0;
00487     int tl = dl;
00488     struct indexEntry_s ieprev;
00489 
00490 /*@-boundswrite@*/
00491     memset(&ieprev, 0, sizeof(ieprev));
00492 /*@=boundswrite@*/
00493     for (; il > 0; il--, pe++) {
00494         struct indexEntry_s ie;
00495         int_32 type;
00496 
00497         ie.info.tag = ntohl(pe->tag);
00498         ie.info.type = ntohl(pe->type);
00499         ie.info.count = ntohl(pe->count);
00500         ie.info.offset = ntohl(pe->offset);
00501 
00502         if (hdrchkType(ie.info.type))
00503             return -1;
00504         if (hdrchkData(ie.info.count))
00505             return -1;
00506         if (hdrchkData(ie.info.offset))
00507             return -1;
00508 /*@-boundsread@*/
00509         if (hdrchkAlign(ie.info.type, ie.info.offset))
00510             return -1;
00511 /*@=boundsread@*/
00512 
00513         ie.data = t = dataStart + ie.info.offset;
00514         if (dataEnd && t >= dataEnd)
00515             return -1;
00516 
00517         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00518         if (ie.length < 0 || hdrchkData(ie.length))
00519             return -1;
00520 
00521         ie.rdlen = 0;
00522 
00523         if (entry) {
00524             ie.info.offset = regionid;
00525 /*@-boundswrite@*/
00526             *entry = ie;        /* structure assignment */
00527 /*@=boundswrite@*/
00528             entry++;
00529         }
00530 
00531         /* Alignment */
00532         type = ie.info.type;
00533 /*@-boundsread@*/
00534         if (typeSizes[type] > 1) {
00535             unsigned diff;
00536             diff = typeSizes[type] - (dl % typeSizes[type]);
00537             if (diff != typeSizes[type]) {
00538                 dl += diff;
00539                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00540                     ieprev.length += diff;
00541             }
00542         }
00543 /*@=boundsread@*/
00544         tdel = (tprev ? (t - tprev) : 0);
00545         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00546             tdel = ieprev.length;
00547 
00548         if (ie.info.tag >= HEADER_I18NTABLE) {
00549             tprev = t;
00550         } else {
00551             tprev = dataStart;
00552             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00553             /*@-sizeoftype@*/
00554             if (ie.info.tag == HEADER_IMAGE)
00555                 tprev -= REGION_TAG_COUNT;
00556             /*@=sizeoftype@*/
00557         }
00558 
00559         /* Perform endian conversions */
00560         switch (ntohl(pe->type)) {
00561 /*@-bounds@*/
00562         case RPM_INT64_TYPE:
00563         {   int_64 * it = (int_64 *)t;
00564             int_32 b[2];
00565             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00566                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00567                     return -1;
00568                 b[1] = htonl(((int_32 *)it)[0]);
00569                 b[0] = htonl(((int_32 *)it)[1]);
00570                 if (b[1] != ((int_32 *)it)[0])
00571                     memcpy(it, b, sizeof(b));
00572             }
00573             t = (char *) it;
00574         }   /*@switchbreak@*/ break;
00575         case RPM_INT32_TYPE:
00576         {   int_32 * it = (int_32 *)t;
00577             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00578                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00579                     return -1;
00580                 *it = htonl(*it);
00581             }
00582             t = (char *) it;
00583         }   /*@switchbreak@*/ break;
00584         case RPM_INT16_TYPE:
00585         {   int_16 * it = (int_16 *) t;
00586             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00587                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00588                     return -1;
00589                 *it = htons(*it);
00590             }
00591             t = (char *) it;
00592         }   /*@switchbreak@*/ break;
00593 /*@=bounds@*/
00594         default:
00595             t += ie.length;
00596             /*@switchbreak@*/ break;
00597         }
00598 
00599         dl += ie.length;
00600         if (dataEnd && dataStart + dl > dataEnd) return -1;
00601         tl += tdel;
00602         ieprev = ie;    /* structure assignment */
00603 
00604     }
00605     tdel = (tprev ? (t - tprev) : 0);
00606     tl += tdel;
00607 
00608     /* XXX
00609      * There are two hacks here:
00610      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00611      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00612      */
00613     /*@-sizeoftype@*/
00614     if (tl+REGION_TAG_COUNT == dl)
00615         tl += REGION_TAG_COUNT;
00616     /*@=sizeoftype@*/
00617 
00618     return dl;
00619 }
00620 
00626 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
00627                 /*@out@*/ int * lengthPtr)
00628         /*@modifies h, *lengthPtr @*/
00629         /*@requires maxSet(lengthPtr) >= 0 @*/
00630         /*@ensures maxRead(result) == (*lengthPtr) @*/
00631 {
00632     int_32 * ei = NULL;
00633     entryInfo pe;
00634     char * dataStart;
00635     char * te;
00636     unsigned pad;
00637     unsigned len;
00638     int_32 il = 0;
00639     int_32 dl = 0;
00640     indexEntry entry; 
00641     int_32 type;
00642     int i;
00643     int drlen, ndribbles;
00644     int driplen, ndrips;
00645     int legacy = 0;
00646 
00647     /* Sort entries by (offset,tag). */
00648     headerUnsort(h);
00649 
00650     /* Compute (il,dl) for all tags, including those deleted in region. */
00651     pad = 0;
00652     drlen = ndribbles = driplen = ndrips = 0;
00653     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00654         if (ENTRY_IS_REGION(entry)) {
00655             int_32 rdl = -entry->info.offset;   /* negative offset */
00656             int_32 ril = rdl/sizeof(*pe);
00657             int rid = entry->info.offset;
00658 
00659             il += ril;
00660             dl += entry->rdlen + entry->info.count;
00661             /* XXX Legacy regions do not include the region tag and data. */
00662             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00663                 il += 1;
00664 
00665             /* Skip rest of entries in region, but account for dribbles. */
00666             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00667                 if (entry->info.offset <= rid)
00668                     /*@innercontinue@*/ continue;
00669 
00670                 /* Alignment */
00671                 type = entry->info.type;
00672                 if (typeSizes[type] > 1) {
00673                     unsigned diff;
00674                     diff = typeSizes[type] - (dl % typeSizes[type]);
00675                     if (diff != typeSizes[type]) {
00676                         drlen += diff;
00677                         pad += diff;
00678                         dl += diff;
00679                     }
00680                 }
00681 
00682                 ndribbles++;
00683                 il++;
00684                 drlen += entry->length;
00685                 dl += entry->length;
00686             }
00687             i--;
00688             entry--;
00689             continue;
00690         }
00691 
00692         /* Ignore deleted drips. */
00693         if (entry->data == NULL || entry->length <= 0)
00694             continue;
00695 
00696         /* Alignment */
00697         type = entry->info.type;
00698         if (typeSizes[type] > 1) {
00699             unsigned diff;
00700             diff = typeSizes[type] - (dl % typeSizes[type]);
00701             if (diff != typeSizes[type]) {
00702                 driplen += diff;
00703                 pad += diff;
00704                 dl += diff;
00705             } else
00706                 diff = 0;
00707         }
00708 
00709         ndrips++;
00710         il++;
00711         driplen += entry->length;
00712         dl += entry->length;
00713     }
00714 
00715     /* Sanity checks on header intro. */
00716     if (hdrchkTags(il) || hdrchkData(dl))
00717         goto errxit;
00718 
00719     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00720 
00721 /*@-boundswrite@*/
00722     ei = xmalloc(len);
00723     ei[0] = htonl(il);
00724     ei[1] = htonl(dl);
00725 /*@=boundswrite@*/
00726 
00727     pe = (entryInfo) &ei[2];
00728     dataStart = te = (char *) (pe + il);
00729 
00730     pad = 0;
00731     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00732         const char * src;
00733 char *t;
00734         int count;
00735         int rdlen;
00736 
00737         if (entry->data == NULL || entry->length <= 0)
00738             continue;
00739 
00740 t = te;
00741         pe->tag = htonl(entry->info.tag);
00742         pe->type = htonl(entry->info.type);
00743         pe->count = htonl(entry->info.count);
00744 
00745         if (ENTRY_IS_REGION(entry)) {
00746             int_32 rdl = -entry->info.offset;   /* negative offset */
00747             int_32 ril = rdl/sizeof(*pe) + ndribbles;
00748             int rid = entry->info.offset;
00749 
00750             src = (char *)entry->data;
00751             rdlen = entry->rdlen;
00752 
00753             /* XXX Legacy regions do not include the region tag and data. */
00754             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00755                 int_32 stei[4];
00756 
00757                 legacy = 1;
00758 /*@-boundswrite@*/
00759                 memcpy(pe+1, src, rdl);
00760                 memcpy(te, src + rdl, rdlen);
00761 /*@=boundswrite@*/
00762                 te += rdlen;
00763 
00764                 pe->offset = htonl(te - dataStart);
00765                 stei[0] = pe->tag;
00766                 stei[1] = pe->type;
00767                 stei[2] = htonl(-rdl-entry->info.count);
00768                 stei[3] = pe->count;
00769 /*@-boundswrite@*/
00770                 memcpy(te, stei, entry->info.count);
00771 /*@=boundswrite@*/
00772                 te += entry->info.count;
00773                 ril++;
00774                 rdlen += entry->info.count;
00775 
00776                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00777                 if (count != rdlen)
00778                     goto errxit;
00779 
00780             } else {
00781 
00782 /*@-boundswrite@*/
00783                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00784                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00785 /*@=boundswrite@*/
00786                 te += rdlen;
00787                 {   /*@-castexpose@*/
00788                     entryInfo se = (entryInfo)src;
00789                     /*@=castexpose@*/
00790                     int off = ntohl(se->offset);
00791                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00792                 }
00793                 te += entry->info.count + drlen;
00794 
00795                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00796                 if (count != (rdlen + entry->info.count + drlen))
00797                     goto errxit;
00798             }
00799 
00800             /* Skip rest of entries in region. */
00801             while (i < h->indexUsed && entry->info.offset <= rid+1) {
00802                 i++;
00803                 entry++;
00804             }
00805             i--;
00806             entry--;
00807             pe += ril;
00808             continue;
00809         }
00810 
00811         /* Ignore deleted drips. */
00812         if (entry->data == NULL || entry->length <= 0)
00813             continue;
00814 
00815         /* Alignment */
00816         type = entry->info.type;
00817         if (typeSizes[type] > 1) {
00818             unsigned diff;
00819             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00820             if (diff != typeSizes[type]) {
00821 /*@-boundswrite@*/
00822                 memset(te, 0, diff);
00823 /*@=boundswrite@*/
00824                 te += diff;
00825                 pad += diff;
00826             }
00827         }
00828 
00829         pe->offset = htonl(te - dataStart);
00830 
00831         /* copy data w/ endian conversions */
00832 /*@-boundswrite@*/
00833         switch (entry->info.type) {
00834         case RPM_INT64_TYPE:
00835         {   int_32 b[2];
00836             count = entry->info.count;
00837             src = entry->data;
00838             while (count--) {
00839                 b[1] = htonl(((int_32 *)src)[0]);
00840                 b[0] = htonl(((int_32 *)src)[1]);
00841                 if (b[1] == ((int_32 *)src)[0])
00842                     memcpy(te, src, sizeof(b));
00843                 else
00844                     memcpy(te, b, sizeof(b));
00845                 te += sizeof(b);
00846                 src += sizeof(b);
00847             }
00848         }   /*@switchbreak@*/ break;
00849 
00850         case RPM_INT32_TYPE:
00851             count = entry->info.count;
00852             src = entry->data;
00853             while (count--) {
00854                 *((int_32 *)te) = htonl(*((int_32 *)src));
00855                 /*@-sizeoftype@*/
00856                 te += sizeof(int_32);
00857                 src += sizeof(int_32);
00858                 /*@=sizeoftype@*/
00859             }
00860             /*@switchbreak@*/ break;
00861 
00862         case RPM_INT16_TYPE:
00863             count = entry->info.count;
00864             src = entry->data;
00865             while (count--) {
00866                 *((int_16 *)te) = htons(*((int_16 *)src));
00867                 /*@-sizeoftype@*/
00868                 te += sizeof(int_16);
00869                 src += sizeof(int_16);
00870                 /*@=sizeoftype@*/
00871             }
00872             /*@switchbreak@*/ break;
00873 
00874         default:
00875             memcpy(te, entry->data, entry->length);
00876             te += entry->length;
00877             /*@switchbreak@*/ break;
00878         }
00879 /*@=boundswrite@*/
00880         pe++;
00881     }
00882    
00883     /* Insure that there are no memcpy underruns/overruns. */
00884     if (((char *)pe) != dataStart)
00885         goto errxit;
00886     if ((((char *)ei)+len) != te)
00887         goto errxit;
00888 
00889     if (lengthPtr)
00890         *lengthPtr = len;
00891 
00892     h->flags &= ~HEADERFLAG_SORTED;
00893     headerSort(h);
00894 
00895     return (void *) ei;
00896 
00897 errxit:
00898     /*@-usereleased@*/
00899     ei = _free(ei);
00900     /*@=usereleased@*/
00901     return (void *) ei;
00902 }
00903 
00909 static /*@only@*/ /*@null@*/
00910 void * headerUnload(Header h)
00911         /*@modifies h @*/
00912 {
00913     int length;
00914 /*@-boundswrite@*/
00915     void * uh = doHeaderUnload(h, &length);
00916 /*@=boundswrite@*/
00917     return uh;
00918 }
00919 
00927 static /*@null@*/
00928 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
00929         /*@modifies h @*/
00930 {
00931     indexEntry entry, entry2, last;
00932     struct indexEntry_s key;
00933 
00934     if (h == NULL) return NULL;
00935     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00936 
00937     key.info.tag = tag;
00938 
00939 /*@-boundswrite@*/
00940     entry2 = entry = 
00941         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00942 /*@=boundswrite@*/
00943     if (entry == NULL)
00944         return NULL;
00945 
00946     if (type == RPM_NULL_TYPE)
00947         return entry;
00948 
00949     /* look backwards */
00950     while (entry->info.tag == tag && entry->info.type != type &&
00951            entry > h->index) entry--;
00952 
00953     if (entry->info.tag == tag && entry->info.type == type)
00954         return entry;
00955 
00956     last = h->index + h->indexUsed;
00957     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
00958     while (entry2->info.tag == tag && entry2->info.type != type &&
00959            entry2 < last) entry2++;
00960     /*@=usereleased@*/
00961 
00962     if (entry->info.tag == tag && entry->info.type == type)
00963         return entry;
00964 
00965     return NULL;
00966 }
00967 
00977 static
00978 int headerRemoveEntry(Header h, int_32 tag)
00979         /*@modifies h @*/
00980 {
00981     indexEntry last = h->index + h->indexUsed;
00982     indexEntry entry, first;
00983     int ne;
00984 
00985     entry = findEntry(h, tag, RPM_NULL_TYPE);
00986     if (!entry) return 1;
00987 
00988     /* Make sure entry points to the first occurence of this tag. */
00989     while (entry > h->index && (entry - 1)->info.tag == tag)  
00990         entry--;
00991 
00992     /* Free data for tags being removed. */
00993     for (first = entry; first < last; first++) {
00994         void * data;
00995         if (first->info.tag != tag)
00996             break;
00997         data = first->data;
00998         first->data = NULL;
00999         first->length = 0;
01000         if (ENTRY_IN_REGION(first))
01001             continue;
01002         data = _free(data);
01003     }
01004 
01005     ne = (first - entry);
01006     if (ne > 0) {
01007         h->indexUsed -= ne;
01008         ne = last - first;
01009 /*@-boundswrite@*/
01010         if (ne > 0)
01011             memmove(entry, first, (ne * sizeof(*entry)));
01012 /*@=boundswrite@*/
01013     }
01014 
01015     return 0;
01016 }
01017 
01023 static /*@null@*/
01024 Header headerLoad(/*@kept@*/ void * uh)
01025         /*@modifies uh @*/
01026 {
01027     int_32 * ei = (int_32 *) uh;
01028     int_32 il = ntohl(ei[0]);           /* index length */
01029     int_32 dl = ntohl(ei[1]);           /* data length */
01030     /*@-sizeoftype@*/
01031     size_t pvlen = sizeof(il) + sizeof(dl) +
01032                (il * sizeof(struct entryInfo_s)) + dl;
01033     /*@=sizeoftype@*/
01034     void * pv = uh;
01035     Header h = NULL;
01036     entryInfo pe;
01037     unsigned char * dataStart;
01038     unsigned char * dataEnd;
01039     indexEntry entry; 
01040     int rdlen;
01041     int i;
01042 
01043     /* Sanity checks on header intro. */
01044     if (hdrchkTags(il) || hdrchkData(dl))
01045         goto errxit;
01046 
01047     ei = (int_32 *) pv;
01048     /*@-castexpose@*/
01049     pe = (entryInfo) &ei[2];
01050     /*@=castexpose@*/
01051     dataStart = (unsigned char *) (pe + il);
01052     dataEnd = dataStart + dl;
01053 
01054     h = xcalloc(1, sizeof(*h));
01055     /*@-assignexpose@*/
01056     h->hv = *hdrVec;            /* structure assignment */
01057     /*@=assignexpose@*/
01058     /*@-assignexpose -kepttrans@*/
01059     h->blob = uh;
01060     /*@=assignexpose =kepttrans@*/
01061     h->indexAlloced = il + 1;
01062     h->indexUsed = il;
01063     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01064     h->flags |= HEADERFLAG_SORTED;
01065     h->nrefs = 0;
01066     h = headerLink(h);
01067 
01068     /*
01069      * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
01070      * %verifyscript tag that needs to be diddled.
01071      */
01072     if (ntohl(pe->tag) == 15 &&
01073         ntohl(pe->type) == RPM_STRING_TYPE &&
01074         ntohl(pe->count) == 1)
01075     {
01076         pe->tag = htonl(1079);
01077     }
01078 
01079     entry = h->index;
01080     i = 0;
01081     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01082         h->flags |= HEADERFLAG_LEGACY;
01083         entry->info.type = REGION_TAG_TYPE;
01084         entry->info.tag = HEADER_IMAGE;
01085         /*@-sizeoftype@*/
01086         entry->info.count = REGION_TAG_COUNT;
01087         /*@=sizeoftype@*/
01088         entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
01089 
01090         /*@-assignexpose@*/
01091         entry->data = pe;
01092         /*@=assignexpose@*/
01093         entry->length = pvlen - sizeof(il) - sizeof(dl);
01094         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01095 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
01096         if (rdlen != dl)
01097             goto errxit;
01098 #endif
01099         entry->rdlen = rdlen;
01100         entry++;
01101         h->indexUsed++;
01102     } else {
01103         int_32 rdl;
01104         int_32 ril;
01105 
01106         h->flags &= ~HEADERFLAG_LEGACY;
01107 
01108         entry->info.type = htonl(pe->type);
01109         entry->info.count = htonl(pe->count);
01110 
01111         if (hdrchkType(entry->info.type))
01112             goto errxit;
01113         if (hdrchkTags(entry->info.count))
01114             goto errxit;
01115 
01116         {   int off = ntohl(pe->offset);
01117 
01118             if (hdrchkData(off))
01119                 goto errxit;
01120             if (off) {
01121 /*@-sizeoftype@*/
01122                 size_t nb = REGION_TAG_COUNT;
01123 /*@=sizeoftype@*/
01124                 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01125                 rdl = -ntohl(stei[2]);  /* negative offset */
01126                 ril = rdl/sizeof(*pe);
01127                 if (hdrchkTags(ril) || hdrchkData(rdl))
01128                     goto errxit;
01129                 entry->info.tag = htonl(pe->tag);
01130             } else {
01131                 ril = il;
01132                 /*@-sizeoftype@*/
01133                 rdl = (ril * sizeof(struct entryInfo_s));
01134                 /*@=sizeoftype@*/
01135                 entry->info.tag = HEADER_IMAGE;
01136             }
01137         }
01138         entry->info.offset = -rdl;      /* negative offset */
01139 
01140         /*@-assignexpose@*/
01141         entry->data = pe;
01142         /*@=assignexpose@*/
01143         entry->length = pvlen - sizeof(il) - sizeof(dl);
01144         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01145         if (rdlen < 0)
01146             goto errxit;
01147         entry->rdlen = rdlen;
01148 
01149         if (ril < h->indexUsed) {
01150             indexEntry newEntry = entry + ril;
01151             int ne = (h->indexUsed - ril);
01152             int rid = entry->info.offset+1;
01153             int rc;
01154 
01155             /* Load dribble entries from region. */
01156             rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01157             if (rc < 0)
01158                 goto errxit;
01159             rdlen += rc;
01160 
01161           { indexEntry firstEntry = newEntry;
01162             int save = h->indexUsed;
01163             int j;
01164 
01165             /* Dribble entries replace duplicate region entries. */
01166             h->indexUsed -= ne;
01167             for (j = 0; j < ne; j++, newEntry++) {
01168                 (void) headerRemoveEntry(h, newEntry->info.tag);
01169                 if (newEntry->info.tag == HEADER_BASENAMES)
01170                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01171             }
01172 
01173             /* If any duplicate entries were replaced, move new entries down. */
01174 /*@-boundswrite@*/
01175             if (h->indexUsed < (save - ne)) {
01176                 memmove(h->index + h->indexUsed, firstEntry,
01177                         (ne * sizeof(*entry)));
01178             }
01179 /*@=boundswrite@*/
01180             h->indexUsed += ne;
01181           }
01182         }
01183     }
01184 
01185     h->flags &= ~HEADERFLAG_SORTED;
01186     headerSort(h);
01187 
01188     /*@-globstate -observertrans @*/
01189     return h;
01190     /*@=globstate =observertrans @*/
01191 
01192 errxit:
01193     /*@-usereleased@*/
01194     if (h) {
01195         h->index = _free(h->index);
01196         /*@-refcounttrans@*/
01197         h = _free(h);
01198         /*@=refcounttrans@*/
01199     }
01200     /*@=usereleased@*/
01201     /*@-refcounttrans -globstate@*/
01202     return h;
01203     /*@=refcounttrans =globstate@*/
01204 }
01205 
01211 static /*@observer@*/ /*@null@*/
01212 const char * headerGetOrigin(/*@null@*/ Header h)
01213         /*@*/
01214 {
01215     return (h != NULL ? h->origin : NULL);
01216 }
01217 
01224 static
01225 int headerSetOrigin(/*@null@*/ Header h, const char * origin)
01226         /*@modifies h @*/
01227 {
01228     if (h != NULL) {
01229         h->origin = _free(h->origin);
01230         h->origin = xstrdup(origin);
01231     }
01232     return 0;
01233 }
01234 
01240 static
01241 int headerGetInstance(/*@null@*/ Header h)
01242         /*@*/
01243 {
01244     return (h != NULL ? h->instance : 0);
01245 }
01246 
01253 static
01254 int headerSetInstance(/*@null@*/ Header h, int instance)
01255         /*@modifies h @*/
01256 {
01257     if (h != NULL)
01258         h->instance = instance;
01259     return 0;
01260 }
01261 
01269 static /*@null@*/
01270 Header headerReload(/*@only@*/ Header h, int tag)
01271         /*@modifies h @*/
01272 {
01273     Header nh;
01274     int length;
01275     /*@-onlytrans@*/
01276 /*@-boundswrite@*/
01277     void * uh = doHeaderUnload(h, &length);
01278 /*@=boundswrite@*/
01279     const char * origin;
01280     int_32 instance = h->instance;
01281     int xx;
01282 
01283     origin = (h->origin != NULL ? xstrdup(h->origin) : NULL);
01284     h = headerFree(h);
01285     /*@=onlytrans@*/
01286     if (uh == NULL)
01287         return NULL;
01288     nh = headerLoad(uh);
01289     if (nh == NULL) {
01290         uh = _free(uh);
01291         return NULL;
01292     }
01293     if (nh->flags & HEADERFLAG_ALLOCATED)
01294         uh = _free(uh);
01295     nh->flags |= HEADERFLAG_ALLOCATED;
01296     if (ENTRY_IS_REGION(nh->index)) {
01297 /*@-boundswrite@*/
01298         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01299             nh->index[0].info.tag = tag;
01300 /*@=boundswrite@*/
01301     }
01302     if (origin != NULL) {
01303         xx = headerSetOrigin(nh, origin);
01304         origin = _free(origin);
01305     }
01306     xx = headerSetInstance(nh, instance);
01307     return nh;
01308 }
01309 
01315 static /*@null@*/
01316 Header headerCopyLoad(const void * uh)
01317         /*@*/
01318 {
01319     int_32 * ei = (int_32 *) uh;
01320 /*@-boundsread@*/
01321     int_32 il = ntohl(ei[0]);           /* index length */
01322     int_32 dl = ntohl(ei[1]);           /* data length */
01323 /*@=boundsread@*/
01324     /*@-sizeoftype@*/
01325     size_t pvlen = sizeof(il) + sizeof(dl) +
01326                         (il * sizeof(struct entryInfo_s)) + dl;
01327     /*@=sizeoftype@*/
01328     void * nuh = NULL;
01329     Header h = NULL;
01330 
01331     /* Sanity checks on header intro. */
01332     /*@-branchstate@*/
01333     if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01334 /*@-boundsread@*/
01335         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01336 /*@=boundsread@*/
01337         if ((h = headerLoad(nuh)) != NULL)
01338             h->flags |= HEADERFLAG_ALLOCATED;
01339     }
01340     /*@=branchstate@*/
01341     /*@-branchstate@*/
01342     if (h == NULL)
01343         nuh = _free(nuh);
01344     /*@=branchstate@*/
01345     return h;
01346 }
01347 
01354 static /*@null@*/
01355 Header headerRead(FD_t fd, enum hMagic magicp)
01356         /*@modifies fd @*/
01357 {
01358     int_32 block[4];
01359     int_32 reserved;
01360     int_32 * ei = NULL;
01361     int_32 il;
01362     int_32 dl;
01363     int_32 magic;
01364     Header h = NULL;
01365     size_t len;
01366     int i;
01367 
01368     memset(block, 0, sizeof(block));
01369     i = 2;
01370     if (magicp == HEADER_MAGIC_YES)
01371         i += 2;
01372 
01373     /*@-type@*/ /* FIX: cast? */
01374     if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01375         goto exit;
01376     /*@=type@*/
01377 
01378     i = 0;
01379 
01380 /*@-boundsread@*/
01381     if (magicp == HEADER_MAGIC_YES) {
01382         magic = block[i++];
01383         if (memcmp(&magic, header_magic, sizeof(magic)))
01384             goto exit;
01385         reserved = block[i++];
01386     }
01387     
01388     il = ntohl(block[i]);       i++;
01389     dl = ntohl(block[i]);       i++;
01390 /*@=boundsread@*/
01391 
01392     /*@-sizeoftype@*/
01393     len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01394     /*@=sizeoftype@*/
01395 
01396     /* Sanity checks on header intro. */
01397     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01398         goto exit;
01399 
01400 /*@-boundswrite@*/
01401     ei = xmalloc(len);
01402     ei[0] = htonl(il);
01403     ei[1] = htonl(dl);
01404     len -= sizeof(il) + sizeof(dl);
01405 /*@=boundswrite@*/
01406 
01407 /*@-boundsread@*/
01408     /*@-type@*/ /* FIX: cast? */
01409     if (timedRead(fd, (char *)&ei[2], len) != len)
01410         goto exit;
01411     /*@=type@*/
01412 /*@=boundsread@*/
01413     
01414     h = headerLoad(ei);
01415 
01416     {   const char * origin = fdGetOPath(fd);
01417         if (origin != NULL)
01418             (void) headerSetOrigin(h, origin);
01419     }
01420 
01421 exit:
01422     if (h) {
01423         if (h->flags & HEADERFLAG_ALLOCATED)
01424             ei = _free(ei);
01425         h->flags |= HEADERFLAG_ALLOCATED;
01426     } else if (ei)
01427         ei = _free(ei);
01428     /*@-mustmod@*/      /* FIX: timedRead macro obscures annotation */
01429     return h;
01430     /*@-mustmod@*/
01431 }
01432 
01440 static
01441 int headerWrite(FD_t fd, /*@null@*/ Header h, enum hMagic magicp)
01442         /*@globals fileSystem @*/
01443         /*@modifies fd, h, fileSystem @*/
01444 {
01445     ssize_t nb;
01446     int length;
01447     const void * uh;
01448 
01449     if (h == NULL)
01450         return 1;
01451 /*@-boundswrite@*/
01452     uh = doHeaderUnload(h, &length);
01453 /*@=boundswrite@*/
01454     if (uh == NULL)
01455         return 1;
01456     switch (magicp) {
01457     case HEADER_MAGIC_YES:
01458 /*@-boundsread@*/
01459         /*@-sizeoftype@*/
01460         nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01461         /*@=sizeoftype@*/
01462 /*@=boundsread@*/
01463         if (nb != sizeof(header_magic))
01464             goto exit;
01465         break;
01466     case HEADER_MAGIC_NO:
01467         break;
01468     }
01469 
01470     /*@-sizeoftype@*/
01471     nb = Fwrite(uh, sizeof(char), length, fd);
01472     /*@=sizeoftype@*/
01473 
01474 exit:
01475     uh = _free(uh);
01476     return (nb == length ? 0 : 1);
01477 }
01478 
01485 static
01486 int headerIsEntry(/*@null@*/Header h, int_32 tag)
01487         /*@*/
01488 {
01489     /*@-mods@*/         /*@ FIX: h modified by sort. */
01490     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01491     /*@=mods@*/ 
01492 }
01493 
01504 static int copyEntry(const indexEntry entry,
01505                 /*@null@*/ /*@out@*/ hTYP_t type,
01506                 /*@null@*/ /*@out@*/ hPTR_t * p,
01507                 /*@null@*/ /*@out@*/ hCNT_t c,
01508                 int minMem)
01509         /*@modifies *type, *p, *c @*/
01510         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01511 {
01512     int_32 count = entry->info.count;
01513     int rc = 1;         /* XXX 1 on success. */
01514 
01515     if (p)
01516     switch (entry->info.type) {
01517     case RPM_BIN_TYPE:
01518         /*
01519          * XXX This only works for
01520          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
01521          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
01522          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
01523          */
01524         if (ENTRY_IS_REGION(entry)) {
01525             int_32 * ei = ((int_32 *)entry->data) - 2;
01526             /*@-castexpose@*/
01527             entryInfo pe = (entryInfo) (ei + 2);
01528             /*@=castexpose@*/
01529 /*@-boundsread@*/
01530             char * dataStart = (char *) (pe + ntohl(ei[0]));
01531 /*@=boundsread@*/
01532             int_32 rdl = -entry->info.offset;   /* negative offset */
01533             int_32 ril = rdl/sizeof(*pe);
01534 
01535             /*@-sizeoftype@*/
01536             rdl = entry->rdlen;
01537             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01538             if (entry->info.tag == HEADER_IMAGE) {
01539                 ril -= 1;
01540                 pe += 1;
01541             } else {
01542                 count += REGION_TAG_COUNT;
01543                 rdl += REGION_TAG_COUNT;
01544             }
01545 
01546 /*@-bounds@*/
01547             *p = xmalloc(count);
01548             ei = (int_32 *) *p;
01549             ei[0] = htonl(ril);
01550             ei[1] = htonl(rdl);
01551 
01552             /*@-castexpose@*/
01553             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01554             /*@=castexpose@*/
01555 
01556             dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01557             /*@=sizeoftype@*/
01558 /*@=bounds@*/
01559 
01560             rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01561             /* XXX 1 on success. */
01562             rc = (rc < 0) ? 0 : 1;
01563         } else {
01564             count = entry->length;
01565             *p = (!minMem
01566                 ? memcpy(xmalloc(count), entry->data, count)
01567                 : entry->data);
01568         }
01569         break;
01570     case RPM_STRING_TYPE:
01571         if (count == 1) {
01572             *p = entry->data;
01573             break;
01574         }
01575         /*@fallthrough@*/
01576     case RPM_STRING_ARRAY_TYPE:
01577     case RPM_I18NSTRING_TYPE:
01578     {   const char ** ptrEntry;
01579         /*@-sizeoftype@*/
01580         int tableSize = count * sizeof(char *);
01581         /*@=sizeoftype@*/
01582         char * t;
01583         int i;
01584 
01585 /*@-bounds@*/
01586         /*@-mods@*/
01587         if (minMem) {
01588             *p = xmalloc(tableSize);
01589             ptrEntry = (const char **) *p;
01590             t = entry->data;
01591         } else {
01592             t = xmalloc(tableSize + entry->length);
01593             *p = (void *)t;
01594             ptrEntry = (const char **) *p;
01595             t += tableSize;
01596             memcpy(t, entry->data, entry->length);
01597         }
01598         /*@=mods@*/
01599 /*@=bounds@*/
01600         for (i = 0; i < count; i++) {
01601 /*@-boundswrite@*/
01602             *ptrEntry++ = t;
01603 /*@=boundswrite@*/
01604             t = strchr(t, 0);
01605             t++;
01606         }
01607     }   break;
01608 
01609     case RPM_OPENPGP_TYPE:      /* XXX W2DO? */
01610     case RPM_ASN1_TYPE:         /* XXX W2DO? */
01611     default:
01612         *p = entry->data;
01613         break;
01614     }
01615     if (type) *type = entry->info.type;
01616     if (c) *c = count;
01617     return rc;
01618 }
01619 
01638 static int headerMatchLocale(const char *td, const char *l, const char *le)
01639         /*@*/
01640 {
01641     const char *fe;
01642 
01643 
01644 #if 0
01645   { const char *s, *ll, *CC, *EE, *dd;
01646     char *lbuf, *t.
01647 
01648     /* Copy the buffer and parse out components on the fly. */
01649     lbuf = alloca(le - l + 1);
01650     for (s = l, ll = t = lbuf; *s; s++, t++) {
01651         switch (*s) {
01652         case '_':
01653             *t = '\0';
01654             CC = t + 1;
01655             break;
01656         case '.':
01657             *t = '\0';
01658             EE = t + 1;
01659             break;
01660         case '@':
01661             *t = '\0';
01662             dd = t + 1;
01663             break;
01664         default:
01665             *t = *s;
01666             break;
01667         }
01668     }
01669 
01670     if (ll)     /* ISO language should be lower case */
01671         for (t = ll; *t; t++)   *t = tolower(*t);
01672     if (CC)     /* ISO country code should be upper case */
01673         for (t = CC; *t; t++)   *t = toupper(*t);
01674 
01675     /* There are a total of 16 cases to attempt to match. */
01676   }
01677 #endif
01678 
01679     /* First try a complete match. */
01680     if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01681         return 1;
01682 
01683     /* Next, try stripping optional dialect and matching.  */
01684     for (fe = l; fe < le && *fe != '@'; fe++)
01685         {};
01686     if (fe < le && !strncmp(td, l, (fe - l)))
01687         return 1;
01688 
01689     /* Next, try stripping optional codeset and matching.  */
01690     for (fe = l; fe < le && *fe != '.'; fe++)
01691         {};
01692     if (fe < le && !strncmp(td, l, (fe - l)))
01693         return 1;
01694 
01695     /* Finally, try stripping optional country code and matching. */
01696     for (fe = l; fe < le && *fe != '_'; fe++)
01697         {};
01698     if (fe < le && !strncmp(td, l, (fe - l)))
01699         return 1;
01700 
01701     return 0;
01702 }
01703 
01710 /*@dependent@*/ /*@exposed@*/ static char *
01711 headerFindI18NString(Header h, indexEntry entry)
01712         /*@*/
01713 {
01714     const char *lang, *l, *le;
01715     indexEntry table;
01716 
01717     /* XXX Drepper sez' this is the order. */
01718     if ((lang = getenv("LANGUAGE")) == NULL &&
01719         (lang = getenv("LC_ALL")) == NULL &&
01720         (lang = getenv("LC_MESSAGES")) == NULL &&
01721         (lang = getenv("LANG")) == NULL)
01722             return entry->data;
01723     
01724     /*@-mods@*/
01725     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01726         return entry->data;
01727     /*@=mods@*/
01728 
01729 /*@-boundsread@*/
01730     for (l = lang; *l != '\0'; l = le) {
01731         const char *td;
01732         char *ed;
01733         int langNum;
01734 
01735         while (*l && *l == ':')                 /* skip leading colons */
01736             l++;
01737         if (*l == '\0')
01738             break;
01739         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
01740             {};
01741 
01742         /* For each entry in the header ... */
01743         for (langNum = 0, td = table->data, ed = entry->data;
01744              langNum < entry->info.count;
01745              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01746 
01747                 if (headerMatchLocale(td, l, le))
01748                     return ed;
01749 
01750         }
01751     }
01752 /*@=boundsread@*/
01753 
01754     return entry->data;
01755 }
01756 
01767 static int intGetEntry(Header h, int_32 tag,
01768                 /*@null@*/ /*@out@*/ hTAG_t type,
01769                 /*@null@*/ /*@out@*/ hPTR_t * p,
01770                 /*@null@*/ /*@out@*/ hCNT_t c,
01771                 int minMem)
01772         /*@modifies *type, *p, *c @*/
01773         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01774 {
01775     indexEntry entry;
01776     int rc;
01777 
01778     /* First find the tag */
01779     /*@-mods@*/         /*@ FIX: h modified by sort. */
01780     entry = findEntry(h, tag, RPM_NULL_TYPE);
01781     /*@mods@*/
01782     if (entry == NULL) {
01783         if (type) type = 0;
01784         if (p) *p = NULL;
01785         if (c) *c = 0;
01786         return 0;
01787     }
01788 
01789     switch (entry->info.type) {
01790     case RPM_I18NSTRING_TYPE:
01791         rc = 1;
01792         if (type) *type = RPM_STRING_TYPE;
01793         if (c) *c = 1;
01794         /*@-dependenttrans@*/
01795         if (p) *p = headerFindI18NString(h, entry);
01796         /*@=dependenttrans@*/
01797         break;
01798     default:
01799         rc = copyEntry(entry, type, p, c, minMem);
01800         break;
01801     }
01802 
01803     /* XXX 1 on success */
01804     return ((rc == 1) ? 1 : 0);
01805 }
01806 
01814 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
01815                 /*@only@*/ /*@null@*/ const void * data, rpmTagType type)
01816         /*@modifies data @*/
01817 {
01818     if (data) {
01819         /*@-branchstate@*/
01820         if (type == -1 ||
01821             type == RPM_STRING_ARRAY_TYPE ||
01822             type == RPM_I18NSTRING_TYPE ||
01823             type == RPM_BIN_TYPE ||
01824             type == RPM_ASN1_TYPE ||
01825             type == RPM_OPENPGP_TYPE)
01826                 data = _free(data);
01827         /*@=branchstate@*/
01828     }
01829     return NULL;
01830 }
01831 
01845 static
01846 int headerGetEntry(Header h, int_32 tag,
01847                         /*@null@*/ /*@out@*/ hTYP_t type,
01848                         /*@null@*/ /*@out@*/ void * p,
01849                         /*@null@*/ /*@out@*/ hCNT_t c)
01850         /*@modifies *type, *p, *c @*/
01851         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01852 {
01853     return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01854 }
01855 
01868 static
01869 int headerGetEntryMinMemory(Header h, int_32 tag,
01870                         /*@null@*/ /*@out@*/ hTYP_t type,
01871                         /*@null@*/ /*@out@*/ void * p,
01872                         /*@null@*/ /*@out@*/ hCNT_t c)
01873         /*@modifies *type, *p, *c @*/
01874         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01875 {
01876     return intGetEntry(h, tag, type, p, c, 1);
01877 }
01878 
01879 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, void * p, int_32 * c)
01880 {
01881     indexEntry entry;
01882     int rc;
01883 
01884     if (p == NULL) return headerIsEntry(h, tag);
01885 
01886     /* First find the tag */
01887     /*@-mods@*/         /*@ FIX: h modified by sort. */
01888     entry = findEntry(h, tag, RPM_NULL_TYPE);
01889     /*@=mods@*/
01890     if (!entry) {
01891         if (p) *(void **)p = NULL;
01892         if (c) *c = 0;
01893         return 0;
01894     }
01895 
01896     rc = copyEntry(entry, type, p, c, 0);
01897 
01898     /* XXX 1 on success */
01899     return ((rc == 1) ? 1 : 0);
01900 }
01901 
01904 static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
01905                 int_32 cnt, int dataLength)
01906         /*@modifies *dstPtr @*/
01907 {
01908     switch (type) {
01909     case RPM_STRING_ARRAY_TYPE:
01910     case RPM_I18NSTRING_TYPE:
01911     {   const char ** av = (const char **) srcPtr;
01912         char * t = dstPtr;
01913 
01914 /*@-bounds@*/
01915         while (cnt-- > 0 && dataLength > 0) {
01916             const char * s;
01917             if ((s = *av++) == NULL)
01918                 continue;
01919             do {
01920                 *t++ = *s++;
01921             } while (s[-1] && --dataLength > 0);
01922         }
01923 /*@=bounds@*/
01924     }   break;
01925 
01926     default:
01927 /*@-boundswrite@*/
01928         memmove(dstPtr, srcPtr, dataLength);
01929 /*@=boundswrite@*/
01930         break;
01931     }
01932 }
01933 
01942 /*@null@*/
01943 static void *
01944 grabData(int_32 type, hPTR_t p, int_32 c, /*@out@*/ int * lengthPtr)
01945         /*@modifies *lengthPtr @*/
01946         /*@requires maxSet(lengthPtr) >= 0 @*/
01947 {
01948     void * data = NULL;
01949     int length;
01950 
01951     length = dataLength(type, p, c, 0, NULL);
01952 /*@-branchstate@*/
01953     if (length > 0) {
01954         data = xmalloc(length);
01955         copyData(type, data, p, c, length);
01956     }
01957 /*@=branchstate@*/
01958 
01959     if (lengthPtr)
01960         *lengthPtr = length;
01961     return data;
01962 }
01963 
01978 static
01979 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01980         /*@modifies h @*/
01981 {
01982     indexEntry entry;
01983     void * data;
01984     int length;
01985 
01986     /* Count must always be >= 1 for headerAddEntry. */
01987     if (c <= 0)
01988         return 0;
01989 
01990     if (hdrchkType(type))
01991         return 0;
01992     if (hdrchkData(c))
01993         return 0;
01994 
01995     length = 0;
01996 /*@-boundswrite@*/
01997     data = grabData(type, p, c, &length);
01998 /*@=boundswrite@*/
01999     if (data == NULL || length <= 0)
02000         return 0;
02001 
02002     /* Allocate more index space if necessary */
02003     if (h->indexUsed == h->indexAlloced) {
02004         h->indexAlloced += INDEX_MALLOC_SIZE;
02005         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
02006     }
02007 
02008     /* Fill in the index */
02009     entry = h->index + h->indexUsed;
02010     entry->info.tag = tag;
02011     entry->info.type = type;
02012     entry->info.count = c;
02013     entry->info.offset = 0;
02014     entry->data = data;
02015     entry->length = length;
02016 
02017 /*@-boundsread@*/
02018     if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
02019         h->flags &= ~HEADERFLAG_SORTED;
02020 /*@=boundsread@*/
02021     h->indexUsed++;
02022 
02023     return 1;
02024 }
02025 
02040 static
02041 int headerAppendEntry(Header h, int_32 tag, int_32 type,
02042                 const void * p, int_32 c)
02043         /*@modifies h @*/
02044 {
02045     indexEntry entry;
02046     int length;
02047 
02048     if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
02049         /* we can't do this */
02050         return 0;
02051     }
02052 
02053     /* Find the tag entry in the header. */
02054     entry = findEntry(h, tag, type);
02055     if (!entry)
02056         return 0;
02057 
02058     length = dataLength(type, p, c, 0, NULL);
02059     if (length < 0)
02060         return 0;
02061 
02062     if (ENTRY_IN_REGION(entry)) {
02063         char * t = xmalloc(entry->length + length);
02064 /*@-bounds@*/
02065         memcpy(t, entry->data, entry->length);
02066 /*@=bounds@*/
02067         entry->data = t;
02068         entry->info.offset = 0;
02069     } else
02070         entry->data = xrealloc(entry->data, entry->length + length);
02071 
02072     copyData(type, ((char *) entry->data) + entry->length, p, c, length);
02073 
02074     entry->length += length;
02075 
02076     entry->info.count += c;
02077 
02078     return 1;
02079 }
02080 
02090 static
02091 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
02092                 const void * p, int_32 c)
02093         /*@modifies h @*/
02094 {
02095     return (findEntry(h, tag, type)
02096         ? headerAppendEntry(h, tag, type, p, c)
02097         : headerAddEntry(h, tag, type, p, c));
02098 }
02099 
02120 static
02121 int headerAddI18NString(Header h, int_32 tag, const char * string,
02122                 const char * lang)
02123         /*@modifies h @*/
02124 {
02125     indexEntry table, entry;
02126     const char ** strArray;
02127     int length;
02128     int ghosts;
02129     int i, langNum;
02130     char * buf;
02131 
02132     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02133     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02134 
02135     if (!table && entry)
02136         return 0;               /* this shouldn't ever happen!! */
02137 
02138     if (!table && !entry) {
02139         const char * charArray[2];
02140         int count = 0;
02141         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02142             /*@-observertrans -readonlytrans@*/
02143             charArray[count++] = "C";
02144             /*@=observertrans =readonlytrans@*/
02145         } else {
02146             /*@-observertrans -readonlytrans@*/
02147             charArray[count++] = "C";
02148             /*@=observertrans =readonlytrans@*/
02149             charArray[count++] = lang;
02150         }
02151         if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE, 
02152                         &charArray, count))
02153             return 0;
02154         table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02155     }
02156 
02157     if (!table)
02158         return 0;
02159     /*@-branchstate@*/
02160     if (!lang) lang = "C";
02161     /*@=branchstate@*/
02162 
02163     {   const char * l = table->data;
02164         for (langNum = 0; langNum < table->info.count; langNum++) {
02165             if (!strcmp(l, lang)) break;
02166             l += strlen(l) + 1;
02167         }
02168     }
02169 
02170     if (langNum >= table->info.count) {
02171         length = strlen(lang) + 1;
02172         if (ENTRY_IN_REGION(table)) {
02173             char * t = xmalloc(table->length + length);
02174             memcpy(t, table->data, table->length);
02175             table->data = t;
02176             table->info.offset = 0;
02177         } else
02178             table->data = xrealloc(table->data, table->length + length);
02179         memmove(((char *)table->data) + table->length, lang, length);
02180         table->length += length;
02181         table->info.count++;
02182     }
02183 
02184     if (!entry) {
02185         strArray = alloca(sizeof(*strArray) * (langNum + 1));
02186         for (i = 0; i < langNum; i++)
02187             strArray[i] = "";
02188         strArray[langNum] = string;
02189         return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray, 
02190                                 langNum + 1);
02191     } else if (langNum >= entry->info.count) {
02192         ghosts = langNum - entry->info.count;
02193         
02194         length = strlen(string) + 1 + ghosts;
02195         if (ENTRY_IN_REGION(entry)) {
02196             char * t = xmalloc(entry->length + length);
02197             memcpy(t, entry->data, entry->length);
02198             entry->data = t;
02199             entry->info.offset = 0;
02200         } else
02201             entry->data = xrealloc(entry->data, entry->length + length);
02202 
02203         memset(((char *)entry->data) + entry->length, '\0', ghosts);
02204         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02205 
02206         entry->length += length;
02207         entry->info.count = langNum + 1;
02208     } else {
02209         char *b, *be, *e, *ee, *t;
02210         size_t bn, sn, en;
02211 
02212         /* Set beginning/end pointers to previous data */
02213         b = be = e = ee = entry->data;
02214         for (i = 0; i < table->info.count; i++) {
02215             if (i == langNum)
02216                 be = ee;
02217             ee += strlen(ee) + 1;
02218             if (i == langNum)
02219                 e  = ee;
02220         }
02221 
02222         /* Get storage for new buffer */
02223         bn = (be-b);
02224         sn = strlen(string) + 1;
02225         en = (ee-e);
02226         length = bn + sn + en;
02227         t = buf = xmalloc(length);
02228 
02229         /* Copy values into new storage */
02230         memcpy(t, b, bn);
02231         t += bn;
02232 /*@-mayaliasunique@*/
02233         memcpy(t, string, sn);
02234         t += sn;
02235         memcpy(t, e, en);
02236         t += en;
02237 /*@=mayaliasunique@*/
02238 
02239         /* Replace i18N string array */
02240         entry->length -= strlen(be) + 1;
02241         entry->length += sn;
02242         
02243         if (ENTRY_IN_REGION(entry)) {
02244             entry->info.offset = 0;
02245         } else
02246             entry->data = _free(entry->data);
02247         /*@-dependenttrans@*/
02248         entry->data = buf;
02249         /*@=dependenttrans@*/
02250     }
02251 
02252     return 0;
02253 }
02254 
02265 static
02266 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02267                         const void * p, int_32 c)
02268         /*@modifies h @*/
02269 {
02270     indexEntry entry;
02271     void * oldData;
02272     void * data;
02273     int length;
02274 
02275     /* First find the tag */
02276     entry = findEntry(h, tag, type);
02277     if (!entry)
02278         return 0;
02279 
02280     length = 0;
02281     data = grabData(type, p, c, &length);
02282     if (data == NULL || length <= 0)
02283         return 0;
02284 
02285     /* make sure entry points to the first occurence of this tag */
02286     while (entry > h->index && (entry - 1)->info.tag == tag)  
02287         entry--;
02288 
02289     /* free after we've grabbed the new data in case the two are intertwined;
02290        that's a bad idea but at least we won't break */
02291     oldData = entry->data;
02292 
02293     entry->info.count = c;
02294     entry->info.type = type;
02295     entry->data = data;
02296     entry->length = length;
02297 
02298     /*@-branchstate@*/
02299     if (ENTRY_IN_REGION(entry)) {
02300         entry->info.offset = 0;
02301     } else
02302         oldData = _free(oldData);
02303     /*@=branchstate@*/
02304 
02305     return 1;
02306 }
02307 
02310 static char escapedChar(const char ch)  /*@*/
02311 {
02312     switch (ch) {
02313     case 'a':   return '\a';
02314     case 'b':   return '\b';
02315     case 'f':   return '\f';
02316     case 'n':   return '\n';
02317     case 'r':   return '\r';
02318     case 't':   return '\t';
02319     case 'v':   return '\v';
02320     default:    return ch;
02321     }
02322 }
02323 
02330 static /*@null@*/ sprintfToken
02331 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
02332         /*@modifies *format @*/
02333 {
02334     int i;
02335 
02336     if (format == NULL) return NULL;
02337 
02338     for (i = 0; i < num; i++) {
02339         switch (format[i].type) {
02340         case PTOK_ARRAY:
02341 /*@-boundswrite@*/
02342             format[i].u.array.format =
02343                 freeFormat(format[i].u.array.format,
02344                         format[i].u.array.numTokens);
02345 /*@=boundswrite@*/
02346             /*@switchbreak@*/ break;
02347         case PTOK_COND:
02348 /*@-boundswrite@*/
02349             format[i].u.cond.ifFormat =
02350                 freeFormat(format[i].u.cond.ifFormat, 
02351                         format[i].u.cond.numIfTokens);
02352             format[i].u.cond.elseFormat =
02353                 freeFormat(format[i].u.cond.elseFormat, 
02354                         format[i].u.cond.numElseTokens);
02355 /*@=boundswrite@*/
02356             /*@switchbreak@*/ break;
02357         case PTOK_NONE:
02358         case PTOK_TAG:
02359         case PTOK_STRING:
02360         default:
02361             /*@switchbreak@*/ break;
02362         }
02363     }
02364     format = _free(format);
02365     return NULL;
02366 }
02367 
02371 struct headerIterator_s {
02372 /*@unused@*/
02373     Header h;           
02374 /*@unused@*/
02375     int next_index;     
02376 };
02377 
02383 static /*@null@*/
02384 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi)
02385         /*@modifies hi @*/
02386 {
02387     if (hi != NULL) {
02388         hi->h = headerFree(hi->h);
02389         hi = _free(hi);
02390     }
02391     return hi;
02392 }
02393 
02399 static
02400 HeaderIterator headerInitIterator(Header h)
02401         /*@modifies h */
02402 {
02403     HeaderIterator hi = xmalloc(sizeof(*hi));
02404 
02405     headerSort(h);
02406 
02407     hi->h = headerLink(h);
02408     hi->next_index = 0;
02409     return hi;
02410 }
02411 
02421 static
02422 int headerNextIterator(HeaderIterator hi,
02423                 /*@null@*/ /*@out@*/ hTAG_t tag,
02424                 /*@null@*/ /*@out@*/ hTYP_t type,
02425                 /*@null@*/ /*@out@*/ hPTR_t * p,
02426                 /*@null@*/ /*@out@*/ hCNT_t c)
02427         /*@modifies hi, *tag, *type, *p, *c @*/
02428         /*@requires maxSet(tag) >= 0 /\ maxSet(type) >= 0
02429                 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
02430 {
02431     Header h = hi->h;
02432     int slot = hi->next_index;
02433     indexEntry entry = NULL;
02434     int rc;
02435 
02436     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02437         entry = h->index + slot;
02438         if (!ENTRY_IS_REGION(entry))
02439             break;
02440     }
02441     hi->next_index = slot;
02442     if (entry == NULL || slot >= h->indexUsed)
02443         return 0;
02444 
02445     /*@-noeffect@*/     /* LCL: no clue */
02446     hi->next_index++;
02447     /*@=noeffect@*/
02448 
02449     if (tag)
02450         *tag = entry->info.tag;
02451 
02452     rc = copyEntry(entry, type, p, c, 0);
02453 
02454     /* XXX 1 on success */
02455     return ((rc == 1) ? 1 : 0);
02456 }
02457 
02463 static /*@null@*/
02464 Header headerCopy(Header h)
02465         /*@modifies h @*/
02466 {
02467     Header nh = headerNew();
02468     HeaderIterator hi;
02469     int_32 tag, type, count;
02470     hPTR_t ptr;
02471    
02472     /*@-branchstate@*/
02473     for (hi = headerInitIterator(h);
02474         headerNextIterator(hi, &tag, &type, &ptr, &count);
02475         ptr = headerFreeData((void *)ptr, type))
02476     {
02477         if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02478     }
02479     hi = headerFreeIterator(hi);
02480     /*@=branchstate@*/
02481 
02482     return headerReload(nh, HEADER_IMAGE);
02483 }
02484 
02487 typedef struct headerSprintfArgs_s {
02488     Header h;
02489     char * fmt;
02490 /*@temp@*/
02491     headerTagTableEntry tags;
02492 /*@temp@*/
02493     headerSprintfExtension exts;
02494 /*@observer@*/ /*@null@*/
02495     const char * errmsg;
02496     rpmec ec;
02497     sprintfToken format;
02498 /*@relnull@*/
02499     HeaderIterator hi;
02500 /*@owned@*/
02501     char * val;
02502     size_t vallen;
02503     size_t alloced;
02504     int numTokens;
02505     int i;
02506 } * headerSprintfArgs;
02507 
02513 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
02514         /*@modifies hsa */
02515 {
02516     sprintfTag tag =
02517         (hsa->format->type == PTOK_TAG
02518             ? &hsa->format->u.tag :
02519         (hsa->format->type == PTOK_ARRAY
02520             ? &hsa->format->u.array.format->u.tag :
02521         NULL));
02522 
02523     if (hsa != NULL) {
02524         hsa->i = 0;
02525         if (tag != NULL && tag->tag == -2)
02526             hsa->hi = headerInitIterator(hsa->h);
02527     }
02528 /*@-nullret@*/
02529     return hsa;
02530 /*@=nullret@*/
02531 }
02532 
02538 /*@null@*/
02539 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
02540         /*@modifies hsa */
02541 {
02542     sprintfToken fmt = NULL;
02543     sprintfTag tag =
02544         (hsa->format->type == PTOK_TAG
02545             ? &hsa->format->u.tag :
02546         (hsa->format->type == PTOK_ARRAY
02547             ? &hsa->format->u.array.format->u.tag :
02548         NULL));
02549 
02550     if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02551         fmt = hsa->format + hsa->i;
02552         if (hsa->hi == NULL) {
02553             hsa->i++;
02554         } else {
02555             int_32 tagno;
02556             int_32 type;
02557             int_32 count;
02558 
02559 /*@-boundswrite@*/
02560             if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02561                 fmt = NULL;
02562             tag->tag = tagno;
02563 /*@=boundswrite@*/
02564         }
02565     }
02566 
02567 /*@-dependenttrans -onlytrans@*/
02568     return fmt;
02569 /*@=dependenttrans =onlytrans@*/
02570 }
02571 
02577 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
02578         /*@modifies hsa */
02579 {
02580     if (hsa != NULL) {
02581         hsa->hi = headerFreeIterator(hsa->hi);
02582         hsa->i = 0;
02583     }
02584 /*@-nullret@*/
02585     return hsa;
02586 /*@=nullret@*/
02587 }
02588 
02595 /*@dependent@*/ /*@exposed@*/
02596 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02597         /*@modifies hsa */
02598 {
02599     if ((hsa->vallen + need) >= hsa->alloced) {
02600         if (hsa->alloced <= need)
02601             hsa->alloced += need;
02602         hsa->alloced <<= 1;
02603         hsa->val = xrealloc(hsa->val, hsa->alloced+1);  
02604     }
02605     return hsa->val + hsa->vallen;
02606 }
02607 
02616 /*@observer@*/ /*@null@*/
02617 static const char * myTagName(headerTagTableEntry tbl, int val,
02618                 /*@null@*/ int *typep)
02619         /*@*/
02620 {
02621     static char name[128];
02622     const char * s;
02623     char *t;
02624 
02625     for (; tbl->name != NULL; tbl++) {
02626         if (tbl->val == val)
02627             break;
02628     }
02629     if ((s = tbl->name) == NULL)
02630         return NULL;
02631     s += sizeof("RPMTAG_") - 1;
02632     t = name;
02633     *t++ = *s++;
02634     while (*s != '\0')
02635         *t++ = xtolower(*s++);
02636     *t = '\0';
02637     if (typep)
02638         *typep = tbl->type;
02639     return name;
02640 }
02641 
02649 static int myTagValue(headerTagTableEntry tbl, const char * name)
02650         /*@*/
02651 {
02652     for (; tbl->name != NULL; tbl++) {
02653         if (!xstrcasecmp(tbl->name, name))
02654             return tbl->val;
02655     }
02656     return 0;
02657 }
02658 
02666 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02667         /*@modifies token @*/
02668 {
02669     headerSprintfExtension ext;
02670     sprintfTag stag = (token->type == PTOK_COND
02671         ? &token->u.cond.tag : &token->u.tag);
02672 
02673     stag->fmt = NULL;
02674     stag->ext = NULL;
02675     stag->extNum = 0;
02676     stag->tag = -1;
02677 
02678     if (!strcmp(name, "*")) {
02679         stag->tag = -2;
02680         goto bingo;
02681     }
02682 
02683 /*@-branchstate@*/
02684     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02685 /*@-boundswrite@*/
02686         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02687         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02688         name = t;
02689 /*@=boundswrite@*/
02690     }
02691 /*@=branchstate@*/
02692 
02693     /* Search extensions for specific tag override. */
02694     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02695         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02696     {
02697         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02698             continue;
02699         if (!xstrcasecmp(ext->name, name)) {
02700             stag->ext = ext->u.tagFunction;
02701             stag->extNum = ext - hsa->exts;
02702             goto bingo;
02703         }
02704     }
02705 
02706     /* Search tag names. */
02707     stag->tag = myTagValue(hsa->tags, name);
02708     if (stag->tag != 0)
02709         goto bingo;
02710 
02711     return 1;
02712 
02713 bingo:
02714     /* Search extensions for specific format. */
02715     if (stag->type != NULL)
02716     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02717             ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02718     {
02719         if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02720             continue;
02721         if (!strcmp(ext->name, stag->type)) {
02722             stag->fmt = ext->u.formatFunction;
02723             break;
02724         }
02725     }
02726     return 0;
02727 }
02728 
02729 /* forward ref */
02738 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02739                 char * str, /*@out@*/char ** endPtr)
02740         /*@modifies hsa, str, token, *endPtr @*/
02741         /*@requires maxSet(endPtr) >= 0 @*/;
02742 
02753 static int parseFormat(headerSprintfArgs hsa, /*@null@*/ char * str,
02754                 /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
02755                 /*@null@*/ /*@out@*/ char ** endPtr, int state)
02756         /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
02757         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
02758                 /\ maxSet(endPtr) >= 0 @*/
02759 {
02760     char * chptr, * start, * next, * dst;
02761     sprintfToken format;
02762     sprintfToken token;
02763     int numTokens;
02764     int i;
02765     int done = 0;
02766 
02767     /* upper limit on number of individual formats */
02768     numTokens = 0;
02769     if (str != NULL)
02770     for (chptr = str; *chptr != '\0'; chptr++)
02771         if (*chptr == '%') numTokens++;
02772     numTokens = numTokens * 2 + 1;
02773 
02774     format = xcalloc(numTokens, sizeof(*format));
02775     if (endPtr) *endPtr = NULL;
02776 
02777     /*@-infloops@*/ /* LCL: can't detect done termination */
02778     dst = start = str;
02779     numTokens = 0;
02780     token = NULL;
02781     if (start != NULL)
02782     while (*start != '\0') {
02783         switch (*start) {
02784         case '%':
02785             /* handle %% */
02786             if (*(start + 1) == '%') {
02787                 if (token == NULL || token->type != PTOK_STRING) {
02788                     token = format + numTokens++;
02789                     token->type = PTOK_STRING;
02790                     /*@-temptrans -assignexpose@*/
02791                     dst = token->u.string.string = start;
02792                     /*@=temptrans =assignexpose@*/
02793                 }
02794                 start++;
02795 /*@-boundswrite@*/
02796                 *dst++ = *start++;
02797 /*@=boundswrite@*/
02798                 /*@switchbreak@*/ break;
02799             } 
02800 
02801             token = format + numTokens++;
02802 /*@-boundswrite@*/
02803             *dst++ = '\0';
02804 /*@=boundswrite@*/
02805             start++;
02806 
02807             if (*start == '|') {
02808                 char * newEnd;
02809 
02810                 start++;
02811 /*@-boundswrite@*/
02812                 if (parseExpression(hsa, token, start, &newEnd))
02813                 {
02814                     format = freeFormat(format, numTokens);
02815                     return 1;
02816                 }
02817 /*@=boundswrite@*/
02818                 start = newEnd;
02819                 /*@switchbreak@*/ break;
02820             }
02821 
02822             /*@-assignexpose@*/
02823             token->u.tag.format = start;
02824             /*@=assignexpose@*/
02825             token->u.tag.pad = 0;
02826             token->u.tag.justOne = 0;
02827             token->u.tag.arrayCount = 0;
02828 
02829             chptr = start;
02830             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02831             if (!*chptr || *chptr == '%') {
02832                 hsa->errmsg = _("missing { after %");
02833                 format = freeFormat(format, numTokens);
02834                 return 1;
02835             }
02836 
02837 /*@-boundswrite@*/
02838             *chptr++ = '\0';
02839 /*@=boundswrite@*/
02840 
02841             while (start < chptr) {
02842                 if (xisdigit(*start)) {
02843                     i = strtoul(start, &start, 10);
02844                     token->u.tag.pad += i;
02845                 } else {
02846                     start++;
02847                 }
02848             }
02849 
02850             if (*start == '=') {
02851                 token->u.tag.justOne = 1;
02852                 start++;
02853             } else if (*start == '#') {
02854                 token->u.tag.justOne = 1;
02855                 token->u.tag.arrayCount = 1;
02856                 start++;
02857             }
02858 
02859             next = start;
02860             while (*next && *next != '}') next++;
02861             if (!*next) {
02862                 hsa->errmsg = _("missing } after %{");
02863                 format = freeFormat(format, numTokens);
02864                 return 1;
02865             }
02866 /*@-boundswrite@*/
02867             *next++ = '\0';
02868 /*@=boundswrite@*/
02869 
02870             chptr = start;
02871             while (*chptr && *chptr != ':') chptr++;
02872 
02873             if (*chptr != '\0') {
02874 /*@-boundswrite@*/
02875                 *chptr++ = '\0';
02876 /*@=boundswrite@*/
02877                 if (!*chptr) {
02878                     hsa->errmsg = _("empty tag format");
02879                     format = freeFormat(format, numTokens);
02880                     return 1;
02881                 }
02882                 /*@-assignexpose@*/
02883                 token->u.tag.type = chptr;
02884                 /*@=assignexpose@*/
02885             } else {
02886                 token->u.tag.type = NULL;
02887             }
02888             
02889             if (!*start) {
02890                 hsa->errmsg = _("empty tag name");
02891                 format = freeFormat(format, numTokens);
02892                 return 1;
02893             }
02894 
02895             i = 0;
02896             token->type = PTOK_TAG;
02897 
02898             if (findTag(hsa, token, start)) {
02899                 hsa->errmsg = _("unknown tag");
02900                 format = freeFormat(format, numTokens);
02901                 return 1;
02902             }
02903 
02904             start = next;
02905             /*@switchbreak@*/ break;
02906 
02907         case '[':
02908 /*@-boundswrite@*/
02909             *dst++ = '\0';
02910             *start++ = '\0';
02911 /*@=boundswrite@*/
02912             token = format + numTokens++;
02913 
02914 /*@-boundswrite@*/
02915             if (parseFormat(hsa, start,
02916                             &token->u.array.format,
02917                             &token->u.array.numTokens,
02918                             &start, PARSER_IN_ARRAY))
02919             {
02920                 format = freeFormat(format, numTokens);
02921                 return 1;
02922             }
02923 /*@=boundswrite@*/
02924 
02925             if (!start) {
02926                 hsa->errmsg = _("] expected at end of array");
02927                 format = freeFormat(format, numTokens);
02928                 return 1;
02929             }
02930 
02931             dst = start;
02932 
02933             token->type = PTOK_ARRAY;
02934 
02935             /*@switchbreak@*/ break;
02936 
02937         case ']':
02938             if (state != PARSER_IN_ARRAY) {
02939                 hsa->errmsg = _("unexpected ]");
02940                 format = freeFormat(format, numTokens);
02941                 return 1;
02942             }
02943 /*@-boundswrite@*/
02944             *start++ = '\0';
02945 /*@=boundswrite@*/
02946             if (endPtr) *endPtr = start;
02947             done = 1;
02948             /*@switchbreak@*/ break;
02949 
02950         case '}':
02951             if (state != PARSER_IN_EXPR) {
02952                 hsa->errmsg = _("unexpected }");
02953                 format = freeFormat(format, numTokens);
02954                 return 1;
02955             }
02956 /*@-boundswrite@*/
02957             *start++ = '\0';
02958 /*@=boundswrite@*/
02959             if (endPtr) *endPtr = start;
02960             done = 1;
02961             /*@switchbreak@*/ break;
02962 
02963         default:
02964             if (token == NULL || token->type != PTOK_STRING) {
02965                 token = format + numTokens++;
02966                 token->type = PTOK_STRING;
02967                 /*@-temptrans -assignexpose@*/
02968                 dst = token->u.string.string = start;
02969                 /*@=temptrans =assignexpose@*/
02970             }
02971 
02972 /*@-boundswrite@*/
02973             if (*start == '\\') {
02974                 start++;
02975                 *dst++ = escapedChar(*start++);
02976             } else {
02977                 *dst++ = *start++;
02978             }
02979 /*@=boundswrite@*/
02980             /*@switchbreak@*/ break;
02981         }
02982         if (done)
02983             break;
02984     }
02985     /*@=infloops@*/
02986 
02987 /*@-boundswrite@*/
02988     if (dst != NULL)
02989         *dst = '\0';
02990 /*@=boundswrite@*/
02991 
02992     for (i = 0; i < numTokens; i++) {
02993         token = format + i;
02994         if (token->type == PTOK_STRING)
02995             token->u.string.len = strlen(token->u.string.string);
02996     }
02997 
02998     *numTokensPtr = numTokens;
02999     *formatPtr = format;
03000 
03001     return 0;
03002 }
03003 
03004 /*@-boundswrite@*/
03005 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
03006                 char * str, /*@out@*/ char ** endPtr)
03007 {
03008     char * chptr;
03009     char * end;
03010 
03011     hsa->errmsg = NULL;
03012     chptr = str;
03013     while (*chptr && *chptr != '?') chptr++;
03014 
03015     if (*chptr != '?') {
03016         hsa->errmsg = _("? expected in expression");
03017         return 1;
03018     }
03019 
03020     *chptr++ = '\0';;
03021 
03022     if (*chptr != '{') {
03023         hsa->errmsg = _("{ expected after ? in expression");
03024         return 1;
03025     }
03026 
03027     chptr++;
03028 
03029     if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 
03030                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 
03031         return 1;
03032 
03033     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
03034     if (!(end && *end)) {
03035         hsa->errmsg = _("} expected in expression");
03036         token->u.cond.ifFormat =
03037                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03038         return 1;
03039     }
03040 
03041     chptr = end;
03042     if (*chptr != ':' && *chptr != '|') {
03043         hsa->errmsg = _(": expected following ? subexpression");
03044         token->u.cond.ifFormat =
03045                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03046         return 1;
03047     }
03048 
03049     if (*chptr == '|') {
03050         if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 
03051                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
03052         {
03053             token->u.cond.ifFormat =
03054                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03055             return 1;
03056         }
03057     } else {
03058         chptr++;
03059 
03060         if (*chptr != '{') {
03061             hsa->errmsg = _("{ expected after : in expression");
03062             token->u.cond.ifFormat =
03063                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03064             return 1;
03065         }
03066 
03067         chptr++;
03068 
03069         if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 
03070                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 
03071             return 1;
03072 
03073         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
03074         if (!(end && *end)) {
03075             hsa->errmsg = _("} expected in expression");
03076             token->u.cond.ifFormat =
03077                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03078             return 1;
03079         }
03080 
03081         chptr = end;
03082         if (*chptr != '|') {
03083             hsa->errmsg = _("| expected at end of expression");
03084             token->u.cond.ifFormat =
03085                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03086             token->u.cond.elseFormat =
03087                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
03088             return 1;
03089         }
03090     }
03091         
03092     chptr++;
03093 
03094     *endPtr = chptr;
03095 
03096     token->type = PTOK_COND;
03097 
03098     (void) findTag(hsa, token, str);
03099 
03100     return 0;
03101 }
03102 /*@=boundswrite@*/
03103 
03114 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03115                 /*@out@*/ hTYP_t typeptr,
03116                 /*@out@*/ hPTR_t * data,
03117                 /*@out@*/ hCNT_t countptr,
03118                 rpmec ec)
03119         /*@modifies *typeptr, *data, *countptr, ec @*/
03120         /*@requires maxSet(typeptr) >= 0 /\ maxSet(data) >= 0
03121                 /\ maxSet(countptr) >= 0 @*/
03122 {
03123     if (!ec->avail) {
03124         if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03125             return 1;
03126         ec->avail = 1;
03127     }
03128 
03129     if (typeptr) *typeptr = ec->type;
03130     if (data) *data = ec->data;
03131     if (countptr) *countptr = ec->count;
03132 
03133     return 0;
03134 }
03135 
03143 /*@observer@*/ /*@null@*/
03144 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03145         /*@modifies hsa @*/
03146 {
03147     char * val = NULL;
03148     size_t need = 0;
03149     char * t, * te;
03150     char buf[20];
03151     int_32 count, type;
03152     hPTR_t data;
03153     unsigned int intVal;
03154     uint_64 llVal;
03155     const char ** strarray;
03156     int datafree = 0;
03157     int countBuf;
03158 
03159     memset(buf, 0, sizeof(buf));
03160     if (tag->ext) {
03161 /*@-boundswrite -branchstate @*/
03162         if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03163         {
03164             count = 1;
03165             type = RPM_STRING_TYPE;     
03166             data = "(none)";
03167         }
03168 /*@=boundswrite =branchstate @*/
03169     } else {
03170 /*@-boundswrite -branchstate @*/
03171         if (!headerGetEntry(hsa->h, tag->tag, &type, &data, &count)) {
03172             count = 1;
03173             type = RPM_STRING_TYPE;     
03174             data = "(none)";
03175         }
03176 /*@=boundswrite =branchstate @*/
03177 
03178         /* XXX this test is unnecessary, array sizes are checked */
03179         switch (type) {
03180         default:
03181             if (element >= count) {
03182                 /*@-modobserver -observertrans@*/
03183                 data = headerFreeData(data, type);
03184                 /*@=modobserver =observertrans@*/
03185 
03186                 hsa->errmsg = _("(index out of range)");
03187                 return NULL;
03188             }
03189             break;
03190         case RPM_OPENPGP_TYPE:
03191         case RPM_ASN1_TYPE:
03192         case RPM_BIN_TYPE:
03193         case RPM_STRING_TYPE:
03194             break;
03195         }
03196         datafree = 1;
03197     }
03198 
03199     if (tag->arrayCount) {
03200         /*@-branchstate -observertrans -modobserver@*/
03201         if (datafree)
03202             data = headerFreeData(data, type);
03203         /*@=branchstate =observertrans =modobserver@*/
03204 
03205         countBuf = count;
03206         data = &countBuf;
03207         count = 1;
03208         type = RPM_INT32_TYPE;
03209     }
03210 
03211 /*@-boundswrite@*/
03212     (void) stpcpy( stpcpy(buf, "%"), tag->format);
03213 /*@=boundswrite@*/
03214 
03215     /*@-branchstate@*/
03216     if (data)
03217     switch (type) {
03218     case RPM_STRING_ARRAY_TYPE:
03219         strarray = (const char **)data;
03220 
03221         if (tag->fmt)
03222             val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, (count > 1 ? element : -1));
03223 
03224         if (val) {
03225             need = strlen(val);
03226         } else {
03227             need = strlen(strarray[element]) + tag->pad + 20;
03228             val = xmalloc(need+1);
03229             strcat(buf, "s");
03230             /*@-formatconst@*/
03231             sprintf(val, buf, strarray[element]);
03232             /*@=formatconst@*/
03233         }
03234 
03235         break;
03236 
03237     case RPM_STRING_TYPE:
03238         if (tag->fmt)
03239             val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad,  -1);
03240 
03241         if (val) {
03242             need = strlen(val);
03243         } else {
03244             need = strlen(data) + tag->pad + 20;
03245             val = xmalloc(need+1);
03246             strcat(buf, "s");
03247             /*@-formatconst@*/
03248             sprintf(val, buf, data);
03249             /*@=formatconst@*/
03250         }
03251         break;
03252 
03253     case RPM_INT64_TYPE:
03254         llVal = *(((int_64 *) data) + element);
03255         if (tag->fmt)
03256             val = tag->fmt(RPM_INT64_TYPE, &llVal, buf, tag->pad, (count > 1 ? element : -1));
03257         if (val) {
03258             need = strlen(val);
03259         } else {
03260             need = 10 + tag->pad + 40;
03261             val = xmalloc(need+1);
03262             strcat(buf, "lld");
03263             /*@-formatconst@*/
03264             sprintf(val, buf, llVal);
03265             /*@=formatconst@*/
03266         }
03267         break;
03268 
03269     case RPM_CHAR_TYPE:
03270     case RPM_INT8_TYPE:
03271     case RPM_INT16_TYPE:
03272     case RPM_INT32_TYPE:
03273         switch (type) {
03274         case RPM_CHAR_TYPE:     
03275         case RPM_INT8_TYPE:
03276             intVal = *(((int_8 *) data) + element);
03277             /*@innerbreak@*/ break;
03278         case RPM_INT16_TYPE:
03279             intVal = *(((uint_16 *) data) + element);
03280             /*@innerbreak@*/ break;
03281         default:                /* keep -Wall quiet */
03282         case RPM_INT32_TYPE:
03283             intVal = *(((int_32 *) data) + element);
03284             /*@innerbreak@*/ break;
03285         }
03286 
03287         if (tag->fmt)
03288             val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, (count > 1 ? element : -1));
03289 
03290         if (val) {
03291             need = strlen(val);
03292         } else {
03293             need = 10 + tag->pad + 20;
03294             val = xmalloc(need+1);
03295             strcat(buf, "d");
03296             /*@-formatconst@*/
03297             sprintf(val, buf, intVal);
03298             /*@=formatconst@*/
03299         }
03300         break;
03301 
03302     case RPM_OPENPGP_TYPE:      /* XXX W2DO? */
03303     case RPM_ASN1_TYPE:         /* XXX W2DO? */
03304     case RPM_BIN_TYPE:
03305         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
03306         if (tag->fmt)
03307             val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03308 
03309         if (val) {
03310             need = strlen(val);
03311         } else {
03312 #ifdef  NOTYET
03313             val = memcpy(xmalloc(count), data, count);
03314 #else
03315             /* XXX format string not used */
03316             static char hex[] = "0123456789abcdef";
03317             const char * s = data;
03318 
03319 /*@-boundswrite@*/
03320             need = 2*count + tag->pad;
03321             val = t = xmalloc(need+1);
03322             while (count-- > 0) {
03323                 unsigned int i;
03324                 i = *s++;
03325                 *t++ = hex[ (i >> 4) & 0xf ];
03326                 *t++ = hex[ (i     ) & 0xf ];
03327             }
03328             *t = '\0';
03329 /*@=boundswrite@*/
03330 #endif
03331         }
03332         break;
03333 
03334     default:
03335         need = sizeof("(unknown type)") - 1;
03336         val = xstrdup("(unknown type)");
03337         break;
03338     }
03339     /*@=branchstate@*/
03340 
03341     /*@-branchstate -observertrans -modobserver@*/
03342     if (datafree)
03343         data = headerFreeData(data, type);
03344     /*@=branchstate =observertrans =modobserver@*/
03345 
03346     /*@-branchstate@*/
03347     if (val && need > 0) {
03348         t = hsaReserve(hsa, need);
03349 /*@-boundswrite@*/
03350         te = stpcpy(t, val);
03351 /*@=boundswrite@*/
03352         hsa->vallen += (te - t);
03353         val = _free(val);
03354     }
03355     /*@=branchstate@*/
03356 
03357     return (hsa->val + hsa->vallen);
03358 }
03359 
03367 /*@observer@*/
03368 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03369                 int element)
03370         /*@modifies hsa @*/
03371 {
03372     char numbuf[64];    /* XXX big enuf for "Tag_0x01234567" */
03373     char * t, * te;
03374     int i, j;
03375     int numElements;
03376     int_32 type;
03377     int_32 count;
03378     sprintfToken spft;
03379     int condNumFormats;
03380     size_t need;
03381 
03382     /* we assume the token and header have been validated already! */
03383 
03384     switch (token->type) {
03385     case PTOK_NONE:
03386         break;
03387 
03388     case PTOK_STRING:
03389         need = token->u.string.len;
03390         if (need == 0) break;
03391         t = hsaReserve(hsa, need);
03392 /*@-boundswrite@*/
03393         te = stpcpy(t, token->u.string.string);
03394 /*@=boundswrite@*/
03395         hsa->vallen += (te - t);
03396         break;
03397 
03398     case PTOK_TAG:
03399         t = hsa->val + hsa->vallen;
03400         te = formatValue(hsa, &token->u.tag,
03401                         (token->u.tag.justOne ? 0 : element));
03402         if (te == NULL)
03403             return NULL;
03404         break;
03405 
03406     case PTOK_COND:
03407         if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03408             spft = token->u.cond.ifFormat;
03409             condNumFormats = token->u.cond.numIfTokens;
03410         } else {
03411             spft = token->u.cond.elseFormat;
03412             condNumFormats = token->u.cond.numElseTokens;
03413         }
03414 
03415         need = condNumFormats * 20;
03416         if (spft == NULL || need == 0) break;
03417 
03418         t = hsaReserve(hsa, need);
03419         for (i = 0; i < condNumFormats; i++, spft++) {
03420             te = singleSprintf(hsa, spft, element);
03421             if (te == NULL)
03422                 return NULL;
03423         }
03424         break;
03425 
03426     case PTOK_ARRAY:
03427         numElements = -1;
03428         spft = token->u.array.format;
03429         for (i = 0; i < token->u.array.numTokens; i++, spft++)
03430         {
03431             if (spft->type != PTOK_TAG ||
03432                 spft->u.tag.arrayCount ||
03433                 spft->u.tag.justOne) continue;
03434 
03435             if (spft->u.tag.ext) {
03436 /*@-boundswrite@*/
03437                 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count, 
03438                                  hsa->ec + spft->u.tag.extNum))
03439                      continue;
03440 /*@=boundswrite@*/
03441             } else {
03442 /*@-boundswrite@*/
03443                 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03444                     continue;
03445 /*@=boundswrite@*/
03446             } 
03447 
03448             if (type == RPM_BIN_TYPE || type == RPM_ASN1_TYPE || type == RPM_OPENPGP_TYPE)
03449                 count = 1;      /* XXX count abused as no. of bytes. */
03450 
03451             if (numElements > 1 && count != numElements)
03452             switch (type) {
03453             default:
03454                 hsa->errmsg =
03455                         _("array iterator used with different sized arrays");
03456                 return NULL;
03457                 /*@notreached@*/ /*@switchbreak@*/ break;
03458             case RPM_OPENPGP_TYPE:
03459             case RPM_ASN1_TYPE:
03460             case RPM_BIN_TYPE:
03461             case RPM_STRING_TYPE:
03462                 /*@switchbreak@*/ break;
03463             }
03464             if (count > numElements)
03465                 numElements = count;
03466         }
03467 
03468         if (numElements == -1) {
03469 #ifdef  DYING   /* XXX lots of pugly "(none)" lines with --conflicts. */
03470             need = sizeof("(none)\n") - 1;
03471             t = hsaReserve(hsa, need);
03472 /*@-boundswrite@*/
03473             te = stpcpy(t, "(none)\n");
03474 /*@=boundswrite@*/
03475             hsa->vallen += (te - t);
03476 #endif
03477         } else {
03478             int isxml;
03479             int isyaml;
03480 
03481             need = numElements * token->u.array.numTokens;
03482             if (need == 0) break;
03483 
03484             spft = token->u.array.format;
03485             isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03486                 !strcmp(spft->u.tag.type, "xml"));
03487             isyaml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03488                 !strcmp(spft->u.tag.type, "yaml"));
03489 
03490             if (isxml) {
03491                 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag, NULL);
03492                 /* XXX display "Tag_0x01234567" for unknown tags. */
03493                 if (tagN == NULL) {
03494                     (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03495                                 spft->u.tag.tag);
03496                     numbuf[sizeof(numbuf)-1] = '\0';
03497                     tagN = numbuf;
03498                 }
03499                 need = sizeof("  <rpmTag name=\"\">\n") + strlen(tagN);
03500                 te = t = hsaReserve(hsa, need);
03501 /*@-boundswrite@*/
03502                 te = stpcpy( stpcpy( stpcpy(te, "  <rpmTag name=\""), tagN), "\">\n");
03503 /*@=boundswrite@*/
03504                 hsa->vallen += (te - t);
03505             }
03506             if (isyaml) {
03507                 int tagT = -1;
03508                 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag, &tagT);
03509                 /* XXX display "Tag_0x01234567" for unknown tags. */
03510                 if (tagN == NULL) {
03511                     (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03512                                 spft->u.tag.tag);
03513                     numbuf[sizeof(numbuf)-1] = '\0';
03514                     tagN = numbuf;
03515                     tagT = numElements > 1
03516                         ?  RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE;
03517                 }
03518                 need = sizeof("  :     - ") + strlen(tagN);
03519                 te = t = hsaReserve(hsa, need);
03520 /*@-boundswrite@*/
03521                 *te++ = ' ';
03522                 *te++ = ' ';
03523                 te = stpcpy(te, tagN);
03524                 *te++ = ':';
03525                 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03526                         ? '\n' : ' ');
03527                 /* XXX Dirnames: in srpms need "    " indent */
03528                 if (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03529                  && numElements == 1) {
03530                     te = stpcpy(te, "    ");
03531                     if (spft->u.tag.tag != 1118)
03532                         te = stpcpy(te, "- ");
03533                 }
03534                 *te = '\0';
03535 /*@=boundswrite@*/
03536                 hsa->vallen += (te - t);
03537             }
03538 
03539             need = numElements * token->u.array.numTokens * 10;
03540             t = hsaReserve(hsa, need);
03541             for (j = 0; j < numElements; j++) {
03542                 spft = token->u.array.format;
03543                 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03544                     te = singleSprintf(hsa, spft, j);
03545                     if (te == NULL)
03546                         return NULL;
03547                 }
03548             }
03549 
03550             if (isxml) {
03551                 need = sizeof("  </rpmTag>\n") - 1;
03552                 te = t = hsaReserve(hsa, need);
03553 /*@-boundswrite@*/
03554                 te = stpcpy(te, "  </rpmTag>\n");
03555 /*@=boundswrite@*/
03556                 hsa->vallen += (te - t);
03557             }
03558             if (isyaml) {
03559 #if 0
03560                 need = sizeof("\n") - 1;
03561                 te = t = hsaReserve(hsa, need);
03562 /*@-boundswrite@*/
03563                 te = stpcpy(te, "\n");
03564 /*@=boundswrite@*/
03565                 hsa->vallen += (te - t);
03566 #endif
03567             }
03568 
03569         }
03570         break;
03571     }
03572 
03573     return (hsa->val + hsa->vallen);
03574 }
03575 
03581 static /*@only@*/ rpmec
03582 rpmecNew(const headerSprintfExtension exts)
03583         /*@*/
03584 {
03585     headerSprintfExtension ext;
03586     rpmec ec;
03587     int i = 0;
03588 
03589     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03590         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03591     {
03592         i++;
03593     }
03594 
03595     ec = xcalloc(i, sizeof(*ec));
03596     return ec;
03597 }
03598 
03605 static /*@null@*/ rpmec
03606 rpmecFree(const headerSprintfExtension exts, /*@only@*/ rpmec ec)
03607         /*@modifies ec @*/
03608 {
03609     headerSprintfExtension ext;
03610     int i = 0;
03611 
03612     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03613         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03614     {
03615 /*@-boundswrite@*/
03616         if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03617 /*@=boundswrite@*/
03618         i++;
03619     }
03620 
03621     ec = _free(ec);
03622     return NULL;
03623 }
03624 
03636 static /*@only@*/ /*@null@*/
03637 char * headerSprintf(Header h, const char * fmt,
03638                      const struct headerTagTableEntry_s * tbltags,
03639                      const struct headerSprintfExtension_s * extensions,
03640                      /*@null@*/ /*@out@*/ errmsg_t * errmsg)
03641         /*@modifies h, *errmsg @*/
03642         /*@requires maxSet(errmsg) >= 0 @*/
03643 {
03644     headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03645     sprintfToken nextfmt;
03646     sprintfTag tag;
03647     char * t, * te;
03648     int isxml;
03649     int isyaml;
03650     int need;
03651  
03652     hsa->h = headerLink(h);
03653     hsa->fmt = xstrdup(fmt);
03654 /*@-castexpose@*/       /* FIX: legacy API shouldn't change. */
03655     hsa->exts = (headerSprintfExtension) extensions;
03656     hsa->tags = (headerTagTableEntry) tbltags;
03657 /*@=castexpose@*/
03658     hsa->errmsg = NULL;
03659 
03660 /*@-boundswrite@*/
03661     if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03662         goto exit;
03663 /*@=boundswrite@*/
03664 
03665     hsa->ec = rpmecNew(hsa->exts);
03666     hsa->val = xstrdup("");
03667 
03668     tag =
03669         (hsa->format->type == PTOK_TAG
03670             ? &hsa->format->u.tag :
03671         (hsa->format->type == PTOK_ARRAY
03672             ? &hsa->format->u.array.format->u.tag :
03673         NULL));
03674     isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03675     isyaml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "yaml"));
03676 
03677     if (isxml) {
03678         need = sizeof("<rpmHeader>\n") - 1;
03679         t = hsaReserve(hsa, need);
03680 /*@-boundswrite@*/
03681         te = stpcpy(t, "<rpmHeader>\n");
03682 /*@=boundswrite@*/
03683         hsa->vallen += (te - t);
03684     }
03685     if (isyaml) {
03686         need = sizeof("- !!omap\n") - 1;
03687         t = hsaReserve(hsa, need);
03688 /*@-boundswrite@*/
03689         te = stpcpy(t, "- !!omap\n");
03690 /*@=boundswrite@*/
03691         hsa->vallen += (te - t);
03692     }
03693 
03694     hsa = hsaInit(hsa);
03695     while ((nextfmt = hsaNext(hsa)) != NULL) {
03696         te = singleSprintf(hsa, nextfmt, 0);
03697         if (te == NULL) {
03698             hsa->val = _free(hsa->val);
03699             break;
03700         }
03701     }
03702     hsa = hsaFini(hsa);
03703 
03704     if (isxml) {
03705         need = sizeof("</rpmHeader>\n") - 1;
03706         t = hsaReserve(hsa, need);
03707 /*@-boundswrite@*/
03708         te = stpcpy(t, "</rpmHeader>\n");
03709 /*@=boundswrite@*/
03710         hsa->vallen += (te - t);
03711     }
03712     if (isyaml) {
03713         need = sizeof("\n") - 1;
03714         t = hsaReserve(hsa, need);
03715 /*@-boundswrite@*/
03716         te = stpcpy(t, "\n");
03717 /*@=boundswrite@*/
03718         hsa->vallen += (te - t);
03719     }
03720 
03721     if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03722         hsa->val = xrealloc(hsa->val, hsa->vallen+1);   
03723 
03724     hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03725     hsa->format = freeFormat(hsa->format, hsa->numTokens);
03726 
03727 exit:
03728 /*@-dependenttrans -observertrans @*/
03729     if (errmsg)
03730         *errmsg = hsa->errmsg;
03731 /*@=dependenttrans =observertrans @*/
03732     hsa->h = headerFree(hsa->h);
03733     hsa->fmt = _free(hsa->fmt);
03734     return hsa->val;
03735 }
03736 
03746 static char * octalFormat(int_32 type, hPTR_t data, 
03747                 char * formatPrefix, int padding, /*@unused@*/int element)
03748         /*@modifies formatPrefix @*/
03749 {
03750     char * val;
03751 
03752     if (type == RPM_INT32_TYPE) {
03753         val = xmalloc(20 + padding);
03754 /*@-boundswrite@*/
03755         strcat(formatPrefix, "o");
03756 /*@=boundswrite@*/
03757         /*@-formatconst@*/
03758         sprintf(val, formatPrefix, *((int_32 *) data));
03759         /*@=formatconst@*/
03760     } else if (type == RPM_INT64_TYPE) {
03761         val = xmalloc(40 + padding);
03762 /*@-boundswrite@*/
03763         strcat(formatPrefix, "llo");
03764 /*@=boundswrite@*/
03765         /*@-formatconst@*/
03766         sprintf(val, formatPrefix, *((int_64 *) data));
03767         /*@=formatconst@*/
03768     } else
03769         val = xstrdup(_("(not a number)"));
03770 
03771     return val;
03772 }
03773 
03783 static char * hexFormat(int_32 type, hPTR_t data, 
03784                 char * formatPrefix, int padding, /*@unused@*/int element)
03785         /*@modifies formatPrefix @*/
03786 {
03787     char * val;
03788 
03789     if (type == RPM_INT32_TYPE) {
03790         val = xmalloc(20 + padding);
03791 /*@-boundswrite@*/
03792         strcat(formatPrefix, "x");
03793 /*@=boundswrite@*/
03794         /*@-formatconst@*/
03795         sprintf(val, formatPrefix, *((int_32 *) data));
03796         /*@=formatconst@*/
03797     } else if (type == RPM_INT64_TYPE) {
03798         val = xmalloc(40 + padding);
03799 /*@-boundswrite@*/
03800         strcat(formatPrefix, "llx");
03801 /*@=boundswrite@*/
03802         /*@-formatconst@*/
03803         sprintf(val, formatPrefix, *((int_64 *) data));
03804         /*@=formatconst@*/
03805     } else
03806         val = xstrdup(_("(not a number)"));
03807 
03808     return val;
03809 }
03810 
03821 static char * realDateFormat(int_32 type, hPTR_t data, 
03822                 char * formatPrefix, int padding, /*@unused@*/int element,
03823                 const char * strftimeFormat)
03824         /*@modifies formatPrefix @*/
03825 {
03826     char * val;
03827 
03828     if (type != RPM_INT32_TYPE) {
03829         val = xstrdup(_("(not a number)"));
03830     } else {
03831         struct tm * tstruct;
03832         char buf[50];
03833 
03834         val = xmalloc(50 + padding);
03835 /*@-boundswrite@*/
03836         strcat(formatPrefix, "s");
03837 /*@=boundswrite@*/
03838 
03839         /* this is important if sizeof(int_32) ! sizeof(time_t) */
03840         {   time_t dateint = *((int_32 *) data);
03841             tstruct = localtime(&dateint);
03842         }
03843         buf[0] = '\0';
03844         if (tstruct)
03845             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03846         /*@-formatconst@*/
03847         sprintf(val, formatPrefix, buf);
03848         /*@=formatconst@*/
03849     }
03850 
03851     return val;
03852 }
03853 
03863 static char * dateFormat(int_32 type, hPTR_t data, 
03864                          char * formatPrefix, int padding, int element)
03865         /*@modifies formatPrefix @*/
03866 {
03867     return realDateFormat(type, data, formatPrefix, padding, element,
03868                         _("%c"));
03869 }
03870 
03880 static char * dayFormat(int_32 type, hPTR_t data, 
03881                          char * formatPrefix, int padding, int element)
03882         /*@modifies formatPrefix @*/
03883 {
03884     return realDateFormat(type, data, formatPrefix, padding, element, 
03885                           _("%a %b %d %Y"));
03886 }
03887 
03897 static char * shescapeFormat(int_32 type, hPTR_t data, 
03898                 char * formatPrefix, int padding, /*@unused@*/int element)
03899         /*@modifies formatPrefix @*/
03900 {
03901     char * result, * dst, * src, * buf;
03902 
03903     if (type == RPM_INT32_TYPE) {
03904         result = xmalloc(padding + 20);
03905 /*@-boundswrite@*/
03906         strcat(formatPrefix, "d");
03907 /*@=boundswrite@*/
03908         /*@-formatconst@*/
03909         sprintf(result, formatPrefix, *((int_32 *) data));
03910         /*@=formatconst@*/
03911     } else if (type == RPM_INT64_TYPE) {
03912         result = xmalloc(padding + 40);
03913 /*@-boundswrite@*/
03914         strcat(formatPrefix, "lld");
03915 /*@=boundswrite@*/
03916         /*@-formatconst@*/
03917         sprintf(result, formatPrefix, *((int_64 *) data));
03918         /*@=formatconst@*/
03919     } else {
03920         buf = alloca(strlen(data) + padding + 2);
03921 /*@-boundswrite@*/
03922         strcat(formatPrefix, "s");
03923 /*@=boundswrite@*/
03924         /*@-formatconst@*/
03925         sprintf(buf, formatPrefix, data);
03926         /*@=formatconst@*/
03927 
03928 /*@-boundswrite@*/
03929         result = dst = xmalloc(strlen(buf) * 4 + 3);
03930         *dst++ = '\'';
03931         for (src = buf; *src != '\0'; src++) {
03932             if (*src == '\'') {
03933                 *dst++ = '\'';
03934                 *dst++ = '\\';
03935                 *dst++ = '\'';
03936                 *dst++ = '\'';
03937             } else {
03938                 *dst++ = *src;
03939             }
03940         }
03941         *dst++ = '\'';
03942         *dst = '\0';
03943 /*@=boundswrite@*/
03944 
03945     }
03946 
03947     return result;
03948 }
03949 
03950 /*@-type@*/ /* FIX: cast? */
03951 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03952     { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03953     { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03954     { HEADER_EXT_FORMAT, "date", { dateFormat } },
03955     { HEADER_EXT_FORMAT, "day", { dayFormat } },
03956     { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03957     { HEADER_EXT_LAST, NULL, { NULL } }
03958 };
03959 /*@=type@*/
03960 
03967 static
03968 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03969         /*@modifies headerTo @*/
03970 {
03971     int * p;
03972 
03973     if (headerFrom == headerTo)
03974         return;
03975 
03976     for (p = tagstocopy; *p != 0; p++) {
03977         char *s;
03978         int_32 type;
03979         int_32 count;
03980         if (headerIsEntry(headerTo, *p))
03981             continue;
03982 /*@-boundswrite@*/
03983         if (!headerGetEntryMinMemory(headerFrom, *p, &type, &s, &count))
03984             continue;
03985 /*@=boundswrite@*/
03986         (void) headerAddEntry(headerTo, *p, type, s, count);
03987         s = headerFreeData(s, type);
03988     }
03989 }
03990 
03991 /*@observer@*/ /*@unchecked@*/
03992 static struct HV_s hdrVec1 = {
03993     headerLink,
03994     headerUnlink,
03995     headerFree,
03996     headerNew,
03997     headerSort,
03998     headerUnsort,
03999     headerSizeof,
04000     headerUnload,
04001     headerReload,
04002     headerCopy,
04003     headerLoad,
04004     headerCopyLoad,
04005     headerRead,
04006     headerWrite,
04007     headerIsEntry,
04008     headerFreeTag,
04009     headerGetEntry,
04010     headerGetEntryMinMemory,
04011     headerAddEntry,
04012     headerAppendEntry,
04013     headerAddOrAppendEntry,
04014     headerAddI18NString,
04015     headerModifyEntry,
04016     headerRemoveEntry,
04017     headerSprintf,
04018     headerCopyTags,
04019     headerFreeIterator,
04020     headerInitIterator,
04021     headerNextIterator,
04022     headerGetOrigin,
04023     headerSetOrigin,
04024     headerGetInstance,
04025     headerSetInstance,
04026     NULL, NULL,
04027     1
04028 };
04029 
04030 /*@-compmempass -redef@*/
04031 /*@observer@*/ /*@unchecked@*/
04032 HV_t hdrVec = &hdrVec1;
04033 /*@=compmempass =redef@*/

Generated on Fri Aug 31 10:50:46 2007 for rpm by  doxygen 1.5.1