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