15 /*@access Header@*/ /* XXX compared with NULL */
16 /*@access FD_t@*/ /* XXX compared with NULL */
18 typedef /*@abstract@*/ struct fileIndexEntry_s * fileIndexEntry;
19 typedef /*@abstract@*/ struct dirInfo_s * dirInfo;
20 typedef /*@abstract@*/ struct availableIndexEntry_s * availableIndexEntry;
21 typedef /*@abstract@*/ struct availableIndex_s * availableIndex;
23 /*@access availableIndexEntry@*/
24 /*@access availableIndex@*/
25 /*@access fileIndexEntry@*/
27 /*@access availableList@*/
29 /*@access availablePackage@*/
30 /*@access tsortInfo@*/
36 /*@access rpmDepSet@*/
39 * Info about a single package to be installed.
41 struct availablePackage_s {
43 Header h; /*!< Package header. */
45 const char * name; /*!< Header name. */
47 const char * version; /*!< Header version. */
49 const char * release; /*!< Header release. */
50 /*@dependent@*//*@null@*/
51 int_32 * epoch; /*!< Header epoch (if any). */
53 /*@owned@*/ /*@null@*/
54 rpmDepSet provides; /*!< Provides: dependencies. */
55 /*@owned@*/ /*@null@*/
56 rpmDepSet requires; /*!< Requires: dependencies. */
58 rpmFNSet fns; /*!< File name set. */
61 uint_32 multiLib; /* MULTILIB */
67 * A single available item (e.g. a Provides: dependency).
69 struct availableIndexEntry_s {
70 /*@dependent@*/ /*@null@*/
71 alKey pkgKey; /*!< Containing package. */
73 const char * entry; /*!< Dependency name. */
74 unsigned short entryLen; /*!< No. of bytes in name. */
75 unsigned short entryIx; /*!< Dependency index. */
77 IET_PROVIDES=1 /*!< A Provides: dependency. */
78 } type; /*!< Type of available item. */
82 * Index of all available items.
84 struct availableIndex_s {
86 availableIndexEntry index; /*!< Array of available items. */
87 int size; /*!< No. of available items. */
88 int k; /*!< Current index. */
92 * A file to be installed/removed.
94 struct fileIndexEntry_s {
96 const char * baseName; /*!< File basename. */
98 alNum pkgNum; /*!< Containing package index. */
99 int fileFlags; /* MULTILIB */
103 * A directory to be installed/removed.
107 const char * dirName; /*!< Directory path (+ trailing '/'). */
108 int dirNameLen; /*!< No. bytes in directory path. */
110 fileIndexEntry files; /*!< Array of files in directory. */
111 int numFiles; /*!< No. files in directory. */
115 * Set of available packages, items, and directories.
117 struct availableList_s {
118 /*@owned@*/ /*@null@*/
119 availablePackage list; /*!< Set of packages. */
120 struct availableIndex_s index; /*!< Set of available items. */
121 int delta; /*!< Delta for pkg list reallocation. */
122 int size; /*!< No. of pkgs in list. */
123 int alloced; /*!< No. of pkgs allocated for list. */
124 int numDirs; /*!< No. of directories. */
125 /*@owned@*/ /*@null@*/
126 dirInfo dirs; /*!< Set of directories. */
130 static int _al_debug = 0;
133 * Destroy available item index.
134 * @param al available list
136 static void alFreeIndex(availableList al)
139 availableIndex ai = &al->index;
141 ai->index = _free(ai->index);
146 int alGetSize(const availableList al)
151 static inline alNum alKey2Num(/*@unused@*/ /*@null@*/ const availableList al,
152 /*@null@*/ alKey pkgKey)
155 /*@-nullret -temptrans -retalias @*/
156 return ((alNum)pkgKey);
157 /*@=nullret =temptrans =retalias @*/
160 static inline alKey alNum2Key(/*@unused@*/ /*@null@*/ const availableList al,
161 /*@null@*/ alNum pkgNum)
164 /*@-nullret -temptrans -retalias @*/
165 return ((alKey)pkgNum);
166 /*@=nullret =temptrans =retalias @*/
169 availablePackage alGetPkg(const availableList al, alKey pkgKey)
171 availablePackage alp = NULL;
172 alNum pkgNum = alKey2Num(al, pkgKey);
174 if (al != NULL && pkgNum >= 0 && pkgNum < al->size) {
175 if (al->list != NULL)
176 alp = al->list + pkgNum;
180 fprintf(stderr, "*** alp[%d] %p\n", pkgNum, alp);
186 int alGetMultiLib(const availableList al, alKey pkgKey)
188 availablePackage alp = alGetPkg(al, alKey);
189 return (alp != NULL ? alp->multiLib : 0);
194 int alGetFilesCount(const availableList al, alKey pkgKey)
196 availablePackage alp = alGetPkg(al, pkgKey);
197 int_32 filesCount = 0;
199 if (alp->fns != NULL)
200 filesCount = alp->fns->Count;
205 rpmDepSet alGetProvides(const availableList al, alKey pkgKey)
207 availablePackage alp = alGetPkg(al, pkgKey);
209 return (alp != NULL ? alp->provides : 0);
213 rpmDepSet alGetRequires(const availableList al, alKey pkgKey)
215 availablePackage alp = alGetPkg(al, pkgKey);
217 return (alp != NULL ? alp->requires : 0);
221 Header alGetHeader(availableList al, alKey pkgKey, int unlink)
223 availablePackage alp = alGetPkg(al, pkgKey);
226 if (alp != NULL && alp->h != NULL) {
227 h = headerLink(alp->h, "alGetHeader");
229 alp->h = headerFree(alp->h, "alGetHeader unlink");
236 char * alGetNVR(const availableList al, alKey pkgKey)
238 availablePackage alp = alGetPkg(al, pkgKey);
239 char * pkgNVR = NULL;
243 t = xcalloc(1, strlen(alp->name) +
244 strlen(alp->version) +
245 strlen(alp->release) + sizeof("--"));
247 t = stpcpy(t, alp->name);
249 t = stpcpy(t, alp->version);
251 t = stpcpy(t, alp->release);
256 availableList alCreate(int delta)
258 availableList al = xcalloc(1, sizeof(*al));
259 availableIndex ai = &al->index;
263 al->list = xcalloc(al->delta, sizeof(*al->list));
264 al->alloced = al->delta;
274 availableList alFree(availableList al)
276 availablePackage alp;
283 if ((alp = al->list) != NULL)
284 for (i = 0; i < al->size; i++, alp++) {
286 alp->provides = dsFree(alp->provides);
287 alp->requires = dsFree(alp->requires);
289 alp->fns = fnsFree(alp->fns);
291 alp->h = headerFree(alp->h, "alFree");
295 if ((die = al->dirs) != NULL)
296 for (i = 0; i < al->numDirs; i++, die++) {
297 die->dirName = _free(die->dirName);
298 die->files = _free(die->files);
300 al->dirs = _free(al->dirs);
303 al->list = _free(al->list);
310 * Compare two directory info entries by name (qsort/bsearch).
311 * @param one 1st directory info
312 * @param two 2nd directory info
313 * @return result of comparison
315 static int dieCompare(const void * one, const void * two)
319 const dirInfo a = (const dirInfo) one;
320 const dirInfo b = (const dirInfo) two;
322 int lenchk = a->dirNameLen - b->dirNameLen;
327 /* XXX FIXME: this might do "backward" strcmp for speed */
328 return strcmp(a->dirName, b->dirName);
332 * Compare two file info entries by name (qsort/bsearch).
333 * @param one 1st directory info
334 * @param two 2nd directory info
335 * @return result of comparison
337 static int fieCompare(const void * one, const void * two)
341 const fileIndexEntry a = (const fileIndexEntry) one;
342 const fileIndexEntry b = (const fileIndexEntry) two;
344 int lenchk = a->baseNameLen - b->baseNameLen;
349 /* XXX FIXME: this might do "backward" strcmp for speed */
350 return strcmp(a->baseName, b->baseName);
353 void alDelPackage(availableList al, alKey pkgKey)
356 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
357 HFD_t hfd = headerFreeData;
359 availablePackage alp;
361 alNum pkgNum = alKey2Num(al, pkgKey);
363 /*@-nullptrarith@*/ /* FIX: al->list might be NULL */
364 alp = al->list + pkgNum;
369 fprintf(stderr, "*** del %p[%d] %s-%s-%s\n", al->list, pkgNum, alp->name, alp->version, alp->release);
372 /* Delete directory/file info entries from added package list. */
373 if ((fns = alp->fns) != NULL)
374 if (fns->BN != NULL && fns->Count > 0) {
375 int origNumDirs = al->numDirs;
377 const char ** dirNames;
383 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
389 xx = hge(alp->h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, &numDirs);
392 /* XXX FIXME: We ought to relocate the directory list here */
394 if (al->dirs != NULL)
396 for (dirNum = fns->DCount - 1; dirNum >= 0; dirNum--) {
400 dieNeedle->dirName = (char *) fns->DN[dirNum];
402 dieNeedle->dirNameLen = strlen(dieNeedle->dirName);
403 die = bsearch(dieNeedle, al->dirs, al->numDirs,
404 sizeof(*dieNeedle), dieCompare);
408 last = die->numFiles;
409 fie = die->files + last - 1;
410 for (i = last - 1; i >= 0; i--, fie--) {
411 if (fie->pkgNum != pkgNum)
412 /*@innercontinue@*/ continue;
414 if (i > die->numFiles)
415 /*@innercontinue@*/ continue;
416 memmove(fie, fie+1, (die->numFiles - i));
418 if (die->numFiles > 0) {
420 die->files = xrealloc(die->files,
421 die->numFiles * sizeof(*die->files));
424 die->files = _free(die->files);
425 die->dirName = _free(die->dirName);
427 if ((die - al->dirs) > al->numDirs)
429 memmove(die, die+1, (al->numDirs - (die - al->dirs)));
432 if (origNumDirs > al->numDirs) {
434 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
436 al->dirs = _free(al->dirs);
440 dirNames = hfd(dirNames, dnt);
444 alp->provides = dsFree(alp->provides);
445 alp->requires = dsFree(alp->requires);
446 alp->fns = fnsFree(alp->fns);
447 alp->h = headerFree(alp->h, "alDelPackage");
449 memset(alp, 0, sizeof(*alp)); /* XXX trash and burn */
450 /*@-nullstate@*/ /* FIX: al->list->h may be NULL */
455 alKey alAddPackage(availableList al, alKey pkgKey, Header h)
456 /*@modifies al, h @*/
459 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
461 HFD_t hfd = headerFreeData;
463 availablePackage alp;
464 alNum pkgNum = alKey2Num(al, pkgKey);
467 uint_32 multiLibMask = 0;
472 if (pkgNum >= 0 && pkgNum < al->size) {
473 alDelPackage(al, pkgKey);
475 if (al->size == al->alloced) {
476 al->alloced += al->delta;
477 al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
483 alp = al->list + pkgNum;
486 alp->h = headerLink(h, "alAddPackage");
488 alp->multiLib = 0; /* MULTILIB */
491 xx = headerNVR(alp->h, &alp->name, &alp->version, &alp->release);
495 fprintf(stderr, "*** add %p[%d] %s-%s-%s\n", al->list, pkgNum, alp->name, alp->version, alp->release);
499 { uint_32 *pp = NULL;
500 /* XXX This should be added always so that packages look alike.
501 * XXX However, there is logic in files.c/depends.c that checks for
502 * XXX existence (rather than value) that will need to change as well.
504 if (hge(alp->h, RPMTAG_MULTILIBS, NULL, (void **) &pp, NULL))
508 for (i = 0; i < pkgNum - 1; i++) {
509 if (!strcmp (alp->name, al->list[i].name)
510 && hge(al->list[i].h, RPMTAG_MULTILIBS, NULL,
512 && !rpmVersionCompare(alp->h, al->list[i].h)
513 && *pp && !(*pp & multiLibMask))
514 alp->multiLib = multiLibMask;
520 if (!hge(h, RPMTAG_EPOCH, NULL, (void **) &alp->epoch, NULL))
523 alp->provides = dsNew(h, RPMTAG_PROVIDENAME, scareMem);
524 alp->requires = dsNew(h, RPMTAG_REQUIRENAME, scareMem);
526 alp->fns = fns = fnsNew(h, RPMTAG_BASENAMES, scareMem);
528 if (fns && fns->Count > 0) {
531 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
533 int first, last, dirNum;
536 /* XXX FIXME: We ought to relocate the directory list here */
538 dirMapping = alloca(sizeof(*dirMapping) * fns->DCount);
540 /* allocated enough space for all the directories we could possible
542 al->dirs = xrealloc(al->dirs,
543 (al->numDirs + fns->DCount) * sizeof(*al->dirs));
544 origNumDirs = al->numDirs;
547 for (dirNum = 0; dirNum < fns->DCount; dirNum++) {
549 dieNeedle->dirName = (char *) fns->DN[dirNum];
551 dieNeedle->dirNameLen = strlen(fns->DN[dirNum]);
552 die = bsearch(dieNeedle, al->dirs, origNumDirs,
553 sizeof(*dieNeedle), dieCompare);
555 dirMapping[dirNum] = die - al->dirs;
557 dirMapping[dirNum] = al->numDirs;
558 die = al->dirs + al->numDirs;
559 die->dirName = xstrdup(fns->DN[dirNum]);
560 die->dirNameLen = strlen(die->dirName);
568 fns->DN = hfd(fns->DN, fns->DNt);
572 for (first = 0; first < fns->Count; first = last + 1) {
575 if (fns->DI == NULL) /* XXX can't happen */
578 for (last = first; (last + 1) < fns->Count; last++) {
579 if (fns->DI[first] != fns->DI[last + 1])
580 /*@innerbreak@*/ break;
583 die = al->dirs + dirMapping[fns->DI[first]];
584 die->files = xrealloc(die->files,
585 (die->numFiles + last - first + 1) *
586 sizeof(*die->files));
588 fie = die->files + die->numFiles;
589 for (fns->i = first; fns->i <= last; fns->i++) {
590 if (fns->BN == NULL) /* XXX can't happen */
591 /*@innercontinue@*/ continue;
592 if (fns->Flags == NULL) /* XXX can't happen */
593 /*@innercontinue@*/ continue;
595 fie->baseName = fns->BN[fns->i];
596 fie->baseNameLen = strlen(fns->BN[fns->i]);
598 fie->pkgNum = pkgNum;
599 fie->fileFlags = fns->Flags[fns->i];
603 qsort(die->files, die->numFiles, sizeof(*die->files), fieCompare);
606 /* XXX should we realloc al->dirs to actual size? */
608 /* If any directories were added, resort the directory list. */
609 if (origNumDirs != al->numDirs)
610 qsort(al->dirs, al->numDirs, sizeof(*al->dirs), dieCompare);
616 assert(((alNum)(alp - al->list)) == pkgNum);
617 return ((alKey)(alp - al->list));
621 * Compare two available index entries by name (qsort/bsearch).
622 * @param one 1st available index entry
623 * @param two 2nd available index entry
624 * @return result of comparison
626 static int indexcmp(const void * one, const void * two)
630 const availableIndexEntry a = (const availableIndexEntry) one;
631 const availableIndexEntry b = (const availableIndexEntry) two;
635 lenchk = a->entryLen - b->entryLen;
639 return strcmp(a->entry, b->entry);
642 void alAddProvides(availableList al, alKey pkgKey, rpmDepSet provides)
644 availableIndex ai = &al->index;
645 int i = alKey2Num(al, pkgKey);
647 if (provides == NULL || i < 0 || i >= al->size)
649 if (ai->index == NULL || ai->k < 0 || ai->k >= ai->size)
652 if (dsiInit(provides) != NULL)
653 while (dsiNext(provides) >= 0) {
656 #ifdef DYING /* XXX FIXME: multilib colored dependency search */
657 const int_32 Flags = dsiGetFlags(provides);
659 /* If multilib install, skip non-multilib provides. */
660 if (al->list[i].multiLib && !isDependsMULTILIB(Flags)) {
662 /*@innercontinue@*/ continue;
666 if ((Name = dsiGetN(provides)) == NULL)
667 continue; /* XXX can't happen */
671 ai->index[ai->k].pkgKey = pkgKey;
673 ai->index[ai->k].entry = Name;
675 ai->index[ai->k].entryLen = strlen(Name);
676 assert(provides->i < 0x10000);
677 ai->index[ai->k].entryIx = provides->i;
678 ai->index[ai->k].type = IET_PROVIDES;
683 void alMakeIndex(availableList al)
685 availableIndex ai = &al->index;
688 if (ai->size || al->list == NULL) return;
690 for (i = 0; i < al->size; i++)
691 if (al->list[i].provides != NULL)
692 ai->size += al->list[i].provides->Count;
695 ai->index = xcalloc(ai->size, sizeof(*ai->index));
698 for (i = 0; i < al->size; i++)
699 alAddProvides(al, (alKey)i, al->list[i].provides);
701 qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
705 alKey * alAllFileSatisfiesDepend(const availableList al, const rpmDepSet ds)
708 const char * dirName;
709 const char * baseName;
711 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
713 fileIndexEntry fieNeedle =
714 memset(alloca(sizeof(*fieNeedle)), 0, sizeof(*fieNeedle));
717 const char * fileName;
719 if ((fileName = dsiGetN(ds)) == NULL || *fileName != '/')
722 /* Solaris 2.6 bsearch sucks down on this. */
723 if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
727 dirName = t = xstrdup(fileName);
728 if ((t = strrchr(t, '/')) != NULL) {
729 t++; /* leave the trailing '/' */
734 dieNeedle->dirName = (char *) dirName;
735 dieNeedle->dirNameLen = strlen(dirName);
736 die = bsearch(dieNeedle, al->dirs, al->numDirs,
737 sizeof(*dieNeedle), dieCompare);
741 /* rewind to the first match */
742 while (die > al->dirs && dieCompare(die-1, dieNeedle) == 0)
745 if ((baseName = strrchr(fileName, '/')) == NULL)
749 /*@-branchstate@*/ /* FIX: ret is a problem */
750 for (found = 0, ret = NULL;
751 die <= al->dirs + al->numDirs && dieCompare(die, dieNeedle) == 0;
755 fieNeedle->baseName = baseName;
756 fieNeedle->baseNameLen = strlen(fieNeedle->baseName);
757 fie = bsearch(fieNeedle, die->files, die->numFiles,
758 sizeof(*fieNeedle), fieCompare);
760 continue; /* XXX shouldn't happen */
762 #ifdef DYING /* XXX FIXME: multilib colored dependency search */
764 * If a file dependency would be satisfied by a file
765 * we are not going to install, skip it.
767 if (al->list[fie->pkgNum].multiLib && !isFileMULTILIB(fie->fileFlags))
771 dsiNotify(ds, _("(added files)"), 0);
773 ret = xrealloc(ret, (found+2) * sizeof(*ret));
774 if (ret) /* can't happen */
775 ret[found++] = alNum2Key(al, fie->pkgNum);
780 dirName = _free(dirName);
781 /*@-mods@*/ /* AOK: al->list not modified through ret alias. */
790 * Check added package file lists for first package that provides a file.
791 * @param al available list
792 * @param ds dependency
793 * @return available package pointer
795 /*@unused@*/ static /*@dependent@*/ /*@null@*/ alKey
796 alFileSatisfiesDepend(const availableList al, const rpmDepSet ds)
800 alKey * tmp = alAllFileSatisfiesDepend(al, ds);
811 alAllSatisfiesDepend(const availableList al, const rpmDepSet ds)
813 availableIndex ai = &al->index;
814 availableIndexEntry needle =
815 memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
816 availableIndexEntry match;
819 availablePackage alp;
822 if ((KName = dsiGetN(ds)) == NULL)
826 ret = alAllFileSatisfiesDepend(al, ds);
827 /* XXX Provides: /path was broken with added packages (#52183). */
828 if (ret != NULL && *ret != NULL)
832 if (ai->index == NULL || ai->size <= 0)
835 /*@-assignexpose -temptrans@*/
836 needle->entry = KName;
837 /*@=assignexpose =temptrans@*/
838 needle->entryLen = strlen(needle->entry);
840 match = bsearch(needle, ai->index, ai->size, sizeof(*ai->index), indexcmp);
844 /* rewind to the first match */
845 while (match > ai->index && indexcmp(match-1, needle) == 0)
848 for (ret = NULL, found = 0;
849 match <= ai->index + ai->size && indexcmp(match, needle) == 0;
853 alp = al->list + alKey2Num(al, match->pkgKey);
857 if (alp->provides != NULL) /* XXX can't happen */
858 switch (match->type) {
860 alp->provides->i = match->entryIx;
862 /* XXX single step on dsiNext to regenerate DNEVR string */
864 if (dsiNext(alp->provides) >= 0)
865 rc = dsCompare(alp->provides, ds);
868 dsiNotify(ds, _("(added provide)"), 0);
870 /*@switchbreak@*/ break;
875 ret = xrealloc(ret, (found + 2) * sizeof(*ret));
876 if (ret) /* can't happen */
877 ret[found++] = ((alKey)(alp - al->list));
888 alKey alSatisfiesDepend(const availableList al, const rpmDepSet ds)
890 alKey * tmp = alAllSatisfiesDepend(al, ds);
897 return RPMAL_NOMATCH;