- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# lib/rpmal.c

Go to the documentation of this file.

    00001
    00005 #include "system.h"
    00006
    00007 #include <rpmio.h>
    00008 #include <rpmcb.h>              /* XXX fnpyKey */
    00009 #include <rpmlib.h>
    00010
    00011 #include "rpmal.h"
    00012 #define _RPMDS_INTERNAL
    00013 #include "rpmds.h"
    00014 #include "rpmfi.h"
    00015
    00016 #include "debug.h"
    00017
    00018 typedef /*@abstract@*/ struct availablePackage_s * availablePackage;
    00019
    00020 /*@unchecked@*/
    00021 int _rpmal_debug = 0;
    00022
    00023 /*@access alKey @*/
    00024 /*@access alNum @*/
    00025 /*@access rpmal @*/
    00026 /*@access rpmds @*/
    00027 /*@access availablePackage @*/
    00028
    00029 /*@access fnpyKey @*/   /* XXX suggestedKeys array */
    00030
    00034 struct availablePackage_s {
    00035 /*@refcounted@*/ /*@null@*/
    00036     rpmds provides;
    00037 /*@refcounted@*/ /*@null@*/
    00038     rpmfi fi;
    00040     uint32_t tscolor;
    00042 /*@exposed@*/ /*@dependent@*/ /*@null@*/
    00043     fnpyKey key;
    00045 };
    00046
    00047 typedef /*@abstract@*/ struct availableIndexEntry_s *   availableIndexEntry;
    00048 /*@access availableIndexEntry@*/
    00049
    00053 struct availableIndexEntry_s {
    00054 /*@exposed@*/ /*@dependent@*/ /*@null@*/
    00055     alKey pkgKey;
    00056 /*@observer@*/
    00057     const char * entry;
    00058     unsigned short entryLen;
    00059     unsigned short entryIx;
    00060     enum indexEntryType {
    00061         IET_PROVIDES=1
    00062     } type;
    00063 };
    00064
    00065 typedef /*@abstract@*/ struct availableIndex_s *        availableIndex;
    00066 /*@access availableIndex@*/
    00067
    00071 struct availableIndex_s {
    00072 /*@null@*/
    00073     availableIndexEntry index;
    00074     int size;
    00075     int k;
    00076 };
    00077
    00078 typedef /*@abstract@*/ struct fileIndexEntry_s *        fileIndexEntry;
    00079 /*@access fileIndexEntry@*/
    00080
    00084 struct fileIndexEntry_s {
    00085 /*@dependent@*/ /*@relnull@*/
    00086     const char * baseName;
    00087     int baseNameLen;
    00088     alNum pkgNum;
    00089     uint32_t ficolor;
    00090 };
    00091
    00092 typedef /*@abstract@*/ struct dirInfo_s *               dirInfo;
    00093 /*@access dirInfo@*/
    00094
    00098 struct dirInfo_s {
    00099 /*@owned@*/ /*@relnull@*/
    00100     const char * dirName;
    00101     int dirNameLen;
    00102 /*@owned@*/
    00103     fileIndexEntry files;
    00104     int numFiles;
    00105 };
    00106
    00110 struct rpmal_s {
    00111 /*@owned@*/ /*@null@*/
    00112     availablePackage list;
    00113     struct availableIndex_s index;
    00114     int delta;
    00115     int size;
    00116     int alloced;
    00117     uint32_t tscolor;
    00118     int numDirs;
    00119 /*@owned@*/ /*@null@*/
    00120     dirInfo dirs;
    00121 };
    00122
    00127 static void rpmalFreeIndex(rpmal al)
    00128         /*@modifies al @*/
    00129 {
    00130     availableIndex ai = &al->index;
    00131     if (ai->size > 0) {
    00132         ai->index = _free(ai->index);
    00133         ai->size = 0;
    00134     }
    00135 }
    00136
    00137 #ifdef  DYING
    00138
    00143 static int alGetSize(/*@null@*/ const rpmal al)
    00144         /*@*/
    00145 {
    00146     return (al != NULL ? al->size : 0);
    00147 }
    00148 #endif
    00149
    00150 static inline alNum alKey2Num(/*@unused@*/ /*@null@*/ const rpmal al,
    00151                 /*@null@*/ alKey pkgKey)
    00152         /*@*/
    00153 {
    00154     /*@-nullret -temptrans -retalias @*/
    00155     union { alKey key; alNum num; } u;
    00156     u.key = pkgKey;
    00157     return u.num;
    00158     /*@=nullret =temptrans =retalias @*/
    00159 }
    00160
    00161 static inline alKey alNum2Key(/*@unused@*/ /*@null@*/ const rpmal al,
    00162                 /*@null@*/ alNum pkgNum)
    00163         /*@*/
    00164 {
    00165     /*@-nullret -temptrans -retalias @*/
    00166     union { alKey key; alNum num; } u;
    00167     u.num = pkgNum;
    00168     return u.key;
    00169     /*@=nullret =temptrans =retalias @*/
    00170 }
    00171
    00172 #ifdef  DYING
    00173
    00179 /*@dependent@*/ /*@null@*/
    00180 static availablePackage alGetPkg(/*@null@*/ const rpmal al,
    00181                 /*@null@*/ alKey pkgKey)
    00182         /*@*/
    00183 {
    00184     alNum pkgNum = alKey2Num(al, pkgKey);
    00185     availablePackage alp = NULL;
    00186
    00187     if (al != NULL && pkgNum >= 0 && pkgNum < alGetSize(al)) {
    00188         if (al->list != NULL)
    00189             alp = al->list + pkgNum;
    00190     }
    00191     return alp;
    00192 }
    00193 #endif
    00194
    00195 rpmal rpmalCreate(int delta)
    00196 {
    00197     rpmal al = xcalloc(1, sizeof(*al));
    00198     availableIndex ai = &al->index;
    00199
    00200     al->delta = delta;
    00201     al->size = 0;
    00202     al->list = xcalloc(al->delta, sizeof(*al->list));
    00203     al->alloced = al->delta;
    00204
    00205     ai->index = NULL;
    00206     ai->size = 0;
    00207
    00208     al->numDirs = 0;
    00209     al->dirs = NULL;
    00210     return al;
    00211 }
    00212
    00213 rpmal rpmalFree(rpmal al)
    00214 {
    00215     availablePackage alp;
    00216     dirInfo die;
    00217     int i;
    00218
    00219     if (al == NULL)
    00220         return NULL;
    00221
    00222     if ((alp = al->list) != NULL)
    00223     for (i = 0; i < al->size; i++, alp++) {
    00224         alp->provides = rpmdsFree(alp->provides);
    00225         alp->fi = rpmfiFree(alp->fi);
    00226     }
    00227
    00228     if ((die = al->dirs) != NULL)
    00229     for (i = 0; i < al->numDirs; i++, die++) {
    00230         die->dirName = _free(die->dirName);
    00231         die->files = _free(die->files);
    00232     }
    00233     al->dirs = _free(al->dirs);
    00234     al->numDirs = 0;
    00235
    00236     al->list = _free(al->list);
    00237     al->alloced = 0;
    00238     rpmalFreeIndex(al);
    00239     al = _free(al);
    00240     return NULL;
    00241 }
    00242
    00249 static int dieCompare(const void * one, const void * two)
    00250         /*@*/
    00251 {
    00252     /*@-castexpose@*/
    00253     const dirInfo a = (const dirInfo) one;
    00254     const dirInfo b = (const dirInfo) two;
    00255     /*@=castexpose@*/
    00256     int lenchk = a->dirNameLen - b->dirNameLen;
    00257
    00258     if (lenchk || a->dirNameLen == 0)
    00259         return lenchk;
    00260
    00261     if (a->dirName == NULL || b->dirName == NULL)
    00262         return lenchk;
    00263
    00264     /* XXX FIXME: this might do "backward" strcmp for speed */
    00265     return strcmp(a->dirName, b->dirName);
    00266 }
    00267
    00274 static int fieCompare(const void * one, const void * two)
    00275         /*@*/
    00276 {
    00277     /*@-castexpose@*/
    00278     const fileIndexEntry a = (const fileIndexEntry) one;
    00279     const fileIndexEntry b = (const fileIndexEntry) two;
    00280     /*@=castexpose@*/
    00281     int lenchk = a->baseNameLen - b->baseNameLen;
    00282
    00283     if (lenchk)
    00284         return lenchk;
    00285
    00286     if (a->baseName == NULL || b->baseName == NULL)
    00287         return lenchk;
    00288
    00289 #ifdef  NOISY
    00290 /*@-modfilesys@*/
    00291 if (_rpmal_debug) {
    00292 fprintf(stderr, "\t\tstrcmp(%p:%p, %p:%p)", a, a->baseName, b, b->baseName);
    00293 #if 0
    00294 fprintf(stderr, " a %s", a->baseName);
    00295 #endif
    00296 fprintf(stderr, " b %s", a->baseName);
    00297 fprintf(stderr, "\n");
    00298 }
    00299 /*@=modfilesys@*/
    00300 #endif
    00301
    00302     return strcmp(a->baseName, b->baseName);
    00303 }
    00304
    00305 void rpmalDel(rpmal al, alKey pkgKey)
    00306 {
    00307     alNum pkgNum = alKey2Num(al, pkgKey);
    00308     availablePackage alp;
    00309     rpmfi fi;
    00310
    00311     if (al == NULL || al->list == NULL)
    00312         return;         /* XXX can't happen */
    00313
    00314     alp = al->list + pkgNum;
    00315
    00316 /*@-modfilesys@*/
    00317 if (_rpmal_debug)
    00318 fprintf(stderr, "*** del %p[%d]\n", al->list, pkgNum);
    00319 /*@=modfilesys@*/
    00320
    00321     /* Delete directory/file info entries from added package list. */
    00322     if ((fi = alp->fi) != NULL)
    00323     if (rpmfiFC(fi) > 0) {
    00324         int origNumDirs = al->numDirs;
    00325         int dx;
    00326         dirInfo dieNeedle =
    00327                 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
    00328         dirInfo die;
    00329         int last;
    00330         int i;
    00331
    00332         /* XXX FIXME: We ought to relocate the directory list here */
    00333
    00334         if (al->dirs != NULL)
    00335         for (dx = rpmfiDC(fi) - 1; dx >= 0; dx--)
    00336         {
    00337             fileIndexEntry fie;
    00338
    00339             (void) rpmfiSetDX(fi, dx);
    00340
    00341             /*@-assignexpose -dependenttrans -observertrans@*/
    00342             dieNeedle->dirName = (char *) rpmfiDN(fi);
    00343             /*@=assignexpose =dependenttrans =observertrans@*/
    00344             dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
    00345                         ? strlen(dieNeedle->dirName) : 0);
    00346             die = bsearch(dieNeedle, al->dirs, al->numDirs,
    00347                                sizeof(*dieNeedle), dieCompare);
    00348             if (die == NULL)
    00349                 continue;
    00350
    00351 /*@-modfilesys@*/
    00352 if (_rpmal_debug)
    00353 fprintf(stderr, "--- die[%5d] %p [%3d] %s\n", (int)(die - al->dirs), die, die->dirNameLen, die->dirName);
    00354 /*@=modfilesys@*/
    00355
    00356             last = die->numFiles;
    00357             fie = die->files + last - 1;
    00358             for (i = last - 1; i >= 0; i--, fie--) {
    00359                 if (fie->pkgNum != pkgNum)
    00360                     /*@innercontinue@*/ continue;
    00361                 die->numFiles--;
    00362
    00363                 if (i < die->numFiles) {
    00364 /*@-modfilesys@*/
    00365 if (_rpmal_debug)
    00366 fprintf(stderr, "\t%p[%3d] memmove(%p:%p,%p:%p,0x%x) %s <- %s\n", die->files, die->numFiles, fie, fie->baseName, fie+1, (fie+1)->baseName, (unsigned) ((die->numFiles - i) * sizeof(*fie)), fie->baseName, (fie+1)->baseName);
    00367 /*@=modfilesys@*/
    00368
    00369                     memmove(fie, fie+1, (die->numFiles - i) * sizeof(*fie));
    00370                 }
    00371 /*@-modfilesys@*/
    00372 if (_rpmal_debug)
    00373 fprintf(stderr, "\t%p[%3d] memset(%p,0,0x%x) %p [%3d] %s\n", die->files, die->numFiles, die->files + die->numFiles, (unsigned)sizeof(*fie), fie->baseName, fie->baseNameLen, fie->baseName);
    00374 /*@=modfilesys@*/
    00375                 memset(die->files + die->numFiles, 0, sizeof(*fie)); /* overkill */
    00376
    00377             }
    00378             if (die->numFiles > 0) {
    00379                 if (last > i)
    00380                     die->files = xrealloc(die->files,
    00381                                         die->numFiles * sizeof(*die->files));
    00382                 continue;
    00383             }
    00384             die->files = _free(die->files);
    00385             die->dirName = _free(die->dirName);
    00386             al->numDirs--;
    00387             if ((die - al->dirs) < al->numDirs) {
    00388 /*@-modfilesys@*/
    00389 if (_rpmal_debug)
    00390 fprintf(stderr, "    die[%5d] memmove(%p,%p,0x%x)\n", (int)(die - al->dirs), die, die+1, (unsigned)((al->numDirs - (die - al->dirs)) * sizeof(*die)));
    00391 /*@=modfilesys@*/
    00392
    00393                 memmove(die, die+1, (al->numDirs - (die - al->dirs)) * sizeof(*die));
    00394             }
    00395
    00396 /*@-modfilesys@*/
    00397 if (_rpmal_debug)
    00398 fprintf(stderr, "    die[%5d] memset(%p,0,0x%x)\n", al->numDirs, al->dirs + al->numDirs, (unsigned)sizeof(*die));
    00399 /*@=modfilesys@*/
    00400             memset(al->dirs + al->numDirs, 0, sizeof(*al->dirs)); /* overkill */
    00401         }
    00402
    00403         if (origNumDirs > al->numDirs) {
    00404             if (al->numDirs > 0)
    00405                 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
    00406             else
    00407                 al->dirs = _free(al->dirs);
    00408         }
    00409     }
    00410
    00411     alp->provides = rpmdsFree(alp->provides);
    00412     alp->fi = rpmfiFree(alp->fi);
    00413
    00414     memset(alp, 0, sizeof(*alp));       /* XXX trash and burn */
    00415     return;
    00416 }
    00417
    00418 alKey rpmalAdd(rpmal * alistp, alKey pkgKey, fnpyKey key,
    00419                 rpmds provides, rpmfi fi, uint32_t tscolor)
    00420 {
    00421     alNum pkgNum;
    00422     rpmal al;
    00423     availablePackage alp;
    00424
    00425     /* If list doesn't exist yet, create. */
    00426     if (*alistp == NULL)
    00427         *alistp = rpmalCreate(5);
    00428     al = *alistp;
    00429     pkgNum = alKey2Num(al, pkgKey);
    00430
    00431     if (pkgNum >= 0 && pkgNum < al->size) {
    00432         rpmalDel(al, pkgKey);
    00433     } else {
    00434         if (al->size == al->alloced) {
    00435             al->alloced += al->delta;
    00436             al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
    00437         }
    00438         pkgNum = al->size++;
    00439     }
    00440
    00441     if (al->list == NULL)
    00442         return RPMAL_NOMATCH;           /* XXX can't happen */
    00443
    00444     alp = al->list + pkgNum;
    00445
    00446     alp->key = key;
    00447     alp->tscolor = tscolor;
    00448
    00449 /*@-modfilesys@*/
    00450 if (_rpmal_debug)
    00451 fprintf(stderr, "*** add %p[%d] 0x%x\n", al->list, pkgNum, tscolor);
    00452 /*@=modfilesys@*/
    00453
    00454     alp->provides = rpmdsLink(provides, "Provides (rpmalAdd)");
    00455     alp->fi = rpmfiLink(fi, "Files (rpmalAdd)");
    00456
    00457     fi = rpmfiLink(alp->fi, "Files index (rpmalAdd)");
    00458     fi = rpmfiInit(fi, 0);
    00459     if (rpmfiFC(fi) > 0) {
    00460         dirInfo dieNeedle =
    00461                 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
    00462         dirInfo die;
    00463         int dc = rpmfiDC(fi);
    00464         int dx;
    00465         int * dirMapping = alloca(sizeof(*dirMapping) * dc);
    00466         int * dirUnique = alloca(sizeof(*dirUnique) * dc);
    00467         const char * DN;
    00468         int origNumDirs;
    00469         int first;
    00470
    00471         /* XXX FIXME: We ought to relocate the directory list here */
    00472
    00473         /* XXX enough space for all directories, late realloc to truncate. */
    00474         al->dirs = xrealloc(al->dirs, (al->numDirs + dc) * sizeof(*al->dirs));
    00475
    00476         /* Only previously allocated dirInfo is sorted and bsearch'able. */
    00477         origNumDirs = al->numDirs;
    00478
    00479         /* Package dirnames are not currently unique. Create unique mapping. */
    00480         for (dx = 0; dx < dc; dx++) {
    00481             int i = 0;
    00482             (void) rpmfiSetDX(fi, dx);
    00483             DN = rpmfiDN(fi);
    00484             if (DN != NULL)
    00485             for (i = 0; i < dx; i++) {
    00486                 const char * iDN;
    00487                 (void) rpmfiSetDX(fi, i);
    00488                 iDN = rpmfiDN(fi);
    00489                 if (iDN != NULL && !strcmp(DN, iDN))
    00490                     /*@innerbreak@*/ break;
    00491             }
    00492             dirUnique[dx] = i;
    00493         }
    00494
    00495         /* Map package dirs into transaction dirInfo index. */
    00496         for (dx = 0; dx < dc; dx++) {
    00497
    00498             /* Non-unique package dirs use the 1st entry mapping. */
    00499             if (dirUnique[dx] < dx) {
    00500                 dirMapping[dx] = dirMapping[dirUnique[dx]];
    00501                 continue;
    00502             }
    00503
    00504             /* Find global dirInfo mapping for first encounter. */
    00505             (void) rpmfiSetDX(fi, dx);
    00506
    00507             /*@-assignexpose -dependenttrans -observertrans@*/
    00508             dieNeedle->dirName = rpmfiDN(fi);
    00509             /*@=assignexpose =dependenttrans =observertrans@*/
    00510
    00511             dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
    00512                         ? strlen(dieNeedle->dirName) : 0);
    00513             die = bsearch(dieNeedle, al->dirs, origNumDirs,
    00514                                sizeof(*dieNeedle), dieCompare);
    00515             if (die) {
    00516                 dirMapping[dx] = die - al->dirs;
    00517             } else {
    00518                 dirMapping[dx] = al->numDirs;
    00519                 die = al->dirs + al->numDirs;
    00520                 if (dieNeedle->dirName != NULL)
    00521                     die->dirName = xstrdup(dieNeedle->dirName);
    00522                 die->dirNameLen = dieNeedle->dirNameLen;
    00523                 die->files = NULL;
    00524                 die->numFiles = 0;
    00525 /*@-modfilesys@*/
    00526 if (_rpmal_debug)
    00527 fprintf(stderr, "+++ die[%5d] %p [%3d] %s\n", al->numDirs, die, die->dirNameLen, die->dirName);
    00528 /*@=modfilesys@*/
    00529
    00530                 al->numDirs++;
    00531             }
    00532         }
    00533
    00534         for (first = rpmfiNext(fi); first >= 0;) {
    00535             fileIndexEntry fie;
    00536             int next;
    00537
    00538             /* Find the first file of the next directory. */
    00539             dx = rpmfiDX(fi);
    00540             while ((next = rpmfiNext(fi)) >= 0) {
    00541                 if (dx != rpmfiDX(fi))
    00542                     /*@innerbreak@*/ break;
    00543             }
    00544             if (next < 0) next = rpmfiFC(fi);   /* XXX reset end-of-list */
    00545
    00546             die = al->dirs + dirMapping[dx];
    00547             die->files = xrealloc(die->files,
    00548                         (die->numFiles + next - first) * sizeof(*die->files));
    00549
    00550             fie = die->files + die->numFiles;
    00551
    00552 /*@-modfilesys@*/
    00553 if (_rpmal_debug)
    00554 fprintf(stderr, "    die[%5d] %p->files [%p[%d],%p) -> [%p[%d],%p)\n", dirMapping[dx], die,
    00555 die->files, die->numFiles, die->files+die->numFiles,
    00556 fie, (next - first), fie + (next - first));
    00557 /*@=modfilesys@*/
    00558
    00559             /* Rewind to first file, generate file index entry for each file. */
    00560             fi = rpmfiInit(fi, first);
    00561             while ((first = rpmfiNext(fi)) >= 0 && first < next) {
    00562                 /*@-assignexpose -dependenttrans -observertrans @*/
    00563                 fie->baseName = rpmfiBN(fi);
    00564                 /*@=assignexpose =dependenttrans =observertrans @*/
    00565                 fie->baseNameLen = (fie->baseName ? strlen(fie->baseName) : 0);
    00566                 fie->pkgNum = pkgNum;
    00567                 fie->ficolor = rpmfiFColor(fi);
    00568 /*@-modfilesys@*/
    00569 if (_rpmal_debug)
    00570 fprintf(stderr, "\t%p[%3d] %p:%p[%2d] %s\n", die->files, die->numFiles, fie, fie->baseName, fie->baseNameLen, rpmfiFN(fi));
    00571 /*@=modfilesys@*/
    00572
    00573                 die->numFiles++;
    00574                 fie++;
    00575             }
    00576             qsort(die->files, die->numFiles, sizeof(*die->files), fieCompare);
    00577         }
    00578
    00579         /* Resize the directory list. If any directories were added, resort. */
    00580         al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
    00581         if (origNumDirs != al->numDirs)
    00582             qsort(al->dirs, al->numDirs, sizeof(*al->dirs), dieCompare);
    00583     }
    00584     fi = rpmfiUnlink(fi, "Files index (rpmalAdd)");
    00585
    00586     rpmalFreeIndex(al);
    00587
    00588 assert(((alNum)(alp - al->list)) == pkgNum);
    00589     return ((alKey)(alp - al->list));
    00590 }
    00591
    00598 static int indexcmp(const void * one, const void * two)
    00599         /*@*/
    00600 {
    00601     /*@-castexpose@*/
    00602     const availableIndexEntry a = (const availableIndexEntry) one;
    00603     const availableIndexEntry b = (const availableIndexEntry) two;
    00604     /*@=castexpose@*/
    00605     int lenchk;
    00606
    00607     lenchk = a->entryLen - b->entryLen;
    00608     if (lenchk)
    00609         return lenchk;
    00610
    00611     return strcmp(a->entry, b->entry);
    00612 }
    00613
    00614 void rpmalAddProvides(rpmal al, alKey pkgKey, rpmds provides, uint32_t tscolor)
    00615 {
    00616     uint32_t dscolor;
    00617     const char * Name;
    00618     alNum pkgNum = alKey2Num(al, pkgKey);
    00619     availableIndex ai = &al->index;
    00620     availableIndexEntry aie;
    00621     int ix;
    00622
    00623     if (provides == NULL || pkgNum < 0 || pkgNum >= al->size)
    00624         return;
    00625     if (ai->index == NULL || ai->k < 0 || ai->k >= ai->size)
    00626         return;
    00627
    00628     if (rpmdsInit(provides) != NULL)
    00629     while (rpmdsNext(provides) >= 0) {
    00630
    00631         if ((Name = provides->N[provides->i]) == NULL)
    00632             continue;   /* XXX can't happen */
    00633
    00634         /* Ignore colored provides not in our rainbow. */
    00635         dscolor = rpmdsColor(provides);
    00636         if (tscolor && dscolor && !(tscolor & dscolor))
    00637             continue;
    00638
    00639         aie = ai->index + ai->k;
    00640         ai->k++;
    00641
    00642         aie->pkgKey = pkgKey;
    00643 /*@-assignexpose@*/
    00644         aie->entry = Name;
    00645 /*@=assignexpose@*/
    00646         aie->entryLen = strlen(Name);
    00647         ix = rpmdsIx(provides);
    00648
    00649 /* XXX make sure that element index fits in unsigned short */
    00650 assert(ix < 0x10000);
    00651
    00652         aie->entryIx = ix;
    00653         aie->type = IET_PROVIDES;
    00654     }
    00655 }
    00656
    00657 void rpmalMakeIndex(rpmal al)
    00658 {
    00659     availableIndex ai;
    00660     availablePackage alp;
    00661     int i;
    00662
    00663     if (al == NULL || al->list == NULL) return;
    00664     ai = &al->index;
    00665
    00666     ai->size = 0;
    00667     for (i = 0; i < al->size; i++) {
    00668         alp = al->list + i;
    00669         if (alp->provides != NULL)
    00670             ai->size += rpmdsCount(alp->provides);
    00671     }
    00672     if (ai->size == 0) return;
    00673
    00674     ai->index = xrealloc(ai->index, ai->size * sizeof(*ai->index));
    00675     ai->k = 0;
    00676     for (i = 0; i < al->size; i++) {
    00677         alp = al->list + i;
    00678         rpmalAddProvides(al, alNum2Key(NULL, (alNum)i), alp->provides, alp->tscolor);
    00679     }
    00680
    00681     /* Reset size to the no. of provides added. */
    00682     ai->size = ai->k;
    00683     qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
    00684 }
    00685
    00686 fnpyKey *
    00687 rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
    00688 {
    00689     uint32_t tscolor;
    00690     uint32_t ficolor;
    00691     int found = 0;
    00692     const char * dirName;
    00693     const char * baseName;
    00694     dirInfo dieNeedle =
    00695                 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
    00696     dirInfo die;
    00697     fileIndexEntry fieNeedle =
    00698                 memset(alloca(sizeof(*fieNeedle)), 0, sizeof(*fieNeedle));
    00699     fileIndexEntry fie;
    00700     availablePackage alp;
    00701     fnpyKey * ret = NULL;
    00702     const char * fileName;
    00703
    00704     if (keyp) *keyp = RPMAL_NOMATCH;
    00705
    00706     if (al == NULL || (fileName = rpmdsN(ds)) == NULL || *fileName != '/')
    00707         return NULL;
    00708
    00709     /* Solaris 2.6 bsearch sucks down on this. */
    00710     if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
    00711         return NULL;
    00712
    00713     {   char * t;
    00714         dirName = t = xstrdup(fileName);
    00715         if ((t = strrchr(t, '/')) != NULL) {
    00716             t++;                /* leave the trailing '/' */
    00717             *t = '\0';
    00718         }
    00719     }
    00720
    00721     dieNeedle->dirName = (char *) dirName;
    00722     dieNeedle->dirNameLen = strlen(dirName);
    00723     die = bsearch(dieNeedle, al->dirs, al->numDirs,
    00724                        sizeof(*dieNeedle), dieCompare);
    00725     if (die == NULL)
    00726         goto exit;
    00727
    00728     /* rewind to the first match */
    00729     while (die > al->dirs && dieCompare(die-1, dieNeedle) == 0)
    00730         die--;
    00731
    00732     if ((baseName = strrchr(fileName, '/')) == NULL)
    00733         goto exit;
    00734     baseName++;
    00735
    00736     for (found = 0, ret = NULL;
    00737          die < al->dirs + al->numDirs && dieCompare(die, dieNeedle) == 0;
    00738          die++)
    00739     {
    00740
    00741 /*@-modfilesys@*/
    00742 if (_rpmal_debug)
    00743 fprintf(stderr, "==> die %p %s\n", die, (die->dirName ? die->dirName : "(nil)"));
    00744 /*@=modfilesys@*/
    00745
    00746 /*@-observertrans@*/
    00747         fieNeedle->baseName = baseName;
    00748 /*@=observertrans@*/
    00749         fieNeedle->baseNameLen = strlen(fieNeedle->baseName);
    00750         fie = bsearch(fieNeedle, die->files, die->numFiles,
    00751                        sizeof(*fieNeedle), fieCompare);
    00752         if (fie == NULL)
    00753             continue;   /* XXX shouldn't happen */
    00754
    00755 /*@-modfilesys@*/
    00756 if (_rpmal_debug)
    00757 fprintf(stderr, "==> fie %p %s\n", fie, (fie->baseName ? fie->baseName : "(nil)"));
    00758 /*@=modfilesys@*/
    00759
    00760         alp = al->list + fie->pkgNum;
    00761
    00762         /* Ignore colored files not in our rainbow. */
    00763         tscolor = alp->tscolor;
    00764         ficolor = fie->ficolor;
    00765         if (tscolor && ficolor && !(tscolor & ficolor))
    00766             continue;
    00767
    00768         rpmdsNotify(ds, _("(added files)"), 0);
    00769
    00770         ret = xrealloc(ret, (found+2) * sizeof(*ret));
    00771         if (ret)        /* can't happen */
    00772             ret[found] = alp->key;
    00773         if (keyp)
    00774             *keyp = alNum2Key(al, fie->pkgNum);
    00775         found++;
    00776     }
    00777
    00778 exit:
    00779     dirName = _free(dirName);
    00780     if (ret)
    00781         ret[found] = NULL;
    00782     return ret;
    00783 }
    00784
    00785 fnpyKey *
    00786 rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
    00787 {
    00788     availableIndex ai;
    00789     availableIndexEntry needle;
    00790     availableIndexEntry match;
    00791     fnpyKey * ret = NULL;
    00792     int found = 0;
    00793     const char * KName;
    00794     availablePackage alp;
    00795     int rc;
    00796
    00797     if (keyp) *keyp = RPMAL_NOMATCH;
    00798
    00799     if (al == NULL || ds == NULL || (KName = rpmdsN(ds)) == NULL)
    00800         return ret;
    00801
    00802     if (*KName == '/') {
    00803         /* First, look for files "contained" in package ... */
    00804         ret = rpmalAllFileSatisfiesDepend(al, ds, keyp);
    00805         if (ret != NULL && *ret != NULL)
    00806             return ret;
    00807         ret = _free(ret);
    00808         /* ... then, look for files "provided" by package. */
    00809     }
    00810
    00811     ai = &al->index;
    00812     if (ai->index == NULL || ai->size <= 0)
    00813         return NULL;
    00814
    00815     needle = memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
    00816     /*@-assignexpose -temptrans@*/
    00817     needle->entry = KName;
    00818     /*@=assignexpose =temptrans@*/
    00819     needle->entryLen = strlen(needle->entry);
    00820
    00821     match = bsearch(needle, ai->index, ai->size, sizeof(*ai->index), indexcmp);
    00822     if (match == NULL)
    00823         return NULL;
    00824
    00825     /* rewind to the first match */
    00826     while (match > ai->index && indexcmp(match-1, needle) == 0)
    00827         match--;
    00828
    00829     if (al->list != NULL)       /* XXX always true */
    00830     for (ret = NULL, found = 0;
    00831          match < ai->index + ai->size && indexcmp(match, needle) == 0;
    00832          match++)
    00833     {
    00834         alp = al->list + alKey2Num(al, match->pkgKey);
    00835
    00836         rc = 0;
    00837         if (alp->provides != NULL)      /* XXX can't happen */
    00838         switch (match->type) {
    00839         case IET_PROVIDES:
    00840             /* XXX single step on rpmdsNext to regenerate DNEVR string */
    00841             (void) rpmdsSetIx(alp->provides, match->entryIx - 1);
    00842             if (rpmdsNext(alp->provides) >= 0)
    00843                 rc = rpmdsCompare(alp->provides, ds);
    00844
    00845             if (rc)
    00846                 rpmdsNotify(ds, _("(added provide)"), 0);
    00847
    00848             /*@switchbreak@*/ break;
    00849         }
    00850
    00851         if (rc) {
    00852             ret = xrealloc(ret, (found + 2) * sizeof(*ret));
    00853             if (ret)    /* can't happen */
    00854                 ret[found] = alp->key;
    00855 /*@-dependenttrans@*/
    00856             if (keyp)
    00857                 *keyp = match->pkgKey;
    00858 /*@=dependenttrans@*/
    00859             found++;
    00860         }
    00861     }
    00862
    00863     if (ret)
    00864         ret[found] = NULL;
    00865
    00866 /*@-nullstate@*/ /* FIX: *keyp may be NULL */
    00867     return ret;
    00868 /*@=nullstate@*/
    00869 }
    00870
    00871 fnpyKey
    00872 rpmalSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
    00873 {
    00874     fnpyKey * tmp = rpmalAllSatisfiesDepend(al, ds, keyp);
    00875
    00876     if (tmp) {
    00877         fnpyKey ret = tmp[0];
    00878         free(tmp);
    00879         return ret;
    00880     }
    00881     return NULL;
    00882 }