char * rpmfiFNIndex(rpmfi fi, int ix) { char *fn = NULL; if (fi != NULL && ix >= 0 && ix < fi->fc) { fn = rstrscat(NULL, rpmstrPoolStr(fi->pool, fi->dnid[fi->dil[ix]]), rpmstrPoolStr(fi->pool, fi->bnid[ix]), NULL); } return fn; }
static rpmte * rpmalAllFileSatisfiesDepend(const rpmal al, const char *fileName, const rpmds filterds) { const char *slash; rpmte * ret = NULL; if (al == NULL || fileName == NULL || *fileName != '/') return NULL; /* Split path into dirname and basename components for lookup */ if ((slash = strrchr(fileName, '/')) != NULL) { availableIndexFileEntry result; int resultCnt = 0; size_t bnStart = (slash - fileName) + 1; rpmsid baseName; if (al->fileHash == NULL) rpmalMakeFileIndex(al); baseName = rpmstrPoolId(al->pool, fileName + bnStart, 0); if (!baseName) return NULL; /* no match possible */ rpmalFileHashGetEntry(al->fileHash, baseName, &result, &resultCnt, NULL); if (resultCnt > 0) { int i, found; ret = xmalloc((resultCnt+1) * sizeof(*ret)); fingerPrint * fp = NULL; rpmsid dirName = rpmstrPoolIdn(al->pool, fileName, bnStart, 1); if (!al->fpc) al->fpc = fpCacheCreate(1001, NULL); fpLookup(al->fpc, rpmstrPoolStr(al->pool, dirName), fileName + bnStart, &fp); for (found = i = 0; i < resultCnt; i++) { availablePackage alp = al->list + result[i].pkgNum; if (alp->p == NULL) /* deleted */ continue; /* ignore self-conflicts/obsoletes */ if (filterds && rpmteDS(alp->p, rpmdsTagN(filterds)) == filterds) continue; if (result[i].dirName != dirName && !fpLookupEquals(al->fpc, fp, rpmstrPoolStr(al->pool, result[i].dirName), fileName + bnStart)) continue; ret[found] = alp->p; found++; } _free(fp); ret[found] = NULL; } } return ret; }
const char * rpmdsEVRIndex(rpmds ds, int i) { const char * EVR = NULL; if (ds != NULL && i >= 0 && i < ds->Count && ds->EVR != NULL) EVR = rpmstrPoolStr(ds->pool, ds->EVR[i]); return EVR; }
const char * fpEntryDir(fingerPrintCache cache, fingerPrint *fp) { const char * dn = NULL; if (fp && fp->entry) dn = rpmstrPoolStr(cache->pool, fp->entry->dirId); return dn; }
const char * rpmdsNIndex(rpmds ds, int i) { const char * N = NULL; if (ds != NULL && i >= 0 && i < ds->Count && ds->N != NULL) N = rpmstrPoolStr(ds->pool, ds->N[i]); return N; }
static int doLookupId(fingerPrintCache cache, rpmsid dirNameId, rpmsid baseNameId, fingerPrint *fp) { struct stat sb; const struct fprintCacheEntry_s * cacheHit; char *cdn = canonDir(cache->pool, dirNameId); rpmsid fpId; size_t fpLen; if (cdn == NULL) goto exit; /* XXX only if realpath() above fails */ memset(fp, 0, sizeof(*fp)); fpId = rpmstrPoolId(cache->pool, cdn, 1); fpLen = rpmstrPoolStrlen(cache->pool, fpId);; while (1) { /* as we're stating paths here, we want to follow symlinks */ cacheHit = cacheContainsDirectory(cache, fpId); if (cacheHit != NULL) { fp->entry = cacheHit; } else if (!stat(rpmstrPoolStr(cache->pool, fpId), &sb)) { struct fprintCacheEntry_s * newEntry = xmalloc(sizeof(* newEntry)); newEntry->ino = sb.st_ino; newEntry->dev = sb.st_dev; newEntry->dirId = fpId; fp->entry = newEntry; rpmFpEntryHashAddEntry(cache->ht, fpId, fp->entry); } if (fp->entry) { const char * subDir = cdn + fpLen - 1; /* XXX don't bother saving '/' as subdir */ if (subDir[0] == '\0' || (subDir[0] == '/' && subDir[1] == '\0')) subDir = NULL; fp->baseNameId = baseNameId; if (subDir != NULL) fp->subDirId = rpmstrPoolId(cache->pool, subDir, 1); goto exit; } /* stat of '/' just failed! */ if (fpLen == 1) abort(); /* Find the parent directory and its id for the next round */ fpLen--; while (fpLen > 1 && cdn[fpLen-1] != '/') fpLen--; fpId = rpmstrPoolIdn(cache->pool, cdn, fpLen, 1); } exit: free(cdn); /* XXX TODO: failure from eg realpath() should be returned and handled */ return 0; }
const char * rpmfiFLangsIndex(rpmfi fi, int ix) { const char *flangs = NULL; if (fi != NULL && fi->flangs != NULL && ix >= 0 && ix < fi->fc) { flangs = rpmstrPoolStr(fi->pool, fi->flangs[ix]); } return flangs; }
const char * rpmfiBNIndex(rpmfi fi, int ix) { const char * BN = NULL; if (fi != NULL && ix >= 0 && ix < fi->fc) { if (fi->bnid != NULL) BN = rpmstrPoolStr(fi->pool, fi->bnid[ix]); } return BN; }
const char * rpmfiFLinkIndex(rpmfi fi, int ix) { const char * flink = NULL; if (fi != NULL && ix >= 0 && ix < fi->fc) { if (fi->flinks != NULL) flink = rpmstrPoolStr(fi->pool, fi->flinks[ix]); } return flink; }
const char * rpmfiDNIndex(rpmfi fi, int jx) { const char * DN = NULL; if (fi != NULL && jx >= 0 && jx < fi->dc) { if (fi->dnid != NULL) DN = rpmstrPoolStr(fi->pool, fi->dnid[jx]); } return DN; }
const char * rpmfiFUserIndex(rpmfi fi, int ix) { const char * fuser = NULL; if (fi != NULL && ix >= 0 && ix < fi->fc) { if (fi->fuser != NULL) fuser = rpmstrPoolStr(fi->pool, fi->fuser[ix]); } return fuser; }
const char * rpmfiFGroupIndex(rpmfi fi, int ix) { const char * fgroup = NULL; if (fi != NULL && ix >= 0 && ix < fi->fc) { if (fi->fgroup != NULL) fgroup = rpmstrPoolStr(fi->pool, fi->fgroup[ix]); } return fgroup; }
/* Get a rpmdbMatchIterator containing all files in * the rpmdb that share the basename with one from * the transaction. * @param ts transaction set * @return rpmdbMatchIterator sorted by (package, fileNum) */ static rpmdbMatchIterator rpmFindBaseNamesInDB(rpmts ts, uint64_t fileCount) { tsMembers tsmem = rpmtsMembers(ts); rpmstrPool tspool = rpmtsPool(ts); rpmtsi pi; rpmte p; rpmfiles files; rpmfi fi; rpmdbMatchIterator mi; int oc = 0; const char * baseName; rpmsid baseNameId; rpmStringSet baseNames = rpmStringSetCreate(fileCount, sidHash, sidCmp, NULL); mi = rpmdbNewIterator(rpmtsGetRdb(ts), RPMDBI_BASENAMES); pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { (void) rpmdbCheckSignals(); rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_PROGRESS, oc++, tsmem->orderCount); /* Gather all installed headers with matching basename's. */ files = rpmteFiles(p); fi = rpmfilesIter(files, RPMFI_ITER_FWD); while (rpmfiNext(fi) >= 0) { size_t keylen; baseNameId = rpmfiBNId(fi); if (rpmStringSetHasEntry(baseNames, baseNameId)) continue; keylen = rpmstrPoolStrlen(tspool, baseNameId); baseName = rpmstrPoolStr(tspool, baseNameId); if (keylen == 0) keylen++; /* XXX "/" fixup. */ rpmdbExtendIterator(mi, baseName, keylen); rpmStringSetAddEntry(baseNames, baseNameId); } rpmfiFree(fi); rpmfilesFree(files); } rpmtsiFree(pi); rpmStringSetFree(baseNames); rpmdbSortIterator(mi); /* iterator is now sorted by (recnum, filenum) */ return mi; }
static char * canonDir(rpmstrPool pool, rpmsid dirNameId) { const char * dirName = rpmstrPoolStr(pool, dirNameId); size_t cdnl = rpmstrPoolStrlen(pool, dirNameId);; char *cdnbuf = NULL; if (*dirName == '/') { cdnbuf = xstrdup(dirName); cdnbuf = rpmCleanPath(cdnbuf); /* leave my trailing slashes along you b**** */ if (cdnl > 1) cdnbuf = rstrcat(&cdnbuf, "/"); } else { /* Using realpath on the arg isn't correct if the arg is a symlink, * especially if the symlink is a dangling link. What we * do instead is use realpath() on `.' and then append arg to * the result. */ /* if the current directory doesn't exist, we might fail. oh well. likewise if it's too long. */ /* XXX we should let realpath() allocate if it can */ cdnbuf = xmalloc(PATH_MAX); cdnbuf[0] = '\0'; if (realpath(".", cdnbuf) != NULL) { char *end = cdnbuf + strlen(cdnbuf); if (end[-1] != '/') *end++ = '/'; end = stpncpy(end, dirName, PATH_MAX - (end - cdnbuf)); *end = '\0'; (void)rpmCleanPath(cdnbuf); /* XXX possible /../ from concatenation */ end = cdnbuf + strlen(cdnbuf); if (end[-1] != '/') *end++ = '/'; *end = '\0'; } else { cdnbuf = _free(cdnbuf); } } return cdnbuf; }
/* Check file for to be installed symlinks in their path and correct their fp */ static void fpLookupSubdir(rpmFpHash symlinks, fingerPrintCache fpc, rpmte p, int filenr) { rpmfiles fi = rpmteFiles(p); struct fingerPrint_s current_fp; const char *currentsubdir; size_t lensubDir, bnStart, bnEnd; struct rpmffi_s * recs; int numRecs; int i; fingerPrint *fp = rpmfilesFps(fi) + filenr; int symlinkcount = 0; struct rpmffi_s ffi = { p, filenr}; if (fp->subDirId == 0) { rpmFpHashAddEntry(fpc->fp, fp, ffi); goto exit; } currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId); lensubDir = rpmstrPoolStrlen(fpc->pool, fp->subDirId); current_fp = *fp; /* Set baseName to the upper most dir */ bnStart = bnEnd = 1; while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/') bnEnd++; /* no subDir for now */ current_fp.subDirId = 0; while (bnEnd < lensubDir) { char found = 0; current_fp.baseNameId = rpmstrPoolIdn(fpc->pool, currentsubdir + bnStart, bnEnd - bnStart, 1); rpmFpHashGetEntry(symlinks, ¤t_fp, &recs, &numRecs, NULL); for (i = 0; i < numRecs; i++) { rpmfiles foundfi = rpmteFiles(recs[i].p); char const *linktarget = rpmfilesFLink(foundfi, recs[i].fileno); char *link; /* Ignore already removed (by eg %pretrans) links */ if (linktarget && rpmteType(recs[i].p) == TR_REMOVED) { char *path = rpmfilesFN(foundfi, recs[i].fileno); struct stat sb; if (lstat(path, &sb) == -1) linktarget = NULL; free(path); } foundfi = rpmfilesFree(foundfi); if (linktarget && *linktarget != '\0') { const char *bn; /* this "directory" is a symlink */ link = NULL; if (*linktarget != '/') { const char *dn, *subDir = NULL; dn = rpmstrPoolStr(fpc->pool, current_fp.entry->dirId); if (current_fp.subDirId) { subDir = rpmstrPoolStr(fpc->pool, current_fp.subDirId); } rstrscat(&link, dn, subDir ? subDir : "", "/", NULL); } rstrscat(&link, linktarget, "/", NULL); if (strlen(currentsubdir + bnEnd)) { rstrscat(&link, currentsubdir + bnEnd, NULL); } bn = rpmstrPoolStr(fpc->pool, fp->baseNameId); doLookup(fpc, link, bn, fp); free(link); symlinkcount++; /* setup current_fp for the new path */ found = 1; current_fp = *fp; if (fp->subDirId == 0) { /* directory exists - no need to look for symlinks */ rpmFpHashAddEntry(fpc->fp, fp, ffi); goto exit; } currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId); lensubDir = rpmstrPoolStrlen(fpc->pool, fp->subDirId); /* no subDir for now */ current_fp.subDirId = 0; /* Set baseName to the upper most dir */ bnStart = bnEnd = 1; while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/') bnEnd++; break; } } if (symlinkcount > 50) { // found too many symlinks in the path // most likley a symlink cicle // giving up // TODO warning/error break; } if (found) { continue; // restart loop after symlink } /* Set former baseName as subDir */ bnEnd++; current_fp.subDirId = rpmstrPoolIdn(fpc->pool, currentsubdir, bnEnd, 1); /* set baseName to the next lower dir */ bnStart = bnEnd; while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/') bnEnd++; } rpmFpHashAddEntry(fpc->fp, fp, ffi); exit: rpmfilesFree(fi); }
int parseFiles(rpmSpec spec) { int nextPart, res = PART_ERROR; Package pkg; int rc, argc; int arg; const char ** argv = NULL; const char *name = NULL; int flag = PART_SUBNAME; poptContext optCon = NULL; struct poptOption optionsTable[] = { { NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL}, { NULL, 'f', POPT_ARG_STRING, NULL, 'f', NULL, NULL}, { 0, 0, 0, 0, 0, NULL, NULL} }; /* XXX unmask %license while parsing %files */ rpmPushMacro(spec->macros, "license", NULL, "%%license", RMIL_SPEC); if ((rc = poptParseArgvString(spec->line, &argc, &argv))) { rpmlog(RPMLOG_ERR, _("line %d: Error parsing %%files: %s\n"), spec->lineNum, poptStrerror(rc)); goto exit; } optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); while ((arg = poptGetNextOpt(optCon)) > 0) { if (arg == 'n') { flag = PART_NAME; } } if (arg < -1) { rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"), spec->lineNum, poptBadOption(optCon, POPT_BADOPTION_NOALIAS), spec->line); goto exit; } if (poptPeekArg(optCon)) { if (name == NULL) name = poptGetArg(optCon); if (poptPeekArg(optCon)) { rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"), spec->lineNum, spec->line); goto exit; } } if (lookupPackage(spec, name, flag, &pkg)) goto exit; /* * This should be an error, but its surprisingly commonly abused for the * effect of multiple -f arguments in versions that dont support it. * Warn but preserve behavior, except for leaking memory. */ if (pkg->fileList != NULL) { rpmlog(RPMLOG_WARNING, _("line %d: multiple %%files for package '%s'\n"), spec->lineNum, rpmstrPoolStr(pkg->pool, pkg->name)); pkg->fileList = argvFree(pkg->fileList); } for (arg=1; arg<argc; arg++) { if (rstreq(argv[arg], "-f") && argv[arg+1]) { char *file = rpmGetPath(argv[arg+1], NULL); argvAdd(&(pkg->fileFile), file); free(file); } } pkg->fileList = argvNew(); if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) { nextPart = PART_NONE; } else if (rc < 0) { goto exit; } else { while (! (nextPart = isPart(spec->line))) { argvAdd(&(pkg->fileList), spec->line); if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) { nextPart = PART_NONE; break; } else if (rc < 0) { goto exit; } } } res = nextPart; exit: rpmPopMacro(NULL, "license"); free(argv); poptFreeContext(optCon); return res; }
rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds) { rpmte * ret = NULL; int i, ix, found; rpmsid nameId; const char *name; availableIndexEntry result; int resultCnt; int obsolete; rpmTagVal dtag; rpmds filterds = NULL; availablePackage alp; int rc; if (al == NULL || ds == NULL || (nameId = rpmdsNId(ds)) == 0) return ret; dtag = rpmdsTagN(ds); obsolete = (dtag == RPMTAG_OBSOLETENAME); if (dtag == RPMTAG_OBSOLETENAME || dtag == RPMTAG_CONFLICTNAME) filterds = ds; name = rpmstrPoolStr(al->pool, nameId); if (!obsolete && *name == '/') { /* First, look for files "contained" in package ... */ ret = rpmalAllFileSatisfiesDepend(al, name, filterds); if (ret != NULL && *ret != NULL) { rpmdsNotify(ds, "(added files)", 0); return ret; } /* ... then, look for files "provided" by package. */ ret = _free(ret); } if (al->providesHash == NULL) rpmalMakeProvidesIndex(al); rpmalDepHashGetEntry(al->providesHash, nameId, &result, &resultCnt, NULL); if (resultCnt==0) return NULL; ret = xmalloc((resultCnt+1) * sizeof(*ret)); for (found=i=0; i<resultCnt; i++) { alp = al->list + result[i].pkgNum; if (alp->p == NULL) /* deleted */ continue; /* ignore self-conflicts/obsoletes */ if (filterds && rpmteDS(alp->p, rpmdsTagN(filterds)) == filterds) continue; ix = result[i].entryIx; if (obsolete) { /* Obsoletes are on package NEVR only */ rpmds thisds; if (!rstreq(rpmdsNIndex(alp->provides, ix), rpmteN(alp->p))) continue; thisds = rpmteDS(alp->p, RPMTAG_NAME); rc = rpmdsCompareIndex(thisds, rpmdsIx(thisds), ds, rpmdsIx(ds)); } else { rc = rpmdsCompareIndex(alp->provides, ix, ds, rpmdsIx(ds)); } if (rc) ret[found++] = alp->p; } if (found) { rpmdsNotify(ds, "(added provide)", 0); ret[found] = NULL; } else { ret = _free(ret); } return ret; }