10 #include <rpm/rpmstrpool.h>
12 #include "lib/rpmal.h"
14 #include "lib/rpmte_internal.h"
15 #include "lib/rpmds_internal.h"
16 #include "lib/rpmfi_internal.h"
20 typedef struct availablePackage_s * availablePackage;
24 * Info about a single package to be installed.
26 struct availablePackage_s {
27 rpmte p; /*!< transaction member */
28 rpmds provides; /*!< Provides: dependencies. */
29 rpmds obsoletes; /*!< Obsoletes: dependencies. */
30 rpmfiles fi; /*!< File info set. */
34 * A single available item (e.g. a Provides: dependency).
36 typedef struct availableIndexEntry_s {
37 rpmalNum pkgNum; /*!< Containing package index. */
38 unsigned int entryIx; /*!< Dependency index. */
39 } * availableIndexEntry;
44 #define HASHTYPE rpmalDepHash
45 #define HTKEYTYPE rpmsid
46 #define HTDATATYPE struct availableIndexEntry_s
47 #include "lib/rpmhash.H"
48 #include "lib/rpmhash.C"
50 typedef struct availableIndexFileEntry_s {
52 rpmalNum pkgNum; /*!< Containing package index. */
53 unsigned int entryIx; /*!< Dependency index. */
54 } * availableIndexFileEntry;
59 #define HASHTYPE rpmalFileHash
60 #define HTKEYTYPE rpmsid
61 #define HTDATATYPE struct availableIndexFileEntry_s
62 #include "lib/rpmhash.H"
63 #include "lib/rpmhash.C"
66 * Set of available packages, items, and directories.
69 rpmstrPool pool; /*!< String pool */
70 availablePackage list; /*!< Set of packages. */
71 rpmalDepHash providesHash;
72 rpmalDepHash obsoletesHash;
73 rpmalFileHash fileHash;
74 int delta; /*!< Delta for pkg list reallocation. */
75 int size; /*!< No. of pkgs in list. */
76 int alloced; /*!< No. of pkgs allocated for list. */
77 rpmtransFlags tsflags; /*!< Transaction control flags. */
78 rpm_color_t tscolor; /*!< Transaction color. */
79 rpm_color_t prefcolor; /*!< Transaction preferred color. */
84 * Destroy available item index.
85 * @param al available list
87 static void rpmalFreeIndex(rpmal al)
89 al->providesHash = rpmalDepHashFree(al->providesHash);
90 al->obsoletesHash = rpmalDepHashFree(al->obsoletesHash);
91 al->fileHash = rpmalFileHashFree(al->fileHash);
92 al->fpc = fpCacheFree(al->fpc);
95 rpmal rpmalCreate(rpmstrPool pool, int delta, rpmtransFlags tsflags,
96 rpm_color_t tscolor, rpm_color_t prefcolor)
98 rpmal al = xcalloc(1, sizeof(*al));
100 /* transition time safe-guard */
101 assert(pool != NULL);
103 al->pool = rpmstrPoolLink(pool);
106 al->alloced = al->delta;
107 al->list = xmalloc(sizeof(*al->list) * al->alloced);;
109 al->providesHash = NULL;
110 al->obsoletesHash = NULL;
112 al->tsflags = tsflags;
113 al->tscolor = tscolor;
114 al->prefcolor = prefcolor;
119 rpmal rpmalFree(rpmal al)
121 availablePackage alp;
127 if ((alp = al->list) != NULL)
128 for (i = 0; i < al->size; i++, alp++) {
129 alp->obsoletes = rpmdsFree(alp->obsoletes);
130 alp->provides = rpmdsFree(alp->provides);
131 alp->fi = rpmfilesFree(alp->fi);
133 al->pool = rpmstrPoolFree(al->pool);
134 al->list = _free(al->list);
142 static unsigned int sidHash(rpmsid sid)
147 static int sidCmp(rpmsid a, rpmsid b)
152 void rpmalDel(rpmal al, rpmte p)
154 availablePackage alp;
157 if (al == NULL || al->list == NULL)
158 return; /* XXX can't happen */
160 // XXX use a search for self provide
161 for (pkgNum=0; pkgNum<al->size; pkgNum++) {
162 if (al->list[pkgNum].p == p) {
166 if (pkgNum == al->size ) return; // Not found!
168 alp = al->list + pkgNum;
169 // do not actually delete, just set p to NULL
170 // and later filter that out of the results
174 static void rpmalAddFiles(rpmal al, rpmalNum pkgNum, rpmfiles fi)
176 struct availableIndexFileEntry_s fileEntry;
177 int fc = rpmfilesFC(fi);
179 int skipdoc = (al->tsflags & RPMTRANS_FLAG_NODOCS);
180 int skipconf = (al->tsflags & RPMTRANS_FLAG_NOCONFIGS);
182 fileEntry.pkgNum = pkgNum;
184 for (int i = 0; i < fc; i++) {
185 /* Ignore colored provides not in our rainbow. */
186 ficolor = rpmfilesFColor(fi, i);
187 if (al->tscolor && ficolor && !(al->tscolor & ficolor))
190 /* Ignore files that wont be installed */
191 if (skipdoc && (rpmfilesFFlags(fi, i) & RPMFILE_DOC))
193 if (skipconf && (rpmfilesFFlags(fi, i) & RPMFILE_CONFIG))
196 fileEntry.dirName = rpmfilesDNId(fi, rpmfilesDI(fi, i));
197 fileEntry.entryIx = i;
199 rpmalFileHashAddEntry(al->fileHash, rpmfilesBNId(fi, i), fileEntry);
203 static void rpmalAddProvides(rpmal al, rpmalNum pkgNum, rpmds provides)
205 struct availableIndexEntry_s indexEntry;
207 int skipconf = (al->tsflags & RPMTRANS_FLAG_NOCONFIGS);
208 int dc = rpmdsCount(provides);
210 indexEntry.pkgNum = pkgNum;
212 for (int i = 0; i < dc; i++) {
213 /* Ignore colored provides not in our rainbow. */
214 dscolor = rpmdsColorIndex(provides, i);
215 if (al->tscolor && dscolor && !(al->tscolor & dscolor))
218 /* Ignore config() provides if the files wont be installed */
219 if (skipconf & (rpmdsFlagsIndex(provides, i) & RPMSENSE_CONFIG))
222 indexEntry.entryIx = i;;
223 rpmalDepHashAddEntry(al->providesHash,
224 rpmdsNIdIndex(provides, i), indexEntry);
228 static void rpmalAddObsoletes(rpmal al, rpmalNum pkgNum, rpmds obsoletes)
230 struct availableIndexEntry_s indexEntry;
232 int dc = rpmdsCount(obsoletes);
234 indexEntry.pkgNum = pkgNum;
236 for (int i = 0; i < dc; i++) {
237 /* Obsoletes shouldn't be colored but just in case... */
238 dscolor = rpmdsColorIndex(obsoletes, i);
239 if (al->tscolor && dscolor && !(al->tscolor & dscolor))
242 indexEntry.entryIx = i;;
243 rpmalDepHashAddEntry(al->obsoletesHash,
244 rpmdsNIdIndex(obsoletes, i), indexEntry);
248 void rpmalAdd(rpmal al, rpmte p)
251 availablePackage alp;
253 if (al->size == al->alloced) {
254 al->alloced += al->delta;
255 al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
259 alp = al->list + pkgNum;
263 alp->provides = rpmdsLink(rpmteDS(p, RPMTAG_PROVIDENAME));
264 alp->obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME));
265 alp->fi = rpmteFiles(p);
268 * Transition-time safe-guard to catch private-pool uses.
269 * File sets with no files have NULL pool, that's fine. But WTF is up
270 * with the provides: every single package should have at least its
271 * own name as a provide, and thus never NULL, and normal use matches
272 * this expectation. However the test-suite is tripping up on NULL
273 * NULL pool from NULL alp->provides in numerous cases?
276 rpmstrPool fipool = rpmfilesPool(alp->fi);
277 rpmstrPool dspool = rpmdsPool(alp->provides);
279 assert(fipool == NULL || fipool == al->pool);
280 assert(dspool == NULL || dspool == al->pool);
283 /* Try to be lazy as delayed hash creation is cheaper */
284 if (al->providesHash != NULL)
285 rpmalAddProvides(al, pkgNum, alp->provides);
286 if (al->obsoletesHash != NULL)
287 rpmalAddObsoletes(al, pkgNum, alp->obsoletes);
288 if (al->fileHash != NULL)
289 rpmalAddFiles(al, pkgNum, alp->fi);
291 assert(((rpmalNum)(alp - al->list)) == pkgNum);
294 static void rpmalMakeFileIndex(rpmal al)
296 availablePackage alp;
299 for (i = 0; i < al->size; i++) {
302 fileCnt += rpmfilesFC(alp->fi);
304 al->fileHash = rpmalFileHashCreate(fileCnt/4+128,
305 sidHash, sidCmp, NULL, NULL);
306 for (i = 0; i < al->size; i++) {
308 rpmalAddFiles(al, i, alp->fi);
312 static void rpmalMakeProvidesIndex(rpmal al)
314 availablePackage alp;
315 int i, providesCnt = 0;
317 for (i = 0; i < al->size; i++) {
319 providesCnt += rpmdsCount(alp->provides);
322 al->providesHash = rpmalDepHashCreate(providesCnt/4+128,
323 sidHash, sidCmp, NULL, NULL);
324 for (i = 0; i < al->size; i++) {
326 rpmalAddProvides(al, i, alp->provides);
330 static void rpmalMakeObsoletesIndex(rpmal al)
332 availablePackage alp;
333 int i, obsoletesCnt = 0;
335 for (i = 0; i < al->size; i++) {
337 obsoletesCnt += rpmdsCount(alp->obsoletes);
340 al->obsoletesHash = rpmalDepHashCreate(obsoletesCnt/4+128,
341 sidHash, sidCmp, NULL, NULL);
342 for (i = 0; i < al->size; i++) {
344 rpmalAddObsoletes(al, i, alp->obsoletes);
348 rpmte * rpmalAllObsoletes(rpmal al, rpmds ds)
352 availableIndexEntry result;
355 if (al == NULL || ds == NULL || (nameId = rpmdsNId(ds)) == 0)
358 if (al->obsoletesHash == NULL)
359 rpmalMakeObsoletesIndex(al);
361 rpmalDepHashGetEntry(al->obsoletesHash, nameId, &result, &resultCnt, NULL);
364 availablePackage alp;
367 ret = xmalloc((resultCnt+1) * sizeof(*ret));
369 for (int i = 0; i < resultCnt; i++) {
370 alp = al->list + result[i].pkgNum;
371 if (alp->p == NULL) // deleted
374 rc = rpmdsCompareIndex(alp->obsoletes, result[i].entryIx,
378 rpmdsNotify(ds, "(added obsolete)", 0);
393 static rpmte * rpmalAllFileSatisfiesDepend(const rpmal al, const char *fileName, const rpmds filterds)
398 if (al == NULL || fileName == NULL || *fileName != '/')
401 /* Split path into dirname and basename components for lookup */
402 if ((slash = strrchr(fileName, '/')) != NULL) {
403 availableIndexFileEntry result;
405 size_t bnStart = (slash - fileName) + 1;
408 if (al->fileHash == NULL)
409 rpmalMakeFileIndex(al);
411 baseName = rpmstrPoolId(al->pool, fileName + bnStart, 0);
413 return NULL; /* no match possible */
415 rpmalFileHashGetEntry(al->fileHash, baseName, &result, &resultCnt, NULL);
419 ret = xmalloc((resultCnt+1) * sizeof(*ret));
420 fingerPrint * fp = NULL;
421 rpmsid dirName = rpmstrPoolIdn(al->pool, fileName, bnStart, 1);
424 al->fpc = fpCacheCreate(1001, NULL);
425 fpLookup(al->fpc, rpmstrPoolStr(al->pool, dirName), fileName + bnStart, &fp);
427 for (found = i = 0; i < resultCnt; i++) {
428 availablePackage alp = al->list + result[i].pkgNum;
429 if (alp->p == NULL) /* deleted */
431 /* ignore self-conflicts/obsoletes */
432 if (filterds && rpmteDS(alp->p, rpmdsTagN(filterds)) == filterds)
434 if (result[i].dirName != dirName &&
435 !fpLookupEquals(al->fpc, fp, rpmstrPoolStr(al->pool, result[i].dirName), fileName + bnStart))
449 rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds)
455 availableIndexEntry result;
459 rpmds filterds = NULL;
461 availablePackage alp;
464 if (al == NULL || ds == NULL || (nameId = rpmdsNId(ds)) == 0)
467 dtag = rpmdsTagN(ds);
468 obsolete = (dtag == RPMTAG_OBSOLETENAME);
469 if (dtag == RPMTAG_OBSOLETENAME || dtag == RPMTAG_CONFLICTNAME)
471 name = rpmstrPoolStr(al->pool, nameId);
472 if (!obsolete && *name == '/') {
473 /* First, look for files "contained" in package ... */
474 ret = rpmalAllFileSatisfiesDepend(al, name, filterds);
475 if (ret != NULL && *ret != NULL) {
476 rpmdsNotify(ds, "(added files)", 0);
479 /* ... then, look for files "provided" by package. */
483 if (al->providesHash == NULL)
484 rpmalMakeProvidesIndex(al);
486 rpmalDepHashGetEntry(al->providesHash, nameId, &result,
489 if (resultCnt==0) return NULL;
491 ret = xmalloc((resultCnt+1) * sizeof(*ret));
493 for (found=i=0; i<resultCnt; i++) {
494 alp = al->list + result[i].pkgNum;
495 if (alp->p == NULL) /* deleted */
497 /* ignore self-conflicts/obsoletes */
498 if (filterds && rpmteDS(alp->p, rpmdsTagN(filterds)) == filterds)
500 ix = result[i].entryIx;
503 /* Obsoletes are on package NEVR only */
505 if (!rstreq(rpmdsNIndex(alp->provides, ix), rpmteN(alp->p)))
507 thisds = rpmteDS(alp->p, RPMTAG_NAME);
508 rc = rpmdsCompareIndex(thisds, rpmdsIx(thisds), ds, rpmdsIx(ds));
510 rc = rpmdsCompareIndex(alp->provides, ix, ds, rpmdsIx(ds));
514 ret[found++] = alp->p;
518 rpmdsNotify(ds, "(added provide)", 0);
528 rpmalSatisfiesDepend(const rpmal al, const rpmte te, const rpmds ds)
530 rpmte *providers = rpmalAllSatisfiesDepend(al, ds);
535 rpm_color_t dscolor = rpmdsColor(ds);
536 for (rpmte *p = providers; *p; p++) {
540 * For colored dependencies, prefer a matching colored provider.
541 * Otherwise prefer provider of ts preferred color.
544 rpm_color_t tecolor = rpmteColor(*p);
546 if (dscolor == tecolor) score += 2;
547 } else if (al->prefcolor) {
548 if (al->prefcolor == tecolor) score += 2;
552 /* Being self-provided is a bonus */
556 if (score > bestscore) {
561 /* if not decided by now, just pick first match */
562 if (!best) best = providers[0];
569 rpmalLookupTE(const rpmal al, const rpmte te)
572 for (pkgNum=0; pkgNum < al->size; pkgNum++)
573 if (al->list[pkgNum].p == te)
575 return pkgNum < al->size ? pkgNum : (unsigned int)-1;