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 uint_32 tscolor;
00038
00039 fnpyKey key;
00041 };
00042
00043 typedef struct availableIndexEntry_s * availableIndexEntry;
00044
00045
00049 struct availableIndexEntry_s {
00050
00051 alKey pkgKey;
00052
00053 const char * entry;
00054 unsigned short entryLen;
00055 unsigned short entryIx;
00056 enum indexEntryType {
00057 IET_PROVIDES=1
00058 } type;
00059 };
00060
00061 typedef struct availableIndex_s * availableIndex;
00062
00063
00067 struct availableIndex_s {
00068
00069 availableIndexEntry index;
00070 int size;
00071 int k;
00072 };
00073
00074 typedef struct fileIndexEntry_s * fileIndexEntry;
00075
00076
00080 struct fileIndexEntry_s {
00081
00082 const char * baseName;
00083 int baseNameLen;
00084 alNum pkgNum;
00085 uint_32 ficolor;
00086 };
00087
00088 typedef struct dirInfo_s * dirInfo;
00089
00090
00094 struct dirInfo_s {
00095
00096 const char * dirName;
00097 int dirNameLen;
00098
00099 fileIndexEntry files;
00100 int numFiles;
00101 };
00102
00106 struct rpmal_s {
00107
00108 availablePackage list;
00109 struct availableIndex_s index;
00110 int delta;
00111 int size;
00112 int alloced;
00113 uint_32 tscolor;
00114 int numDirs;
00115
00116 dirInfo dirs;
00117 };
00118
00123 static void rpmalFreeIndex(rpmal al)
00124
00125 {
00126 availableIndex ai = &al->index;
00127 if (ai->size > 0) {
00128 ai->index = _free(ai->index);
00129 ai->size = 0;
00130 }
00131 }
00132
00133 #ifdef DYING
00134
00139 static int alGetSize( const rpmal al)
00140
00141 {
00142 return (al != NULL ? al->size : 0);
00143 }
00144 #endif
00145
00146 static inline alNum alKey2Num( const rpmal al,
00147 alKey pkgKey)
00148
00149 {
00150
00151 return ((alNum)pkgKey);
00152
00153 }
00154
00155 static inline alKey alNum2Key( const rpmal al,
00156 alNum pkgNum)
00157
00158 {
00159
00160 return ((alKey)pkgNum);
00161
00162 }
00163
00164 #ifdef DYING
00165
00171
00172 static availablePackage alGetPkg( const rpmal al,
00173 alKey pkgKey)
00174
00175 {
00176 alNum pkgNum = alKey2Num(al, pkgKey);
00177 availablePackage alp = NULL;
00178
00179 if (al != NULL && pkgNum >= 0 && pkgNum < alGetSize(al)) {
00180 if (al->list != NULL)
00181 alp = al->list + pkgNum;
00182 }
00183 return alp;
00184 }
00185 #endif
00186
00187 rpmal rpmalCreate(int delta)
00188 {
00189 rpmal al = xcalloc(1, sizeof(*al));
00190 availableIndex ai = &al->index;
00191
00192 al->delta = delta;
00193 al->size = 0;
00194 al->list = xcalloc(al->delta, sizeof(*al->list));
00195 al->alloced = al->delta;
00196
00197 ai->index = NULL;
00198 ai->size = 0;
00199
00200 al->numDirs = 0;
00201 al->dirs = NULL;
00202 return al;
00203 }
00204
00205 rpmal rpmalFree(rpmal al)
00206 {
00207 availablePackage alp;
00208 dirInfo die;
00209 int i;
00210
00211 if (al == NULL)
00212 return NULL;
00213
00214 if ((alp = al->list) != NULL)
00215 for (i = 0; i < al->size; i++, alp++) {
00216 alp->provides = rpmdsFree(alp->provides);
00217 alp->fi = rpmfiFree(alp->fi);
00218 }
00219
00220 if ((die = al->dirs) != NULL)
00221 for (i = 0; i < al->numDirs; i++, die++) {
00222 die->dirName = _free(die->dirName);
00223 die->files = _free(die->files);
00224 }
00225 al->dirs = _free(al->dirs);
00226 al->numDirs = 0;
00227
00228 al->list = _free(al->list);
00229 al->alloced = 0;
00230 rpmalFreeIndex(al);
00231 al = _free(al);
00232 return NULL;
00233 }
00234
00241 static int dieCompare(const void * one, const void * two)
00242
00243 {
00244
00245 const dirInfo a = (const dirInfo) one;
00246 const dirInfo b = (const dirInfo) two;
00247
00248 int lenchk = a->dirNameLen - b->dirNameLen;
00249
00250 if (lenchk || a->dirNameLen == 0)
00251 return lenchk;
00252
00253 if (a->dirName == NULL || b->dirName == NULL)
00254 return lenchk;
00255
00256
00257 return strcmp(a->dirName, b->dirName);
00258 }
00259
00266 static int fieCompare(const void * one, const void * two)
00267
00268 {
00269
00270 const fileIndexEntry a = (const fileIndexEntry) one;
00271 const fileIndexEntry b = (const fileIndexEntry) two;
00272
00273 int lenchk = a->baseNameLen - b->baseNameLen;
00274
00275 if (lenchk)
00276 return lenchk;
00277
00278 if (a->baseName == NULL || b->baseName == NULL)
00279 return lenchk;
00280
00281
00282 return strcmp(a->baseName, b->baseName);
00283 }
00284
00285 void rpmalDel(rpmal al, alKey pkgKey)
00286 {
00287 alNum pkgNum = alKey2Num(al, pkgKey);
00288 availablePackage alp;
00289 rpmfi fi;
00290
00291 if (al == NULL || al->list == NULL)
00292 return;
00293
00294 alp = al->list + pkgNum;
00295
00296
00297 if (_rpmal_debug)
00298 fprintf(stderr, "*** del %p[%d]\n", al->list, pkgNum);
00299
00300
00301
00302 if ((fi = alp->fi) != NULL)
00303 if (rpmfiFC(fi) > 0) {
00304 int origNumDirs = al->numDirs;
00305 int dx;
00306 dirInfo dieNeedle =
00307 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
00308 dirInfo die;
00309 int last;
00310 int i;
00311
00312
00313
00314 if (al->dirs != NULL)
00315 for (dx = rpmfiDC(fi) - 1; dx >= 0; dx--)
00316 {
00317 fileIndexEntry fie;
00318
00319 (void) rpmfiSetDX(fi, dx);
00320
00321
00322 dieNeedle->dirName = (char *) rpmfiDN(fi);
00323
00324 dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
00325 ? strlen(dieNeedle->dirName) : 0);
00326
00327 die = bsearch(dieNeedle, al->dirs, al->numDirs,
00328 sizeof(*dieNeedle), dieCompare);
00329
00330 if (die == NULL)
00331 continue;
00332
00333 last = die->numFiles;
00334 fie = die->files + last - 1;
00335 for (i = last - 1; i >= 0; i--, fie--) {
00336 if (fie->pkgNum != pkgNum)
00337 continue;
00338 die->numFiles--;
00339 if (i > die->numFiles)
00340 continue;
00341
00342 memmove(fie, fie+1, (die->numFiles - i) * sizeof(*fie));
00343
00344 }
00345 if (die->numFiles > 0) {
00346 if (last > i)
00347 die->files = xrealloc(die->files,
00348 die->numFiles * sizeof(*die->files));
00349 continue;
00350 }
00351 die->files = _free(die->files);
00352 die->dirName = _free(die->dirName);
00353 al->numDirs--;
00354 if ((die - al->dirs) > al->numDirs)
00355 continue;
00356
00357 memmove(die, die+1, (al->numDirs - (die - al->dirs)) * sizeof(*die));
00358
00359 }
00360
00361 if (origNumDirs > al->numDirs) {
00362 if (al->numDirs > 0)
00363 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
00364 else
00365 al->dirs = _free(al->dirs);
00366 }
00367 }
00368
00369 alp->provides = rpmdsFree(alp->provides);
00370 alp->fi = rpmfiFree(alp->fi);
00371
00372
00373 memset(alp, 0, sizeof(*alp));
00374
00375 return;
00376 }
00377
00378
00379 alKey rpmalAdd(rpmal * alistp, alKey pkgKey, fnpyKey key,
00380 rpmds provides, rpmfi fi, uint_32 tscolor)
00381 {
00382 alNum pkgNum;
00383 rpmal al;
00384 availablePackage alp;
00385
00386
00387 if (*alistp == NULL)
00388 *alistp = rpmalCreate(5);
00389 al = *alistp;
00390 pkgNum = alKey2Num(al, pkgKey);
00391
00392 if (pkgNum >= 0 && pkgNum < al->size) {
00393 rpmalDel(al, pkgKey);
00394 } else {
00395 if (al->size == al->alloced) {
00396 al->alloced += al->delta;
00397 al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
00398 }
00399 pkgNum = al->size++;
00400 }
00401
00402 if (al->list == NULL)
00403 return RPMAL_NOMATCH;
00404
00405 alp = al->list + pkgNum;
00406
00407 alp->key = key;
00408 alp->tscolor = tscolor;
00409
00410
00411 if (_rpmal_debug)
00412 fprintf(stderr, "*** add %p[%d] 0x%x\n", al->list, pkgNum, tscolor);
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->ficolor = rpmfiFColor(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, uint_32 tscolor)
00542 {
00543 uint_32 dscolor;
00544 const char * Name;
00545 alNum pkgNum = alKey2Num(al, pkgKey);
00546 availableIndex ai = &al->index;
00547 availableIndexEntry aie;
00548 int ix;
00549
00550 if (provides == NULL || pkgNum < 0 || pkgNum >= al->size)
00551 return;
00552 if (ai->index == NULL || ai->k < 0 || ai->k >= ai->size)
00553 return;
00554
00555 if (rpmdsInit(provides) != NULL)
00556 while (rpmdsNext(provides) >= 0) {
00557
00558 if ((Name = rpmdsN(provides)) == NULL)
00559 continue;
00560
00561
00562 dscolor = rpmdsColor(provides);
00563 if (tscolor && dscolor && !(tscolor & dscolor))
00564 continue;
00565
00566 aie = ai->index + ai->k;
00567 ai->k++;
00568
00569 aie->pkgKey = pkgKey;
00570 aie->entry = Name;
00571 aie->entryLen = strlen(Name);
00572 ix = rpmdsIx(provides);
00573
00574
00575 assert(ix < 0x10000);
00576
00577 aie->entryIx = ix;
00578 aie->type = IET_PROVIDES;
00579 }
00580 }
00581
00582 void rpmalMakeIndex(rpmal al)
00583 {
00584 availableIndex ai;
00585 availablePackage alp;
00586 int i;
00587
00588 if (al == NULL || al->list == NULL) return;
00589 ai = &al->index;
00590
00591 ai->size = 0;
00592 for (i = 0; i < al->size; i++) {
00593 alp = al->list + i;
00594 if (alp->provides != NULL)
00595 ai->size += rpmdsCount(alp->provides);
00596 }
00597 if (ai->size == 0) return;
00598
00599 ai->index = xrealloc(ai->index, ai->size * sizeof(*ai->index));
00600 ai->k = 0;
00601
00602 for (i = 0; i < al->size; i++) {
00603 alp = al->list + i;
00604 rpmalAddProvides(al, (alKey)i, alp->provides, alp->tscolor);
00605 }
00606 qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
00607 }
00608
00609 fnpyKey *
00610 rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00611 {
00612 uint_32 tscolor;
00613 uint_32 ficolor;
00614 int found = 0;
00615 const char * dirName;
00616 const char * baseName;
00617 dirInfo dieNeedle =
00618 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
00619 dirInfo die;
00620 fileIndexEntry fieNeedle =
00621 memset(alloca(sizeof(*fieNeedle)), 0, sizeof(*fieNeedle));
00622 fileIndexEntry fie;
00623 availablePackage alp;
00624 fnpyKey * ret = NULL;
00625 const char * fileName;
00626
00627 if (keyp) *keyp = RPMAL_NOMATCH;
00628
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 alp = al->list + fie->pkgNum;
00685
00686
00687 tscolor = alp->tscolor;
00688 ficolor = fie->ficolor;
00689 if (tscolor && ficolor && !(tscolor & ficolor))
00690 continue;
00691
00692 rpmdsNotify(ds, _("(added files)"), 0);
00693
00694 ret = xrealloc(ret, (found+2) * sizeof(*ret));
00695 if (ret)
00696 ret[found] = alp->key;
00697 if (keyp)
00698 *keyp = alNum2Key(al, fie->pkgNum);
00699 found++;
00700 }
00701
00702
00703 exit:
00704 dirName = _free(dirName);
00705 if (ret)
00706 ret[found] = NULL;
00707 return ret;
00708 }
00709
00710 fnpyKey *
00711 rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00712 {
00713 availableIndex ai;
00714 availableIndexEntry needle;
00715 availableIndexEntry match;
00716 fnpyKey * ret = NULL;
00717 int found = 0;
00718 const char * KName;
00719 availablePackage alp;
00720 int rc;
00721
00722 if (keyp) *keyp = RPMAL_NOMATCH;
00723
00724 if (al == NULL || ds == NULL || (KName = rpmdsN(ds)) == NULL)
00725 return ret;
00726
00727 if (*KName == '/') {
00728
00729 ret = rpmalAllFileSatisfiesDepend(al, ds, keyp);
00730 if (ret != NULL && *ret != NULL)
00731 return ret;
00732
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
00781 if (keyp)
00782 *keyp = match->pkgKey;
00783
00784 found++;
00785 }
00786
00787 }
00788
00789 if (ret)
00790 ret[found] = NULL;
00791
00792
00793 return ret;
00794
00795 }
00796
00797 fnpyKey
00798 rpmalSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00799 {
00800 fnpyKey * tmp = rpmalAllSatisfiesDepend(al, ds, keyp);
00801
00802 if (tmp) {
00803 fnpyKey ret = tmp[0];
00804 free(tmp);
00805 return ret;
00806 }
00807 return NULL;
00808 }