15 typedef struct availablePackage_s * availablePackage;
21 * Info about a single package to be installed.
23 struct availablePackage_s {
24 rpmds provides; /*!< Provides: dependencies. */
25 rpmfi fi; /*!< File info set. */
27 uint32_t tscolor; /*!< Transaction color bits. */
29 fnpyKey key; /*!< Associated file name/python object */
33 typedef struct availableIndexEntry_s * availableIndexEntry;
36 * A single available item (e.g. a Provides: dependency).
38 struct availableIndexEntry_s {
39 rpmalKey pkgKey; /*!< Containing package. */
40 const char * entry; /*!< Dependency name. */
41 unsigned short entryLen; /*!< No. of bytes in name. */
42 unsigned short entryIx; /*!< Dependency index. */
44 IET_PROVIDES=1 /*!< A Provides: dependency. */
45 } type; /*!< Type of available item. */
48 typedef struct availableIndex_s * availableIndex;
51 * Index of all available items.
53 struct availableIndex_s {
54 availableIndexEntry index; /*!< Array of available items. */
55 int size; /*!< No. of available items. */
56 int k; /*!< Current index. */
59 typedef struct fileIndexEntry_s * fileIndexEntry;
62 * A file to be installed/removed.
64 struct fileIndexEntry_s {
65 const char * baseName; /*!< File basename. */
67 rpmalNum pkgNum; /*!< Containing package index. */
71 typedef struct dirInfo_s * dirInfo;
74 * A directory to be installed/removed.
77 const char * dirName; /*!< Directory path (+ trailing '/'). */
78 int dirNameLen; /*!< No. bytes in directory path. */
79 fileIndexEntry files; /*!< Array of files in directory. */
80 int numFiles; /*!< No. files in directory. */
84 * Set of available packages, items, and directories.
87 availablePackage list; /*!< Set of packages. */
88 struct availableIndex_s index; /*!< Set of available items. */
89 int delta; /*!< Delta for pkg list reallocation. */
90 int size; /*!< No. of pkgs in list. */
91 int alloced; /*!< No. of pkgs allocated for list. */
92 uint32_t tscolor; /*!< Transaction color. */
93 int numDirs; /*!< No. of directories. */
94 dirInfo dirs; /*!< Set of directories. */
98 * Destroy available item index.
99 * @param al available list
101 static void rpmalFreeIndex(rpmal al)
103 availableIndex ai = &al->index;
105 ai->index = _free(ai->index);
110 static inline rpmalNum alKey2Num(const rpmal al,
113 return ((rpmalNum)pkgKey);
116 static inline rpmalKey alNum2Key(const rpmal al,
119 return ((rpmalKey)pkgNum);
122 rpmal rpmalCreate(int delta)
124 rpmal al = xcalloc(1, sizeof(*al));
125 availableIndex ai = &al->index;
129 al->list = xcalloc(al->delta, sizeof(*al->list));
130 al->alloced = al->delta;
140 rpmal rpmalFree(rpmal al)
142 availablePackage alp;
149 if ((alp = al->list) != NULL)
150 for (i = 0; i < al->size; i++, alp++) {
151 alp->provides = rpmdsFree(alp->provides);
152 alp->fi = rpmfiFree(alp->fi);
155 if ((die = al->dirs) != NULL)
156 for (i = 0; i < al->numDirs; i++, die++) {
157 die->dirName = _free(die->dirName);
158 die->files = _free(die->files);
160 al->dirs = _free(al->dirs);
163 al->list = _free(al->list);
171 * Compare two directory info entries by name (qsort/bsearch).
172 * @param one 1st directory info
173 * @param two 2nd directory info
174 * @return result of comparison
176 static int dieCompare(const void * one, const void * two)
178 const dirInfo a = (const dirInfo) one;
179 const dirInfo b = (const dirInfo) two;
180 int lenchk = a->dirNameLen - b->dirNameLen;
182 if (lenchk || a->dirNameLen == 0)
185 if (a->dirName == NULL || b->dirName == NULL)
188 /* XXX FIXME: this might do "backward" strcmp for speed */
189 return strcmp(a->dirName, b->dirName);
193 * Compare two file info entries by name (qsort/bsearch).
194 * @param one 1st directory info
195 * @param two 2nd directory info
196 * @return result of comparison
198 static int fieCompare(const void * one, const void * two)
200 const fileIndexEntry a = (const fileIndexEntry) one;
201 const fileIndexEntry b = (const fileIndexEntry) two;
202 int lenchk = a->baseNameLen - b->baseNameLen;
207 if (a->baseName == NULL || b->baseName == NULL)
212 fprintf(stderr, "\t\tstrcmp(%p:%p, %p:%p)", a, a->baseName, b, b->baseName);
214 fprintf(stderr, " a %s", a->baseName);
216 fprintf(stderr, " b %s", a->baseName);
217 fprintf(stderr, "\n");
221 return strcmp(a->baseName, b->baseName);
224 void rpmalDel(rpmal al, rpmalKey pkgKey)
226 rpmalNum pkgNum = alKey2Num(al, pkgKey);
227 availablePackage alp;
230 if (al == NULL || al->list == NULL)
231 return; /* XXX can't happen */
233 alp = al->list + pkgNum;
236 fprintf(stderr, "*** del %p[%d]\n", al->list, (int) pkgNum);
238 /* Delete directory/file info entries from added package list. */
239 if ((fi = alp->fi) != NULL)
240 if (rpmfiFC(fi) > 0) {
241 int origNumDirs = al->numDirs;
244 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
249 /* XXX FIXME: We ought to relocate the directory list here */
251 if (al->dirs != NULL)
252 for (dx = rpmfiDC(fi) - 1; dx >= 0; dx--)
256 (void) rpmfiSetDX(fi, dx);
258 dieNeedle->dirName = (char *) rpmfiDN(fi);
259 dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
260 ? strlen(dieNeedle->dirName) : 0);
261 die = bsearch(dieNeedle, al->dirs, al->numDirs,
262 sizeof(*dieNeedle), dieCompare);
267 fprintf(stderr, "--- die[%5ld] %p [%3d] %s\n", (die - al->dirs), die, die->dirNameLen, die->dirName);
269 last = die->numFiles;
270 fie = die->files + last - 1;
271 for (i = last - 1; i >= 0; i--, fie--) {
272 if (fie->pkgNum != pkgNum)
276 if (i < die->numFiles) {
278 fprintf(stderr, "\t%p[%3d] memmove(%p:%p,%p:%p,0x%lx) %s <- %s\n", die->files, die->numFiles, fie, fie->baseName, fie+1, (fie+1)->baseName, ((die->numFiles - i) * sizeof(*fie)), fie->baseName, (fie+1)->baseName);
280 memmove(fie, fie+1, (die->numFiles - i) * sizeof(*fie));
283 fprintf(stderr, "\t%p[%3d] memset(%p,0,0x%lx) %p [%3d] %s\n", die->files, die->numFiles, die->files + die->numFiles, sizeof(*fie), fie->baseName, fie->baseNameLen, fie->baseName);
284 memset(die->files + die->numFiles, 0, sizeof(*fie)); /* overkill */
287 if (die->numFiles > 0) {
289 die->files = xrealloc(die->files,
290 die->numFiles * sizeof(*die->files));
293 die->files = _free(die->files);
294 die->dirName = _free(die->dirName);
296 if ((die - al->dirs) < al->numDirs) {
298 fprintf(stderr, " die[%5ld] memmove(%p,%p,0x%lx)\n", (die - al->dirs), die, die+1, ((al->numDirs - (die - al->dirs)) * sizeof(*die)));
300 memmove(die, die+1, (al->numDirs - (die - al->dirs)) * sizeof(*die));
304 fprintf(stderr, " die[%5d] memset(%p,0,0x%lx)\n", al->numDirs, al->dirs + al->numDirs, sizeof(*die));
305 memset(al->dirs + al->numDirs, 0, sizeof(*al->dirs)); /* overkill */
308 if (origNumDirs > al->numDirs) {
310 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
312 al->dirs = _free(al->dirs);
316 alp->provides = rpmdsFree(alp->provides);
317 alp->fi = rpmfiFree(alp->fi);
319 memset(alp, 0, sizeof(*alp)); /* XXX trash and burn */
323 rpmalKey rpmalAdd(rpmal * alistp, rpmalKey pkgKey, fnpyKey key,
324 rpmds provides, rpmfi fi, uint32_t tscolor)
328 availablePackage alp;
330 /* If list doesn't exist yet, create. */
332 *alistp = rpmalCreate(5);
334 pkgNum = alKey2Num(al, pkgKey);
336 if (pkgNum >= 0 && pkgNum < al->size) {
337 rpmalDel(al, pkgKey);
339 if (al->size == al->alloced) {
340 al->alloced += al->delta;
341 al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
346 if (al->list == NULL)
347 return RPMAL_NOMATCH; /* XXX can't happen */
349 alp = al->list + pkgNum;
352 alp->tscolor = tscolor;
355 fprintf(stderr, "*** add %p[%d] 0x%x\n", al->list, (int) pkgNum, tscolor);
357 alp->provides = rpmdsLink(provides, "Provides (rpmalAdd)");
358 alp->fi = rpmfiLink(fi, "Files (rpmalAdd)");
360 fi = rpmfiLink(alp->fi, "Files index (rpmalAdd)");
361 fi = rpmfiInit(fi, 0);
362 if (rpmfiFC(fi) > 0) {
364 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
366 int dc = rpmfiDC(fi);
368 int * dirMapping = alloca(sizeof(*dirMapping) * dc);
369 int * dirUnique = alloca(sizeof(*dirUnique) * dc);
375 /* XXX FIXME: We ought to relocate the directory list here */
377 /* XXX enough space for all directories, late realloc to truncate. */
378 al->dirs = xrealloc(al->dirs, (al->numDirs + dc) * sizeof(*al->dirs));
380 /* Only previously allocated dirInfo is sorted and bsearch'able. */
381 origNumDirs = al->numDirs;
383 /* Package dirnames are not currently unique. Create unique mapping. */
384 for (dx = 0; dx < dc; dx++) {
385 (void) rpmfiSetDX(fi, dx);
388 for (i = 0; i < dx; i++) {
390 (void) rpmfiSetDX(fi, i);
392 if (iDN != NULL && !strcmp(DN, iDN))
398 /* Map package dirs into transaction dirInfo index. */
399 for (dx = 0; dx < dc; dx++) {
401 /* Non-unique package dirs use the 1st entry mapping. */
402 if (dirUnique[dx] < dx) {
403 dirMapping[dx] = dirMapping[dirUnique[dx]];
407 /* Find global dirInfo mapping for first encounter. */
408 (void) rpmfiSetDX(fi, dx);
412 #if defined(__ia64__)
413 /* XXX Make sure that autorelocated file dependencies are satisfied. */
414 #define DNPREFIX "/emul/ia32-linux"
415 if (!strncmp(DN, DNPREFIX, sizeof(DNPREFIX)-1))
416 DN += sizeof(DNPREFIX)-1;
418 dieNeedle->dirName = DN;
421 dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
422 ? strlen(dieNeedle->dirName) : 0);
423 die = bsearch(dieNeedle, al->dirs, origNumDirs,
424 sizeof(*dieNeedle), dieCompare);
426 dirMapping[dx] = die - al->dirs;
428 dirMapping[dx] = al->numDirs;
429 die = al->dirs + al->numDirs;
430 if (dieNeedle->dirName != NULL)
431 die->dirName = xstrdup(dieNeedle->dirName);
432 die->dirNameLen = dieNeedle->dirNameLen;
436 fprintf(stderr, "+++ die[%5d] %p [%3d] %s\n", al->numDirs, die, die->dirNameLen, die->dirName);
442 for (first = rpmfiNext(fi); first >= 0;) {
446 /* Find the first file of the next directory. */
448 while ((next = rpmfiNext(fi)) >= 0) {
449 if (dx != rpmfiDX(fi))
452 if (next < 0) next = rpmfiFC(fi); /* XXX reset end-of-list */
454 die = al->dirs + dirMapping[dx];
455 die->files = xrealloc(die->files,
456 (die->numFiles + next - first) * sizeof(*die->files));
458 fie = die->files + die->numFiles;
461 fprintf(stderr, " die[%5d] %p->files [%p[%d],%p) -> [%p[%d],%p)\n", dirMapping[dx], die,
462 die->files, die->numFiles, die->files+die->numFiles,
463 fie, (next - first), fie + (next - first));
465 /* Rewind to first file, generate file index entry for each file. */
466 fi = rpmfiInit(fi, first);
467 while ((first = rpmfiNext(fi)) >= 0 && first < next) {
468 fie->baseName = rpmfiBN(fi);
469 fie->baseNameLen = (fie->baseName ? strlen(fie->baseName) : 0);
470 fie->pkgNum = pkgNum;
471 fie->ficolor = rpmfiFColor(fi);
473 fprintf(stderr, "\t%p[%3d] %p:%p[%2d] %s\n", die->files, die->numFiles, fie, fie->baseName, fie->baseNameLen, rpmfiFN(fi));
478 qsort(die->files, die->numFiles, sizeof(*die->files), fieCompare);
481 /* Resize the directory list. If any directories were added, resort. */
482 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
483 if (origNumDirs != al->numDirs)
484 qsort(al->dirs, al->numDirs, sizeof(*al->dirs), dieCompare);
486 fi = rpmfiUnlink(fi, "Files index (rpmalAdd)");
490 assert(((rpmalNum)(alp - al->list)) == pkgNum);
491 return ((rpmalKey)(alp - al->list));
495 * Compare two available index entries by name (qsort/bsearch).
496 * @param one 1st available index entry
497 * @param two 2nd available index entry
498 * @return result of comparison
500 static int indexcmp(const void * one, const void * two)
502 const availableIndexEntry a = (const availableIndexEntry) one;
503 const availableIndexEntry b = (const availableIndexEntry) two;
506 lenchk = a->entryLen - b->entryLen;
510 return strcmp(a->entry, b->entry);
513 void rpmalAddProvides(rpmal al, rpmalKey pkgKey, rpmds provides, uint32_t tscolor)
517 rpmalNum pkgNum = alKey2Num(al, pkgKey);
518 availableIndex ai = &al->index;
519 availableIndexEntry aie;
522 if (provides == NULL || pkgNum < 0 || pkgNum >= al->size)
524 if (ai->index == NULL || ai->k < 0 || ai->k >= ai->size)
527 if (rpmdsInit(provides) != NULL)
528 while (rpmdsNext(provides) >= 0) {
530 if ((Name = rpmdsN(provides)) == NULL)
531 continue; /* XXX can't happen */
533 /* Ignore colored provides not in our rainbow. */
534 dscolor = rpmdsColor(provides);
535 if (tscolor && dscolor && !(tscolor & dscolor))
538 aie = ai->index + ai->k;
541 aie->pkgKey = pkgKey;
543 aie->entryLen = strlen(Name);
544 ix = rpmdsIx(provides);
546 /* XXX make sure that element index fits in unsigned short */
547 assert(ix < 0x10000);
550 aie->type = IET_PROVIDES;
554 void rpmalMakeIndex(rpmal al)
557 availablePackage alp;
560 if (al == NULL || al->list == NULL) return;
564 for (i = 0; i < al->size; i++) {
566 if (alp->provides != NULL)
567 ai->size += rpmdsCount(alp->provides);
569 if (ai->size == 0) return;
571 ai->index = xrealloc(ai->index, ai->size * sizeof(*ai->index));
573 for (i = 0; i < al->size; i++) {
575 rpmalAddProvides(al, (rpmalKey)i, alp->provides, alp->tscolor);
578 /* Reset size to the no. of provides added. */
580 qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
584 rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, rpmalKey * keyp)
589 const char * dirName;
590 const char * baseName;
592 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
594 fileIndexEntry fieNeedle =
595 memset(alloca(sizeof(*fieNeedle)), 0, sizeof(*fieNeedle));
597 availablePackage alp;
598 fnpyKey * ret = NULL;
599 const char * fileName;
601 if (keyp) *keyp = RPMAL_NOMATCH;
603 if (al == NULL || (fileName = rpmdsN(ds)) == NULL || *fileName != '/')
606 /* Solaris 2.6 bsearch sucks down on this. */
607 if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
611 dirName = t = xstrdup(fileName);
612 if ((t = strrchr(t, '/')) != NULL) {
613 t++; /* leave the trailing '/' */
618 dieNeedle->dirName = (char *) dirName;
619 dieNeedle->dirNameLen = strlen(dirName);
620 die = bsearch(dieNeedle, al->dirs, al->numDirs,
621 sizeof(*dieNeedle), dieCompare);
625 /* rewind to the first match */
626 while (die > al->dirs && dieCompare(die-1, dieNeedle) == 0)
629 if ((baseName = strrchr(fileName, '/')) == NULL)
633 /* FIX: ret is a problem */
634 for (found = 0, ret = NULL;
635 die < al->dirs + al->numDirs && dieCompare(die, dieNeedle) == 0;
640 fprintf(stderr, "==> die %p %s\n", die, (die->dirName ? die->dirName : "(nil)"));
642 fieNeedle->baseName = baseName;
643 fieNeedle->baseNameLen = strlen(fieNeedle->baseName);
644 fie = bsearch(fieNeedle, die->files, die->numFiles,
645 sizeof(*fieNeedle), fieCompare);
647 continue; /* XXX shouldn't happen */
650 fprintf(stderr, "==> fie %p %s\n", fie, (fie->baseName ? fie->baseName : "(nil)"));
652 alp = al->list + fie->pkgNum;
654 /* Ignore colored files not in our rainbow. */
655 tscolor = alp->tscolor;
656 ficolor = fie->ficolor;
657 if (tscolor && ficolor && !(tscolor & ficolor))
660 rpmdsNotify(ds, _("(added files)"), 0);
662 ret = xrealloc(ret, (found+2) * sizeof(*ret));
663 if (ret) /* can't happen */
664 ret[found] = alp->key;
666 *keyp = alNum2Key(al, fie->pkgNum);
671 dirName = _free(dirName);
678 rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, rpmalKey * keyp)
681 availableIndexEntry needle;
682 availableIndexEntry match;
683 fnpyKey * ret = NULL;
686 availablePackage alp;
689 if (keyp) *keyp = RPMAL_NOMATCH;
691 if (al == NULL || ds == NULL || (KName = rpmdsN(ds)) == NULL)
695 /* First, look for files "contained" in package ... */
696 ret = rpmalAllFileSatisfiesDepend(al, ds, keyp);
697 if (ret != NULL && *ret != NULL)
699 /* ... then, look for files "provided" by package. */
704 if (ai->index == NULL || ai->size <= 0)
707 needle = memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
708 needle->entry = KName;
709 needle->entryLen = strlen(needle->entry);
711 match = bsearch(needle, ai->index, ai->size, sizeof(*ai->index), indexcmp);
715 /* rewind to the first match */
716 while (match > ai->index && indexcmp(match-1, needle) == 0)
719 if (al->list != NULL) /* XXX always true */
720 for (ret = NULL, found = 0;
721 match < ai->index + ai->size && indexcmp(match, needle) == 0;
724 alp = al->list + alKey2Num(al, match->pkgKey);
727 if (alp->provides != NULL) /* XXX can't happen */
728 switch (match->type) {
730 /* XXX single step on rpmdsNext to regenerate DNEVR string */
731 (void) rpmdsSetIx(alp->provides, match->entryIx - 1);
732 if (rpmdsNext(alp->provides) >= 0)
733 rc = rpmdsCompare(alp->provides, ds);
736 rpmdsNotify(ds, _("(added provide)"), 0);
742 ret = xrealloc(ret, (found + 2) * sizeof(*ret));
743 if (ret) /* can't happen */
744 ret[found] = alp->key;
746 *keyp = match->pkgKey;
754 /* FIX: *keyp may be NULL */
759 rpmalSatisfiesDepend(const rpmal al, const rpmds ds, rpmalKey * keyp)
761 fnpyKey * tmp = rpmalAllSatisfiesDepend(al, ds, keyp);
764 fnpyKey ret = tmp[0];