rpm  5.2.1
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@*/
80 /*@unchecked@*/
81 static struct rpmop_s hdr_getops;
82 /*@unchecked@*/ /*@relnull@*/
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) {
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@*/
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 
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));
183  h->indexUsed = 0;
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
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
245  /*@modifies h @*/
246 {
247  qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
248 }
249 
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 
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:
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:
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
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));
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@*/
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)
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 
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 
1224 {
1225  return (h != NULL ? h->instance : 0);
1226 }
1227 
1229 {
1230  if (h != NULL)
1231  h->instance = instance;
1232  return 0;
1233 }
1234 
1236 {
1237  return (h != NULL ? h->startoff : 0);
1238 }
1239 
1241 {
1242  if (h != NULL)
1243  h->startoff = startoff;
1244  return 0;
1245 }
1246 
1248 {
1249  return (h != NULL ? h->endoff : 0);
1250 }
1251 
1253 {
1254  if (h != NULL)
1255  h->endoff = endoff;
1256  return 0;
1257 }
1258 
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 
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 *
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
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) {
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
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
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 
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
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 
2038  size_t next_index;
2039 };
2040 
2042 {
2043  if (hi != NULL) {
2044  (void)headerFree(hi->h);
2045  hi->h = NULL;
2046  hi = _free(hi);
2047  }
2048  return hi;
2049 }
2050 
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 
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;
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 }