--- rpm-5.4.7/rpmdb/package.c.rpmv3~ 2012-04-12 13:08:29.214493302 +0200 +++ rpm-5.4.7/rpmdb/package.c 2012-04-12 16:33:05.021039135 +0200 @@ -19,6 +19,8 @@ #include "rpmts.h" +#define _RPMEVR_INTERNAL +#include #include "debug.h" #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s)) @@ -79,6 +81,349 @@ static int pgpStashKeyid(pgpDig dig) } #endif +/*@-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 @*/ +{ + HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); + + char ** fileNames; + const char ** dirNames; + const char ** baseNames; + int32_t * 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)) { + he->tag = RPMTAG_OLDFILENAMES; + headerDel(h, he, 0); + return; /* Already converted. */ + } + + he->tag = RPMTAG_OLDFILENAMES; + if (!headerGet(h, he, 0)) + return; + + fileNames = he->p.ptr; + if (he->c <= 0) + return; + count = he->c; + + 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) { + + he->tag = RPMTAG_DIRINDEXES; + if (headerGet(h, he, 0)) + dirIndexes = he->p.ptr; + he->tag = RPMTAG_BASENAMES; + if (headerGet(h, he, 0)) + baseNames = he->p.ptr; + he->tag = RPMTAG_DIRNAMES; + if (headerGet(h, he, 0)) + dirNames = he->p.ptr; + + he->tag = RPMTAG_DIRINDEXES; + he->t = RPM_UINT32_TYPE; + he->p.ptr = dirIndexes; + he->c = count; + headerPut(h, he, 0); + + he->tag = RPMTAG_BASENAMES; + he->t = RPM_STRING_ARRAY_TYPE; + he->p.ptr = baseNames; + he->c = count; + headerPut(h, he, 0); + + he->tag = RPMTAG_DIRNAMES; + he->t = RPM_STRING_ARRAY_TYPE; + he->p.ptr = dirNames; + he->c = dirIndex +1; + headerPut(h,he,0); + } + + fileNames = _free(fileNames); + + he->tag = RPMTAG_OLDFILENAMES; + headerDel(h, he, 0); + +} +/*@=bounds@*/ + +/* copied verbatim from build/pack.c */ +static void providePackageNVR(Header h) +{ + HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); + const char *N, *V, *R; +#ifdef RPM_VENDOR_MANDRIVA + const char *D; + int gotD; +#endif + rpmuint32_t E; + int gotE; + const char *pEVR; + char *p; + rpmuint32_t pFlags = RPMSENSE_EQUAL; + const char ** provides = NULL; + const char ** providesEVR = NULL; + rpmuint32_t * provideFlags = NULL; + int providesCount; + int bingo = 1; + size_t nb; + int xx; + int i; + + /* Generate provides for this package N-V-R. */ + xx = headerNEVRA(h, &N, NULL, &V, &R, NULL); + if (!(N && V && R)) + return; + + nb = 21 + strlen(V) + 1 + strlen(R) + 1; +#ifdef RPM_VENDOR_MANDRIVA + he->tag = RPMTAG_DISTEPOCH; + gotD = headerGet(h, he, 0); + D = (he->p.str ? he->p.str : NULL); + nb += (gotD ? strlen(D) + 1 : 0); +#endif + pEVR = p = alloca(nb); + *p = '\0'; + he->tag = RPMTAG_EPOCH; + gotE = headerGet(h, he, 0); + E = (he->p.ui32p ? he->p.ui32p[0] : 0); + he->p.ptr = _free(he->p.ptr); + if (gotE) { + sprintf(p, "%d:", E); + p += strlen(p); + } + p = stpcpy( stpcpy( stpcpy(p, V) , "-") , R); +#ifdef RPM_VENDOR_MANDRIVA + if (gotD) { + p = stpcpy( stpcpy( p, ":"), D); + D = _free(D); + //(void) rpmlibNeedsFeature(h, "DistEpoch", "5.4.7-1"); + } +#endif + V = _free(V); + R = _free(R); + + /* + * Rpm prior to 3.0.3 does not have versioned provides. + * If no provides at all are available, we can just add. + */ + he->tag = RPMTAG_PROVIDENAME; +/*@-nullstate@*/ + xx = headerGet(h, he, 0); +/*@=nullstate@*/ + provides = he->p.argv; + providesCount = he->c; + if (!xx) + goto exit; + + /* + * Otherwise, fill in entries on legacy packages. + */ + he->tag = RPMTAG_PROVIDEVERSION; +/*@-nullstate@*/ + xx = headerGet(h, he, 0); +/*@=nullstate@*/ + providesEVR = he->p.argv; + if (!xx) { + for (i = 0; i < providesCount; i++) { + /*@observer@*/ + static const char * vdummy = ""; + static rpmsenseFlags fdummy = RPMSENSE_ANY; + + he->tag = RPMTAG_PROVIDEVERSION; + he->t = RPM_STRING_ARRAY_TYPE; + he->p.argv = &vdummy; + he->c = 1; + he->append = 1; +/*@-nullstate@*/ + xx = headerPut(h, he, 0); +/*@=nullstate@*/ + he->append = 0; + + he->tag = RPMTAG_PROVIDEFLAGS; + he->t = RPM_UINT32_TYPE; + he->p.ui32p = (void *) &fdummy; + he->c = 1; + he->append = 1; +/*@-nullstate@*/ + xx = headerPut(h, he, 0); +/*@=nullstate@*/ + he->append = 0; + } + goto exit; + } + + he->tag = RPMTAG_PROVIDEFLAGS; +/*@-nullstate@*/ + xx = headerGet(h, he, 0); +/*@=nullstate@*/ + provideFlags = he->p.ui32p; + + /*@-nullderef@*/ /* LCL: providesEVR is not NULL */ + if (provides && providesEVR && provideFlags) + for (i = 0; i < providesCount; i++) { + if (!(provides[i] && providesEVR[i])) + continue; + if (!(provideFlags[i] == RPMSENSE_EQUAL && + !strcmp(N, provides[i]) && !strcmp(pEVR, providesEVR[i]))) + continue; + bingo = 0; + break; + } + /*@=nullderef@*/ + +exit: +/*@-usereleased@*/ + provides = _free(provides); + providesEVR = _free(providesEVR); + provideFlags = _free(provideFlags); +/*@=usereleased@*/ + + if (bingo) { + he->tag = RPMTAG_PROVIDENAME; + he->t = RPM_STRING_ARRAY_TYPE; + he->p.argv = &N; + he->c = 1; + he->append = 1; +/*@-nullstate@*/ + xx = headerPut(h, he, 0); +/*@=nullstate@*/ + he->append = 0; + + /* XXX succeeds only at allocating the necessary appended space, + * not copying to it..? */ + xx = headerGet(h, he, 0); + he->p.argv[providesCount] = N; + xx = headerPut(h, he, 0); + _free(he->p.ptr); + + he->tag = RPMTAG_PROVIDEVERSION; + he->t = RPM_STRING_ARRAY_TYPE; + he->p.argv = &pEVR; + he->c = 1; + he->append = 1; +/*@-nullstate@*/ + xx = headerPut(h, he, 0); +/*@=nullstate@*/ + he->append = 0; + + he->tag = RPMTAG_PROVIDEFLAGS; + he->t = RPM_UINT32_TYPE; + he->p.ui32p = &pFlags; + he->c = 1; + he->append = 1; +/*@-nullstate@*/ + xx = headerPut(h, he, 0); +/*@=nullstate@*/ + he->append = 0; + } + N = _free(N); +} + +static void add_RPMTAG_SOURCERPM(Header h) +{ + if (!headerIsEntry(h, RPMTAG_SOURCERPM) && !headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) { + /* we have no way to know if this is a srpm or an rpm with no SOURCERPM */ + /* but since this is an old v3 rpm, we suppose it's not a srpm */ + HE_t he = (HE_t)memset(alloca(sizeof(*he)), 0, sizeof(*he)); + + he->tag = RPMTAG_SOURCERPM; + he->t = RPM_STRING_TYPE; + he->p.str = "\0"; + he->c = 1; + headerPut(h, he, 0); + } +} + +/* rpm v3 compatibility */ +static void rpm3to4(Header h) { + const char * rpmversion = NULL; + HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); + + he->tag = RPMTAG_RPMVERSION; + if (headerGet(h, he, 0)) { + rpmversion = he->p.str; + } + + if ((!rpmversion) || rpmversion[0] < '4') { + add_RPMTAG_SOURCERPM(h); + providePackageNVR(h); + compressFilelist(h); + } + rpmversion = _free(rpmversion); + return; +} + /*@-mods@*/ rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp) { @@ -383,6 +728,8 @@ exit: /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); + rpm3to4(h); + /* Bump reference count for return. */ *hdrp = headerLink(h); }