Skip to content

Commit

Permalink
Move headerConvert() and its helpers to headerutil.c
Browse files Browse the repository at this point in the history
This is not actual legacy material since rpm itself uses it all
the time. Header utility is a much more better classification.
No functional changes though.
  • Loading branch information
pmatilai committed Oct 24, 2016
1 parent c68fa9a commit ab24d7a
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 241 deletions.
2 changes: 1 addition & 1 deletion lib/Makefile.am
Expand Up @@ -37,7 +37,7 @@ librpm_la_SOURCES = \
rpmte.c rpmte_internal.h rpmts.c rpmfs.h rpmfs.c \
rpmvercmp.c signature.c signature.h transaction.c \
verify.c rpmlock.c rpmlock.h misc.h relocation.c \
rpmscript.h rpmscript.c legacy.c \
rpmscript.h rpmscript.c \
rpmchroot.c rpmchroot.h \
rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h \
rpmtriggers.h rpmtriggers.c
Expand Down
227 changes: 227 additions & 0 deletions lib/headerutil.c
Expand Up @@ -7,6 +7,7 @@
#include <rpm/rpmtypes.h>
#include <rpm/header.h>
#include <rpm/rpmstring.h>
#include <rpm/rpmds.h>

#include "debug.h"

Expand Down Expand Up @@ -189,3 +190,229 @@ int headerPutBin(Header h, rpmTagVal tag, const uint8_t *val, rpm_count_t size)
return headerPutType(h, tag, RPM_BIN_TYPE, val, size);
}

static int dncmp(const void * a, const void * b)
{
const char *const * first = a;
const char *const * second = b;
return strcmp(*first, *second);
}

static void compressFilelist(Header h)
{
struct rpmtd_s fileNames;
char ** dirNames;
const char ** baseNames;
uint32_t * dirIndexes;
rpm_count_t count, realCount = 0;
int i;
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)) {
headerDel(h, RPMTAG_OLDFILENAMES);
return; /* Already converted. */
}

if (!headerGet(h, RPMTAG_OLDFILENAMES, &fileNames, HEADERGET_MINMEM))
return;
count = rpmtdCount(&fileNames);
if (count < 1)
return;

dirNames = xmalloc(sizeof(*dirNames) * count); /* worst case */
baseNames = xmalloc(sizeof(*dirNames) * count);
dirIndexes = xmalloc(sizeof(*dirIndexes) * count);

/* HACK. Source RPM, so just do things differently */
{ const char *fn = rpmtdGetString(&fileNames);
if (fn && *fn != '/') {
dirIndex = 0;
dirNames[dirIndex] = xstrdup("");
while ((i = rpmtdNext(&fileNames)) >= 0) {
dirIndexes[i] = dirIndex;
baseNames[i] = rpmtdGetString(&fileNames);
realCount++;
}
goto exit;
}
}

/*
* XXX EVIL HACK, FIXME:
* This modifies (and then restores) a const string from rpmtd
* through basename retrieved from strrchr() which silently
* casts away const on return.
*/
while ((i = rpmtdNext(&fileNames)) >= 0) {
char ** needle;
char savechar;
char * baseName;
size_t len;
char *filename = (char *) rpmtdGetString(&fileNames); /* HACK HACK */

if (filename == NULL) /* XXX can't happen */
continue;
baseName = strrchr(filename, '/');
if (baseName == NULL) {
baseName = filename;
} else {
baseName += 1;
}
len = baseName - filename;
needle = dirNames;
savechar = *baseName;
*baseName = '\0';
if (dirIndex < 0 ||
(needle = bsearch(&filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
char *s = xmalloc(len + 1);
rstrlcpy(s, filename, len + 1);
dirIndexes[realCount] = ++dirIndex;
dirNames[dirIndex] = s;
} else
dirIndexes[realCount] = needle - dirNames;

*baseName = savechar;
baseNames[realCount] = baseName;
realCount++;
}

exit:
if (count > 0) {
headerPutUint32(h, RPMTAG_DIRINDEXES, dirIndexes, realCount);
headerPutStringArray(h, RPMTAG_BASENAMES, baseNames, realCount);
headerPutStringArray(h, RPMTAG_DIRNAMES,
(const char **) dirNames, dirIndex + 1);
}

rpmtdFreeData(&fileNames);
for (i = 0; i <= dirIndex; i++) {
free(dirNames[i]);
}
free(dirNames);
free(baseNames);
free(dirIndexes);

headerDel(h, RPMTAG_OLDFILENAMES);
}

static void expandFilelist(Header h)
{
struct rpmtd_s filenames;

if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
(void) headerGet(h, RPMTAG_FILENAMES, &filenames, HEADERGET_EXT);
if (rpmtdCount(&filenames) < 1)
return;
rpmtdSetTag(&filenames, RPMTAG_OLDFILENAMES);
headerPut(h, &filenames, HEADERPUT_DEFAULT);
rpmtdFreeData(&filenames);
}

(void) headerDel(h, RPMTAG_DIRNAMES);
(void) headerDel(h, RPMTAG_BASENAMES);
(void) headerDel(h, RPMTAG_DIRINDEXES);
}

/*
* Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
* Retrofit an explicit "Provides: name = epoch:version-release.
*/
static void providePackageNVR(Header h)
{
const char *name = headerGetString(h, RPMTAG_NAME);
char *pEVR = headerGetAsString(h, RPMTAG_EVR);
rpmsenseFlags pFlags = RPMSENSE_EQUAL;
int bingo = 1;
struct rpmtd_s pnames;
rpmds hds, nvrds;

/* Generate provides for this package name-version-release. */
if (!(name && pEVR))
return;

/*
* Rpm prior to 3.0.3 does not have versioned provides.
* If no provides at all are available, we can just add.
*/
if (!headerGet(h, RPMTAG_PROVIDENAME, &pnames, HEADERGET_MINMEM)) {
goto exit;
}

/*
* Otherwise, fill in entries on legacy packages.
*/
if (!headerIsEntry(h, RPMTAG_PROVIDEVERSION)) {
while (rpmtdNext(&pnames) >= 0) {
rpmsenseFlags fdummy = RPMSENSE_ANY;

headerPutString(h, RPMTAG_PROVIDEVERSION, "");
headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &fdummy, 1);
}
goto exit;
}

/* see if we already have this provide */
hds = rpmdsNew(h, RPMTAG_PROVIDENAME, 0);
nvrds = rpmdsSingle(RPMTAG_PROVIDENAME, name, pEVR, pFlags);
if (rpmdsFind(hds, nvrds) >= 0) {
bingo = 0;
}
rpmdsFree(hds);
rpmdsFree(nvrds);


exit:
if (bingo) {
headerPutString(h, RPMTAG_PROVIDENAME, name);
headerPutString(h, RPMTAG_PROVIDEVERSION, pEVR);
headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pFlags, 1);
}
rpmtdFreeData(&pnames);
free(pEVR);
}

static void legacyRetrofit(Header h)
{
/*
* The file list was moved to a more compressed format which not
* only saves memory (nice), but gives fingerprinting a nice, fat
* speed boost (very nice). Go ahead and convert old headers to
* the new style (this is a noop for new headers).
*/
compressFilelist(h);

/* Retrofit "Provide: name = EVR" for binary packages. */
if (!headerIsSource(h)) {
providePackageNVR(h);
}
}

int headerConvert(Header h, int op)
{
int rc = 1;

if (h == NULL)
return 0;

switch (op) {
case HEADERCONV_EXPANDFILELIST:
expandFilelist(h);
break;
case HEADERCONV_COMPRESSFILELIST:
compressFilelist(h);
break;
case HEADERCONV_RETROFIT_V3:
legacyRetrofit(h);
break;
default:
rc = 0;
break;
}
return rc;
};

0 comments on commit ab24d7a

Please sign in to comment.