diff --git a/lib/Makefile.am b/lib/Makefile.am index 9229fd1..3456db6 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -14,7 +14,7 @@ pkgincdir = $(pkgincludedir) pkginc_HEADERS = \ header.h misc.h rpmcli.h rpmlib.h stringbuf.h noinst_HEADERS = \ - cpio.h depends.h fsm.h header_internal.h \ + al.h cpio.h depends.h fsm.h header_internal.h \ manifest.h psm.h \ rpmlead.h signature.h @@ -28,7 +28,7 @@ LIBS = lib_LTLIBRARIES = librpm.la librpm_la_SOURCES = \ - closeall.c cpio.c depends.c formats.c fs.c fsm.c getdate.c \ + al.c closeall.c cpio.c depends.c formats.c fs.c fsm.c getdate.c \ header_internal.c manifest.c misc.c package.c \ problems.c poptI.c poptK.c poptQV.c psm.c query.c \ rpmchecksig.c rpminstall.c rpmlead.c rpmlibprov.c rpmrc.c \ diff --git a/lib/al.c b/lib/al.c new file mode 100644 index 0000000..a565d2b --- /dev/null +++ b/lib/al.c @@ -0,0 +1,465 @@ +#include "system.h" +#include "rpmlib.h" +#include "debug.h" + +#include "depends.h" +#include "al.h" + +struct alEntry { + const char *name; + int len; + /* entry-specific members */ +}; + +struct alIndex { + int sorted; + int size; + /* flexible array of entries */ +}; + +/** + * Compare two available index entries by name (qsort/bsearch). + * @param one 1st available prov entry + * @param two 2nd available prov entry + * @return result of comparison + */ +static inline +int nameCmp(const void * one, const void * two) /*@*/ +{ + const struct alEntry *a = one, *b = two; + int lencmp = a->len - b->len; + if (lencmp) + return lencmp; + return strcmp(a->name, b->name); +} + +static +void *axSearch(void *index, int esize, const char *name, int *nfound) +{ + if (nfound) + *nfound = 0; + + struct alIndex *ax = index; + if (ax == NULL) + return NULL; + assert(ax->size > 0); + + char *entries = (char *)(ax + 1); + struct alEntry needle = { name, strlen(name) }; + if (ax->size == 1) { + if (nameCmp(entries, &needle)) + return NULL; + if (nfound) + *nfound = 1; + return entries; + } + if (!ax->sorted) { + qsort(entries, ax->size, esize, nameCmp); + ax->sorted = 1; + } + + char *first, *last; + first = last = bsearch(&needle, entries, ax->size, esize, nameCmp); + if (first == NULL) + return NULL; + + if (nfound) { + *nfound = 1; + + /* rewind to the first match */ + while (first > entries) { + if (nameCmp(first - esize, &needle)) + break; + first -= esize; + (*nfound)++; + } + + /* rewind to the last match */ + while (last + esize < entries + esize * ax->size) { + if (nameCmp(last + esize, &needle)) + break; + last += esize; + (*nfound)++; + } + } + + return first; +} + +static +void *axGrow(void *index, int esize, int more) +{ + struct alIndex *ax = index; + if (ax) { + assert(ax->size > 0); + ax = xrealloc(ax, sizeof(*ax) + esize * (ax->size + more)); + } + else { + ax = xmalloc(sizeof(*ax) + esize * more); + ax->size = 0; + } + return ax; +} + +/** \ingroup rpmdep + * A single available item (e.g. a Provides: dependency). + */ +struct alProvEntry { +/*@dependent@*/ const char * name; /*!< Provides name. */ + int len; /*!< No. of bytes in name. */ + int pkgIx; /*!< Containing package index. */ + int provIx; /*!< Provides index in package. */ +} ; + +/** \ingroup rpmdep + * Index of all available items. + */ +struct alProvIndex { + int sorted; + int size; /*!< No. of available items. */ + struct alProvEntry prov[1]; /*!< Array of available items. */ +} ; + +static +void alIndexPkgProvides(availableList al, int pkgIx) +{ + const struct availablePackage *alp = &al->list[pkgIx]; + if (alp->providesCount == 0) + return; + + struct alProvIndex *px = al->provIndex = + axGrow(al->provIndex, sizeof(*px->prov), alp->providesCount); + + int provIx; + for (provIx = 0; provIx < alp->providesCount; provIx++) { + struct alProvEntry *pe = &px->prov[px->size++]; + pe->name = alp->provides[provIx]; + pe->len = strlen(pe->name); + pe->pkgIx = pkgIx; + pe->provIx = provIx; + } + + px->sorted = 0; +} + +static +struct alProvEntry *alSearchProv(availableList al, const char *name, int *n) +{ + return axSearch(al->provIndex, sizeof(*al->provIndex->prov), name, n); +} + +static +void alFreeProvIndex(availableList al) +{ + al->provIndex = _free(al->provIndex); +} + +/** \ingroup rpmdep + * A file to be installed/removed. + */ +struct alFileEntry { + const char *basename; /*!< File basename. */ + int len; /*!< Basename length. */ + int pkgIx; /*!< Containing package number. */ +}; + +struct alFileIndex { + int sorted; + int size; + struct alFileEntry files[1]; +}; + +/** \ingroup rpmdep + * A directory which contains some files. + */ +struct alDirEntry { + const char *dirname; /*!< Directory path (+ trailing '/'). */ + int len; /*!< No. bytes in directory path. */ + struct alFileIndex *fx; /*!< Files index this directory. */ +}; + +struct alDirIndex { + int sorted; + int size; + struct alDirEntry dirs[1]; +}; + +static +void alIndexPkgFiles(availableList al, int pkgIx) +{ + const struct availablePackage *alp = &al->list[pkgIx]; + if (alp->filesCount == 0) + return; + + const HGE_t hge = (HGE_t)headerGetEntryMinMemory; + const HFD_t hfd = headerFreeData; + const char **bn = NULL, **dn = NULL; + const int *di = NULL; + rpmTagType bnt = 0, dnt = 0, dit = 0; + int bnc = 0, dnc = 0, dic = 0; + if (!hge(alp->h, RPMTAG_BASENAMES, &bnt, (void**)&bn, &bnc)) + goto exit; + if (!hge(alp->h, RPMTAG_DIRNAMES, &dnt, (void**)&dn, &dnc)) + goto exit; + if (!hge(alp->h, RPMTAG_DIRINDEXES, &dit, (void**)&di, &dic)) + goto exit; + if (bnc != dic) + goto exit; + + /* XXX FIXME: We ought to relocate the directory list here */ + + struct alDirIndex *dx = al->dirIndex = + axGrow(al->dirIndex, sizeof(*dx->dirs), dnc); + + int i = 0; + while (i < bnc) { + /* maybe a few files under the same dir */ + int j = i; + while (j + 1 < bnc) { + if (di[i] != di[j + 1]) + break; + j++; + } + /* find or create dir entry */ + const char *d = dn[di[i]]; + struct alDirEntry *de = (dx->size == 0) ? NULL : + axSearch(dx, sizeof(*dx->dirs), d, NULL); + if (de == NULL) { + de = &dx->dirs[dx->size++]; + de->dirname = d; + de->len = strlen(d); + de->fx = NULL; + dx->sorted = 0; + } + struct alFileIndex *fx = de->fx = + axGrow(de->fx, sizeof(*fx->files), j - i + 1); + while (i <= j) { + /* add file entries */ + const char *b = bn[i++]; + struct alFileEntry *fe = &fx->files[fx->size++]; + fe->basename = b; + fe->len = strlen(b); + fe->pkgIx = pkgIx; + } + fx->sorted = 0; + } + +exit: + /* XXX strings point to header memory */ + bn = hfd(bn, bnt); + dn = hfd(dn, dnt); + di = hfd(di, dit); +} + +static +struct alFileEntry *alSearchFile(availableList al, const char *fname, int *n) +{ + /* need to preserve trailing slahs in d */ + const char *b = strrchr(fname, '/') + 1; + int dlen = b - fname; + char *d = alloca(dlen + 1); + memcpy(d, fname, dlen); + d[dlen] = '\0'; + + struct alDirEntry *de = axSearch(al->dirIndex, sizeof(*de), d, NULL); + if (de == NULL) { + *n = 0; + return NULL; + } + assert(de->fx); + return axSearch(de->fx, sizeof(*de->fx->files), b, n); +} + +static +void alFreeDirIndex(availableList al) +{ + struct alDirIndex *dx = al->dirIndex; + if (dx) { + int i; + for (i = 0; i < dx->size; i++) { + struct alDirEntry *de = &dx->dirs[i]; + de->fx = _free(de->fx); + } + al->dirIndex = _free(al->dirIndex); + } +} + +struct availablePackage ** +alAllSatisfiesDepend(const availableList al, + const char * keyName, const char * keyEVR, int keyFlags) +{ + struct availablePackage ** ret = NULL; + int found = 0; + int i, n; + + if (*keyName == '/' && (keyFlags & RPMSENSE_SENSEMASK) == 0) { + const struct alFileEntry *fe = alSearchFile(al, keyName, &n); + for (i = 0; fe && i < n; i++, fe++) { + struct availablePackage *alp = &al->list[fe->pkgIx]; + int j, already = 0; + for (j = 0; j < found; j++) + if (ret[j] == alp) { + already = 1; + break; + } + if (already) + continue; + ret = xrealloc(ret, (found + 2) * sizeof(*ret)); + ret[found++] = alp; + } + } + + const struct alProvEntry *pe = alSearchProv(al, keyName, &n); + for (i = 0; pe && i < n; i++, pe++) { + struct availablePackage *alp = &al->list[pe->pkgIx]; + int j, already = 0; + for (j = 0; j < found; j++) + if (ret[j] == alp) { + already = 1; + break; + } + if (already) + continue; + if ((keyFlags & RPMSENSE_SENSEMASK)) { + const char *provName = pe->name; + const char *provEVR = alp->providesEVR ? + alp->providesEVR[pe->provIx] : NULL; + int provFlags = alp->provideFlags ? + alp->provideFlags[pe->provIx] : 0; + if (!(provFlags & RPMSENSE_SENSEMASK)) + provFlags |= RPMSENSE_EQUAL; /* ALT21-139-g6cb9a9a */ + int rc = rpmRangesOverlap(provName, provEVR, provFlags, + keyName, keyEVR, keyFlags); + if (rc == 0) + continue; + } + ret = xrealloc(ret, (found + 2) * sizeof(*ret)); + ret[found++] = alp; + } + + if (ret) + ret[found] = NULL; + return ret; +} + +struct availablePackage * +alAddPackage(availableList al, + Header h, /*@null@*/ /*@dependent@*/ const void * key, + /*@null@*/ FD_t fd, /*@null@*/ rpmRelocation * relocs) +{ + HGE_t hge = (HGE_t)headerGetEntryMinMemory; + struct availablePackage * p; + rpmRelocation * r; + int i; + int pkgNum; + + AUTO_REALLOC(al->list, al->size); + pkgNum = al->size++; + p = al->list + pkgNum; + p->h = headerLink(h); /* XXX reference held by transaction set */ + p->depth = p->npreds = 0; + memset(&p->tsi, 0, sizeof(p->tsi)); + + (void) headerNVR(p->h, &p->name, &p->version, &p->release); + + if (!hge(h, RPMTAG_EPOCH, NULL, (void **) &p->epoch, NULL)) + p->epoch = NULL; + + if (!hge(h, RPMTAG_BUILDTIME, NULL, (void **) &p->buildtime, NULL)) + p->buildtime = NULL; + + if (!hge(h, RPMTAG_PROVIDENAME, NULL, (void **) &p->provides, + &p->providesCount)) { + p->providesCount = 0; + p->provides = NULL; + p->providesEVR = NULL; + p->provideFlags = NULL; + } else { + if (!hge(h, RPMTAG_PROVIDEVERSION, + NULL, (void **) &p->providesEVR, NULL)) + p->providesEVR = NULL; + if (!hge(h, RPMTAG_PROVIDEFLAGS, + NULL, (void **) &p->provideFlags, NULL)) + p->provideFlags = NULL; + } + + if (!hge(h, RPMTAG_REQUIRENAME, NULL, (void **) &p->requires, + &p->requiresCount)) { + p->requiresCount = 0; + p->requires = NULL; + p->requiresEVR = NULL; + p->requireFlags = NULL; + } else { + if (!hge(h, RPMTAG_REQUIREVERSION, + NULL, (void **) &p->requiresEVR, NULL)) + p->requiresEVR = NULL; + if (!hge(h, RPMTAG_REQUIREFLAGS, + NULL, (void **) &p->requireFlags, NULL)) + p->requireFlags = NULL; + } + + if (!hge(h, RPMTAG_BASENAMES, NULL, NULL, &p->filesCount)) + p->filesCount = 0; + + p->key = key; + p->fd = (fd != NULL ? fdLink(fd, "alAddPackage") : NULL); + + if (relocs) { + for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) + {}; + p->relocs = xmalloc((i + 1) * sizeof(*p->relocs)); + + for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) { + p->relocs[i].oldPath = r->oldPath ? xstrdup(r->oldPath) : NULL; + p->relocs[i].newPath = r->newPath ? xstrdup(r->newPath) : NULL; + } + p->relocs[i].oldPath = NULL; + p->relocs[i].newPath = NULL; + } else { + p->relocs = NULL; + } + + alIndexPkgProvides(al, pkgNum); + alIndexPkgFiles(al, pkgNum); + return p; +} + +void alFree(availableList al) +{ + HFD_t hfd = headerFreeData; + struct availablePackage * p; + rpmRelocation * r; + int i; + + if ((p = al->list) != NULL) + for (i = 0; i < al->size; i++, p++) { + + { tsortInfo tsi; + while ((tsi = p->tsi.tsi_next) != NULL) { + p->tsi.tsi_next = tsi->tsi_next; + tsi->tsi_next = NULL; + tsi = _free(tsi); + } + } + + p->provides = hfd(p->provides, -1); + p->providesEVR = hfd(p->providesEVR, -1); + p->requires = hfd(p->requires, -1); + p->requiresEVR = hfd(p->requiresEVR, -1); + p->h = headerFree(p->h); + + if (p->relocs) { + for (r = p->relocs; (r->oldPath || r->newPath); r++) { + r->oldPath = _free(r->oldPath); + r->newPath = _free(r->newPath); + } + p->relocs = _free(p->relocs); + } + if (p->fd != NULL) + p->fd = fdFree(p->fd, "alAddPackage (alFree)"); + } + + al->list = _free(al->list); + alFreeProvIndex(al); + alFreeDirIndex(al); +} diff --git a/lib/al.h b/lib/al.h new file mode 100644 index 0000000..cabd7ef --- /dev/null +++ b/lib/al.h @@ -0,0 +1,79 @@ +#ifndef RPM_AL_H +#define RPM_AL_H + +/** + * Initialize available packckages, items, and directories list. + * @param al available list + */ +static inline +void alCreate(availableList al) + /*@modifies al @*/ +{ + al->list = NULL; + al->size = 0; + al->dirIndex = NULL; + al->provIndex = NULL; +} + +/** + * Free available packages, items, and directories members. + * @param al available list + */ +void alFree(availableList al) + /*@modifies al @*/; + +/** + * Add package to available list. + * @param al available list + * @param h package header + * @param key package private data + * @param fd package file handle + * @param relocs package file relocations + * @return available package pointer + */ +/*@exposed@*/ struct availablePackage * +alAddPackage(availableList al, + Header h, /*@null@*/ /*@dependent@*/ const void * key, + /*@null@*/ FD_t fd, /*@null@*/ rpmRelocation * relocs) + /*@modifies al, h @*/; + +/** + * Check added package file lists for package(s) that have a provide. + * @param al available list + * @param keyName dependency name string + * @param keyEVR dependency [epoch:]version[-release] string + * @param keyFlags dependency logical range qualifiers + * @return available package pointer + */ +/*@only@*/ /*@null@*/ struct availablePackage ** +alAllSatisfiesDepend(const availableList al, + const char * keyName, const char * keyEVR, int keyFlags) + /*@*/; + +/** + * Check added package file lists for first package that has a provide. + * @todo Eliminate. + * @param al available list + * @param keyName dependency name string + * @param keyEVR dependency [epoch:]version[-release] string + * @param keyFlags dependency logical range qualifiers + * @return available package pointer + */ +static inline /*@only@*/ /*@null@*/ struct availablePackage * +alSatisfiesDepend(const availableList al, + const char * keyName, const char * keyEVR, int keyFlags) + /*@*/ +{ + struct availablePackage * ret; + struct availablePackage ** tmp = + alAllSatisfiesDepend(al, keyName, keyEVR, keyFlags); + + if (tmp) { + ret = tmp[0]; + tmp = _free(tmp); + return ret; + } + return NULL; +} + +#endif diff --git a/lib/depends.c b/lib/depends.c index 63b0f5d..66427ac 100644 --- a/lib/depends.c +++ b/lib/depends.c @@ -8,6 +8,7 @@ #include "rpmmacro.h" /* XXX for rpmExpand() */ #include "depends.h" +#include "al.h" #include "rpmdb.h" /* XXX response cache needs dbiOpen et al. */ #include "debug.h" @@ -97,331 +98,6 @@ struct orderListIndex { int orIndex; }; -/** - * Destroy available item index. - * @param al available list - */ -static void alFreeIndex(availableList al) - /*@modifies al @*/ -{ - if (al->index.size) { - al->index.index = _free(al->index.index); - al->index.size = 0; - } -} - -/** - * Initialize available packckages, items, and directories list. - * @param al available list - */ -static void alCreate(availableList al) - /*@modifies al @*/ -{ - al->alloced = al->delta; - al->size = 0; - al->list = xcalloc(al->alloced, sizeof(*al->list)); - - al->index.index = NULL; - al->index.size = 0; - - al->numDirs = 0; - al->dirs = NULL; -} - -/** - * Free available packages, items, and directories members. - * @param al available list - */ -static void alFree(availableList al) - /*@modifies al @*/ -{ - HFD_t hfd = headerFreeData; - struct availablePackage * p; - rpmRelocation * r; - int i; - - if ((p = al->list) != NULL) - for (i = 0; i < al->size; i++, p++) { - - { tsortInfo tsi; - while ((tsi = p->tsi.tsi_next) != NULL) { - p->tsi.tsi_next = tsi->tsi_next; - tsi->tsi_next = NULL; - tsi = _free(tsi); - } - } - - p->provides = hfd(p->provides, -1); - p->providesEVR = hfd(p->providesEVR, -1); - p->requires = hfd(p->requires, -1); - p->requiresEVR = hfd(p->requiresEVR, -1); - p->baseNames = hfd(p->baseNames, -1); - p->h = headerFree(p->h); - - if (p->relocs) { - for (r = p->relocs; (r->oldPath || r->newPath); r++) { - r->oldPath = _free(r->oldPath); - r->newPath = _free(r->newPath); - } - p->relocs = _free(p->relocs); - } - if (p->fd != NULL) - p->fd = fdFree(p->fd, "alAddPackage (alFree)"); - } - - if (al->dirs != NULL) - for (i = 0; i < al->numDirs; i++) { - al->dirs[i].dirName = _free(al->dirs[i].dirName); - al->dirs[i].files = _free(al->dirs[i].files); - } - - al->dirs = _free(al->dirs); - al->numDirs = 0; - al->list = _free(al->list); - al->alloced = 0; - alFreeIndex(al); -} - -/** - * Compare two directory info entries by name (qsort/bsearch). - * @param one 1st directory info - * @param two 2nd directory info - * @return result of comparison - */ -static int dirInfoCompare(const void * one, const void * two) /*@*/ -{ - const dirInfo a = (const dirInfo) one; - const dirInfo b = (const dirInfo) two; - int lenchk = a->dirNameLen - b->dirNameLen; - - if (lenchk) - return lenchk; - - /* XXX FIXME: this might do "backward" strcmp for speed */ - return strcmp(a->dirName, b->dirName); -} - -/** - * Add package to available list. - * @param al available list - * @param h package header - * @param key package private data - * @param fd package file handle - * @param relocs package file relocations - * @return available package pointer - */ -static /*@exposed@*/ struct availablePackage * -alAddPackage(availableList al, - Header h, /*@null@*/ /*@dependent@*/ const void * key, - /*@null@*/ FD_t fd, /*@null@*/ rpmRelocation * relocs) - /*@modifies al, h @*/ -{ - HGE_t hge = (HGE_t)headerGetEntryMinMemory; - HFD_t hfd = headerFreeData; - rpmTagType dnt, bnt; - struct availablePackage * p; - rpmRelocation * r; - int i; - int_32 * dirIndexes; - const char ** dirNames; - int numDirs, dirNum; - int * dirMapping; - struct dirInfo_s dirNeedle; - dirInfo dirMatch; - int first, last, fileNum; - int origNumDirs; - int pkgNum; - - if (al->size == al->alloced) { - al->alloced += al->delta; - al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced); - } - - pkgNum = al->size++; - p = al->list + pkgNum; - p->h = headerLink(h); /* XXX reference held by transaction set */ - p->depth = p->npreds = 0; - memset(&p->tsi, 0, sizeof(p->tsi)); - - (void) headerNVR(p->h, &p->name, &p->version, &p->release); - - if (!hge(h, RPMTAG_EPOCH, NULL, (void **) &p->epoch, NULL)) - p->epoch = NULL; - - if (!hge(h, RPMTAG_BUILDTIME, NULL, (void **) &p->buildtime, NULL)) - p->buildtime = NULL; - - if (!hge(h, RPMTAG_PROVIDENAME, NULL, (void **) &p->provides, - &p->providesCount)) { - p->providesCount = 0; - p->provides = NULL; - p->providesEVR = NULL; - p->provideFlags = NULL; - } else { - if (!hge(h, RPMTAG_PROVIDEVERSION, - NULL, (void **) &p->providesEVR, NULL)) - p->providesEVR = NULL; - if (!hge(h, RPMTAG_PROVIDEFLAGS, - NULL, (void **) &p->provideFlags, NULL)) - p->provideFlags = NULL; - } - - if (!hge(h, RPMTAG_REQUIRENAME, NULL, (void **) &p->requires, - &p->requiresCount)) { - p->requiresCount = 0; - p->requires = NULL; - p->requiresEVR = NULL; - p->requireFlags = NULL; - } else { - if (!hge(h, RPMTAG_REQUIREVERSION, - NULL, (void **) &p->requiresEVR, NULL)) - p->requiresEVR = NULL; - if (!hge(h, RPMTAG_REQUIREFLAGS, - NULL, (void **) &p->requireFlags, NULL)) - p->requireFlags = NULL; - } - - if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **)&p->baseNames, &p->filesCount)) - { - p->filesCount = 0; - p->baseNames = NULL; - } else { - (void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, &numDirs); - (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL); - - /* XXX FIXME: We ought to relocate the directory list here */ - - dirMapping = alloca(sizeof(*dirMapping) * numDirs); - - /* allocated enough space for all the directories we could possible - need to add */ - al->dirs = xrealloc(al->dirs, - sizeof(*al->dirs) * (al->numDirs + numDirs)); - origNumDirs = al->numDirs; - - for (dirNum = 0; dirNum < numDirs; dirNum++) { - dirNeedle.dirName = (char *) dirNames[dirNum]; - dirNeedle.dirNameLen = strlen(dirNames[dirNum]); - dirMatch = bsearch(&dirNeedle, al->dirs, origNumDirs, - sizeof(dirNeedle), dirInfoCompare); - if (dirMatch) { - dirMapping[dirNum] = dirMatch - al->dirs; - } else { - dirMapping[dirNum] = al->numDirs; - al->dirs[al->numDirs].dirName = xstrdup(dirNames[dirNum]); - al->dirs[al->numDirs].dirNameLen = strlen(dirNames[dirNum]); - al->dirs[al->numDirs].files = NULL; - al->dirs[al->numDirs].numFiles = 0; - al->numDirs++; - } - } - - dirNames = hfd(dirNames, dnt); - - first = 0; - while (first < p->filesCount) { - last = first; - while ((last + 1) < p->filesCount) { - if (dirIndexes[first] != dirIndexes[last + 1]) - /*@innerbreak@*/ break; - last++; - } - - dirMatch = al->dirs + dirMapping[dirIndexes[first]]; - dirMatch->files = xrealloc(dirMatch->files, - sizeof(*dirMatch->files) * - (dirMatch->numFiles + last - first + 1)); - if (p->baseNames != NULL) /* XXX can't happen */ - for (fileNum = first; fileNum <= last; fileNum++) { - dirMatch->files[dirMatch->numFiles].baseName = - p->baseNames[fileNum]; - dirMatch->files[dirMatch->numFiles].pkgNum = pkgNum; - dirMatch->numFiles++; - } - - first = last + 1; - } - - if (origNumDirs + al->numDirs) - qsort(al->dirs, al->numDirs, sizeof(dirNeedle), dirInfoCompare); - - } - - p->key = key; - p->fd = (fd != NULL ? fdLink(fd, "alAddPackage") : NULL); - - if (relocs) { - for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) - {}; - p->relocs = xmalloc((i + 1) * sizeof(*p->relocs)); - - for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) { - p->relocs[i].oldPath = r->oldPath ? xstrdup(r->oldPath) : NULL; - p->relocs[i].newPath = r->newPath ? xstrdup(r->newPath) : NULL; - } - p->relocs[i].oldPath = NULL; - p->relocs[i].newPath = NULL; - } else { - p->relocs = NULL; - } - - alFreeIndex(al); - - return p; -} - -/** - * Compare two available index entries by name (qsort/bsearch). - * @param one 1st available index entry - * @param two 2nd available index entry - * @return result of comparison - */ -static int indexcmp(const void * one, const void * two) /*@*/ -{ - const struct availableIndexEntry * a = one; - const struct availableIndexEntry * b = two; - int lenchk = a->entryLen - b->entryLen; - - if (lenchk) - return lenchk; - - return strcmp(a->entry, b->entry); -} - -/** - * Generate index for available list. - * @param al available list - */ -static void alMakeIndex(availableList al) - /*@modifies al @*/ -{ - struct availableIndex * ai = &al->index; - int i, j, k; - - if (ai->size || al->list == NULL) return; - - for (i = 0; i < al->size; i++) - ai->size += al->list[i].providesCount; - - if (ai->size) { - ai->index = xcalloc(ai->size, sizeof(*ai->index)); - - k = 0; - for (i = 0; i < al->size; i++) { - for (j = 0; j < al->list[i].providesCount; j++) { - ai->index[k].package = al->list + i; - ai->index[k].entry = al->list[i].provides[j]; - ai->index[k].entryLen = strlen(al->list[i].provides[j]); - ai->index[k].entryIx = j; - ai->index[k].type = IET_PROVIDES; - k++; - } - } - - qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp); - } -} - /* parseEVR() moved to rpmvercmp.c */ const char *rpmNAME = PACKAGE; @@ -536,7 +212,7 @@ static int rangeMatchesDepFlags (Header h, continue; if (!(provideFlags[i] & RPMSENSE_SENSEMASK)) - provideFlags[i] |= RPMSENSE_EQUAL; + provideFlags[i] |= RPMSENSE_EQUAL; /* ALT21-139-g6cb9a9a */ result = rpmRangesOverlap(provides[i], providesEVR[i], provideFlags[i], reqName, reqEVR, reqFlags); @@ -595,12 +271,9 @@ rpmTransactionSet rpmtransCreateSet(rpmdb rpmdb, const char * rootDir) /*@=assignexpose@*/ ts->scriptFd = NULL; ts->id = 0; - ts->delta = 5; ts->numRemovedPackages = 0; - ts->allocedRemovedPackages = ts->delta; - ts->removedPackages = xcalloc(ts->allocedRemovedPackages, - sizeof(*ts->removedPackages)); + ts->removedPackages = NULL; /* This canonicalizes the root */ rootLen = strlen(rootDir); @@ -617,12 +290,10 @@ rpmTransactionSet rpmtransCreateSet(rpmdb rpmdb, const char * rootDir) ts->currDir = NULL; ts->chrootDone = 0; - ts->addedPackages.delta = ts->delta; alCreate(&ts->addedPackages); - ts->orderAlloced = ts->delta; ts->orderCount = 0; - ts->order = xcalloc(ts->orderAlloced, sizeof(*ts->order)); + ts->order = NULL; return ts; } @@ -659,22 +330,11 @@ static int removePackage(rpmTransactionSet ts, int dboffset, int depends) return 0; } - if (ts->numRemovedPackages == ts->allocedRemovedPackages) { - ts->allocedRemovedPackages += ts->delta; - ts->removedPackages = xrealloc(ts->removedPackages, - sizeof(int *) * ts->allocedRemovedPackages); - } - - if (ts->removedPackages != NULL) { /* XXX can't happen. */ - ts->removedPackages[ts->numRemovedPackages++] = dboffset; - qsort(ts->removedPackages, ts->numRemovedPackages, sizeof(int), intcmp); - } - - if (ts->orderCount == ts->orderAlloced) { - ts->orderAlloced += ts->delta; - ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced); - } + AUTO_REALLOC(ts->removedPackages, ts->numRemovedPackages); + ts->removedPackages[ts->numRemovedPackages++] = dboffset; + qsort(ts->removedPackages, ts->numRemovedPackages, sizeof(int), intcmp); + AUTO_REALLOC(ts->order, ts->orderCount); ts->order[ts->orderCount].type = TR_REMOVED; ts->order[ts->orderCount].u.removed.dboffset = dboffset; ts->order[ts->orderCount++].u.removed.dependsOnIndex = depends; @@ -710,7 +370,6 @@ int rpmtransAddPackage(rpmTransactionSet ts, Header h, FD_t fd, const char * name; int count; const char ** obsoletes; - int alNum; /* * FIXME: handling upgrades like this is *almost* okay. It doesn't @@ -718,16 +377,11 @@ int rpmtransAddPackage(rpmTransactionSet ts, Header h, FD_t fd, * makes it difficult to generate a return code based on the number of * packages which failed. */ - if (ts->orderCount == ts->orderAlloced) { - ts->orderAlloced += ts->delta; - ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced); - } + struct availablePackage *alp = + alAddPackage(&ts->addedPackages, h, key, fd, relocs); + int alNum = alp - ts->addedPackages.list; + AUTO_REALLOC(ts->order, ts->orderCount); ts->order[ts->orderCount].type = TR_ADDED; - if (ts->addedPackages.list == NULL) - return 0; - - alNum = alAddPackage(&ts->addedPackages, h, key, fd, relocs) - - ts->addedPackages.list; ts->order[ts->orderCount++].u.addedIndex = alNum; if (!upgrade || ts->rpmdb == NULL) @@ -838,221 +492,6 @@ rpmDependencyConflict rpmdepFreeConflicts(rpmDependencyConflict conflicts, return (conflicts = _free(conflicts)); } -/** - * Check added package file lists for package(s) that provide a file. - * @param al available list - * @param keyType type of dependency - * @param fileName file name to search for - * @return available package pointer - */ -static /*@only@*/ /*@null@*/ struct availablePackage ** -alAllFileSatisfiesDepend(const availableList al, - const char * keyType, const char * fileName) - /*@*/ -{ - int i, found; - const char * dirName; - const char * baseName; - struct dirInfo_s dirNeedle; - dirInfo dirMatch; - struct availablePackage ** ret; - - /* Solaris 2.6 bsearch sucks down on this. */ - if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL) - return NULL; - - { char * t; - dirName = t = xstrdup(fileName); - if ((t = strrchr(t, '/')) != NULL) { - t++; /* leave the trailing '/' */ - *t = '\0'; - } - } - - dirNeedle.dirName = (char *) dirName; - dirNeedle.dirNameLen = strlen(dirName); - dirMatch = bsearch(&dirNeedle, al->dirs, al->numDirs, - sizeof(dirNeedle), dirInfoCompare); - if (dirMatch == NULL) { - dirName = _free(dirName); - return NULL; - } - - /* rewind to the first match */ - while (dirMatch > al->dirs && dirInfoCompare(dirMatch-1, &dirNeedle) == 0) - dirMatch--; - - /*@-nullptrarith@*/ /* FIX: fileName NULL ??? */ - baseName = strrchr(fileName, '/') + 1; - /*@=nullptrarith@*/ - - for (found = 0, ret = NULL; - dirMatch <= al->dirs + al->numDirs && - dirInfoCompare(dirMatch, &dirNeedle) == 0; - dirMatch++) - { - /* XXX FIXME: these file lists should be sorted and bsearched */ - for (i = 0; i < dirMatch->numFiles; i++) { - if (dirMatch->files[i].baseName == NULL || - strcmp(dirMatch->files[i].baseName, baseName)) - continue; - - if (keyType) - rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added files)\n"), - keyType, fileName); - - ret = xrealloc(ret, (found+2) * sizeof(*ret)); - if (ret) /* can't happen */ - ret[found++] = al->list + dirMatch->files[i].pkgNum; - /*@innerbreak@*/ break; - } - } - - dirName = _free(dirName); - /*@-mods@*/ /* FIX: al->list might be modified. */ - if (ret) - ret[found] = NULL; - /*@=mods@*/ - return ret; -} - -#ifdef DYING -/** - * Check added package file lists for first package that provides a file. - * @param al available list - * @param keyType type of dependency - * @param fileName file name to search for - * @return available package pointer - */ -/*@unused@*/ static /*@dependent@*/ /*@null@*/ struct availablePackage * -alFileSatisfiesDepend(const availableList al, - const char * keyType, const char * fileName) - /*@*/ -{ - struct availablePackage * ret; - struct availablePackage ** tmp = - alAllFileSatisfiesDepend(al, keyType, fileName); - - if (tmp) { - ret = tmp[0]; - tmp = _free(tmp); - return ret; - } - return NULL; -} -#endif /* DYING */ - -/** - * Check added package file lists for package(s) that have a provide. - * @param al available list - * @param keyType type of dependency - * @param keyDepend dependency string representation - * @param keyName dependency name string - * @param keyEVR dependency [epoch:]version[-release] string - * @param keyFlags dependency logical range qualifiers - * @return available package pointer - */ -static /*@only@*/ /*@null@*/ struct availablePackage ** -alAllSatisfiesDepend(const availableList al, - const char * keyType, const char * keyDepend, - const char * keyName, const char * keyEVR, int keyFlags) - /*@*/ -{ - struct availableIndexEntry needle, * match; - struct availablePackage * p, ** ret = NULL; - int i, rc, found; - - if (*keyName == '/') { - ret = alAllFileSatisfiesDepend(al, keyType, keyName); - /* XXX Provides: /path was broken with added packages (#52183). */ - if (ret != NULL && *ret != NULL) - return ret; - } - - if (!al->index.size || al->index.index == NULL) return NULL; - - needle.entry = keyName; - needle.entryLen = strlen(keyName); - match = bsearch(&needle, al->index.index, al->index.size, - sizeof(*al->index.index), indexcmp); - - if (match == NULL) return NULL; - - /* rewind to the first match */ - while (match > al->index.index && indexcmp(match-1, &needle) == 0) - match--; - - for (ret = NULL, found = 0; - match < al->index.index + al->index.size && - indexcmp(match, &needle) == 0; - match++) - { - - p = match->package; - rc = 0; - switch (match->type) { - case IET_PROVIDES: - i = match->entryIx; - { const char * proEVR; - int proFlags; - - proEVR = (p->providesEVR ? p->providesEVR[i] : NULL); - proFlags = (p->provideFlags ? p->provideFlags[i] : 0); - if ((keyFlags & RPMSENSE_SENSEMASK) && !(proFlags & RPMSENSE_SENSEMASK)) - proFlags |= RPMSENSE_EQUAL; - rc = rpmRangesOverlap(p->provides[i], proEVR, proFlags, - keyName, keyEVR, keyFlags); - if (rc) - /*@switchbreak@*/ break; - } - if (keyType && keyDepend && rc) - rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added provide)\n"), - keyType, keyDepend+2); - break; - } - - if (rc) { - ret = xrealloc(ret, (found + 2) * sizeof(*ret)); - if (ret) /* can't happen */ - ret[found++] = p; - } - } - - if (ret) - ret[found] = NULL; - - return ret; -} - -/** - * Check added package file lists for first package that has a provide. - * @todo Eliminate. - * @param al available list - * @param keyType type of dependency - * @param keyDepend dependency string representation - * @param keyName dependency name string - * @param keyEVR dependency [epoch:]version[-release] string - * @param keyFlags dependency logical range qualifiers - * @return available package pointer - */ -static inline /*@only@*/ /*@null@*/ struct availablePackage * -alSatisfiesDepend(const availableList al, - const char * keyType, const char * keyDepend, - const char * keyName, const char * keyEVR, int keyFlags) - /*@*/ -{ - struct availablePackage * ret; - struct availablePackage ** tmp = - alAllSatisfiesDepend(al, keyType, keyDepend, keyName, keyEVR, keyFlags); - - if (tmp) { - ret = tmp[0]; - tmp = _free(tmp); - return ret; - } - return NULL; -} - /** * Check key for an unsatisfied dependency. * @todo Eliminate rpmrc provides. @@ -1142,9 +581,11 @@ static int unsatisfiedDepend(rpmTransactionSet ts, goto unsatisfied; } - if (alSatisfiesDepend(&ts->addedPackages, keyType, keyDepend, - keyName, keyEVR, keyFlags)) + if (alSatisfiesDepend(&ts->addedPackages, keyName, keyEVR, keyFlags)) { + /* XXX here we do not discern between files and provides */ + rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added provide)\n"), + keyType, keyDepend+2); goto exit; } @@ -1286,11 +727,7 @@ static int checkPackageDeps(rpmTransactionSet ts, problemsSet psp, rpmMessage(RPMMESS_DEBUG, _("package %s-%s-%s require not satisfied: %s\n"), name, version, release, keyDepend+2); - if (psp->num == psp->alloced) { - psp->alloced += 5; - psp->problems = xrealloc(psp->problems, sizeof(*psp->problems) * - psp->alloced); - } + AUTO_REALLOC(psp->problems, psp->num); { rpmDependencyConflict pp = psp->problems + psp->num; pp->byHeader = headerLink(h); @@ -1347,11 +784,7 @@ static int checkPackageDeps(rpmTransactionSet ts, problemsSet psp, rpmMessage(RPMMESS_DEBUG, _("package %s conflicts: %s\n"), name, keyDepend+2); - if (psp->num == psp->alloced) { - psp->alloced += 5; - psp->problems = xrealloc(psp->problems, - sizeof(*psp->problems) * psp->alloced); - } + AUTO_REALLOC(psp->problems, psp->num); { rpmDependencyConflict pp = psp->problems + psp->num; pp->byHeader = headerLink(h); @@ -1667,7 +1100,7 @@ static inline int addRelation( const rpmTransactionSet ts, if (!p->requires || !p->requiresEVR || !p->requireFlags) return 0; - q = alSatisfiesDepend(&ts->addedPackages, NULL, NULL, + q = alSatisfiesDepend(&ts->addedPackages, p->requires[j], p->requiresEVR[j], p->requireFlags[j]); /* Ordering depends only on added package relations. */ @@ -1774,8 +1207,6 @@ int rpmdepOrder(rpmTransactionSet ts) int qlen; int i, j; - alMakeIndex(&ts->addedPackages); - /* T1. Initialize. */ loopcheck = npkgs; @@ -2050,7 +1481,6 @@ rescan: ts->order = _free(ts->order); ts->order = newOrder; - ts->orderAlloced = ts->orderCount; orderList = _free(orderList); return 0; @@ -2103,15 +1533,12 @@ int rpmdepCheck(rpmTransactionSet ts, npkgs = ts->addedPackages.size; ps = xcalloc(1, sizeof(*ps)); - ps->alloced = 5; ps->num = 0; - ps->problems = xcalloc(ps->alloced, sizeof(*ps->problems)); + ps->problems = NULL; *conflicts = NULL; *numConflicts = 0; - alMakeIndex(&ts->addedPackages); - /* * Look at all of the added packages and make sure their dependencies * are satisfied. diff --git a/lib/depends.h b/lib/depends.h index f5c78b2..3a2b450 100644 --- a/lib/depends.h +++ b/lib/depends.h @@ -43,7 +43,6 @@ struct availablePackage { /*@owned@*//*@null@*/ const char ** requires; /*!< Requires: name strings. */ /*@owned@*//*@null@*/ const char ** requiresEVR;/*!< Requires: [epoch:]version[-release] strings. */ /*@dependent@*//*@null@*/ int * requireFlags; /*!< Requires: logical range qualifiers. */ -/*@owned@*//*@null@*/ const char ** baseNames; /*!< Header file basenames. */ /*@dependent@*//*@null@*/ int_32 * epoch; /*!< Header epoch (if any). */ int providesCount; /*!< No. of Provide:'s in header. */ int requiresCount; /*!< No. of Require:'s in header. */ @@ -63,56 +62,14 @@ struct availablePackage { int_32 * buildtime; } ; -/** \ingroup rpmdep - * A single available item (e.g. a Provides: dependency). - */ -struct availableIndexEntry { -/*@dependent@*/ struct availablePackage * package; /*!< Containing package. */ -/*@dependent@*/ const char * entry; /*!< Available item name. */ - int entryLen; /*!< No. of bytes in name. */ - int entryIx; /*!< Item index. */ - enum indexEntryType { - IET_PROVIDES=1 /*!< A Provides: dependency. */ - } type; /*!< Type of available item. */ -} ; - -/** \ingroup rpmdep - * Index of all available items. - */ -struct availableIndex { -/*@null@*/ struct availableIndexEntry * index; /*!< Array of available items. */ - int size; /*!< No. of available items. */ -} ; - -/** \ingroup rpmdep - * A file to be installed/removed. - */ -struct fileIndexEntry { - int pkgNum; /*!< Containing package number. */ -/*@dependent@*/ /*@null@*/ const char * baseName; /*!< File basename. */ -} ; - -/** \ingroup rpmdep - * A directory to be installed/removed. - */ -typedef struct dirInfo_s { -/*@owned@*/ const char * dirName; /*!< Directory path (+ trailing '/'). */ - int dirNameLen; /*!< No. bytes in directory path. */ -/*@owned@*/ struct fileIndexEntry * files; /*!< Array of files in directory. */ - int numFiles; /*!< No. files in directory. */ -} * dirInfo ; - /** \ingroup rpmdep * Set of available packages, items, and directories. */ typedef /*@abstract@*/ struct availableList_s { /*@owned@*/ /*@null@*/ struct availablePackage * list; /*!< Set of packages. */ - struct availableIndex index; /*!< Set of available items. */ - int delta; /*!< Delta for pkg list reallocation. */ int size; /*!< No. of pkgs in list. */ - int alloced; /*!< No. of pkgs allocated for list. */ - int numDirs; /*!< No. of directories. */ -/*@owned@*/ /*@null@*/ dirInfo dirs; /*!< Set of directories. */ + struct alDirIndex *dirIndex; /*!< Files index. */ + struct alProvIndex *provIndex; /*!< Provides index. */ } * availableList; /** \ingroup rpmdep @@ -148,20 +105,17 @@ struct rpmTransactionSet_s { /*@kept@*/ /*@null@*/ rpmdb rpmdb; /*!< Database handle. */ /*@only@*/ int * removedPackages; /*!< Set of packages being removed. */ int numRemovedPackages; /*!< No. removed rpmdb instances. */ - int allocedRemovedPackages; /*!< Size of removed packages array. */ struct availableList_s addedPackages; /*!< Set of packages being installed. */ /*@only@*/ transactionElement order; /*!< Packages sorted by dependencies. */ int orderCount; /*!< No. of transaction elements. */ - int orderAlloced; /*!< No. of allocated transaction elements. */ /*@only@*/ TFI_t flList; /*!< Transaction element(s) file info. */ int flEntries; /*!< No. of transaction elements. */ int chrootDone; /*!< Has chroot(2) been been done? */ /*@only@*/ const char * rootDir;/*!< Path to top of install tree. */ /*@only@*/ const char * currDir;/*!< Current working directory. */ /*@null@*/ FD_t scriptFd; /*!< Scriptlet stdout/stderr. */ - int delta; /*!< Delta for reallocation. */ int id; /*!< Transaction id. */ } ; @@ -171,7 +125,6 @@ struct rpmTransactionSet_s { typedef /*@abstract@*/ struct problemsSet_s { rpmDependencyConflict problems; /*!< Problems encountered. */ int num; /*!< No. of problems found. */ - int alloced; /*!< No. of problems allocated. */ } * problemsSet; #ifdef __cplusplus @@ -196,4 +149,11 @@ int headerMatchesDepFlags(Header h, } #endif +#define REALLOC_DELTA 8 +#define AUTO_REALLOC(ptr, size) \ + do { \ + if (((size) & (REALLOC_DELTA - 1)) == 0) \ + ptr = xrealloc((ptr), sizeof(*(ptr)) * ((size) + REALLOC_DELTA)); \ + } while (0) + #endif /* H_DEPENDS */ diff --git a/rpm-4_0.spec b/rpm-4_0.spec index adbcfc0..194af98 100644 --- a/rpm-4_0.spec +++ b/rpm-4_0.spec @@ -4,7 +4,7 @@ Name: %rpm_name Version: %rpm_version -Release: alt98.22 +Release: alt98.23 %define ifdef() %if %{expand:%%{?%{1}:1}%%{!?%{1}:0}} %define get_dep() %(rpm -q --qf '%%{NAME} >= %%|SERIAL?{%%{SERIAL}:}|%%{VERSION}-%%{RELEASE}' %1 2>/dev/null || echo '%1 >= unknown') @@ -488,6 +488,12 @@ fi %_bindir/rpm2cpio.static %changelog +* Sun Oct 04 2009 Alexey Tourbin 4.0.4-alt98.23 +- depends.c: avoid expression dependent on evaluation order +- depends.c: implemented automatic realloc +- al.c: factored from depends.c +- al.c: reimplemented alProvIndex and alDirIndex/alFileIndex routines + * Thu Oct 01 2009 Alexey Tourbin 4.0.4-alt98.22 - Removed support for availablePackages/suggestedPackages. - Removed rebuilddb db_filter_dups code (Panu Matilainen).