10 #include <rpm/rpmfi.h>
12 #include "lib/rpmal.h"
17 typedef struct availablePackage_s * availablePackage;
21 * Info about a single package to be installed.
23 struct availablePackage_s {
24 rpmte p; /*!< transaction member */
25 rpmds provides; /*!< Provides: dependencies. */
26 rpmfi fi; /*!< File info set. */
29 typedef struct availableIndexEntry_s * availableIndexEntry;
32 * A single available item (e.g. a Provides: dependency).
34 struct availableIndexEntry_s {
35 rpmalNum pkgNum; /*!< Containing package index. */
36 unsigned int entryIx; /*!< Dependency index. */
39 struct fileNameEntry_s {
41 const char * baseName;
46 * A file to be installed/removed.
48 typedef struct fileIndexEntry_s * fileIndex;
50 struct fileIndexEntry_s {
51 rpmalNum pkgNum; /*!< Containing package index. */
58 #define HASHTYPE rpmalProvidesHash
59 #define HTKEYTYPE const char *
60 #define HTDATATYPE struct availableIndexEntry_s
61 #include "lib/rpmhash.H"
62 #include "lib/rpmhash.C"
67 #define HASHTYPE rpmalFileHash
68 #define HTKEYTYPE struct fileNameEntry_s
69 #define HTDATATYPE struct fileIndexEntry_s
70 #include "lib/rpmhash.H"
71 #include "lib/rpmhash.C"
76 * Set of available packages, items, and directories.
79 availablePackage list; /*!< Set of packages. */
80 rpmalProvidesHash providesHash;
81 rpmalFileHash fileHash;
82 int delta; /*!< Delta for pkg list reallocation. */
83 int size; /*!< No. of pkgs in list. */
84 int alloced; /*!< No. of pkgs allocated for list. */
85 rpm_color_t tscolor; /*!< Transaction color. */
86 rpm_color_t prefcolor; /*!< Transaction preferred color. */
90 * Destroy available item index.
91 * @param al available list
93 static void rpmalFreeIndex(rpmal al)
95 al->providesHash = rpmalProvidesHashFree(al->providesHash);
96 al->fileHash = rpmalFileHashFree(al->fileHash);
99 rpmal rpmalCreate(int delta, rpm_color_t tscolor, rpm_color_t prefcolor)
101 rpmal al = xcalloc(1, sizeof(*al));
105 al->alloced = al->delta;
106 al->list = xmalloc(sizeof(*al->list) * al->alloced);;
108 al->providesHash = NULL;
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->provides = rpmdsFree(alp->provides);
127 alp->fi = rpmfiFree(alp->fi);
129 al->list = _free(al->list);
137 static unsigned int fileHash(struct fileNameEntry_s file){
138 return hashFunctionString(file.dirName) ^ hashFunctionString(file.baseName);
141 static int fileCompare(struct fileNameEntry_s one, struct fileNameEntry_s two) {
143 rc = strcmp(one.dirName, two.dirName);
145 rc = strcmp(one.baseName, two.baseName);
149 void rpmalDel(rpmal al, rpmte p)
151 availablePackage alp;
154 if (al == NULL || al->list == NULL)
155 return; /* XXX can't happen */
157 // XXX use a search for self provide
158 for (pkgNum=0; pkgNum<al->size; pkgNum++) {
159 if (al->list[pkgNum].p == p) {
163 if (pkgNum == al->size ) return; // Not found!
165 alp = al->list + pkgNum;
166 // do not actually delete, just set p to NULL
167 // and later filter that out of the results
171 static void rpmalAddFiles(rpmal al, rpmalNum pkgNum, rpmfi fi){
172 struct fileNameEntry_s fileName;
173 struct fileIndexEntry_s fileEntry;
177 fileEntry.pkgNum = pkgNum;
179 fi = rpmfiInit(fi, 0);
180 while ((i = rpmfiNext(fi)) >= 0) {
181 /* Ignore colored provides not in our rainbow. */
182 ficolor = rpmfiFColor(fi);
183 if (al->tscolor && ficolor && !(al->tscolor & ficolor))
186 fileName.dirName = rpmfiDN(fi);
187 fileName.baseName = rpmfiBN(fi);
189 fileEntry.entryIx = i;
191 rpmalFileHashAddEntry(al->fileHash, fileName, fileEntry);
195 static void rpmalAddProvides(rpmal al, rpmalNum pkgNum, rpmds provides){
196 struct availableIndexEntry_s indexEntry;
199 indexEntry.pkgNum = pkgNum;
201 if (rpmdsInit(provides) != NULL)
202 while (rpmdsNext(provides) >= 0) {
203 /* Ignore colored provides not in our rainbow. */
204 dscolor = rpmdsColor(provides);
205 if (al->tscolor && dscolor && !(al->tscolor & dscolor))
208 indexEntry.entryIx = rpmdsIx(provides);
209 rpmalProvidesHashAddEntry(al->providesHash, rpmdsN(provides), indexEntry);
213 void rpmalAdd(rpmal al, rpmte p)
216 availablePackage alp;
218 if (al->size == al->alloced) {
219 al->alloced += al->delta;
220 al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
224 alp = al->list + pkgNum;
228 alp->provides = rpmdsLink(rpmteDS(p, RPMTAG_PROVIDENAME));
229 alp->fi = rpmfiLink(rpmteFI(p));
231 if (al->providesHash != NULL) { // index is already created
232 rpmalAddProvides(al, pkgNum, alp->provides);
233 rpmalAddFiles(al, pkgNum, alp->fi);
236 assert(((rpmalNum)(alp - al->list)) == pkgNum);
239 static void rpmalMakeIndex(rpmal al)
241 availablePackage alp;
246 if (al == NULL || al->list == NULL) return;
247 if (al->providesHash != NULL || al->fileHash != NULL)
249 for (i = 0; i < al->size; i++) {
251 if (alp->provides != NULL)
252 providesCnt += rpmdsCount(alp->provides);
254 fileCnt += rpmfiFC(alp->fi);
257 al->providesHash = rpmalProvidesHashCreate(providesCnt/4+128, hashFunctionString,
259 al->fileHash = rpmalFileHashCreate(fileCnt/4+128, fileHash, fileCompare,
262 for (i = 0; i < al->size; i++) {
264 rpmalAddProvides(al, i, alp->provides);
265 rpmalAddFiles(al, i, alp->fi);
269 static rpmte * rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds)
271 const char *fileName = rpmdsN(ds);
275 if (al == NULL || fileName == NULL || *fileName != '/')
278 /* Split path into dirname and basename components for lookup */
279 if ((slash = strrchr(fileName, '/')) != NULL) {
282 size_t bnStart = (slash - fileName) + 1;
283 char dirName[bnStart + 1];
284 struct fileNameEntry_s fne = {
285 .baseName = fileName + bnStart,
288 strncpy(dirName, fileName, bnStart);
289 dirName[bnStart] = '\0';
291 rpmalFileHashGetEntry(al->fileHash, fne, &result, &resultCnt, NULL);
295 ret = xmalloc((resultCnt+1) * sizeof(*ret));
297 for (found = i = 0; i < resultCnt; i++) {
298 availablePackage alp = al->list + result[i].pkgNum;
299 if (alp->p == NULL) // deleted
302 rpmdsNotify(ds, "(added files)", 0);
314 static rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds)
319 availableIndexEntry result;
322 availablePackage alp;
325 if (al == NULL || ds == NULL || (name = rpmdsN(ds)) == NULL)
328 if (al->providesHash == NULL && al->fileHash == NULL)
332 /* First, look for files "contained" in package ... */
333 ret = rpmalAllFileSatisfiesDepend(al, ds);
334 if (ret != NULL && *ret != NULL)
336 /* ... then, look for files "provided" by package. */
340 rpmalProvidesHashGetEntry(al->providesHash, name, &result,
343 if (resultCnt==0) return NULL;
345 ret = xmalloc((resultCnt+1) * sizeof(*ret));
347 for (found=i=0; i<resultCnt; i++) {
348 alp = al->list + result[i].pkgNum;
349 if (alp->p == NULL) // deleted
351 (void) rpmdsSetIx(alp->provides, result[i].entryIx);
353 if (rpmdsIx(alp->provides) >= 0)
354 rc = rpmdsCompare(alp->provides, ds);
357 rpmdsNotify(ds, "(added provide)", 0);
368 rpmalSatisfiesDepend(const rpmal al, const rpmds ds)
370 rpmte *providers = rpmalAllSatisfiesDepend(al, ds);
376 * For colored dependencies, try to find a matching provider.
377 * Otherwise prefer provider of ts preferred color.
379 rpm_color_t dscolor = rpmdsColor(ds);
380 for (rpmte *p = providers; *p; p++) {
381 rpm_color_t tecolor = rpmteColor(*p);
383 if (dscolor == tecolor) best = *p;
384 } else if (al->prefcolor) {
385 if (al->prefcolor == tecolor) best = *p;
390 /* if not decided by now, just pick first match */
391 if (!best) best = providers[0];