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
00612 for (i = 0; i < al->size; i++) {
00613 alp = al->list + i;
00614 rpmalAddProvides(al, (alKey)i, alp->provides, alp->tscolor);
00615 }
00616
00617
00618 ai->size = ai->k;
00619 qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
00620 }
00621
00622 fnpyKey *
00623 rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00624 {
00625 uint_32 tscolor;
00626 uint_32 ficolor;
00627 int found = 0;
00628 const char * dirName;
00629 const char * baseName;
00630 dirInfo dieNeedle =
00631 memset(alloca(sizeof(*dieNeedle)), 0, sizeof(*dieNeedle));
00632 dirInfo die;
00633 fileIndexEntry fieNeedle =
00634 memset(alloca(sizeof(*fieNeedle)), 0, sizeof(*fieNeedle));
00635 fileIndexEntry fie;
00636 availablePackage alp;
00637 fnpyKey * ret = NULL;
00638 const char * fileName;
00639
00640 if (keyp) *keyp = RPMAL_NOMATCH;
00641
00642 if (al == NULL || (fileName = rpmdsN(ds)) == NULL || *fileName != '/')
00643 return NULL;
00644
00645
00646 if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
00647 return NULL;
00648
00649 { char * t;
00650 dirName = t = xstrdup(fileName);
00651 if ((t = strrchr(t, '/')) != NULL) {
00652 t++;
00653 *t = '\0';
00654 }
00655 }
00656
00657 dieNeedle->dirName = (char *) dirName;
00658 dieNeedle->dirNameLen = strlen(dirName);
00659 die = bsearch(dieNeedle, al->dirs, al->numDirs,
00660 sizeof(*dieNeedle), dieCompare);
00661 if (die == NULL)
00662 goto exit;
00663
00664
00665 while (die > al->dirs && dieCompare(die-1, dieNeedle) == 0)
00666 die--;
00667
00668 if ((baseName = strrchr(fileName, '/')) == NULL)
00669 goto exit;
00670 baseName++;
00671
00672
00673 for (found = 0, ret = NULL;
00674 die <= al->dirs + al->numDirs && dieCompare(die, dieNeedle) == 0;
00675 die++)
00676 {
00677
00678
00679 if (_rpmal_debug)
00680 fprintf(stderr, "==> die %p %s\n", die, (die->dirName ? die->dirName : "(nil)"));
00681
00682
00683
00684 fieNeedle->baseName = baseName;
00685
00686 fieNeedle->baseNameLen = strlen(fieNeedle->baseName);
00687 fie = bsearch(fieNeedle, die->files, die->numFiles,
00688 sizeof(*fieNeedle), fieCompare);
00689 if (fie == NULL)
00690 continue;
00691
00692
00693 if (_rpmal_debug)
00694 fprintf(stderr, "==> fie %p %s\n", fie, (fie->baseName ? fie->baseName : "(nil)"));
00695
00696
00697 alp = al->list + fie->pkgNum;
00698
00699
00700 tscolor = alp->tscolor;
00701 ficolor = fie->ficolor;
00702 if (tscolor && ficolor && !(tscolor & ficolor))
00703 continue;
00704
00705 rpmdsNotify(ds, _("(added files)"), 0);
00706
00707 ret = xrealloc(ret, (found+2) * sizeof(*ret));
00708 if (ret)
00709 ret[found] = alp->key;
00710 if (keyp)
00711 *keyp = alNum2Key(al, fie->pkgNum);
00712 found++;
00713 }
00714
00715
00716 exit:
00717 dirName = _free(dirName);
00718 if (ret)
00719 ret[found] = NULL;
00720 return ret;
00721 }
00722
00723 fnpyKey *
00724 rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00725 {
00726 availableIndex ai;
00727 availableIndexEntry needle;
00728 availableIndexEntry match;
00729 fnpyKey * ret = NULL;
00730 int found = 0;
00731 const char * KName;
00732 availablePackage alp;
00733 int rc;
00734
00735 if (keyp) *keyp = RPMAL_NOMATCH;
00736
00737 if (al == NULL || ds == NULL || (KName = rpmdsN(ds)) == NULL)
00738 return ret;
00739
00740 if (*KName == '/') {
00741
00742 ret = rpmalAllFileSatisfiesDepend(al, ds, keyp);
00743 if (ret != NULL && *ret != NULL)
00744 return ret;
00745
00746 }
00747
00748 ai = &al->index;
00749 if (ai->index == NULL || ai->size <= 0)
00750 return NULL;
00751
00752 needle = memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
00753
00754 needle->entry = KName;
00755
00756 needle->entryLen = strlen(needle->entry);
00757
00758 match = bsearch(needle, ai->index, ai->size, sizeof(*ai->index), indexcmp);
00759 if (match == NULL)
00760 return NULL;
00761
00762
00763 while (match > ai->index && indexcmp(match-1, needle) == 0)
00764 match--;
00765
00766 if (al->list != NULL)
00767 for (ret = NULL, found = 0;
00768 match < ai->index + ai->size && indexcmp(match, needle) == 0;
00769 match++)
00770 {
00771 alp = al->list + alKey2Num(al, match->pkgKey);
00772
00773 rc = 0;
00774 if (alp->provides != NULL)
00775 switch (match->type) {
00776 case IET_PROVIDES:
00777
00778 (void) rpmdsSetIx(alp->provides, match->entryIx - 1);
00779 if (rpmdsNext(alp->provides) >= 0)
00780 rc = rpmdsCompare(alp->provides, ds);
00781
00782 if (rc)
00783 rpmdsNotify(ds, _("(added provide)"), 0);
00784
00785 break;
00786 }
00787
00788
00789 if (rc) {
00790 ret = xrealloc(ret, (found + 2) * sizeof(*ret));
00791 if (ret)
00792 ret[found] = alp->key;
00793
00794 if (keyp)
00795 *keyp = match->pkgKey;
00796
00797 found++;
00798 }
00799
00800 }
00801
00802 if (ret)
00803 ret[found] = NULL;
00804
00805
00806 return ret;
00807
00808 }
00809
00810 fnpyKey
00811 rpmalSatisfiesDepend(const rpmal al, const rpmds ds, alKey * keyp)
00812 {
00813 fnpyKey * tmp = rpmalAllSatisfiesDepend(al, ds, keyp);
00814
00815 if (tmp) {
00816 fnpyKey ret = tmp[0];
00817 free(tmp);
00818 return ret;
00819 }
00820 return NULL;
00821 }