--- ./lib/package.c 2006-07-26 14:45:41.000000000 +0200 +++ rpm-4.4.9/lib/package.c 2008-10-26 17:56:29.000000000 +0200 @@ -10,6 +10,7 @@ #include #include "rpmts.h" +#include "rpmevr.h" #include "misc.h" /* XXX stripTrailingChar() */ #include "rpmlead.h" @@ -94,6 +95,148 @@ */ #define hdrchkRange(_dl, _off) ((_off) < 0 || (_off) > (_dl)) +/*@-boundsread@*/ +static int dncmp(const void * a, const void * b) + /*@*/ +{ + const char *const * first = a; + const char *const * second = b; + return strcmp(*first, *second); +} +/*@=boundsread@*/ + +/*@-bounds@*/ +/** + * Convert absolute path tag to (dirname,basename,dirindex) tags. + * @param h header + */ +static void compressFilelist(Header h) + /*@modifies h @*/ +{ + HGE_t hge = (HGE_t)headerGetEntryMinMemory; + HAE_t hae = (HAE_t)headerAddEntry; + HRE_t hre = (HRE_t)headerRemoveEntry; + HFD_t hfd = headerFreeData; + char ** fileNames; + const char ** dirNames; + const char ** baseNames; + int_32 * dirIndexes; + rpmTagType fnt; + int count; + int i, xx; + int dirIndex = -1; + + /* + * This assumes the file list is already sorted, and begins with a + * single '/'. That assumption isn't critical, but it makes things go + * a bit faster. + */ + + if (headerIsEntry(h, RPMTAG_DIRNAMES)) { + xx = hre(h, RPMTAG_OLDFILENAMES); + return; /* Already converted. */ + } + + if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count)) + return; /* no file list */ + if (fileNames == NULL || count <= 0) + return; + + dirNames = alloca(sizeof(*dirNames) * count); /* worst case */ + baseNames = alloca(sizeof(*dirNames) * count); + dirIndexes = alloca(sizeof(*dirIndexes) * count); + + if (fileNames[0][0] != '/') { + /* HACK. Source RPM, so just do things differently */ + dirIndex = 0; + dirNames[dirIndex] = ""; + for (i = 0; i < count; i++) { + dirIndexes[i] = dirIndex; + baseNames[i] = fileNames[i]; + } + goto exit; + } + + /*@-branchstate@*/ + for (i = 0; i < count; i++) { + const char ** needle; + char savechar; + char * baseName; + int len; + + if (fileNames[i] == NULL) /* XXX can't happen */ + continue; + baseName = strrchr(fileNames[i], '/') + 1; + len = baseName - fileNames[i]; + needle = dirNames; + savechar = *baseName; + *baseName = '\0'; +/*@-compdef@*/ + if (dirIndex < 0 || + (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) { + char *s = alloca(len + 1); + memcpy(s, fileNames[i], len + 1); + s[len] = '\0'; + dirIndexes[i] = ++dirIndex; + dirNames[dirIndex] = s; + } else + dirIndexes[i] = needle - dirNames; +/*@=compdef@*/ + + *baseName = savechar; + baseNames[i] = baseName; + } + /*@=branchstate@*/ + +exit: + if (count > 0) { + xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count); + xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE, + baseNames, count); + xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE, + dirNames, dirIndex + 1); + } + + fileNames = hfd(fileNames, fnt); + + xx = hre(h, RPMTAG_OLDFILENAMES); +} +/*@=bounds@*/ + +/* rpm v3 compatibility */ +static void rpm3to4(Header h) { + char * rpmversion; + int_32 rpmversion_type; + + (void) headerGetEntry(h, RPMTAG_RPMVERSION, NULL, (void **) &rpmversion, &rpmversion_type); + + if ((!rpmversion) || rpmversion[0] < '4') { + int *epoch; + const char * name, *version, *release; + const char *pEVR; + char *p; + int_32 pFlags = RPMSENSE_EQUAL; + + if (headerNVR(h, &name, &version, &release) == 0) { + pEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1); + *p = '\0'; + if (headerGetEntry(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) { + sprintf(p, "%d:", *epoch); + while (*p != '\0') + p++; + } + (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release); + + headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE, &name, 1); + headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE, &pFlags, 1); + headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE, &pEVR, 1); + } + compressFilelist(h); + } + headerFreeTag(h, (void *) rpmversion, rpmversion_type); + return; +} + void headerMergeLegacySigs(Header h, const Header sigh) { HFD_t hfd = (HFD_t) headerFreeData; @@ -1062,6 +1205,8 @@ /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); + rpm3to4(h); + /* Bump reference count for return. */ /*@-boundswrite@*/ *hdrp = headerLink(h);