rpm
4.5
|
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 #include <rpmmacro.h> 00018 00019 #include "debug.h" 00020 00021 /*@unchecked@*/ 00022 int _hdr_debug = 0; 00023 00024 /*@unchecked@*/ 00025 int _tagcache = 1; /* XXX Cache tag data persistently? */ 00026 00027 /*@access entryInfo @*/ 00028 /*@access indexEntry @*/ 00029 00030 /*@access sprintfTag @*/ 00031 /*@access sprintfToken @*/ 00032 /*@access HV_t @*/ 00033 00034 #define PARSER_BEGIN 0 00035 #define PARSER_IN_ARRAY 1 00036 #define PARSER_IN_EXPR 2 00037 00040 /*@observer@*/ /*@unchecked@*/ 00041 static unsigned char header_magic[8] = { 00042 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00 00043 }; 00044 00048 /*@observer@*/ /*@unchecked@*/ 00049 static int typeAlign[16] = { 00050 1, 00051 1, 00052 1, 00053 2, 00054 4, 00055 8, 00056 1, 00057 1, 00058 1, 00059 1, 00060 1, 00061 1, 00062 0, 00063 0, 00064 0, 00065 0 00066 }; 00067 00071 /*@observer@*/ /*@unchecked@*/ 00072 static int typeSizes[16] = { 00073 0, 00074 1, 00075 1, 00076 2, 00077 4, 00078 8, 00079 -1, 00080 1, 00081 -1, 00082 -1, 00083 1, 00084 1, 00085 0, 00086 0, 00087 0, 00088 0 00089 }; 00090 00094 /*@unchecked@*/ 00095 static size_t headerMaxbytes = (32*1024*1024); 00096 00101 #define hdrchkTags(_ntags) ((_ntags) & 0xffff0000) 00102 00106 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE) 00107 00112 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000) 00113 00117 #define hdrchkAlign(_type, _off) ((_off) & (typeAlign[_type]-1)) 00118 00122 #define hdrchkRange(_dl, _off) ((_off) < 0 || (_off) > (_dl)) 00123 00124 /*@observer@*/ /*@unchecked@*/ 00125 HV_t hdrVec; /* forward reference */ 00126 00133 static /*@null@*/ 00134 void * headerGetStats(/*@unused@*/ Header h, /*@unused@*/ int opx) 00135 /*@*/ 00136 { 00137 rpmop op = NULL; 00138 return op; 00139 } 00140 00146 static 00147 Header headerLink(Header h) 00148 /*@modifies h @*/ 00149 { 00150 /*@-nullret@*/ 00151 if (h == NULL) return NULL; 00152 /*@=nullret@*/ 00153 00154 h->nrefs++; 00155 /*@-modfilesys@*/ 00156 if (_hdr_debug) 00157 fprintf(stderr, "--> h %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__); 00158 /*@=modfilesys@*/ 00159 00160 /*@-refcounttrans @*/ 00161 return h; 00162 /*@=refcounttrans @*/ 00163 } 00164 00170 static /*@null@*/ 00171 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h) 00172 /*@modifies h @*/ 00173 { 00174 if (h == NULL) return NULL; 00175 /*@-modfilesys@*/ 00176 if (_hdr_debug) 00177 fprintf(stderr, "--> h %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__); 00178 /*@=modfilesys@*/ 00179 h->nrefs--; 00180 return NULL; 00181 } 00182 00188 static /*@null@*/ 00189 Header headerFree(/*@killref@*/ /*@null@*/ Header h) 00190 /*@modifies h @*/ 00191 { 00192 (void) headerUnlink(h); 00193 00194 /*@-usereleased@*/ 00195 if (h == NULL || h->nrefs > 0) 00196 return NULL; /* XXX return previous header? */ 00197 00198 if (h->index) { 00199 indexEntry entry = h->index; 00200 int i; 00201 for (i = 0; i < h->indexUsed; i++, entry++) { 00202 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) { 00203 if (entry->length > 0) { 00204 int_32 * ei = entry->data; 00205 if ((ei - 2) == h->blob) h->blob = _free(h->blob); 00206 entry->data = NULL; 00207 } 00208 } else if (!ENTRY_IN_REGION(entry)) { 00209 entry->data = _free(entry->data); 00210 } 00211 entry->data = NULL; 00212 } 00213 h->index = _free(h->index); 00214 } 00215 h->origin = _free(h->origin); 00216 h->baseurl = _free(h->baseurl); 00217 h->digest = _free(h->digest); 00218 00219 /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/ 00220 return h; 00221 /*@=usereleased@*/ 00222 } 00223 00228 static 00229 Header headerNew(void) 00230 /*@*/ 00231 { 00232 Header h = xcalloc(1, sizeof(*h)); 00233 00234 /*@-assignexpose@*/ 00235 h->hv = *hdrVec; /* structure assignment */ 00236 /*@=assignexpose@*/ 00237 h->blob = NULL; 00238 h->origin = NULL; 00239 h->baseurl = NULL; 00240 h->digest = NULL; 00241 h->instance = 0; 00242 h->indexAlloced = INDEX_MALLOC_SIZE; 00243 h->indexUsed = 0; 00244 h->flags |= HEADERFLAG_SORTED; 00245 00246 h->index = (h->indexAlloced 00247 ? xcalloc(h->indexAlloced, sizeof(*h->index)) 00248 : NULL); 00249 00250 h->nrefs = 0; 00251 /*@-globstate -observertrans @*/ 00252 return headerLink(h); 00253 /*@=globstate =observertrans @*/ 00254 } 00255 00258 static int indexCmp(const void * avp, const void * bvp) 00259 /*@*/ 00260 { 00261 /*@-castexpose@*/ 00262 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp; 00263 /*@=castexpose@*/ 00264 return (ap->info.tag - bp->info.tag); 00265 } 00266 00271 static 00272 void headerSort(Header h) 00273 /*@modifies h @*/ 00274 { 00275 if (!(h->flags & HEADERFLAG_SORTED)) { 00276 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp); 00277 h->flags |= HEADERFLAG_SORTED; 00278 } 00279 } 00280 00283 static int offsetCmp(const void * avp, const void * bvp) /*@*/ 00284 { 00285 /*@-castexpose@*/ 00286 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp; 00287 /*@=castexpose@*/ 00288 int rc = (ap->info.offset - bp->info.offset); 00289 00290 if (rc == 0) { 00291 /* Within a region, entries sort by address. Added drips sort by tag. */ 00292 if (ap->info.offset < 0) 00293 rc = (((char *)ap->data) - ((char *)bp->data)); 00294 else 00295 rc = (ap->info.tag - bp->info.tag); 00296 } 00297 return rc; 00298 } 00299 00304 static 00305 void headerUnsort(Header h) 00306 /*@modifies h @*/ 00307 { 00308 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp); 00309 } 00310 00317 static 00318 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp) 00319 /*@modifies h @*/ 00320 { 00321 indexEntry entry; 00322 unsigned int size = 0; 00323 unsigned int pad = 0; 00324 int i; 00325 00326 if (h == NULL) 00327 return size; 00328 00329 headerSort(h); 00330 00331 switch (magicp) { 00332 case HEADER_MAGIC_YES: 00333 size += sizeof(header_magic); 00334 break; 00335 case HEADER_MAGIC_NO: 00336 break; 00337 } 00338 00339 /*@-sizeoftype@*/ 00340 size += 2 * sizeof(int_32); /* count of index entries */ 00341 /*@=sizeoftype@*/ 00342 00343 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) { 00344 unsigned diff; 00345 rpmTagType type; 00346 00347 /* Regions go in as is ... */ 00348 if (ENTRY_IS_REGION(entry)) { 00349 size += entry->length; 00350 /* XXX Legacy regions do not include the region tag and data. */ 00351 /*@-sizeoftype@*/ 00352 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) 00353 size += sizeof(struct entryInfo_s) + entry->info.count; 00354 /*@=sizeoftype@*/ 00355 continue; 00356 } 00357 00358 /* ... and region elements are skipped. */ 00359 if (entry->info.offset < 0) 00360 continue; 00361 00362 /* Alignment */ 00363 type = entry->info.type; 00364 if (typeSizes[type] > 1) { 00365 diff = typeSizes[type] - (size % typeSizes[type]); 00366 if (diff != typeSizes[type]) { 00367 size += diff; 00368 pad += diff; 00369 } 00370 } 00371 00372 /*@-sizeoftype@*/ 00373 size += sizeof(struct entryInfo_s) + entry->length; 00374 /*@=sizeoftype@*/ 00375 } 00376 00377 return size; 00378 } 00379 00389 static int dataLength(rpmTagType type, rpmTagData * p, rpmTagCount count, 00390 int onDisk, /*@null@*/ rpmTagData * pend) 00391 /*@*/ 00392 { 00393 const unsigned char * s = (*p).ui8p; 00394 const unsigned char * se = (pend ? (*pend).ui8p : NULL); 00395 int length = 0; 00396 00397 switch (type) { 00398 case RPM_STRING_TYPE: 00399 if (count != 1) 00400 return -1; 00401 while (*s++) { 00402 if (se && s > se) 00403 return -1; 00404 length++; 00405 } 00406 length++; /* count nul terminator too. */ 00407 break; 00408 /* These are like RPM_STRING_TYPE, except they're *always* an array */ 00409 /* Compute sum of length of all strings, including nul terminators */ 00410 case RPM_I18NSTRING_TYPE: 00411 case RPM_STRING_ARRAY_TYPE: 00412 if (onDisk) { 00413 while (count--) { 00414 length++; /* count nul terminator too */ 00415 while (*s++) { 00416 if (se && s > se) 00417 return -1; /* XXX change errret, use size_t */ 00418 length++; 00419 } 00420 } 00421 } else { 00422 const char ** av = (*p).argv; 00423 while (count--) { 00424 /* add one for null termination */ 00425 length += strlen(*av++) + 1; 00426 } 00427 } 00428 break; 00429 default: 00430 if (typeSizes[type] == -1) 00431 return -1; /* XXX change errret, use size_t */ 00432 length = typeSizes[(type & 0xf)] * count; 00433 if (length < 0 || (se && (s + length) > se)) 00434 return -1; /* XXX change errret, use size_t */ 00435 break; 00436 } 00437 00438 return length; 00439 } 00440 00467 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl, 00468 entryInfo pe, 00469 unsigned char * dataStart, 00470 /*@null@*/ const unsigned char * dataEnd, 00471 int regionid) 00472 /*@modifies *entry, *dataStart @*/ 00473 { 00474 rpmTagData p; 00475 rpmTagData pend; 00476 unsigned char * tprev = NULL; 00477 unsigned char * t = NULL; 00478 int tdel = 0; 00479 int tl = dl; 00480 struct indexEntry_s ieprev; 00481 00482 memset(&ieprev, 0, sizeof(ieprev)); 00483 for (; il > 0; il--, pe++) { 00484 struct indexEntry_s ie; 00485 rpmTagType type; 00486 00487 ie.info.tag = ntohl(pe->tag); 00488 ie.info.type = ntohl(pe->type); 00489 ie.info.count = ntohl(pe->count); 00490 ie.info.offset = ntohl(pe->offset); 00491 00492 if (hdrchkType(ie.info.type)) 00493 return -1; 00494 if (hdrchkData(ie.info.count)) 00495 return -1; 00496 if (hdrchkData(ie.info.offset)) 00497 return -1; 00498 if (hdrchkAlign(ie.info.type, ie.info.offset)) 00499 return -1; 00500 00501 ie.data = t = dataStart + ie.info.offset; 00502 if (dataEnd && t >= dataEnd) 00503 return -1; 00504 00505 p.ptr = ie.data; 00506 pend.ui8p = (unsigned char *) dataEnd; 00507 ie.length = dataLength(ie.info.type, &p, ie.info.count, 1, &pend); 00508 if (ie.length < 0 || hdrchkData(ie.length)) 00509 return -1; 00510 00511 ie.rdlen = 0; 00512 00513 if (entry) { 00514 ie.info.offset = regionid; 00515 *entry = ie; /* structure assignment */ 00516 entry++; 00517 } 00518 00519 /* Alignment */ 00520 type = ie.info.type; 00521 if (typeSizes[type] > 1) { 00522 unsigned diff; 00523 diff = typeSizes[type] - (dl % typeSizes[type]); 00524 if (diff != typeSizes[type]) { 00525 dl += diff; 00526 if (ieprev.info.type == RPM_I18NSTRING_TYPE) 00527 ieprev.length += diff; 00528 } 00529 } 00530 tdel = (tprev ? (t - tprev) : 0); 00531 if (ieprev.info.type == RPM_I18NSTRING_TYPE) 00532 tdel = ieprev.length; 00533 00534 if (ie.info.tag >= HEADER_I18NTABLE) { 00535 tprev = t; 00536 } else { 00537 tprev = dataStart; 00538 /* XXX HEADER_IMAGE tags don't include region sub-tag. */ 00539 /*@-sizeoftype@*/ 00540 if (ie.info.tag == HEADER_IMAGE) 00541 tprev -= REGION_TAG_COUNT; 00542 /*@=sizeoftype@*/ 00543 } 00544 00545 /* Perform endian conversions */ 00546 switch (ntohl(pe->type)) { 00547 case RPM_INT64_TYPE: 00548 { int_64 * it = (int_64 *)t; 00549 int_32 b[2]; 00550 for (; ie.info.count > 0; ie.info.count--, it += 1) { 00551 if (dataEnd && ((unsigned char *)it) >= dataEnd) 00552 return -1; 00553 b[1] = htonl(((int_32 *)it)[0]); 00554 b[0] = htonl(((int_32 *)it)[1]); 00555 if (b[1] != ((int_32 *)it)[0]) 00556 memcpy(it, b, sizeof(b)); 00557 } 00558 t = (unsigned char *) it; 00559 } /*@switchbreak@*/ break; 00560 case RPM_INT32_TYPE: 00561 { int_32 * it = (int_32 *)t; 00562 for (; ie.info.count > 0; ie.info.count--, it += 1) { 00563 if (dataEnd && ((unsigned char *)it) >= dataEnd) 00564 return -1; 00565 *it = htonl(*it); 00566 } 00567 t = (unsigned char *) it; 00568 } /*@switchbreak@*/ break; 00569 case RPM_INT16_TYPE: 00570 { int_16 * it = (int_16 *) t; 00571 for (; ie.info.count > 0; ie.info.count--, it += 1) { 00572 if (dataEnd && ((unsigned char *)it) >= dataEnd) 00573 return -1; 00574 *it = htons(*it); 00575 } 00576 t = (unsigned char *) it; 00577 } /*@switchbreak@*/ break; 00578 default: 00579 t += ie.length; 00580 /*@switchbreak@*/ break; 00581 } 00582 00583 dl += ie.length; 00584 if (dataEnd && (dataStart + dl) > dataEnd) return -1; 00585 tl += tdel; 00586 ieprev = ie; /* structure assignment */ 00587 00588 } 00589 tdel = (tprev ? (t - tprev) : 0); 00590 tl += tdel; 00591 00592 /* XXX 00593 * There are two hacks here: 00594 * 1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload(). 00595 * 2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl. 00596 */ 00597 /*@-sizeoftype@*/ 00598 if (tl+REGION_TAG_COUNT == dl) 00599 tl += REGION_TAG_COUNT; 00600 /*@=sizeoftype@*/ 00601 00602 return dl; 00603 } 00604 00610 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h, 00611 /*@out@*/ size_t * lenp) 00612 /*@modifies h, *lenp @*/ 00613 /*@requires maxSet(lenp) >= 0 @*/ 00614 /*@ensures maxRead(result) == (*lenp) @*/ 00615 { 00616 void * sw; 00617 int_32 * ei = NULL; 00618 entryInfo pe; 00619 unsigned char * dataStart; 00620 unsigned char * te; 00621 unsigned pad; 00622 unsigned len = 0; 00623 int_32 il = 0; 00624 int_32 dl = 0; 00625 indexEntry entry; 00626 rpmTagType type; 00627 int i; 00628 int drlen, ndribbles; 00629 int driplen, ndrips; 00630 int legacy = 0; 00631 00632 if ((sw = headerGetStats(h, 18)) != NULL) /* RPMTS_OP_HDRLOAD */ 00633 (void) rpmswEnter(sw, 0); 00634 00635 /* Sort entries by (offset,tag). */ 00636 headerUnsort(h); 00637 00638 /* Compute (il,dl) for all tags, including those deleted in region. */ 00639 pad = 0; 00640 drlen = ndribbles = driplen = ndrips = 0; 00641 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) { 00642 if (ENTRY_IS_REGION(entry)) { 00643 int_32 rdl = -entry->info.offset; /* negative offset */ 00644 int_32 ril = rdl/sizeof(*pe); 00645 int rid = entry->info.offset; 00646 00647 il += ril; 00648 dl += entry->rdlen + entry->info.count; 00649 /* XXX Legacy regions do not include the region tag and data. */ 00650 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) 00651 il += 1; 00652 00653 /* Skip rest of entries in region, but account for dribbles. */ 00654 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) { 00655 if (entry->info.offset <= rid) 00656 /*@innercontinue@*/ continue; 00657 00658 /* Alignment */ 00659 type = entry->info.type; 00660 if (typeSizes[type] > 1) { 00661 unsigned diff; 00662 diff = typeSizes[type] - (dl % typeSizes[type]); 00663 if (diff != typeSizes[type]) { 00664 drlen += diff; 00665 pad += diff; 00666 dl += diff; 00667 } 00668 } 00669 00670 ndribbles++; 00671 il++; 00672 drlen += entry->length; 00673 dl += entry->length; 00674 } 00675 i--; 00676 entry--; 00677 continue; 00678 } 00679 00680 /* Ignore deleted drips. */ 00681 if (entry->data == NULL || entry->length <= 0) 00682 continue; 00683 00684 /* Alignment */ 00685 type = entry->info.type; 00686 if (typeSizes[type] > 1) { 00687 unsigned diff; 00688 diff = typeSizes[type] - (dl % typeSizes[type]); 00689 if (diff != typeSizes[type]) { 00690 driplen += diff; 00691 pad += diff; 00692 dl += diff; 00693 } else 00694 diff = 0; 00695 } 00696 00697 ndrips++; 00698 il++; 00699 driplen += entry->length; 00700 dl += entry->length; 00701 } 00702 00703 /* Sanity checks on header intro. */ 00704 if (hdrchkTags(il) || hdrchkData(dl)) 00705 goto errxit; 00706 00707 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl; 00708 00709 ei = xmalloc(len); 00710 ei[0] = htonl(il); 00711 ei[1] = htonl(dl); 00712 00713 pe = (entryInfo) &ei[2]; 00714 dataStart = te = (unsigned char *) (pe + il); 00715 00716 pad = 0; 00717 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) { 00718 const char * src; 00719 unsigned char *t; 00720 int count; 00721 int rdlen; 00722 00723 if (entry->data == NULL || entry->length <= 0) 00724 continue; 00725 00726 t = te; 00727 pe->tag = htonl(entry->info.tag); 00728 pe->type = htonl(entry->info.type); 00729 pe->count = htonl(entry->info.count); 00730 00731 if (ENTRY_IS_REGION(entry)) { 00732 int_32 rdl = -entry->info.offset; /* negative offset */ 00733 int_32 ril = rdl/sizeof(*pe) + ndribbles; 00734 int rid = entry->info.offset; 00735 00736 src = (char *)entry->data; 00737 rdlen = entry->rdlen; 00738 00739 /* XXX Legacy regions do not include the region tag and data. */ 00740 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) { 00741 int_32 stei[4]; 00742 00743 legacy = 1; 00744 memcpy(pe+1, src, rdl); 00745 memcpy(te, src + rdl, rdlen); 00746 te += rdlen; 00747 00748 pe->offset = htonl(te - dataStart); 00749 stei[0] = pe->tag; 00750 stei[1] = pe->type; 00751 stei[2] = htonl(-rdl-entry->info.count); 00752 stei[3] = pe->count; 00753 memcpy(te, stei, entry->info.count); 00754 te += entry->info.count; 00755 ril++; 00756 rdlen += entry->info.count; 00757 00758 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0); 00759 if (count != rdlen) 00760 goto errxit; 00761 00762 } else { 00763 00764 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe))); 00765 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen); 00766 te += rdlen; 00767 { /*@-castexpose@*/ 00768 entryInfo se = (entryInfo)src; 00769 /*@=castexpose@*/ 00770 int off = ntohl(se->offset); 00771 pe->offset = (off) ? htonl(te - dataStart) : htonl(off); 00772 } 00773 te += entry->info.count + drlen; 00774 00775 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0); 00776 if (count != (rdlen + entry->info.count + drlen)) 00777 goto errxit; 00778 } 00779 00780 /* Skip rest of entries in region. */ 00781 while (i < h->indexUsed && entry->info.offset <= rid+1) { 00782 i++; 00783 entry++; 00784 } 00785 i--; 00786 entry--; 00787 pe += ril; 00788 continue; 00789 } 00790 00791 /* Ignore deleted drips. */ 00792 if (entry->data == NULL || entry->length <= 0) 00793 continue; 00794 00795 /* Alignment */ 00796 type = entry->info.type; 00797 if (typeSizes[type] > 1) { 00798 unsigned diff; 00799 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]); 00800 if (diff != typeSizes[type]) { 00801 memset(te, 0, diff); 00802 te += diff; 00803 pad += diff; 00804 } 00805 } 00806 00807 pe->offset = htonl(te - dataStart); 00808 00809 /* copy data w/ endian conversions */ 00810 switch (entry->info.type) { 00811 case RPM_INT64_TYPE: 00812 { int_32 b[2]; 00813 count = entry->info.count; 00814 src = entry->data; 00815 while (count--) { 00816 b[1] = htonl(((int_32 *)src)[0]); 00817 b[0] = htonl(((int_32 *)src)[1]); 00818 if (b[1] == ((int_32 *)src)[0]) 00819 memcpy(te, src, sizeof(b)); 00820 else 00821 memcpy(te, b, sizeof(b)); 00822 te += sizeof(b); 00823 src += sizeof(b); 00824 } 00825 } /*@switchbreak@*/ break; 00826 00827 case RPM_INT32_TYPE: 00828 count = entry->info.count; 00829 src = entry->data; 00830 while (count--) { 00831 *((int_32 *)te) = htonl(*((int_32 *)src)); 00832 /*@-sizeoftype@*/ 00833 te += sizeof(int_32); 00834 src += sizeof(int_32); 00835 /*@=sizeoftype@*/ 00836 } 00837 /*@switchbreak@*/ break; 00838 00839 case RPM_INT16_TYPE: 00840 count = entry->info.count; 00841 src = entry->data; 00842 while (count--) { 00843 *((int_16 *)te) = htons(*((int_16 *)src)); 00844 /*@-sizeoftype@*/ 00845 te += sizeof(int_16); 00846 src += sizeof(int_16); 00847 /*@=sizeoftype@*/ 00848 } 00849 /*@switchbreak@*/ break; 00850 00851 default: 00852 memcpy(te, entry->data, entry->length); 00853 te += entry->length; 00854 /*@switchbreak@*/ break; 00855 } 00856 pe++; 00857 } 00858 00859 /* Insure that there are no memcpy underruns/overruns. */ 00860 if (((unsigned char *)pe) != dataStart) 00861 goto errxit; 00862 if ((((unsigned char *)ei)+len) != te) 00863 goto errxit; 00864 00865 if (lenp) 00866 *lenp = len; 00867 00868 h->flags &= ~HEADERFLAG_SORTED; 00869 headerSort(h); 00870 00871 if (sw != NULL) (void) rpmswExit(sw, len); 00872 00873 return (void *) ei; 00874 00875 errxit: 00876 if (sw != NULL) (void) rpmswExit(sw, len); 00877 /*@-usereleased@*/ 00878 ei = _free(ei); 00879 /*@=usereleased@*/ 00880 return (void *) ei; 00881 } 00882 00888 static /*@only@*/ /*@null@*/ 00889 void * headerUnload(Header h) 00890 /*@modifies h @*/ 00891 { 00892 size_t length; 00893 void * uh = doHeaderUnload(h, &length); 00894 return uh; 00895 } 00896 00904 static /*@null@*/ 00905 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, rpmTagType type) 00906 /*@modifies h @*/ 00907 { 00908 indexEntry entry, entry2, last; 00909 struct indexEntry_s key; 00910 00911 if (h == NULL) return NULL; 00912 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h); 00913 00914 key.info.tag = tag; 00915 00916 entry2 = entry = 00917 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp); 00918 if (entry == NULL) 00919 return NULL; 00920 00921 if (type == RPM_NULL_TYPE) 00922 return entry; 00923 00924 /* look backwards */ 00925 while (entry->info.tag == tag && entry->info.type != type && 00926 entry > h->index) entry--; 00927 00928 if (entry->info.tag == tag && entry->info.type == type) 00929 return entry; 00930 00931 last = h->index + h->indexUsed; 00932 /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */ 00933 while (entry2->info.tag == tag && entry2->info.type != type && 00934 entry2 < last) entry2++; 00935 /*@=usereleased@*/ 00936 00937 if (entry->info.tag == tag && entry->info.type == type) 00938 return entry; 00939 00940 return NULL; 00941 } 00942 00952 static 00953 int headerRemoveEntry(Header h, int_32 tag) 00954 /*@modifies h @*/ 00955 { 00956 indexEntry last = h->index + h->indexUsed; 00957 indexEntry entry, first; 00958 int ne; 00959 00960 entry = findEntry(h, tag, RPM_NULL_TYPE); 00961 if (!entry) return 1; 00962 00963 /* Make sure entry points to the first occurence of this tag. */ 00964 while (entry > h->index && (entry - 1)->info.tag == tag) 00965 entry--; 00966 00967 /* Free data for tags being removed. */ 00968 for (first = entry; first < last; first++) { 00969 void * data; 00970 if (first->info.tag != tag) 00971 break; 00972 data = first->data; 00973 first->data = NULL; 00974 first->length = 0; 00975 if (ENTRY_IN_REGION(first)) 00976 continue; 00977 data = _free(data); 00978 } 00979 00980 ne = (first - entry); 00981 if (ne > 0) { 00982 h->indexUsed -= ne; 00983 ne = last - first; 00984 if (ne > 0) 00985 memmove(entry, first, (ne * sizeof(*entry))); 00986 } 00987 00988 return 0; 00989 } 00990 00996 static /*@null@*/ 00997 Header headerLoad(/*@kept@*/ void * uh) 00998 /*@modifies uh @*/ 00999 { 01000 void * sw = NULL; 01001 int_32 * ei = (int_32 *) uh; 01002 int_32 il = ntohl(ei[0]); /* index length */ 01003 int_32 dl = ntohl(ei[1]); /* data length */ 01004 /*@-sizeoftype@*/ 01005 size_t pvlen = sizeof(il) + sizeof(dl) + 01006 (il * sizeof(struct entryInfo_s)) + dl; 01007 /*@=sizeoftype@*/ 01008 void * pv = uh; 01009 Header h = NULL; 01010 entryInfo pe; 01011 unsigned char * dataStart; 01012 unsigned char * dataEnd; 01013 indexEntry entry; 01014 int rdlen; 01015 int i; 01016 01017 /* Sanity checks on header intro. */ 01018 if (hdrchkTags(il) || hdrchkData(dl)) 01019 goto errxit; 01020 01021 ei = (int_32 *) pv; 01022 /*@-castexpose@*/ 01023 pe = (entryInfo) &ei[2]; 01024 /*@=castexpose@*/ 01025 dataStart = (unsigned char *) (pe + il); 01026 dataEnd = dataStart + dl; 01027 01028 h = xcalloc(1, sizeof(*h)); 01029 if ((sw = headerGetStats(h, 18)) != NULL) /* RPMTS_OP_HDRLOAD */ 01030 (void) rpmswEnter(sw, 0); 01031 /*@-assignexpose@*/ 01032 h->hv = *hdrVec; /* structure assignment */ 01033 /*@=assignexpose@*/ 01034 /*@-assignexpose -kepttrans@*/ 01035 h->blob = uh; 01036 /*@=assignexpose =kepttrans@*/ 01037 h->indexAlloced = il + 1; 01038 h->indexUsed = il; 01039 h->index = xcalloc(h->indexAlloced, sizeof(*h->index)); 01040 h->flags |= HEADERFLAG_SORTED; 01041 h->nrefs = 0; 01042 h = headerLink(h); 01043 01044 entry = h->index; 01045 i = 0; 01046 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) { 01047 h->flags |= HEADERFLAG_LEGACY; 01048 entry->info.type = REGION_TAG_TYPE; 01049 entry->info.tag = HEADER_IMAGE; 01050 /*@-sizeoftype@*/ 01051 entry->info.count = REGION_TAG_COUNT; 01052 /*@=sizeoftype@*/ 01053 entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */ 01054 01055 /*@-assignexpose@*/ 01056 entry->data = pe; 01057 /*@=assignexpose@*/ 01058 entry->length = pvlen - sizeof(il) - sizeof(dl); 01059 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset); 01060 #if 0 /* XXX don't check, the 8/98 i18n bug fails here. */ 01061 if (rdlen != dl) 01062 goto errxit; 01063 #endif 01064 entry->rdlen = rdlen; 01065 entry++; 01066 h->indexUsed++; 01067 } else { 01068 int_32 rdl; 01069 int_32 ril; 01070 01071 h->flags &= ~HEADERFLAG_LEGACY; 01072 01073 entry->info.type = htonl(pe->type); 01074 entry->info.count = htonl(pe->count); 01075 01076 if (hdrchkType(entry->info.type)) 01077 goto errxit; 01078 if (hdrchkTags(entry->info.count)) 01079 goto errxit; 01080 01081 { int off = ntohl(pe->offset); 01082 01083 if (hdrchkData(off)) 01084 goto errxit; 01085 if (off) { 01086 /*@-sizeoftype@*/ 01087 size_t nb = REGION_TAG_COUNT; 01088 /*@=sizeoftype@*/ 01089 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb); 01090 rdl = -ntohl(stei[2]); /* negative offset */ 01091 ril = rdl/sizeof(*pe); 01092 if (hdrchkTags(ril) || hdrchkData(rdl)) 01093 goto errxit; 01094 entry->info.tag = htonl(pe->tag); 01095 } else { 01096 ril = il; 01097 /*@-sizeoftype@*/ 01098 rdl = (ril * sizeof(struct entryInfo_s)); 01099 /*@=sizeoftype@*/ 01100 entry->info.tag = HEADER_IMAGE; 01101 } 01102 } 01103 entry->info.offset = -rdl; /* negative offset */ 01104 01105 /*@-assignexpose@*/ 01106 entry->data = pe; 01107 /*@=assignexpose@*/ 01108 entry->length = pvlen - sizeof(il) - sizeof(dl); 01109 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset); 01110 if (rdlen < 0) 01111 goto errxit; 01112 entry->rdlen = rdlen; 01113 01114 if (ril < h->indexUsed) { 01115 indexEntry newEntry = entry + ril; 01116 int ne = (h->indexUsed - ril); 01117 int rid = entry->info.offset+1; 01118 int rc; 01119 01120 /* Load dribble entries from region. */ 01121 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid); 01122 if (rc < 0) 01123 goto errxit; 01124 rdlen += rc; 01125 01126 { indexEntry firstEntry = newEntry; 01127 int save = h->indexUsed; 01128 int j; 01129 01130 /* Dribble entries replace duplicate region entries. */ 01131 h->indexUsed -= ne; 01132 for (j = 0; j < ne; j++, newEntry++) { 01133 (void) headerRemoveEntry(h, newEntry->info.tag); 01134 if (newEntry->info.tag == HEADER_BASENAMES) 01135 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES); 01136 } 01137 01138 /* If any duplicate entries were replaced, move new entries down. */ 01139 if (h->indexUsed < (save - ne)) { 01140 memmove(h->index + h->indexUsed, firstEntry, 01141 (ne * sizeof(*entry))); 01142 } 01143 h->indexUsed += ne; 01144 } 01145 } 01146 } 01147 01148 h->flags &= ~HEADERFLAG_SORTED; 01149 headerSort(h); 01150 01151 if (sw != NULL) (void) rpmswExit(sw, pvlen); 01152 01153 /*@-globstate -observertrans @*/ 01154 return h; 01155 /*@=globstate =observertrans @*/ 01156 01157 errxit: 01158 if (sw != NULL) (void) rpmswExit(sw, pvlen); 01159 /*@-usereleased@*/ 01160 if (h) { 01161 h->index = _free(h->index); 01162 /*@-refcounttrans@*/ 01163 h = _free(h); 01164 /*@=refcounttrans@*/ 01165 } 01166 /*@=usereleased@*/ 01167 /*@-refcounttrans -globstate@*/ 01168 return h; 01169 /*@=refcounttrans =globstate@*/ 01170 } 01171 01177 static /*@observer@*/ /*@null@*/ 01178 const char * headerGetOrigin(/*@null@*/ Header h) 01179 /*@*/ 01180 { 01181 return (h != NULL ? h->origin : NULL); 01182 } 01183 01190 static 01191 int headerSetOrigin(/*@null@*/ Header h, const char * origin) 01192 /*@modifies h @*/ 01193 { 01194 if (h != NULL) { 01195 h->origin = _free(h->origin); 01196 h->origin = xstrdup(origin); 01197 } 01198 return 0; 01199 } 01200 01201 const char * headerGetBaseURL(Header h); /* XXX keep GCC quiet */ 01202 const char * headerGetBaseURL(Header h) 01203 { 01204 return (h != NULL ? h->baseurl : NULL); 01205 } 01206 01207 int headerSetBaseURL(Header h, const char * baseurl); /* XXX keep GCC quiet */ 01208 int headerSetBaseURL(Header h, const char * baseurl) 01209 { 01210 if (h != NULL) { 01211 h->baseurl = _free(h->baseurl); 01212 h->baseurl = xstrdup(baseurl); 01213 } 01214 return 0; 01215 } 01216 01217 struct stat * headerGetStatbuf(Header h); /* XXX keep GCC quiet */ 01218 struct stat * headerGetStatbuf(Header h) 01219 { 01220 return &h->sb; 01221 } 01222 01223 int headerSetStatbuf(Header h, struct stat * st); /* XXX keep GCC quiet */ 01224 int headerSetStatbuf(Header h, struct stat * st) 01225 { 01226 if (h != NULL && st != NULL) 01227 memcpy(&h->sb, st, sizeof(h->sb)); 01228 return 0; 01229 } 01230 01231 const char * headerGetDigest(Header h); /* XXX keep GCC quiet. */ 01232 const char * headerGetDigest(Header h) 01233 { 01234 return (h != NULL ? h->digest : NULL); 01235 } 01236 01237 int headerSetDigest(Header h, const char * digest); /* XXX keep GCC quiet */ 01238 int headerSetDigest(Header h, const char * digest) 01239 { 01240 if (h != NULL) { 01241 h->digest = _free(h->digest); 01242 h->digest = xstrdup(digest); 01243 } 01244 return 0; 01245 } 01246 01247 static 01248 uint32_t headerGetInstance(/*@null@*/ Header h) 01249 /*@*/ 01250 { 01251 return (h != NULL ? h->instance : 0); 01252 } 01253 01254 static 01255 uint32_t headerSetInstance(/*@null@*/ Header h, uint32_t instance) 01256 /*@modifies h @*/ 01257 { 01258 if (h != NULL) 01259 h->instance = instance; 01260 return 0; 01261 } 01262 01263 uint32_t headerGetStartOff(Header h); /* XXX keep GCC quiet */ 01264 uint32_t headerGetStartOff(Header h) 01265 { 01266 return (h != NULL ? h->startoff : 0); 01267 } 01268 01269 uint32_t headerSetStartOff(Header h, uint32_t startoff); /* XXX keep GCC quiet */ 01270 uint32_t headerSetStartOff(Header h, uint32_t startoff) 01271 { 01272 if (h != NULL) 01273 h->startoff = startoff; 01274 return 0; 01275 } 01276 01277 uint32_t headerGetEndOff(Header h); /* XXX keep GCC quiet */ 01278 uint32_t headerGetEndOff(Header h) 01279 { 01280 return (h != NULL ? h->endoff : 0); 01281 } 01282 01283 uint32_t headerSetEndOff(Header h, uint32_t endoff); /* XXX keep GCC quiet. */ 01284 uint32_t headerSetEndOff(Header h, uint32_t endoff) 01285 { 01286 if (h != NULL) 01287 h->endoff = endoff; 01288 return 0; 01289 } 01290 01298 static /*@null@*/ 01299 Header headerReload(/*@only@*/ Header h, int tag) 01300 /*@modifies h @*/ 01301 { 01302 Header nh; 01303 size_t length; 01304 void * uh; 01305 const char * origin = (h->origin != NULL ? xstrdup(h->origin) : NULL); 01306 const char * baseurl = (h->baseurl != NULL ? xstrdup(h->baseurl) : NULL); 01307 const char * digest = (h->digest != NULL ? xstrdup(h->digest) : NULL); 01308 struct stat sb = h->sb; /* structure assignment */ 01309 int_32 instance = h->instance; 01310 int xx; 01311 01312 /*@-onlytrans@*/ 01313 uh = doHeaderUnload(h, &length); 01314 h = headerFree(h); 01315 /*@=onlytrans@*/ 01316 if (uh == NULL) 01317 return NULL; 01318 nh = headerLoad(uh); 01319 if (nh == NULL) { 01320 uh = _free(uh); 01321 return NULL; 01322 } 01323 if (nh->flags & HEADERFLAG_ALLOCATED) 01324 uh = _free(uh); 01325 nh->flags |= HEADERFLAG_ALLOCATED; 01326 if (ENTRY_IS_REGION(nh->index)) { 01327 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE) 01328 nh->index[0].info.tag = tag; 01329 } 01330 if (origin != NULL) { 01331 xx = headerSetOrigin(nh, origin); 01332 origin = _free(origin); 01333 } 01334 if (baseurl != NULL) { 01335 xx = headerSetBaseURL(nh, baseurl); 01336 baseurl = _free(baseurl); 01337 } 01338 if (digest != NULL) { 01339 xx = headerSetDigest(nh, digest); 01340 digest = _free(digest); 01341 } 01342 nh->sb = sb; /* structure assignment */ 01343 xx = headerSetInstance(nh, instance); 01344 return nh; 01345 } 01346 01352 static /*@null@*/ 01353 Header headerCopyLoad(const void * uh) 01354 /*@*/ 01355 { 01356 int_32 * ei = (int_32 *) uh; 01357 int_32 il = ntohl(ei[0]); /* index length */ 01358 int_32 dl = ntohl(ei[1]); /* data length */ 01359 /*@-sizeoftype@*/ 01360 size_t pvlen = sizeof(il) + sizeof(dl) + 01361 (il * sizeof(struct entryInfo_s)) + dl; 01362 /*@=sizeoftype@*/ 01363 void * nuh = NULL; 01364 Header h = NULL; 01365 01366 /* Sanity checks on header intro. */ 01367 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) { 01368 nuh = memcpy(xmalloc(pvlen), uh, pvlen); 01369 if ((h = headerLoad(nuh)) != NULL) 01370 h->flags |= HEADERFLAG_ALLOCATED; 01371 } 01372 if (h == NULL) 01373 nuh = _free(nuh); 01374 return h; 01375 } 01376 01383 static /*@null@*/ 01384 Header headerRead(void * _fd, enum hMagic magicp) 01385 /*@modifies _fd @*/ 01386 { 01387 FD_t fd = _fd; 01388 int_32 block[4]; 01389 int_32 reserved; 01390 int_32 * ei = NULL; 01391 int_32 il; 01392 int_32 dl; 01393 int_32 magic; 01394 Header h = NULL; 01395 size_t len; 01396 int i; 01397 01398 memset(block, 0, sizeof(block)); 01399 i = 2; 01400 if (magicp == HEADER_MAGIC_YES) 01401 i += 2; 01402 01403 /*@-type@*/ /* FIX: cast? */ 01404 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block))) 01405 goto exit; 01406 /*@=type@*/ 01407 01408 i = 0; 01409 01410 if (magicp == HEADER_MAGIC_YES) { 01411 magic = block[i++]; 01412 if (memcmp(&magic, header_magic, sizeof(magic))) 01413 goto exit; 01414 reserved = block[i++]; 01415 } 01416 01417 il = ntohl(block[i]); i++; 01418 dl = ntohl(block[i]); i++; 01419 01420 /*@-sizeoftype@*/ 01421 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl; 01422 /*@=sizeoftype@*/ 01423 01424 /* Sanity checks on header intro. */ 01425 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes) 01426 goto exit; 01427 01428 ei = xmalloc(len); 01429 ei[0] = htonl(il); 01430 ei[1] = htonl(dl); 01431 len -= sizeof(il) + sizeof(dl); 01432 01433 /*@-type@*/ /* FIX: cast? */ 01434 if (timedRead(fd, (char *)&ei[2], len) != len) 01435 goto exit; 01436 /*@=type@*/ 01437 01438 h = headerLoad(ei); 01439 01440 { const char * origin = fdGetOPath(fd); 01441 if (origin != NULL) 01442 (void) headerSetOrigin(h, origin); 01443 } 01444 01445 exit: 01446 if (h) { 01447 if (h->flags & HEADERFLAG_ALLOCATED) 01448 ei = _free(ei); 01449 h->flags |= HEADERFLAG_ALLOCATED; 01450 } else if (ei) 01451 ei = _free(ei); 01452 /*@-mustmod@*/ /* FIX: timedRead macro obscures annotation */ 01453 return h; 01454 /*@-mustmod@*/ 01455 } 01456 01464 static 01465 int headerWrite(void * _fd, /*@null@*/ Header h, enum hMagic magicp) 01466 /*@globals fileSystem @*/ 01467 /*@modifies fd, h, fileSystem @*/ 01468 { 01469 FD_t fd = _fd; 01470 ssize_t nb; 01471 size_t length; 01472 const void * uh; 01473 01474 if (h == NULL) 01475 return 1; 01476 uh = doHeaderUnload(h, &length); 01477 if (uh == NULL) 01478 return 1; 01479 switch (magicp) { 01480 case HEADER_MAGIC_YES: 01481 /*@-sizeoftype@*/ 01482 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd); 01483 /*@=sizeoftype@*/ 01484 if (nb != sizeof(header_magic)) 01485 goto exit; 01486 break; 01487 case HEADER_MAGIC_NO: 01488 break; 01489 } 01490 01491 /*@-sizeoftype@*/ 01492 nb = Fwrite(uh, sizeof(char), length, fd); 01493 /*@=sizeoftype@*/ 01494 01495 exit: 01496 uh = _free(uh); 01497 return (nb == length ? 0 : 1); 01498 } 01499 01506 static 01507 int headerIsEntry(/*@null@*/Header h, int_32 tag) 01508 /*@*/ 01509 { 01510 /*@-mods@*/ /*@ FIX: h modified by sort. */ 01511 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0); 01512 /*@=mods@*/ 01513 } 01514 01525 static int copyEntry(const indexEntry entry, 01526 /*@null@*/ /*@out@*/ rpmTagType * type, 01527 /*@null@*/ /*@out@*/ rpmTagData * p, 01528 /*@null@*/ /*@out@*/ rpmTagCount * c, 01529 int minMem) 01530 /*@modifies *type, *p, *c @*/ 01531 /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/ 01532 { 01533 rpmTagCount count = entry->info.count; 01534 int rc = 1; /* XXX 1 on success. */ 01535 01536 if (p) 01537 switch (entry->info.type) { 01538 case RPM_BIN_TYPE: 01539 /* 01540 * XXX This only works for 01541 * XXX "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE. 01542 * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e. 01543 * XXX a legacy header freshly read, but not yet unloaded to the rpmdb). 01544 */ 01545 if (ENTRY_IS_REGION(entry)) { 01546 int_32 * ei = ((int_32 *)entry->data) - 2; 01547 /*@-castexpose@*/ 01548 entryInfo pe = (entryInfo) (ei + 2); 01549 /*@=castexpose@*/ 01550 unsigned char * dataStart = (unsigned char *) (pe + ntohl(ei[0])); 01551 unsigned char * dataEnd; 01552 int_32 rdl = -entry->info.offset; /* negative offset */ 01553 int_32 ril = rdl/sizeof(*pe); 01554 01555 /*@-sizeoftype@*/ 01556 rdl = entry->rdlen; 01557 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl; 01558 if (entry->info.tag == HEADER_IMAGE) { 01559 ril -= 1; 01560 pe += 1; 01561 } else { 01562 count += REGION_TAG_COUNT; 01563 rdl += REGION_TAG_COUNT; 01564 } 01565 01566 (*p).i32p = ei = xmalloc(count); 01567 ei[0] = htonl(ril); 01568 ei[1] = htonl(rdl); 01569 01570 /*@-castexpose@*/ 01571 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe))); 01572 /*@=castexpose@*/ 01573 01574 dataStart = (unsigned char *) memcpy(pe + ril, dataStart, rdl); 01575 dataEnd = dataStart + rdl; 01576 /*@=sizeoftype@*/ 01577 01578 rc = regionSwab(NULL, ril, 0, pe, dataStart, dataEnd, 0); 01579 /* XXX 1 on success. */ 01580 rc = (rc < 0) ? 0 : 1; 01581 } else { 01582 count = entry->length; 01583 (*p).ptr = (!minMem 01584 ? memcpy(xmalloc(count), entry->data, count) 01585 : entry->data); 01586 } 01587 break; 01588 case RPM_STRING_TYPE: 01589 if (count == 1) { 01590 (*p).str = entry->data; 01591 break; 01592 } 01593 /*@fallthrough@*/ 01594 case RPM_I18NSTRING_TYPE: 01595 case RPM_STRING_ARRAY_TYPE: 01596 { const char ** argv; 01597 size_t nb = count * sizeof(*argv); 01598 char * t; 01599 int i; 01600 01601 /*@-mods@*/ 01602 if (minMem) { 01603 (*p).argv = argv = xmalloc(nb); 01604 t = entry->data; 01605 } else { 01606 (*p).argv = argv = xmalloc(nb + entry->length); 01607 t = (char *) &argv[count]; 01608 memcpy(t, entry->data, entry->length); 01609 } 01610 /*@=mods@*/ 01611 for (i = 0; i < count; i++) { 01612 argv[i] = t; 01613 t = strchr(t, 0); 01614 t++; 01615 } 01616 } break; 01617 01618 case RPM_OPENPGP_TYPE: /* XXX W2DO? */ 01619 case RPM_ASN1_TYPE: /* XXX W2DO? */ 01620 default: 01621 (*p).ptr = entry->data; 01622 break; 01623 } 01624 if (type) *type = entry->info.type; 01625 if (c) *c = count; 01626 return rc; 01627 } 01628 01647 static int headerMatchLocale(const char *td, const char *l, const char *le) 01648 /*@*/ 01649 { 01650 const char *fe; 01651 01652 01653 #if 0 01654 { const char *s, *ll, *CC, *EE, *dd; 01655 char *lbuf, *t. 01656 01657 /* Copy the buffer and parse out components on the fly. */ 01658 lbuf = alloca(le - l + 1); 01659 for (s = l, ll = t = lbuf; *s; s++, t++) { 01660 switch (*s) { 01661 case '_': 01662 *t = '\0'; 01663 CC = t + 1; 01664 break; 01665 case '.': 01666 *t = '\0'; 01667 EE = t + 1; 01668 break; 01669 case '@': 01670 *t = '\0'; 01671 dd = t + 1; 01672 break; 01673 default: 01674 *t = *s; 01675 break; 01676 } 01677 } 01678 01679 if (ll) /* ISO language should be lower case */ 01680 for (t = ll; *t; t++) *t = tolower(*t); 01681 if (CC) /* ISO country code should be upper case */ 01682 for (t = CC; *t; t++) *t = toupper(*t); 01683 01684 /* There are a total of 16 cases to attempt to match. */ 01685 } 01686 #endif 01687 01688 /* First try a complete match. */ 01689 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l))) 01690 return 1; 01691 01692 /* Next, try stripping optional dialect and matching. */ 01693 for (fe = l; fe < le && *fe != '@'; fe++) 01694 {}; 01695 if (fe < le && !strncmp(td, l, (fe - l))) 01696 return 1; 01697 01698 /* Next, try stripping optional codeset and matching. */ 01699 for (fe = l; fe < le && *fe != '.'; fe++) 01700 {}; 01701 if (fe < le && !strncmp(td, l, (fe - l))) 01702 return 1; 01703 01704 /* Finally, try stripping optional country code and matching. */ 01705 for (fe = l; fe < le && *fe != '_'; fe++) 01706 {}; 01707 if (fe < le && !strncmp(td, l, (fe - l))) 01708 return 1; 01709 01710 return 0; 01711 } 01712 01719 /*@dependent@*/ /*@exposed@*/ static char * 01720 headerFindI18NString(Header h, indexEntry entry) 01721 /*@*/ 01722 { 01723 const char *lang, *l, *le; 01724 indexEntry table; 01725 01726 /* XXX Drepper sez' this is the order. */ 01727 if ((lang = getenv("LANGUAGE")) == NULL && 01728 (lang = getenv("LC_ALL")) == NULL && 01729 (lang = getenv("LC_MESSAGES")) == NULL && 01730 (lang = getenv("LANG")) == NULL) 01731 return entry->data; 01732 01733 /*@-mods@*/ 01734 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL) 01735 return entry->data; 01736 /*@=mods@*/ 01737 01738 for (l = lang; *l != '\0'; l = le) { 01739 const char *td; 01740 char *ed; 01741 int langNum; 01742 01743 while (*l && *l == ':') /* skip leading colons */ 01744 l++; 01745 if (*l == '\0') 01746 break; 01747 for (le = l; *le && *le != ':'; le++) /* find end of this locale */ 01748 {}; 01749 01750 /* For each entry in the header ... */ 01751 for (langNum = 0, td = table->data, ed = entry->data; 01752 langNum < entry->info.count; 01753 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) { 01754 01755 if (headerMatchLocale(td, l, le)) 01756 return ed; 01757 01758 } 01759 } 01760 01761 /* when everything fail, try gettext */ 01762 return ((entry->data != NULL) && *(char*)(entry->data)) ? _(entry->data) : entry->data; 01763 } 01764 01775 static int intGetEntry(Header h, int_32 tag, 01776 /*@null@*/ /*@out@*/ rpmTagType * type, 01777 /*@null@*/ /*@out@*/ rpmTagData * p, 01778 /*@null@*/ /*@out@*/ rpmTagCount * c, 01779 int minMem) 01780 /*@modifies *type, *p, *c @*/ 01781 /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/ 01782 { 01783 indexEntry entry; 01784 int rc; 01785 01786 /* First find the tag */ 01787 /*@-mods@*/ /*@ FIX: h modified by sort. */ 01788 entry = findEntry(h, tag, RPM_NULL_TYPE); 01789 /*@=mods@*/ 01790 if (entry == NULL) { 01791 if (type) type = 0; 01792 if (p) (*p).ptr = NULL; 01793 if (c) *c = 0; 01794 return 0; 01795 } 01796 01797 switch (entry->info.type) { 01798 case RPM_I18NSTRING_TYPE: 01799 rc = 1; 01800 if (type) *type = RPM_STRING_TYPE; 01801 if (c) *c = 1; 01802 /*@-dependenttrans@*/ 01803 if (p) (*p).str = headerFindI18NString(h, entry); 01804 /*@=dependenttrans@*/ 01805 break; 01806 default: 01807 rc = copyEntry(entry, type, p, c, minMem); 01808 break; 01809 } 01810 01811 /* XXX 1 on success */ 01812 return ((rc == 1) ? 1 : 0); 01813 } 01814 01822 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h, 01823 /*@only@*/ /*@null@*/ const void * data, rpmTagType type) 01824 /*@modifies data @*/ 01825 { 01826 if (data) { 01827 if (type == -1 || 01828 type == RPM_STRING_ARRAY_TYPE || 01829 type == RPM_I18NSTRING_TYPE || 01830 type == RPM_BIN_TYPE || 01831 type == RPM_ASN1_TYPE || 01832 type == RPM_OPENPGP_TYPE) 01833 data = _free(data); 01834 } 01835 return NULL; 01836 } 01837 01851 static 01852 int headerGetEntry(Header h, int_32 tag, 01853 /*@null@*/ /*@out@*/ hTYP_t type, 01854 /*@null@*/ /*@out@*/ void * p, 01855 /*@null@*/ /*@out@*/ hCNT_t c) 01856 /*@modifies *type, *p, *c @*/ 01857 /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/ 01858 { 01859 void * sw; 01860 int rc; 01861 01862 if ((sw = headerGetStats(h, 19)) != NULL) /* RPMTS_OP_HDRGET */ 01863 (void) rpmswEnter(sw, 0); 01864 rc = intGetEntry(h, tag, (rpmTagType *)type, (rpmTagData *)p, (rpmTagCount *)c, 0); 01865 if (sw != NULL) (void) rpmswExit(sw, 0); 01866 return rc; 01867 } 01868 01881 static 01882 int headerGetEntryMinMemory(Header h, int_32 tag, 01883 /*@null@*/ /*@out@*/ hTYP_t type, 01884 /*@null@*/ /*@out@*/ void * p, 01885 /*@null@*/ /*@out@*/ hCNT_t c) 01886 /*@modifies *type, *p, *c @*/ 01887 /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/ 01888 { 01889 void * sw; 01890 int rc; 01891 01892 if ((sw = headerGetStats(h, 19)) != NULL) /* RPMTS_OP_HDRGET */ 01893 (void) rpmswEnter(sw, 0); 01894 rc = intGetEntry(h, tag, (rpmTagType *)type, (rpmTagData *)p, (rpmTagCount *)c, 1); 01895 if (sw != NULL) (void) rpmswExit(sw, 0); 01896 return rc; 01897 } 01898 01899 int headerGetRawEntry(Header h, int_32 tag, rpmTagType * type, void * p, rpmTagCount * c) 01900 { 01901 indexEntry entry; 01902 int rc; 01903 01904 if (p == NULL) return headerIsEntry(h, tag); 01905 01906 /* First find the tag */ 01907 /*@-mods@*/ /*@ FIX: h modified by sort. */ 01908 entry = findEntry(h, tag, RPM_NULL_TYPE); 01909 /*@=mods@*/ 01910 if (!entry) { 01911 if (p) *(void **)p = NULL; 01912 if (c) *c = 0; 01913 return 0; 01914 } 01915 01916 rc = copyEntry(entry, type, p, c, 0); 01917 01918 /* XXX 1 on success */ 01919 return ((rc == 1) ? 1 : 0); 01920 } 01921 01924 static void copyData(rpmTagType type, rpmTagData * dest, rpmTagData * src, 01925 rpmTagCount cnt, size_t len) 01926 /*@modifies *dest @*/ 01927 { 01928 switch (type) { 01929 case RPM_I18NSTRING_TYPE: 01930 case RPM_STRING_ARRAY_TYPE: 01931 { const char ** av = (*src).argv; 01932 char * t = (char *) (*dest).str; 01933 01934 while (cnt-- > 0 && len > 0) { 01935 const char * s; 01936 if ((s = *av++) == NULL) 01937 continue; 01938 do { 01939 *t++ = *s++; 01940 } while (s[-1] && --len > 0); 01941 } 01942 } break; 01943 default: 01944 memmove((*dest).ptr, (*src).ptr, len); 01945 break; 01946 } 01947 } 01948 01957 /*@null@*/ 01958 static void * 01959 grabData(rpmTagType type, rpmTagData * p, rpmTagCount c, /*@out@*/ int * lenp) 01960 /*@modifies *lenp @*/ 01961 /*@requires maxSet(lengthPtr) >= 0 @*/ 01962 { 01963 rpmTagData data = { .ptr = NULL }; 01964 int length; 01965 01966 length = dataLength(type, p, c, 0, NULL); 01967 if (length > 0) { 01968 data.ptr = xmalloc(length); 01969 copyData(type, &data, p, c, length); 01970 } 01971 01972 if (lenp) 01973 *lenp = length; 01974 return data.ptr; 01975 } 01976 01991 static 01992 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c) 01993 /*@modifies h @*/ 01994 { 01995 indexEntry entry; 01996 rpmTagData q = { .ptr = (void *) p }; 01997 rpmTagData data; 01998 int length; 01999 02000 /* Count must always be >= 1 for headerAddEntry. */ 02001 if (c <= 0) 02002 return 0; 02003 02004 if (hdrchkType(type)) 02005 return 0; 02006 if (hdrchkData(c)) 02007 return 0; 02008 02009 length = 0; 02010 data.ptr = grabData(type, &q, c, &length); 02011 if (data.ptr == NULL || length <= 0) 02012 return 0; 02013 02014 /* Allocate more index space if necessary */ 02015 if (h->indexUsed == h->indexAlloced) { 02016 h->indexAlloced += INDEX_MALLOC_SIZE; 02017 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index)); 02018 } 02019 02020 /* Fill in the index */ 02021 entry = h->index + h->indexUsed; 02022 entry->info.tag = tag; 02023 entry->info.type = type; 02024 entry->info.count = c; 02025 entry->info.offset = 0; 02026 entry->data = data.ptr; 02027 entry->length = length; 02028 02029 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag) 02030 h->flags &= ~HEADERFLAG_SORTED; 02031 h->indexUsed++; 02032 02033 return 1; 02034 } 02035 02050 static 02051 int headerAppendEntry(Header h, int_32 tag, int_32 type, 02052 const void * p, int_32 c) 02053 /*@modifies h @*/ 02054 { 02055 rpmTagData src = { .ptr = (void *) p }; 02056 rpmTagData dest = { .ptr = NULL }; 02057 indexEntry entry; 02058 int length; 02059 02060 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) { 02061 /* we can't do this */ 02062 return 0; 02063 } 02064 02065 /* Find the tag entry in the header. */ 02066 entry = findEntry(h, tag, type); 02067 if (!entry) 02068 return 0; 02069 02070 length = dataLength(type, &src, c, 0, NULL); 02071 if (length < 0) 02072 return 0; 02073 02074 if (ENTRY_IN_REGION(entry)) { 02075 char * t = xmalloc(entry->length + length); 02076 memcpy(t, entry->data, entry->length); 02077 entry->data = t; 02078 entry->info.offset = 0; 02079 } else 02080 entry->data = xrealloc(entry->data, entry->length + length); 02081 02082 dest.ptr = ((char *) entry->data) + entry->length; 02083 copyData(type, &dest, &src, c, length); 02084 02085 entry->length += length; 02086 02087 entry->info.count += c; 02088 02089 return 1; 02090 } 02091 02101 static 02102 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type, 02103 const void * p, int_32 c) 02104 /*@modifies h @*/ 02105 { 02106 return (findEntry(h, tag, type) 02107 ? headerAppendEntry(h, tag, type, p, c) 02108 : headerAddEntry(h, tag, type, p, c)); 02109 } 02110 02131 static 02132 int headerAddI18NString(Header h, int_32 tag, const char * string, 02133 const char * lang) 02134 /*@modifies h @*/ 02135 { 02136 indexEntry table, entry; 02137 rpmTagData p; 02138 int length; 02139 int ghosts; 02140 int i, langNum; 02141 char * buf; 02142 02143 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE); 02144 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE); 02145 02146 if (!table && entry) 02147 return 0; /* this shouldn't ever happen!! */ 02148 02149 if (!table && !entry) { 02150 const char * argv[2]; 02151 int count = 0; 02152 p.argv = argv; 02153 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) { 02154 /*@-observertrans -readonlytrans@*/ 02155 p.argv[count++] = "C"; 02156 /*@=observertrans =readonlytrans@*/ 02157 } else { 02158 /*@-observertrans -readonlytrans@*/ 02159 p.argv[count++] = "C"; 02160 /*@=observertrans =readonlytrans@*/ 02161 p.argv[count++] = lang; 02162 } 02163 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE, 02164 p.ptr, count)) 02165 return 0; 02166 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE); 02167 } 02168 02169 if (!table) 02170 return 0; 02171 if (!lang) lang = "C"; 02172 02173 { const char * l = table->data; 02174 for (langNum = 0; langNum < table->info.count; langNum++) { 02175 if (!strcmp(l, lang)) break; 02176 l += strlen(l) + 1; 02177 } 02178 } 02179 02180 if (langNum >= table->info.count) { 02181 length = strlen(lang) + 1; 02182 if (ENTRY_IN_REGION(table)) { 02183 char * t = xmalloc(table->length + length); 02184 memcpy(t, table->data, table->length); 02185 table->data = t; 02186 table->info.offset = 0; 02187 } else 02188 table->data = xrealloc(table->data, table->length + length); 02189 memmove(((char *)table->data) + table->length, lang, length); 02190 table->length += length; 02191 table->info.count++; 02192 } 02193 02194 if (!entry) { 02195 p.argv = alloca(sizeof(*p.argv) * (langNum + 1)); 02196 for (i = 0; i < langNum; i++) 02197 p.argv[i] = ""; 02198 p.argv[langNum] = string; 02199 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, p.ptr, langNum + 1); 02200 } else if (langNum >= entry->info.count) { 02201 ghosts = langNum - entry->info.count; 02202 02203 length = strlen(string) + 1 + ghosts; 02204 if (ENTRY_IN_REGION(entry)) { 02205 char * t = xmalloc(entry->length + length); 02206 memcpy(t, entry->data, entry->length); 02207 entry->data = t; 02208 entry->info.offset = 0; 02209 } else 02210 entry->data = xrealloc(entry->data, entry->length + length); 02211 02212 memset(((char *)entry->data) + entry->length, '\0', ghosts); 02213 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1); 02214 02215 entry->length += length; 02216 entry->info.count = langNum + 1; 02217 } else { 02218 char *b, *be, *e, *ee, *t; 02219 size_t bn, sn, en; 02220 02221 /* Set beginning/end pointers to previous data */ 02222 b = be = e = ee = entry->data; 02223 for (i = 0; i < table->info.count; i++) { 02224 if (i == langNum) 02225 be = ee; 02226 ee += strlen(ee) + 1; 02227 if (i == langNum) 02228 e = ee; 02229 } 02230 02231 /* Get storage for new buffer */ 02232 bn = (be-b); 02233 sn = strlen(string) + 1; 02234 en = (ee-e); 02235 length = bn + sn + en; 02236 t = buf = xmalloc(length); 02237 02238 /* Copy values into new storage */ 02239 memcpy(t, b, bn); 02240 t += bn; 02241 /*@-mayaliasunique@*/ 02242 memcpy(t, string, sn); 02243 t += sn; 02244 memcpy(t, e, en); 02245 t += en; 02246 /*@=mayaliasunique@*/ 02247 02248 /* Replace i18N string array */ 02249 entry->length -= strlen(be) + 1; 02250 entry->length += sn; 02251 02252 if (ENTRY_IN_REGION(entry)) { 02253 entry->info.offset = 0; 02254 } else 02255 entry->data = _free(entry->data); 02256 /*@-dependenttrans@*/ 02257 entry->data = buf; 02258 /*@=dependenttrans@*/ 02259 } 02260 02261 return 0; 02262 } 02263 02274 static 02275 int headerModifyEntry(Header h, int_32 tag, int_32 type, 02276 const void * p, int_32 c) 02277 /*@modifies h @*/ 02278 { 02279 indexEntry entry; 02280 rpmTagData q = { .ptr = (void *) p }; 02281 rpmTagData oldData; 02282 rpmTagData newData; 02283 int length; 02284 02285 /* First find the tag */ 02286 entry = findEntry(h, tag, type); 02287 if (!entry) 02288 return 0; 02289 02290 length = 0; 02291 newData.ptr = grabData(type, &q, c, &length); 02292 if (newData.ptr == NULL || length <= 0) 02293 return 0; 02294 02295 /* make sure entry points to the first occurence of this tag */ 02296 while (entry > h->index && (entry - 1)->info.tag == tag) 02297 entry--; 02298 02299 /* free after we've grabbed the new data in case the two are intertwined; 02300 that's a bad idea but at least we won't break */ 02301 oldData.ptr = entry->data; 02302 02303 entry->info.count = c; 02304 entry->info.type = type; 02305 entry->data = newData.ptr; 02306 entry->length = length; 02307 02308 if (ENTRY_IN_REGION(entry)) { 02309 entry->info.offset = 0; 02310 } else 02311 oldData.ptr = _free(oldData.ptr); 02312 02313 return 1; 02314 } 02315 02318 static char escapedChar(const char ch) /*@*/ 02319 { 02320 /*@-modfilesys@*/ 02321 if (_hdr_debug) 02322 fprintf(stderr, "\t\t\\%c\n", ch); 02323 /*@=modfilesys@*/ 02324 switch (ch) { 02325 case 'a': return '\a'; 02326 case 'b': return '\b'; 02327 case 'f': return '\f'; 02328 case 'n': return '\n'; 02329 case 'r': return '\r'; 02330 case 't': return '\t'; 02331 case 'v': return '\v'; 02332 default: return ch; 02333 } 02334 } 02335 02340 static HE_t rpmheMark(/*@null@*/ HE_t he) 02341 /*@modifies he @*/ 02342 { 02343 /* Set he->freeData as appropriate for headerGetEntry() . */ 02344 if (he) 02345 switch (he->t) { 02346 default: 02347 he->freeData = 0; 02348 break; 02349 case RPM_I18NSTRING_TYPE: 02350 case RPM_STRING_ARRAY_TYPE: 02351 case RPM_BIN_TYPE: 02352 he->freeData = 1; 02353 break; 02354 } 02355 return he; 02356 } 02357 02362 static HE_t rpmheClean(/*@null@*/ HE_t he) 02363 /*@modifies he @*/ 02364 { 02365 if (he) { 02366 if (he->freeData && he->p.ptr != NULL) 02367 he->p.ptr = _free(he->p.ptr); 02368 memset(he, 0, sizeof(*he)); 02369 } 02370 return he; 02371 } 02372 02379 static /*@null@*/ sprintfToken 02380 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num) 02381 /*@modifies *format @*/ 02382 { 02383 int i; 02384 02385 if (format == NULL) return NULL; 02386 02387 for (i = 0; i < num; i++) { 02388 switch (format[i].type) { 02389 case PTOK_TAG: 02390 if (_tagcache) 02391 (void) rpmheClean(&format[i].u.tag.he); 02392 format[i].u.tag.av = argvFree(format[i].u.tag.av); 02393 format[i].u.tag.params = argvFree(format[i].u.tag.params); 02394 format[i].u.tag.fmtfuncs = _free(format[i].u.tag.fmtfuncs); 02395 /*@switchbreak@*/ break; 02396 case PTOK_ARRAY: 02397 format[i].u.array.format = 02398 freeFormat(format[i].u.array.format, 02399 format[i].u.array.numTokens); 02400 /*@switchbreak@*/ break; 02401 case PTOK_COND: 02402 format[i].u.cond.ifFormat = 02403 freeFormat(format[i].u.cond.ifFormat, 02404 format[i].u.cond.numIfTokens); 02405 format[i].u.cond.elseFormat = 02406 freeFormat(format[i].u.cond.elseFormat, 02407 format[i].u.cond.numElseTokens); 02408 if (_tagcache) 02409 (void) rpmheClean(&format[i].u.cond.tag.he); 02410 format[i].u.cond.tag.av = argvFree(format[i].u.cond.tag.av); 02411 format[i].u.cond.tag.params = argvFree(format[i].u.cond.tag.params); 02412 format[i].u.cond.tag.fmtfuncs = _free(format[i].u.cond.tag.fmtfuncs); 02413 /*@switchbreak@*/ break; 02414 case PTOK_NONE: 02415 case PTOK_STRING: 02416 default: 02417 /*@switchbreak@*/ break; 02418 } 02419 } 02420 format = _free(format); 02421 return NULL; 02422 } 02423 02427 struct headerIterator_s { 02428 /*@unused@*/ 02429 Header h; 02430 /*@unused@*/ 02431 int next_index; 02432 }; 02433 02439 static /*@null@*/ 02440 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi) 02441 /*@modifies hi @*/ 02442 { 02443 if (hi != NULL) { 02444 hi->h = headerFree(hi->h); 02445 hi = _free(hi); 02446 } 02447 return hi; 02448 } 02449 02455 static 02456 HeaderIterator headerInitIterator(Header h) 02457 /*@modifies h */ 02458 { 02459 HeaderIterator hi = xmalloc(sizeof(*hi)); 02460 02461 headerSort(h); 02462 02463 hi->h = headerLink(h); 02464 hi->next_index = 0; 02465 return hi; 02466 } 02467 02477 static 02478 int headerNextIterator(HeaderIterator hi, 02479 /*@null@*/ /*@out@*/ hTAG_t tag, 02480 /*@null@*/ /*@out@*/ hTYP_t type, 02481 /*@null@*/ /*@out@*/ hPTR_t * p, 02482 /*@null@*/ /*@out@*/ hCNT_t c) 02483 /*@modifies hi, *tag, *type, *p, *c @*/ 02484 /*@requires maxSet(tag) >= 0 /\ maxSet(type) >= 0 02485 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/ 02486 { 02487 void * sw; 02488 Header h = hi->h; 02489 int slot = hi->next_index; 02490 indexEntry entry = NULL; 02491 int rc; 02492 02493 for (slot = hi->next_index; slot < h->indexUsed; slot++) { 02494 entry = h->index + slot; 02495 if (!ENTRY_IS_REGION(entry)) 02496 break; 02497 } 02498 hi->next_index = slot; 02499 if (entry == NULL || slot >= h->indexUsed) 02500 return 0; 02501 02502 /*@-noeffect@*/ /* LCL: no clue */ 02503 hi->next_index++; 02504 /*@=noeffect@*/ 02505 02506 if ((sw = headerGetStats(h, 19)) != NULL) /* RPMTS_OP_HDRGET */ 02507 (void) rpmswEnter(sw, 0); 02508 02509 if (tag) 02510 *tag = entry->info.tag; 02511 02512 rc = copyEntry(entry, (rpmTagType *)type, (rpmTagData *)p, (rpmTagCount *)c, 0); 02513 02514 if (sw != NULL) (void) rpmswExit(sw, 0); 02515 02516 /* XXX 1 on success */ 02517 return ((rc == 1) ? 1 : 0); 02518 } 02519 02525 static /*@null@*/ 02526 Header headerCopy(Header h) 02527 /*@modifies h @*/ 02528 { 02529 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02530 Header nh = headerNew(); 02531 HeaderIterator hi; 02532 02533 for (hi = headerInitIterator(h); 02534 headerNextIterator(hi, &he->tag, (hTYP_t)&he->t, (hPTR_t *)&he->p, &he->c); 02535 he->p.ptr = headerFreeData(he->p.ptr, he->t)) 02536 { 02537 if (he->p.ptr) (void) headerAddEntry(nh, he->tag, he->t, he->p.ptr, he->c); 02538 } 02539 hi = headerFreeIterator(hi); 02540 02541 return headerReload(nh, HEADER_IMAGE); 02542 } 02543 02546 typedef struct headerSprintfArgs_s { 02547 Header h; 02548 char * fmt; 02549 /*@temp@*/ 02550 headerTagTableEntry tags; 02551 /*@temp@*/ 02552 headerSprintfExtension exts; 02553 /*@observer@*/ /*@null@*/ 02554 const char * errmsg; 02555 HE_t ec; 02556 int nec; 02557 sprintfToken format; 02558 /*@relnull@*/ 02559 HeaderIterator hi; 02560 /*@owned@*/ 02561 char * val; 02562 size_t vallen; 02563 size_t alloced; 02564 int numTokens; 02565 int i; 02566 } * headerSprintfArgs; 02567 02573 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa) 02574 /*@modifies hsa */ 02575 { 02576 sprintfTag tag = 02577 (hsa->format->type == PTOK_TAG 02578 ? &hsa->format->u.tag : 02579 (hsa->format->type == PTOK_ARRAY 02580 ? &hsa->format->u.array.format->u.tag : 02581 NULL)); 02582 02583 if (hsa != NULL) { 02584 hsa->i = 0; 02585 if (tag != NULL && tag->tagno == -2) 02586 hsa->hi = headerInitIterator(hsa->h); 02587 } 02588 /*@-nullret@*/ 02589 return hsa; 02590 /*@=nullret@*/ 02591 } 02592 02598 /*@null@*/ 02599 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa) 02600 /*@modifies hsa */ 02601 { 02602 sprintfToken fmt = NULL; 02603 sprintfTag tag = 02604 (hsa->format->type == PTOK_TAG 02605 ? &hsa->format->u.tag : 02606 (hsa->format->type == PTOK_ARRAY 02607 ? &hsa->format->u.array.format->u.tag : 02608 NULL)); 02609 02610 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) { 02611 fmt = hsa->format + hsa->i; 02612 if (hsa->hi == NULL) { 02613 hsa->i++; 02614 } else { 02615 HE_t he = rpmheClean(&tag->he); 02616 if (!headerNextIterator(hsa->hi, &he->tag, (hTAG_t)&he->t, (hPTR_t *)&he->p.ptr, &he->c)) 02617 { 02618 tag->tagno = 0; 02619 return NULL; 02620 } 02621 he = rpmheMark(he); 02622 he->avail = 1; 02623 tag->tagno = he->tag; 02624 } 02625 } 02626 02627 /*@-dependenttrans -onlytrans@*/ 02628 return fmt; 02629 /*@=dependenttrans =onlytrans@*/ 02630 } 02631 02637 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa) 02638 /*@modifies hsa */ 02639 { 02640 if (hsa != NULL) { 02641 hsa->hi = headerFreeIterator(hsa->hi); 02642 hsa->i = 0; 02643 } 02644 /*@-nullret@*/ 02645 return hsa; 02646 /*@=nullret@*/ 02647 } 02648 02655 /*@dependent@*/ /*@exposed@*/ 02656 static char * hsaReserve(headerSprintfArgs hsa, size_t need) 02657 /*@modifies hsa */ 02658 { 02659 if ((hsa->vallen + need) >= hsa->alloced) { 02660 if (hsa->alloced <= need) 02661 hsa->alloced += need; 02662 hsa->alloced <<= 1; 02663 hsa->val = xrealloc(hsa->val, hsa->alloced+1); 02664 } 02665 return hsa->val + hsa->vallen; 02666 } 02667 02676 /*@observer@*/ /*@null@*/ 02677 static const char * myTagName(headerTagTableEntry tbl, int val, 02678 /*@null@*/ int *typep) 02679 /*@modifies *typep @*/ 02680 { 02681 static char name[128]; 02682 const char * s; 02683 char *t; 02684 02685 for (; tbl->name != NULL; tbl++) { 02686 if (tbl->val == val) 02687 break; 02688 } 02689 if ((s = tbl->name) == NULL) 02690 return NULL; 02691 s += sizeof("RPMTAG_") - 1; 02692 t = name; 02693 *t++ = *s++; 02694 while (*s != '\0') 02695 *t++ = xtolower(*s++); 02696 *t = '\0'; 02697 if (typep) 02698 *typep = tbl->type; 02699 return name; 02700 } 02701 02702 /*@observer@*/ /*@null@*/ 02703 static int myTagType(headerTagTableEntry tbl, int val) 02704 { 02705 for (; tbl->name != NULL; tbl++) { 02706 if (tbl->val == val) 02707 break; 02708 } 02709 return (tbl->name != NULL ? tbl->type : 0); 02710 } 02711 02719 static int myTagValue(headerTagTableEntry tbl, const char * name) 02720 /*@*/ 02721 { 02722 for (; tbl->name != NULL; tbl++) { 02723 if (!xstrcasecmp(tbl->name, name)) 02724 return tbl->val; 02725 } 02726 return 0; 02727 } 02728 02736 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name) 02737 /*@modifies token @*/ 02738 { 02739 headerSprintfExtension exts = hsa->exts; 02740 headerSprintfExtension ext; 02741 sprintfTag stag = (token->type == PTOK_COND 02742 ? &token->u.cond.tag : &token->u.tag); 02743 int extNum; 02744 02745 stag->fmtfuncs = NULL; 02746 stag->ext = NULL; 02747 stag->extNum = 0; 02748 stag->tagno = -1; 02749 02750 if (!strcmp(name, "*")) { 02751 stag->tagno = -2; 02752 goto bingo; 02753 } 02754 02755 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) { 02756 char * t = alloca(strlen(name) + sizeof("RPMTAG_")); 02757 (void) stpcpy( stpcpy(t, "RPMTAG_"), name); 02758 name = t; 02759 } 02760 02761 /* Search extensions for specific tag override. */ 02762 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 02763 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1), extNum++) 02764 { 02765 if (ext->name == NULL || ext->type != HEADER_EXT_TAG) 02766 continue; 02767 if (!xstrcasecmp(ext->name, name)) { 02768 stag->ext = ext->u.tagFunction; 02769 stag->extNum = extNum; 02770 goto bingo; 02771 } 02772 } 02773 02774 /* Search tag names. */ 02775 stag->tagno = myTagValue(hsa->tags, name); 02776 if (stag->tagno != 0) 02777 goto bingo; 02778 02779 return 1; 02780 02781 bingo: 02782 /* Search extensions for specific format. */ 02783 if (stag->av != NULL) { 02784 int i; 02785 stag->fmtfuncs = xcalloc(argvCount(stag->av) + 1, sizeof(*stag->fmtfuncs)); 02786 for (i = 0; stag->av[i] != NULL; i++) { 02787 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST; 02788 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1)) 02789 { 02790 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT) 02791 continue; 02792 if (strcmp(ext->name, stag->av[i]+1)) 02793 continue; 02794 stag->fmtfuncs[i] = ext->u.fmtFunction; 02795 break; 02796 } 02797 } 02798 } 02799 return 0; 02800 } 02801 02809 char * intFormat(HE_t he, /*@null@*/ const char ** av, const char * fmt) 02810 { 02811 int ix = (he->ix > 0 ? he->ix : 0); 02812 int_64 ival = 0; 02813 const char * istr = NULL; 02814 char * b; 02815 size_t nb = 0; 02816 02817 if (fmt == NULL || *fmt == '\0') 02818 fmt = "d"; 02819 02820 switch (he->t) { 02821 default: 02822 return xstrdup(_("(not a number)")); 02823 break; 02824 case RPM_CHAR_TYPE: 02825 case RPM_INT8_TYPE: 02826 ival = he->p.i8p[ix]; 02827 break; 02828 case RPM_INT16_TYPE: 02829 ival = he->p.ui16p[ix]; /* XXX note unsigned. */ 02830 break; 02831 case RPM_INT32_TYPE: 02832 ival = he->p.i32p[ix]; 02833 break; 02834 case RPM_INT64_TYPE: 02835 ival = he->p.i64p[ix]; 02836 break; 02837 case RPM_STRING_TYPE: 02838 istr = he->p.str; 02839 break; 02840 case RPM_STRING_ARRAY_TYPE: 02841 istr = he->p.argv[ix]; 02842 break; 02843 case RPM_OPENPGP_TYPE: /* XXX W2DO? */ 02844 case RPM_ASN1_TYPE: /* XXX W2DO? */ 02845 case RPM_BIN_TYPE: 02846 { static char hex[] = "0123456789abcdef"; 02847 const char * s = he->p.str; 02848 int c = he->c; 02849 char * t; 02850 02851 nb = 2 * c + 1; 02852 t = b = alloca(nb+1); 02853 while (c-- > 0) { 02854 unsigned int i; 02855 i = *s++; 02856 *t++ = hex[ (i >> 4) & 0xf ]; 02857 *t++ = hex[ (i ) & 0xf ]; 02858 } 02859 *t = '\0'; 02860 } break; 02861 } 02862 02863 if (istr) { /* string */ 02864 b = (char *)istr; /* NOCAST */ 02865 } else 02866 if (nb == 0) { /* number */ 02867 char myfmt[] = "%llX"; 02868 myfmt[3] = *fmt; 02869 nb = 64; 02870 b = alloca(nb); 02871 snprintf(b, nb, myfmt, ival); 02872 b[nb-1] = '\0'; 02873 } 02874 02875 return xstrdup(b); 02876 } 02877 02884 static char * octFormat(HE_t he, /*@null@*/ const char ** av) 02885 /*@*/ 02886 { 02887 return intFormat(he, NULL, "o"); 02888 } 02889 02896 static char * hexFormat(HE_t he, /*@null@*/ const char ** av) 02897 /*@*/ 02898 { 02899 return intFormat(he, NULL, "x"); 02900 } 02901 02908 static char * decFormat(HE_t he, /*@null@*/ const char ** av) 02909 /*@*/ 02910 { 02911 return intFormat(he, NULL, "d"); 02912 } 02913 02921 static char * realDateFormat(HE_t he, /*@null@*/ const char ** av, const char * strftimeFormat) 02922 /*@*/ 02923 { 02924 rpmTagData data = { .ptr = he->p.ptr }; 02925 char * val; 02926 02927 if (he->t != RPM_INT64_TYPE) { 02928 val = xstrdup(_("(not a number)")); 02929 } else { 02930 struct tm * tstruct; 02931 char buf[50]; 02932 02933 /* this is important if sizeof(int_64) ! sizeof(time_t) */ 02934 { time_t dateint = data.ui64p[0]; 02935 tstruct = localtime(&dateint); 02936 } 02937 buf[0] = '\0'; 02938 if (tstruct) 02939 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct); 02940 buf[sizeof(buf) - 1] = '\0'; 02941 val = xstrdup(buf); 02942 } 02943 02944 return val; 02945 } 02946 02953 static char * dateFormat(HE_t he, /*@null@*/ const char ** av) 02954 /*@*/ 02955 { 02956 return realDateFormat(he, NULL, _("%c")); 02957 } 02958 02965 static char * dayFormat(HE_t he, /*@null@*/ const char ** av) 02966 /*@*/ 02967 { 02968 return realDateFormat(he, NULL, _("%a %b %d %Y")); 02969 } 02970 02977 static char * shescapeFormat(HE_t he, /*@null@*/ const char ** av) 02978 /*@*/ 02979 { 02980 char * val; 02981 size_t nb; 02982 02983 /* XXX one of these integer types is unnecessary. */ 02984 if (he->t == RPM_INT32_TYPE) { 02985 nb = 20; 02986 val = xmalloc(nb); 02987 snprintf(val, nb, "%d", he->p.i32p[0]); 02988 val[nb-1] = '\0'; 02989 } else if (he->t == RPM_INT64_TYPE) { 02990 nb = 40; 02991 val = xmalloc(40); 02992 snprintf(val, nb, "%lld", he->p.i64p[0]); 02993 val[nb-1] = '\0'; 02994 } else if (he->t == RPM_STRING_TYPE) { 02995 const char * s = he->p.str; 02996 char * t; 02997 int c; 02998 02999 nb = 0; 03000 for (s = he->p.str; (c = (int)*s) != 0; s++) { 03001 nb++; 03002 if (c == (int)'\'') 03003 nb += 3; 03004 } 03005 nb += 3; 03006 t = val = xmalloc(nb); 03007 *t++ = '\''; 03008 for (s = he->p.str; (c = (int)*s) != 0; s++) { 03009 if (c == (int)'\'') { 03010 *t++ = '\''; 03011 *t++ = '\\'; 03012 *t++ = '\''; 03013 } 03014 *t++ = (char) c; 03015 } 03016 *t++ = '\''; 03017 *t = '\0'; 03018 } else 03019 val = xstrdup(_("invalid type")); 03020 03021 return val; 03022 } 03023 03024 /*@-type@*/ /* FIX: cast? */ 03025 const struct headerSprintfExtension_s headerDefaultFormats[] = { 03026 { HEADER_EXT_FORMAT, "octal", 03027 { .fmtFunction = octFormat } }, 03028 { HEADER_EXT_FORMAT, "oct", 03029 { .fmtFunction = octFormat } }, 03030 { HEADER_EXT_FORMAT, "hex", 03031 { .fmtFunction = hexFormat } }, 03032 { HEADER_EXT_FORMAT, "decimal", 03033 { .fmtFunction = decFormat } }, 03034 { HEADER_EXT_FORMAT, "dec", 03035 { .fmtFunction = decFormat } }, 03036 { HEADER_EXT_FORMAT, "date", 03037 { .fmtFunction = dateFormat } }, 03038 { HEADER_EXT_FORMAT, "day", 03039 { .fmtFunction = dayFormat } }, 03040 { HEADER_EXT_FORMAT, "shescape", 03041 { .fmtFunction = shescapeFormat } }, 03042 { HEADER_EXT_LAST, NULL, { NULL } } 03043 }; 03044 /*@=type@*/ 03045 03046 /* forward ref */ 03055 static int parseExpression(headerSprintfArgs hsa, sprintfToken token, 03056 char * str, /*@out@*/char ** endPtr) 03057 /*@modifies hsa, str, token, *endPtr @*/ 03058 /*@requires maxSet(endPtr) >= 0 @*/; 03059 03070 static int parseFormat(headerSprintfArgs hsa, /*@null@*/ char * str, 03071 /*@out@*/ sprintfToken * formatPtr, 03072 /*@out@*/ int * numTokensPtr, 03073 /*@null@*/ /*@out@*/ char ** endPtr, int state) 03074 /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/ 03075 /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0 03076 /\ maxSet(endPtr) >= 0 @*/ 03077 { 03078 /*@observer@*/ 03079 static const char *pstates[] = { 03080 "NORMAL", "ARRAY", "EXPR", "WTF?" 03081 }; 03082 char * chptr, * start, * next, * dst; 03083 sprintfToken format; 03084 sprintfToken token; 03085 unsigned numTokens; 03086 unsigned i; 03087 int done = 0; 03088 int xx; 03089 03090 /*@-modfilesys@*/ 03091 if (_hdr_debug) 03092 fprintf(stderr, "--> parseFormat(%p, \"%.20s...\", %p, %p, %p, %s)\n", hsa, str, formatPtr, numTokensPtr, endPtr, pstates[(state & 0x3)]); 03093 /*@=modfilesys@*/ 03094 03095 /* upper limit on number of individual formats */ 03096 numTokens = 0; 03097 if (str != NULL) 03098 for (chptr = str; *chptr != '\0'; chptr++) 03099 if (*chptr == '%') numTokens++; 03100 numTokens = numTokens * 2 + 1; 03101 03102 format = xcalloc(numTokens, sizeof(*format)); 03103 if (endPtr) *endPtr = NULL; 03104 03105 /*@-infloops@*/ /* LCL: can't detect done termination */ 03106 dst = start = str; 03107 numTokens = 0; 03108 token = NULL; 03109 if (start != NULL) 03110 while (*start != '\0') { 03111 switch (*start) { 03112 case '%': 03113 /* handle %% */ 03114 if (*(start + 1) == '%') { 03115 if (token == NULL || token->type != PTOK_STRING) { 03116 token = format + numTokens++; 03117 token->type = PTOK_STRING; 03118 /*@-temptrans -assignexpose@*/ 03119 dst = token->u.string.string = start; 03120 /*@=temptrans =assignexpose@*/ 03121 } 03122 start++; 03123 *dst++ = *start++; 03124 /*@switchbreak@*/ break; 03125 } 03126 03127 token = format + numTokens++; 03128 *dst++ = '\0'; 03129 start++; 03130 03131 if (*start == '|') { 03132 char * newEnd; 03133 03134 start++; 03135 if (parseExpression(hsa, token, start, &newEnd)) 03136 { 03137 format = freeFormat(format, numTokens); 03138 return 1; 03139 } 03140 start = newEnd; 03141 /*@switchbreak@*/ break; 03142 } 03143 03144 /*@-assignexpose@*/ 03145 token->u.tag.format = start; 03146 /*@=assignexpose@*/ 03147 token->u.tag.pad = 0; 03148 token->u.tag.justOne = 0; 03149 token->u.tag.arrayCount = 0; 03150 03151 chptr = start; 03152 while (*chptr && *chptr != '{' && *chptr != '%') chptr++; 03153 if (!*chptr || *chptr == '%') { 03154 hsa->errmsg = _("missing { after %"); 03155 format = freeFormat(format, numTokens); 03156 return 1; 03157 } 03158 03159 /*@-modfilesys@*/ 03160 if (_hdr_debug) 03161 fprintf(stderr, "\tchptr *%p = NUL\n", chptr); 03162 /*@=modfilesys@*/ 03163 *chptr++ = '\0'; 03164 03165 while (start < chptr) { 03166 if (xisdigit((int)*start)) { 03167 i = strtoul(start, &start, 10); 03168 token->u.tag.pad += i; 03169 start = chptr; 03170 /*@innerbreak@*/ break; 03171 } else { 03172 start++; 03173 } 03174 } 03175 03176 if (*start == '=') { 03177 token->u.tag.justOne = 1; 03178 start++; 03179 } else if (*start == '#') { 03180 token->u.tag.justOne = 1; 03181 token->u.tag.arrayCount = 1; 03182 start++; 03183 } 03184 03185 next = start; 03186 while (*next && *next != '}') next++; 03187 if (!*next) { 03188 hsa->errmsg = _("missing } after %{"); 03189 format = freeFormat(format, numTokens); 03190 return 1; 03191 } 03192 /*@-modfilesys@*/ 03193 if (_hdr_debug) 03194 fprintf(stderr, "\tnext *%p = NUL\n", next); 03195 /*@=modfilesys@*/ 03196 *next++ = '\0'; 03197 03198 #define isSEP(_c) ((_c) == ':' || (_c) == '|') 03199 chptr = start; 03200 while (!(*chptr == '\0' || isSEP(*chptr))) chptr++; 03201 /* Split ":bing|bang:boom" --qf pipeline formatters (if any) */ 03202 while (isSEP(*chptr)) { 03203 if (chptr[1] == '\0' || isSEP(chptr[1])) { 03204 hsa->errmsg = _("empty tag format"); 03205 format = freeFormat(format, numTokens); 03206 return 1; 03207 } 03208 /* Parse the formatter parameter list. */ 03209 { char * te = chptr + 1; 03210 char * t = strchr(te, '('); 03211 char c; 03212 03213 while (!(*te == '\0' || isSEP(*te))) { 03214 #ifdef NOTYET /* XXX some means of escaping is needed */ 03215 if (te[0] == '\\' && te[1] != '\0') te++; 03216 #endif 03217 te++; 03218 } 03219 c = *te; *te = '\0'; 03220 /* Parse (a,b,c) parameter list. */ 03221 if (t != NULL) { 03222 *t++ = '\0'; 03223 if (te <= t || te[-1] != ')') { 03224 hsa->errmsg = _("malformed parameter list"); 03225 format = freeFormat(format, numTokens); 03226 return 1; 03227 } 03228 te[-1] = '\0'; 03229 xx = argvAdd(&token->u.tag.params, t); 03230 } else 03231 xx = argvAdd(&token->u.tag.params, ""); 03232 /*@-modfilesys@*/ 03233 if (_hdr_debug) 03234 fprintf(stderr, "\tformat \"%s\" params \"%s\"\n", chptr, (t ? t : "")); 03235 /*@=modfilesys@*/ 03236 xx = argvAdd(&token->u.tag.av, chptr); 03237 *te = c; 03238 *chptr = '\0'; 03239 chptr = te; 03240 } 03241 } 03242 #undef isSEP 03243 03244 if (*start == '\0') { 03245 hsa->errmsg = _("empty tag name"); 03246 format = freeFormat(format, numTokens); 03247 return 1; 03248 } 03249 03250 i = 0; 03251 token->type = PTOK_TAG; 03252 03253 if (findTag(hsa, token, start)) { 03254 hsa->errmsg = _("unknown tag"); 03255 format = freeFormat(format, numTokens); 03256 return 1; 03257 } 03258 03259 dst = start = next; 03260 /*@-modfilesys@*/ 03261 if (_hdr_debug) 03262 fprintf(stderr, "\tdst = start = next %p\n", dst); 03263 /*@=modfilesys@*/ 03264 /*@switchbreak@*/ break; 03265 03266 case '[': 03267 /*@-modfilesys@*/ 03268 if (_hdr_debug) 03269 fprintf(stderr, "\t%s => %s *%p = NUL\n", pstates[(state & 0x3)], pstates[PARSER_IN_ARRAY], start); 03270 /*@=modfilesys@*/ 03271 *start++ = '\0'; 03272 token = format + numTokens++; 03273 03274 if (parseFormat(hsa, start, 03275 &token->u.array.format, 03276 &token->u.array.numTokens, 03277 &start, PARSER_IN_ARRAY)) 03278 { 03279 format = freeFormat(format, numTokens); 03280 return 1; 03281 } 03282 03283 if (!start) { 03284 hsa->errmsg = _("] expected at end of array"); 03285 format = freeFormat(format, numTokens); 03286 return 1; 03287 } 03288 03289 dst = start; 03290 /*@-modfilesys@*/ 03291 if (_hdr_debug) 03292 fprintf(stderr, "\tdst = start %p\n", dst); 03293 /*@=modfilesys@*/ 03294 03295 token->type = PTOK_ARRAY; 03296 03297 /*@switchbreak@*/ break; 03298 03299 case ']': 03300 if (state != PARSER_IN_ARRAY) { 03301 hsa->errmsg = _("unexpected ]"); 03302 format = freeFormat(format, numTokens); 03303 return 1; 03304 } 03305 *start++ = '\0'; 03306 /*@-modfilesys@*/ 03307 if (_hdr_debug) 03308 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start); 03309 /*@=modfilesys@*/ 03310 if (endPtr) *endPtr = start; 03311 done = 1; 03312 /*@switchbreak@*/ break; 03313 03314 case '}': 03315 if (state != PARSER_IN_EXPR) { 03316 hsa->errmsg = _("unexpected }"); 03317 format = freeFormat(format, numTokens); 03318 return 1; 03319 } 03320 *start++ = '\0'; 03321 /*@-modfilesys@*/ 03322 if (_hdr_debug) 03323 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start); 03324 /*@=modfilesys@*/ 03325 if (endPtr) *endPtr = start; 03326 done = 1; 03327 /*@switchbreak@*/ break; 03328 03329 default: 03330 if (token == NULL || token->type != PTOK_STRING) { 03331 token = format + numTokens++; 03332 token->type = PTOK_STRING; 03333 /*@-temptrans -assignexpose@*/ 03334 dst = token->u.string.string = start; 03335 /*@=temptrans =assignexpose@*/ 03336 } 03337 03338 /*@-modfilesys@*/ 03339 if (_hdr_debug) 03340 fprintf(stderr, "\t*%p = *%p \"%.30s\"\n", dst, start, start); 03341 /*@=modfilesys@*/ 03342 if (start[0] == '\\' && start[1] != '\0') { 03343 start++; 03344 *dst++ = escapedChar(*start); 03345 *start++ = '\0'; 03346 } else { 03347 *dst++ = *start++; 03348 } 03349 if (dst < start) *dst = '\0'; 03350 /*@switchbreak@*/ break; 03351 } 03352 if (done) 03353 break; 03354 } 03355 /*@=infloops@*/ 03356 03357 if (dst != NULL) 03358 *dst = '\0'; 03359 03360 for (i = 0; i < (unsigned) numTokens; i++) { 03361 token = format + i; 03362 switch(token->type) { 03363 default: 03364 /*@switchbreak@*/ break; 03365 case PTOK_STRING: 03366 token->u.string.len = strlen(token->u.string.string); 03367 /*@switchbreak@*/ break; 03368 } 03369 } 03370 03371 if (numTokensPtr != NULL) 03372 *numTokensPtr = numTokens; 03373 if (formatPtr != NULL) 03374 *formatPtr = format; 03375 03376 return 0; 03377 } 03378 03379 static int parseExpression(headerSprintfArgs hsa, sprintfToken token, 03380 char * str, /*@out@*/ char ** endPtr) 03381 { 03382 char * chptr; 03383 char * end; 03384 03385 /*@-modfilesys@*/ 03386 if (_hdr_debug) 03387 fprintf(stderr, "--> parseExpression(%p, %p, \"%.20s...\", %p)\n", hsa, token, str, endPtr); 03388 /*@=modfilesys@*/ 03389 03390 hsa->errmsg = NULL; 03391 chptr = str; 03392 while (*chptr && *chptr != '?') chptr++; 03393 03394 if (*chptr != '?') { 03395 hsa->errmsg = _("? expected in expression"); 03396 return 1; 03397 } 03398 03399 *chptr++ = '\0'; 03400 03401 if (*chptr != '{') { 03402 hsa->errmsg = _("{ expected after ? in expression"); 03403 return 1; 03404 } 03405 03406 chptr++; 03407 03408 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 03409 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 03410 return 1; 03411 03412 /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/ 03413 if (!(end && *end)) { 03414 hsa->errmsg = _("} expected in expression"); 03415 token->u.cond.ifFormat = 03416 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 03417 return 1; 03418 } 03419 03420 chptr = end; 03421 if (*chptr != ':' && *chptr != '|') { 03422 hsa->errmsg = _(": expected following ? subexpression"); 03423 token->u.cond.ifFormat = 03424 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 03425 return 1; 03426 } 03427 03428 if (*chptr == '|') { 03429 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 03430 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 03431 { 03432 token->u.cond.ifFormat = 03433 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 03434 return 1; 03435 } 03436 } else { 03437 chptr++; 03438 03439 if (*chptr != '{') { 03440 hsa->errmsg = _("{ expected after : in expression"); 03441 token->u.cond.ifFormat = 03442 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 03443 return 1; 03444 } 03445 03446 chptr++; 03447 03448 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 03449 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 03450 return 1; 03451 03452 /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */ 03453 if (!(end && *end)) { 03454 hsa->errmsg = _("} expected in expression"); 03455 token->u.cond.ifFormat = 03456 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 03457 return 1; 03458 } 03459 03460 chptr = end; 03461 if (*chptr != '|') { 03462 hsa->errmsg = _("| expected at end of expression"); 03463 token->u.cond.ifFormat = 03464 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens); 03465 token->u.cond.elseFormat = 03466 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens); 03467 return 1; 03468 } 03469 } 03470 03471 chptr++; 03472 03473 *endPtr = chptr; 03474 03475 token->type = PTOK_COND; 03476 03477 (void) findTag(hsa, token, str); 03478 03479 return 0; 03480 } 03481 03490 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn, 03491 HE_t he, HE_t ec) 03492 /*@modifies he, ec @*/ 03493 { 03494 int rc = 0; 03495 if (!ec->avail) { 03496 he = rpmheClean(he); 03497 rc = fn(hsa->h, he); 03498 *ec = *he; /* structure copy. */ 03499 if (!rc) 03500 ec->avail = 1; 03501 } else 03502 *he = *ec; /* structure copy. */ 03503 he->freeData = 0; 03504 return rc; 03505 } 03506 03514 /*@observer@*/ /*@null@*/ 03515 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element) 03516 /*@modifies hsa @*/ 03517 { 03518 HE_t vhe = memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe)); 03519 HE_t he = &tag->he; 03520 char * val = NULL; 03521 size_t need = 0; 03522 char * t, * te; 03523 int_64 ival = 0; 03524 rpmTagCount countBuf; 03525 int xx; 03526 03527 if (!he->avail) { 03528 if (tag->ext) { 03529 xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum); 03530 } else { 03531 he->tag = tag->tagno; 03532 #ifdef NOTYET 03533 if (_usehge) { 03534 xx = headerGetExtension(hsa->h, he->tag, &he->t, &he->p, &he->c); 03535 if (xx) /* XXX 1 on success */ 03536 he->freeData = 1; 03537 } else 03538 #endif 03539 { 03540 xx = headerGetEntry(hsa->h, he->tag, (hTYP_t)&he->t, &he->p, &he->c); 03541 if (xx) /* XXX 1 on success */ 03542 he = rpmheMark(he); 03543 } 03544 xx = (xx == 0); /* XXX invert headerGetEntry return. */ 03545 } 03546 if (xx) { 03547 (void) rpmheClean(he); 03548 he->t = RPM_STRING_TYPE; 03549 he->p.str = "(none)"; 03550 he->c = 1; 03551 } 03552 he->avail = 1; 03553 } 03554 03555 if (tag->arrayCount) { 03556 countBuf = he->c; 03557 he = rpmheClean(he); 03558 he->t = RPM_INT32_TYPE; 03559 he->p.i32p = &countBuf; 03560 he->c = 1; 03561 he->freeData = 0; 03562 } 03563 03564 if (he->p.ptr) 03565 switch (he->t) { 03566 default: 03567 val = xstrdup("(unknown type)"); 03568 need = strlen(val) + 1; 03569 goto exit; 03570 /*@notreached@*/ break; 03571 case RPM_I18NSTRING_TYPE: 03572 case RPM_STRING_ARRAY_TYPE: 03573 vhe->t = RPM_STRING_TYPE; 03574 vhe->p.str = he->p.argv[element]; 03575 vhe->c = he->c; 03576 vhe->ix = (he->t == RPM_STRING_ARRAY_TYPE || he->c > 1 ? 0 : -1); 03577 break; 03578 case RPM_STRING_TYPE: 03579 vhe->p.str = he->p.str; 03580 vhe->t = RPM_STRING_TYPE; 03581 vhe->c = 0; 03582 vhe->ix = -1; 03583 break; 03584 case RPM_CHAR_TYPE: 03585 case RPM_INT8_TYPE: 03586 case RPM_INT16_TYPE: 03587 case RPM_INT32_TYPE: 03588 case RPM_INT64_TYPE: 03589 switch (he->t) { 03590 default: 03591 assert(0); /* XXX keep gcc quiet. */ 03592 break; 03593 case RPM_CHAR_TYPE: 03594 case RPM_INT8_TYPE: 03595 ival = he->p.i8p[element]; 03596 break; 03597 case RPM_INT16_TYPE: 03598 ival = he->p.ui16p[element]; /* XXX note unsigned. */ 03599 break; 03600 case RPM_INT32_TYPE: 03601 ival = he->p.i32p[element]; 03602 break; 03603 case RPM_INT64_TYPE: 03604 ival = he->p.i64p[element]; 03605 break; 03606 } 03607 vhe->t = RPM_INT64_TYPE; 03608 vhe->p.i64p = &ival; 03609 vhe->c = he->c; 03610 vhe->ix = (he->c > 1 ? 0 : -1); 03611 if ((myTagType(hsa->tags, he->tag) & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) 03612 vhe->ix = 0; 03613 break; 03614 03615 case RPM_OPENPGP_TYPE: /* XXX W2DO? */ 03616 case RPM_ASN1_TYPE: /* XXX W2DO? */ 03617 case RPM_BIN_TYPE: 03618 vhe->t = RPM_BIN_TYPE; 03619 vhe->p.ptr = he->p.ptr; 03620 vhe->c = he->c; 03621 vhe->ix = -1; 03622 break; 03623 } 03624 03625 /*@-compmempass@*/ /* vhe->p.ui64p is stack, not owned */ 03626 if (tag->fmtfuncs) { 03627 char * nval; 03628 int i; 03629 for (i = 0; tag->av[i] != NULL; i++) { 03630 headerTagFormatFunction fmt; 03631 ARGV_t av; 03632 if ((fmt = tag->fmtfuncs[i]) == NULL) 03633 continue; 03634 /* If !1st formatter, and transformer, not extractor, save val. */ 03635 if (val != NULL && *tag->av[i] == '|') { 03636 int ix = vhe->ix; 03637 vhe = rpmheClean(vhe); 03638 vhe->tag = he->tag; 03639 vhe->t = RPM_STRING_TYPE; 03640 vhe->p.str = xstrdup(val); 03641 vhe->c = he->c; 03642 vhe->ix = ix; 03643 vhe->freeData = 1; 03644 } 03645 av = NULL; 03646 if (tag->params && tag->params[i] && *tag->params[i] != '\0') 03647 xx = argvSplit(&av, tag->params[i], ","); 03648 03649 nval = fmt(vhe, av); 03650 03651 /*@-modfilesys@*/ 03652 if (_hdr_debug) 03653 fprintf(stderr, "\t%s(%s) %p(%p,%p) ret \"%s\"\n", tag->av[i], tag->params[i], fmt, vhe, (av ? av : NULL), val); 03654 /*@=modfilesys@*/ 03655 03656 /* Accumulate (by appending) next formmatter's return string. */ 03657 if (val == NULL) 03658 val = xstrdup((nval ? nval : "")); 03659 else { 03660 char * oval = val; 03661 /* XXX using ... | ... as separator is feeble. */ 03662 val = rpmExpand(val, (*val ? " | " : ""), nval, NULL); 03663 oval = _free(oval); 03664 } 03665 nval = _free(nval); 03666 av = argvFree(av); 03667 } 03668 } 03669 if (val == NULL) 03670 val = intFormat(vhe, NULL, NULL); 03671 /*@=compmempass@*/ 03672 assert(val != NULL); 03673 if (val) 03674 need = strlen(val) + 1; 03675 03676 exit: 03677 if (!_tagcache) 03678 he = rpmheClean(he); 03679 03680 if (val && need > 0) { 03681 if (tag->format && *tag->format && tag->pad) { 03682 size_t nb; 03683 nb = strlen(tag->format) + sizeof("%s"); 03684 t = alloca(nb); 03685 (void) stpcpy( stpcpy( stpcpy(t, "%"), tag->format), "s"); 03686 nb = tag->pad + strlen(val) + 1; 03687 te = xmalloc(nb); 03688 (void) snprintf(te, nb, t, val); 03689 te[nb-1] = '\0'; 03690 val = _free(val); 03691 val = te; 03692 need += tag->pad; 03693 } 03694 t = hsaReserve(hsa, need); 03695 te = stpcpy(t, val); 03696 hsa->vallen += (te - t); 03697 val = _free(val); 03698 } 03699 03700 return (hsa->val + hsa->vallen); 03701 } 03702 03710 /*@observer@*/ 03711 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token, 03712 int element) 03713 /*@modifies hsa @*/ 03714 { 03715 char numbuf[64]; /* XXX big enuf for "Tag_0x01234567" */ 03716 char * t, * te; 03717 int i, j; 03718 int numElements; 03719 sprintfToken spft; 03720 sprintfTag tag = NULL; 03721 HE_t he = NULL; 03722 int condNumFormats; 03723 size_t need; 03724 int xx; 03725 03726 /* we assume the token and header have been validated already! */ 03727 03728 switch (token->type) { 03729 case PTOK_NONE: 03730 break; 03731 03732 case PTOK_STRING: 03733 need = token->u.string.len; 03734 if (need == 0) break; 03735 t = hsaReserve(hsa, need); 03736 te = stpcpy(t, token->u.string.string); 03737 hsa->vallen += (te - t); 03738 break; 03739 03740 case PTOK_TAG: 03741 t = hsa->val + hsa->vallen; 03742 te = formatValue(hsa, &token->u.tag, 03743 (token->u.tag.justOne ? 0 : element)); 03744 if (te == NULL) 03745 return NULL; 03746 break; 03747 03748 case PTOK_COND: 03749 if (token->u.cond.tag.ext 03750 || headerIsEntry(hsa->h, token->u.cond.tag.tagno)) 03751 { 03752 spft = token->u.cond.ifFormat; 03753 condNumFormats = token->u.cond.numIfTokens; 03754 } else { 03755 spft = token->u.cond.elseFormat; 03756 condNumFormats = token->u.cond.numElseTokens; 03757 } 03758 03759 need = condNumFormats * 20; 03760 if (spft == NULL || need == 0) break; 03761 03762 t = hsaReserve(hsa, need); 03763 for (i = 0; i < condNumFormats; i++, spft++) { 03764 te = singleSprintf(hsa, spft, element); 03765 if (te == NULL) 03766 return NULL; 03767 } 03768 break; 03769 03770 case PTOK_ARRAY: 03771 numElements = -1; 03772 spft = token->u.array.format; 03773 for (i = 0; i < token->u.array.numTokens; i++, spft++) 03774 { 03775 tag = &spft->u.tag; 03776 if (spft->type != PTOK_TAG || tag->arrayCount || tag->justOne) 03777 continue; 03778 he = &tag->he; 03779 if (!he->avail) { 03780 he->tag = tag->tagno; 03781 if (tag->ext) 03782 xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum); 03783 else { 03784 #ifdef NOTYET 03785 if (_usehge) { 03786 xx = headerGetExtension(hsa->h, he->tag, &he->t, &he->p, &he->c); 03787 if (xx) 03788 he->freeData = 1; 03789 } else 03790 #endif 03791 { 03792 xx = headerGetEntry(hsa->h, he->tag, (hTYP_t)&he->t, &he->p, &he->c); 03793 if (xx) /* XXX 1 on success */ 03794 rpmheMark(he); 03795 } 03796 xx = (xx == 0); /* XXX invert headerGetEntry return. */ 03797 } 03798 if (xx) { 03799 (void) rpmheClean(he); 03800 continue; 03801 } 03802 he->avail = 1; 03803 } 03804 03805 /* Check iteration arrays are same dimension (or scalar). */ 03806 switch (he->t) { 03807 default: 03808 if (numElements == -1) { 03809 numElements = he->c; 03810 /*@switchbreak@*/ break; 03811 } 03812 if (he->c == numElements) 03813 /*@switchbreak@*/ break; 03814 hsa->errmsg = 03815 _("array iterator used with different sized arrays"); 03816 he = rpmheClean(he); 03817 return NULL; 03818 /*@notreached@*/ /*@switchbreak@*/ break; 03819 case RPM_OPENPGP_TYPE: 03820 case RPM_ASN1_TYPE: 03821 case RPM_BIN_TYPE: 03822 case RPM_STRING_TYPE: 03823 if (numElements == -1) 03824 numElements = 1; 03825 /*@switchbreak@*/ break; 03826 } 03827 if (!_tagcache) 03828 he = rpmheClean(he); 03829 } 03830 spft = token->u.array.format; 03831 03832 if (numElements == -1) { 03833 #ifdef DYING /* XXX lots of pugly "(none)" lines with --conflicts. */ 03834 need = sizeof("(none)\n") - 1; 03835 t = hsaReserve(hsa, need); 03836 te = stpcpy(t, "(none)\n"); 03837 hsa->vallen += (te - t); 03838 #endif 03839 } else { 03840 int isxml; 03841 int isyaml; 03842 03843 need = numElements * token->u.array.numTokens; 03844 if (need == 0) break; 03845 03846 tag = &spft->u.tag; 03847 03848 /* XXX Ick: +1 needed to handle :extractor |transformer marking. */ 03849 isxml = (spft->type == PTOK_TAG && tag->av != NULL && 03850 tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml")); 03851 isyaml = (spft->type == PTOK_TAG && tag->av != NULL && 03852 tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml")); 03853 03854 if (isxml) { 03855 const char * tagN = myTagName(hsa->tags, tag->tagno, NULL); 03856 /* XXX display "Tag_0x01234567" for unknown tags. */ 03857 if (tagN == NULL) { 03858 (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x", 03859 tag->tagno); 03860 numbuf[sizeof(numbuf)-1] = '\0'; 03861 tagN = numbuf; 03862 } 03863 need = sizeof(" <rpmTag name=\"\">\n") + strlen(tagN); 03864 te = t = hsaReserve(hsa, need); 03865 te = stpcpy( stpcpy( stpcpy(te, " <rpmTag name=\""), tagN), "\">\n"); 03866 hsa->vallen += (te - t); 03867 } 03868 if (isyaml) { 03869 int tagT = -1; 03870 const char * tagN = myTagName(hsa->tags, tag->tagno, &tagT); 03871 /* XXX display "Tag_0x01234567" for unknown tags. */ 03872 if (tagN == NULL) { 03873 (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x", 03874 tag->tagno); 03875 numbuf[sizeof(numbuf)-1] = '\0'; 03876 tagN = numbuf; 03877 tagT = numElements > 1 03878 ? RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE; 03879 } 03880 need = sizeof(" : - ") + strlen(tagN); 03881 te = t = hsaReserve(hsa, need); 03882 *te++ = ' '; 03883 *te++ = ' '; 03884 te = stpcpy(te, tagN); 03885 *te++ = ':'; 03886 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) 03887 ? '\n' : ' '); 03888 *te = '\0'; 03889 hsa->vallen += (te - t); 03890 } 03891 03892 need = numElements * token->u.array.numTokens * 10; 03893 t = hsaReserve(hsa, need); 03894 for (j = 0; j < numElements; j++) { 03895 spft = token->u.array.format; 03896 for (i = 0; i < token->u.array.numTokens; i++, spft++) { 03897 te = singleSprintf(hsa, spft, j); 03898 if (te == NULL) 03899 return NULL; 03900 } 03901 } 03902 03903 if (isxml) { 03904 need = sizeof(" </rpmTag>\n") - 1; 03905 te = t = hsaReserve(hsa, need); 03906 te = stpcpy(te, " </rpmTag>\n"); 03907 hsa->vallen += (te - t); 03908 } 03909 if (isyaml) { 03910 #if 0 03911 need = sizeof("\n") - 1; 03912 te = t = hsaReserve(hsa, need); 03913 te = stpcpy(te, "\n"); 03914 hsa->vallen += (te - t); 03915 #endif 03916 } 03917 03918 } 03919 break; 03920 } 03921 03922 return (hsa->val + hsa->vallen); 03923 } 03924 03931 static /*@only@*/ HE_t 03932 rpmecNew(const headerSprintfExtension exts, /*@null@*/ int * necp) 03933 /*@*/ 03934 { 03935 headerSprintfExtension ext; 03936 HE_t ec; 03937 int extNum = 0; 03938 03939 if (exts != NULL) 03940 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 03941 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1), extNum++) 03942 { 03943 ; 03944 } 03945 if (necp) 03946 *necp = extNum; 03947 ec = xcalloc(extNum+1, sizeof(*ec)); /* XXX +1 unnecessary */ 03948 return ec; 03949 } 03950 03957 static /*@null@*/ HE_t 03958 rpmecFree(const headerSprintfExtension exts, /*@only@*/ HE_t ec) 03959 /*@modifies ec @*/ 03960 { 03961 headerSprintfExtension ext; 03962 int extNum; 03963 03964 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST; 03965 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1), extNum++) 03966 { 03967 (void) rpmheClean(&ec[extNum]); 03968 } 03969 03970 ec = _free(ec); 03971 return NULL; 03972 } 03973 03974 extern const struct headerTagTableEntry_s * rpmTagTable; 03975 03987 static /*@only@*/ /*@null@*/ 03988 char * headerSprintf(Header h, const char * fmt, 03989 const struct headerTagTableEntry_s * tags, 03990 const struct headerSprintfExtension_s * exts, 03991 /*@null@*/ /*@out@*/ errmsg_t * errmsg) 03992 /*@modifies h, *errmsg @*/ 03993 /*@requires maxSet(errmsg) >= 0 @*/ 03994 { 03995 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa)); 03996 sprintfToken nextfmt; 03997 sprintfTag tag; 03998 char * t, * te; 03999 int isxml; 04000 int isyaml; 04001 int need; 04002 04003 /*@-modfilesys@*/ 04004 if (_hdr_debug) 04005 fprintf(stderr, "==> headerSprintf(%p, \"%s\", %p, %p, %p)\n", h, fmt, tags, exts, errmsg); 04006 /*@=modfilesys@*/ 04007 04008 /* Set some reasonable defaults */ 04009 if (tags == NULL) 04010 tags = rpmTagTable; 04011 04012 hsa->h = headerLink(h); 04013 hsa->fmt = xstrdup(fmt); 04014 /*@-castexpose@*/ /* FIX: legacy API shouldn't change. */ 04015 hsa->exts = (headerSprintfExtension) exts; 04016 hsa->tags = (headerTagTableEntry) tags; 04017 /*@=castexpose@*/ 04018 hsa->errmsg = NULL; 04019 04020 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN)) 04021 goto exit; 04022 04023 hsa->nec = 0; 04024 hsa->ec = rpmecNew(hsa->exts, &hsa->nec); 04025 hsa->val = xstrdup(""); 04026 04027 tag = 04028 (hsa->format->type == PTOK_TAG 04029 ? &hsa->format->u.tag : 04030 (hsa->format->type == PTOK_ARRAY 04031 ? &hsa->format->u.array.format->u.tag : 04032 NULL)); 04033 /* XXX Ick: +1 needed to handle :extractor |transformer marking. */ 04034 isxml = (tag != NULL && tag->tagno == -2 && tag->av != NULL 04035 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml")); 04036 isyaml = (tag != NULL && tag->tagno == -2 && tag->av != NULL 04037 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml")); 04038 04039 if (isxml) { 04040 need = sizeof("<rpmHeader>\n") - 1; 04041 t = hsaReserve(hsa, need); 04042 te = stpcpy(t, "<rpmHeader>\n"); 04043 hsa->vallen += (te - t); 04044 } 04045 if (isyaml) { 04046 need = sizeof("- !!omap\n") - 1; 04047 t = hsaReserve(hsa, need); 04048 te = stpcpy(t, "- !!omap\n"); 04049 hsa->vallen += (te - t); 04050 } 04051 04052 hsa = hsaInit(hsa); 04053 while ((nextfmt = hsaNext(hsa)) != NULL) { 04054 te = singleSprintf(hsa, nextfmt, 0); 04055 if (te == NULL) { 04056 hsa->val = _free(hsa->val); 04057 break; 04058 } 04059 } 04060 hsa = hsaFini(hsa); 04061 04062 if (isxml) { 04063 need = sizeof("</rpmHeader>\n") - 1; 04064 t = hsaReserve(hsa, need); 04065 te = stpcpy(t, "</rpmHeader>\n"); 04066 hsa->vallen += (te - t); 04067 } 04068 if (isyaml) { 04069 need = sizeof("\n") - 1; 04070 t = hsaReserve(hsa, need); 04071 te = stpcpy(t, "\n"); 04072 hsa->vallen += (te - t); 04073 } 04074 04075 if (hsa->val != NULL && hsa->vallen < hsa->alloced) 04076 hsa->val = xrealloc(hsa->val, hsa->vallen+1); 04077 04078 hsa->ec = rpmecFree(hsa->exts, hsa->ec); 04079 hsa->nec = 0; 04080 hsa->format = freeFormat(hsa->format, hsa->numTokens); 04081 04082 exit: 04083 /*@-dependenttrans -observertrans @*/ 04084 if (errmsg) 04085 *errmsg = hsa->errmsg; 04086 /*@=dependenttrans =observertrans @*/ 04087 hsa->h = headerFree(hsa->h); 04088 hsa->fmt = _free(hsa->fmt); 04089 return hsa->val; 04090 } 04091 04098 static 04099 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy) 04100 /*@modifies headerTo @*/ 04101 { 04102 int * tagno; 04103 04104 if (headerFrom == headerTo) 04105 return; 04106 04107 for (tagno = tagstocopy; *tagno != 0; tagno++) { 04108 rpmTagType t; 04109 rpmTagData p = { .ptr = NULL }; 04110 rpmTagCount c; 04111 if (headerIsEntry(headerTo, *tagno)) 04112 continue; 04113 if (!headerGetEntryMinMemory(headerFrom, *tagno, (hTYP_t)&t, &p, &c)) 04114 continue; 04115 (void) headerAddEntry(headerTo, *tagno, t, p.ptr, c); 04116 p.ptr = headerFreeData(p.ptr, t); 04117 } 04118 } 04119 04120 /*@observer@*/ /*@unchecked@*/ 04121 static struct HV_s hdrVec1 = { 04122 headerLink, 04123 headerUnlink, 04124 headerFree, 04125 headerNew, 04126 headerSort, 04127 headerUnsort, 04128 headerSizeof, 04129 headerUnload, 04130 headerReload, 04131 headerCopy, 04132 headerLoad, 04133 headerCopyLoad, 04134 headerRead, 04135 headerWrite, 04136 headerIsEntry, 04137 headerFreeTag, 04138 headerGetEntry, 04139 headerGetEntryMinMemory, 04140 headerAddEntry, 04141 headerAppendEntry, 04142 headerAddOrAppendEntry, 04143 headerAddI18NString, 04144 headerModifyEntry, 04145 headerRemoveEntry, 04146 headerSprintf, 04147 headerCopyTags, 04148 headerFreeIterator, 04149 headerInitIterator, 04150 headerNextIterator, 04151 headerGetOrigin, 04152 headerSetOrigin, 04153 headerGetInstance, 04154 headerSetInstance, 04155 NULL, NULL, 04156 1 04157 }; 04158 04159 /*@-compmempass -redef@*/ 04160 /*@observer@*/ /*@unchecked@*/ 04161 HV_t hdrVec = &hdrVec1; 04162 /*@=compmempass =redef@*/