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