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