rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

header.c
Go to the documentation of this file.
1
5 /* RPM - Copyright (C) 1995-2002 Red Hat Software */
6
7 /* Data written to file descriptors is in network byte order. */
8 /* Data read from file descriptors is expected to be in */
9 /* network byte order and is converted on the fly to host order. */
10
11 #include "system.h"
12
13 #include <rpmiotypes.h>
14 #include <rpmio.h> /* XXX for rpmioPool et al */
15 #define _RPMTAG_INTERNAL
16 #include <header_internal.h>
17
18 #include "debug.h"
19
20 /*@unchecked@*/
21 int _hdr_debug = 0;
22
23 /*@access Header @*/
24 /*@access HeaderIterator @*/
25 /*@access headerSprintfExtension @*/
26 /*@access headerTagTableEntry @*/
27
28 /*@access entryInfo @*/
29 /*@access indexEntry @*/
30
33 /*@-type@*/
34 /*@observer@*/ /*@unchecked@*/
35 static unsigned char header_magic[8] = {
36 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
37 };
38 /*@=type@*/
39
43 /*@observer@*/ /*@unchecked@*/
44 static int typeSizes[16] = {
45 0,
46 1,
47 1,
48 2,
49 4,
50 8,
51 -1,
52 1,
53 -1,
54 -1,
55 0,
56 0,
57 0,
58 0,
59 0,
60 0
61 };
62
66 /*@unchecked@*/
67 static size_t headerMaxbytes = (1024*1024*1024);
68
72 /*@unchecked@*/
73 int _hdr_stats = 0;
74
75 /*@-compmempass@*/
76 /*@unchecked@*/
77 static struct rpmop_s hdr_loadops;
78 /*@unchecked@*/ /*@relnull@*/
79 rpmop _hdr_loadops = &hdr_loadops;
80 /*@unchecked@*/
81 static struct rpmop_s hdr_getops;
82 /*@unchecked@*/ /*@relnull@*/
83 rpmop _hdr_getops = &hdr_getops;
84 /*@=compmempass@*/
85
86 void * headerGetStats(Header h, int opx)
87 {
88 rpmop op = NULL;
89 if (_hdr_stats)
90 switch (opx) {
91 case 18: op = &h->h_loadops; break; /* RPMTS_OP_HDRLOAD */
92 case 19: op = &h->h_getops; break; /* RPMTS_OP_HDRGET */
93 }
94 return op;
95 }
96
97 /*@-mustmod@*/
98 static void headerScrub(void * _h) /* XXX headerFini already in use */
99 /*@modifies *_h @*/
100 {
101 Header h = _h;
102
103 if (h->index != NULL) {
104 int mask = (HEADERFLAG_ALLOCATED | HEADERFLAG_MAPPED);
105 indexEntry entry = h->index;
106 size_t i;
107 for (i = 0; i < h->indexUsed; i++, entry++) {
108 if ((h->flags & mask) && ENTRY_IS_REGION(entry)) {
109 if (entry->length > 0) {
110 rpmuint32_t * ei = entry->data;
111 if ((ei - 2) == h->blob) {
112 if (h->flags & HEADERFLAG_MAPPED) {
113 if (munmap(h->blob, h->bloblen) != 0)
114 fprintf(stderr,
115 "==> munmap(%p[%u]) error(%d): %s\n",
116 h->blob, h->bloblen,
117 errno, strerror(errno));
118 h->blob = NULL;
119 } else
120 h->blob = _free(h->blob);
121 h->bloblen = 0;
122 }
123 entry->data = NULL;
124 }
125 } else if (!ENTRY_IN_REGION(entry)) {
126 entry->data = _free(entry->data);
127 }
128 entry->data = NULL;
129 entry->length = 0;
130 }
131 h->index = _free(h->index);
132 }
133 h->origin = _free(h->origin);
134 h->baseurl = _free(h->baseurl);
135 h->digest = _free(h->digest);
136
137 /*@-nullstate@*/
138 if (_hdr_stats) {
139 if (_hdr_loadops) /* RPMTS_OP_HDRLOAD */
140 (void) rpmswAdd(_hdr_loadops, headerGetStats(h, 18));
141 if (_hdr_getops) /* RPMTS_OP_HDRGET */
142 (void) rpmswAdd(_hdr_getops, headerGetStats(h, 19));
143 }
144 /*@=nullstate@*/
145 }
146 /*@=mustmod@*/
147
148 /*@unchecked@*/ /*@only@*/ /*@null@*/
149 rpmioPool _headerPool;
150
151 static Header headerGetPool(/*@null@*/ rpmioPool pool)
152 /*@globals _headerPool, fileSystem @*/
153 /*@modifies pool, _headerPool, fileSystem @*/
154 {
155 Header h;
156
157 if (_headerPool == NULL) {
158 _headerPool = rpmioNewPool("h", sizeof(*h), -1, _hdr_debug,
159 NULL, NULL, headerScrub);
160 pool = _headerPool;
161 }
162 return (Header) rpmioGetPool(pool, sizeof(*h));
163 }
164
165 Header headerNew(void)
166 {
167 Header h = headerGetPool(_headerPool);
168
169 (void) memcpy(h->magic, header_magic, sizeof(h->magic));
170 h->blob = NULL;
171 h->bloblen = 0;
172 h->origin = NULL;
173 h->baseurl = NULL;
174 h->digest = NULL;
175 h->rpmdb = NULL;
176 memset(&h->sb, 0, sizeof(h->sb));
177 h->instance = 0;
178 h->startoff = 0;
179 h->endoff = 0;
180 memset(&h->h_loadops, 0, sizeof(h->h_loadops));
181 memset(&h->h_getops, 0, sizeof(h->h_getops));
182 h->indexAlloced = INDEX_MALLOC_SIZE;
183 h->indexUsed = 0;
184 h->flags = HEADERFLAG_SORTED;
185
186 h->index = (h->indexAlloced
187 ? xcalloc(h->indexAlloced, sizeof(*h->index))
188 : NULL);
189
190 /*@-globstate -nullret -observertrans @*/
191 return headerLink(h);
192 /*@=globstate =nullret =observertrans @*/
193 }
194
197 static int indexCmp(const void * avp, const void * bvp)
198 /*@*/
199 {
200 /*@-castexpose@*/
201 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
202 /*@=castexpose@*/
203 return ((int)ap->info.tag - (int)bp->info.tag);
204 }
205
210 static
211 void headerSort(Header h)
212 /*@modifies h @*/
213 {
214 if (!(h->flags & HEADERFLAG_SORTED)) {
215 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
216 h->flags |= HEADERFLAG_SORTED;
217 }
218 }
219
222 static int offsetCmp(const void * avp, const void * bvp) /*@*/
223 {
224 /*@-castexpose@*/
225 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
226 /*@=castexpose@*/
227 int rc = ((int)ap->info.offset - (int)bp->info.offset);
228
229 if (rc == 0) {
230 /* Within a region, entries sort by address. Added drips sort by tag. */
231 if (ap->info.offset < 0)
232 rc = (((char *)ap->data) - ((char *)bp->data));
233 else
234 rc = ((int)ap->info.tag - (int)bp->info.tag);
235 }
236 return rc;
237 }
238
243 static
244 void headerUnsort(Header h)
245 /*@modifies h @*/
246 {
247 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
248 }
249
250 size_t headerSizeof(Header h)
251 {
252 indexEntry entry;
253 size_t size = 0;
254 size_t pad = 0;
255 size_t i;
256
257 if (h == NULL)
258 return size;
259
260 headerSort(h);
261
262 size += sizeof(header_magic); /* XXX HEADER_MAGIC_YES */
263
264 /*@-sizeoftype@*/
265 size += 2 * sizeof(rpmuint32_t); /* count of index entries */
266 /*@=sizeoftype@*/
267
268 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
269 size_t diff;
270 rpmTagType type;
271
272 /* Regions go in as is ... */
273 if (ENTRY_IS_REGION(entry)) {
274 size += entry->length;
275 /* XXX Legacy regions do not include the region tag and data. */
276 /*@-sizeoftype@*/
277 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
278 size += sizeof(struct entryInfo_s) + entry->info.count;
279 /*@=sizeoftype@*/
280 continue;
281 }
282
283 /* ... and region elements are skipped. */
284 if (entry->info.offset < 0)
285 continue;
286
287 /* Alignment */
288 type = entry->info.type;
289 if (typeSizes[type] > 1) {
290 diff = typeSizes[type] - (size % typeSizes[type]);
291 if ((int)diff != typeSizes[type]) {
292 size += diff;
293 pad += diff;
294 }
295 }
296
297 /*@-sizeoftype@*/
298 size += sizeof(struct entryInfo_s) + entry->length;
299 /*@=sizeoftype@*/
300 }
301
302 return size;
303 }
304
314 static size_t dataLength(rpmTagType type, rpmTagData * p, rpmTagCount count,
315 int onDisk, /*@null@*/ rpmTagData * pend)
316 /*@*/
317 {
318 const unsigned char * s = (unsigned char *) (*p).ui8p;
319 const unsigned char * se = (unsigned char *) (pend ? (*pend).ui8p : NULL);
320 size_t length = 0;
321
322 switch (type) {
323 case RPM_STRING_TYPE:
324 if (count != 1)
325 return 0;
326 while (*s++ != '\0') {
327 if (se && s > se)
328 return 0;
329 length++;
330 }
331 length++; /* count nul terminator too. */
332 break;
333 /* These are like RPM_STRING_TYPE, except they're *always* an array */
334 /* Compute sum of length of all strings, including nul terminators */
335 case RPM_I18NSTRING_TYPE:
336 case RPM_STRING_ARRAY_TYPE:
337 if (onDisk) {
338 while (count--) {
339 length++; /* count nul terminator too */
340 while (*s++ != '\0') {
341 if (se && s > se)
342 return 0;
343 length++;
344 }
345 }
346 } else {
347 const char ** av = (*p).argv;
348 while (count--) {
349 /* add one for null termination */
350 length += strlen(*av++) + 1;
351 }
352 }
353 break;
354 default:
355 if (typeSizes[type] == -1)
356 return 0;
357 length = typeSizes[(type & 0xf)] * count;
358 if ((se && (s + length) > se))
359 return 0;
360 break;
361 }
362
363 return length;
364 }
365
370 static unsigned char * tagSwab(/*@out@*/ /*@returned@*/ unsigned char * t,
371 const HE_t he, size_t nb)
372 /*@modifies *t @*/
373 {
374 rpmuint32_t i;
375
376 switch (he->t) {
377 case RPM_UINT64_TYPE:
378 { rpmuint32_t * tt = (rpmuint32_t *)t;
379 assert(nb == (he->c * sizeof(*tt)));
380 for (i = 0; i < he->c; i++) {
381 rpmuint32_t j = 2 * i;
382 rpmuint32_t b = (rpmuint32_t) htonl(he->p.ui32p[j]);
383 tt[j ] = (rpmuint32_t) htonl(he->p.ui32p[j+1]);
384 tt[j+1] = b;
385 }
386 } break;
387 case RPM_UINT32_TYPE:
388 { rpmuint32_t * tt = (rpmuint32_t *)t;
389 assert(nb == (he->c * sizeof(*tt)));
390 for (i = 0; i < he->c; i++)
391 tt[i] = (rpmuint32_t) htonl(he->p.ui32p[i]);
392 } break;
393 case RPM_UINT16_TYPE:
394 { rpmuint16_t * tt = (rpmuint16_t *)t;
395 assert(nb == (he->c * sizeof(*tt)));
396 for (i = 0; i < he->c; i++)
397 tt[i] = (rpmuint16_t) htons(he->p.ui16p[i]);
398 } break;
399 default:
400 assert(he->p.ptr != NULL);
401 if ((void *)t != he->p.ptr && nb)
402 memcpy(t, he->p.ptr, nb);
403 t += nb;
404 break;
405 }
406 /*@-compdef@*/
407 return t;
408 /*@=compdef@*/
409 }
410
416 static int rpmheRealloc(HE_t he)
417 /*@modifies he @*/
418 {
419 size_t nb = 0;
420 int rc = 1; /* assume success */
421
422 switch (he->t) {
423 default:
424 assert(0); /* XXX stop unimplemented oversights. */
425 break;
426 case RPM_BIN_TYPE:
427 he->freeData = 1; /* XXX RPM_BIN_TYPE is malloc'd */
428 /*@fallthrough@*/
429 case RPM_UINT8_TYPE:
430 nb = he->c * sizeof(*he->p.ui8p);
431 break;
432 case RPM_UINT16_TYPE:
433 nb = he->c * sizeof(*he->p.ui16p);
434 break;
435 case RPM_UINT32_TYPE:
436 nb = he->c * sizeof(*he->p.ui32p);
437 break;
438 case RPM_UINT64_TYPE:
439 nb = he->c * sizeof(*he->p.ui64p);
440 break;
441 case RPM_STRING_TYPE:
442 if (he->p.str)
443 nb = strlen(he->p.str) + 1;
444 else
445 rc = 0;
446 break;
447 case RPM_I18NSTRING_TYPE:
448 case RPM_STRING_ARRAY_TYPE:
449 break;
450 }
451
452 /* Allocate all returned storage (if not already). */
453 if (he->p.ptr && nb && !he->freeData) {
454 void * ptr = xmalloc(nb);
455 if (tagSwab(ptr, he, nb) != NULL)
456 he->p.ptr = ptr;
457 else {
458 ptr = _free(ptr);
459 rc = 0;
460 }
461 }
462
463 if (rc)
464 he->freeData = 1;
465
466 return rc;
467 }
468
495 /*@-globs@*/ /* XXX rpm_typeAlign usage */
496 static rpmuint32_t regionSwab(/*@null@*/ indexEntry entry, rpmuint32_t il, rpmuint32_t dl,
497 entryInfo pe,
498 unsigned char * dataStart,
499 /*@null@*/ const unsigned char * dataEnd,
500 rpmint32_t regionid)
501 /*@modifies *entry, *dataStart @*/
502 {
503 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
504 rpmTagData p;
505 rpmTagData pend;
506 unsigned char * tprev = NULL;
507 unsigned char * t = NULL;
508 size_t tdel = 0;
509 size_t tl = dl;
510 struct indexEntry_s ieprev;
511
512 assert(dataEnd != NULL);
513 assert(entry != NULL);
514 assert(dl == 0); /* XXX eliminate dl argument (its always 0) */
515
516 memset(&ieprev, 0, sizeof(ieprev));
517 for (; il > 0; il--, pe++) {
518 struct indexEntry_s ie;
519 rpmTagType type;
520
521 ie.info.tag = (rpmuint32_t) ntohl(pe->tag);
522 ie.info.type = (rpmuint32_t) ntohl(pe->type);
523 ie.info.count = (rpmuint32_t) ntohl(pe->count);
524 ie.info.offset = (rpmint32_t) ntohl(pe->offset);
525 assert(ie.info.offset >= 0); /* XXX insurance */
526
527 if (hdrchkType(ie.info.type))
528 return 0;
529 if (hdrchkData(ie.info.count))
530 return 0;
531 if (hdrchkData(ie.info.offset))
532 return 0;
533 if (hdrchkAlign(ie.info.type, ie.info.offset))
534 return 0;
535
536 ie.data = t = dataStart + ie.info.offset;
537 if (dataEnd && t >= dataEnd)
538 return 0;
539
540 p.ptr = ie.data;
541 pend.ui8p = (rpmuint8_t *) dataEnd;
542
543 /* Compute the tag data store length using offsets. */
544 if (il > 1)
545 ie.length = ((rpmuint32_t)ntohl(pe[1].offset) - ie.info.offset);
546 else {
547 /* XXX (dataEnd - t) +/- REGION_TAG_COUNT forces dataLength() */
548 ie.length = dataLength(ie.info.type, &p, ie.info.count, 1, &pend);
549 }
550
551 if (ie.length == 0 || hdrchkData(ie.length))
552 return 0;
553
554 ie.rdlen = 0;
555
556 if (entry) {
557 ie.info.offset = regionid;
558 /*@-kepttrans@*/ /* entry->data is kept */
559 *entry = ie; /* structure assignment */
560 /*@=kepttrans@*/
561 entry++;
562 }
563
564 /* Alignment */
565 type = ie.info.type;
566 if (typeSizes[type] > 1) {
567 size_t diff = typeSizes[type] - (dl % typeSizes[type]);
568 if ((int)diff != typeSizes[type]) {
569 dl += diff;
570 #ifdef DYING
571 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
572 ieprev.length += diff;
573 #endif
574 }
575 }
576 tdel = (tprev ? (t - tprev) : 0);
577 #ifdef DYING
578 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
579 tdel = ieprev.length;
580 #endif
581
582 if (ie.info.tag >= HEADER_I18NTABLE) {
583 tprev = t;
584 } else {
585 tprev = dataStart;
586 /* XXX HEADER_IMAGE tags don't include region sub-tag. */
587 /*@-sizeoftype@*/
588 if (ie.info.tag == HEADER_IMAGE)
589 tprev -= REGION_TAG_COUNT;
590 /*@=sizeoftype@*/
591 }
592
593 t += ie.length;
594
595 dl += ie.length;
596 if (dataEnd && (dataStart + dl) > dataEnd) return 0;
597 tl += tdel;
598 ieprev = ie; /* structure assignment */
599
600 }
601 tdel = (tprev ? (t - tprev) : 0);
602 tl += tdel;
603
604 /* XXX
605 * There are two hacks here:
606 * 1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
607 * 2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
608 */
609 /*@-sizeoftype@*/
610 if (tl+REGION_TAG_COUNT == dl)
611 tl += REGION_TAG_COUNT;
612 /*@=sizeoftype@*/
613
614 return dl;
615 }
616 /*@=globs@*/
617
618 void * headerUnload(Header h, size_t * lenp)
619 {
620 void * sw;
621 rpmuint32_t * ei = NULL;
622 entryInfo pe;
623 unsigned char * dataStart;
624 unsigned char * te;
625 unsigned pad;
626 size_t len = 0;
627 rpmuint32_t il = 0;
628 rpmuint32_t dl = 0;
629 indexEntry entry;
630 rpmTagType type;
631 size_t i;
632 size_t drlen;
633 size_t ndribbles;
634 size_t driplen;
635 size_t ndrips;
636 int legacy = 0;
637
638 if ((sw = headerGetStats(h, 18)) != NULL) /* RPMTS_OP_HDRLOAD */
639 (void) rpmswEnter(sw, 0);
640
641 /* Sort entries by (offset,tag). */
642 headerUnsort(h);
643
644 /* Compute (il,dl) for all tags, including those deleted in region. */
645 pad = 0;
646 drlen = ndribbles = driplen = ndrips = 0;
647 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
648 if (ENTRY_IS_REGION(entry)) {
649 rpmuint32_t rdl;
650 rpmuint32_t ril;
651 rpmint32_t rid;
652
653 assert(entry->info.offset <= 0); /* XXX insurance */
654 rdl = (rpmuint32_t)-entry->info.offset; /* negative offset */
655 ril = (rpmuint32_t)(rdl/sizeof(*pe));
656 rid = (rpmuint32_t)entry->info.offset;
657
658 il += ril;
659 dl += entry->rdlen + entry->info.count;
660 /* XXX Legacy regions do not include the region tag and data. */
661 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
662 il += 1;
663
664 /* Skip rest of entries in region, but account for dribbles. */
665 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
666 if (entry->info.offset <= rid)
667 /*@innercontinue@*/ continue;
668
669 /* Alignment */
670 type = entry->info.type;
671 if (typeSizes[type] > 1) {
672 size_t diff = typeSizes[type] - (dl % typeSizes[type]);
673 if ((int)diff != typeSizes[type]) {
674 drlen += diff;
675 pad += diff;
676 dl += diff;
677 }
678 }
679
680 ndribbles++;
681 il++;
682 drlen += entry->length;
683 dl += entry->length;
684 }
685 i--;
686 entry--;
687 continue;
688 }
689
690 /* Ignore deleted drips. */
691 if (entry->data == NULL || entry->length == 0)
692 continue;
693
694 /* Alignment */
695 type = entry->info.type;
696 if (typeSizes[type] > 1) {
697 size_t diff = typeSizes[type] - (dl % typeSizes[type]);
698 if ((int)diff != typeSizes[type]) {
699 driplen += diff;
700 pad += diff;
701 dl += diff;
702 } else
703 diff = 0;
704 }
705
706 ndrips++;
707 il++;
708 driplen += entry->length;
709 dl += entry->length;
710 }
711
712 /* Sanity checks on header intro. */
713 if (hdrchkTags(il) || hdrchkData(dl))
714 goto errxit;
715
716 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
717
718 ei = xmalloc(len);
719 ei[0] = (rpmuint32_t) htonl(il);
720 ei[1] = (rpmuint32_t) htonl(dl);
721
722 pe = (entryInfo) &ei[2];
723 dataStart = te = (unsigned char *) (pe + il);
724
725 pad = 0;
726 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
727 const char * src;
728 unsigned char *t;
729 size_t rdlen;
730
731 if (entry->data == NULL || entry->length == 0)
732 continue;
733
734 t = te;
735 pe->tag = (rpmuint32_t) htonl(entry->info.tag);
736 pe->type = (rpmuint32_t) htonl(entry->info.type);
737 pe->count = (rpmuint32_t) htonl(entry->info.count);
738
739 if (ENTRY_IS_REGION(entry)) {
740 rpmuint32_t rdl;
741 rpmuint32_t ril;
742 rpmint32_t rid;
743
744 assert(entry->info.offset <= 0); /* XXX insurance */
745
746 rdl = (rpmuint32_t)-entry->info.offset; /* negative offset */
747 ril = (rpmuint32_t)(rdl/sizeof(*pe) + ndribbles);
748 rid = (rpmuint32_t)entry->info.offset;
749
750 src = (char *)entry->data;
751 rdlen = entry->rdlen;
752
753 /* XXX Legacy regions do not include the region tag and data. */
754 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
755 rpmuint32_t stei[4];
756
757 legacy = 1;
758 memcpy(pe+1, src, rdl);
759 memcpy(te, src + rdl, rdlen);
760 te += rdlen;
761
762 pe->offset = (rpmint32_t) htonl(te - dataStart);
763 stei[0] = (rpmuint32_t) pe->tag;
764 stei[1] = (rpmuint32_t) pe->type;
765 stei[2] = (rpmuint32_t) htonl(-rdl-entry->info.count);
766 stei[3] = (rpmuint32_t) pe->count;
767 memcpy(te, stei, entry->info.count);
768 te += entry->info.count;
769 ril++;
770 rdlen += entry->info.count;
771
772 } else {
773
774 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
775 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
776 te += rdlen;
777 { /*@-castexpose@*/
778 entryInfo se = (entryInfo)src;
779 /*@=castexpose@*/
780 rpmint32_t off = (rpmint32_t) ntohl(se->offset);
781 pe->offset = (rpmint32_t)((off)
782 ? htonl(te - dataStart) : htonl(off));
783 }
784 te += entry->info.count + drlen;
785
786 }
787
788 /* Skip rest of entries in region. */
789 while (i < h->indexUsed && entry->info.offset <= rid+1) {
790 i++;
791 entry++;
792 }
793 i--;
794 entry--;
795 pe += ril;
796 continue;
797 }
798
799 /* Ignore deleted drips. */
800 if (entry->data == NULL || entry->length == 0)
801 continue;
802
803 /* Alignment */
804 type = entry->info.type;
805 if (typeSizes[type] > 1) {
806 size_t diff;
807 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
808 if ((int)diff != typeSizes[type]) {
809 memset(te, 0, diff);
810 te += diff;
811 pad += diff;
812 }
813 }
814
815 /* Move tag data into header data store. */
816 pe->offset = (rpmint32_t) htonl(te - dataStart);
817 memcpy(te, entry->data, entry->length);
818 te += entry->length;
819 pe++;
820 }
821
822 /* Insure that there are no memcpy underruns/overruns. */
823 if (((unsigned char *)pe) != dataStart)
824 goto errxit;
825 if ((((unsigned char *)ei)+len) != te)
826 goto errxit;
827
828 if (lenp)
829 *lenp = len;
830
831 h->flags &= ~HEADERFLAG_SORTED;
832 headerSort(h);
833
834 if (sw != NULL) (void) rpmswExit(sw, len);
835
836 return (void *) ei;
837
838 errxit:
839 if (sw != NULL) (void) rpmswExit(sw, len);
840 /*@-usereleased@*/
841 ei = _free(ei);
842 /*@=usereleased@*/
843 return (void *) ei;
844 }
845
853 static /*@null@*/
854 indexEntry findEntry(/*@null@*/ Header h, rpmTag tag, rpmTagType type)
855 /*@modifies h @*/
856 {
857 indexEntry entry, entry2, last;
858 struct indexEntry_s key;
859
860 if (h == NULL) return NULL;
861 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
862
863 key.info.tag = tag;
864
865 entry2 = entry =
866 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
867 if (entry == NULL)
868 return NULL;
869
870 if (type == 0)
871 return entry;
872
873 /* look backwards */
874 while (entry->info.tag == tag && entry->info.type != type &&
875 entry > h->index) entry--;
876
877 if (entry->info.tag == tag && entry->info.type == type)
878 return entry;
879
880 last = h->index + h->indexUsed;
881 /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
882 while (entry2->info.tag == tag && entry2->info.type != type &&
883 entry2 < last) entry2++;
884 /*@=usereleased@*/
885
886 if (entry->info.tag == tag && entry->info.type == type)
887 return entry;
888
889 return NULL;
890 }
891
901 static
902 int headerRemoveEntry(Header h, rpmTag tag)
903 /*@modifies h @*/
904 {
905 indexEntry last = h->index + h->indexUsed;
906 indexEntry entry, first;
907 int ne;
908
909 entry = findEntry(h, tag, 0);
910 if (!entry) return 1;
911
912 /* Make sure entry points to the first occurence of this tag. */
913 while (entry > h->index && (entry - 1)->info.tag == tag)
914 entry--;
915
916 /* Free data for tags being removed. */
917 for (first = entry; first < last; first++) {
918 void * data;
919 if (first->info.tag != tag)
920 break;
921 data = first->data;
922 first->data = NULL;
923 first->length = 0;
924 if (ENTRY_IN_REGION(first))
925 continue;
926 data = _free(data);
927 }
928
929 ne = (first - entry);
930 if (ne > 0) {
931 h->indexUsed -= ne;
932 ne = last - first;
933 if (ne > 0)
934 memmove(entry, first, (ne * sizeof(*entry)));
935 }
936
937 return 0;
938 }
939
940 Header headerLoad(void * uh)
941 {
942 void * sw = NULL;
943 rpmuint32_t * ei = (rpmuint32_t *) uh;
944 rpmuint32_t il = (rpmuint32_t) ntohl(ei[0]); /* index length */
945 rpmuint32_t dl = (rpmuint32_t) ntohl(ei[1]); /* data length */
946 /*@-sizeoftype@*/
947 size_t pvlen = sizeof(il) + sizeof(dl) +
948 (il * sizeof(struct entryInfo_s)) + dl;
949 /*@=sizeoftype@*/
950 void * pv = uh;
951 Header h = NULL;
952 entryInfo pe;
953 unsigned char * dataStart;
954 unsigned char * dataEnd;
955 indexEntry entry;
956 rpmuint32_t rdlen;
957 int i;
958
959 /* Sanity checks on header intro. */
960 if (hdrchkTags(il) || hdrchkData(dl))
961 goto errxit;
962
963 ei = (rpmuint32_t *) pv;
964 /*@-castexpose@*/
965 pe = (entryInfo) &ei[2];
966 /*@=castexpose@*/
967 dataStart = (unsigned char *) (pe + il);
968 dataEnd = dataStart + dl;
969
970 h = headerGetPool(_headerPool);
971 memset(&h->h_loadops, 0, sizeof(h->h_loadops));
972 if ((sw = headerGetStats(h, 18)) != NULL) /* RPMTS_OP_HDRLOAD */
973 (void) rpmswEnter(sw, 0);
974 { unsigned char * hmagic = header_magic;
975 (void) memcpy(h->magic, hmagic, sizeof(h->magic));
976 }
977 /*@-assignexpose -kepttrans@*/
978 h->blob = uh;
979 h->bloblen = pvlen;
980 /*@=assignexpose =kepttrans@*/
981 h->origin = NULL;
982 h->baseurl = NULL;
983 h->digest = NULL;
984 h->rpmdb = NULL;
985 memset(&h->sb, 0, sizeof(h->sb));
986 h->instance = 0;
987 h->startoff = 0;
988 h->endoff = (rpmuint32_t) pvlen;
989 memset(&h->h_getops, 0, sizeof(h->h_getops));
990 h->indexAlloced = il + 1;
991 h->indexUsed = il;
992 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
993 h->flags = HEADERFLAG_SORTED;
994 h = headerLink(h);
995 assert(h != NULL);
996
997 entry = h->index;
998 i = 0;
999 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
1000 h->flags |= HEADERFLAG_LEGACY;
1001 entry->info.type = REGION_TAG_TYPE;
1002 entry->info.tag = HEADER_IMAGE;
1003 /*@-sizeoftype@*/
1004 entry->info.count = (rpmTagCount)REGION_TAG_COUNT;
1005 /*@=sizeoftype@*/
1006 entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
1007
1008 /*@-assignexpose@*/
1009 entry->data = pe;
1010 /*@=assignexpose@*/
1011 entry->length = pvlen - sizeof(il) - sizeof(dl);
1012 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
1013 #if 0 /* XXX don't check, the 8/98 i18n bug fails here. */
1014 if (rdlen != dl)
1015 goto errxit;
1016 #endif
1017 entry->rdlen = rdlen;
1018 entry++;
1019 h->indexUsed++;
1020 } else {
1021 rpmuint32_t rdl;
1022 rpmuint32_t ril;
1023
1024 h->flags &= ~HEADERFLAG_LEGACY;
1025
1026 entry->info.type = (rpmuint32_t) htonl(pe->type);
1027 entry->info.count = (rpmuint32_t) htonl(pe->count);
1028
1029 if (hdrchkType(entry->info.type))
1030 goto errxit;
1031 if (hdrchkTags(entry->info.count))
1032 goto errxit;
1033
1034 { rpmint32_t off = (rpmint32_t) ntohl(pe->offset);
1035
1036 if (hdrchkData(off))
1037 goto errxit;
1038 if (off) {
1039 /*@-sizeoftype@*/
1040 size_t nb = REGION_TAG_COUNT;
1041 /*@=sizeoftype@*/
1042 rpmuint32_t * stei = memcpy(alloca(nb), dataStart + off, nb);
1043 rdl = (rpmuint32_t)-ntohl(stei[2]); /* negative offset */
1044 assert((rpmint32_t)rdl >= 0); /* XXX insurance */
1045 ril = (rpmuint32_t)(rdl/sizeof(*pe));
1046 if (hdrchkTags(ril) || hdrchkData(rdl))
1047 goto errxit;
1048 entry->info.tag = (rpmuint32_t) htonl(pe->tag);
1049 } else {
1050 ril = il;
1051 /*@-sizeoftype@*/
1052 rdl = (rpmuint32_t)(ril * sizeof(struct entryInfo_s));
1053 /*@=sizeoftype@*/
1054 entry->info.tag = HEADER_IMAGE;
1055 }
1056 }
1057 entry->info.offset = (rpmint32_t) -rdl; /* negative offset */
1058
1059 /*@-assignexpose@*/
1060 entry->data = pe;
1061 /*@=assignexpose@*/
1062 entry->length = pvlen - sizeof(il) - sizeof(dl);
1063 rdlen = regionSwab(entry+1, (ril-1), 0, pe+1, dataStart, dataEnd, entry->info.offset);
1064 if (rdlen == 0)
1065 goto errxit;
1066 entry->rdlen = rdlen;
1067
1068 if (ril < (rpmuint32_t)h->indexUsed) {
1069 indexEntry newEntry = entry + ril;
1070 size_t ne = (h->indexUsed - ril);
1071 rpmint32_t rid = entry->info.offset+1;
1072 rpmuint32_t rc;
1073
1074 /* Load dribble entries from region. */
1075 rc = regionSwab(newEntry, (rpmuint32_t)ne, 0, pe+ril, dataStart, dataEnd, rid);
1076 if (rc == 0)
1077 goto errxit;
1078 rdlen += rc;
1079
1080 { indexEntry firstEntry = newEntry;
1081 size_t save = h->indexUsed;
1082 size_t j;
1083
1084 /* Dribble entries replace duplicate region entries. */
1085 h->indexUsed -= ne;
1086 for (j = 0; j < ne; j++, newEntry++) {
1087 (void) headerRemoveEntry(h, newEntry->info.tag);
1088 if (newEntry->info.tag == HEADER_BASENAMES)
1089 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
1090 }
1091
1092 /* If any duplicate entries were replaced, move new entries down. */
1093 if (h->indexUsed < (save - ne)) {
1094 memmove(h->index + h->indexUsed, firstEntry,
1095 (ne * sizeof(*entry)));
1096 }
1097 h->indexUsed += ne;
1098 }
1099 }
1100 }
1101
1102 h->flags &= ~HEADERFLAG_SORTED;
1103 headerSort(h);
1104
1105 if (sw != NULL) (void) rpmswExit(sw, pvlen);
1106
1107 /*@-globstate -observertrans @*/
1108 return h;
1109 /*@=globstate =observertrans @*/
1110
1111 errxit:
1112 if (sw != NULL) (void) rpmswExit(sw, pvlen);
1113 /*@-usereleased@*/
1114 if (h) {
1115 h->index = _free(h->index);
1116 yarnPossess(h->_item.use); /* XXX rpmioPutItem expects locked. */
1117 h = (Header) rpmioPutPool((rpmioItem)h);
1118 }
1119 /*@=usereleased@*/
1120 /*@-refcounttrans -globstate@*/
1121 return h;
1122 /*@=refcounttrans =globstate@*/
1123 }
1124
1125 int headerGetMagic(Header h, unsigned char ** magicp, size_t * nmagicp)
1126 {
1127 unsigned char * hmagic = header_magic;
1128 if (magicp)
1129 *magicp = (h ? h->magic : hmagic);
1130 if (nmagicp)
1131 *nmagicp = (h ? sizeof(h->magic) : sizeof(header_magic));
1132 return 0;
1133 }
1134
1135 int headerSetMagic(Header h, unsigned char * magic, size_t nmagic)
1136 {
1137 if (nmagic > sizeof(h->magic))
1138 nmagic = sizeof(h->magic);
1139 if (h) {
1140 memset(h->magic, 0, sizeof(h->magic));
1141 if (nmagic > 0)
1142 memmove(h->magic, magic, nmagic);
1143 }
1144 return 0;
1145 }
1146
1147 const char * headerGetOrigin(Header h)
1148 {
1149 return (h != NULL ? h->origin : NULL);
1150 }
1151
1152 int headerSetOrigin(Header h, const char * origin)
1153 {
1154 if (h != NULL) {
1155 h->origin = _free(h->origin);
1156 h->origin = xstrdup(origin);
1157 }
1158 return 0;
1159 }
1160
1161 const char * headerGetBaseURL(Header h)
1162 {
1163 /*@-retexpose@*/
1164 return (h != NULL ? h->baseurl : NULL);
1165 /*@=retexpose@*/
1166 }
1167
1168 int headerSetBaseURL(Header h, const char * baseurl)
1169 {
1170 if (h != NULL) {
1171 h->baseurl = _free(h->baseurl);
1172 h->baseurl = xstrdup(baseurl);
1173 }
1174 return 0;
1175 }
1176
1177 struct stat * headerGetStatbuf(Header h)
1178 {
1179 /*@-immediatetrans -retexpose@*/
1180 return (h != NULL ? &h->sb : NULL);
1181 /*@=immediatetrans =retexpose@*/
1182 }
1183
1184 int headerSetStatbuf(Header h, struct stat * st)
1185 {
1186 if (h != NULL && st != NULL)
1187 memcpy(&h->sb, st, sizeof(h->sb));
1188 return 0;
1189 }
1190
1191 const char * headerGetDigest(Header h)
1192 {
1193 /*@-compdef -retexpose -usereleased @*/
1194 return (h != NULL ? h->digest : NULL);
1195 /*@=compdef =retexpose =usereleased @*/
1196 }
1197
1198 int headerSetDigest(Header h, const char * digest)
1199 {
1200 if (h != NULL) {
1201 h->digest = _free(h->digest);
1202 h->digest = xstrdup(digest);
1203 }
1204 return 0;
1205 }
1206
1207 void * headerGetRpmdb(Header h)
1208 {
1209 /*@-compdef -retexpose -usereleased @*/
1210 return (h != NULL ? h->rpmdb : NULL);
1211 /*@=compdef =retexpose =usereleased @*/
1212 }
1213
1214 void * headerSetRpmdb(Header h, void * rpmdb)
1215 {
1216 /*@-assignexpose -temptrans @*/
1217 if (h != NULL)
1218 h->rpmdb = rpmdb;
1219 /*@=assignexpose =temptrans @*/
1220 return NULL;
1221 }
1222
1223 rpmuint32_t headerGetInstance(Header h)
1224 {
1225 return (h != NULL ? h->instance : 0);
1226 }
1227
1228 rpmuint32_t headerSetInstance(Header h, rpmuint32_t instance)
1229 {
1230 if (h != NULL)
1231 h->instance = instance;
1232 return 0;
1233 }
1234
1235 rpmuint32_t headerGetStartOff(Header h)
1236 {
1237 return (h != NULL ? h->startoff : 0);
1238 }
1239
1240 rpmuint32_t headerSetStartOff(Header h, rpmuint32_t startoff)
1241 {
1242 if (h != NULL)
1243 h->startoff = startoff;
1244 return 0;
1245 }
1246
1247 rpmuint32_t headerGetEndOff(Header h)
1248 {
1249 return (h != NULL ? h->endoff : 0);
1250 }
1251
1252 rpmuint32_t headerSetEndOff(Header h, rpmuint32_t endoff)
1253 {
1254 if (h != NULL)
1255 h->endoff = endoff;
1256 return 0;
1257 }
1258
1259 Header headerReload(Header h, int tag)
1260 {
1261 Header nh;
1262 void * uh;
1263 const char * origin = (h->origin != NULL ? xstrdup(h->origin) : NULL);
1264 const char * baseurl = (h->baseurl != NULL ? xstrdup(h->baseurl) : NULL);
1265 const char * digest = (h->digest != NULL ? xstrdup(h->digest) : NULL);
1266 struct stat sb = h->sb; /* structure assignment */
1267 void * rpmdb = h->rpmdb;
1268 rpmuint32_t instance = h->instance;
1269 int xx;
1270
1271 /*@-onlytrans@*/
1272 uh = headerUnload(h, NULL);
1273 (void)headerFree(h);
1274 h = NULL ;
1275 /*@=onlytrans@*/
1276 if (uh == NULL)
1277 return NULL;
1278 nh = headerLoad(uh);
1279 if (nh == NULL) {
1280 uh = _free(uh);
1281 return NULL;
1282 }
1283 nh->flags |= HEADERFLAG_ALLOCATED;
1284 if (ENTRY_IS_REGION(nh->index)) {
1285 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
1286 nh->index[0].info.tag = tag;
1287 }
1288 if (origin != NULL) {
1289 xx = headerSetOrigin(nh, origin);
1290 origin = _free(origin);
1291 }
1292 if (baseurl != NULL) {
1293 xx = headerSetBaseURL(nh, baseurl);
1294 baseurl = _free(baseurl);
1295 }
1296 if (digest != NULL) {
1297 xx = headerSetDigest(nh, digest);
1298 digest = _free(digest);
1299 }
1300 /*@-assignexpose@*/
1301 nh->sb = sb; /* structure assignment */
1302 /*@=assignexpose@*/
1303 (void) headerSetRpmdb(nh, rpmdb);
1304 xx = (int) headerSetInstance(nh, instance);
1305 return nh;
1306 }
1307
1308 static Header headerMap(const void * uh, int map)
1309 /*@*/
1310 {
1311 rpmuint32_t * ei = (rpmuint32_t *) uh;
1312 rpmuint32_t il = (rpmuint32_t) ntohl(ei[0]); /* index length */
1313 rpmuint32_t dl = (rpmuint32_t) ntohl(ei[1]); /* data length */
1314 /*@-sizeoftype@*/
1315 size_t pvlen = sizeof(il) + sizeof(dl) +
1316 (il * sizeof(struct entryInfo_s)) + dl;
1317 /*@=sizeoftype@*/
1318 void * nuh = NULL;
1319 Header nh = NULL;
1320
1321 /* Sanity checks on header intro. */
1322 if (hdrchkTags(il) || hdrchkData(dl) || pvlen >= headerMaxbytes)
1323 return NULL;
1324
1325 if (map) {
1326 static const int prot = PROT_READ | PROT_WRITE;
1327 static const int flags = MAP_PRIVATE| MAP_ANONYMOUS;
1328 static const int fdno = -1;
1329 static const off_t off = 0;
1330 nuh = mmap(NULL, pvlen, prot, flags, fdno, off);
1331 if (nuh == NULL || nuh == (void *)-1)
1332 fprintf(stderr,
1333 "==> mmap(%p[%u], 0x%x, 0x%x, %d, 0x%x) error(%d): %s\n",
1334 NULL, pvlen, prot, flags, fdno, (unsigned)off,
1335 errno, strerror(errno));
1336 memcpy(nuh, uh, pvlen);
1337 if (mprotect(nuh, pvlen, PROT_READ) != 0)
1338 fprintf(stderr, "==> mprotect(%p[%u],0x%x) error(%d): %s\n",
1339 nuh, pvlen, PROT_READ,
1340 errno, strerror(errno));
1341 nh = headerLoad(nuh);
1342 if (nh != NULL) {
1343 assert(nh->bloblen == pvlen);
1344 nh->flags |= HEADERFLAG_MAPPED;
1345 nh->flags |= HEADERFLAG_RDONLY;
1346 } else {
1347 if (munmap(nuh, pvlen) != 0)
1348 fprintf(stderr, "==> munmap(%p[%u]) error(%d): %s\n",
1349 nuh, pvlen, errno, strerror(errno));
1350 }
1351 } else {
1352 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
1353 if ((nh = headerLoad(nuh)) != NULL)
1354 nh->flags |= HEADERFLAG_ALLOCATED;
1355 else
1356 nuh = _free(nuh);
1357 }
1358
1359 return nh;
1360 }
1361
1362 Header headerCopyLoad(const void * uh)
1363 {
1364 static const int map = 1;
1365 return headerMap(uh, map);
1366 }
1367
1368 int headerIsEntry(Header h, rpmTag tag)
1369 {
1370 /*@-mods@*/ /*@ FIX: h modified by sort. */
1371 return (findEntry(h, tag, 0) ? 1 : 0);
1372 /*@=mods@*/
1373 }
1374
1383 static int copyEntry(const indexEntry entry, HE_t he, int minMem)
1384 /*@modifies he @*/
1385 {
1386 rpmTagCount count = entry->info.count;
1387 int rc = 1; /* XXX 1 on success. */
1388
1389 switch (entry->info.type) {
1390 case RPM_BIN_TYPE:
1391 /*
1392 * XXX This only works for
1393 * XXX "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
1394 * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
1395 * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
1396 */
1397 if (ENTRY_IS_REGION(entry)) {
1398 rpmuint32_t * ei = ((rpmuint32_t *)entry->data) - 2;
1399 /*@-castexpose@*/
1400 entryInfo pe = (entryInfo) (ei + 2);
1401 /*@=castexpose@*/
1402 unsigned char * dataStart = (unsigned char *) (pe + ntohl(ei[0]));
1403 rpmuint32_t rdl;
1404 rpmuint32_t ril;
1405
1406 assert(entry->info.offset <= 0); /* XXX insurance */
1407 rdl = (rpmuint32_t)-entry->info.offset; /* negative offset */
1408 ril = (rpmuint32_t)(rdl/sizeof(*pe));
1409 /*@-sizeoftype@*/
1410 rdl = (rpmuint32_t)entry->rdlen;
1411 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
1412 if (entry->info.tag == HEADER_IMAGE) {
1413 ril -= 1;
1414 pe += 1;
1415 } else {
1416 count += REGION_TAG_COUNT;
1417 rdl += REGION_TAG_COUNT;
1418 }
1419
1420 he->p.ui32p = ei = xmalloc(count);
1421 ei[0] = (rpmuint32_t)htonl(ril);
1422 ei[1] = (rpmuint32_t)htonl(rdl);
1423
1424 /*@-castexpose@*/
1425 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
1426 /*@=castexpose@*/
1427
1428 (void) memcpy(pe + ril, dataStart, rdl);
1429 } else {
1430 count = (rpmTagCount)entry->length;
1431 he->p.ptr = (!minMem
1432 ? memcpy(xmalloc(count), entry->data, count)
1433 : entry->data);
1434 }
1435 break;
1436 case RPM_STRING_TYPE:
1437 if (count == 1) {
1438 he->p.str = entry->data;
1439 break;
1440 }
1441 /*@fallthrough@*/
1442 case RPM_I18NSTRING_TYPE:
1443 case RPM_STRING_ARRAY_TYPE:
1444 { const char ** argv;
1445 size_t nb = count * sizeof(*argv);
1446 char * t;
1447 unsigned i;
1448
1449 /*@-mods@*/
1450 if (minMem) {
1451 he->p.argv = argv = xmalloc(nb);
1452 t = entry->data;
1453 } else {
1454 he->p.argv = argv = xmalloc(nb + entry->length);
1455 t = (char *) &argv[count];
1456 memcpy(t, entry->data, entry->length);
1457 }
1458 /*@=mods@*/
1459 for (i = 0; i < (unsigned) count; i++) {
1460 argv[i] = t;
1461 t = strchr(t, 0);
1462 t++;
1463 }
1464 } break;
1465
1466 default:
1467 he->p.ptr = entry->data;
1468 break;
1469 }
1470 he->t = entry->info.type;
1471 he->c = count;
1472 return rc;
1473 }
1474
1493 static int headerMatchLocale(const char *td, const char *l, const char *le)
1494 /*@*/
1495 {
1496 const char *fe;
1497
1498
1499 #if 0
1500 { const char *s, *ll, *CC, *EE, *dd;
1501 char *lbuf, *t.
1502
1503 /* Copy the buffer and parse out components on the fly. */
1504 lbuf = alloca(le - l + 1);
1505 for (s = l, ll = t = lbuf; *s; s++, t++) {
1506 switch (*s) {
1507 case '_':
1508 *t = '\0';
1509 CC = t + 1;
1510 break;
1511 case '.':
1512 *t = '\0';
1513 EE = t + 1;
1514 break;
1515 case '@':
1516 *t = '\0';
1517 dd = t + 1;
1518 break;
1519 default:
1520 *t = *s;
1521 break;
1522 }
1523 }
1524
1525 if (ll) /* ISO language should be lower case */
1526 for (t = ll; *t; t++) *t = tolower(*t);
1527 if (CC) /* ISO country code should be upper case */
1528 for (t = CC; *t; t++) *t = toupper(*t);
1529
1530 /* There are a total of 16 cases to attempt to match. */
1531 }
1532 #endif
1533
1534 /* First try a complete match. */
1535 if (strlen(td) == (size_t)(le - l) && !strncmp(td, l, (size_t)(le - l)))
1536 return 1;
1537
1538 /* Next, try stripping optional dialect and matching. */
1539 for (fe = l; fe < le && *fe != '@'; fe++)
1540 {};
1541 if (fe < le && !strncmp(td, l, (fe - l)))
1542 return 1;
1543
1544 /* Next, try stripping optional codeset and matching. */
1545 for (fe = l; fe < le && *fe != '.'; fe++)
1546 {};
1547 if (fe < le && !strncmp(td, l, (fe - l)))
1548 return 1;
1549
1550 /* Finally, try stripping optional country code and matching. */
1551 for (fe = l; fe < le && *fe != '_'; fe++)
1552 {};
1553 if (fe < le && !strncmp(td, l, (fe - l)))
1554 return 2;
1555
1556 return 0;
1557 }
1558
1565 /*@dependent@*/ /*@exposed@*/ static char *
1566 headerFindI18NString(Header h, indexEntry entry)
1567 /*@*/
1568 {
1569 const char *lang, *l, *le;
1570 indexEntry table;
1571
1572 /* XXX Drepper sez' this is the order. */
1573 if ((lang = getenv("LANGUAGE")) == NULL &&
1574 (lang = getenv("LC_ALL")) == NULL &&
1575 (lang = getenv("LC_MESSAGES")) == NULL &&
1576 (lang = getenv("LANG")) == NULL)
1577 return entry->data;
1578
1579 /*@-mods@*/
1580 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
1581 return entry->data;
1582 /*@=mods@*/
1583
1584 for (l = lang; *l != '\0'; l = le) {
1585 const char *td;
1586 char *ed, *ed_weak = NULL;
1587 rpmuint32_t langNum;
1588
1589 while (*l && *l == ':') /* skip leading colons */
1590 l++;
1591 if (*l == '\0')
1592 break;
1593 for (le = l; *le && *le != ':'; le++) /* find end of this locale */
1594 {};
1595
1596 /* For each entry in the header ... */
1597 for (langNum = 0, td = table->data, ed = entry->data;
1598 langNum < entry->info.count;
1599 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1)
1600 {
1601 int match = headerMatchLocale(td, l, le);
1602 if (match == 1) return ed;
1603 else if (match == 2) ed_weak = ed;
1604 }
1605 if (ed_weak) return ed_weak;
1606 }
1607
1608 return entry->data;
1609 }
1610
1618 static int intGetEntry(Header h, HE_t he, int flags)
1619 /*@modifies he @*/
1620 {
1621 int minMem = 0;
1622 indexEntry entry;
1623 int rc;
1624
1625 /* First find the tag */
1626 /*@-mods@*/ /*@ FIX: h modified by sort. */
1627 entry = findEntry(h, he->tag, 0);
1628 /*@=mods@*/
1629 if (entry == NULL) {
1630 he->t = 0;
1631 he->p.ptr = NULL;
1632 he->c = 0;
1633 return 0;
1634 }
1635
1636 switch (entry->info.type) {
1637 case RPM_I18NSTRING_TYPE:
1638 if (!(flags & HEADERGET_NOI18NSTRING)) {
1639 rc = 1;
1640 he->t = RPM_STRING_TYPE;
1641 he->c = 1;
1642 /*@-dependenttrans@*/
1643 he->p.str = headerFindI18NString(h, entry);
1644 /*@=dependenttrans@*/
1645 break;
1646 }
1647 /*@fallthrough@*/
1648 default:
1649 rc = copyEntry(entry, he, minMem);
1650 break;
1651 }
1652
1653 /* XXX 1 on success */
1654 return (rc == 1 ? 1 : 0);
1655 }
1656
1664 static int copyData(char * t, const HE_t he, size_t nb)
1665 /*@modifies *t @*/
1666 {
1667 int rc = 0; /* assume success */
1668
1669 switch (he->t) {
1670 case RPM_I18NSTRING_TYPE:
1671 case RPM_STRING_ARRAY_TYPE:
1672 { const char ** av = he->p.argv;
1673 rpmTagCount cnt = he->c;
1674 const char * s;
1675
1676 while (cnt-- > 0 && nb > 0) {
1677 if ((s = *av++) != NULL)
1678 do {
1679 *t++ = *s++;
1680 } while (s[-1] && --nb > 0);
1681 }
1682 } break;
1683 default:
1684 if (tagSwab((unsigned char *)t, he, nb) == NULL)
1685 rc = 1;
1686 break;
1687 }
1688 return rc;
1689 }
1690
1697 /*@null@*/
1698 static void *
1699 grabData(HE_t he, /*@out@*/ size_t * lenp)
1700 /*@modifies *lenp @*/
1701 {
1702 size_t nb = dataLength(he->t, &he->p, he->c, 0, NULL);
1703 char * t = NULL;
1704
1705 if (nb > 0) {
1706 t = xmalloc(nb);
1707 if (copyData(t, he, nb)) {
1708 t = _free(t);
1709 nb = 0;
1710 }
1711 }
1712 if (lenp)
1713 *lenp = nb;
1714 return t;
1715 }
1716
1728 static
1729 int headerAddEntry(Header h, HE_t he)
1730 /*@modifies h @*/
1731 {
1732 indexEntry entry;
1733 rpmTagData data;
1734 size_t length = 0;
1735 int rc = 0; /* assume failure */
1736
1737 /* Count must always be >= 1 for headerAddEntry. */
1738 if (he->c == 0)
1739 return rc;
1740
1741 if (hdrchkType(he->t))
1742 return rc;
1743 if (hdrchkData(he->c))
1744 return rc;
1745
1746 data.ptr = grabData(he, &length);
1747 if (data.ptr == NULL || length == 0)
1748 return rc;
1749
1750 /* Allocate more index space if necessary */
1751 if (h->indexUsed == h->indexAlloced) {
1752 h->indexAlloced += INDEX_MALLOC_SIZE;
1753 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
1754 }
1755
1756 /* Fill in the index */
1757 entry = h->index + h->indexUsed;
1758 entry->info.tag = he->tag;
1759 entry->info.type = he->t;
1760 entry->info.count = he->c;
1761 entry->info.offset = 0;
1762 entry->data = data.ptr;
1763 entry->length = length;
1764
1765 if (h->indexUsed > 0 && he->tag < h->index[h->indexUsed-1].info.tag)
1766 h->flags &= ~HEADERFLAG_SORTED;
1767 h->indexUsed++;
1768 rc = 1;
1769
1770 return rc;
1771 }
1772
1782 static
1783 int headerAppendEntry(Header h, HE_t he)
1784 /*@modifies h @*/
1785 {
1786 rpmTagData src = { .ptr = he->p.ptr };
1787 char * t;
1788 indexEntry entry;
1789 size_t length;
1790 int rc = 0; /* assume failure */
1791
1792 if (he->t == RPM_STRING_TYPE || he->t == RPM_I18NSTRING_TYPE) {
1793 /* we can't do this */
1794 return rc;
1795 }
1796
1797 /* Find the tag entry in the header. */
1798 entry = findEntry(h, he->tag, he->t);
1799 if (!entry)
1800 return rc;
1801
1802 length = dataLength(he->t, &src, he->c, 0, NULL);
1803 if (length == 0)
1804 return rc;
1805
1806 if (ENTRY_IN_REGION(entry)) {
1807 char * t = xmalloc(entry->length + length);
1808 memcpy(t, entry->data, entry->length);
1809 entry->data = t;
1810 entry->info.offset = 0;
1811 } else
1812 entry->data = xrealloc(entry->data, entry->length + length);
1813
1814 t = ((char *) entry->data) + entry->length;
1815 if (!copyData(t, he, length))
1816 rc = 1;
1817
1818 entry->length += length;
1819
1820 entry->info.count += he->c;
1821
1822 return rc;
1823 }
1824
1831 static
1832 int headerAddOrAppendEntry(Header h, HE_t he)
1833 /*@modifies h @*/
1834 {
1835 return (findEntry(h, he->tag, he->t)
1836 ? headerAppendEntry(h, he)
1837 : headerAddEntry(h, he));
1838 }
1839
1840 int headerAddI18NString(Header h, rpmTag tag, const char * string,
1841 const char * lang)
1842 {
1843 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
1844 indexEntry table, entry;
1845 rpmTagData p;
1846 size_t length;
1847 size_t ghosts;
1848 rpmuint32_t i;
1849 rpmuint32_t langNum;
1850 char * buf;
1851 int xx;
1852
1853 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
1854 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
1855
1856 if (!table && entry)
1857 return 0; /* this shouldn't ever happen!! */
1858
1859 if (!table && !entry) {
1860 const char * argv[2];
1861 int count = 0;
1862 p.argv = argv;
1863 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
1864 /*@-observertrans -readonlytrans@*/
1865 p.argv[count++] = "C";
1866 /*@=observertrans =readonlytrans@*/
1867 } else {
1868 /*@-observertrans -readonlytrans@*/
1869 p.argv[count++] = "C";
1870 /*@=observertrans =readonlytrans@*/
1871 p.argv[count++] = lang;
1872 }
1873 he->tag = HEADER_I18NTABLE;
1874 he->t = RPM_STRING_ARRAY_TYPE;
1875 he->p.ptr = p.ptr;
1876 he->c = count;
1877 xx = headerAddEntry(h, he);
1878 if (!xx)
1879 return 0;
1880 table = findEntry(h, he->tag, he->t);
1881 }
1882
1883 if (!table)
1884 return 0;
1885 if (!lang) lang = "C";
1886
1887 { const char * l = table->data;
1888 for (langNum = 0; langNum < table->info.count; langNum++) {
1889 if (!strcmp(l, lang)) break;
1890 l += strlen(l) + 1;
1891 }
1892 }
1893
1894 if (langNum >= table->info.count) {
1895 length = strlen(lang) + 1;
1896 if (ENTRY_IN_REGION(table)) {
1897 char * t = xmalloc(table->length + length);
1898 memcpy(t, table->data, table->length);
1899 table->data = t;
1900 table->info.offset = 0;
1901 } else
1902 table->data = xrealloc(table->data, table->length + length);
1903 memmove(((char *)table->data) + table->length, lang, length);
1904 table->length += length;
1905 table->info.count++;
1906 }
1907
1908 if (!entry) {
1909 p.argv = alloca(sizeof(*p.argv) * (langNum + 1));
1910 /*@-observertrans -readonlytrans@*/
1911 for (i = 0; i < langNum; i++)
1912 p.argv[i] = "";
1913 /*@=observertrans =readonlytrans@*/
1914 p.argv[langNum] = string;
1915 he->tag = tag;
1916 he->t = RPM_I18NSTRING_TYPE;
1917 he->p.ptr = p.ptr;
1918 he->c = langNum + 1;
1919 /*@-compmempass@*/
1920 xx = headerAddEntry(h, he);
1921 /*@=compmempass@*/
1922 return xx;
1923 } else if (langNum >= entry->info.count) {
1924 ghosts = langNum - entry->info.count;
1925
1926 length = strlen(string) + 1 + ghosts;
1927 if (ENTRY_IN_REGION(entry)) {
1928 char * t = xmalloc(entry->length + length);
1929 memcpy(t, entry->data, entry->length);
1930 entry->data = t;
1931 entry->info.offset = 0;
1932 } else
1933 entry->data = xrealloc(entry->data, entry->length + length);
1934
1935 memset(((char *)entry->data) + entry->length, 0, ghosts);
1936 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
1937
1938 entry->length += length;
1939 entry->info.count = langNum + 1;
1940 } else {
1941 char *b, *be, *e, *ee, *t;
1942 size_t bn, sn, en;
1943
1944 /* Set beginning/end pointers to previous data */
1945 b = be = e = ee = entry->data;
1946 for (i = 0; i < table->info.count; i++) {
1947 if (i == langNum)
1948 be = ee;
1949 ee += strlen(ee) + 1;
1950 if (i == langNum)
1951 e = ee;
1952 }
1953
1954 /* Get storage for new buffer */
1955 bn = (be-b);
1956 sn = strlen(string) + 1;
1957 en = (ee-e);
1958 length = bn + sn + en;
1959 t = buf = xmalloc(length);
1960
1961 /* Copy values into new storage */
1962 memcpy(t, b, bn);
1963 t += bn;
1964 /*@-mayaliasunique@*/
1965 memcpy(t, string, sn);
1966 t += sn;
1967 memcpy(t, e, en);
1968 t += en;
1969 /*@=mayaliasunique@*/
1970
1971 /* Replace i18N string array */
1972 entry->length -= strlen(be) + 1;
1973 entry->length += sn;
1974
1975 if (ENTRY_IN_REGION(entry)) {
1976 entry->info.offset = 0;
1977 } else
1978 entry->data = _free(entry->data);
1979 /*@-dependenttrans@*/
1980 entry->data = buf;
1981 /*@=dependenttrans@*/
1982 }
1983
1984 return 0;
1985 }
1986
1994 static
1995 int headerModifyEntry(Header h, HE_t he)
1996 /*@modifies h @*/
1997 {
1998 indexEntry entry;
1999 rpmTagData oldData;
2000 rpmTagData newData;
2001 size_t length = 0;
2002
2003 /* First find the tag */
2004 entry = findEntry(h, he->tag, he->t);
2005 if (!entry)
2006 return 0;
2007
2008 newData.ptr = grabData(he, &length);
2009 if (newData.ptr == NULL || length == 0)
2010 return 0;
2011
2012 /* make sure entry points to the first occurence of this tag */
2013 while (entry > h->index && (entry - 1)->info.tag == he->tag)
2014 entry--;
2015
2016 /* free after we've grabbed the new data in case the two are intertwined;
2017 that's a bad idea but at least we won't break */
2018 oldData.ptr = entry->data;
2019
2020 entry->info.count = he->c;
2021 entry->info.type = he->t;
2022 entry->data = newData.ptr;
2023 entry->length = length;
2024
2025 if (ENTRY_IN_REGION(entry)) {
2026 entry->info.offset = 0;
2027 } else
2028 oldData.ptr = _free(oldData.ptr);
2029
2030 return 1;
2031 }
2032
2036 struct headerIterator_s {
2037 Header h;
2038 size_t next_index;
2039 };
2040
2041 HeaderIterator headerFini(/*@only@*/ HeaderIterator hi)
2042 {
2043 if (hi != NULL) {
2044 (void)headerFree(hi->h);
2045 hi->h = NULL;
2046 hi = _free(hi);
2047 }
2048 return hi;
2049 }
2050
2051 HeaderIterator headerInit(Header h)
2052 {
2053 HeaderIterator hi = xmalloc(sizeof(*hi));
2054
2055 headerSort(h);
2056
2057 /*@-assignexpose -castexpose @*/
2058 hi->h = headerLink(h);
2059 /*@=assignexpose =castexpose @*/
2060 assert(hi->h != NULL);
2061 hi->next_index = 0;
2062 return hi;
2063 }
2064
2065 int headerNext(HeaderIterator hi, HE_t he, /*@unused@*/ unsigned int flags)
2066 {
2067 void * sw;
2068 Header h = hi->h;
2069 size_t slot = hi->next_index;
2070 indexEntry entry = NULL;
2071 int rc;
2072
2073 /* Insure that *he is reliably initialized. */
2074 memset(he, 0, sizeof(*he));
2075
2076 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
2077 entry = h->index + slot;
2078 if (!ENTRY_IS_REGION(entry))
2079 break;
2080 }
2081 hi->next_index = slot;
2082 if (entry == NULL || slot >= h->indexUsed)
2083 return 0;
2084
2085 hi->next_index++;
2086
2087 if ((sw = headerGetStats(h, 19)) != NULL) /* RPMTS_OP_HDRGET */
2088 (void) rpmswEnter(sw, 0);
2089
2090 he->tag = entry->info.tag;
2091 rc = copyEntry(entry, he, 0);
2092 if (rc)
2093 rc = rpmheRealloc(he);
2094
2095 if (sw != NULL) (void) rpmswExit(sw, 0);
2096
2097 /* XXX 1 on success */
2098 return ((rc == 1) ? 1 : 0);
2099 }
2100
2101 Header headerCopy(Header h)
2102 {
2103 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
2104 Header nh = headerNew();
2105 HeaderIterator hi;
2106
2107 for (hi = headerInit(h);
2108 headerNext(hi, he, 0);
2109 he->p.ptr = _free(he->p.ptr))
2110 {
2111 if (he->p.ptr) (void) headerAddEntry(nh, he);
2112 }
2113 hi = headerFini(hi);
2114
2115 return headerReload(nh, HEADER_IMAGE);
2116 }
2117
2118 void headerCopyTags(Header headerFrom, Header headerTo, rpmTag * tagstocopy)
2119 {
2120 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
2121 rpmTag * tagno;
2122 int xx;
2123
2124 if (headerFrom == headerTo)
2125 return;
2126
2127 for (tagno = tagstocopy; *tagno != 0; tagno++) {
2128 if (headerIsEntry(headerTo, *tagno))
2129 continue;
2130 he->tag = *tagno;
2131 if (!headerGet(headerFrom, he, 0))
2132 continue;
2133 xx = headerPut(headerTo, he, 0);
2134 he->p.ptr = _free(he->p.ptr);
2135 }
2136 }
2137
2138 int headerGet(Header h, HE_t he, unsigned int flags)
2139 {
2140 void * sw;
2141 const char * name;
2142 headerSprintfExtension exts = headerCompoundFormats;
2143 headerSprintfExtension ext = NULL;
2144 int extNum;
2145 int rc;
2146
2147 if (h == NULL || he == NULL) return 0; /* XXX this is nutty. */
2148
2149 /* Insure that *he is reliably initialized. */
2150 { rpmTag tag = he->tag;
2151 memset(he, 0, sizeof(*he));
2152 he->tag = tag;
2153 }
2154 name = tagName(he->tag);
2155
2156 if ((sw = headerGetStats(h, 19)) != NULL) /* RPMTS_OP_HDRGET */
2157 (void) rpmswEnter(sw, 0);
2158
2159 /* Search extensions for specific tag override. */
2160 if (!(flags & HEADERGET_NOEXTENSION))
2161 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
2162 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
2163 {
2164 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
2165 continue;
2166 if (!xstrcasecmp(ext->name + (sizeof("RPMTAG_")-1), name))
2167 break;
2168 }
2169
2170 if (ext && ext->name != NULL && ext->type == HEADER_EXT_TAG) {
2171 rc = ext->u.tagFunction(h, he);
2172 rc = (rc == 0); /* XXX invert extension return. */
2173 } else
2174 rc = intGetEntry(h, he, flags);
2175
2176 if (rc)
2177 rc = rpmheRealloc(he);
2178
2179 if (sw != NULL) (void) rpmswExit(sw, 0);
2180
2181 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
2182 /*@-modfilesys@*/
2183 /* XXX verify that explicit and implicit types are identical. */
2184 if (rc)
2185 tagTypeValidate(he);
2186 /*@=modfilesys@*/
2187 #endif
2188
2189 /*@-modfilesys@*/
2190 if (!((rc == 0 && he->freeData == 0 && he->p.ptr == NULL) ||
2191 (rc == 1 && he->freeData == 1 && he->p.ptr != NULL)))
2192 {
2193 if (_hdr_debug)
2194 fprintf(stderr, "==> %s(%u) %u %p[%u] free %u rc %d\n", name, (unsigned) he->tag, (unsigned) he->t, he->p.ptr, (unsigned) he->c, he->freeData, rc);
2195 }
2196 /*@=modfilesys@*/
2197
2198 return rc;
2199 }
2200
2201 int headerPut(Header h, HE_t he, /*@unused@*/ unsigned int flags)
2202 {
2203 int rc;
2204
2205 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
2206 /*@-modfilesys@*/
2207 /* XXX verify that explicit and implicit types are identical. */
2208 tagTypeValidate(he);
2209 /*@=modfilesys@*/
2210 #endif
2211
2212 if (he->append)
2213 rc = headerAddOrAppendEntry(h, he);
2214 else
2215 rc = headerAddEntry(h, he);
2216
2217 return rc;
2218 }
2219
2220 int headerDel(Header h, HE_t he, /*@unused@*/ unsigned int flags)
2221 /*@modifies h @*/
2222 {
2223 return headerRemoveEntry(h, he->tag);
2224 }
2225
2226 int headerMod(Header h, HE_t he, /*@unused@*/ unsigned int flags)
2227 /*@modifies h @*/
2228 {
2229
2230 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
2231 /*@-modfilesys@*/
2232 /* XXX verify that explicit and implicit types are identical. */
2233 tagTypeValidate(he);
2234 /*@=modfilesys@*/
2235 #endif
2236
2237 return headerModifyEntry(h, he);
2238 }