summaryrefslogtreecommitdiff
path: root/lib/rpmal.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rpmal.c')
-rw-r--r--lib/rpmal.c406
1 files changed, 406 insertions, 0 deletions
diff --git a/lib/rpmal.c b/lib/rpmal.c
new file mode 100644
index 0000000..2f934c7
--- /dev/null
+++ b/lib/rpmal.c
@@ -0,0 +1,406 @@
+/** \ingroup rpmdep
+ * \file lib/rpmal.c
+ */
+
+#include "system.h"
+
+
+#include <rpm/rpmds.h>
+#include <rpm/rpmte.h>
+#include <rpm/rpmfi.h>
+
+#include "lib/rpmal.h"
+#include "lib/misc.h"
+#include "lib/rpmte_internal.h"
+
+#include "debug.h"
+
+typedef struct availablePackage_s * availablePackage;
+typedef int rpmalNum;
+
+/** \ingroup rpmdep
+ * Info about a single package to be installed.
+ */
+struct availablePackage_s {
+ rpmte p; /*!< transaction member */
+ rpmds provides; /*!< Provides: dependencies. */
+ rpmfi fi; /*!< File info set. */
+};
+
+/** \ingroup rpmdep
+ * A single available item (e.g. a Provides: dependency).
+ */
+typedef struct availableIndexEntry_s {
+ rpmalNum pkgNum; /*!< Containing package index. */
+ unsigned int entryIx; /*!< Dependency index. */
+} * availableIndexEntry;
+
+struct fileNameEntry_s {
+ const char * dirName;
+ const char * baseName;
+};
+
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
+#define HASHTYPE rpmalProvidesHash
+#define HTKEYTYPE const char *
+#define HTDATATYPE struct availableIndexEntry_s
+#include "lib/rpmhash.H"
+#include "lib/rpmhash.C"
+
+#undef HASHTYPE
+#undef HTKEYTYPE
+#undef HTDATATYPE
+#define HASHTYPE rpmalFileHash
+#define HTKEYTYPE struct fileNameEntry_s
+#define HTDATATYPE struct availableIndexEntry_s
+#include "lib/rpmhash.H"
+#include "lib/rpmhash.C"
+
+/** \ingroup rpmdep
+ * Set of available packages, items, and directories.
+ */
+struct rpmal_s {
+ availablePackage list; /*!< Set of packages. */
+ rpmalProvidesHash providesHash;
+ rpmalFileHash fileHash;
+ int delta; /*!< Delta for pkg list reallocation. */
+ int size; /*!< No. of pkgs in list. */
+ int alloced; /*!< No. of pkgs allocated for list. */
+ rpm_color_t tscolor; /*!< Transaction color. */
+ rpm_color_t prefcolor; /*!< Transaction preferred color. */
+};
+
+/**
+ * Destroy available item index.
+ * @param al available list
+ */
+static void rpmalFreeIndex(rpmal al)
+{
+ al->providesHash = rpmalProvidesHashFree(al->providesHash);
+ al->fileHash = rpmalFileHashFree(al->fileHash);
+}
+
+rpmal rpmalCreate(int delta, rpm_color_t tscolor, rpm_color_t prefcolor)
+{
+ rpmal al = xcalloc(1, sizeof(*al));
+
+ al->delta = delta;
+ al->size = 0;
+ al->alloced = al->delta;
+ al->list = xmalloc(sizeof(*al->list) * al->alloced);;
+
+ al->providesHash = NULL;
+ al->fileHash = NULL;
+ al->tscolor = tscolor;
+ al->prefcolor = prefcolor;
+
+ return al;
+}
+
+rpmal rpmalFree(rpmal al)
+{
+ availablePackage alp;
+ int i;
+
+ if (al == NULL)
+ return NULL;
+
+ if ((alp = al->list) != NULL)
+ for (i = 0; i < al->size; i++, alp++) {
+ alp->provides = rpmdsFree(alp->provides);
+ alp->fi = rpmfiFree(alp->fi);
+ }
+ al->list = _free(al->list);
+ al->alloced = 0;
+
+ rpmalFreeIndex(al);
+ al = _free(al);
+ return NULL;
+}
+
+static unsigned int fileHash(struct fileNameEntry_s file){
+ return hashFunctionString(file.dirName) ^ hashFunctionString(file.baseName);
+}
+
+static int fileCompare(struct fileNameEntry_s one, struct fileNameEntry_s two) {
+ int rc = 0;
+ rc = strcmp(one.dirName, two.dirName);
+ if (!rc)
+ rc = strcmp(one.baseName, two.baseName);
+ return rc;
+}
+
+void rpmalDel(rpmal al, rpmte p)
+{
+ availablePackage alp;
+ rpmalNum pkgNum;
+
+ if (al == NULL || al->list == NULL)
+ return; /* XXX can't happen */
+
+ // XXX use a search for self provide
+ for (pkgNum=0; pkgNum<al->size; pkgNum++) {
+ if (al->list[pkgNum].p == p) {
+ break;
+ }
+ }
+ if (pkgNum == al->size ) return; // Not found!
+
+ alp = al->list + pkgNum;
+ // do not actually delete, just set p to NULL
+ // and later filter that out of the results
+ alp->p = NULL;
+}
+
+static void rpmalAddFiles(rpmal al, rpmalNum pkgNum, rpmfi fi){
+ struct fileNameEntry_s fileName;
+ struct availableIndexEntry_s fileEntry;
+ int i;
+ rpm_color_t ficolor;
+
+ fileEntry.pkgNum = pkgNum;
+
+ fi = rpmfiInit(fi, 0);
+ while ((i = rpmfiNext(fi)) >= 0) {
+ /* Ignore colored provides not in our rainbow. */
+ ficolor = rpmfiFColor(fi);
+ if (al->tscolor && ficolor && !(al->tscolor & ficolor))
+ continue;
+
+ fileName.dirName = rpmfiDN(fi);
+ fileName.baseName = rpmfiBN(fi);
+
+ fileEntry.entryIx = i;
+
+ rpmalFileHashAddEntry(al->fileHash, fileName, fileEntry);
+ }
+}
+
+static void rpmalAddProvides(rpmal al, rpmalNum pkgNum, rpmds provides){
+ struct availableIndexEntry_s indexEntry;
+ rpm_color_t dscolor;
+
+ indexEntry.pkgNum = pkgNum;
+
+ if (rpmdsInit(provides) != NULL)
+ while (rpmdsNext(provides) >= 0) {
+ /* Ignore colored provides not in our rainbow. */
+ dscolor = rpmdsColor(provides);
+ if (al->tscolor && dscolor && !(al->tscolor & dscolor))
+ continue;
+
+ indexEntry.entryIx = rpmdsIx(provides);
+ rpmalProvidesHashAddEntry(al->providesHash, rpmdsN(provides), indexEntry);
+ }
+}
+
+void rpmalAdd(rpmal al, rpmte p)
+{
+ rpmalNum pkgNum;
+ availablePackage alp;
+
+ if (al->size == al->alloced) {
+ al->alloced += al->delta;
+ al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
+ }
+ pkgNum = al->size++;
+
+ alp = al->list + pkgNum;
+
+ alp->p = p;
+
+ alp->provides = rpmdsLink(rpmteDS(p, RPMTAG_PROVIDENAME));
+ alp->fi = rpmfiLink(rpmteFI(p));
+
+ if (al->providesHash != NULL) { // index is already created
+ rpmalAddProvides(al, pkgNum, alp->provides);
+ rpmalAddFiles(al, pkgNum, alp->fi);
+ }
+
+ assert(((rpmalNum)(alp - al->list)) == pkgNum);
+}
+
+static void rpmalMakeIndex(rpmal al)
+{
+ availablePackage alp;
+ int i;
+ int providesCnt = 0;
+ int fileCnt = 0;
+
+ if (al == NULL || al->list == NULL) return;
+ if (al->providesHash != NULL || al->fileHash != NULL)
+ return;
+ for (i = 0; i < al->size; i++) {
+ alp = al->list + i;
+ if (alp->provides != NULL)
+ providesCnt += rpmdsCount(alp->provides);
+ if (alp->fi != NULL)
+ fileCnt += rpmfiFC(alp->fi);
+ }
+
+ al->providesHash = rpmalProvidesHashCreate(providesCnt/4+128, hashFunctionString,
+ strcmp, NULL, NULL);
+ al->fileHash = rpmalFileHashCreate(fileCnt/4+128, fileHash, fileCompare,
+ NULL, NULL);
+
+ for (i = 0; i < al->size; i++) {
+ alp = al->list + i;
+ rpmalAddProvides(al, i, alp->provides);
+ rpmalAddFiles(al, i, alp->fi);
+ }
+}
+
+static rpmte * rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds)
+{
+ const char *fileName = rpmdsN(ds);
+ const char *slash;
+ rpmte * ret = NULL;
+
+ if (al == NULL || fileName == NULL || *fileName != '/')
+ return NULL;
+
+ /* Split path into dirname and basename components for lookup */
+ if ((slash = strrchr(fileName, '/')) != NULL) {
+ availableIndexEntry result;
+ int resultCnt = 0;
+ size_t bnStart = (slash - fileName) + 1;
+ char dirName[bnStart + 1];
+ struct fileNameEntry_s fne = {
+ .baseName = fileName + bnStart,
+ .dirName = dirName,
+ };
+ strncpy(dirName, fileName, bnStart);
+ dirName[bnStart] = '\0';
+
+ rpmalFileHashGetEntry(al->fileHash, fne, &result, &resultCnt, NULL);
+
+ if (resultCnt > 0) {
+ int i, found;
+ ret = xmalloc((resultCnt+1) * sizeof(*ret));
+
+ for (found = i = 0; i < resultCnt; i++) {
+ availablePackage alp = al->list + result[i].pkgNum;
+ if (alp->p == NULL) // deleted
+ continue;
+
+ rpmdsNotify(ds, "(added files)", 0);
+
+ ret[found] = alp->p;
+ found++;
+ }
+ ret[found] = NULL;
+ }
+ }
+
+ return ret;
+}
+
+static rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds)
+{
+ rpmte * ret = NULL;
+ int i, found;
+ const char * name;
+ availableIndexEntry result;
+ int resultCnt;
+
+ availablePackage alp;
+ int rc;
+
+ if (al == NULL || ds == NULL || (name = rpmdsN(ds)) == NULL)
+ return ret;
+
+ if (al->providesHash == NULL && al->fileHash == NULL)
+ rpmalMakeIndex(al);
+
+ if (*name == '/') {
+ /* First, look for files "contained" in package ... */
+ ret = rpmalAllFileSatisfiesDepend(al, ds);
+ if (ret != NULL && *ret != NULL)
+ return ret;
+ /* ... then, look for files "provided" by package. */
+ ret = _free(ret);
+ }
+
+ rpmalProvidesHashGetEntry(al->providesHash, name, &result,
+ &resultCnt, NULL);
+
+ if (resultCnt==0) return NULL;
+
+ ret = xmalloc((resultCnt+1) * sizeof(*ret));
+
+ for (found=i=0; i<resultCnt; i++) {
+ alp = al->list + result[i].pkgNum;
+ if (alp->p == NULL) // deleted
+ continue;
+ (void) rpmdsSetIx(alp->provides, result[i].entryIx);
+ rc = 0;
+ if (rpmdsIx(alp->provides) >= 0)
+ rc = rpmdsCompare(alp->provides, ds);
+
+ if (rc) {
+ rpmdsNotify(ds, "(added provide)", 0);
+ ret[found] = alp->p;
+ found++;
+ }
+ }
+ ret[found] = NULL;
+
+ return ret;
+}
+
+rpmte
+rpmalSatisfiesDepend(const rpmal al, const rpmds ds)
+{
+ rpmte *providers = rpmalAllSatisfiesDepend(al, ds);
+ rpmte best = NULL;
+
+ if (providers) {
+ if (al->tscolor) {
+ /*
+ * For colored dependencies, try to find a matching provider.
+ * Otherwise prefer provider of ts preferred color.
+ */
+ rpm_color_t dscolor = rpmdsColor(ds);
+ for (rpmte *p = providers; *p; p++) {
+ rpm_color_t tecolor = rpmteColor(*p);
+ if (dscolor) {
+ if (dscolor == tecolor) best = *p;
+ } else if (al->prefcolor) {
+ if (al->prefcolor == tecolor) best = *p;
+ }
+ if (best) break;
+ }
+ }
+ /* if not decided by now, just pick first match */
+ if (!best) best = providers[0];
+ free(providers);
+ }
+ return best;
+}
+
+rpmte *
+rpmalAllInCollection(const rpmal al, const char *collname)
+{
+ rpmte *ret = NULL;
+ int found = 0;
+ rpmalNum pkgNum;
+
+ if (!al || !al->list || !collname)
+ return NULL;
+
+ for (pkgNum = 0; pkgNum < al->size; pkgNum++) {
+ rpmte p = al->list[pkgNum].p;
+ if (rpmteHasCollection(p, collname)) {
+ ret = xrealloc(ret, sizeof(*ret) * (found + 1 + 1));
+ ret[found] = p;
+ found++;
+ }
+ }
+ if (ret) {
+ ret[found] = NULL;
+ }
+
+ return ret;
+}