15 typedef /*@abstract@*/ struct availablePackage_s * availablePackage;
23 /*@access availablePackage @*/
25 /*@access fnpyKey @*/ /* XXX suggestedKeys array */
28 * Info about a single package to be installed.
30 struct availablePackage_s {
31 /*@refcounted@*/ /*@null@*/
32 rpmds provides; /*!< Provides: dependencies. */
33 /*@refcounted@*/ /*@null@*/
34 rpmfi fi; /*!< File info set. */
36 uint_32 tscolor; /*!< Transaction color bits. */
38 /*@exposed@*/ /*@dependent@*/ /*@null@*/
39 fnpyKey key; /*!< Associated file name/python object */
43 typedef /*@abstract@*/ struct availableIndexEntry_s * availableIndexEntry;
44 /*@access availableIndexEntry@*/
47 * A single available item (e.g. a Provides: dependency).
49 struct availableIndexEntry_s {
50 /*@exposed@*/ /*@dependent@*/ /*@null@*/
51 alKey pkgKey; /*!< Containing package. */
53 const char * entry; /*!< Dependency name. */
54 unsigned short entryLen; /*!< No. of bytes in name. */
55 unsigned short entryIx; /*!< Dependency index. */
57 IET_PROVIDES=1 /*!< A Provides: dependency. */
58 } type; /*!< Type of available item. */
61 typedef /*@abstract@*/ struct availableIndex_s * availableIndex;
62 /*@access availableIndex@*/
65 * Index of all available items.
67 struct availableIndex_s {
69 availableIndexEntry index; /*!< Array of available items. */
70 int size; /*!< No. of available items. */
71 int k; /*!< Current index. */
74 typedef /*@abstract@*/ struct fileIndexEntry_s * fileIndexEntry;
75 /*@access fileIndexEntry@*/
78 * A file to be installed/removed.
80 struct fileIndexEntry_s {
81 /*@dependent@*/ /*@null@*/
82 const char * baseName; /*!< File basename. */
84 alNum pkgNum; /*!< Containing package index. */
88 typedef /*@abstract@*/ struct dirInfo_s * dirInfo;
92 * A directory to be installed/removed.
95 /*@owned@*/ /*@null@*/
96 const char * dirName; /*!< Directory path (+ trailing '/'). */
97 int dirNameLen; /*!< No. bytes in directory path. */
99 fileIndexEntry files; /*!< Array of files in directory. */
100 int numFiles; /*!< No. files in directory. */
104 * Set of available packages, items, and directories.
107 /*@owned@*/ /*@null@*/
108 availablePackage list; /*!< Set of packages. */
109 struct availableIndex_s index; /*!< Set of available items. */
110 int delta; /*!< Delta for pkg list reallocation. */
111 int size; /*!< No. of pkgs in list. */
112 int alloced; /*!< No. of pkgs allocated for list. */
113 uint_32 tscolor; /*!< Transaction color. */
114 int numDirs; /*!< No. of directories. */
115 /*@owned@*/ /*@null@*/
116 dirInfo dirs; /*!< Set of directories. */
120 * Destroy available item index.
121 * @param al available list
123 static void rpmalFreeIndex(rpmal al)
126 availableIndex ai = &al->index;
128 ai->index = _free(ai->index);
135 * Return number of packages in list.
136 * @param al available list
137 * @return no. of packages in list
139 static int alGetSize(/*@null@*/ const rpmal al)
142 return (al != NULL ? al->size : 0);
146 static inline alNum alKey2Num(/*@unused@*/ /*@null@*/ const rpmal al,
147 /*@null@*/ alKey pkgKey)
150 /*@-nullret -temptrans -retalias @*/
151 return ((alNum)pkgKey);
152 /*@=nullret =temptrans =retalias @*/
155 static inline alKey alNum2Key(/*@unused@*/ /*@null@*/ const rpmal al,
156 /*@null@*/ alNum pkgNum)
159 /*@-nullret -temptrans -retalias @*/
160 return ((alKey)pkgNum);
161 /*@=nullret =temptrans =retalias @*/
166 * Return available package.
167 * @param al available list
168 * @param pkgKey available package key
169 * @return available package pointer
171 /*@dependent@*/ /*@null@*/
172 static availablePackage alGetPkg(/*@null@*/ const rpmal al,
173 /*@null@*/ alKey pkgKey)
176 alNum pkgNum = alKey2Num(al, pkgKey);
177 availablePackage alp = NULL;
179 if (al != NULL && pkgNum >= 0 && pkgNum < alGetSize(al)) {
180 if (al->list != NULL)
181 alp = al->list + pkgNum;
187 rpmal rpmalCreate(int delta)
189 rpmal al = xcalloc(1, sizeof(*al));
190 availableIndex ai = &al->index;
194 al->list = xcalloc(al->delta, sizeof(*al->list));
195 al->alloced = al->delta;
205 rpmal rpmalFree(rpmal al)
207 availablePackage alp;
214 if ((alp = al->list) != NULL)
215 for (i = 0; i < al->size; i++, alp++) {
216 alp->provides = rpmdsFree(alp->provides);
217 alp->fi = rpmfiFree(alp->fi);
220 if ((die = al->dirs) != NULL)
221 for (i = 0; i < al->numDirs; i++, die++) {
222 die->dirName = _free(die->dirName);
223 die->files = _free(die->files);
225 al->dirs = _free(al->dirs);
228 al->list = _free(al->list);
236 * Compare two directory info entries by name (qsort/bsearch).
237 * @param one 1st directory info
238 * @param two 2nd directory info
239 * @return result of comparison
241 static int dieCompare(const void * one, const void * two)
245 const dirInfo a = (const dirInfo) one;
246 const dirInfo b = (const dirInfo) two;
248 int lenchk = a->dirNameLen - b->dirNameLen;
250 if (lenchk || a->dirNameLen == 0)
253 if (a->dirName == NULL || b->dirName == NULL)
256 /* XXX FIXME: this might do "backward" strcmp for speed */
257 return strcmp(a->dirName, b->dirName);
261 * Compare two file info entries by name (qsort/bsearch).
262 * @param one 1st directory info
263 * @param two 2nd directory info
264 * @return result of comparison
266 static int fieCompare(const void * one, const void * two)
270 const fileIndexEntry a = (const fileIndexEntry) one;
271 const fileIndexEntry b = (const fileIndexEntry) two;
273 int lenchk = a->baseNameLen - b->baseNameLen;
278 if (a->baseName == NULL || b->baseName == NULL)
281 /* XXX FIXME: this might do "backward" strcmp for speed */
282 return strcmp(a->baseName, b->baseName);
285 void rpmalDel(rpmal al, alKey pkgKey)
287 alNum pkgNum = alKey2Num(al, pkgKey);
288 availablePackage alp;
291 if (al == NULL || al->list == NULL)
292 return; /* XXX can't happen */
294 alp = al->list + pkgNum;
298 fprintf(stderr, "*** del %p[%d]\n", al->list, pkgNum);
301 /* Delete directory/file info entries from added package list. */
302 if ((fi = alp->fi) != NULL)
303 if (rpmfiFC(fi) > 0) {
304 int origNumDirs = al->numDirs;
307 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
312 /* XXX FIXME: We ought to relocate the directory list here */
314 if (al->dirs != NULL)
315 for (dx = rpmfiDC(fi) - 1; dx >= 0; dx--)
319 (void) rpmfiSetDX(fi, dx);
321 /*@-assignexpose -dependenttrans -observertrans@*/
322 dieNeedle->dirName = (char *) rpmfiDN(fi);
323 /*@=assignexpose =dependenttrans =observertrans@*/
324 dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
325 ? strlen(dieNeedle->dirName) : 0);
327 die = bsearch(dieNeedle, al->dirs, al->numDirs,
328 sizeof(*dieNeedle), dieCompare);
333 last = die->numFiles;
334 fie = die->files + last - 1;
335 for (i = last - 1; i >= 0; i--, fie--) {
336 if (fie->pkgNum != pkgNum)
337 /*@innercontinue@*/ continue;
339 if (i > die->numFiles)
340 /*@innercontinue@*/ continue;
342 memmove(fie, fie+1, (die->numFiles - i) * sizeof(*fie));
345 if (die->numFiles > 0) {
347 die->files = xrealloc(die->files,
348 die->numFiles * sizeof(*die->files));
351 die->files = _free(die->files);
352 die->dirName = _free(die->dirName);
354 if ((die - al->dirs) > al->numDirs)
357 memmove(die, die+1, (al->numDirs - (die - al->dirs)) * sizeof(*die));
361 if (origNumDirs > al->numDirs) {
363 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
365 al->dirs = _free(al->dirs);
369 alp->provides = rpmdsFree(alp->provides);
370 alp->fi = rpmfiFree(alp->fi);
373 memset(alp, 0, sizeof(*alp)); /* XXX trash and burn */
379 alKey rpmalAdd(rpmal * alistp, alKey pkgKey, fnpyKey key,
380 rpmds provides, rpmfi fi, uint_32 tscolor)
384 availablePackage alp;
386 /* If list doesn't exist yet, create. */
388 *alistp = rpmalCreate(5);
390 pkgNum = alKey2Num(al, pkgKey);
392 if (pkgNum >= 0 && pkgNum < al->size) {
393 rpmalDel(al, pkgKey);
395 if (al->size == al->alloced) {
396 al->alloced += al->delta;
397 al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
402 if (al->list == NULL)
403 return RPMAL_NOMATCH; /* XXX can't happen */
405 alp = al->list + pkgNum;
408 alp->tscolor = tscolor;
412 fprintf(stderr, "*** add %p[%d] 0x%x\n", al->list, pkgNum, tscolor);
415 alp->provides = rpmdsLink(provides, "Provides (rpmalAdd)");
416 alp->fi = rpmfiLink(fi, "Files (rpmalAdd)");
418 fi = rpmfiLink(alp->fi, "Files index (rpmalAdd)");
419 fi = rpmfiInit(fi, 0);
420 if (rpmfiFC(fi) > 0) {
423 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
432 /* XXX FIXME: We ought to relocate the directory list here */
434 dirMapping = alloca(sizeof(*dirMapping) * dc);
437 * Allocated enough space for all the directories we could possible
440 al->dirs = xrealloc(al->dirs, (al->numDirs + dc) * sizeof(*al->dirs));
441 origNumDirs = al->numDirs;
443 for (dx = 0; dx < dc; dx++) {
445 (void) rpmfiSetDX(fi, dx);
447 /*@-assignexpose -dependenttrans -observertrans@*/
448 dieNeedle->dirName = (char *) rpmfiDN(fi);
449 /*@=assignexpose =dependenttrans =observertrans@*/
450 dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
451 ? strlen(dieNeedle->dirName) : 0);
452 die = bsearch(dieNeedle, al->dirs, origNumDirs,
453 sizeof(*dieNeedle), dieCompare);
455 dirMapping[dx] = die - al->dirs;
457 dirMapping[dx] = al->numDirs;
458 die = al->dirs + al->numDirs;
459 if (dieNeedle->dirName != NULL)
460 die->dirName = xstrdup(dieNeedle->dirName);
461 die->dirNameLen = dieNeedle->dirNameLen;
466 fprintf(stderr, "+++ die[%3d] %p [%d] %s\n", al->numDirs, die, die->dirNameLen, die->dirName);
473 for (first = rpmfiNext(fi); first >= 0;) {
477 /* Find the first file of the next directory. */
479 while ((next = rpmfiNext(fi)) >= 0) {
480 if (dx != rpmfiDX(fi))
481 /*@innerbreak@*/ break;
483 if (next < 0) next = rpmfiFC(fi); /* XXX reset end-of-list */
485 die = al->dirs + dirMapping[dx];
486 die->files = xrealloc(die->files,
487 (die->numFiles + next - first) * sizeof(*die->files));
488 fie = die->files + die->numFiles;
490 /* Rewind to first file, generate file index entry for each file. */
491 fi = rpmfiInit(fi, first);
492 while ((first = rpmfiNext(fi)) >= 0 && first < next) {
493 /*@-assignexpose -dependenttrans -observertrans @*/
494 fie->baseName = rpmfiBN(fi);
495 /*@=assignexpose =dependenttrans =observertrans @*/
496 fie->baseNameLen = (fie->baseName ? strlen(fie->baseName) : 0);
497 fie->pkgNum = pkgNum;
498 fie->ficolor = rpmfiFColor(fi);
502 qsort(die->files, die->numFiles, sizeof(*die->files), fieCompare);
505 /* Resize the directory list. If any directories were added, resort. */
506 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
507 if (origNumDirs != al->numDirs)
508 qsort(al->dirs, al->numDirs, sizeof(*al->dirs), dieCompare);
510 fi = rpmfiUnlink(fi, "Files index (rpmalAdd)");
514 assert(((alNum)(alp - al->list)) == pkgNum);
515 return ((alKey)(alp - al->list));
520 * Compare two available index entries by name (qsort/bsearch).
521 * @param one 1st available index entry
522 * @param two 2nd available index entry
523 * @return result of comparison
525 static int indexcmp(const void * one, const void * two)
529 const availableIndexEntry a = (const availableIndexEntry) one;
530 const availableIndexEntry b = (const availableIndexEntry) two;
534 lenchk = a->entryLen - b->entryLen;
538 return strcmp(a->entry, b->entry);
541 void rpmalAddProvides(rpmal al, alKey pkgKey, rpmds provides, uint_32 tscolor)
545 alNum pkgNum = alKey2Num(al, pkgKey);
546 availableIndex ai = &al->index;
547 availableIndexEntry aie;
550 if (provides == NULL || pkgNum < 0 || pkgNum >= al->size)
552 if (ai->index == NULL || ai->k < 0 || ai->k >= ai->size)
555 if (rpmdsInit(provides) != NULL)
556 while (rpmdsNext(provides) >= 0) {
558 if ((Name = rpmdsN(provides)) == NULL)
559 continue; /* XXX can't happen */
561 /* Ignore colored provides not in our rainbow. */
562 dscolor = rpmdsColor(provides);
563 if (tscolor && dscolor && !(tscolor & dscolor))
566 aie = ai->index + ai->k;
569 aie->pkgKey = pkgKey;
571 aie->entryLen = strlen(Name);
572 ix = rpmdsIx(provides);
574 /* XXX make sure that element index fits in unsigned short */
575 assert(ix < 0x10000);
578 aie->type = IET_PROVIDES;
582 void rpmalMakeIndex(rpmal al)
585 availablePackage alp;
588 if (al == NULL || al->list == NULL) return;
592 for (i = 0; i < al->size; i++) {
594 if (alp->provides != NULL)
595 ai->size += rpmdsCount(alp->provides);
597 if (ai->size == 0) return;
599 ai->index = xrealloc(ai->index, ai->size * sizeof(*ai->index));
602 for (i = 0; i < al->size; i++) {
604 rpmalAddProvides(al, (alKey)i, alp->provides, alp->tscolor);
606 qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
610 rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
615 const char * dirName;
616 const char * baseName;
618 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
620 fileIndexEntry fieNeedle =
621 memset(alloca(sizeof(*fieNeedle)), 0, sizeof(*fieNeedle));
623 availablePackage alp;
624 fnpyKey * ret = NULL;
625 const char * fileName;
627 if (keyp) *keyp = RPMAL_NOMATCH;
629 if (al == NULL || (fileName = rpmdsN(ds)) == NULL || *fileName != '/')
632 /* Solaris 2.6 bsearch sucks down on this. */
633 if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
637 dirName = t = xstrdup(fileName);
638 if ((t = strrchr(t, '/')) != NULL) {
639 t++; /* leave the trailing '/' */
644 dieNeedle->dirName = (char *) dirName;
645 dieNeedle->dirNameLen = strlen(dirName);
646 die = bsearch(dieNeedle, al->dirs, al->numDirs,
647 sizeof(*dieNeedle), dieCompare);
651 /* rewind to the first match */
652 while (die > al->dirs && dieCompare(die-1, dieNeedle) == 0)
655 if ((baseName = strrchr(fileName, '/')) == NULL)
659 /*@-branchstate@*/ /* FIX: ret is a problem */
660 for (found = 0, ret = NULL;
661 die <= al->dirs + al->numDirs && dieCompare(die, dieNeedle) == 0;
667 fprintf(stderr, "==> die %p %s\n", die, (die->dirName ? die->dirName : "(nil)"));
671 fieNeedle->baseName = baseName;
673 fieNeedle->baseNameLen = strlen(fieNeedle->baseName);
674 fie = bsearch(fieNeedle, die->files, die->numFiles,
675 sizeof(*fieNeedle), fieCompare);
677 continue; /* XXX shouldn't happen */
681 fprintf(stderr, "==> fie %p %s\n", fie, (fie->baseName ? fie->baseName : "(nil)"));
684 alp = al->list + fie->pkgNum;
686 /* Ignore colored files not in our rainbow. */
687 tscolor = alp->tscolor;
688 ficolor = fie->ficolor;
689 if (tscolor && ficolor && !(tscolor & ficolor))
692 rpmdsNotify(ds, _("(added files)"), 0);
694 ret = xrealloc(ret, (found+2) * sizeof(*ret));
695 if (ret) /* can't happen */
696 ret[found] = alp->key;
698 *keyp = alNum2Key(al, fie->pkgNum);
704 dirName = _free(dirName);
711 rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
714 availableIndexEntry needle;
715 availableIndexEntry match;
716 fnpyKey * ret = NULL;
719 availablePackage alp;
722 if (keyp) *keyp = RPMAL_NOMATCH;
724 if (al == NULL || ds == NULL || (KName = rpmdsN(ds)) == NULL)
728 /* First, look for files "contained" in package ... */
729 ret = rpmalAllFileSatisfiesDepend(al, ds, keyp);
730 if (ret != NULL && *ret != NULL)
732 /* ... then, look for files "provided" by package. */
736 if (ai->index == NULL || ai->size <= 0)
739 needle = memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
740 /*@-assignexpose -temptrans@*/
741 needle->entry = KName;
742 /*@=assignexpose =temptrans@*/
743 needle->entryLen = strlen(needle->entry);
745 match = bsearch(needle, ai->index, ai->size, sizeof(*ai->index), indexcmp);
749 /* rewind to the first match */
750 while (match > ai->index && indexcmp(match-1, needle) == 0)
753 if (al->list != NULL) /* XXX always true */
754 for (ret = NULL, found = 0;
755 match < ai->index + ai->size && indexcmp(match, needle) == 0;
758 alp = al->list + alKey2Num(al, match->pkgKey);
761 if (alp->provides != NULL) /* XXX can't happen */
762 switch (match->type) {
764 /* XXX single step on rpmdsNext to regenerate DNEVR string */
765 (void) rpmdsSetIx(alp->provides, match->entryIx - 1);
766 if (rpmdsNext(alp->provides) >= 0)
767 rc = rpmdsCompare(alp->provides, ds);
770 rpmdsNotify(ds, _("(added provide)"), 0);
772 /*@switchbreak@*/ break;
777 ret = xrealloc(ret, (found + 2) * sizeof(*ret));
778 if (ret) /* can't happen */
779 ret[found] = alp->key;
780 /*@-dependenttrans@*/
782 *keyp = match->pkgKey;
783 /*@=dependenttrans@*/
792 /*@-nullstate@*/ /* FIX: *keyp may be NULL */
798 rpmalSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
800 fnpyKey * tmp = rpmalAllSatisfiesDepend(al, ds, keyp);
803 fnpyKey ret = tmp[0];