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