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 rpmfi 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;
41 struct fileNameEntry_s {
49 #define HASHTYPE rpmalDepHash
50 #define HTKEYTYPE rpmsid
51 #define HTDATATYPE struct availableIndexEntry_s
52 #include "lib/rpmhash.H"
53 #include "lib/rpmhash.C"
58 #define HASHTYPE rpmalFileHash
59 #define HTKEYTYPE struct fileNameEntry_s
60 #define HTDATATYPE struct availableIndexEntry_s
61 #include "lib/rpmhash.H"
62 #include "lib/rpmhash.C"
65 * Set of available packages, items, and directories.
68 rpmstrPool pool; /*!< String pool */
69 availablePackage list; /*!< Set of packages. */
70 rpmalDepHash providesHash;
71 rpmalDepHash obsoletesHash;
72 rpmalFileHash fileHash;
73 int delta; /*!< Delta for pkg list reallocation. */
74 int size; /*!< No. of pkgs in list. */
75 int alloced; /*!< No. of pkgs allocated for list. */
76 rpmtransFlags tsflags; /*!< Transaction control flags. */
77 rpm_color_t tscolor; /*!< Transaction color. */
78 rpm_color_t prefcolor; /*!< Transaction preferred color. */
82 * Destroy available item index.
83 * @param al available list
85 static void rpmalFreeIndex(rpmal al)
87 al->providesHash = rpmalDepHashFree(al->providesHash);
88 al->obsoletesHash = rpmalDepHashFree(al->obsoletesHash);
89 al->fileHash = rpmalFileHashFree(al->fileHash);
92 rpmal rpmalCreate(rpmstrPool pool, int delta, rpmtransFlags tsflags,
93 rpm_color_t tscolor, rpm_color_t prefcolor)
95 rpmal al = xcalloc(1, sizeof(*al));
97 /* transition time safe-guard */
100 al->pool = rpmstrPoolLink(pool);
103 al->alloced = al->delta;
104 al->list = xmalloc(sizeof(*al->list) * al->alloced);;
106 al->providesHash = NULL;
107 al->obsoletesHash = NULL;
109 al->tsflags = tsflags;
110 al->tscolor = tscolor;
111 al->prefcolor = prefcolor;
116 rpmal rpmalFree(rpmal al)
118 availablePackage alp;
124 if ((alp = al->list) != NULL)
125 for (i = 0; i < al->size; i++, alp++) {
126 alp->obsoletes = rpmdsFree(alp->obsoletes);
127 alp->provides = rpmdsFree(alp->provides);
128 alp->fi = rpmfiFree(alp->fi);
130 al->pool = rpmstrPoolFree(al->pool);
131 al->list = _free(al->list);
139 static unsigned int sidHash(rpmsid sid)
144 static int sidCmp(rpmsid a, rpmsid b)
149 static unsigned int fileHash(struct fileNameEntry_s file)
151 return file.dirName ^ file.baseName;
154 static int fileCompare(struct fileNameEntry_s one, struct fileNameEntry_s two)
156 int rc = (one.dirName != two.dirName);;
158 rc = (one.baseName != two.baseName);
162 void rpmalDel(rpmal al, rpmte p)
164 availablePackage alp;
167 if (al == NULL || al->list == NULL)
168 return; /* XXX can't happen */
170 // XXX use a search for self provide
171 for (pkgNum=0; pkgNum<al->size; pkgNum++) {
172 if (al->list[pkgNum].p == p) {
176 if (pkgNum == al->size ) return; // Not found!
178 alp = al->list + pkgNum;
179 // do not actually delete, just set p to NULL
180 // and later filter that out of the results
184 static void rpmalAddFiles(rpmal al, rpmalNum pkgNum, rpmfi fi)
186 struct fileNameEntry_s fileName;
187 struct availableIndexEntry_s fileEntry;
188 int fc = rpmfiFC(fi);
190 int skipdoc = (al->tsflags & RPMTRANS_FLAG_NODOCS);
191 int skipconf = (al->tsflags & RPMTRANS_FLAG_NOCONFIGS);
193 fileEntry.pkgNum = pkgNum;
195 for (int i = 0; i < fc; i++) {
196 /* Ignore colored provides not in our rainbow. */
197 ficolor = rpmfiFColorIndex(fi, i);
198 if (al->tscolor && ficolor && !(al->tscolor & ficolor))
201 /* Ignore files that wont be installed */
202 if (skipdoc && (rpmfiFFlagsIndex(fi, i) & RPMFILE_DOC))
204 if (skipconf && (rpmfiFFlagsIndex(fi, i) & RPMFILE_CONFIG))
207 fileName.dirName = rpmfiDNIdIndex(fi, rpmfiDIIndex(fi, i));
208 fileName.baseName = rpmfiBNIdIndex(fi, i);
210 fileEntry.entryIx = i;
212 rpmalFileHashAddEntry(al->fileHash, fileName, fileEntry);
216 static void rpmalAddProvides(rpmal al, rpmalNum pkgNum, rpmds provides)
218 struct availableIndexEntry_s indexEntry;
220 int skipconf = (al->tsflags & RPMTRANS_FLAG_NOCONFIGS);
221 int dc = rpmdsCount(provides);
223 indexEntry.pkgNum = pkgNum;
225 for (int i = 0; i < dc; i++) {
226 /* Ignore colored provides not in our rainbow. */
227 dscolor = rpmdsColorIndex(provides, i);
228 if (al->tscolor && dscolor && !(al->tscolor & dscolor))
231 /* Ignore config() provides if the files wont be installed */
232 if (skipconf & (rpmdsFlagsIndex(provides, i) & RPMSENSE_CONFIG))
235 indexEntry.entryIx = i;;
236 rpmalDepHashAddEntry(al->providesHash,
237 rpmdsNIdIndex(provides, i), indexEntry);
241 static void rpmalAddObsoletes(rpmal al, rpmalNum pkgNum, rpmds obsoletes)
243 struct availableIndexEntry_s indexEntry;
245 int dc = rpmdsCount(obsoletes);
247 indexEntry.pkgNum = pkgNum;
249 for (int i = 0; i < dc; i++) {
250 /* Obsoletes shouldn't be colored but just in case... */
251 dscolor = rpmdsColorIndex(obsoletes, i);
252 if (al->tscolor && dscolor && !(al->tscolor & dscolor))
255 indexEntry.entryIx = i;;
256 rpmalDepHashAddEntry(al->obsoletesHash,
257 rpmdsNIdIndex(obsoletes, i), indexEntry);
261 void rpmalAdd(rpmal al, rpmte p)
264 availablePackage alp;
266 if (al->size == al->alloced) {
267 al->alloced += al->delta;
268 al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
272 alp = al->list + pkgNum;
276 alp->provides = rpmdsLink(rpmteDS(p, RPMTAG_PROVIDENAME));
277 alp->obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME));
278 alp->fi = rpmfiLink(rpmteFI(p));
281 * Transition-time safe-guard to catch private-pool uses.
282 * File sets with no files have NULL pool, that's fine. But WTF is up
283 * with the provides: every single package should have at least its
284 * own name as a provide, and thus never NULL, and normal use matches
285 * this expectation. However the test-suite is tripping up on NULL
286 * NULL pool from NULL alp->provides in numerous cases?
289 rpmstrPool fipool = rpmfiPool(alp->fi);
290 rpmstrPool dspool = rpmdsPool(alp->provides);
292 assert(fipool == NULL || fipool == al->pool);
293 assert(dspool == NULL || dspool == al->pool);
296 /* Try to be lazy as delayed hash creation is cheaper */
297 if (al->providesHash != NULL)
298 rpmalAddProvides(al, pkgNum, alp->provides);
299 if (al->obsoletesHash != NULL)
300 rpmalAddObsoletes(al, pkgNum, alp->obsoletes);
301 if (al->fileHash != NULL)
302 rpmalAddFiles(al, pkgNum, alp->fi);
304 assert(((rpmalNum)(alp - al->list)) == pkgNum);
307 static void rpmalMakeFileIndex(rpmal al)
309 availablePackage alp;
312 for (i = 0; i < al->size; i++) {
315 fileCnt += rpmfiFC(alp->fi);
317 al->fileHash = rpmalFileHashCreate(fileCnt/4+128,
318 fileHash, fileCompare, NULL, NULL);
319 for (i = 0; i < al->size; i++) {
321 rpmalAddFiles(al, i, alp->fi);
325 static void rpmalMakeProvidesIndex(rpmal al)
327 availablePackage alp;
328 int i, providesCnt = 0;
330 for (i = 0; i < al->size; i++) {
332 providesCnt += rpmdsCount(alp->provides);
335 al->providesHash = rpmalDepHashCreate(providesCnt/4+128,
336 sidHash, sidCmp, NULL, NULL);
337 for (i = 0; i < al->size; i++) {
339 rpmalAddProvides(al, i, alp->provides);
343 static void rpmalMakeObsoletesIndex(rpmal al)
345 availablePackage alp;
346 int i, obsoletesCnt = 0;
348 for (i = 0; i < al->size; i++) {
350 obsoletesCnt += rpmdsCount(alp->obsoletes);
353 al->obsoletesHash = rpmalDepHashCreate(obsoletesCnt/4+128,
354 sidHash, sidCmp, NULL, NULL);
355 for (i = 0; i < al->size; i++) {
357 rpmalAddObsoletes(al, i, alp->obsoletes);
361 rpmte * rpmalAllObsoletes(rpmal al, rpmds ds)
365 availableIndexEntry result;
368 if (al == NULL || ds == NULL || (nameId = rpmdsNId(ds)) == 0)
371 if (al->obsoletesHash == NULL)
372 rpmalMakeObsoletesIndex(al);
374 rpmalDepHashGetEntry(al->obsoletesHash, nameId, &result, &resultCnt, NULL);
377 availablePackage alp;
380 ret = xmalloc((resultCnt+1) * sizeof(*ret));
382 for (int i = 0; i < resultCnt; i++) {
383 alp = al->list + result[i].pkgNum;
384 if (alp->p == NULL) // deleted
387 rc = rpmdsCompareIndex(alp->obsoletes, result[i].entryIx,
391 rpmdsNotify(ds, "(added obsolete)", 0);
406 static rpmte * rpmalAllFileSatisfiesDepend(const rpmal al, const char *fileName)
411 if (al == NULL || fileName == NULL || *fileName != '/')
414 /* Split path into dirname and basename components for lookup */
415 if ((slash = strrchr(fileName, '/')) != NULL) {
416 availableIndexEntry result;
418 size_t bnStart = (slash - fileName) + 1;
419 struct fileNameEntry_s fne;
421 fne.baseName = rpmstrPoolId(al->pool, fileName + bnStart, 0);
422 fne.dirName = rpmstrPoolIdn(al->pool, fileName, bnStart, 0);
424 if (al->fileHash == NULL)
425 rpmalMakeFileIndex(al);
427 rpmalFileHashGetEntry(al->fileHash, fne, &result, &resultCnt, NULL);
431 ret = xmalloc((resultCnt+1) * sizeof(*ret));
433 for (found = i = 0; i < resultCnt; i++) {
434 availablePackage alp = al->list + result[i].pkgNum;
435 if (alp->p == NULL) // deleted
448 rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds)
454 availableIndexEntry result;
458 availablePackage alp;
461 if (al == NULL || ds == NULL || (nameId = rpmdsNId(ds)) == 0)
464 obsolete = (rpmdsTagN(ds) == RPMTAG_OBSOLETENAME);
465 name = rpmstrPoolStr(al->pool, nameId);
466 if (!obsolete && *name == '/') {
467 /* First, look for files "contained" in package ... */
468 ret = rpmalAllFileSatisfiesDepend(al, name);
469 if (ret != NULL && *ret != NULL) {
470 rpmdsNotify(ds, "(added files)", 0);
473 /* ... then, look for files "provided" by package. */
477 if (al->providesHash == NULL)
478 rpmalMakeProvidesIndex(al);
480 rpmalDepHashGetEntry(al->providesHash, nameId, &result,
483 if (resultCnt==0) return NULL;
485 ret = xmalloc((resultCnt+1) * sizeof(*ret));
487 for (found=i=0; i<resultCnt; i++) {
488 alp = al->list + result[i].pkgNum;
489 if (alp->p == NULL) // deleted
491 ix = result[i].entryIx;
493 /* Obsoletes are on package name, filter out other provide matches */
494 if (obsolete && !rstreq(rpmdsNIndex(alp->provides, ix), rpmteN(alp->p)))
497 rc = rpmdsCompareIndex(alp->provides, ix, ds, rpmdsIx(ds));
500 rpmdsNotify(ds, "(added provide)", 0);
515 rpmalSatisfiesDepend(const rpmal al, const rpmds ds)
517 rpmte *providers = rpmalAllSatisfiesDepend(al, ds);
523 * For colored dependencies, try to find a matching provider.
524 * Otherwise prefer provider of ts preferred color.
526 rpm_color_t dscolor = rpmdsColor(ds);
527 for (rpmte *p = providers; *p; p++) {
528 rpm_color_t tecolor = rpmteColor(*p);
530 if (dscolor == tecolor) best = *p;
531 } else if (al->prefcolor) {
532 if (al->prefcolor == tecolor) best = *p;
537 /* if not decided by now, just pick first match */
538 if (!best) best = providers[0];
545 rpmalAllInCollection(const rpmal al, const char *collname)
551 if (!al || !al->list || !collname)
554 for (pkgNum = 0; pkgNum < al->size; pkgNum++) {
555 rpmte p = al->list[pkgNum].p;
556 if (rpmteHasCollection(p, collname)) {
557 ret = xrealloc(ret, sizeof(*ret) * (found + 1 + 1));