00001
00005 #include "system.h"
00006
00007 #include <rpmlib.h>
00008
00009 #include "rpmal.h"
00010 #include "rpmds.h"
00011 #include "rpmfi.h"
00012
00013 #include "debug.h"
00014
00015 typedef struct availablePackage_s * availablePackage;
00016
00017
00018 int _rpmal_debug = 0;
00019
00020
00021
00022
00023
00024
00025
00026
00030 struct availablePackage_s {
00031
00032 rpmds provides;
00033
00034 rpmfi fi;
00036 #ifdef DYING
00037 uint_32 multiLib;
00038 #endif
00039
00040
00041 fnpyKey key;
00043 };
00044
00045 typedef struct availableIndexEntry_s * availableIndexEntry;
00046
00047
00051 struct availableIndexEntry_s {
00052
00053 alKey pkgKey;
00054
00055 const char * entry;
00056 unsigned short entryLen;
00057 unsigned short entryIx;
00058 enum indexEntryType {
00059 IET_PROVIDES=1
00060 } type;
00061 };
00062
00063 typedef struct availableIndex_s * availableIndex;
00064
00065
00069 struct availableIndex_s {
00070
00071 availableIndexEntry index;
00072 int size;
00073 int k;
00074 };
00075
00076 typedef struct fileIndexEntry_s * fileIndexEntry;
00077
00078
00082 struct fileIndexEntry_s {
00083
00084 const char * baseName;
00085 int baseNameLen;
00086 alNum pkgNum;
00087 int fileFlags;
00088 };
00089
00090 typedef struct dirInfo_s * dirInfo;
00091
00092
00096 struct dirInfo_s {
00097
00098 const char * dirName;
00099 int dirNameLen;
00100
00101 fileIndexEntry files;
00102 int numFiles;
00103 };
00104
00108 struct rpmal_s {
00109
00110 availablePackage list;
00111 struct availableIndex_s index;
00112 int delta;
00113 int size;
00114 int alloced;
00115 int numDirs;
00116
00117 dirInfo dirs;
00118 };
00119
00124 static void rpmalFreeIndex(rpmal al)
00125
00126 {
00127 availableIndex ai = &al->index;
00128 if (ai->size > 0) {
00129 ai->index = _free(ai->index);
00130 ai->size = 0;
00131 }
00132 }
00133
00134 #ifdef DYING
00135
00140 static int alGetSize( const rpmal al)
00141
00142 {
00143 return (al != NULL ? al->size : 0);
00144 }
00145 #endif
00146
00147 static inline alNum alKey2Num( const rpmal al,
00148 alKey pkgKey)
00149
00150 {
00151
00152 return ((alNum)pkgKey);
00153
00154 }
00155
00156 static inline alKey alNum2Key( const rpmal al,
00157 alNum pkgNum)
00158
00159 {
00160
00161 return ((alKey)pkgNum);
00162
00163 }
00164
00165 #ifdef DYING
00166
00172
00173 static availablePackage alGetPkg( const rpmal al,
00174 alKey pkgKey)
00175
00176 {
00177 alNum pkgNum = alKey2Num(al, pkgKey);
00178 availablePackage alp = NULL;
00179
00180 if (al != NULL && pkgNum >= 0 && pkgNum < alGetSize(al)) {
00181 if (al->list != NULL)
00182 alp = al->list + pkgNum;
00183 }
00184 return alp;
00185 }
00186 #endif
00187
00188 rpmal rpmalCreate(int delta)
00189 {
00190 rpmal al = xcalloc(1, sizeof(*al));
00191 availableIndex ai = &al->index;
00192
00193 al->delta = delta;
00194 al->size = 0;
00195 al->list = xcalloc(al->delta, sizeof(*al->list));
00196 al->alloced = al->delta;
00197
00198 ai->index = NULL;
00199 ai->size = 0;
00200
00201 al->numDirs = 0;
00202 al->dirs = NULL;
00203 return al;
00204 }
00205
00206 rpmal rpmalFree(rpmal al)
00207 {
00208 availablePackage alp;
00209 dirInfo die;
00210 int i;
00211
00212 if (al == NULL)
00213 return NULL;
00214
00215 if ((alp = al->list) != NULL)
00216 for (i = 0; i < al->size; i++, alp++) {
00217 alp->provides = rpmdsFree(alp->provides);
00218 alp->fi = rpmfiFree(alp->fi);
00219 }
00220
00221 if ((die = al->dirs) != NULL)
00222 for (i = 0; i < al->numDirs; i++, die++) {
00223 die->dirName = _free(die->dirName);
00224 die->files = _free(die->files);
00225 }
00226 al->dirs = _free(al->dirs);
00227 al->numDirs = 0;
00228
00229 al->list = _free(al->list);
00230 al->alloced = 0;
00231 rpmalFreeIndex(al);
00232 al = _free(al);
00233 return NULL;
00234 }
00235
00242 static int dieCompare(const void * one, const void * two)
00243
00244 {
00245
00246 const dirInfo a = (const dirInfo) one;
00247 const dirInfo b = (const dirInfo) two;
00248
00249 int lenchk = a->dirNameLen - b->dirNameLen;
00250
00251 if (lenchk || a->dirNameLen == 0)
00252 return lenchk;
00253
00254 if (a->dirName == NULL || b->dirName == NULL)
00255 return lenchk;
00256
00257
00258 return strcmp(a->dirName, b->dirName);
00259 }
00260
00267 static int fieCompare(const void * one, const void * two)
00268
00269 {
00270
00271 const fileIndexEntry a = (const fileIndexEntry) one;
00272 const fileIndexEntry b = (const fileIndexEntry) two;
00273
00274 int lenchk = a->baseNameLen - b->baseNameLen;
00275
00276 if (lenchk)
00277 return lenchk;
00278
00279 if (a->baseName == NULL || b->baseName == NULL)
00280 return lenchk;
00281
00282
00283 return strcmp(a->baseName, b->baseName);
00284 }
00285
00286 void rpmalDel(rpmal al, alKey pkgKey)
00287 {
00288 alNum pkgNum = alKey2Num(al, pkgKey);
00289 availablePackage alp;
00290 rpmfi fi;
00291
00292 if (al == NULL || al->list == NULL)
00293 return;
00294
00295 alp = al->list + pkgNum;
00296
00297
00298 if (_rpmal_debug)
00299 fprintf(stderr, "*** del %p[%d]\n", al->list, pkgNum);
00300
00301
00302
00303 if ((fi = alp->fi) != NULL)
00304 if (rpmfiFC(fi) > 0) {
00305 int origNumDirs = al->numDirs;
00306 int dx;
00307 dirInfo dieNeedle =
00308 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
00309 dirInfo die;
00310 int last;
00311 int i;
00312
00313
00314
00315 if (al->dirs != NULL)
00316 for (dx = rpmfiDC(fi) - 1; dx >= 0; dx--)
00317 {
00318 fileIndexEntry fie;
00319
00320 (void) rpmfiSetDX(fi, dx);
00321
00322
00323 dieNeedle->dirName = (char *) rpmfiDN(fi);
00324
00325 dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
00326 ? strlen(dieNeedle->dirName) : 0);
00327
00328 die = bsearch(dieNeedle, al->dirs, al->numDirs,
00329 sizeof(*dieNeedle), dieCompare);
00330
00331 if (die == NULL)
00332 continue;
00333
00334 last = die->numFiles;
00335 fie = die->files + last - 1;
00336 for (i = last - 1; i >= 0; i--, fie--) {
00337 if (fie->pkgNum != pkgNum)
00338 continue;
00339 die->numFiles--;
00340 if (i > die->numFiles)
00341 continue;
00342
00343 memmove(fie, fie+1, (die->numFiles - i) * sizeof(*fie));
00344
00345 }
00346 if (die->numFiles > 0) {
00347 if (last > i)
00348 die->files = xrealloc(die->files,
00349 die->numFiles * sizeof(*die->files));
00350 continue;
00351 }
00352 die->files = _free(die->files);
00353 die->dirName = _free(die->dirName);
00354 al->numDirs--;
00355 if ((die - al->dirs) > al->numDirs)
00356 continue;
00357
00358 memmove(die, die+1, (al->numDirs - (die - al->dirs)) * sizeof(*die));
00359
00360 }
00361
00362 if (origNumDirs > al->numDirs) {
00363 if (al->numDirs > 0)
00364 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
00365 else
00366 al->dirs = _free(al->dirs);
00367 }
00368 }
00369
00370 alp->provides = rpmdsFree(alp->provides);
00371 alp->fi = rpmfiFree(alp->fi);
00372
00373
00374 memset(alp, 0, sizeof(*alp));
00375
00376 return;
00377 }
00378
00379
00380 alKey rpmalAdd(rpmal * alistp, alKey pkgKey, fnpyKey key,
00381 rpmds provides, rpmfi fi)
00382 {
00383 alNum pkgNum;
00384 rpmal al;
00385 availablePackage alp;
00386
00387
00388 if (*alistp == NULL)
00389 *alistp = rpmalCreate(5);
00390 al = *alistp;
00391 pkgNum = alKey2Num(al, pkgKey);
00392
00393 if (pkgNum >= 0 && pkgNum < al->size) {
00394 rpmalDel(al, pkgKey);
00395 } else {
00396 if (al->size == al->alloced) {
00397 al->alloced += al->delta;
00398 al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
00399 }
00400 pkgNum = al->size++;
00401 }
00402
00403 if (al->list == NULL)
00404 return RPMAL_NOMATCH;
00405
00406 alp = al->list + pkgNum;
00407
00408 alp->key = key;
00409
00410
00411 if (_rpmal_debug)
00412 fprintf(stderr, "*** add %p[%d]\n", al->list, pkgNum);
00413
00414
00415 alp->provides = rpmdsLink(provides, "Provides (rpmalAdd)");
00416 alp->fi = rpmfiLink(fi, "Files (rpmalAdd)");
00417
00418 fi = rpmfiLink(alp->fi, "Files index (rpmalAdd)");
00419 fi = rpmfiInit(fi, 0);
00420 if (rpmfiFC(fi) > 0) {
00421 int * dirMapping;
00422 dirInfo dieNeedle =
00423 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
00424 dirInfo die;
00425 int first;
00426 int origNumDirs;
00427 int dx;
00428 int dc;
00429
00430 dc = rpmfiDC(fi);
00431
00432
00433
00434 dirMapping = alloca(sizeof(*dirMapping) * dc);
00435
00436
00437
00438
00439
00440 al->dirs = xrealloc(al->dirs, (al->numDirs + dc) * sizeof(*al->dirs));
00441 origNumDirs = al->numDirs;
00442
00443 for (dx = 0; dx < dc; dx++) {
00444
00445 (void) rpmfiSetDX(fi, dx);
00446
00447
00448 dieNeedle->dirName = (char *) rpmfiDN(fi);
00449
00450 dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
00451 ? strlen(dieNeedle->dirName) : 0);
00452 die = bsearch(dieNeedle, al->dirs, origNumDirs,
00453 sizeof(*dieNeedle), dieCompare);
00454 if (die) {
00455 dirMapping[dx] = die - al->dirs;
00456 } else {
00457 dirMapping[dx] = al->numDirs;
00458 die = al->dirs + al->numDirs;
00459 if (dieNeedle->dirName != NULL)
00460 die->dirName = xstrdup(dieNeedle->dirName);
00461 die->dirNameLen = dieNeedle->dirNameLen;
00462 die->files = NULL;
00463 die->numFiles = 0;
00464
00465 if (_rpmal_debug)
00466 fprintf(stderr, "+++ die[%3d] %p [%d] %s\n", al->numDirs, die, die->dirNameLen, die->dirName);
00467
00468
00469 al->numDirs++;
00470 }
00471 }
00472
00473 for (first = rpmfiNext(fi); first >= 0;) {
00474 fileIndexEntry fie;
00475 int next;
00476
00477
00478 dx = rpmfiDX(fi);
00479 while ((next = rpmfiNext(fi)) >= 0) {
00480 if (dx != rpmfiDX(fi))
00481 break;
00482 }
00483 if (next < 0) next = rpmfiFC(fi);
00484
00485 die = al->dirs + dirMapping[dx];
00486 die->files = xrealloc(die->files,
00487 (die->numFiles + next - first) * sizeof(*die->files));
00488 fie = die->files + die->numFiles;
00489
00490
00491 fi = rpmfiInit(fi, first);
00492 while ((first = rpmfiNext(fi)) >= 0 && first < next) {
00493
00494 fie->baseName = rpmfiBN(fi);
00495
00496 fie->baseNameLen = (fie->baseName ? strlen(fie->baseName) : 0);
00497 fie->pkgNum = pkgNum;
00498 fie->fileFlags = rpmfiFFlags(fi);
00499 die->numFiles++;
00500 fie++;
00501 }
00502 qsort(die->files, die->numFiles, sizeof(*die->files), fieCompare);
00503 }
00504
00505
00506 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
00507 if (origNumDirs != al->numDirs)
00508 qsort(al->dirs, al->numDirs, sizeof(*al->dirs), dieCompare);
00509 }
00510 fi = rpmfiUnlink(fi, "Files index (rpmalAdd)");
00511
00512 rpmalFreeIndex(al);
00513
00514 assert(((alNum)(alp - al->list)) == pkgNum);
00515 return ((alKey)(alp - al->list));
00516 }
00517
00518
00525 static int indexcmp(const void * one, const void * two)
00526
00527 {
00528
00529 const availableIndexEntry a = (const availableIndexEntry) one;
00530 const availableIndexEntry b = (const availableIndexEntry) two;
00531
00532 int lenchk;
00533
00534 lenchk = a->entryLen - b->entryLen;
00535 if (lenchk)
00536 return lenchk;
00537
00538 return strcmp(a->entry, b->entry);
00539 }
00540
00541 void rpmalAddProvides(rpmal al, alKey pkgKey, rpmds provides)
00542 {
00543 alNum pkgNum = alKey2Num(al, pkgKey);
00544 availableIndex ai = &al->index;
00545 availableIndexEntry aie;
00546 int ix;
00547
00548 if (provides == NULL || pkgNum < 0 || pkgNum >= al->size)
00549 return;
00550 if (ai->index == NULL || ai->k < 0 || ai->k >= ai->size)
00551 return;
00552
00553 if (rpmdsInit(provides) != NULL)
00554 while (rpmdsNext(provides) >= 0) {
00555 const char * Name;
00556
00557 #ifdef DYING
00558 const int_32 Flags = rpmdsFlags(provides);
00559
00560
00561 if (al->list[i].multiLib && !isDependsMULTILIB(Flags)) {
00562 ai->size--;
00563 continue;
00564 }
00565 #endif
00566
00567 if ((Name = rpmdsN(provides)) == NULL)
00568 continue;
00569
00570 aie = ai->index + ai->k;
00571 ai->k++;
00572
00573 aie->pkgKey = pkgKey;
00574 aie->entry = Name;
00575 aie->entryLen = strlen(Name);
00576 ix = rpmdsIx(provides);
00577
00578
00579 assert(ix < 0x10000);
00580
00581 aie->entryIx = ix;
00582 aie->type = IET_PROVIDES;
00583 }
00584 }
00585
00586 void rpmalMakeIndex(rpmal al)
00587 {
00588 availableIndex ai;
00589 availablePackage alp;
00590 int i;
00591
00592 if (al == NULL || al->list == NULL) return;
00593 ai = &al->index;
00594
00595 ai->size = 0;
00596 for (i = 0; i < al->size; i++) {
00597 alp = al->list + i;
00598 if (alp->provides != NULL)
00599 ai->size += rpmdsCount(alp->provides);
00600 }
00601
00602 ai->index = xrealloc(ai->index, ai->size * sizeof(*ai->index));
00603 ai->k = 0;
00604
00605 for (i = 0; i < al->size; i++) {
00606 alp = al->list + i;
00607 rpmalAddProvides(al, (alKey)i, alp->provides);
00608 }
00609 qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
00610 }
00611
00612 fnpyKey *
00613 rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00614 {
00615 int found = 0;
00616 const char * dirName;
00617 const char * baseName;
00618 dirInfo dieNeedle =
00619 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
00620 dirInfo die;
00621 fileIndexEntry fieNeedle =
00622 memset(alloca(sizeof(*fieNeedle)), 0, sizeof(*fieNeedle));
00623 fileIndexEntry fie;
00624 availablePackage alp;
00625 fnpyKey * ret = NULL;
00626 const char * fileName;
00627
00628 if (keyp) *keyp = RPMAL_NOMATCH;
00629 if (al == NULL || (fileName = rpmdsN(ds)) == NULL || *fileName != '/')
00630 return NULL;
00631
00632
00633 if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
00634 return NULL;
00635
00636 { char * t;
00637 dirName = t = xstrdup(fileName);
00638 if ((t = strrchr(t, '/')) != NULL) {
00639 t++;
00640 *t = '\0';
00641 }
00642 }
00643
00644 dieNeedle->dirName = (char *) dirName;
00645 dieNeedle->dirNameLen = strlen(dirName);
00646 die = bsearch(dieNeedle, al->dirs, al->numDirs,
00647 sizeof(*dieNeedle), dieCompare);
00648 if (die == NULL)
00649 goto exit;
00650
00651
00652 while (die > al->dirs && dieCompare(die-1, dieNeedle) == 0)
00653 die--;
00654
00655 if ((baseName = strrchr(fileName, '/')) == NULL)
00656 goto exit;
00657 baseName++;
00658
00659
00660 for (found = 0, ret = NULL;
00661 die <= al->dirs + al->numDirs && dieCompare(die, dieNeedle) == 0;
00662 die++)
00663 {
00664
00665
00666 if (_rpmal_debug)
00667 fprintf(stderr, "==> die %p %s\n", die, (die->dirName ? die->dirName : "(nil)"));
00668
00669
00670
00671 fieNeedle->baseName = baseName;
00672
00673 fieNeedle->baseNameLen = strlen(fieNeedle->baseName);
00674 fie = bsearch(fieNeedle, die->files, die->numFiles,
00675 sizeof(*fieNeedle), fieCompare);
00676 if (fie == NULL)
00677 continue;
00678
00679
00680 if (_rpmal_debug)
00681 fprintf(stderr, "==> fie %p %s\n", fie, (fie->baseName ? fie->baseName : "(nil)"));
00682
00683
00684 #ifdef DYING
00685
00686
00687
00688
00689 if (al->list[fie->pkgNum].multiLib && !isFileMULTILIB(fie->fileFlags))
00690 continue;
00691 #endif
00692
00693 rpmdsNotify(ds, _("(added files)"), 0);
00694
00695 alp = al->list + fie->pkgNum;
00696 ret = xrealloc(ret, (found+2) * sizeof(*ret));
00697 if (ret)
00698 ret[found++] = alp->key;
00699 if (keyp)
00700 *keyp = alNum2Key(al, fie->pkgNum);
00701 }
00702
00703
00704 exit:
00705 dirName = _free(dirName);
00706 if (ret)
00707 ret[found] = NULL;
00708 return ret;
00709 }
00710
00711 fnpyKey *
00712 rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00713 {
00714 availableIndex ai;
00715 availableIndexEntry needle;
00716 availableIndexEntry match;
00717 fnpyKey * ret = NULL;
00718 int found = 0;
00719 const char * KName;
00720 availablePackage alp;
00721 int rc;
00722
00723 if (keyp) *keyp = RPMAL_NOMATCH;
00724
00725 if (al == NULL || ds == NULL || (KName = rpmdsN(ds)) == NULL)
00726 return ret;
00727
00728 if (*KName == '/') {
00729 ret = rpmalAllFileSatisfiesDepend(al, ds, keyp);
00730
00731 if (ret != NULL && *ret != NULL)
00732 return ret;
00733 }
00734
00735 ai = &al->index;
00736 if (ai->index == NULL || ai->size <= 0)
00737 return NULL;
00738
00739 needle = memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
00740
00741 needle->entry = KName;
00742
00743 needle->entryLen = strlen(needle->entry);
00744
00745 match = bsearch(needle, ai->index, ai->size, sizeof(*ai->index), indexcmp);
00746 if (match == NULL)
00747 return NULL;
00748
00749
00750 while (match > ai->index && indexcmp(match-1, needle) == 0)
00751 match--;
00752
00753 if (al->list != NULL)
00754 for (ret = NULL, found = 0;
00755 match <= ai->index + ai->size && indexcmp(match, needle) == 0;
00756 match++)
00757 {
00758 alp = al->list + alKey2Num(al, match->pkgKey);
00759
00760 rc = 0;
00761 if (alp->provides != NULL)
00762 switch (match->type) {
00763 case IET_PROVIDES:
00764
00765 (void) rpmdsSetIx(alp->provides, match->entryIx - 1);
00766 if (rpmdsNext(alp->provides) >= 0)
00767 rc = rpmdsCompare(alp->provides, ds);
00768
00769 if (rc)
00770 rpmdsNotify(ds, _("(added provide)"), 0);
00771
00772 break;
00773 }
00774
00775
00776 if (rc) {
00777 ret = xrealloc(ret, (found + 2) * sizeof(*ret));
00778 if (ret)
00779 ret[found++] = alp->key;
00780 if (keyp)
00781 *keyp = ((alKey)(alp - al->list));
00782 }
00783
00784 }
00785
00786 if (ret)
00787 ret[found] = NULL;
00788
00789 return ret;
00790 }
00791
00792 fnpyKey
00793 rpmalSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00794 {
00795 fnpyKey * tmp = rpmalAllSatisfiesDepend(al, ds, keyp);
00796
00797 if (tmp) {
00798 fnpyKey ret = tmp[0];
00799 free(tmp);
00800 return ret;
00801 }
00802 return NULL;
00803 }