rpm  5.4.4
lib/rpmal.c
Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmio.h>
00008 #include <rpmiotypes.h>         /* XXX fnpyKey */
00009 #include <rpmbf.h>
00010 
00011 #include <rpmtag.h>
00012 #include <rpmtypes.h>
00013 
00014 #define _RPMDS_INTERNAL
00015 #include <rpmds.h>
00016 #include <rpmal.h>
00017 
00018 #include "debug.h"
00019 
00020 typedef /*@abstract@*/ struct availablePackage_s * availablePackage;
00021 
00022 /*@access alKey @*/
00023 /*@access alNum @*/
00024 /*@access rpmal @*/
00025 /*@access rpmds @*/
00026 /*@access availablePackage @*/
00027 
00028 /*@access fnpyKey @*/   /* XXX suggestedKeys array */
00029 
00030 /*@unchecked@*/
00031 int _rpmal_debug = 0;
00032 
00036 struct availablePackage_s {
00037 /*@refcounted@*/ /*@null@*/
00038     rpmds provides;             
00039 /*@refcounted@*/ /*@null@*/
00040     rpmbf bf;                   
00042     rpmuint32_t tscolor;        
00044 /*@exposed@*/ /*@dependent@*/ /*@null@*/
00045     fnpyKey key;                
00047 };
00048 
00049 typedef /*@abstract@*/ struct availableIndexEntry_s *   availableIndexEntry;
00050 /*@access availableIndexEntry@*/
00051 
00055 struct availableIndexEntry_s {
00056 /*@exposed@*/ /*@dependent@*/ /*@null@*/
00057     alKey pkgKey;               
00058 /*@observer@*/
00059     const char * entry;         
00060     unsigned short entryLen;    
00061     unsigned short entryIx;     
00062     enum indexEntryType {
00063         IET_PROVIDES=1                  
00064     } type;                     
00065 };
00066 
00067 typedef /*@abstract@*/ struct availableIndex_s *        availableIndex;
00068 /*@access availableIndex@*/
00069 
00073 struct availableIndex_s {
00074 /*@null@*/
00075     availableIndexEntry index;  
00076     int size;                   
00077     int k;                      
00078 };
00079 
00083 struct rpmal_s {
00084     struct rpmioItem_s _item;   
00085 /*@owned@*/ /*@null@*/
00086     availablePackage list;      
00087     struct availableIndex_s index;      
00088     int delta;                  
00089     int size;                   
00090     int alloced;                
00091     rpmuint32_t tscolor;        
00092 };
00093 
00094 static inline alNum alKey2Num(/*@unused@*/ /*@null@*/ const rpmal al,
00095                 /*@null@*/ alKey pkgKey)
00096         /*@*/
00097 {
00098     /*@-nullret -temptrans -retalias @*/
00099     union { alKey key; alNum num; } u;
00100     u.num = 0;
00101     u.key = pkgKey;
00102     return u.num;
00103     /*@=nullret =temptrans =retalias @*/
00104 }
00105 
00106 static inline alKey alNum2Key(/*@unused@*/ /*@null@*/ const rpmal al,
00107                 /*@null@*/ alNum pkgNum)
00108         /*@*/
00109 {
00110     /*@-nullret -temptrans -retalias @*/
00111     union { alKey key; alNum num; } u;
00112     u.key = 0;
00113     u.num = pkgNum;
00114     return u.key;
00115     /*@=nullret =temptrans =retalias @*/
00116 }
00117 
00122 static void rpmalFreeIndex(rpmal al)
00123         /*@modifies al @*/
00124 {
00125     availableIndex ai = &al->index;
00126     if (ai->size > 0) {
00127         ai->index = _free(ai->index);
00128         ai->size = 0;
00129     }
00130 }
00131 
00132 static void rpmalFini(void * _al)
00133 {
00134     rpmal al = _al;
00135     availablePackage alp;
00136     int i;
00137 
00138     if ((alp = al->list) != NULL)
00139     for (i = 0; i < al->size; i++, alp++) {
00140         (void)rpmdsFree(alp->provides);
00141         alp->provides = NULL;
00142         (void)rpmbfFree(alp->bf);
00143         alp->bf = NULL;
00144     }
00145 
00146     al->list = _free(al->list);
00147     al->alloced = 0;
00148     rpmalFreeIndex(al);
00149 }
00150 
00151 /*@unchecked@*/ /*@only@*/ /*@null@*/
00152 rpmioPool _rpmalPool;
00153 
00154 static rpmal rpmalGetPool(/*@null@*/ rpmioPool pool)
00155         /*@globals _rpmdsPool, fileSystem, internalState @*/
00156         /*@modifies pool, _rpmdsPool, fileSystem, internalState @*/
00157 {
00158     rpmal al;
00159 
00160     if (_rpmalPool == NULL) {
00161         _rpmalPool = rpmioNewPool("al", sizeof(*al), -1, _rpmal_debug,
00162                         NULL, NULL, rpmalFini);
00163         pool = _rpmalPool;
00164     }
00165     al = (rpmal) rpmioGetPool(pool, sizeof(*al));
00166     memset(((char *)al)+sizeof(al->_item), 0, sizeof(*al)-sizeof(al->_item));
00167     return al;
00168 }
00169 
00170 rpmal rpmalNew(int delta)
00171 {
00172     rpmal al = rpmalGetPool(_rpmalPool);
00173     availableIndex ai = &al->index;
00174 
00175     al->delta = delta;
00176     al->size = 0;
00177     al->list = xcalloc(al->delta, sizeof(*al->list));
00178     al->alloced = al->delta;
00179 
00180     ai->index = NULL;
00181     ai->size = 0;
00182 
00183     return rpmalLink(al, __FUNCTION__);
00184 }
00185 
00186 void rpmalDel(rpmal al, alKey pkgKey)
00187 {
00188     alNum pkgNum = alKey2Num(al, pkgKey);
00189     availablePackage alp;
00190 
00191     if (al == NULL || al->list == NULL)
00192         return;         /* XXX can't happen */
00193 
00194     alp = al->list + pkgNum;
00195 
00196     (void)rpmdsFree(alp->provides);
00197     alp->provides = NULL;
00198     (void)rpmbfFree(alp->bf);
00199     alp->bf = NULL;
00200 
00201     memset(alp, 0, sizeof(*alp));       /* XXX trash and burn */
00202     return;
00203 }
00204 
00205 alKey rpmalAdd(rpmal * alistp, alKey pkgKey, fnpyKey key,
00206                 rpmds provides, rpmfi fi, rpmuint32_t tscolor)
00207 {
00208     alNum pkgNum;
00209     rpmal al;
00210     availablePackage alp;
00211 
00212     /* If list doesn't exist yet, create. */
00213     if (*alistp == NULL)
00214         *alistp = rpmalNew(5);
00215     al = *alistp;
00216     pkgNum = alKey2Num(al, pkgKey);
00217 
00218     if (pkgNum >= 0 && pkgNum < al->size) {
00219         rpmalDel(al, pkgKey);
00220     } else {
00221         if (al->size == al->alloced) {
00222             al->alloced += al->delta;
00223             al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
00224         }
00225         pkgNum = al->size++;
00226     }
00227 
00228     if (al->list == NULL)
00229         return RPMAL_NOMATCH;           /* XXX can't happen */
00230 
00231     alp = al->list + pkgNum;
00232 
00233     alp->key = key;
00234     alp->tscolor = tscolor;
00235 
00236 /*@-assignexpose -castexpose @*/
00237     alp->provides = rpmdsLink(provides, "Provides (rpmalAdd)");
00238     alp->bf = rpmbfLink(rpmfiFNBF(fi));
00239 /*@=assignexpose =castexpose @*/
00240 
00241     rpmalFreeIndex(al);
00242 
00243 assert(((alNum)(alp - al->list)) == pkgNum);
00244     return ((alKey)(alp - al->list));
00245 }
00246 
00253 static int indexcmp(const void * one, const void * two)
00254         /*@*/
00255 {
00256     /*@-castexpose@*/
00257     const availableIndexEntry a = (const availableIndexEntry) one;
00258     const availableIndexEntry b = (const availableIndexEntry) two;
00259     /*@=castexpose@*/
00260     int lenchk;
00261 
00262     lenchk = a->entryLen - b->entryLen;
00263     if (lenchk)
00264         return lenchk;
00265 
00266     return strcmp(a->entry, b->entry);
00267 }
00268 
00269 void rpmalAddProvides(rpmal al, alKey pkgKey, rpmds provides, rpmuint32_t tscolor)
00270 {
00271     rpmuint32_t dscolor;
00272     const char * Name;
00273     alNum pkgNum = alKey2Num(al, pkgKey);
00274     availableIndex ai = &al->index;
00275     availableIndexEntry aie;
00276     int ix;
00277 
00278     if (provides == NULL || pkgNum < 0 || pkgNum >= al->size)
00279         return;
00280     if (ai->index == NULL || ai->k < 0 || ai->k >= ai->size)
00281         return;
00282 
00283     if (rpmdsInit(provides) != NULL)
00284     while (rpmdsNext(provides) >= 0) {
00285 
00286         if ((Name = provides->N[provides->i]) == NULL)
00287             continue;   /* XXX can't happen */
00288 
00289         /* Ignore colored provides not in our rainbow. */
00290         dscolor = rpmdsColor(provides);
00291         if (tscolor && dscolor && !(tscolor & dscolor))
00292             continue;
00293 
00294         aie = ai->index + ai->k;
00295         ai->k++;
00296 
00297         aie->pkgKey = pkgKey;
00298 /*@-assignexpose@*/
00299         aie->entry = Name;
00300 /*@=assignexpose@*/
00301         aie->entryLen = (unsigned short)strlen(Name);
00302         ix = rpmdsIx(provides);
00303 
00304 /* XXX make sure that element index fits in unsigned short */
00305 assert(ix < 0x10000);
00306 
00307         aie->entryIx = ix;
00308         aie->type = IET_PROVIDES;
00309     }
00310 }
00311 
00312 void rpmalMakeIndex(rpmal al)
00313 {
00314     availableIndex ai;
00315     availablePackage alp;
00316     int i;
00317 
00318     if (al == NULL || al->list == NULL) return;
00319     ai = &al->index;
00320 
00321     ai->size = 0;
00322     for (i = 0; i < al->size; i++) {
00323         alp = al->list + i;
00324         if (alp->provides != NULL)
00325             ai->size += rpmdsCount(alp->provides);
00326     }
00327     if (ai->size == 0) return;
00328 
00329     ai->index = xrealloc(ai->index, ai->size * sizeof(*ai->index));
00330     ai->k = 0;
00331     for (i = 0; i < al->size; i++) {
00332         alp = al->list + i;
00333         rpmalAddProvides(al, alNum2Key(NULL, (alNum)i), alp->provides, alp->tscolor);
00334     }
00335 
00336     /* Reset size to the no. of provides added. */
00337     ai->size = ai->k;
00338     qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
00339 }
00340 
00341 fnpyKey *
00342 rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00343 {
00344     fnpyKey * ret = NULL;
00345     int found = 0;
00346     const char * fn;
00347     size_t nfn;
00348     int i;
00349 
00350     if (keyp) *keyp = RPMAL_NOMATCH;
00351 
00352     if (al == NULL || (fn = rpmdsN(ds)) == NULL || *fn != '/')
00353         goto exit;
00354     nfn = strlen(fn);
00355 
00356     if (al->list != NULL)       /* XXX always true */
00357     for (i = 0; i < al->size; i++) {
00358         availablePackage alp = al->list + i;
00359 
00360         if (!rpmbfChk(alp->bf, fn, nfn))
00361             continue;
00362 
00363         rpmdsNotify(ds, _("(added files)"), 0);
00364 
00365         ret = xrealloc(ret, (found + 2) * sizeof(*ret));
00366         if (ret)        /* can't happen */
00367             ret[found] = alp->key;
00368         if (keyp)
00369             *keyp = alNum2Key(al, i);
00370         found++;
00371     }
00372 
00373     if (ret)
00374         ret[found] = NULL;
00375 
00376 exit:
00377 /*@-nullstate@*/ /* FIX: *keyp may be NULL */
00378     return ret;
00379 /*@=nullstate@*/
00380 }
00381 
00382 fnpyKey *
00383 rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00384 {
00385     availableIndex ai;
00386     availableIndexEntry needle;
00387     availableIndexEntry match;
00388     fnpyKey * ret = NULL;
00389     int found = 0;
00390     const char * KName;
00391     availablePackage alp;
00392     int rc;
00393 
00394     if (keyp) *keyp = RPMAL_NOMATCH;
00395 
00396     if (al == NULL || ds == NULL || (KName = rpmdsN(ds)) == NULL)
00397         goto exit;
00398 
00399     if (*KName == '/') {
00400         /* First, look for files "contained" in package ... */
00401         ret = rpmalAllFileSatisfiesDepend(al, ds, keyp);
00402         if (ret != NULL && *ret != NULL)
00403             goto exit;
00404         ret = _free(ret);
00405         /* ... then, look for files "provided" by package. */
00406     }
00407 
00408     ai = &al->index;
00409     if (ai->index == NULL || ai->size <= 0)
00410         goto exit;
00411 
00412     needle = memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
00413     /*@-assignexpose -temptrans@*/
00414     needle->entry = KName;
00415     /*@=assignexpose =temptrans@*/
00416     needle->entryLen = (unsigned short)strlen(needle->entry);
00417 
00418     match = bsearch(needle, ai->index, ai->size, sizeof(*ai->index), indexcmp);
00419     if (match == NULL)
00420         goto exit;
00421 
00422     /* rewind to the first match */
00423     while (match > ai->index && indexcmp(match-1, needle) == 0)
00424         match--;
00425 
00426     if (al->list != NULL)       /* XXX always true */
00427     for (ret = NULL, found = 0;
00428          match < ai->index + ai->size && indexcmp(match, needle) == 0;
00429          match++)
00430     {
00431         alp = al->list + alKey2Num(al, match->pkgKey);
00432 
00433         rc = 0;
00434         if (alp->provides != NULL)      /* XXX can't happen */
00435         switch (match->type) {
00436         case IET_PROVIDES:
00437             /* XXX single step on rpmdsNext to regenerate DNEVR string */
00438             (void) rpmdsSetIx(alp->provides, match->entryIx - 1);
00439             if (rpmdsNext(alp->provides) >= 0)
00440                 rc = rpmdsCompare(alp->provides, ds);
00441 
00442             if (rc)
00443                 rpmdsNotify(ds, _("(added provide)"), 0);
00444 
00445             /*@switchbreak@*/ break;
00446         }
00447 
00448         if (rc) {
00449             ret = xrealloc(ret, (found + 2) * sizeof(*ret));
00450             if (ret)    /* can't happen */
00451                 ret[found] = alp->key;
00452 /*@-dependenttrans@*/
00453             if (keyp)
00454                 *keyp = match->pkgKey;
00455 /*@=dependenttrans@*/
00456             found++;
00457         }
00458     }
00459 
00460     if (ret)
00461         ret[found] = NULL;
00462 
00463 exit:
00464 /*@-nullstate@*/ /* FIX: *keyp may be NULL */
00465     return ret;
00466 /*@=nullstate@*/
00467 }
00468 
00469 fnpyKey
00470 rpmalSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00471 {
00472     fnpyKey * tmp = rpmalAllSatisfiesDepend(al, ds, keyp);
00473 
00474     if (tmp) {
00475         fnpyKey ret = tmp[0];
00476         free(tmp);
00477         return ret;
00478     }
00479     return NULL;
00480 }