00001
00005
00006
00007
00008
00009
00010
00011 #include "system.h"
00012
00013 #define __HEADER_PROTOTYPES__
00014
00015 #include <header_internal.h>
00016
00017 #include "debug.h"
00018
00019
00020 int _hdr_debug = 0;
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #define PARSER_BEGIN 0
00031 #define PARSER_IN_ARRAY 1
00032 #define PARSER_IN_EXPR 2
00033
00036
00037 static unsigned char header_magic[8] = {
00038 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00039 };
00040
00044
00045 static int typeAlign[16] = {
00046 1,
00047 1,
00048 1,
00049 2,
00050 4,
00051 8,
00052 1,
00053 1,
00054 1,
00055 1,
00056 0,
00057 0,
00058 0,
00059 0,
00060 0,
00061 0
00062 };
00063
00067
00068 static int typeSizes[16] = {
00069 0,
00070 1,
00071 1,
00072 2,
00073 4,
00074 -1,
00075 -1,
00076 1,
00077 -1,
00078 -1,
00079 0,
00080 0,
00081 0,
00082 0,
00083 0,
00084 0
00085 };
00086
00090
00091 static size_t headerMaxbytes = (32*1024*1024);
00092
00097 #define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
00098
00102 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00103
00108 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00109
00113 #define hdrchkAlign(_type, _off) ((_off) & (typeAlign[_type]-1))
00114
00118 #define hdrchkRange(_dl, _off) ((_off) < 0 || (_off) > (_dl))
00119
00120
00121 HV_t hdrVec;
00122
00128 static inline void *
00129 _free( const void * p)
00130 {
00131 if (p != NULL) free((void *)p);
00132 return NULL;
00133 }
00134
00140 static
00141 Header headerLink(Header h)
00142
00143 {
00144
00145 if (h == NULL) return NULL;
00146
00147
00148 h->nrefs++;
00149
00150 if (_hdr_debug)
00151 fprintf(stderr, "--> h %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00152
00153
00154
00155 return h;
00156
00157 }
00158
00164 static
00165 Header headerUnlink( Header h)
00166
00167 {
00168 if (h == NULL) return NULL;
00169
00170 if (_hdr_debug)
00171 fprintf(stderr, "--> h %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00172
00173 h->nrefs--;
00174 return NULL;
00175 }
00176
00182 static
00183 Header headerFree( Header h)
00184
00185 {
00186 (void) headerUnlink(h);
00187
00188
00189 if (h == NULL || h->nrefs > 0)
00190 return NULL;
00191
00192 if (h->index) {
00193 indexEntry entry = h->index;
00194 int i;
00195 for (i = 0; i < h->indexUsed; i++, entry++) {
00196 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00197 if (entry->length > 0) {
00198 int_32 * ei = entry->data;
00199 if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00200 entry->data = NULL;
00201 }
00202 } else if (!ENTRY_IN_REGION(entry)) {
00203 entry->data = _free(entry->data);
00204 }
00205 entry->data = NULL;
00206 }
00207 h->index = _free(h->index);
00208 }
00209
00210 h = _free(h);
00211 return h;
00212
00213 }
00214
00219 static
00220 Header headerNew(void)
00221
00222 {
00223 Header h = xcalloc(1, sizeof(*h));
00224
00225
00226
00227 h->hv = *hdrVec;
00228
00229
00230 h->blob = NULL;
00231 h->indexAlloced = INDEX_MALLOC_SIZE;
00232 h->indexUsed = 0;
00233 h->flags |= HEADERFLAG_SORTED;
00234
00235 h->index = (h->indexAlloced
00236 ? xcalloc(h->indexAlloced, sizeof(*h->index))
00237 : NULL);
00238
00239 h->nrefs = 0;
00240
00241 return headerLink(h);
00242
00243 }
00244
00247 static int indexCmp(const void * avp, const void * bvp)
00248
00249 {
00250
00251 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00252
00253 return (ap->info.tag - bp->info.tag);
00254 }
00255
00260 static
00261 void headerSort(Header h)
00262
00263 {
00264 if (!(h->flags & HEADERFLAG_SORTED)) {
00265
00266 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00267
00268 h->flags |= HEADERFLAG_SORTED;
00269 }
00270 }
00271
00274 static int offsetCmp(const void * avp, const void * bvp)
00275 {
00276
00277 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00278
00279 int rc = (ap->info.offset - bp->info.offset);
00280
00281 if (rc == 0) {
00282
00283 if (ap->info.offset < 0)
00284 rc = (((char *)ap->data) - ((char *)bp->data));
00285 else
00286 rc = (ap->info.tag - bp->info.tag);
00287 }
00288 return rc;
00289 }
00290
00295 static
00296 void headerUnsort(Header h)
00297
00298 {
00299
00300 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00301
00302 }
00303
00310 static
00311 unsigned int headerSizeof( Header h, enum hMagic magicp)
00312
00313 {
00314 indexEntry entry;
00315 unsigned int size = 0;
00316 unsigned int pad = 0;
00317 int i;
00318
00319 if (h == NULL)
00320 return size;
00321
00322 headerSort(h);
00323
00324 switch (magicp) {
00325 case HEADER_MAGIC_YES:
00326 size += sizeof(header_magic);
00327 break;
00328 case HEADER_MAGIC_NO:
00329 break;
00330 }
00331
00332
00333 size += 2 * sizeof(int_32);
00334
00335
00336 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00337 unsigned diff;
00338 int_32 type;
00339
00340
00341 if (ENTRY_IS_REGION(entry)) {
00342 size += entry->length;
00343
00344
00345 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00346 size += sizeof(struct entryInfo_s) + entry->info.count;
00347
00348 continue;
00349 }
00350
00351
00352 if (entry->info.offset < 0)
00353 continue;
00354
00355
00356 type = entry->info.type;
00357
00358 if (typeSizes[type] > 1) {
00359 diff = typeSizes[type] - (size % typeSizes[type]);
00360 if (diff != typeSizes[type]) {
00361 size += diff;
00362 pad += diff;
00363 }
00364 }
00365
00366
00367
00368 size += sizeof(struct entryInfo_s) + entry->length;
00369
00370 }
00371
00372 return size;
00373 }
00374
00384 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00385 hPTR_t pend)
00386
00387 {
00388 const unsigned char * s = p;
00389 const unsigned char * se = pend;
00390 int length = 0;
00391
00392 switch (type) {
00393 case RPM_STRING_TYPE:
00394 if (count != 1)
00395 return -1;
00396
00397 while (*s++) {
00398 if (se && s > se)
00399 return -1;
00400 length++;
00401 }
00402
00403 length++;
00404 break;
00405
00406 case RPM_STRING_ARRAY_TYPE:
00407 case RPM_I18NSTRING_TYPE:
00408
00409
00410
00411 if (onDisk) {
00412 while (count--) {
00413 length++;
00414
00415 while (*s++) {
00416 if (se && s > se)
00417 return -1;
00418 length++;
00419 }
00420
00421 }
00422 } else {
00423 const char ** av = (const char **)p;
00424
00425 while (count--) {
00426
00427 length += strlen(*av++) + 1;
00428 }
00429
00430 }
00431 break;
00432
00433 default:
00434
00435 if (typeSizes[type] == -1)
00436 return -1;
00437 length = typeSizes[(type & 0xf)] * count;
00438
00439 if (length < 0 || (se && (s + length) > se))
00440 return -1;
00441 break;
00442 }
00443
00444 return length;
00445 }
00446
00473 static int regionSwab( indexEntry entry, int il, int dl,
00474 entryInfo pe,
00475 unsigned char * dataStart,
00476 const unsigned char * dataEnd,
00477 int regionid)
00478
00479 {
00480 unsigned char * tprev = NULL;
00481 unsigned char * t = NULL;
00482 int tdel = 0;
00483 int tl = dl;
00484 struct indexEntry_s ieprev;
00485
00486
00487 memset(&ieprev, 0, sizeof(ieprev));
00488
00489 for (; il > 0; il--, pe++) {
00490 struct indexEntry_s ie;
00491 int_32 type;
00492
00493 ie.info.tag = ntohl(pe->tag);
00494 ie.info.type = ntohl(pe->type);
00495 ie.info.count = ntohl(pe->count);
00496 ie.info.offset = ntohl(pe->offset);
00497
00498 if (hdrchkType(ie.info.type))
00499 return -1;
00500 if (hdrchkData(ie.info.count))
00501 return -1;
00502 if (hdrchkData(ie.info.offset))
00503 return -1;
00504
00505 if (hdrchkAlign(ie.info.type, ie.info.offset))
00506 return -1;
00507
00508
00509 ie.data = t = dataStart + ie.info.offset;
00510 if (dataEnd && t >= dataEnd)
00511 return -1;
00512
00513 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00514 if (ie.length < 0 || hdrchkData(ie.length))
00515 return -1;
00516
00517 ie.rdlen = 0;
00518
00519 if (entry) {
00520 ie.info.offset = regionid;
00521
00522 *entry = ie;
00523
00524 entry++;
00525 }
00526
00527
00528 type = ie.info.type;
00529
00530 if (typeSizes[type] > 1) {
00531 unsigned diff;
00532 diff = typeSizes[type] - (dl % typeSizes[type]);
00533 if (diff != typeSizes[type]) {
00534 dl += diff;
00535 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00536 ieprev.length += diff;
00537 }
00538 }
00539
00540 tdel = (tprev ? (t - tprev) : 0);
00541 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00542 tdel = ieprev.length;
00543
00544 if (ie.info.tag >= HEADER_I18NTABLE) {
00545 tprev = t;
00546 } else {
00547 tprev = dataStart;
00548
00549
00550 if (ie.info.tag == HEADER_IMAGE)
00551 tprev -= REGION_TAG_COUNT;
00552
00553 }
00554
00555
00556 switch (ntohl(pe->type)) {
00557
00558 case RPM_INT32_TYPE:
00559 { int_32 * it = (int_32 *)t;
00560 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00561 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00562 return -1;
00563 *it = htonl(*it);
00564 }
00565 t = (char *) it;
00566 } break;
00567 case RPM_INT16_TYPE:
00568 { int_16 * it = (int_16 *) t;
00569 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00570 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00571 return -1;
00572 *it = htons(*it);
00573 }
00574 t = (char *) it;
00575 } break;
00576
00577 default:
00578 t += ie.length;
00579 break;
00580 }
00581
00582 dl += ie.length;
00583 tl += tdel;
00584 ieprev = ie;
00585
00586 }
00587 tdel = (tprev ? (t - tprev) : 0);
00588 tl += tdel;
00589
00590
00591
00592
00593
00594
00595
00596 if (tl+REGION_TAG_COUNT == dl)
00597 tl += REGION_TAG_COUNT;
00598
00599
00600 return dl;
00601 }
00602
00608 static void * doHeaderUnload(Header h,
00609 int * lengthPtr)
00610
00611
00612
00613 {
00614 int_32 * ei = NULL;
00615 entryInfo pe;
00616 char * dataStart;
00617 char * te;
00618 unsigned pad;
00619 unsigned len;
00620 int_32 il = 0;
00621 int_32 dl = 0;
00622 indexEntry entry;
00623 int_32 type;
00624 int i;
00625 int drlen, ndribbles;
00626 int driplen, ndrips;
00627 int legacy = 0;
00628
00629
00630 headerUnsort(h);
00631
00632
00633 pad = 0;
00634 drlen = ndribbles = driplen = ndrips = 0;
00635 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00636 if (ENTRY_IS_REGION(entry)) {
00637 int_32 rdl = -entry->info.offset;
00638 int_32 ril = rdl/sizeof(*pe);
00639 int rid = entry->info.offset;
00640
00641 il += ril;
00642 dl += entry->rdlen + entry->info.count;
00643
00644 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00645 il += 1;
00646
00647
00648 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00649 if (entry->info.offset <= rid)
00650 continue;
00651
00652
00653 type = entry->info.type;
00654 if (typeSizes[type] > 1) {
00655 unsigned diff;
00656 diff = typeSizes[type] - (dl % typeSizes[type]);
00657 if (diff != typeSizes[type]) {
00658 drlen += diff;
00659 pad += diff;
00660 dl += diff;
00661 }
00662 }
00663
00664 ndribbles++;
00665 il++;
00666 drlen += entry->length;
00667 dl += entry->length;
00668 }
00669 i--;
00670 entry--;
00671 continue;
00672 }
00673
00674
00675 if (entry->data == NULL || entry->length <= 0)
00676 continue;
00677
00678
00679 type = entry->info.type;
00680 if (typeSizes[type] > 1) {
00681 unsigned diff;
00682 diff = typeSizes[type] - (dl % typeSizes[type]);
00683 if (diff != typeSizes[type]) {
00684 driplen += diff;
00685 pad += diff;
00686 dl += diff;
00687 } else
00688 diff = 0;
00689 }
00690
00691 ndrips++;
00692 il++;
00693 driplen += entry->length;
00694 dl += entry->length;
00695 }
00696
00697
00698 if (hdrchkTags(il) || hdrchkData(dl))
00699 goto errxit;
00700
00701 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00702
00703
00704 ei = xmalloc(len);
00705 ei[0] = htonl(il);
00706 ei[1] = htonl(dl);
00707
00708
00709 pe = (entryInfo) &ei[2];
00710 dataStart = te = (char *) (pe + il);
00711
00712 pad = 0;
00713 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00714 const char * src;
00715 char *t;
00716 int count;
00717 int rdlen;
00718
00719 if (entry->data == NULL || entry->length <= 0)
00720 continue;
00721
00722 t = te;
00723 pe->tag = htonl(entry->info.tag);
00724 pe->type = htonl(entry->info.type);
00725 pe->count = htonl(entry->info.count);
00726
00727 if (ENTRY_IS_REGION(entry)) {
00728 int_32 rdl = -entry->info.offset;
00729 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00730 int rid = entry->info.offset;
00731
00732 src = (char *)entry->data;
00733 rdlen = entry->rdlen;
00734
00735
00736 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00737 int_32 stei[4];
00738
00739 legacy = 1;
00740
00741 memcpy(pe+1, src, rdl);
00742 memcpy(te, src + rdl, rdlen);
00743
00744 te += rdlen;
00745
00746 pe->offset = htonl(te - dataStart);
00747 stei[0] = pe->tag;
00748 stei[1] = pe->type;
00749 stei[2] = htonl(-rdl-entry->info.count);
00750 stei[3] = pe->count;
00751
00752 memcpy(te, stei, entry->info.count);
00753
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
00765 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00766 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00767
00768 te += rdlen;
00769 {
00770 entryInfo se = (entryInfo)src;
00771
00772 int off = ntohl(se->offset);
00773 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00774 }
00775 te += entry->info.count + drlen;
00776
00777 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00778 if (count != (rdlen + entry->info.count + drlen))
00779 goto errxit;
00780 }
00781
00782
00783 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00784 i++;
00785 entry++;
00786 }
00787 i--;
00788 entry--;
00789 pe += ril;
00790 continue;
00791 }
00792
00793
00794 if (entry->data == NULL || entry->length <= 0)
00795 continue;
00796
00797
00798 type = entry->info.type;
00799 if (typeSizes[type] > 1) {
00800 unsigned diff;
00801 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00802 if (diff != typeSizes[type]) {
00803
00804 memset(te, 0, diff);
00805
00806 te += diff;
00807 pad += diff;
00808 }
00809 }
00810
00811 pe->offset = htonl(te - dataStart);
00812
00813
00814
00815 switch (entry->info.type) {
00816 case RPM_INT32_TYPE:
00817 count = entry->info.count;
00818 src = entry->data;
00819 while (count--) {
00820 *((int_32 *)te) = htonl(*((int_32 *)src));
00821
00822 te += sizeof(int_32);
00823 src += sizeof(int_32);
00824
00825 }
00826 break;
00827
00828 case RPM_INT16_TYPE:
00829 count = entry->info.count;
00830 src = entry->data;
00831 while (count--) {
00832 *((int_16 *)te) = htons(*((int_16 *)src));
00833
00834 te += sizeof(int_16);
00835 src += sizeof(int_16);
00836
00837 }
00838 break;
00839
00840 default:
00841 memcpy(te, entry->data, entry->length);
00842 te += entry->length;
00843 break;
00844 }
00845
00846 pe++;
00847 }
00848
00849
00850 if (((char *)pe) != dataStart)
00851 goto errxit;
00852 if ((((char *)ei)+len) != te)
00853 goto errxit;
00854
00855 if (lengthPtr)
00856 *lengthPtr = len;
00857
00858 h->flags &= ~HEADERFLAG_SORTED;
00859 headerSort(h);
00860
00861 return (void *) ei;
00862
00863 errxit:
00864
00865 ei = _free(ei);
00866
00867 return (void *) ei;
00868 }
00869
00875 static
00876 void * headerUnload(Header h)
00877
00878 {
00879 int length;
00880
00881 void * uh = doHeaderUnload(h, &length);
00882
00883 return uh;
00884 }
00885
00893 static
00894 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00895
00896 {
00897 indexEntry entry, entry2, last;
00898 struct indexEntry_s key;
00899
00900 if (h == NULL) return NULL;
00901 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00902
00903 key.info.tag = tag;
00904
00905
00906 entry2 = entry =
00907 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00908
00909 if (entry == NULL)
00910 return NULL;
00911
00912 if (type == RPM_NULL_TYPE)
00913 return entry;
00914
00915
00916 while (entry->info.tag == tag && entry->info.type != type &&
00917 entry > h->index) entry--;
00918
00919 if (entry->info.tag == tag && entry->info.type == type)
00920 return entry;
00921
00922 last = h->index + h->indexUsed;
00923
00924 while (entry2->info.tag == tag && entry2->info.type != type &&
00925 entry2 < last) entry2++;
00926
00927
00928 if (entry->info.tag == tag && entry->info.type == type)
00929 return entry;
00930
00931 return NULL;
00932 }
00933
00943 static
00944 int headerRemoveEntry(Header h, int_32 tag)
00945
00946 {
00947 indexEntry last = h->index + h->indexUsed;
00948 indexEntry entry, first;
00949 int ne;
00950
00951 entry = findEntry(h, tag, RPM_NULL_TYPE);
00952 if (!entry) return 1;
00953
00954
00955 while (entry > h->index && (entry - 1)->info.tag == tag)
00956 entry--;
00957
00958
00959 for (first = entry; first < last; first++) {
00960 void * data;
00961 if (first->info.tag != tag)
00962 break;
00963 data = first->data;
00964 first->data = NULL;
00965 first->length = 0;
00966 if (ENTRY_IN_REGION(first))
00967 continue;
00968 data = _free(data);
00969 }
00970
00971 ne = (first - entry);
00972 if (ne > 0) {
00973 h->indexUsed -= ne;
00974 ne = last - first;
00975
00976 if (ne > 0)
00977 memmove(entry, first, (ne * sizeof(*entry)));
00978
00979 }
00980
00981 return 0;
00982 }
00983
00989 static
00990 Header headerLoad( void * uh)
00991
00992 {
00993 int_32 * ei = (int_32 *) uh;
00994 int_32 il = ntohl(ei[0]);
00995 int_32 dl = ntohl(ei[1]);
00996
00997 size_t pvlen = sizeof(il) + sizeof(dl) +
00998 (il * sizeof(struct entryInfo_s)) + dl;
00999
01000 void * pv = uh;
01001 Header h = NULL;
01002 entryInfo pe;
01003 unsigned char * dataStart;
01004 unsigned char * dataEnd;
01005 indexEntry entry;
01006 int rdlen;
01007 int i;
01008
01009
01010 if (hdrchkTags(il) || hdrchkData(dl))
01011 goto errxit;
01012
01013 ei = (int_32 *) pv;
01014
01015 pe = (entryInfo) &ei[2];
01016
01017 dataStart = (unsigned char *) (pe + il);
01018 dataEnd = dataStart + dl;
01019
01020 h = xcalloc(1, sizeof(*h));
01021
01022 h->hv = *hdrVec;
01023
01024
01025 h->blob = uh;
01026
01027 h->indexAlloced = il + 1;
01028 h->indexUsed = il;
01029 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01030 h->flags |= HEADERFLAG_SORTED;
01031 h->nrefs = 0;
01032 h = headerLink(h);
01033
01034
01035
01036
01037
01038 if (ntohl(pe->tag) == 15 &&
01039 ntohl(pe->type) == RPM_STRING_TYPE &&
01040 ntohl(pe->count) == 1)
01041 {
01042 pe->tag = htonl(1079);
01043 }
01044
01045 entry = h->index;
01046 i = 0;
01047 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01048 h->flags |= HEADERFLAG_LEGACY;
01049 entry->info.type = REGION_TAG_TYPE;
01050 entry->info.tag = HEADER_IMAGE;
01051
01052 entry->info.count = REGION_TAG_COUNT;
01053
01054 entry->info.offset = ((unsigned char *)pe - dataStart);
01055
01056
01057 entry->data = pe;
01058
01059 entry->length = pvlen - sizeof(il) - sizeof(dl);
01060 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01061 #if 0
01062 if (rdlen != dl)
01063 goto errxit;
01064 #endif
01065 entry->rdlen = rdlen;
01066 entry++;
01067 h->indexUsed++;
01068 } else {
01069 int_32 rdl;
01070 int_32 ril;
01071
01072 h->flags &= ~HEADERFLAG_LEGACY;
01073
01074 entry->info.type = htonl(pe->type);
01075 entry->info.count = htonl(pe->count);
01076
01077 if (hdrchkType(entry->info.type))
01078 goto errxit;
01079 if (hdrchkTags(entry->info.count))
01080 goto errxit;
01081
01082 { int off = ntohl(pe->offset);
01083
01084 if (hdrchkData(off))
01085 goto errxit;
01086 if (off) {
01087
01088 size_t nb = REGION_TAG_COUNT;
01089
01090 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01091 rdl = -ntohl(stei[2]);
01092 ril = rdl/sizeof(*pe);
01093 if (hdrchkTags(ril) || hdrchkData(rdl))
01094 goto errxit;
01095 entry->info.tag = htonl(pe->tag);
01096 } else {
01097 ril = il;
01098
01099 rdl = (ril * sizeof(struct entryInfo_s));
01100
01101 entry->info.tag = HEADER_IMAGE;
01102 }
01103 }
01104 entry->info.offset = -rdl;
01105
01106
01107 entry->data = pe;
01108
01109 entry->length = pvlen - sizeof(il) - sizeof(dl);
01110 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01111 if (rdlen < 0)
01112 goto errxit;
01113 entry->rdlen = rdlen;
01114
01115 if (ril < h->indexUsed) {
01116 indexEntry newEntry = entry + ril;
01117 int ne = (h->indexUsed - ril);
01118 int rid = entry->info.offset+1;
01119 int rc;
01120
01121
01122 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01123 if (rc < 0)
01124 goto errxit;
01125 rdlen += rc;
01126
01127 { indexEntry firstEntry = newEntry;
01128 int save = h->indexUsed;
01129 int j;
01130
01131
01132 h->indexUsed -= ne;
01133 for (j = 0; j < ne; j++, newEntry++) {
01134 (void) headerRemoveEntry(h, newEntry->info.tag);
01135 if (newEntry->info.tag == HEADER_BASENAMES)
01136 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01137 }
01138
01139
01140
01141 if (h->indexUsed < (save - ne)) {
01142 memmove(h->index + h->indexUsed, firstEntry,
01143 (ne * sizeof(*entry)));
01144 }
01145
01146 h->indexUsed += ne;
01147 }
01148 }
01149 }
01150
01151 h->flags &= ~HEADERFLAG_SORTED;
01152 headerSort(h);
01153
01154
01155 return h;
01156
01157
01158 errxit:
01159
01160 if (h) {
01161 h->index = _free(h->index);
01162
01163 h = _free(h);
01164
01165 }
01166
01167
01168 return h;
01169
01170 }
01171
01179 static
01180 Header headerReload( Header h, int tag)
01181
01182 {
01183 Header nh;
01184 int length;
01185
01186
01187 void * uh = doHeaderUnload(h, &length);
01188
01189
01190 h = headerFree(h);
01191
01192 if (uh == NULL)
01193 return NULL;
01194 nh = headerLoad(uh);
01195 if (nh == NULL) {
01196 uh = _free(uh);
01197 return NULL;
01198 }
01199 if (nh->flags & HEADERFLAG_ALLOCATED)
01200 uh = _free(uh);
01201 nh->flags |= HEADERFLAG_ALLOCATED;
01202 if (ENTRY_IS_REGION(nh->index)) {
01203
01204 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01205 nh->index[0].info.tag = tag;
01206
01207 }
01208 return nh;
01209 }
01210
01216 static
01217 Header headerCopyLoad(const void * uh)
01218
01219 {
01220 int_32 * ei = (int_32 *) uh;
01221
01222 int_32 il = ntohl(ei[0]);
01223 int_32 dl = ntohl(ei[1]);
01224
01225
01226 size_t pvlen = sizeof(il) + sizeof(dl) +
01227 (il * sizeof(struct entryInfo_s)) + dl;
01228
01229 void * nuh = NULL;
01230 Header h = NULL;
01231
01232
01233
01234 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01235
01236 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01237
01238 if ((h = headerLoad(nuh)) != NULL)
01239 h->flags |= HEADERFLAG_ALLOCATED;
01240 }
01241
01242
01243 if (h == NULL)
01244 nuh = _free(nuh);
01245
01246 return h;
01247 }
01248
01255 static
01256 Header headerRead(FD_t fd, enum hMagic magicp)
01257
01258 {
01259 int_32 block[4];
01260 int_32 reserved;
01261 int_32 * ei = NULL;
01262 int_32 il;
01263 int_32 dl;
01264 int_32 magic;
01265 Header h = NULL;
01266 size_t len;
01267 int i;
01268
01269 memset(block, 0, sizeof(block));
01270 i = 2;
01271 if (magicp == HEADER_MAGIC_YES)
01272 i += 2;
01273
01274
01275 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01276 goto exit;
01277
01278
01279 i = 0;
01280
01281
01282 if (magicp == HEADER_MAGIC_YES) {
01283 magic = block[i++];
01284 if (memcmp(&magic, header_magic, sizeof(magic)))
01285 goto exit;
01286 reserved = block[i++];
01287 }
01288
01289 il = ntohl(block[i]); i++;
01290 dl = ntohl(block[i]); i++;
01291
01292
01293
01294 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01295
01296
01297
01298 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01299 goto exit;
01300
01301
01302 ei = xmalloc(len);
01303 ei[0] = htonl(il);
01304 ei[1] = htonl(dl);
01305 len -= sizeof(il) + sizeof(dl);
01306
01307
01308
01309
01310 if (timedRead(fd, (char *)&ei[2], len) != len)
01311 goto exit;
01312
01313
01314
01315 h = headerLoad(ei);
01316
01317 exit:
01318 if (h) {
01319 if (h->flags & HEADERFLAG_ALLOCATED)
01320 ei = _free(ei);
01321 h->flags |= HEADERFLAG_ALLOCATED;
01322 } else if (ei)
01323 ei = _free(ei);
01324
01325 return h;
01326
01327 }
01328
01336 static
01337 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01338
01339
01340 {
01341 ssize_t nb;
01342 int length;
01343 const void * uh;
01344
01345 if (h == NULL)
01346 return 1;
01347
01348 uh = doHeaderUnload(h, &length);
01349
01350 if (uh == NULL)
01351 return 1;
01352 switch (magicp) {
01353 case HEADER_MAGIC_YES:
01354
01355
01356 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01357
01358
01359 if (nb != sizeof(header_magic))
01360 goto exit;
01361 break;
01362 case HEADER_MAGIC_NO:
01363 break;
01364 }
01365
01366
01367 nb = Fwrite(uh, sizeof(char), length, fd);
01368
01369
01370 exit:
01371 uh = _free(uh);
01372 return (nb == length ? 0 : 1);
01373 }
01374
01381 static
01382 int headerIsEntry(Header h, int_32 tag)
01383
01384 {
01385
01386 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01387
01388 }
01389
01400 static int copyEntry(const indexEntry entry,
01401 hTYP_t type,
01402 hPTR_t * p,
01403 hCNT_t c,
01404 int minMem)
01405
01406
01407 {
01408 int_32 count = entry->info.count;
01409 int rc = 1;
01410
01411 if (p)
01412 switch (entry->info.type) {
01413 case RPM_BIN_TYPE:
01414
01415
01416
01417
01418
01419
01420 if (ENTRY_IS_REGION(entry)) {
01421 int_32 * ei = ((int_32 *)entry->data) - 2;
01422
01423 entryInfo pe = (entryInfo) (ei + 2);
01424
01425
01426 char * dataStart = (char *) (pe + ntohl(ei[0]));
01427
01428 int_32 rdl = -entry->info.offset;
01429 int_32 ril = rdl/sizeof(*pe);
01430
01431
01432 rdl = entry->rdlen;
01433 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01434 if (entry->info.tag == HEADER_IMAGE) {
01435 ril -= 1;
01436 pe += 1;
01437 } else {
01438 count += REGION_TAG_COUNT;
01439 rdl += REGION_TAG_COUNT;
01440 }
01441
01442
01443 *p = xmalloc(count);
01444 ei = (int_32 *) *p;
01445 ei[0] = htonl(ril);
01446 ei[1] = htonl(rdl);
01447
01448
01449 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01450
01451
01452 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01453
01454
01455
01456 rc = regionSwab(NULL, ril, 0, pe, dataStart, dataStart + rdl, 0);
01457
01458 rc = (rc < 0) ? 0 : 1;
01459 } else {
01460 count = entry->length;
01461 *p = (!minMem
01462 ? memcpy(xmalloc(count), entry->data, count)
01463 : entry->data);
01464 }
01465 break;
01466 case RPM_STRING_TYPE:
01467 if (count == 1) {
01468 *p = entry->data;
01469 break;
01470 }
01471
01472 case RPM_STRING_ARRAY_TYPE:
01473 case RPM_I18NSTRING_TYPE:
01474 { const char ** ptrEntry;
01475
01476 int tableSize = count * sizeof(char *);
01477
01478 char * t;
01479 int i;
01480
01481
01482
01483 if (minMem) {
01484 *p = xmalloc(tableSize);
01485 ptrEntry = (const char **) *p;
01486 t = entry->data;
01487 } else {
01488 t = xmalloc(tableSize + entry->length);
01489 *p = (void *)t;
01490 ptrEntry = (const char **) *p;
01491 t += tableSize;
01492 memcpy(t, entry->data, entry->length);
01493 }
01494
01495
01496 for (i = 0; i < count; i++) {
01497
01498 *ptrEntry++ = t;
01499
01500 t = strchr(t, 0);
01501 t++;
01502 }
01503 } break;
01504
01505 default:
01506 *p = entry->data;
01507 break;
01508 }
01509 if (type) *type = entry->info.type;
01510 if (c) *c = count;
01511 return rc;
01512 }
01513
01532 static int headerMatchLocale(const char *td, const char *l, const char *le)
01533
01534 {
01535 const char *fe;
01536
01537
01538 #if 0
01539 { const char *s, *ll, *CC, *EE, *dd;
01540 char *lbuf, *t.
01541
01542
01543 lbuf = alloca(le - l + 1);
01544 for (s = l, ll = t = lbuf; *s; s++, t++) {
01545 switch (*s) {
01546 case '_':
01547 *t = '\0';
01548 CC = t + 1;
01549 break;
01550 case '.':
01551 *t = '\0';
01552 EE = t + 1;
01553 break;
01554 case '@':
01555 *t = '\0';
01556 dd = t + 1;
01557 break;
01558 default:
01559 *t = *s;
01560 break;
01561 }
01562 }
01563
01564 if (ll)
01565 for (t = ll; *t; t++) *t = tolower(*t);
01566 if (CC)
01567 for (t = CC; *t; t++) *t = toupper(*t);
01568
01569
01570 }
01571 #endif
01572
01573
01574 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01575 return 1;
01576
01577
01578 for (fe = l; fe < le && *fe != '@'; fe++)
01579 {};
01580 if (fe < le && !strncmp(td, l, (fe - l)))
01581 return 1;
01582
01583
01584 for (fe = l; fe < le && *fe != '.'; fe++)
01585 {};
01586 if (fe < le && !strncmp(td, l, (fe - l)))
01587 return 1;
01588
01589
01590 for (fe = l; fe < le && *fe != '_'; fe++)
01591 {};
01592 if (fe < le && !strncmp(td, l, (fe - l)))
01593 return 2;
01594
01595 return 0;
01596 }
01597
01604 static char *
01605 headerFindI18NString(Header h, indexEntry entry)
01606
01607 {
01608 const char *lang, *l, *le;
01609 indexEntry table;
01610
01611
01612 if ((lang = getenv("LANGUAGE")) == NULL &&
01613 (lang = getenv("LC_ALL")) == NULL &&
01614 (lang = getenv("LC_MESSAGES")) == NULL &&
01615 (lang = getenv("LANG")) == NULL)
01616 return entry->data;
01617
01618
01619 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01620 return entry->data;
01621
01622
01623
01624 for (l = lang; *l != '\0'; l = le) {
01625 const char *td;
01626 char *ed, *ed_weak = NULL;
01627 int langNum;
01628
01629 while (*l && *l == ':')
01630 l++;
01631 if (*l == '\0')
01632 break;
01633 for (le = l; *le && *le != ':'; le++)
01634 {};
01635
01636
01637 for (langNum = 0, td = table->data, ed = entry->data;
01638 langNum < entry->info.count;
01639 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01640
01641 int match = headerMatchLocale(td, l, le);
01642 if (match == 1) return ed;
01643 else if (match == 2) ed_weak = ed;
01644
01645 }
01646 if (ed_weak) return ed_weak;
01647 }
01648
01649
01650 return entry->data;
01651 }
01652
01663 static int intGetEntry(Header h, int_32 tag,
01664 hTAG_t type,
01665 hPTR_t * p,
01666 hCNT_t c,
01667 int minMem)
01668
01669
01670 {
01671 indexEntry entry;
01672 int rc;
01673
01674
01675
01676 entry = findEntry(h, tag, RPM_NULL_TYPE);
01677
01678 if (entry == NULL) {
01679 if (type) type = 0;
01680 if (p) *p = NULL;
01681 if (c) *c = 0;
01682 return 0;
01683 }
01684
01685 switch (entry->info.type) {
01686 case RPM_I18NSTRING_TYPE:
01687 rc = 1;
01688 if (type) *type = RPM_STRING_TYPE;
01689 if (c) *c = 1;
01690
01691 if (p) *p = headerFindI18NString(h, entry);
01692
01693 break;
01694 default:
01695 rc = copyEntry(entry, type, p, c, minMem);
01696 break;
01697 }
01698
01699
01700 return ((rc == 1) ? 1 : 0);
01701 }
01702
01710 static void * headerFreeTag( Header h,
01711 const void * data, rpmTagType type)
01712
01713 {
01714 if (data) {
01715
01716 if (type == -1 ||
01717 type == RPM_STRING_ARRAY_TYPE ||
01718 type == RPM_I18NSTRING_TYPE ||
01719 type == RPM_BIN_TYPE)
01720 data = _free(data);
01721
01722 }
01723 return NULL;
01724 }
01725
01739 static
01740 int headerGetEntry(Header h, int_32 tag,
01741 hTYP_t type,
01742 void ** p,
01743 hCNT_t c)
01744
01745
01746 {
01747 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01748 }
01749
01762 static
01763 int headerGetEntryMinMemory(Header h, int_32 tag,
01764 hTYP_t type,
01765 hPTR_t * p,
01766 hCNT_t c)
01767
01768
01769 {
01770 return intGetEntry(h, tag, type, p, c, 1);
01771 }
01772
01773 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01774 int_32 * c)
01775 {
01776 indexEntry entry;
01777 int rc;
01778
01779 if (p == NULL) return headerIsEntry(h, tag);
01780
01781
01782
01783 entry = findEntry(h, tag, RPM_NULL_TYPE);
01784
01785 if (!entry) {
01786 if (p) *p = NULL;
01787 if (c) *c = 0;
01788 return 0;
01789 }
01790
01791 rc = copyEntry(entry, type, p, c, 0);
01792
01793
01794 return ((rc == 1) ? 1 : 0);
01795 }
01796
01799 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01800 int_32 cnt, int dataLength)
01801
01802 {
01803 switch (type) {
01804 case RPM_STRING_ARRAY_TYPE:
01805 case RPM_I18NSTRING_TYPE:
01806 { const char ** av = (const char **) srcPtr;
01807 char * t = dstPtr;
01808
01809
01810 while (cnt-- > 0 && dataLength > 0) {
01811 const char * s;
01812 if ((s = *av++) == NULL)
01813 continue;
01814 do {
01815 *t++ = *s++;
01816 } while (s[-1] && --dataLength > 0);
01817 }
01818
01819 } break;
01820
01821 default:
01822
01823 memmove(dstPtr, srcPtr, dataLength);
01824
01825 break;
01826 }
01827 }
01828
01837
01838 static void *
01839 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01840
01841
01842 {
01843 void * data = NULL;
01844 int length;
01845
01846 length = dataLength(type, p, c, 0, NULL);
01847
01848 if (length > 0) {
01849 data = xmalloc(length);
01850 copyData(type, data, p, c, length);
01851 }
01852
01853
01854 if (lengthPtr)
01855 *lengthPtr = length;
01856 return data;
01857 }
01858
01873 static
01874 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01875
01876 {
01877 indexEntry entry;
01878 void * data;
01879 int length;
01880
01881
01882 if (c <= 0)
01883 return 0;
01884
01885 if (hdrchkType(type))
01886 return 0;
01887 if (hdrchkData(c))
01888 return 0;
01889
01890 length = 0;
01891
01892 data = grabData(type, p, c, &length);
01893
01894 if (data == NULL || length <= 0)
01895 return 0;
01896
01897
01898 if (h->indexUsed == h->indexAlloced) {
01899 h->indexAlloced += INDEX_MALLOC_SIZE;
01900 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01901 }
01902
01903
01904 entry = h->index + h->indexUsed;
01905 entry->info.tag = tag;
01906 entry->info.type = type;
01907 entry->info.count = c;
01908 entry->info.offset = 0;
01909 entry->data = data;
01910 entry->length = length;
01911
01912
01913 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01914 h->flags &= ~HEADERFLAG_SORTED;
01915
01916 h->indexUsed++;
01917
01918 return 1;
01919 }
01920
01935 static
01936 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01937 const void * p, int_32 c)
01938
01939 {
01940 indexEntry entry;
01941 int length;
01942
01943 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01944
01945 return 0;
01946 }
01947
01948
01949 entry = findEntry(h, tag, type);
01950 if (!entry)
01951 return 0;
01952
01953 length = dataLength(type, p, c, 0, NULL);
01954 if (length < 0)
01955 return 0;
01956
01957 if (ENTRY_IN_REGION(entry)) {
01958 char * t = xmalloc(entry->length + length);
01959
01960 memcpy(t, entry->data, entry->length);
01961
01962 entry->data = t;
01963 entry->info.offset = 0;
01964 } else
01965 entry->data = xrealloc(entry->data, entry->length + length);
01966
01967 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01968
01969 entry->length += length;
01970
01971 entry->info.count += c;
01972
01973 return 1;
01974 }
01975
01986 static
01987 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01988 const void * p, int_32 c)
01989
01990 {
01991 return (findEntry(h, tag, type)
01992 ? headerAppendEntry(h, tag, type, p, c)
01993 : headerAddEntry(h, tag, type, p, c));
01994 }
01995
02016 static
02017 int headerAddI18NString(Header h, int_32 tag, const char * string,
02018 const char * lang)
02019
02020 {
02021 indexEntry table, entry;
02022 const char ** strArray;
02023 int length;
02024 int ghosts;
02025 int i, langNum;
02026 char * buf;
02027
02028 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02029 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02030
02031 if (!table && entry)
02032 return 0;
02033
02034 if (!table && !entry) {
02035 const char * charArray[2];
02036 int count = 0;
02037 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02038
02039 charArray[count++] = "C";
02040
02041 } else {
02042
02043 charArray[count++] = "C";
02044
02045 charArray[count++] = lang;
02046 }
02047 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02048 &charArray, count))
02049 return 0;
02050 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02051 }
02052
02053 if (!table)
02054 return 0;
02055
02056 if (!lang) lang = "C";
02057
02058
02059 { const char * l = table->data;
02060 for (langNum = 0; langNum < table->info.count; langNum++) {
02061 if (!strcmp(l, lang)) break;
02062 l += strlen(l) + 1;
02063 }
02064 }
02065
02066 if (langNum >= table->info.count) {
02067 length = strlen(lang) + 1;
02068 if (ENTRY_IN_REGION(table)) {
02069 char * t = xmalloc(table->length + length);
02070 memcpy(t, table->data, table->length);
02071 table->data = t;
02072 table->info.offset = 0;
02073 } else
02074 table->data = xrealloc(table->data, table->length + length);
02075 memmove(((char *)table->data) + table->length, lang, length);
02076 table->length += length;
02077 table->info.count++;
02078 }
02079
02080 if (!entry) {
02081 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02082 for (i = 0; i < langNum; i++)
02083 strArray[i] = "";
02084 strArray[langNum] = string;
02085 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02086 langNum + 1);
02087 } else if (langNum >= entry->info.count) {
02088 ghosts = langNum - entry->info.count;
02089
02090 length = strlen(string) + 1 + ghosts;
02091 if (ENTRY_IN_REGION(entry)) {
02092 char * t = xmalloc(entry->length + length);
02093 memcpy(t, entry->data, entry->length);
02094 entry->data = t;
02095 entry->info.offset = 0;
02096 } else
02097 entry->data = xrealloc(entry->data, entry->length + length);
02098
02099 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02100 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02101
02102 entry->length += length;
02103 entry->info.count = langNum + 1;
02104 } else {
02105 char *b, *be, *e, *ee, *t;
02106 size_t bn, sn, en;
02107
02108
02109 b = be = e = ee = entry->data;
02110 for (i = 0; i < table->info.count; i++) {
02111 if (i == langNum)
02112 be = ee;
02113 ee += strlen(ee) + 1;
02114 if (i == langNum)
02115 e = ee;
02116 }
02117
02118
02119 bn = (be-b);
02120 sn = strlen(string) + 1;
02121 en = (ee-e);
02122 length = bn + sn + en;
02123 t = buf = xmalloc(length);
02124
02125
02126 memcpy(t, b, bn);
02127 t += bn;
02128
02129 memcpy(t, string, sn);
02130 t += sn;
02131 memcpy(t, e, en);
02132 t += en;
02133
02134
02135
02136 entry->length -= strlen(be) + 1;
02137 entry->length += sn;
02138
02139 if (ENTRY_IN_REGION(entry)) {
02140 entry->info.offset = 0;
02141 } else
02142 entry->data = _free(entry->data);
02143
02144 entry->data = buf;
02145
02146 }
02147
02148 return 0;
02149 }
02150
02161 static
02162 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02163 const void * p, int_32 c)
02164
02165 {
02166 indexEntry entry;
02167 void * oldData;
02168 void * data;
02169 int length;
02170
02171
02172 entry = findEntry(h, tag, type);
02173 if (!entry)
02174 return 0;
02175
02176 length = 0;
02177 data = grabData(type, p, c, &length);
02178 if (data == NULL || length <= 0)
02179 return 0;
02180
02181
02182 while (entry > h->index && (entry - 1)->info.tag == tag)
02183 entry--;
02184
02185
02186
02187 oldData = entry->data;
02188
02189 entry->info.count = c;
02190 entry->info.type = type;
02191 entry->data = data;
02192 entry->length = length;
02193
02194
02195 if (ENTRY_IN_REGION(entry)) {
02196 entry->info.offset = 0;
02197 } else
02198 oldData = _free(oldData);
02199
02200
02201 return 1;
02202 }
02203
02206 static char escapedChar(const char ch)
02207 {
02208 switch (ch) {
02209 case 'a': return '\a';
02210 case 'b': return '\b';
02211 case 'f': return '\f';
02212 case 'n': return '\n';
02213 case 'r': return '\r';
02214 case 't': return '\t';
02215 case 'v': return '\v';
02216 default: return ch;
02217 }
02218 }
02219
02226 static sprintfToken
02227 freeFormat( sprintfToken format, int num)
02228
02229 {
02230 int i;
02231
02232 if (format == NULL) return NULL;
02233
02234 for (i = 0; i < num; i++) {
02235 switch (format[i].type) {
02236 case PTOK_ARRAY:
02237
02238 format[i].u.array.format =
02239 freeFormat(format[i].u.array.format,
02240 format[i].u.array.numTokens);
02241
02242 break;
02243 case PTOK_COND:
02244
02245 format[i].u.cond.ifFormat =
02246 freeFormat(format[i].u.cond.ifFormat,
02247 format[i].u.cond.numIfTokens);
02248 format[i].u.cond.elseFormat =
02249 freeFormat(format[i].u.cond.elseFormat,
02250 format[i].u.cond.numElseTokens);
02251
02252 break;
02253 case PTOK_NONE:
02254 case PTOK_TAG:
02255 case PTOK_STRING:
02256 default:
02257 break;
02258 }
02259 }
02260 format = _free(format);
02261 return NULL;
02262 }
02263
02267 struct headerIterator_s {
02268
02269 Header h;
02270
02271 int next_index;
02272 };
02273
02279 static
02280 HeaderIterator headerFreeIterator( HeaderIterator hi)
02281
02282 {
02283 if (hi != NULL) {
02284 hi->h = headerFree(hi->h);
02285 hi = _free(hi);
02286 }
02287 return hi;
02288 }
02289
02295 static
02296 HeaderIterator headerInitIterator(Header h)
02297
02298 {
02299 HeaderIterator hi = xmalloc(sizeof(*hi));
02300
02301 headerSort(h);
02302
02303 hi->h = headerLink(h);
02304 hi->next_index = 0;
02305 return hi;
02306 }
02307
02317 static
02318 int headerNextIterator(HeaderIterator hi,
02319 hTAG_t tag,
02320 hTYP_t type,
02321 hPTR_t * p,
02322 hCNT_t c)
02323
02324
02325
02326 {
02327 Header h = hi->h;
02328 int slot = hi->next_index;
02329 indexEntry entry = NULL;
02330 int rc;
02331
02332 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02333 entry = h->index + slot;
02334 if (!ENTRY_IS_REGION(entry))
02335 break;
02336 }
02337 hi->next_index = slot;
02338 if (entry == NULL || slot >= h->indexUsed)
02339 return 0;
02340
02341
02342 hi->next_index++;
02343
02344
02345 if (tag)
02346 *tag = entry->info.tag;
02347
02348 rc = copyEntry(entry, type, p, c, 0);
02349
02350
02351 return ((rc == 1) ? 1 : 0);
02352 }
02353
02359 static
02360 Header headerCopy(Header h)
02361
02362 {
02363 Header nh = headerNew();
02364 HeaderIterator hi;
02365 int_32 tag, type, count;
02366 hPTR_t ptr;
02367
02368
02369 for (hi = headerInitIterator(h);
02370 headerNextIterator(hi, &tag, &type, &ptr, &count);
02371 ptr = headerFreeData((void *)ptr, type))
02372 {
02373 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02374 }
02375 hi = headerFreeIterator(hi);
02376
02377
02378 return headerReload(nh, HEADER_IMAGE);
02379 }
02380
02383 typedef struct headerSprintfArgs_s {
02384 Header h;
02385 char * fmt;
02386
02387 headerTagTableEntry tags;
02388
02389 headerSprintfExtension exts;
02390
02391 const char * errmsg;
02392 rpmec ec;
02393 sprintfToken format;
02394
02395 HeaderIterator hi;
02396
02397 char * val;
02398 size_t vallen;
02399 size_t alloced;
02400 int numTokens;
02401 int i;
02402 } * headerSprintfArgs;
02403
02409 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02410
02411 {
02412 sprintfTag tag =
02413 (hsa->format->type == PTOK_TAG
02414 ? &hsa->format->u.tag :
02415 (hsa->format->type == PTOK_ARRAY
02416 ? &hsa->format->u.array.format->u.tag :
02417 NULL));
02418
02419 if (hsa != NULL) {
02420 hsa->i = 0;
02421 if (tag != NULL && tag->tag == -2)
02422 hsa->hi = headerInitIterator(hsa->h);
02423 }
02424
02425 return hsa;
02426
02427 }
02428
02434
02435 static sprintfToken hsaNext( headerSprintfArgs hsa)
02436
02437 {
02438 sprintfToken fmt = NULL;
02439 sprintfTag tag =
02440 (hsa->format->type == PTOK_TAG
02441 ? &hsa->format->u.tag :
02442 (hsa->format->type == PTOK_ARRAY
02443 ? &hsa->format->u.array.format->u.tag :
02444 NULL));
02445
02446 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02447 fmt = hsa->format + hsa->i;
02448 if (hsa->hi == NULL) {
02449 hsa->i++;
02450 } else {
02451 int_32 tagno;
02452 int_32 type;
02453 int_32 count;
02454
02455
02456 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02457 fmt = NULL;
02458 tag->tag = tagno;
02459
02460 }
02461 }
02462
02463
02464 return fmt;
02465
02466 }
02467
02473 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02474
02475 {
02476 if (hsa != NULL) {
02477 hsa->hi = headerFreeIterator(hsa->hi);
02478 hsa->i = 0;
02479 }
02480
02481 return hsa;
02482
02483 }
02484
02491
02492 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02493
02494 {
02495 if ((hsa->vallen + need) >= hsa->alloced) {
02496 if (hsa->alloced <= need)
02497 hsa->alloced += need;
02498 hsa->alloced <<= 1;
02499 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02500 }
02501 return hsa->val + hsa->vallen;
02502 }
02503
02511
02512 static const char * myTagName(headerTagTableEntry tbl, int val)
02513
02514 {
02515 static char name[128];
02516 const char * s;
02517 char *t;
02518
02519 for (; tbl->name != NULL; tbl++) {
02520 if (tbl->val == val)
02521 break;
02522 }
02523 if ((s = tbl->name) == NULL)
02524 return NULL;
02525 s += sizeof("RPMTAG_") - 1;
02526 t = name;
02527 *t++ = *s++;
02528 while (*s != '\0')
02529 *t++ = xtolower(*s++);
02530 *t = '\0';
02531 return name;
02532 }
02533
02541 static int myTagValue(headerTagTableEntry tbl, const char * name)
02542
02543 {
02544 for (; tbl->name != NULL; tbl++) {
02545 if (!xstrcasecmp(tbl->name, name))
02546 return tbl->val;
02547 }
02548 return 0;
02549 }
02550
02557 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02558
02559 {
02560 headerSprintfExtension ext;
02561 sprintfTag stag = (token->type == PTOK_COND
02562 ? &token->u.cond.tag : &token->u.tag);
02563
02564 stag->fmt = NULL;
02565 stag->ext = NULL;
02566 stag->extNum = 0;
02567 stag->tag = -1;
02568
02569 if (!strcmp(name, "*")) {
02570 stag->tag = -2;
02571 goto bingo;
02572 }
02573
02574
02575 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02576
02577 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02578 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02579 name = t;
02580
02581 }
02582
02583
02584
02585 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02586 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02587 {
02588 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02589 continue;
02590 if (!xstrcasecmp(ext->name, name)) {
02591 stag->ext = ext->u.tagFunction;
02592 stag->extNum = ext - hsa->exts;
02593 goto bingo;
02594 }
02595 }
02596
02597
02598 stag->tag = myTagValue(hsa->tags, name);
02599 if (stag->tag != 0)
02600 goto bingo;
02601
02602 return 1;
02603
02604 bingo:
02605
02606 if (stag->type != NULL)
02607 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02608 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02609 {
02610 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02611 continue;
02612 if (!strcmp(ext->name, stag->type)) {
02613 stag->fmt = ext->u.formatFunction;
02614 break;
02615 }
02616 }
02617 return 0;
02618 }
02619
02620
02628 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02629 char * str, char ** endPtr)
02630
02631 ;
02632
02642 static int parseFormat(headerSprintfArgs hsa, char * str,
02643 sprintfToken * formatPtr, int * numTokensPtr,
02644 char ** endPtr, int state)
02645
02646
02647
02648 {
02649 char * chptr, * start, * next, * dst;
02650 sprintfToken format;
02651 sprintfToken token;
02652 int numTokens;
02653 int i;
02654 int done = 0;
02655
02656
02657 numTokens = 0;
02658 if (str != NULL)
02659 for (chptr = str; *chptr != '\0'; chptr++)
02660 if (*chptr == '%') numTokens++;
02661 numTokens = numTokens * 2 + 1;
02662
02663 format = xcalloc(numTokens, sizeof(*format));
02664 if (endPtr) *endPtr = NULL;
02665
02666
02667 dst = start = str;
02668 numTokens = 0;
02669 token = NULL;
02670 if (start != NULL)
02671 while (*start != '\0') {
02672 switch (*start) {
02673 case '%':
02674
02675 if (*(start + 1) == '%') {
02676 if (token == NULL || token->type != PTOK_STRING) {
02677 token = format + numTokens++;
02678 token->type = PTOK_STRING;
02679
02680 dst = token->u.string.string = start;
02681
02682 }
02683 start++;
02684
02685 *dst++ = *start++;
02686
02687 break;
02688 }
02689
02690 token = format + numTokens++;
02691
02692 *dst++ = '\0';
02693
02694 start++;
02695
02696 if (*start == '|') {
02697 char * newEnd;
02698
02699 start++;
02700
02701 if (parseExpression(hsa, token, start, &newEnd))
02702 {
02703 format = freeFormat(format, numTokens);
02704 return 1;
02705 }
02706
02707 start = newEnd;
02708 break;
02709 }
02710
02711
02712 token->u.tag.format = start;
02713
02714 token->u.tag.pad = 0;
02715 token->u.tag.justOne = 0;
02716 token->u.tag.arrayCount = 0;
02717
02718 chptr = start;
02719 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02720 if (!*chptr || *chptr == '%') {
02721 hsa->errmsg = _("missing { after %");
02722 format = freeFormat(format, numTokens);
02723 return 1;
02724 }
02725
02726
02727 *chptr++ = '\0';
02728
02729
02730 while (start < chptr) {
02731 if (xisdigit(*start)) {
02732 i = strtoul(start, &start, 10);
02733 token->u.tag.pad += i;
02734 start = chptr;
02735 break;
02736 } else {
02737 start++;
02738 }
02739 }
02740
02741 if (*start == '=') {
02742 token->u.tag.justOne = 1;
02743 start++;
02744 } else if (*start == '#') {
02745 token->u.tag.justOne = 1;
02746 token->u.tag.arrayCount = 1;
02747 start++;
02748 }
02749
02750 dst = next = start;
02751 while (*next && *next != '}') next++;
02752 if (!*next) {
02753 hsa->errmsg = _("missing } after %{");
02754 format = freeFormat(format, numTokens);
02755 return 1;
02756 }
02757
02758 *next++ = '\0';
02759
02760
02761 chptr = start;
02762 while (*chptr && *chptr != ':') chptr++;
02763
02764 if (*chptr != '\0') {
02765
02766 *chptr++ = '\0';
02767
02768 if (!*chptr) {
02769 hsa->errmsg = _("empty tag format");
02770 format = freeFormat(format, numTokens);
02771 return 1;
02772 }
02773
02774 token->u.tag.type = chptr;
02775
02776 } else {
02777 token->u.tag.type = NULL;
02778 }
02779
02780 if (!*start) {
02781 hsa->errmsg = _("empty tag name");
02782 format = freeFormat(format, numTokens);
02783 return 1;
02784 }
02785
02786 i = 0;
02787 token->type = PTOK_TAG;
02788
02789 if (findTag(hsa, token, start)) {
02790 hsa->errmsg = _("unknown tag");
02791 format = freeFormat(format, numTokens);
02792 return 1;
02793 }
02794
02795 start = next;
02796 break;
02797
02798 case '[':
02799
02800 *dst++ = '\0';
02801 *start++ = '\0';
02802
02803 token = format + numTokens++;
02804
02805
02806 if (parseFormat(hsa, start,
02807 &token->u.array.format,
02808 &token->u.array.numTokens,
02809 &start, PARSER_IN_ARRAY))
02810 {
02811 format = freeFormat(format, numTokens);
02812 return 1;
02813 }
02814
02815
02816 if (!start) {
02817 hsa->errmsg = _("] expected at end of array");
02818 format = freeFormat(format, numTokens);
02819 return 1;
02820 }
02821
02822 dst = start;
02823
02824 token->type = PTOK_ARRAY;
02825
02826 break;
02827
02828 case ']':
02829 if (state != PARSER_IN_ARRAY) {
02830 hsa->errmsg = _("unexpected ]");
02831 format = freeFormat(format, numTokens);
02832 return 1;
02833 }
02834
02835 *start++ = '\0';
02836
02837 if (endPtr) *endPtr = start;
02838 done = 1;
02839 break;
02840
02841 case '}':
02842 if (state != PARSER_IN_EXPR) {
02843 hsa->errmsg = _("unexpected }");
02844 format = freeFormat(format, numTokens);
02845 return 1;
02846 }
02847
02848 *start++ = '\0';
02849
02850 if (endPtr) *endPtr = start;
02851 done = 1;
02852 break;
02853
02854 default:
02855 if (token == NULL || token->type != PTOK_STRING) {
02856 token = format + numTokens++;
02857 token->type = PTOK_STRING;
02858
02859 dst = token->u.string.string = start;
02860
02861 }
02862
02863
02864 if (*start == '\\') {
02865 start++;
02866 *dst++ = escapedChar(*start++);
02867 } else {
02868 *dst++ = *start++;
02869 }
02870
02871 break;
02872 }
02873 if (done)
02874 break;
02875 }
02876
02877
02878
02879 if (dst != NULL)
02880 *dst = '\0';
02881
02882
02883 for (i = 0; i < numTokens; i++) {
02884 token = format + i;
02885 if (token->type == PTOK_STRING)
02886 token->u.string.len = strlen(token->u.string.string);
02887 }
02888
02889 *numTokensPtr = numTokens;
02890 *formatPtr = format;
02891
02892 return 0;
02893 }
02894
02895
02896 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02897 char * str, char ** endPtr)
02898 {
02899 char * chptr;
02900 char * end;
02901
02902 hsa->errmsg = NULL;
02903 chptr = str;
02904 while (*chptr && *chptr != '?') chptr++;
02905
02906 if (*chptr != '?') {
02907 hsa->errmsg = _("? expected in expression");
02908 return 1;
02909 }
02910
02911 *chptr++ = '\0';;
02912
02913 if (*chptr != '{') {
02914 hsa->errmsg = _("{ expected after ? in expression");
02915 return 1;
02916 }
02917
02918 chptr++;
02919
02920 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
02921 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
02922 return 1;
02923
02924
02925 if (!(end && *end)) {
02926 hsa->errmsg = _("} expected in expression");
02927 token->u.cond.ifFormat =
02928 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02929 return 1;
02930 }
02931
02932 chptr = end;
02933 if (*chptr != ':' && *chptr != '|') {
02934 hsa->errmsg = _(": expected following ? subexpression");
02935 token->u.cond.ifFormat =
02936 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02937 return 1;
02938 }
02939
02940 if (*chptr == '|') {
02941 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
02942 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02943 {
02944 token->u.cond.ifFormat =
02945 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02946 return 1;
02947 }
02948 } else {
02949 chptr++;
02950
02951 if (*chptr != '{') {
02952 hsa->errmsg = _("{ expected after : in expression");
02953 token->u.cond.ifFormat =
02954 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02955 return 1;
02956 }
02957
02958 chptr++;
02959
02960 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
02961 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02962 return 1;
02963
02964
02965 if (!(end && *end)) {
02966 hsa->errmsg = _("} expected in expression");
02967 token->u.cond.ifFormat =
02968 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02969 return 1;
02970 }
02971
02972 chptr = end;
02973 if (*chptr != '|') {
02974 hsa->errmsg = _("| expected at end of expression");
02975 token->u.cond.ifFormat =
02976 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02977 token->u.cond.elseFormat =
02978 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02979 return 1;
02980 }
02981 }
02982
02983 chptr++;
02984
02985 *endPtr = chptr;
02986
02987 token->type = PTOK_COND;
02988
02989 (void) findTag(hsa, token, str);
02990
02991 return 0;
02992 }
02993
02994
03005 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03006 hTYP_t typeptr,
03007 hPTR_t * data,
03008 hCNT_t countptr,
03009 rpmec ec)
03010
03011
03012
03013 {
03014 if (!ec->avail) {
03015 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03016 return 1;
03017 ec->avail = 1;
03018 }
03019
03020 if (typeptr) *typeptr = ec->type;
03021 if (data) *data = ec->data;
03022 if (countptr) *countptr = ec->count;
03023
03024 return 0;
03025 }
03026
03033
03034 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03035
03036 {
03037 char * val = NULL;
03038 size_t need = 0;
03039 char * t, * te;
03040 char buf[20];
03041 int_32 count, type;
03042 hPTR_t data;
03043 unsigned int intVal;
03044 const char ** strarray;
03045 int datafree = 0;
03046 int countBuf;
03047
03048 memset(buf, 0, sizeof(buf));
03049 if (tag->ext) {
03050
03051 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03052 {
03053 count = 1;
03054 type = RPM_STRING_TYPE;
03055 data = "(none)";
03056 }
03057
03058 } else {
03059
03060 if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03061 count = 1;
03062 type = RPM_STRING_TYPE;
03063 data = "(none)";
03064 }
03065
03066
03067
03068 switch (type) {
03069 default:
03070 if (element >= count) {
03071
03072 data = headerFreeData(data, type);
03073
03074
03075 hsa->errmsg = _("(index out of range)");
03076 return NULL;
03077 }
03078 break;
03079 case RPM_BIN_TYPE:
03080 case RPM_STRING_TYPE:
03081 break;
03082 }
03083 datafree = 1;
03084 }
03085
03086 if (tag->arrayCount) {
03087
03088 if (datafree)
03089 data = headerFreeData(data, type);
03090
03091
03092 countBuf = count;
03093 data = &countBuf;
03094 count = 1;
03095 type = RPM_INT32_TYPE;
03096 }
03097
03098
03099 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03100
03101
03102
03103 if (data)
03104 switch (type) {
03105 case RPM_STRING_ARRAY_TYPE:
03106 strarray = (const char **)data;
03107
03108 if (tag->fmt)
03109 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03110
03111 if (val) {
03112 need = strlen(val);
03113 } else {
03114 need = strlen(strarray[element]) + tag->pad + 20;
03115 val = xmalloc(need+1);
03116 strcat(buf, "s");
03117
03118 sprintf(val, buf, strarray[element]);
03119
03120 }
03121
03122 break;
03123
03124 case RPM_STRING_TYPE:
03125 if (tag->fmt)
03126 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, 0);
03127
03128 if (val) {
03129 need = strlen(val);
03130 } else {
03131 need = strlen(data) + tag->pad + 20;
03132 val = xmalloc(need+1);
03133 strcat(buf, "s");
03134
03135 sprintf(val, buf, data);
03136
03137 }
03138 break;
03139
03140 case RPM_CHAR_TYPE:
03141 case RPM_INT8_TYPE:
03142 case RPM_INT16_TYPE:
03143 case RPM_INT32_TYPE:
03144 switch (type) {
03145 case RPM_CHAR_TYPE:
03146 case RPM_INT8_TYPE:
03147 intVal = *(((int_8 *) data) + element);
03148 break;
03149 case RPM_INT16_TYPE:
03150 intVal = *(((uint_16 *) data) + element);
03151 break;
03152 default:
03153 case RPM_INT32_TYPE:
03154 intVal = *(((int_32 *) data) + element);
03155 break;
03156 }
03157
03158 if (tag->fmt)
03159 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03160
03161 if (val) {
03162 need = strlen(val);
03163 } else {
03164 need = 10 + tag->pad + 20;
03165 val = xmalloc(need+1);
03166 strcat(buf, "d");
03167
03168 sprintf(val, buf, intVal);
03169
03170 }
03171 break;
03172
03173 case RPM_BIN_TYPE:
03174
03175 if (tag->fmt)
03176 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03177
03178 if (val) {
03179 need = strlen(val);
03180 } else {
03181 val = bin2hex(data, count);
03182 need = strlen(val) + tag->pad;
03183 }
03184 break;
03185
03186 default:
03187 need = sizeof("(unknown type)") - 1;
03188 val = xstrdup("(unknown type)");
03189 break;
03190 }
03191
03192
03193
03194 if (datafree)
03195 data = headerFreeData(data, type);
03196
03197
03198
03199 if (val && need > 0) {
03200 t = hsaReserve(hsa, need);
03201
03202 te = stpcpy(t, val);
03203
03204 hsa->vallen += (te - t);
03205 val = _free(val);
03206 }
03207
03208
03209 return (hsa->val + hsa->vallen);
03210 }
03211
03218
03219 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03220 int element)
03221
03222 {
03223 char * t, * te;
03224 int i, j;
03225 int numElements;
03226 int_32 type;
03227 int_32 count;
03228 sprintfToken spft;
03229 int condNumFormats;
03230 size_t need;
03231
03232
03233
03234 switch (token->type) {
03235 case PTOK_NONE:
03236 break;
03237
03238 case PTOK_STRING:
03239 need = token->u.string.len;
03240 if (need == 0) break;
03241 t = hsaReserve(hsa, need);
03242
03243 te = stpcpy(t, token->u.string.string);
03244
03245 hsa->vallen += (te - t);
03246 break;
03247
03248 case PTOK_TAG:
03249 t = hsa->val + hsa->vallen;
03250 te = formatValue(hsa, &token->u.tag,
03251 (token->u.tag.justOne ? 0 : element));
03252 if (te == NULL)
03253 return NULL;
03254 break;
03255
03256 case PTOK_COND:
03257 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03258 spft = token->u.cond.ifFormat;
03259 condNumFormats = token->u.cond.numIfTokens;
03260 } else {
03261 spft = token->u.cond.elseFormat;
03262 condNumFormats = token->u.cond.numElseTokens;
03263 }
03264
03265 need = condNumFormats * 20;
03266 if (spft == NULL || need == 0) break;
03267
03268 t = hsaReserve(hsa, need);
03269 for (i = 0; i < condNumFormats; i++, spft++) {
03270 te = singleSprintf(hsa, spft, element);
03271 if (te == NULL)
03272 return NULL;
03273 }
03274 break;
03275
03276 case PTOK_ARRAY:
03277 numElements = -1;
03278 spft = token->u.array.format;
03279 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03280 {
03281 if (spft->type != PTOK_TAG ||
03282 spft->u.tag.arrayCount ||
03283 spft->u.tag.justOne) continue;
03284
03285 if (spft->u.tag.ext) {
03286
03287 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03288 hsa->ec + spft->u.tag.extNum))
03289 continue;
03290
03291 } else {
03292
03293 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03294 continue;
03295
03296 }
03297
03298 if (type == RPM_BIN_TYPE)
03299 count = 1;
03300
03301 if (numElements > 1 && count != numElements)
03302 switch (type) {
03303 default:
03304 hsa->errmsg =
03305 _("array iterator used with different sized arrays");
03306 return NULL;
03307 break;
03308 case RPM_BIN_TYPE:
03309 case RPM_STRING_TYPE:
03310 break;
03311 }
03312 if (count > numElements)
03313 numElements = count;
03314 }
03315
03316 if (numElements == -1) {
03317 need = sizeof("(none)") - 1;
03318 t = hsaReserve(hsa, need);
03319
03320 te = stpcpy(t, "(none)");
03321
03322 hsa->vallen += (te - t);
03323 } else {
03324 int isxml;
03325
03326 need = numElements * token->u.array.numTokens * 10;
03327 if (need == 0) break;
03328
03329 spft = token->u.array.format;
03330 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03331 !strcmp(spft->u.tag.type, "xml"));
03332
03333 if (isxml) {
03334 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag);
03335
03336 need = sizeof(" <rpmTag name=\"\">\n") - 1;
03337 if (tagN != NULL)
03338 need += strlen(tagN);
03339 t = hsaReserve(hsa, need);
03340
03341 te = stpcpy(t, " <rpmTag name=\"");
03342 if (tagN != NULL)
03343 te = stpcpy(te, tagN);
03344 te = stpcpy(te, "\">\n");
03345
03346 hsa->vallen += (te - t);
03347 }
03348
03349 t = hsaReserve(hsa, need);
03350 for (j = 0; j < numElements; j++) {
03351 spft = token->u.array.format;
03352 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03353 te = singleSprintf(hsa, spft, j);
03354 if (te == NULL)
03355 return NULL;
03356 }
03357 }
03358
03359 if (isxml) {
03360 need = sizeof(" </rpmTag>\n") - 1;
03361 t = hsaReserve(hsa, need);
03362
03363 te = stpcpy(t, " </rpmTag>\n");
03364
03365 hsa->vallen += (te - t);
03366 }
03367
03368 }
03369 break;
03370 }
03371
03372 return (hsa->val + hsa->vallen);
03373 }
03374
03380 static rpmec
03381 rpmecNew(const headerSprintfExtension exts)
03382
03383 {
03384 headerSprintfExtension ext;
03385 rpmec ec;
03386 int i = 0;
03387
03388 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03389 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03390 {
03391 i++;
03392 }
03393
03394 ec = xcalloc(i, sizeof(*ec));
03395 return ec;
03396 }
03397
03404 static rpmec
03405 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03406
03407 {
03408 headerSprintfExtension ext;
03409 int i = 0;
03410
03411 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03412 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03413 {
03414
03415 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03416
03417 i++;
03418 }
03419
03420 ec = _free(ec);
03421 return NULL;
03422 }
03423
03435 static
03436 char * headerSprintf(Header h, const char * fmt,
03437 const struct headerTagTableEntry_s * tbltags,
03438 const struct headerSprintfExtension_s * extensions,
03439 errmsg_t * errmsg)
03440
03441
03442 {
03443 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03444 sprintfToken nextfmt;
03445 sprintfTag tag;
03446 char * t, * te;
03447 int isxml;
03448 int need;
03449
03450 hsa->h = headerLink(h);
03451 hsa->fmt = xstrdup(fmt);
03452
03453 hsa->exts = (headerSprintfExtension) extensions;
03454 hsa->tags = (headerTagTableEntry) tbltags;
03455
03456 hsa->errmsg = NULL;
03457
03458
03459 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03460 goto exit;
03461
03462
03463 hsa->ec = rpmecNew(hsa->exts);
03464 hsa->val = xstrdup("");
03465
03466 tag =
03467 (hsa->format->type == PTOK_TAG
03468 ? &hsa->format->u.tag :
03469 (hsa->format->type == PTOK_ARRAY
03470 ? &hsa->format->u.array.format->u.tag :
03471 NULL));
03472 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03473
03474 if (isxml) {
03475 need = sizeof("<rpmHeader>\n") - 1;
03476 t = hsaReserve(hsa, need);
03477
03478 te = stpcpy(t, "<rpmHeader>\n");
03479
03480 hsa->vallen += (te - t);
03481 }
03482
03483 hsa = hsaInit(hsa);
03484 while ((nextfmt = hsaNext(hsa)) != NULL) {
03485 te = singleSprintf(hsa, nextfmt, 0);
03486 if (te == NULL) {
03487 hsa->val = _free(hsa->val);
03488 break;
03489 }
03490 }
03491 hsa = hsaFini(hsa);
03492
03493 if (isxml) {
03494 need = sizeof("</rpmHeader>\n") - 1;
03495 t = hsaReserve(hsa, need);
03496
03497 te = stpcpy(t, "</rpmHeader>\n");
03498
03499 hsa->vallen += (te - t);
03500 }
03501
03502 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03503 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03504
03505 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03506 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03507
03508 exit:
03509
03510 if (errmsg)
03511 *errmsg = hsa->errmsg;
03512
03513 hsa->h = headerFree(hsa->h);
03514 hsa->fmt = _free(hsa->fmt);
03515 return hsa->val;
03516 }
03517
03526 static char * octalFormat(int_32 type, hPTR_t data,
03527 char * formatPrefix, int padding, int element)
03528
03529 {
03530 char * val;
03531
03532 if (type != RPM_INT32_TYPE) {
03533 val = xstrdup(_("(not a number)"));
03534 } else {
03535 val = xmalloc(20 + padding);
03536
03537 strcat(formatPrefix, "o");
03538
03539
03540 sprintf(val, formatPrefix, *((int_32 *) data));
03541
03542 }
03543
03544 return val;
03545 }
03546
03555 static char * hexFormat(int_32 type, hPTR_t data,
03556 char * formatPrefix, int padding, int element)
03557
03558 {
03559 char * val;
03560
03561 if (type != RPM_INT32_TYPE) {
03562 val = xstrdup(_("(not a number)"));
03563 } else {
03564 val = xmalloc(20 + padding);
03565
03566 strcat(formatPrefix, "x");
03567
03568
03569 sprintf(val, formatPrefix, *((int_32 *) data));
03570
03571 }
03572
03573 return val;
03574 }
03575
03578 static char * realDateFormat(int_32 type, hPTR_t data,
03579 char * formatPrefix, int padding, int element,
03580 const char * strftimeFormat)
03581
03582 {
03583 char * val;
03584
03585 if (type != RPM_INT32_TYPE) {
03586 val = xstrdup(_("(not a number)"));
03587 } else {
03588 struct tm * tstruct;
03589 char buf[50];
03590
03591 val = xmalloc(50 + padding);
03592
03593 strcat(formatPrefix, "s");
03594
03595
03596
03597 { time_t dateint = *((int_32 *) data);
03598 tstruct = localtime(&dateint);
03599 }
03600 buf[0] = '\0';
03601 if (tstruct)
03602 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03603
03604 sprintf(val, formatPrefix, buf);
03605
03606 }
03607
03608 return val;
03609 }
03610
03619 static char * dateFormat(int_32 type, hPTR_t data,
03620 char * formatPrefix, int padding, int element)
03621
03622 {
03623 return realDateFormat(type, data, formatPrefix, padding, element,
03624 _("%c"));
03625 }
03626
03635 static char * dayFormat(int_32 type, hPTR_t data,
03636 char * formatPrefix, int padding, int element)
03637
03638 {
03639 return realDateFormat(type, data, formatPrefix, padding, element,
03640 _("%a %b %d %Y"));
03641 }
03642
03651 static char * shescapeFormat(int_32 type, hPTR_t data,
03652 char * formatPrefix, int padding, int element)
03653
03654 {
03655 char * result, * dst, * src, * buf;
03656
03657 if (type == RPM_INT32_TYPE) {
03658 result = xmalloc(padding + 20);
03659
03660 strcat(formatPrefix, "d");
03661
03662
03663 sprintf(result, formatPrefix, *((int_32 *) data));
03664
03665 } else {
03666 buf = alloca(strlen(data) + padding + 2);
03667
03668 strcat(formatPrefix, "s");
03669
03670
03671 sprintf(buf, formatPrefix, data);
03672
03673
03674
03675 result = dst = xmalloc(strlen(buf) * 4 + 3);
03676 *dst++ = '\'';
03677 for (src = buf; *src != '\0'; src++) {
03678 if (*src == '\'') {
03679 *dst++ = '\'';
03680 *dst++ = '\\';
03681 *dst++ = '\'';
03682 *dst++ = '\'';
03683 } else {
03684 *dst++ = *src;
03685 }
03686 }
03687 *dst++ = '\'';
03688 *dst = '\0';
03689
03690
03691 }
03692
03693 return result;
03694 }
03695
03696
03697 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03698 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03699 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03700 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03701 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03702 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03703 { HEADER_EXT_LAST, NULL, { NULL } }
03704 };
03705
03706
03713 static
03714 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03715
03716 {
03717 int * p;
03718
03719 if (headerFrom == headerTo)
03720 return;
03721
03722 for (p = tagstocopy; *p != 0; p++) {
03723 char *s;
03724 int_32 type;
03725 int_32 count;
03726 if (headerIsEntry(headerTo, *p))
03727 continue;
03728
03729 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03730 (hPTR_t *) &s, &count))
03731 continue;
03732
03733 (void) headerAddEntry(headerTo, *p, type, s, count);
03734 s = headerFreeData(s, type);
03735 }
03736 }
03737
03738
03739 static struct HV_s hdrVec1 = {
03740 headerLink,
03741 headerUnlink,
03742 headerFree,
03743 headerNew,
03744 headerSort,
03745 headerUnsort,
03746 headerSizeof,
03747 headerUnload,
03748 headerReload,
03749 headerCopy,
03750 headerLoad,
03751 headerCopyLoad,
03752 headerRead,
03753 headerWrite,
03754 headerIsEntry,
03755 headerFreeTag,
03756 headerGetEntry,
03757 headerGetEntryMinMemory,
03758 headerAddEntry,
03759 headerAppendEntry,
03760 headerAddOrAppendEntry,
03761 headerAddI18NString,
03762 headerModifyEntry,
03763 headerRemoveEntry,
03764 headerSprintf,
03765 headerCopyTags,
03766 headerFreeIterator,
03767 headerInitIterator,
03768 headerNextIterator,
03769 NULL, NULL,
03770 1
03771 };
03772
03773
03774
03775 HV_t hdrVec = &hdrVec1;
03776