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 { const char * DN = rpmfiDN(fi);
00449
00450 #if defined(__ia64__)
00451
00452 #define DNPREFIX "/emul/ia32-linux"
00453 if (!strncmp(DN, DNPREFIX, sizeof(DNPREFIX)-1))
00454 DN += sizeof(DNPREFIX)-1;
00455 #endif
00456 dieNeedle->dirName = DN;
00457 }
00458
00459
00460 dieNeedle->dirNameLen = (dieNeedle->dirName != NULL
00461 ? strlen(dieNeedle->dirName) : 0);
00462 die = bsearch(dieNeedle, al->dirs, origNumDirs,
00463 sizeof(*dieNeedle), dieCompare);
00464 if (die) {
00465 dirMapping[dx] = die - al->dirs;
00466 } else {
00467 dirMapping[dx] = al->numDirs;
00468 die = al->dirs + al->numDirs;
00469 if (dieNeedle->dirName != NULL)
00470 die->dirName = xstrdup(dieNeedle->dirName);
00471 die->dirNameLen = dieNeedle->dirNameLen;
00472 die->files = NULL;
00473 die->numFiles = 0;
00474
00475 if (_rpmal_debug)
00476 fprintf(stderr, "+++ die[%3d] %p [%d] %s\n", al->numDirs, die, die->dirNameLen, die->dirName);
00477
00478
00479 al->numDirs++;
00480 }
00481 }
00482
00483 for (first = rpmfiNext(fi); first >= 0;) {
00484 fileIndexEntry fie;
00485 int next;
00486
00487
00488 dx = rpmfiDX(fi);
00489 while ((next = rpmfiNext(fi)) >= 0) {
00490 if (dx != rpmfiDX(fi))
00491 break;
00492 }
00493 if (next < 0) next = rpmfiFC(fi);
00494
00495 die = al->dirs + dirMapping[dx];
00496 die->files = xrealloc(die->files,
00497 (die->numFiles + next - first) * sizeof(*die->files));
00498 fie = die->files + die->numFiles;
00499
00500
00501 fi = rpmfiInit(fi, first);
00502 while ((first = rpmfiNext(fi)) >= 0 && first < next) {
00503
00504 fie->baseName = rpmfiBN(fi);
00505
00506 fie->baseNameLen = (fie->baseName ? strlen(fie->baseName) : 0);
00507 fie->pkgNum = pkgNum;
00508 fie->ficolor = rpmfiFColor(fi);
00509 die->numFiles++;
00510 fie++;
00511 }
00512 qsort(die->files, die->numFiles, sizeof(*die->files), fieCompare);
00513 }
00514
00515
00516 al->dirs = xrealloc(al->dirs, al->numDirs * sizeof(*al->dirs));
00517 if (origNumDirs != al->numDirs)
00518 qsort(al->dirs, al->numDirs, sizeof(*al->dirs), dieCompare);
00519 }
00520 fi = rpmfiUnlink(fi, "Files index (rpmalAdd)");
00521
00522 rpmalFreeIndex(al);
00523
00524 assert(((alNum)(alp - al->list)) == pkgNum);
00525 return ((alKey)(alp - al->list));
00526 }
00527
00528
00535 static int indexcmp(const void * one, const void * two)
00536
00537 {
00538
00539 const availableIndexEntry a = (const availableIndexEntry) one;
00540 const availableIndexEntry b = (const availableIndexEntry) two;
00541
00542 int lenchk;
00543
00544 lenchk = a->entryLen - b->entryLen;
00545 if (lenchk)
00546 return lenchk;
00547
00548 return strcmp(a->entry, b->entry);
00549 }
00550
00551 void rpmalAddProvides(rpmal al, alKey pkgKey, rpmds provides, uint_32 tscolor)
00552 {
00553 uint_32 dscolor;
00554 const char * Name;
00555 alNum pkgNum = alKey2Num(al, pkgKey);
00556 availableIndex ai = &al->index;
00557 availableIndexEntry aie;
00558 int ix;
00559
00560 if (provides == NULL || pkgNum < 0 || pkgNum >= al->size)
00561 return;
00562 if (ai->index == NULL || ai->k < 0 || ai->k >= ai->size)
00563 return;
00564
00565 if (rpmdsInit(provides) != NULL)
00566 while (rpmdsNext(provides) >= 0) {
00567
00568 if ((Name = rpmdsN(provides)) == NULL)
00569 continue;
00570
00571
00572 dscolor = rpmdsColor(provides);
00573 if (tscolor && dscolor && !(tscolor & dscolor))
00574 continue;
00575
00576 aie = ai->index + ai->k;
00577 ai->k++;
00578
00579 aie->pkgKey = pkgKey;
00580 aie->entry = Name;
00581 aie->entryLen = strlen(Name);
00582 ix = rpmdsIx(provides);
00583
00584
00585 assert(ix < 0x10000);
00586
00587 aie->entryIx = ix;
00588 aie->type = IET_PROVIDES;
00589 }
00590 }
00591
00592 void rpmalMakeIndex(rpmal al)
00593 {
00594 availableIndex ai;
00595 availablePackage alp;
00596 int i;
00597
00598 if (al == NULL || al->list == NULL) return;
00599 ai = &al->index;
00600
00601 ai->size = 0;
00602 for (i = 0; i < al->size; i++) {
00603 alp = al->list + i;
00604 if (alp->provides != NULL)
00605 ai->size += rpmdsCount(alp->provides);
00606 }
00607 if (ai->size == 0) return;
00608
00609 ai->index = xrealloc(ai->index, ai->size * sizeof(*ai->index));
00610 ai->k = 0;
00611 for (i = 0; i < al->size; i++) {
00612 alp = al->list + i;
00613 rpmalAddProvides(al, (alKey)i, alp->provides, alp->tscolor);
00614 }
00615
00616
00617 ai->size = ai->k;
00618 qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
00619 }
00620
00621 fnpyKey *
00622 rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00623 {
00624 uint_32 tscolor;
00625 uint_32 ficolor;
00626 int found = 0;
00627 const char * dirName;
00628 const char * baseName;
00629 dirInfo dieNeedle =
00630 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
00631 dirInfo die;
00632 fileIndexEntry fieNeedle =
00633 memset(alloca(sizeof(*fieNeedle)), 0, sizeof(*fieNeedle));
00634 fileIndexEntry fie;
00635 availablePackage alp;
00636 fnpyKey * ret = NULL;
00637 const char * fileName;
00638
00639 if (keyp) *keyp = RPMAL_NOMATCH;
00640
00641 if (al == NULL || (fileName = rpmdsN(ds)) == NULL || *fileName != '/')
00642 return NULL;
00643
00644
00645 if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
00646 return NULL;
00647
00648 { char * t;
00649 dirName = t = xstrdup(fileName);
00650 if ((t = strrchr(t, '/')) != NULL) {
00651 t++;
00652 *t = '\0';
00653 }
00654 }
00655
00656 dieNeedle->dirName = (char *) dirName;
00657 dieNeedle->dirNameLen = strlen(dirName);
00658 die = bsearch(dieNeedle, al->dirs, al->numDirs,
00659 sizeof(*dieNeedle), dieCompare);
00660 if (die == NULL)
00661 goto exit;
00662
00663
00664 while (die > al->dirs && dieCompare(die-1, dieNeedle) == 0)
00665 die--;
00666
00667 if ((baseName = strrchr(fileName, '/')) == NULL)
00668 goto exit;
00669 baseName++;
00670
00671
00672 for (found = 0, ret = NULL;
00673 die <= al->dirs + al->numDirs && dieCompare(die, dieNeedle) == 0;
00674 die++)
00675 {
00676
00677
00678 if (_rpmal_debug)
00679 fprintf(stderr, "==> die %p %s\n", die, (die->dirName ? die->dirName : "(nil)"));
00680
00681
00682
00683 fieNeedle->baseName = baseName;
00684
00685 fieNeedle->baseNameLen = strlen(fieNeedle->baseName);
00686 fie = bsearch(fieNeedle, die->files, die->numFiles,
00687 sizeof(*fieNeedle), fieCompare);
00688 if (fie == NULL)
00689 continue;
00690
00691
00692 if (_rpmal_debug)
00693 fprintf(stderr, "==> fie %p %s\n", fie, (fie->baseName ? fie->baseName : "(nil)"));
00694
00695
00696 alp = al->list + fie->pkgNum;
00697
00698
00699 tscolor = alp->tscolor;
00700 ficolor = fie->ficolor;
00701 if (tscolor && ficolor && !(tscolor & ficolor))
00702 continue;
00703
00704 rpmdsNotify(ds, _("(added files)"), 0);
00705
00706 ret = xrealloc(ret, (found+2) * sizeof(*ret));
00707 if (ret)
00708 ret[found] = alp->key;
00709 if (keyp)
00710 *keyp = alNum2Key(al, fie->pkgNum);
00711 found++;
00712 }
00713
00714
00715 exit:
00716 dirName = _free(dirName);
00717 if (ret)
00718 ret[found] = NULL;
00719 return ret;
00720 }
00721
00722 fnpyKey *
00723 rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00724 {
00725 availableIndex ai;
00726 availableIndexEntry needle;
00727 availableIndexEntry match;
00728 fnpyKey * ret = NULL;
00729 int found = 0;
00730 const char * KName;
00731 availablePackage alp;
00732 int rc;
00733
00734 if (keyp) *keyp = RPMAL_NOMATCH;
00735
00736 if (al == NULL || ds == NULL || (KName = rpmdsN(ds)) == NULL)
00737 return ret;
00738
00739 if (*KName == '/') {
00740
00741 ret = rpmalAllFileSatisfiesDepend(al, ds, keyp);
00742 if (ret != NULL && *ret != NULL)
00743 return ret;
00744
00745 }
00746
00747 ai = &al->index;
00748 if (ai->index == NULL || ai->size <= 0)
00749 return NULL;
00750
00751 needle = memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
00752
00753 needle->entry = KName;
00754
00755 needle->entryLen = strlen(needle->entry);
00756
00757 match = bsearch(needle, ai->index, ai->size, sizeof(*ai->index), indexcmp);
00758 if (match == NULL)
00759 return NULL;
00760
00761
00762 while (match > ai->index && indexcmp(match-1, needle) == 0)
00763 match--;
00764
00765 if (al->list != NULL)
00766 for (ret = NULL, found = 0;
00767 match < ai->index + ai->size && indexcmp(match, needle) == 0;
00768 match++)
00769 {
00770 alp = al->list + alKey2Num(al, match->pkgKey);
00771
00772 rc = 0;
00773 if (alp->provides != NULL)
00774 switch (match->type) {
00775 case IET_PROVIDES:
00776
00777 (void) rpmdsSetIx(alp->provides, match->entryIx - 1);
00778 if (rpmdsNext(alp->provides) >= 0)
00779 rc = rpmdsCompare(alp->provides, ds);
00780
00781 if (rc)
00782 rpmdsNotify(ds, _("(added provide)"), 0);
00783
00784 break;
00785 }
00786
00787
00788 if (rc) {
00789 ret = xrealloc(ret, (found + 2) * sizeof(*ret));
00790 if (ret)
00791 ret[found] = alp->key;
00792
00793 if (keyp)
00794 *keyp = match->pkgKey;
00795
00796 found++;
00797 }
00798
00799 }
00800
00801 if (ret)
00802 ret[found] = NULL;
00803
00804
00805 return ret;
00806
00807 }
00808
00809 fnpyKey
00810 rpmalSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00811 {
00812 fnpyKey * tmp = rpmalAllSatisfiesDepend(al, ds, keyp);
00813
00814 if (tmp) {
00815 fnpyKey ret = tmp[0];
00816 free(tmp);
00817 return ret;
00818 }
00819 return NULL;
00820 }