|
|
20850a |
commit da3a3a14e757ccd517e2eb2a3f0293ff48b3ff7f
|
|
|
20850a |
Author: Panu Matilainen <pmatilai@redhat.com>
|
|
|
20850a |
Date: Wed Feb 5 13:36:31 2014 +0200
|
|
|
20850a |
|
|
|
20850a |
A boolean flag is not sufficient to cover three different states...
|
|
|
20850a |
|
|
|
20850a |
- HEADERFLAG_SORTED flag bit has been used to track the header
|
|
|
20850a |
sort state since beginning of times, but the header sort actually
|
|
|
20850a |
has three different states: truly unsorted (such as after additions),
|
|
|
20850a |
sorted by index achieved with headerSort(), or sorted by offset which
|
|
|
20850a |
is creatively called headerUnsort() in the API.
|
|
|
20850a |
|
|
|
20850a |
There's exactly one place that requires offset sorting, namely
|
|
|
20850a |
headerExport(). It does call headerUnsort() explicitly, but
|
|
|
20850a |
headerUnsort() would not do anything unless the header was in
|
|
|
20850a |
index-sorted state. This is quite often the case, but data addition
|
|
|
20850a |
would unset the sorted-flag, and causing headerUnsort() not to
|
|
|
20850a |
do anything at all when it most certainly should have. That incorrect
|
|
|
20850a |
sorting caused headerExport() calculations to be wildly off.
|
|
|
20850a |
|
|
|
20850a |
This ancient bug was unearthed by the innocent looking
|
|
|
20850a |
commit eae671556470136c37951f53ca966cd1bd09aac4: prior to that,
|
|
|
20850a |
in half the cases headerSizeof() used to be called first, causing
|
|
|
20850a |
index-sorting to take place, after which the headerUnsort() in
|
|
|
20850a |
headerExport() did the right thing. In the other two cases
|
|
|
20850a |
headerSizeof() was called afterwards, and the headerExport() would
|
|
|
20850a |
be garbage in cases where new data had been just added, such as package
|
|
|
20850a |
installation. With headerExport() eliminating the need to call
|
|
|
20850a |
headerSizeof() all the cases became broken as the header would
|
|
|
20850a |
seem much bigger than it is due to the bad sort order and cause
|
|
|
20850a |
cases like RhBug:953719 where a largish header suddenly appears
|
|
|
20850a |
to be oversized, causing mysterious install failure. Prior to the
|
|
|
20850a |
commit (which in itself IS innocent) the issue would've mainly
|
|
|
20850a |
manifested in cases where the header needs to be rewritten, which
|
|
|
20850a |
only happens when files are replaced and the header is rewritten for that.
|
|
|
20850a |
|
|
|
20850a |
diff --git a/lib/header.c b/lib/header.c
|
|
|
20850a |
index ceffb32..f78ba78 100644
|
|
|
20850a |
--- a/lib/header.c
|
|
|
20850a |
+++ b/lib/header.c
|
|
|
20850a |
@@ -68,8 +68,13 @@ static const int typeSizes[16] = {
|
|
|
20850a |
0
|
|
|
20850a |
};
|
|
|
20850a |
|
|
|
20850a |
+enum headerSorted_e {
|
|
|
20850a |
+ HEADERSORT_NONE = 0, /* Not sorted */
|
|
|
20850a |
+ HEADERSORT_OFFSET = 1, /* Sorted by offset (on-disk format) */
|
|
|
20850a |
+ HEADERSORT_INDEX = 2, /* Sorted by index */
|
|
|
20850a |
+};
|
|
|
20850a |
+
|
|
|
20850a |
enum headerFlags_e {
|
|
|
20850a |
- HEADERFLAG_SORTED = (1 << 0), /*!< Are header entries sorted? */
|
|
|
20850a |
HEADERFLAG_ALLOCATED = (1 << 1), /*!< Is 1st header region allocated? */
|
|
|
20850a |
HEADERFLAG_LEGACY = (1 << 2), /*!< Header came from legacy source? */
|
|
|
20850a |
HEADERFLAG_DEBUG = (1 << 3), /*!< Debug this header? */
|
|
|
20850a |
@@ -87,6 +92,7 @@ struct headerToken_s {
|
|
|
20850a |
int indexAlloced; /*!< Allocated size of tag array. */
|
|
|
20850a |
unsigned int instance; /*!< Rpmdb instance (offset) */
|
|
|
20850a |
headerFlags flags;
|
|
|
20850a |
+ int sorted; /*!< Current sort method */
|
|
|
20850a |
int nrefs; /*!< Reference count. */
|
|
|
20850a |
};
|
|
|
20850a |
|
|
|
20850a |
@@ -169,7 +175,7 @@ static Header headerCreate(void *blob, unsigned int pvlen, int32_t indexLen)
|
|
|
20850a |
h->indexUsed = 0;
|
|
|
20850a |
}
|
|
|
20850a |
h->instance = 0;
|
|
|
20850a |
- h->flags |= HEADERFLAG_SORTED;
|
|
|
20850a |
+ h->sorted = HEADERSORT_NONE;
|
|
|
20850a |
|
|
|
20850a |
h->index = (h->indexAlloced
|
|
|
20850a |
? xcalloc(h->indexAlloced, sizeof(*h->index))
|
|
|
20850a |
@@ -219,9 +225,9 @@ static int indexCmp(const void * avp, const void * bvp)
|
|
|
20850a |
|
|
|
20850a |
void headerSort(Header h)
|
|
|
20850a |
{
|
|
|
20850a |
- if (!(h->flags & HEADERFLAG_SORTED)) {
|
|
|
20850a |
+ if (h->sorted != HEADERSORT_INDEX) {
|
|
|
20850a |
qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
|
|
|
20850a |
- h->flags |= HEADERFLAG_SORTED;
|
|
|
20850a |
+ h->sorted = HEADERSORT_INDEX;
|
|
|
20850a |
}
|
|
|
20850a |
}
|
|
|
20850a |
|
|
|
20850a |
@@ -242,9 +248,9 @@ static int offsetCmp(const void * avp, const void * bvp)
|
|
|
20850a |
|
|
|
20850a |
void headerUnsort(Header h)
|
|
|
20850a |
{
|
|
|
20850a |
- if (h->flags & HEADERFLAG_SORTED) {
|
|
|
20850a |
+ if (h->sorted != HEADERSORT_OFFSET) {
|
|
|
20850a |
qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
|
|
|
20850a |
- h->flags &= ~HEADERFLAG_SORTED;
|
|
|
20850a |
+ h->sorted = HEADERSORT_OFFSET;
|
|
|
20850a |
}
|
|
|
20850a |
}
|
|
|
20850a |
|
|
|
20850a |
@@ -721,7 +727,8 @@ indexEntry findEntry(Header h, rpmTagVal tag, rpm_tagtype_t type)
|
|
|
20850a |
struct indexEntry_s key;
|
|
|
20850a |
|
|
|
20850a |
if (h == NULL) return NULL;
|
|
|
20850a |
- if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
|
|
|
20850a |
+ if (h->sorted != HEADERSORT_INDEX)
|
|
|
20850a |
+ headerSort(h);
|
|
|
20850a |
|
|
|
20850a |
key.info.tag = tag;
|
|
|
20850a |
|
|
|
20850a |
@@ -907,7 +914,8 @@ Header headerImport(void * blob, unsigned int bsize, headerImportFlags flags)
|
|
|
20850a |
goto errxit;
|
|
|
20850a |
}
|
|
|
20850a |
|
|
|
20850a |
- h->flags &= ~HEADERFLAG_SORTED;
|
|
|
20850a |
+ /* Force sorting, dribble lookups can cause early sort on partial header */
|
|
|
20850a |
+ h->sorted = HEADERSORT_NONE;
|
|
|
20850a |
headerSort(h);
|
|
|
20850a |
h->flags |= HEADERFLAG_ALLOCATED;
|
|
|
20850a |
|
|
|
20850a |
@@ -1439,7 +1447,7 @@ static int intAddEntry(Header h, rpmtd td)
|
|
|
20850a |
entry->length = length;
|
|
|
20850a |
|
|
|
20850a |
if (h->indexUsed > 0 && td->tag < h->index[h->indexUsed-1].info.tag)
|
|
|
20850a |
- h->flags &= ~HEADERFLAG_SORTED;
|
|
|
20850a |
+ h->sorted = HEADERSORT_NONE;
|
|
|
20850a |
h->indexUsed++;
|
|
|
20850a |
|
|
|
20850a |
return 1;
|