apply some patch for pythons rpm from opensource
[platform/upstream/rpm.git] / lib / header.c
1 /** \ingroup header
2  * \file lib/header.c
3  */
4
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 #include <netdb.h>
13 #include <errno.h>
14 #include <inttypes.h>
15 #include <rpm/rpmtypes.h>
16 #include <rpm/rpmstring.h>
17 #include "lib/header_internal.h"
18 #include "lib/misc.h"                   /* tag function proto */
19
20 #include <errno.h>
21 #include "debug.h"
22
23 /** \ingroup header
24  */
25 const unsigned char rpm_header_magic[8] = {
26         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
27 };
28
29 /** \ingroup header
30  * Alignment needed for header data types.
31  */
32 static const int typeAlign[16] =  {
33     1,  /*!< RPM_NULL_TYPE */
34     1,  /*!< RPM_CHAR_TYPE */
35     1,  /*!< RPM_INT8_TYPE */
36     2,  /*!< RPM_INT16_TYPE */
37     4,  /*!< RPM_INT32_TYPE */
38     8,  /*!< RPM_INT64_TYPE */
39     1,  /*!< RPM_STRING_TYPE */
40     1,  /*!< RPM_BIN_TYPE */
41     1,  /*!< RPM_STRING_ARRAY_TYPE */
42     1,  /*!< RPM_I18NSTRING_TYPE */
43     0,
44     0,
45     0,
46     0,
47     0,
48     0
49 };
50
51 /** \ingroup header
52  * Size of header data types.
53  */
54 static const int typeSizes[16] =  { 
55     0,  /*!< RPM_NULL_TYPE */
56     1,  /*!< RPM_CHAR_TYPE */
57     1,  /*!< RPM_INT8_TYPE */
58     2,  /*!< RPM_INT16_TYPE */
59     4,  /*!< RPM_INT32_TYPE */
60     8,  /*!< RPM_INT64_TYPE */
61     -1, /*!< RPM_STRING_TYPE */
62     1,  /*!< RPM_BIN_TYPE */
63     -1, /*!< RPM_STRING_ARRAY_TYPE */
64     -1, /*!< RPM_I18NSTRING_TYPE */
65     0,
66     0,
67     0,
68     0,
69     0,
70     0
71 };
72
73 enum headerSorted_e {
74     HEADERSORT_NONE     = 0,    /* Not sorted */
75     HEADERSORT_OFFSET   = 1,    /* Sorted by offset (on-disk format) */
76     HEADERSORT_INDEX    = 2,    /* Sorted by index  */
77 };
78
79 enum headerFlags_e {
80     HEADERFLAG_ALLOCATED = (1 << 1), /*!< Is 1st header region allocated? */
81     HEADERFLAG_LEGACY    = (1 << 2), /*!< Header came from legacy source? */
82     HEADERFLAG_DEBUG     = (1 << 3), /*!< Debug this header? */
83 };
84
85 typedef rpmFlags headerFlags;
86
87 /** \ingroup header
88  * A single tag from a Header.
89  */
90 typedef struct indexEntry_s * indexEntry;
91 struct indexEntry_s {
92     struct entryInfo_s info;    /*!< Description of tag data. */
93     rpm_data_t data;            /*!< Location of tag data. */
94     int length;                 /*!< No. bytes of data. */
95     int rdlen;                  /*!< No. bytes of data in region. */
96 };
97
98 /** \ingroup header
99  * The Header data structure.
100  */
101 struct headerToken_s {
102     void * blob;                /*!< Header region blob. */
103     indexEntry index;           /*!< Array of tags. */
104     int indexUsed;              /*!< Current size of tag array. */
105     int indexAlloced;           /*!< Allocated size of tag array. */
106     unsigned int instance;      /*!< Rpmdb instance (offset) */
107     headerFlags flags;
108     int sorted;                 /*!< Current sort method */
109     int nrefs;                  /*!< Reference count. */
110 };
111
112 /** \ingroup header
113  * Maximum no. of bytes permitted in a header.
114  */
115 static const size_t headerMaxbytes = (256*1024*1024);
116
117 #define INDEX_MALLOC_SIZE       8
118
119 #define ENTRY_IS_REGION(_e) \
120         (((_e)->info.tag >= RPMTAG_HEADERIMAGE) && ((_e)->info.tag < RPMTAG_HEADERREGIONS))
121 #define ENTRY_IN_REGION(_e)     ((_e)->info.offset < 0)
122
123 #define REGION_TAG_TYPE         RPM_BIN_TYPE
124 #define REGION_TAG_COUNT        sizeof(struct entryInfo_s)
125
126 /**
127  * Sanity check on no. of tags.
128  * This check imposes a limit of 65K tags, more than enough.
129  */
130 #define HEADER_TAGS_MAX 0x0000ffff
131 #define hdrchkTags(_ntags)      ((_ntags) & (~HEADER_TAGS_MAX))
132
133 /**
134  * Sanity check on tag values.
135  * Catches out nasties like negative values and multiple regions.
136  **/
137 #define hdrchkTag(_tag) ((_tag) < HEADER_I18NTABLE)
138
139 /**
140  * Sanity check on type values.
141  */
142 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
143
144 /**
145  * Sanity check on data size and/or offset and/or count.
146  * This check imposes a limit of 256 MB -- file signatures
147  * may require a lot of space in the header.
148  */
149 #define HEADER_DATA_MAX 0x0fffffff
150 #define hdrchkData(_nbytes) ((_nbytes) & (~HEADER_DATA_MAX))
151
152 /**
153  * Sanity check on data alignment for data type.
154  */
155 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
156
157 /**
158  * Sanity check on range of data offset.
159  */
160 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
161
162 static int dataLength(rpm_tagtype_t type, rpm_constdata_t p, rpm_count_t count,
163                          int onDisk, rpm_constdata_t pend);
164
165 #ifndef htonll
166 /* Convert a 64bit value to network byte order. */
167 RPM_GNUC_CONST
168 static uint64_t htonll(uint64_t n)
169 {
170 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
171     uint32_t *i = (uint32_t*)&n;
172     uint32_t b = i[0];
173     i[0] = htonl(i[1]);
174     i[1] = htonl(b);
175 #endif
176     return n;
177 }
178 #endif
179
180 Header headerLink(Header h)
181 {
182     if (h != NULL)
183         h->nrefs++;
184     return h;
185 }
186
187 static Header headerUnlink(Header h)
188 {
189     if (h != NULL)
190         h->nrefs--;
191     return NULL;
192 }
193
194 Header headerFree(Header h)
195 {
196     (void) headerUnlink(h);
197
198     if (h == NULL || h->nrefs > 0)
199         return NULL;
200
201     if (h->index) {
202         indexEntry entry = h->index;
203         int i;
204         for (i = 0; i < h->indexUsed; i++, entry++) {
205             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
206                 if (entry->length > 0) {
207                     int32_t * ei = entry->data;
208                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
209                     entry->data = NULL;
210                 }
211             } else if (!ENTRY_IN_REGION(entry)) {
212                 entry->data = _free(entry->data);
213             }
214             entry->data = NULL;
215         }
216         h->index = _free(h->index);
217     }
218
219     h = _free(h);
220     return NULL;
221 }
222
223 static Header headerCreate(void *blob, int32_t indexLen)
224 {
225     Header h = xcalloc(1, sizeof(*h));
226     if (blob) {
227         h->blob = blob;
228         h->indexAlloced = indexLen + 1;
229         h->indexUsed = indexLen;
230     } else {
231         h->indexAlloced = INDEX_MALLOC_SIZE;
232         h->indexUsed = 0;
233     }
234     h->instance = 0;
235     h->sorted = HEADERSORT_NONE;
236
237     h->index = (h->indexAlloced
238         ? xcalloc(h->indexAlloced, sizeof(*h->index))
239         : NULL);
240
241     h->nrefs = 0;
242     return headerLink(h);
243 }
244
245 Header headerNew(void)
246 {
247     return headerCreate(NULL, 0);
248 }
249
250 static rpmRC hdrblobVerifyInfo(hdrblob blob, char **emsg)
251 {
252     struct entryInfo_s info;
253     int i, len = 0;
254     int32_t end = 0;
255     const char *ds = (const char *) blob->dataStart;
256     int32_t il = (blob->regionTag) ? blob->il-1 : blob->il;
257     entryInfo pe = (blob->regionTag) ? blob->pe+1 : blob->pe;
258
259     for (i = 0; i < il; i++) {
260         ei2h(&pe[i], &info);
261
262         /* Previous data must not overlap */
263         if (end > info.offset)
264             goto err;
265
266         if (hdrchkTag(info.tag))
267             goto err;
268         if (hdrchkType(info.type))
269             goto err;
270         if (hdrchkAlign(info.type, info.offset))
271             goto err;
272         if (hdrchkRange(blob->dl, info.offset))
273             goto err;
274
275         /* Verify the data actually fits */
276         len = dataLength(info.type, ds + info.offset,
277                          info.count, 1, ds + blob->dl);
278         end = info.offset + len;
279         if (hdrchkRange(blob->dl, end) || len <= 0)
280             goto err;
281     }
282     return 0; /* Everything ok */
283
284 err:
285     if (emsg) {
286         rasprintf(emsg,
287                   _("tag[%d]: BAD, tag %d type %d offset %d count %d len %d"),
288                     i, info.tag, info.type, info.offset, info.count, len);
289     }
290     return i + 1;
291 }
292
293 static int indexCmp(const void * avp, const void * bvp)
294 {
295     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
296     return (ap->info.tag - bp->info.tag);
297 }
298
299 static void headerSort(Header h)
300 {
301     if (h->sorted != HEADERSORT_INDEX) {
302         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
303         h->sorted = HEADERSORT_INDEX;
304     }
305 }
306
307 static int offsetCmp(const void * avp, const void * bvp) 
308 {
309     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
310     int rc = (ap->info.offset - bp->info.offset);
311
312     if (rc == 0) {
313         /* Within a region, entries sort by address. Added drips sort by tag. */
314         if (ap->info.offset < 0)
315             rc = (((char *)ap->data) - ((char *)bp->data));
316         else
317             rc = (ap->info.tag - bp->info.tag);
318     }
319     return rc;
320 }
321
322 static void headerUnsort(Header h)
323 {
324     if (h->sorted != HEADERSORT_OFFSET) {
325         qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
326         h->sorted = HEADERSORT_OFFSET;
327     }
328 }
329
330 static inline unsigned int alignDiff(rpm_tagtype_t type, unsigned int alignsize)
331 {
332     int typesize = typeSizes[type];
333
334     if (typesize > 1) {
335         unsigned int diff = typesize - (alignsize % typesize);
336         if (diff != typesize)
337             return diff;
338     }
339     return 0;
340 }
341
342 unsigned headerSizeof(Header h, int magicp)
343 {
344     indexEntry entry;
345     unsigned int size = 0;
346     int i;
347
348     if (h == NULL)
349         return size;
350
351     headerSort(h);
352
353     if (magicp == HEADER_MAGIC_YES)
354         size += sizeof(rpm_header_magic);
355
356     size += 2 * sizeof(int32_t);        /* count of index entries */
357
358     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
359         /* Regions go in as is ... */
360         if (ENTRY_IS_REGION(entry)) {
361             size += entry->length;
362             /* Reserve space for legacy region tag + data */
363             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
364                 size += sizeof(struct entryInfo_s) + entry->info.count;
365             continue;
366         }
367
368         /* ... and region elements are skipped. */
369         if (entry->info.offset < 0)
370             continue;
371
372         /* Alignment */
373         size += alignDiff(entry->info.type, size);
374
375         size += sizeof(struct entryInfo_s) + entry->length;
376     }
377
378     return size;
379 }
380
381 /*
382  * Header string (array) size calculation, bounded if end is non-NULL.
383  * Return length (including \0 termination) on success, -1 on error.
384  */
385 static inline int strtaglen(const char *str, rpm_count_t c, const char *end)
386 {
387     const char *start = str;
388     const char *s;
389
390     if (end) {
391         if (str >= end)
392             return -1;
393         while ((s = memchr(start, '\0', end-start))) {
394             if (--c == 0 || s > end)
395                 break;
396             start = s + 1;
397         }
398     } else {
399         while ((s = strchr(start, '\0'))) {
400             if (--c == 0)
401                 break;
402             start = s + 1;
403         }
404     }
405     return (c > 0) ? -1 : (s - str + 1);
406 }
407
408 /**
409  * Return length of entry data.
410  * @param type          entry data type
411  * @param p             entry data
412  * @param count         entry item count
413  * @param onDisk        data is concatenated strings (with NUL's))?
414  * @param pend          pointer to end of data (or NULL)
415  * @return              no. bytes in data, -1 on failure
416  */
417 static int dataLength(rpm_tagtype_t type, rpm_constdata_t p, rpm_count_t count,
418                          int onDisk, rpm_constdata_t pend)
419 {
420     const char * s = p;
421     const char * se = pend;
422     int length = 0;
423
424     switch (type) {
425     case RPM_STRING_TYPE:
426         if (count != 1)
427             return -1;
428         length = strtaglen(s, 1, se);
429         break;
430
431     case RPM_STRING_ARRAY_TYPE:
432     case RPM_I18NSTRING_TYPE:
433         /* These are like RPM_STRING_TYPE, except they're *always* an array */
434         /* Compute sum of length of all strings, including nul terminators */
435
436         if (onDisk) {
437             length = strtaglen(s, count, se);
438         } else {
439             const char ** av = (const char **)p;
440             while (count--) {
441                 /* add one for null termination */
442                 length += strlen(*av++) + 1;
443             }
444         }
445         break;
446
447     default:
448         if (typeSizes[type] == -1)
449             return -1;
450         length = typeSizes[(type & 0xf)] * count;
451         if (length < 0 || (se && (s + length) > se))
452             return -1;
453         break;
454     }
455
456     return length;
457 }
458
459 /** \ingroup header
460  * Swap int32_t and int16_t arrays within header region.
461  *
462  * If a header region tag is in the set to be swabbed, as the data for a
463  * a header region is located after all other tag data.
464  *
465  * @param entry         header entry
466  * @param il            no. of entries
467  * @param dl            start no. bytes of data
468  * @param pe            header physical entry pointer (swapped)
469  * @param dataStart     header data start
470  * @param dataEnd       header data end
471  * @param regionid      region offset
472  * @param fast          use offsets for data sizes if possible
473  * @return              no. bytes of data in region, -1 on error
474  */
475 static int regionSwab(indexEntry entry, int il, int dl,
476                 entryInfo pe,
477                 unsigned char * dataStart,
478                 const unsigned char * dataEnd,
479                 int regionid, int fast)
480 {
481     if ((entry != NULL && regionid >= 0) || (entry == NULL && regionid != 0))
482         return -1;
483
484     for (; il > 0; il--, pe++) {
485         struct indexEntry_s ie;
486
487         ei2h(pe, &ie.info);
488
489         if (hdrchkType(ie.info.type))
490             return -1;
491         if (hdrchkData(ie.info.count))
492             return -1;
493         if (hdrchkData(ie.info.offset))
494             return -1;
495         if (hdrchkAlign(ie.info.type, ie.info.offset))
496             return -1;
497
498         ie.data = dataStart + ie.info.offset;
499         if (dataEnd && (unsigned char *)ie.data >= dataEnd)
500             return -1;
501
502         if (fast && il > 1) {
503             ie.length = ntohl(pe[1].offset) - ie.info.offset;
504         } else {
505             ie.length = dataLength(ie.info.type, ie.data, ie.info.count,
506                                    1, dataEnd);
507         }
508         if (ie.length < 0 || hdrchkData(ie.length))
509             return -1;
510
511         ie.rdlen = 0;
512
513         if (entry) {
514             ie.info.offset = regionid;
515             *entry = ie;        /* structure assignment */
516             entry++;
517         }
518
519         /* Alignment */
520         dl += alignDiff(ie.info.type, dl);
521
522         /* Perform endian conversions */
523         switch (ntohl(pe->type)) {
524         case RPM_INT64_TYPE:
525         {   uint64_t * it = ie.data;
526             for (; ie.info.count > 0; ie.info.count--, it += 1) {
527                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
528                     return -1;
529                 *it = htonll(*it);
530             }
531         }   break;
532         case RPM_INT32_TYPE:
533         {   int32_t * it = ie.data;
534             for (; ie.info.count > 0; ie.info.count--, it += 1) {
535                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
536                     return -1;
537                 *it = htonl(*it);
538             }
539         }   break;
540         case RPM_INT16_TYPE:
541         {   int16_t * it = ie.data;
542             for (; ie.info.count > 0; ie.info.count--, it += 1) {
543                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
544                     return -1;
545                 *it = htons(*it);
546             }
547         }   break;
548         }
549
550         dl += ie.length;
551     }
552
553     return dl;
554 }
555
556 void * headerExport(Header h, unsigned int *bsize)
557 {
558     int32_t * ei = NULL;
559     entryInfo pe;
560     char * dataStart;
561     char * te;
562     unsigned len, diff;
563     int32_t il = 0;
564     int32_t dl = 0;
565     indexEntry entry; 
566     int i;
567     int drlen, ndribbles;
568
569     if (h == NULL) return NULL;
570
571     /* Sort entries by (offset,tag). */
572     headerUnsort(h);
573
574     /* Compute (il,dl) for all tags, including those deleted in region. */
575     drlen = ndribbles = 0;
576     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
577         if (ENTRY_IS_REGION(entry)) {
578             int32_t rdl = -entry->info.offset;  /* negative offset */
579             int32_t ril = rdl/sizeof(*pe);
580             int rid = entry->info.offset;
581
582             il += ril;
583             dl += entry->rdlen + entry->info.count;
584             /* Reserve space for legacy region tag */
585             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
586                 il += 1;
587
588             /* Skip rest of entries in region, but account for dribbles. */
589             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
590                 if (entry->info.offset <= rid)
591                     continue;
592
593                 /* Alignment */
594                 diff = alignDiff(entry->info.type, dl);
595                 if (diff) {
596                     drlen += diff;
597                     dl += diff;    
598                 }
599
600                 ndribbles++;
601                 il++;
602                 drlen += entry->length;
603                 dl += entry->length;
604             }
605             i--;
606             entry--;
607             continue;
608         }
609
610         /* Ignore deleted drips. */
611         if (entry->data == NULL || entry->length <= 0)
612             continue;
613
614         /* Alignment */
615         dl += alignDiff(entry->info.type, dl);
616
617         il++;
618         dl += entry->length;
619     }
620
621     /* Sanity checks on header intro. */
622     if (hdrchkTags(il) || hdrchkData(dl))
623         goto errxit;
624
625     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
626
627     ei = xmalloc(len);
628     ei[0] = htonl(il);
629     ei[1] = htonl(dl);
630
631     pe = (entryInfo) &ei[2];
632     dataStart = te = (char *) (pe + il);
633
634     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
635         const char * src;
636         unsigned char *t;
637         int count;
638         int rdlen;
639         unsigned int diff;
640
641         if (entry->data == NULL || entry->length <= 0)
642             continue;
643
644         t = (unsigned char*)te;
645         pe->tag = htonl(entry->info.tag);
646         pe->type = htonl(entry->info.type);
647         pe->count = htonl(entry->info.count);
648
649         if (ENTRY_IS_REGION(entry)) {
650             int32_t rdl = -entry->info.offset;  /* negative offset */
651             int32_t ril = rdl/sizeof(*pe) + ndribbles;
652             int rid = entry->info.offset;
653
654             src = (char *)entry->data;
655             rdlen = entry->rdlen;
656
657             /* Legacy headers don't have regions originally, create one */
658             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
659                 int32_t stei[4];
660
661                 memcpy(pe+1, src, rdl);
662                 memcpy(te, src + rdl, rdlen);
663                 te += rdlen;
664
665                 pe->offset = htonl(te - dataStart);
666                 stei[0] = pe->tag;
667                 stei[1] = pe->type;
668                 stei[2] = htonl(-rdl-entry->info.count);
669                 stei[3] = pe->count;
670                 memcpy(te, stei, entry->info.count);
671                 te += entry->info.count;
672                 ril++;
673                 rdlen += entry->info.count;
674
675                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0, 0);
676                 if (count != rdlen)
677                     goto errxit;
678
679             } else {
680
681                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
682                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
683                 te += rdlen;
684                 {  
685                     entryInfo se = (entryInfo)src;
686                     int off = ntohl(se->offset);
687                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
688                 }
689                 te += entry->info.count + drlen;
690
691                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0, 0);
692                 if (count != (rdlen + entry->info.count + drlen))
693                     goto errxit;
694             }
695
696             /* Skip rest of entries in region. */
697             while (i < h->indexUsed && entry->info.offset <= rid+1) {
698                 i++;
699                 entry++;
700             }
701             i--;
702             entry--;
703             pe += ril;
704             continue;
705         }
706
707         /* Ignore deleted drips. */
708         if (entry->data == NULL || entry->length <= 0)
709             continue;
710
711         /* Alignment */
712         diff = alignDiff(entry->info.type, (te - dataStart));
713         if (diff) {
714             memset(te, 0, diff);
715             te += diff;
716         }
717
718         pe->offset = htonl(te - dataStart);
719
720         /* copy data w/ endian conversions */
721         switch (entry->info.type) {
722         case RPM_INT64_TYPE:
723             count = entry->info.count;
724             src = entry->data;
725             while (count--) {
726                 *((uint64_t *)te) = htonll(*((uint64_t *)src));
727                 te += sizeof(uint64_t);
728                 src += sizeof(uint64_t);
729             }
730             break;
731
732         case RPM_INT32_TYPE:
733             count = entry->info.count;
734             src = entry->data;
735             while (count--) {
736                 *((int32_t *)te) = htonl(*((int32_t *)src));
737                 te += sizeof(int32_t);
738                 src += sizeof(int32_t);
739             }
740             break;
741
742         case RPM_INT16_TYPE:
743             count = entry->info.count;
744             src = entry->data;
745             while (count--) {
746                 *((int16_t *)te) = htons(*((int16_t *)src));
747                 te += sizeof(int16_t);
748                 src += sizeof(int16_t);
749             }
750             break;
751
752         default:
753             memcpy(te, entry->data, entry->length);
754             te += entry->length;
755             break;
756         }
757         pe++;
758     }
759    
760     /* Insure that there are no memcpy underruns/overruns. */
761     if (((char *)pe) != dataStart)
762         goto errxit;
763     if ((((char *)ei)+len) != te)
764         goto errxit;
765
766     if (bsize)
767         *bsize = len;
768
769     headerSort(h);
770
771     return (void *) ei;
772
773 errxit:
774     free(ei);
775     return NULL;
776 }
777
778 void * headerUnload(Header h)
779 {
780     return headerExport(h, NULL);
781 }
782
783 /**
784  * Find matching (tag,type) entry in header.
785  * @param h             header
786  * @param tag           entry tag
787  * @param type          entry type
788  * @return              header entry
789  */
790 static
791 indexEntry findEntry(Header h, rpmTagVal tag, rpm_tagtype_t type)
792 {
793     indexEntry entry;
794     struct indexEntry_s key;
795
796     if (h == NULL) return NULL;
797     if (h->sorted != HEADERSORT_INDEX)
798         headerSort(h);
799
800     key.info.tag = tag;
801
802     entry = bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
803     if (entry == NULL)
804         return NULL;
805
806     if (type == RPM_NULL_TYPE)
807         return entry;
808
809     /* look backwards */
810     while (entry->info.tag == tag && entry->info.type != type &&
811            entry > h->index) entry--;
812
813     if (entry->info.tag == tag && entry->info.type == type)
814         return entry;
815
816     return NULL;
817 }
818
819 int headerDel(Header h, rpmTagVal tag)
820 {
821     indexEntry last = h->index + h->indexUsed;
822     indexEntry entry, first;
823     int ne;
824
825     entry = findEntry(h, tag, RPM_NULL_TYPE);
826     if (!entry) return 1;
827
828     /* Make sure entry points to the first occurrence of this tag. */
829     while (entry > h->index && (entry - 1)->info.tag == tag)  
830         entry--;
831
832     /* Free data for tags being removed. */
833     for (first = entry; first < last; first++) {
834         rpm_data_t data;
835         if (first->info.tag != tag)
836             break;
837         data = first->data;
838         first->data = NULL;
839         first->length = 0;
840         if (ENTRY_IN_REGION(first))
841             continue;
842         free(data);
843     }
844
845     ne = (first - entry);
846     if (ne > 0) {
847         h->indexUsed -= ne;
848         ne = last - first;
849         if (ne > 0)
850             memmove(entry, first, (ne * sizeof(*entry)));
851     }
852
853     return 0;
854 }
855
856 rpmRC hdrblobImport(hdrblob blob, int fast, Header *hdrp, char **emsg)
857 {
858     Header h = NULL;
859     indexEntry entry; 
860     int rdlen;
861
862     h = headerCreate(blob->ei, blob->il);
863
864     entry = h->index;
865     if (!(htonl(blob->pe->tag) < RPMTAG_HEADERI18NTABLE)) {
866         /* An original v3 header, create a legacy region entry for it */
867         h->flags |= HEADERFLAG_LEGACY;
868         entry->info.type = REGION_TAG_TYPE;
869         entry->info.tag = RPMTAG_HEADERIMAGE;
870         entry->info.count = REGION_TAG_COUNT;
871         entry->info.offset = ((unsigned char *)blob->pe - blob->dataStart); /* negative offset */
872
873         entry->data = blob->pe;
874         entry->length = blob->pvlen - sizeof(blob->il) - sizeof(blob->dl);
875         rdlen = regionSwab(entry+1, blob->il, 0, blob->pe,
876                            blob->dataStart, blob->dataEnd,
877                            entry->info.offset, fast);
878         if (rdlen != blob->dl)
879             goto errxit;
880         entry->rdlen = rdlen;
881         h->indexUsed++;
882     } else {
883         /* Either a v4 header or an "upgraded" v3 header with a legacy region */
884         int32_t ril;
885
886         h->flags &= ~HEADERFLAG_LEGACY;
887         ei2h(blob->pe, &entry->info);
888         ril = (entry->info.offset != 0) ? blob->ril : blob->il;
889
890         entry->info.offset = -(ril * sizeof(*blob->pe)); /* negative offset */
891         entry->data = blob->pe;
892         entry->length = blob->pvlen - sizeof(blob->il) - sizeof(blob->dl);
893         rdlen = regionSwab(entry+1, ril-1, 0, blob->pe+1,
894                            blob->dataStart, blob->dataEnd,
895                            entry->info.offset, fast);
896         if (rdlen < 0)
897             goto errxit;
898         entry->rdlen = rdlen;
899
900         if (ril < h->indexUsed) {
901             indexEntry newEntry = entry + ril;
902             int ne = (h->indexUsed - ril);
903             int rid = entry->info.offset+1;
904
905             /* Load dribble entries from region. */
906             rdlen = regionSwab(newEntry, ne, rdlen, blob->pe+ril,
907                                 blob->dataStart, blob->dataEnd, rid, fast);
908             if (rdlen < 0)
909                 goto errxit;
910
911           { indexEntry firstEntry = newEntry;
912             int save = h->indexUsed;
913             int j;
914
915             /* Dribble entries replace duplicate region entries. */
916             h->indexUsed -= ne;
917             for (j = 0; j < ne; j++, newEntry++) {
918                 (void) headerDel(h, newEntry->info.tag);
919                 if (newEntry->info.tag == RPMTAG_BASENAMES)
920                     (void) headerDel(h, RPMTAG_OLDFILENAMES);
921             }
922
923             /* If any duplicate entries were replaced, move new entries down. */
924             if (h->indexUsed < (save - ne)) {
925                 memmove(h->index + h->indexUsed, firstEntry,
926                         (ne * sizeof(*entry)));
927             }
928             h->indexUsed += ne;
929           }
930         }
931
932         rdlen += REGION_TAG_COUNT;
933
934         if (rdlen != blob->dl)
935             goto errxit;
936     }
937
938     /* Force sorting, dribble lookups can cause early sort on partial header */
939     h->sorted = HEADERSORT_NONE;
940     headerSort(h);
941     h->flags |= HEADERFLAG_ALLOCATED;
942     if (hdrp)
943         *hdrp = h;
944
945     /* We own the memory now, avoid double-frees */
946     blob->ei = NULL;
947
948     return RPMRC_OK;
949
950 errxit:
951     if (h) {
952         free(h->index);
953         free(h);
954         rasprintf(emsg, _("hdr load: BAD"));
955     }
956     return RPMRC_FAIL;
957 }
958
959 Header headerReload(Header h, rpmTagVal tag)
960 {
961     Header nh;
962     unsigned int uc = 0;
963     void * uh = headerExport(h, &uc);
964
965     h = headerFree(h);
966     if (uh == NULL)
967         return NULL;
968     nh = headerImport(uh, uc, 0);
969     if (nh == NULL) {
970         uh = _free(uh);
971         return NULL;
972     }
973     if (ENTRY_IS_REGION(nh->index)) {
974         if (tag == RPMTAG_HEADERSIGNATURES || tag == RPMTAG_HEADERIMMUTABLE)
975             nh->index[0].info.tag = tag;
976     }
977     return nh;
978 }
979
980 Header headerLoad(void * uh)
981 {
982     return headerImport(uh, 0, 0);
983 }
984
985 Header headerCopyLoad(const void * uh)
986 {
987     /* Discards const but that's ok as we'll take a copy */
988     return headerImport((void *)uh, 0, HEADERIMPORT_COPY);
989 }
990
991 Header headerRead(FD_t fd, int magicp)
992 {
993     Header h = NULL;
994     struct hdrblob_s blob;
995     char *buf = NULL;
996
997     if (hdrblobRead(fd, magicp, 0, 0, &blob, &buf) == RPMRC_OK)
998         hdrblobImport(&blob, 0, &h, &buf);
999
1000     free(buf);
1001     return h;
1002 }
1003
1004 int headerWrite(FD_t fd, Header h, int magicp)
1005 {
1006     ssize_t nb;
1007     unsigned int length;
1008     void * uh = headerExport(h, &length);
1009
1010     if (uh == NULL)
1011         return 1;
1012
1013     if (magicp == HEADER_MAGIC_YES) {
1014         nb = Fwrite(rpm_header_magic, sizeof(rpm_header_magic), 1, fd);
1015         if (nb != sizeof(rpm_header_magic))
1016             goto exit;
1017     }
1018
1019     nb = Fwrite(uh, sizeof(char), length, fd);
1020
1021 exit:
1022     free(uh);
1023     return (nb == length ? 0 : 1);
1024 }
1025
1026 int headerIsEntry(Header h, rpmTagVal tag)
1027 {
1028                 /* FIX: h modified by sort. */
1029     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
1030         
1031 }
1032
1033 /* simple heuristic to find out if the header is from * a source rpm
1034  * or not: source rpms contain at least the spec file and have all
1035  * files in one directory with an empty name.
1036  */
1037 int headerIsSourceHeuristic(Header h)
1038 {
1039     indexEntry entry = findEntry(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE);
1040     return entry && entry->info.count == 1 && entry->data && !*(const char *)entry->data;
1041 }
1042
1043 /** \ingroup header
1044  * Retrieve data from header entry.
1045  * Relevant flags (others are ignored), if neither is set allocation
1046  * behavior depends on data type(!) 
1047  *     HEADERGET_MINMEM: return pointers to header memory
1048  *     HEADERGET_ALLOC: always return malloced memory, overrides MINMEM
1049  * 
1050  * @todo Permit retrieval of regions other than HEADER_IMUTABLE.
1051  * @param entry         header entry
1052  * @param td            tag data container
1053  * @param flags         flags to control memory allocation
1054  * @return              1 on success, otherwise error.
1055  */
1056 static int copyTdEntry(const indexEntry entry, rpmtd td, headerGetFlags flags)
1057 {
1058     rpm_count_t count = entry->info.count;
1059     int rc = 1;         /* XXX 1 on success. */
1060     /* ALLOC overrides MINMEM */
1061     int allocMem = flags & HEADERGET_ALLOC;
1062     int minMem = allocMem ? 0 : flags & HEADERGET_MINMEM;
1063     int argvArray = (flags & HEADERGET_ARGV) ? 1 : 0;
1064
1065     assert(td != NULL);
1066     td->flags = RPMTD_IMMUTABLE;
1067     switch (entry->info.type) {
1068     case RPM_BIN_TYPE:
1069         /*
1070          * XXX This only works for
1071          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
1072          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
1073          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
1074          */
1075         if (ENTRY_IS_REGION(entry)) {
1076             int32_t * ei = ((int32_t *)entry->data) - 2;
1077             entryInfo pe = (entryInfo) (ei + 2);
1078             unsigned char * dataStart = (unsigned char *) (pe + ntohl(ei[0]));
1079             int32_t rdl = -entry->info.offset;  /* negative offset */
1080             int32_t ril = rdl/sizeof(*pe);
1081
1082             rdl = entry->rdlen;
1083             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
1084             if (entry->info.tag == RPMTAG_HEADERIMAGE) {
1085                 ril -= 1;
1086                 pe += 1;
1087             } else {
1088                 count += REGION_TAG_COUNT;
1089                 rdl += REGION_TAG_COUNT;
1090             }
1091
1092             td->data = xmalloc(count);
1093             ei = (int32_t *) td->data;
1094             ei[0] = htonl(ril);
1095             ei[1] = htonl(rdl);
1096
1097             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
1098
1099             dataStart = (unsigned char *) memcpy(pe + ril, dataStart, rdl);
1100
1101             rc = regionSwab(NULL, ril, 0, pe, dataStart, dataStart + rdl, 0, 0);
1102             /* don't return data on failure */
1103             if (rc < 0) {
1104                 td->data = _free(td->data);
1105             }
1106             /* XXX 1 on success. */
1107             rc = (rc < 0) ? 0 : 1;
1108         } else {
1109             count = entry->length;
1110             td->data = (!minMem
1111                 ? memcpy(xmalloc(count), entry->data, count)
1112                 : entry->data);
1113         }
1114         break;
1115     case RPM_STRING_TYPE:
1116         /* simple string, but fallthrough if its actually an array */
1117         if (count == 1 && !argvArray) {
1118             td->data = allocMem ? xstrdup(entry->data) : entry->data;
1119             break;
1120         }
1121     case RPM_STRING_ARRAY_TYPE:
1122     case RPM_I18NSTRING_TYPE:
1123     {   const char ** ptrEntry;
1124         int tableSize = (count + argvArray) * sizeof(char *);
1125         char * t;
1126         int i;
1127
1128         if (minMem) {
1129             td->data = xmalloc(tableSize);
1130             ptrEntry = (const char **) td->data;
1131             t = entry->data;
1132         } else {
1133             t = xmalloc(tableSize + entry->length);
1134             td->data = (void *)t;
1135             ptrEntry = (const char **) td->data;
1136             t += tableSize;
1137             memcpy(t, entry->data, entry->length);
1138         }
1139         for (i = 0; i < count; i++) {
1140             *ptrEntry++ = t;
1141             t = strchr(t, 0);
1142             t++;
1143         }
1144         if (argvArray) {
1145             *ptrEntry = NULL;
1146             td->flags |= RPMTD_ARGV;
1147         }
1148     }   break;
1149     case RPM_CHAR_TYPE:
1150     case RPM_INT8_TYPE:
1151     case RPM_INT16_TYPE:
1152     case RPM_INT32_TYPE:
1153     case RPM_INT64_TYPE:
1154         if (allocMem) {
1155             td->data = xmalloc(entry->length);
1156             memcpy(td->data, entry->data, entry->length);
1157         } else {
1158             td->data = entry->data;
1159         }
1160         break;
1161     default:
1162         /* WTH? Don't mess with unknown data types... */
1163         rc = 0;
1164         td->data = NULL;
1165         break;
1166     }
1167     td->type = entry->info.type;
1168     td->count = count;
1169     td->size = entry->length;
1170
1171     if (td->data && entry->data != td->data) {
1172         td->flags |= RPMTD_ALLOCED;
1173     }
1174
1175     return rc;
1176 }
1177
1178 /**
1179  * Does locale match entry in header i18n table?
1180  * 
1181  * \verbatim
1182  * The range [l,le) contains the next locale to match:
1183  *    ll[_CC][.EEEEE][@dddd]
1184  * where
1185  *    ll        ISO language code (in lowercase).
1186  *    CC        (optional) ISO coutnry code (in uppercase).
1187  *    EEEEE     (optional) encoding (not really standardized).
1188  *    dddd      (optional) dialect.
1189  * \endverbatim
1190  *
1191  * @param td            header i18n table data, NUL terminated
1192  * @param l             start of locale to match
1193  * @param le            end of locale to match
1194  * @return              1 on good match, 2 on weak match, 0 on no match
1195  */
1196 static int headerMatchLocale(const char *td, const char *l, const char *le)
1197 {
1198     const char *fe;
1199
1200     /* First try a complete match. */
1201     if (strlen(td) == (le-l) && rstreqn(td, l, (le - l)))
1202         return 1;
1203
1204     /* Next, try stripping optional dialect and matching.  */
1205     for (fe = l; fe < le && *fe != '@'; fe++)
1206         {};
1207     if (fe < le && rstreqn(td, l, (fe - l)))
1208         return 1;
1209
1210     /* Next, try stripping optional codeset and matching.  */
1211     for (fe = l; fe < le && *fe != '.'; fe++)
1212         {};
1213     if (fe < le && rstreqn(td, l, (fe - l)))
1214         return 1;
1215
1216     /* Finally, try stripping optional country code and matching. */
1217     for (fe = l; fe < le && *fe != '_'; fe++)
1218         {};
1219     if (fe < le && rstreqn(td, l, (fe - l)))
1220         return 2;
1221
1222     return 0;
1223 }
1224
1225 /**
1226  * Return i18n string from header that matches locale.
1227  * @param h             header
1228  * @param entry         i18n string data
1229  * @retval td           tag data container
1230  * @param flags         flags to control allocation
1231  * @return              1 always
1232  */
1233 static int copyI18NEntry(Header h, indexEntry entry, rpmtd td, 
1234                                                 headerGetFlags flags)
1235 {
1236     const char *lang, *l, *le;
1237     indexEntry table;
1238
1239     td->type = RPM_STRING_TYPE;
1240     td->count = 1;
1241     /* if no match, just return the first string */
1242     td->data = entry->data;
1243
1244     /* XXX Drepper sez' this is the order. */
1245     if ((lang = getenv("LANGUAGE")) == NULL &&
1246         (lang = getenv("LC_ALL")) == NULL &&
1247         (lang = getenv("LC_MESSAGES")) == NULL &&
1248         (lang = getenv("LANG")) == NULL)
1249             goto exit;
1250     
1251     if ((table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
1252         goto exit;
1253
1254     for (l = lang; *l != '\0'; l = le) {
1255         const char *t;
1256         char *ed, *ed_weak = NULL;
1257         int langNum;
1258
1259         while (*l && *l == ':')                 /* skip leading colons */
1260             l++;
1261         if (*l == '\0')
1262             break;
1263         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
1264             {};
1265
1266         /* For each entry in the header ... */
1267         for (langNum = 0, t = table->data, ed = entry->data;
1268              langNum < entry->info.count;
1269              langNum++, t += strlen(t) + 1, ed += strlen(ed) + 1) {
1270
1271             int match = headerMatchLocale(t, l, le);
1272             if (match == 1) {
1273                 td->data = ed;
1274                 goto exit;
1275             } else if (match == 2) { 
1276                 ed_weak = ed;
1277             }
1278         }
1279         if (ed_weak) {
1280             td->data = ed_weak;
1281             goto exit;
1282         }
1283     }
1284
1285 exit:
1286     if (flags & HEADERGET_ALLOC) {
1287         td->data = xstrdup(td->data);
1288         td->flags |= RPMTD_ALLOCED;
1289     }
1290
1291     return 1;
1292 }
1293
1294 /**
1295  * Retrieve tag data from header.
1296  * @param h             header
1297  * @retval td           tag data container
1298  * @param flags         flags to control retrieval
1299  * @return              1 on success, 0 on not found
1300  */
1301 static int intGetTdEntry(Header h, rpmtd td, headerGetFlags flags)
1302 {
1303     indexEntry entry;
1304     int rc;
1305
1306     /* First find the tag */
1307     /* FIX: h modified by sort. */
1308     entry = findEntry(h, td->tag, RPM_NULL_TYPE);
1309     if (entry == NULL) {
1310         /* Td is zeroed above, just return... */
1311         return 0;
1312     }
1313
1314     if (entry->info.type == RPM_I18NSTRING_TYPE && !(flags & HEADERGET_RAW))
1315         rc = copyI18NEntry(h, entry, td, flags);
1316     else
1317         rc = copyTdEntry(entry, td, flags);
1318
1319     if (rc == 0)
1320         td->flags |= RPMTD_INVALID;
1321
1322     /* XXX 1 on success */
1323     return ((rc == 1) ? 1 : 0);
1324 }
1325
1326 int headerGet(Header h, rpmTagVal tag, rpmtd td, headerGetFlags flags)
1327 {
1328     int rc;
1329     headerTagTagFunction tagfunc = intGetTdEntry;
1330
1331     if (td == NULL) return 0;
1332
1333     rpmtdReset(td);
1334     td->tag = tag;
1335
1336     if (flags & HEADERGET_EXT) {
1337         headerTagTagFunction extfunc = rpmHeaderTagFunc(tag);
1338         if (extfunc) tagfunc = extfunc;
1339     }
1340     rc = tagfunc(h, td, flags);
1341
1342     assert(tag == td->tag);
1343     return rc;
1344 }
1345
1346 /**
1347  */
1348 static void copyData(rpm_tagtype_t type, rpm_data_t dstPtr, 
1349                 rpm_constdata_t srcPtr, rpm_count_t cnt, int dataLength)
1350 {
1351     switch (type) {
1352     case RPM_STRING_ARRAY_TYPE:
1353     case RPM_I18NSTRING_TYPE:
1354     {   const char ** av = (const char **) srcPtr;
1355         char * t = dstPtr;
1356
1357         while (cnt-- > 0 && dataLength > 0) {
1358             const char * s;
1359             if ((s = *av++) == NULL)
1360                 continue;
1361             do {
1362                 *t++ = *s++;
1363             } while (s[-1] && --dataLength > 0);
1364         }
1365     }   break;
1366
1367     default:
1368         memmove(dstPtr, srcPtr, dataLength);
1369         break;
1370     }
1371 }
1372
1373 /**
1374  * Return (malloc'ed) copy of entry data.
1375  * @param type          entry data type
1376  * @param p             entry data
1377  * @param c             entry item count
1378  * @retval lengthPtr    no. bytes in returned data
1379  * @return              (malloc'ed) copy of entry data, NULL on error
1380  */
1381 static void *
1382 grabData(rpm_tagtype_t type, rpm_constdata_t p, rpm_count_t c, int * lengthPtr)
1383 {
1384     rpm_data_t data = NULL;
1385     int length;
1386
1387     length = dataLength(type, p, c, 0, NULL);
1388     if (length > 0) {
1389         data = xmalloc(length);
1390         copyData(type, data, p, c, length);
1391     }
1392
1393     if (lengthPtr)
1394         *lengthPtr = length;
1395     return data;
1396 }
1397
1398 static int intAddEntry(Header h, rpmtd td)
1399 {
1400     indexEntry entry;
1401     rpm_data_t data;
1402     int length = 0;
1403
1404     /* Count must always be >= 1 for headerAddEntry. */
1405     if (td->count <= 0)
1406         return 0;
1407
1408     if (hdrchkType(td->type))
1409         return 0;
1410     if (hdrchkData(td->count))
1411         return 0;
1412
1413     data = grabData(td->type, td->data, td->count, &length);
1414     if (data == NULL)
1415         return 0;
1416
1417     /* Allocate more index space if necessary */
1418     if (h->indexUsed == h->indexAlloced) {
1419         h->indexAlloced += INDEX_MALLOC_SIZE;
1420         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
1421     }
1422
1423     /* Fill in the index */
1424     entry = h->index + h->indexUsed;
1425     entry->info.tag = td->tag;
1426     entry->info.type = td->type;
1427     entry->info.count = td->count;
1428     entry->info.offset = 0;
1429     entry->data = data;
1430     entry->length = length;
1431
1432     if (h->indexUsed > 0 && td->tag < h->index[h->indexUsed-1].info.tag)
1433         h->sorted = HEADERSORT_NONE;
1434     h->indexUsed++;
1435
1436     return 1;
1437 }
1438
1439 static int intAppendEntry(Header h, rpmtd td)
1440 {
1441     indexEntry entry;
1442     int length;
1443
1444     if (td->type == RPM_STRING_TYPE || td->type == RPM_I18NSTRING_TYPE) {
1445         /* we can't do this */
1446         return 0;
1447     }
1448
1449     /* Find the tag entry in the header. */
1450     entry = findEntry(h, td->tag, td->type);
1451     if (!entry)
1452         return 0;
1453
1454     length = dataLength(td->type, td->data, td->count, 0, NULL);
1455     if (length < 0)
1456         return 0;
1457
1458     if (ENTRY_IN_REGION(entry)) {
1459         char * t = xmalloc(entry->length + length);
1460         memcpy(t, entry->data, entry->length);
1461         entry->data = t;
1462         entry->info.offset = 0;
1463     } else
1464         entry->data = xrealloc(entry->data, entry->length + length);
1465
1466     copyData(td->type, ((char *) entry->data) + entry->length, 
1467              td->data, td->count, length);
1468
1469     entry->length += length;
1470
1471     entry->info.count += td->count;
1472
1473     return 1;
1474 }
1475
1476 int headerPut(Header h, rpmtd td, headerPutFlags flags)
1477 {
1478     int rc;
1479     
1480     assert(td != NULL);
1481     if (flags & HEADERPUT_APPEND) {
1482         rc = findEntry(h, td->tag, td->type) ?
1483                 intAppendEntry(h, td) :
1484                 intAddEntry(h, td);
1485     } else {
1486         rc = intAddEntry(h, td);
1487     }
1488     return rc;
1489 }
1490
1491 int headerAddI18NString(Header h, rpmTagVal tag, const char * string,
1492                 const char * lang)
1493 {
1494     indexEntry table, entry;
1495     const char ** strArray;
1496     int length;
1497     int ghosts;
1498     rpm_count_t i, langNum;
1499     char * buf;
1500
1501     table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE);
1502     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
1503
1504     if (!table && entry)
1505         return 0;               /* this shouldn't ever happen!! */
1506
1507     if (!table && !entry) {
1508         const char * charArray[2];
1509         rpm_count_t count = 0;
1510         struct rpmtd_s td;
1511         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
1512             charArray[count++] = "C";
1513         } else {
1514             charArray[count++] = "C";
1515             charArray[count++] = lang;
1516         }
1517         
1518         rpmtdReset(&td);
1519         td.tag = RPMTAG_HEADERI18NTABLE;
1520         td.type = RPM_STRING_ARRAY_TYPE;
1521         td.data = (void *) charArray;
1522         td.count = count;
1523         if (!headerPut(h, &td, HEADERPUT_DEFAULT))
1524             return 0;
1525         table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE);
1526     }
1527
1528     if (!table)
1529         return 0;
1530     if (!lang) lang = "C";
1531
1532     {   const char * l = table->data;
1533         for (langNum = 0; langNum < table->info.count; langNum++) {
1534             if (rstreq(l, lang)) break;
1535             l += strlen(l) + 1;
1536         }
1537     }
1538
1539     if (langNum >= table->info.count) {
1540         length = strlen(lang) + 1;
1541         if (ENTRY_IN_REGION(table)) {
1542             char * t = xmalloc(table->length + length);
1543             memcpy(t, table->data, table->length);
1544             table->data = t;
1545             table->info.offset = 0;
1546         } else
1547             table->data = xrealloc(table->data, table->length + length);
1548         memmove(((char *)table->data) + table->length, lang, length);
1549         table->length += length;
1550         table->info.count++;
1551     }
1552
1553     if (!entry) {
1554         int rc;
1555         struct rpmtd_s td;
1556         strArray = xmalloc(sizeof(*strArray) * (langNum + 1));
1557         for (i = 0; i < langNum; i++)
1558             strArray[i] = "";
1559         strArray[langNum] = string;
1560
1561         rpmtdReset(&td);
1562         td.tag = tag;
1563         td.type = RPM_I18NSTRING_TYPE;
1564         td.data = strArray;
1565         td.count = langNum + 1;
1566         rc = headerPut(h, &td, HEADERPUT_DEFAULT);
1567         free(strArray);
1568         return rc;
1569     } else if (langNum >= entry->info.count) {
1570         ghosts = langNum - entry->info.count;
1571         
1572         length = strlen(string) + 1 + ghosts;
1573         if (ENTRY_IN_REGION(entry)) {
1574             char * t = xmalloc(entry->length + length);
1575             memcpy(t, entry->data, entry->length);
1576             entry->data = t;
1577             entry->info.offset = 0;
1578         } else
1579             entry->data = xrealloc(entry->data, entry->length + length);
1580
1581         memset(((char *)entry->data) + entry->length, '\0', ghosts);
1582         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
1583
1584         entry->length += length;
1585         entry->info.count = langNum + 1;
1586     } else {
1587         char *b, *be, *e, *ee, *t;
1588         size_t bn, sn, en;
1589
1590         /* Set beginning/end pointers to previous data */
1591         b = be = e = ee = entry->data;
1592         for (i = 0; i < table->info.count; i++) {
1593             if (i == langNum)
1594                 be = ee;
1595             ee += strlen(ee) + 1;
1596             if (i == langNum)
1597                 e  = ee;
1598         }
1599
1600         /* Get storage for new buffer */
1601         bn = (be-b);
1602         sn = strlen(string) + 1;
1603         en = (ee-e);
1604         length = bn + sn + en;
1605         t = buf = xmalloc(length);
1606
1607         /* Copy values into new storage */
1608         memcpy(t, b, bn);
1609         t += bn;
1610         memcpy(t, string, sn);
1611         t += sn;
1612         memcpy(t, e, en);
1613         t += en;
1614
1615         /* Replace i18N string array */
1616         entry->length -= strlen(be) + 1;
1617         entry->length += sn;
1618         
1619         if (ENTRY_IN_REGION(entry)) {
1620             entry->info.offset = 0;
1621         } else
1622             entry->data = _free(entry->data);
1623         entry->data = buf;
1624     }
1625
1626     return 0;
1627 }
1628
1629 int headerMod(Header h, rpmtd td)
1630 {
1631     indexEntry entry;
1632     rpm_data_t oldData;
1633     rpm_data_t data;
1634     int length = 0;
1635
1636     /* First find the tag */
1637     entry = findEntry(h, td->tag, td->type);
1638     if (!entry)
1639         return 0;
1640
1641     data = grabData(td->type, td->data, td->count, &length);
1642     if (data == NULL)
1643         return 0;
1644
1645     /* make sure entry points to the first occurrence of this tag */
1646     while (entry > h->index && (entry - 1)->info.tag == td->tag)  
1647         entry--;
1648
1649     /* free after we've grabbed the new data in case the two are intertwined;
1650        that's a bad idea but at least we won't break */
1651     oldData = entry->data;
1652
1653     entry->info.count = td->count;
1654     entry->info.type = td->type;
1655     entry->data = data;
1656     entry->length = length;
1657
1658     if (ENTRY_IN_REGION(entry)) {
1659         entry->info.offset = 0;
1660     } else
1661         free(oldData);
1662
1663     return 1;
1664 }
1665
1666 /**
1667  * Header tag iterator data structure.
1668  */
1669 struct headerIterator_s {
1670     Header h;           /*!< Header being iterated. */
1671     int next_index;     /*!< Next tag index. */
1672 };
1673
1674 HeaderIterator headerFreeIterator(HeaderIterator hi)
1675 {
1676     if (hi != NULL) {
1677         hi->h = headerFree(hi->h);
1678         hi = _free(hi);
1679     }
1680     return NULL;
1681 }
1682
1683 HeaderIterator headerInitIterator(Header h)
1684 {
1685     HeaderIterator hi = xmalloc(sizeof(*hi));
1686
1687     headerSort(h);
1688
1689     hi->h = headerLink(h);
1690     hi->next_index = 0;
1691     return hi;
1692 }
1693
1694 static indexEntry nextIndex(HeaderIterator hi)
1695 {
1696     Header h = hi->h;
1697     int slot;
1698     indexEntry entry = NULL;
1699
1700     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
1701         entry = h->index + slot;
1702         if (!ENTRY_IS_REGION(entry))
1703             break;
1704     }
1705     hi->next_index = slot;
1706     if (entry == NULL || slot >= h->indexUsed)
1707         return NULL;
1708
1709     hi->next_index++;
1710     return entry;
1711 }
1712
1713 rpmTagVal headerNextTag(HeaderIterator hi)
1714 {
1715     indexEntry entry = nextIndex(hi);
1716     return entry ? entry->info.tag : RPMTAG_NOT_FOUND;
1717 }
1718
1719 int headerNext(HeaderIterator hi, rpmtd td)
1720 {
1721     indexEntry entry = nextIndex(hi);
1722     int rc = 0;
1723
1724     rpmtdReset(td);
1725     if (entry) {
1726         td->tag = entry->info.tag;
1727         rc = copyTdEntry(entry, td, HEADERGET_DEFAULT);
1728     }
1729     return ((rc == 1) ? 1 : 0);
1730 }
1731
1732 unsigned int headerGetInstance(Header h)
1733 {
1734     return h ? h->instance : 0;
1735 }
1736
1737 void headerSetInstance(Header h, unsigned int instance)
1738 {
1739     h->instance = instance;
1740 }    
1741
1742 #define RETRY_ERROR(_err) \
1743     ((_err) == EINTR || (_err) == EAGAIN || (_err) == EWOULDBLOCK)
1744
1745 ssize_t Freadall(FD_t fd, void * buf, ssize_t size)
1746 {
1747     ssize_t total = 0;
1748     ssize_t nb = 0;
1749     char * bufp = buf;
1750
1751     while (total < size) {
1752         nb = Fread(bufp, 1, size - total, fd);
1753
1754         if (nb == 0 || (nb < 0 && !RETRY_ERROR(errno))) {
1755             total = nb;
1756             break;
1757         }
1758
1759         if (nb > 0) {
1760             bufp += nb;
1761             total += nb;
1762         }
1763     }
1764
1765     return total;
1766 }
1767
1768 static rpmRC hdrblobVerifyRegion(rpmTagVal regionTag, int exact_size,
1769                         hdrblob blob, char **buf)
1770 {
1771     rpmRC rc = RPMRC_FAIL;
1772     struct entryInfo_s trailer, einfo;
1773     unsigned char * regionEnd = NULL;
1774
1775     /* Check that we have at least on tag */
1776     if (blob->il < 1) {
1777         rasprintf(buf, _("region: no tags"));
1778         goto exit;
1779     }
1780
1781     /* Convert the 1st tag element. */
1782     ei2h(blob->pe, &einfo);
1783
1784     if (!regionTag && (einfo.tag == RPMTAG_HEADERSIGNATURES ||
1785                        einfo.tag == RPMTAG_HEADERIMMUTABLE ||
1786                        einfo.tag == RPMTAG_HEADERIMAGE)) {
1787         regionTag = einfo.tag;
1788     }
1789
1790     /* Is there an immutable header region tag? */
1791     if (!(einfo.tag == regionTag)) {
1792         rc = RPMRC_NOTFOUND;
1793         goto exit;
1794     }
1795
1796     /* Is the region tag sane? */
1797     if (!(einfo.type == REGION_TAG_TYPE && einfo.count == REGION_TAG_COUNT)) {
1798         rasprintf(buf,
1799                 _("region tag: BAD, tag %d type %d offset %d count %d"),
1800                 einfo.tag, einfo.type, einfo.offset, einfo.count);
1801         goto exit;
1802     }
1803
1804     /* Is the trailer within the data area? */
1805     if (hdrchkRange(blob->dl, einfo.offset + REGION_TAG_COUNT)) {
1806         rasprintf(buf,
1807                 _("region offset: BAD, tag %d type %d offset %d count %d"),
1808                 einfo.tag, einfo.type, einfo.offset, einfo.count);
1809         goto exit;
1810     }
1811
1812     /* Is there an immutable header region tag trailer? */
1813     memset(&trailer, 0, sizeof(trailer));
1814     regionEnd = blob->dataStart + einfo.offset;
1815     (void) memcpy(&trailer, regionEnd, REGION_TAG_COUNT);
1816     regionEnd += REGION_TAG_COUNT;
1817     blob->rdl = regionEnd - blob->dataStart;
1818
1819     ei2h(&trailer, &einfo);
1820     /* Trailer offset is negative and has a special meaning */
1821     einfo.offset = -einfo.offset;
1822     if (!(einfo.tag == regionTag &&
1823           einfo.type == REGION_TAG_TYPE && einfo.count == REGION_TAG_COUNT))
1824     {
1825         rasprintf(buf,
1826                 _("region trailer: BAD, tag %d type %d offset %d count %d"),
1827                 einfo.tag, einfo.type, einfo.offset, einfo.count);
1828         goto exit;
1829     }
1830
1831     /* Does the region actually fit within the header? */
1832     blob->ril = einfo.offset/sizeof(*blob->pe);
1833     if ((einfo.offset % sizeof(*blob->pe)) || hdrchkRange(blob->il, blob->ril) ||
1834                                         hdrchkRange(blob->dl, blob->rdl)) {
1835         rasprintf(buf, _("region %d size: BAD, ril %d il %d rdl %d dl %d"),
1836                         regionTag, blob->ril, blob->il, blob->rdl, blob->dl);
1837         goto exit;
1838     }
1839
1840     /* In package files region size is expected to match header size. */
1841     if (exact_size && !(blob->il == blob->ril && blob->dl == blob->rdl)) {
1842         rasprintf(buf,
1843                 _("region %d: tag number mismatch il %d ril %d dl %d rdl %d\n"),
1844                 regionTag, blob->il, blob->ril, blob->dl, blob->rdl);
1845         goto exit;
1846     }
1847
1848     blob->regionTag = regionTag;
1849     rc = RPMRC_OK;
1850
1851 exit:
1852     return rc;
1853 }
1854
1855
1856 static rpmRC hdrblobVerifyLengths(rpmTagVal regionTag, uint32_t il, uint32_t dl,
1857                                   char **emsg) {
1858     uint32_t il_max = HEADER_TAGS_MAX;
1859     uint32_t dl_max = HEADER_DATA_MAX;
1860     if (regionTag == RPMTAG_HEADERSIGNATURES) {
1861         il_max = 32;
1862         dl_max = 64 * 1024 * 1024;
1863     }
1864     if (hdrchkRange(il_max, il)) {
1865         rasprintf(emsg, _("hdr tags: BAD, no. of tags(%" PRIu32 ") out of range"), il);
1866         return RPMRC_FAIL;
1867     }
1868     if (hdrchkRange(dl_max, dl)) {
1869         rasprintf(emsg, _("hdr data: BAD, no. of bytes(%" PRIu32 ") out of range"), dl);
1870         return RPMRC_FAIL;
1871     }
1872     return RPMRC_OK;
1873 }
1874 rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrblob blob, char **emsg)
1875 {
1876     int32_t block[4];
1877     int32_t *bs = (magic != 0) ? &block[0] : &block[2];
1878     int blen = (magic != 0) ? sizeof(block) : sizeof(block) / 2;
1879     int32_t il;
1880     int32_t dl;
1881     int32_t * ei = NULL;
1882     size_t uc;
1883     size_t nb;
1884     rpmRC rc = RPMRC_FAIL;              /* assume failure */
1885     int xx;
1886
1887     memset(block, 0, sizeof(block));
1888     if ((xx = Freadall(fd, bs, blen)) != blen) {
1889         rasprintf(emsg,
1890                 _("hdr size(%d): BAD, read returned %d"), blen, xx);
1891         goto exit;
1892     }
1893     if (magic && memcmp(block, rpm_header_magic, sizeof(rpm_header_magic))) {
1894         rasprintf(emsg, _("hdr magic: BAD"));
1895         goto exit;
1896     }
1897     il = ntohl(block[2]);
1898     dl = ntohl(block[3]);
1899     if (hdrblobVerifyLengths(regionTag, il, dl, emsg))
1900         goto exit;
1901
1902     nb = (il * sizeof(struct entryInfo_s)) + dl;
1903     uc = sizeof(il) + sizeof(dl) + nb;
1904     ei = xmalloc(uc);
1905     ei[0] = block[2];
1906     ei[1] = block[3];
1907     if ((xx = Freadall(fd, (char *)&ei[2], nb)) != nb) {
1908         rasprintf(emsg, _("hdr blob(%zd): BAD, read returned %d"), nb, xx);
1909         goto exit;
1910     }
1911
1912     if (regionTag == RPMTAG_HEADERSIGNATURES) {
1913         size_t sigSize = uc + sizeof(rpm_header_magic);
1914         size_t pad = (8 - (sigSize % 8)) % 8;
1915         size_t trc;
1916         if (pad && (trc = Freadall(fd, block, pad)) != pad) {
1917             rasprintf(emsg, _("sigh pad(%zd): BAD, read %zd bytes"), pad, trc);
1918             goto exit;
1919         }
1920     }
1921
1922     rc = hdrblobInit(ei, uc, regionTag, exact_size, blob, emsg);
1923
1924 exit:
1925     if (rc != RPMRC_OK) {
1926         free(ei);
1927         blob->ei = NULL;
1928         if (emsg && *emsg && regionTag == RPMTAG_HEADERSIGNATURES) {
1929             /* rstrscat() cannot handle overlap even if it claims so */
1930             char *tmp = rstrscat(NULL, _("signature "), *emsg, NULL);
1931             free(*emsg);
1932             *emsg = tmp;
1933         }
1934     }
1935
1936     return rc;
1937 }
1938
1939 rpmRC hdrblobInit(const void *uh, size_t uc,
1940                 rpmTagVal regionTag, int exact_size,
1941                 struct hdrblob_s *blob, char **emsg)
1942 {
1943     rpmRC rc = RPMRC_FAIL;
1944     memset(blob, 0, sizeof(*blob));
1945     if (uc && uc < 8) {
1946         rasprintf(emsg, _("hdr length: BAD"));
1947         goto exit;
1948     }
1949
1950     blob->ei = (int32_t *) uh; /* discards const */
1951     blob->il = ntohl((uint32_t)(blob->ei[0]));
1952     blob->dl = ntohl((uint32_t)(blob->ei[1]));
1953     if (hdrblobVerifyLengths(regionTag, blob->il, blob->dl, emsg) != RPMRC_OK)
1954         goto exit;
1955
1956     blob->pe = (entryInfo) &(blob->ei[2]);
1957     blob->pvlen = sizeof(blob->il) + sizeof(blob->dl) +
1958                   (blob->il * sizeof(*blob->pe)) + blob->dl;
1959     blob->dataStart = (uint8_t *) (blob->pe + blob->il);
1960     blob->dataEnd = blob->dataStart + blob->dl;
1961
1962     /* Is the blob the right size? */
1963     if (blob->pvlen >= headerMaxbytes || (uc && blob->pvlen != uc)) {
1964         rasprintf(emsg, _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)"),
1965                         blob->pvlen, blob->il, blob->dl);
1966         goto exit;
1967     }
1968
1969     if (hdrblobVerifyRegion(regionTag, exact_size, blob, emsg) == RPMRC_FAIL)
1970         goto exit;
1971
1972     /* Sanity check the rest of the header structure. */
1973     if (hdrblobVerifyInfo(blob, emsg))
1974         goto exit;
1975
1976     rc = RPMRC_OK;
1977
1978 exit:
1979     return rc;
1980 }
1981
1982 rpmRC hdrblobGet(hdrblob blob, uint32_t tag, rpmtd td)
1983 {
1984     rpmRC rc = RPMRC_NOTFOUND;
1985     struct indexEntry_s entry;
1986     struct entryInfo_s einfo;
1987     const struct entryInfo_s *pe = blob->pe;
1988     uint32_t ntag = htonl(tag);
1989     int tsize;
1990
1991     memset(&einfo, 0, sizeof(einfo));
1992     rpmtdReset(td);
1993
1994     for (int i = 1; i < blob->il; i++, pe++) {
1995         if (pe->tag != ntag)
1996             continue;
1997         ei2h(pe, &einfo);
1998
1999         /* We can only handle non-byteswappable data */
2000         tsize = typeSizes[einfo.type];
2001         if (tsize != 1 && tsize != -1)
2002             return RPMRC_FAIL;
2003
2004         entry.info = einfo; /* struct assignment */
2005         entry.data = blob->dataStart + einfo.offset;
2006         entry.length = dataLength(einfo.type, blob->dataStart + einfo.offset,
2007                          einfo.count, 1, blob->dataEnd);
2008         entry.rdlen = 0;
2009         td->tag = einfo.tag;
2010         rc = copyTdEntry(&entry, td, HEADERGET_MINMEM) ? RPMRC_OK : RPMRC_FAIL;
2011         break;
2012     }
2013     return rc;
2014 }
2015
2016 Header headerImport(void * blob, unsigned int bsize, headerImportFlags flags)
2017 {
2018     Header h = NULL;
2019     struct hdrblob_s hblob;
2020     char *buf = NULL;
2021     void * b = blob;
2022
2023     if (flags & HEADERIMPORT_COPY) {
2024         if (bsize == 0 && hdrblobInit(b, 0, 0, 0, &hblob, &buf) == RPMRC_OK)
2025             bsize = hblob.pvlen;
2026         if (bsize == 0)
2027             goto exit;
2028         b = memcpy(xmalloc(bsize), b, bsize);
2029     }
2030
2031     /* Sanity checks on header intro. */
2032     if (hdrblobInit(b, bsize, 0, 0, &hblob, &buf) == RPMRC_OK)
2033         hdrblobImport(&hblob, (flags & HEADERIMPORT_FAST), &h, &buf);
2034
2035 exit:
2036     if (h == NULL && b != blob)
2037         free(b);
2038     free(buf);
2039
2040     return h;
2041 }