static void prune_todo_range(Repo *repo, struct addfileprovides_cbdata *cbd) { int start = cbd->todo_start, end = cbd->todo_end; while (start < end && !MAPTST(cbd->todo, start - repo->start)) start++; while (end > start && !MAPTST(cbd->todo, end - 1 - repo->start)) end--; cbd->todo_start = start; cbd->todo_end = end; }
void pool_add_pos_literals_complex_dep(Pool *pool, Id dep, Queue *q, Map *m, int neg) { while (ISRELDEP(dep)) { Reldep *rd = GETRELDEP(pool, dep); if (rd->flags != REL_AND && rd->flags != REL_OR && rd->flags != REL_COND) break; pool_add_pos_literals_complex_dep(pool, rd->name, q, m, neg); dep = rd->evr; if (rd->flags == REL_COND) { neg = !neg; if (ISRELDEP(dep)) { Reldep *rd2 = GETRELDEP(pool, rd->evr); if (rd2->flags == REL_ELSE) { pool_add_pos_literals_complex_dep(pool, rd2->evr, q, m, !neg); dep = rd2->name; } } } } if (!neg) { Id p, pp; FOR_PROVIDES(p, pp, dep) if (!MAPTST(m, p)) queue_push(q, p); }
static void enableweakrules(Solver *solv) { int i; Rule *r; for (i = 1, r = solv->rules + i; i < solv->learntrules; i++, r++) { if (r->d >= 0) /* already enabled? */ continue; if (!MAPTST(&solv->weakrulemap, i)) continue; solver_enablerule(solv, r); } }
static int repodata_intersects_todo(Repodata *data, struct addfileprovides_cbdata *cbd) { Repo *repo; int p, start = data->start, end = data->end; if (start >= cbd->todo_end || end <= cbd->todo_start) return 0; repo = data->repo; if (start < cbd->todo_start) start = cbd->todo_start; if (end > cbd->todo_end) end = cbd->todo_end; for (p = start; p < end; p++) if (MAPTST(cbd->todo, p - repo->start)) return 1; return 0; }
static void enableweakrules(Solver *solv) { int i; Rule *r; for (i = 1, r = solv->rules + i; i < solv->learntrules; i++, r++) { if (r->d >= 0) /* already enabled? */ continue; if (!MAPTST(&solv->weakrulemap, i)) continue; solver_enablerule(solv, r); } /* make sure broken orphan rules stay disabled */ if (solv->brokenorphanrules) for (i = 0; i < solv->brokenorphanrules->count; i++) solver_disablerule(solv, solv->rules + solv->brokenorphanrules->elements[i]); }
bool PackageSet::has(Id id) const { return MAPTST(&pImpl->map, id); }
bool PackageSet::has(DnfPackage *pkg) const { return MAPTST(&pImpl->map, dnf_package_get_id(pkg)); }
static void repo_addfileprovides_search(Repo *repo, struct addfileprovides_cbdata *cbd, struct searchfiles *sf) { Repodata *data; int rdid, p, i; int provstart, provend; Map todo; Map providedids; if (repo->end <= repo->start || !repo->nsolvables || !sf->nfiles) return; /* update search data if changed */ if (cbd->nfiles != sf->nfiles || cbd->ids != sf->ids) { free_dirs_names_array(cbd); cbd->nfiles = sf->nfiles; cbd->ids = sf->ids; cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id)); } /* create todo map and range */ map_init(&todo, repo->end - repo->start); for (p = repo->start; p < repo->end; p++) if (repo->pool->solvables[p].repo == repo) MAPSET(&todo, p - repo->start); cbd->todo = &todo; cbd->todo_start = repo->start; cbd->todo_end = repo->end; prune_todo_range(repo, cbd); provstart = provend = 0; map_init(&providedids, 0); data = repo_lookup_repodata(repo, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES); if (data) { Queue fileprovidesq; queue_init(&fileprovidesq); if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) { map_grow(&providedids, repo->pool->ss.nstrings); cbd->providedids = &providedids; provstart = data->start; provend = data->end; for (i = 0; i < fileprovidesq.count; i++) MAPSET(&providedids, fileprovidesq.elements[i]); for (i = 0; i < cbd->nfiles; i++) if (!MAPTST(&providedids, cbd->ids[i])) break; if (i == cbd->nfiles) { /* all included, clear entries from todo list */ if (provstart <= cbd->todo_start && provend >= cbd->todo_end) cbd->todo_end = cbd->todo_start; /* clear complete range */ else { for (p = provstart; p < provend; p++) MAPCLR(&todo, p - repo->start); prune_todo_range(repo, cbd); } } } queue_free(&fileprovidesq); } if (cbd->todo_start >= cbd->todo_end) { map_free(&todo); cbd->todo = 0; map_free(&providedids); cbd->providedids = 0; return; } /* this is similar to repo_lookup_filelist_repodata in repo.c */ for (rdid = 1, data = repo->repodata + rdid; rdid < repo->nrepodata; rdid++, data++) if (data->filelisttype == REPODATA_FILELIST_FILTERED) break; for (; rdid < repo->nrepodata; rdid++, data++) if (data->filelisttype == REPODATA_FILELIST_EXTENSION) break; if (rdid < repo->nrepodata) { /* have at least one repodata with REPODATA_FILELIST_FILTERED followed by REPODATA_FILELIST_EXTENSION */ Map postpone; map_init(&postpone, 0); for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--) { if (data->filelisttype != REPODATA_FILELIST_FILTERED) continue; if (!repodata_intersects_todo(data, cbd)) continue; if (data->state != REPODATA_AVAILABLE) { if (data->state != REPODATA_STUB) continue; repodata_load(data); if (data->state != REPODATA_AVAILABLE || data->filelisttype != REPODATA_FILELIST_FILTERED) continue; } repo_addfileprovides_search_filtered(repo, cbd, rdid, &postpone); } if (postpone.size) { /* add postponed entries back to todo */ map_or(&todo, &postpone); cbd->todo_start = repo->start; cbd->todo_end = repo->end; prune_todo_range(repo, cbd); } map_free(&postpone); } /* search remaining entries in the standard way */ if (cbd->todo_start < cbd->todo_end) { for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--) { if (data->start >= cbd->todo_end || data->end <= cbd->todo_start) continue; if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) continue; if (!repodata_intersects_todo(data, cbd)) continue; repodata_addfileprovides_search(data, cbd); if (cbd->todo_start >= cbd->todo_end) break; } } map_free(&todo); cbd->todo = 0; map_free(&providedids); cbd->providedids = 0; }
static void pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf) { Id dep, sid; const char *s; struct searchfiles *csf; while ((dep = *ida++) != 0) { csf = sf; while (ISRELDEP(dep)) { Reldep *rd; sid = pool->ss.nstrings + GETRELID(dep); if (MAPTST(&csf->seen, sid)) { dep = 0; break; } MAPSET(&csf->seen, sid); rd = GETRELDEP(pool, dep); if (rd->flags < 8) dep = rd->name; else if (rd->flags == REL_NAMESPACE) { if (rd->name == NAMESPACE_SPLITPROVIDES) { csf = isf; if (!csf || MAPTST(&csf->seen, sid)) { dep = 0; break; } MAPSET(&csf->seen, sid); } dep = rd->evr; } else if (rd->flags == REL_FILECONFLICT) { dep = 0; break; } else { Id ids[2]; ids[0] = rd->name; ids[1] = 0; pool_addfileprovides_dep(pool, ids, csf, isf); dep = rd->evr; } } if (!dep) continue; if (MAPTST(&csf->seen, dep)) continue; MAPSET(&csf->seen, dep); s = pool_id2str(pool, dep); if (*s != '/') continue; if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s)) continue; /* skip non-standard locations csf == isf: installed case */ csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); csf->ids[csf->nfiles++] = dep; } }
static void repo_addfileprovides_search_filtered(Repo *repo, struct addfileprovides_cbdata *cbd, int filteredid, Map *postpone) { Repodata *data = repo->repodata + filteredid; Map *providedids = cbd->providedids; int rdid; int start, end, p, i; Map old_todo; int old_todo_start, old_todo_end; start = cbd->todo_start > data->start ? cbd->todo_start : data->start; end = cbd->todo_end > data->end ? data->end : cbd->todo_end; if (providedids) { /* check if all solvables are in the provide range */ if (start < cbd->provstart || end > cbd->provend) { /* unclear, check each solvable */ for (p = start; p < end; p++) { if (p >= cbd->provstart && p < cbd->provend) continue; if (data->incoreoffset[p - data->start] && MAPTST(cbd->todo, p - repo->start)) { providedids = 0; /* nope, cannot prune with providedids */ break; } } } } /* check if the filtered files are enough */ for (i = 0; i < cbd->nfiles; i++) { if (providedids && MAPTST(providedids, cbd->ids[i])) /* this one is already provided */ continue; if (!repodata_filelistfilter_matches(data, pool_id2str(repo->pool, cbd->ids[i]))) break; } if (i < cbd->nfiles) { /* nope, need to search the extensions as well. postpone. */ for (p = start; p < end; p++) { if (data->incoreoffset[p - data->start] && MAPTST(cbd->todo, p - repo->start)) { if (!postpone->size) map_grow(postpone, repo->nsolvables); MAPSET(postpone, p - repo->start); MAPCLR(cbd->todo, p - repo->start); } } prune_todo_range(repo, cbd); return; } /* now check if there is no data marked withour EXTENSION */ /* limit todo to the solvables in this repodata */ old_todo_start = cbd->todo_start; old_todo_end = cbd->todo_end; old_todo = *cbd->todo; map_init(cbd->todo, repo->nsolvables); for (p = start; p < end; p++) if (data->incoreoffset[p - data->start] && MAPTST(&old_todo, p - repo->start)) { MAPCLR(&old_todo, p - repo->start); MAPSET(cbd->todo, p - repo->start); } prune_todo_range(repo, cbd); /* do the check */ for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > filteredid ; rdid--, data--) { if (data->filelisttype == REPODATA_FILELIST_EXTENSION) continue; if (data->start >= cbd->todo_end || data->end <= cbd->todo_start) continue; if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) continue; if (!repodata_intersects_todo(data, cbd)) continue; /* oh no, this filelist data is not tagged with REPODATA_FILELIST_EXTENSION! */ /* postpone entries that have filelist data */ start = cbd->todo_start > data->start ? cbd->todo_start : data->start; end = cbd->todo_end > data->end ? data->end : cbd->todo_end; for (p = start; p < end; p++) if (MAPTST(cbd->todo, p - repo->start)) if (repodata_lookup_type(data, p, SOLVABLE_FILELIST)) { if (!postpone->size) map_grow(postpone, repo->nsolvables); MAPSET(postpone, p - repo->start); MAPCLR(cbd->todo, p - repo->start); } prune_todo_range(repo, cbd); if (cbd->todo_start >= cbd->todo_end) break; } /* do the search over the filtered file list with the remaining entries*/ if (cbd->todo_start < cbd->todo_end) repodata_addfileprovides_search(repo->repodata + filteredid, cbd); /* restore todo map */ map_free(cbd->todo); *cbd->todo = old_todo; cbd->todo_start = old_todo_start; cbd->todo_end = old_todo_end; prune_todo_range(repo, cbd); }
static void repodata_addfileprovides_search(Repodata *data, struct addfileprovides_cbdata *cbd) { Repo *repo = data->repo; int i, p, start, end; Map useddirs; Map *providedids = 0; /* make it available */ if (data->state == REPODATA_STUB) repodata_load(data); if (data->state != REPODATA_AVAILABLE) return; if (!data->incoredata || !data->dirpool.ndirs) return; start = cbd->todo_start > data->start ? cbd->todo_start : data->start; end = cbd->todo_end > data->end ? data->end : cbd->todo_end; if (start >= end) return; /* deal with provideids overlap */ if (cbd->providedids) { if (start >= cbd->provstart && end <= cbd->provend) providedids = cbd->providedids; /* complete overlap */ else if (start < cbd->provend && end > cbd->provstart) { /* partial overlap, need to split search */ if (start < cbd->provstart) { repodata_addfileprovides_search_limited(data, cbd, start, cbd->provstart); start = cbd->provstart; } if (end > cbd->provend) { repodata_addfileprovides_search_limited(data, cbd, cbd->provend, end); end = cbd->provend; } if (start < end) repodata_addfileprovides_search_limited(data, cbd, start, end); return; } } /* set up dirs and names array if not already done */ if (!cbd->dirs) create_dirs_names_array(cbd, repo->pool); /* set up useddirs map and the cbd->dids array */ map_init(&useddirs, data->dirpool.ndirs); for (i = 0; i < cbd->nfiles; i++) { Id did; if (providedids && MAPTST(providedids, cbd->ids[i])) { cbd->dids[i] = 0; /* already included, do not add again */ continue; } cbd->dids[i] = did = repodata_str2dir(data, cbd->dirs[i], 0); if (did) MAPSET(&useddirs, did); } repodata_free_dircache(data); /* repodata_str2dir created it */ for (p = start; p < end; p++) { const unsigned char *dp; Solvable *s; if (!MAPTST(cbd->todo, p - repo->start)) continue; dp = repodata_lookup_packed_dirstrarray(data, p, SOLVABLE_FILELIST); if (!dp) continue; /* now iterate through the packed array */ s = repo->pool->solvables + p; MAPCLR(cbd->todo, p - repo->start); /* this entry is done */ for (;;) { Id did = 0; int c; while ((c = *dp++) & 0x80) did = (did << 7) ^ c ^ 0x80; did = (did << 6) | (c & 0x3f); if ((unsigned int)did < (unsigned int)data->dirpool.ndirs && MAPTST(&useddirs, did)) { /* there is at least one entry with that did */ for (i = 0; i < cbd->nfiles; i++) if (cbd->dids[i] == did && !strcmp(cbd->names[i], (const char *)dp)) s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER); } if (!(c & 0x40)) break; dp += strlen((const char *)dp) + 1; } } map_free(&useddirs); prune_todo_range(repo, cbd); }
static void prune_to_recommended(Solver *solv, Queue *plist) { Pool *pool = solv->pool; int i, j, k, ninst; Solvable *s; Id p, pp, rec, *recp, sug, *sugp; ninst = 0; if (pool->installed) { for (i = 0; i < plist->count; i++) { p = plist->elements[i]; s = pool->solvables + p; if (pool->installed && s->repo == pool->installed) ninst++; } } if (plist->count - ninst < 2) return; /* update our recommendsmap/suggestsmap */ if (solv->recommends_index < 0) { MAPZERO(&solv->recommendsmap); MAPZERO(&solv->suggestsmap); solv->recommends_index = 0; } while (solv->recommends_index < solv->decisionq.count) { p = solv->decisionq.elements[solv->recommends_index++]; if (p < 0) continue; s = pool->solvables + p; if (s->recommends) { recp = s->repo->idarraydata + s->recommends; while ((rec = *recp++) != 0) FOR_PROVIDES(p, pp, rec) MAPSET(&solv->recommendsmap, p); } if (s->suggests) { sugp = s->repo->idarraydata + s->suggests; while ((sug = *sugp++) != 0) FOR_PROVIDES(p, pp, sug) MAPSET(&solv->suggestsmap, p); } } /* prune to recommended/supplemented */ ninst = 0; for (i = j = 0; i < plist->count; i++) { p = plist->elements[i]; s = pool->solvables + p; if (pool->installed && s->repo == pool->installed) { ninst++; if (j) plist->elements[j++] = p; continue; } if (!MAPTST(&solv->recommendsmap, p)) if (!solver_is_supplementing(solv, s)) continue; if (!j && ninst) { for (k = 0; j < ninst; k++) { s = pool->solvables + plist->elements[k]; if (pool->installed && s->repo == pool->installed) plist->elements[j++] = plist->elements[k]; } } plist->elements[j++] = p; } if (j) plist->count = j; /* anything left to prune? */ if (plist->count - ninst < 2) return; /* prune to suggested/enhanced */ ninst = 0; for (i = j = 0; i < plist->count; i++) { p = plist->elements[i]; s = pool->solvables + p; if (pool->installed && s->repo == pool->installed) { ninst++; if (j) plist->elements[j++] = p; continue; } if (!MAPTST(&solv->suggestsmap, p)) if (!solver_is_enhancing(solv, s)) continue; if (!j && ninst) { for (k = 0; j < ninst; k++) { s = pool->solvables + plist->elements[k]; if (pool->installed && s->repo == pool->installed) plist->elements[j++] = plist->elements[k]; } } plist->elements[j++] = p; } if (j) plist->count = j; }
/* * convert a solution rule into a job modifier */ static void convertsolution(Solver *solv, Id why, Queue *solutionq) { Pool *pool = solv->pool; if (why < 0) { why = -why; if (why < solv->pooljobcnt) { queue_push(solutionq, SOLVER_SOLUTION_POOLJOB); queue_push(solutionq, why); } else { queue_push(solutionq, SOLVER_SOLUTION_JOB); queue_push(solutionq, why - solv->pooljobcnt); } return; } if (why >= solv->infarchrules && why < solv->infarchrules_end) { Id p, name; /* infarch rule, find replacement */ assert(solv->rules[why].p < 0); name = pool->solvables[-solv->rules[why].p].name; while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name) why--; p = 0; for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++) if (solv->decisionmap[-solv->rules[why].p] > 0) { p = -solv->rules[why].p; break; } if (!p) return; /* false alarm */ queue_push(solutionq, SOLVER_SOLUTION_INFARCH); queue_push(solutionq, p); return; } if (why >= solv->duprules && why < solv->duprules_end) { Id p, name; /* dist upgrade rule, find replacement */ assert(solv->rules[why].p < 0); name = pool->solvables[-solv->rules[why].p].name; while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name) why--; p = 0; for (; why < solv->duprules_end && pool->solvables[-solv->rules[why].p].name == name; why++) if (solv->decisionmap[-solv->rules[why].p] > 0) { p = -solv->rules[why].p; break; } if (!p) return; /* false alarm */ queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE); queue_push(solutionq, p); return; } if (why >= solv->updaterules && why < solv->updaterules_end) { /* update rule, find replacement package */ Id p, pp, rp = 0; Rule *rr; /* check if this is a false positive, i.e. the update rule is fulfilled */ rr = solv->rules + why; FOR_RULELITERALS(p, pp, rr) if (p > 0 && solv->decisionmap[p] > 0) return; /* false alarm */ p = solv->installed->start + (why - solv->updaterules); if (solv->dupmap_all && solv->rules[why].p != p && solv->decisionmap[p] > 0) { /* distupgrade case, allow to keep old package */ queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE); queue_push(solutionq, p); return; } if (solv->decisionmap[p] > 0) return; /* false alarm, turned out we can keep the package */ rr = solv->rules + solv->featurerules + (why - solv->updaterules); if (!rr->p) rr = solv->rules + why; if (rr->w2) { int mvrp = 0; /* multi-version replacement */ FOR_RULELITERALS(rp, pp, rr) { if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed) { mvrp = rp; if (!(solv->multiversion.size && MAPTST(&solv->multiversion, rp))) break; } } if (!rp && mvrp) { /* found only multi-version replacements */ /* have to split solution into two parts */ queue_push(solutionq, p); queue_push(solutionq, mvrp); } }
static Id transaction_base_type(Transaction *trans, Id p) { Pool *pool = trans->pool; Solvable *s, *s2; int r; Id p2; if (!MAPTST(&trans->transactsmap, p)) return SOLVER_TRANSACTION_IGNORE; p2 = transaction_obs_pkg(trans, p); if (pool->installed && pool->solvables[p].repo == pool->installed) { /* erase */ if (!p2) return SOLVER_TRANSACTION_ERASE; s = pool->solvables + p; s2 = pool->solvables + p2; if (s->name == s2->name) { if (s->evr == s2->evr && solvable_identical(s, s2)) return SOLVER_TRANSACTION_REINSTALLED; r = pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE); if (r < 0) return SOLVER_TRANSACTION_UPGRADED; else if (r > 0) return SOLVER_TRANSACTION_DOWNGRADED; return SOLVER_TRANSACTION_CHANGED; } return SOLVER_TRANSACTION_OBSOLETED; } else { /* install or multiinstall */ int multi = trans->multiversionmap.size && MAPTST(&trans->multiversionmap, p); if (multi) { if (p2) { s = pool->solvables + p; s2 = pool->solvables + p2; if (s->name == s2->name && s->arch == s2->arch && s->evr == s2->evr) return SOLVER_TRANSACTION_MULTIREINSTALL; } return SOLVER_TRANSACTION_MULTIINSTALL; } if (!p2) return SOLVER_TRANSACTION_INSTALL; s = pool->solvables + p; s2 = pool->solvables + p2; if (s->name == s2->name) { if (s->evr == s2->evr && solvable_identical(s, s2)) return SOLVER_TRANSACTION_REINSTALL; r = pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE); if (r > 0) return SOLVER_TRANSACTION_UPGRADE; else if (r < 0) return SOLVER_TRANSACTION_DOWNGRADE; else return SOLVER_TRANSACTION_CHANGE; } return SOLVER_TRANSACTION_OBSOLETES; } }
int pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, int flags, void *(*handle_cb)(Pool *, Id, void *) , void *handle_cbdata) { int i, j, cflmapn, idxmapset; struct cbdata cbdata; unsigned int now, start; void *handle; Repo *installed = pool->installed; Id p; int obsoleteusescolors = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESCOLORS); int hdrfetches; queue_empty(conflicts); if (!pkgs->count) return 0; now = start = solv_timems(0); POOL_DEBUG(SOLV_DEBUG_STATS, "searching for file conflicts\n"); POOL_DEBUG(SOLV_DEBUG_STATS, "packages: %d, cutoff %d\n", pkgs->count, cutoff); memset(&cbdata, 0, sizeof(cbdata)); cbdata.aliases = flags & FINDFILECONFLICTS_CHECK_DIRALIASING; cbdata.pool = pool; if (cbdata.aliases && (flags & FINDFILECONFLICTS_USE_ROOTDIR) != 0) { cbdata.rootdir = pool_get_rootdir(pool); if (cbdata.rootdir && !strcmp(cbdata.rootdir, "/")) cbdata.rootdir = 0; if (cbdata.rootdir) cbdata.rootdirl = strlen(cbdata.rootdir); if (!cbdata.rootdir) cbdata.usestat = 1; } queue_init(&cbdata.lookat); queue_init(&cbdata.lookat_dir); map_init(&cbdata.idxmap, pkgs->count); if (cutoff <= 0) cutoff = pkgs->count; /* avarage file list size: 200 files per package */ /* avarage dir count: 20 dirs per package */ /* first pass: scan dirs */ if (!cbdata.aliases) { hdrfetches = 0; cflmapn = (cutoff + 3) * 64; while ((cflmapn & (cflmapn - 1)) != 0) cflmapn = cflmapn & (cflmapn - 1); cbdata.dirmap = solv_calloc(cflmapn, 2 * sizeof(Id)); cbdata.dirmapn = cflmapn - 1; /* make it a mask */ cbdata.create = 1; idxmapset = 0; for (i = 0; i < pkgs->count; i++) { if (i == cutoff) cbdata.create = 0; cbdata.idx = i; p = pkgs->elements[i]; if ((flags & FINDFILECONFLICTS_USE_SOLVABLEFILELIST) != 0 && installed) { if (p >= installed->start && p < installed->end && pool->solvables[p].repo == installed) { iterate_solvable_dirs(pool, p, finddirs_cb, &cbdata); if (MAPTST(&cbdata.idxmap, i)) idxmapset++; continue; } } handle = (*handle_cb)(pool, p, handle_cbdata); if (!handle) continue; hdrfetches++; rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_ONLYDIRS, finddirs_cb, &cbdata); if (MAPTST(&cbdata.idxmap, i)) idxmapset++; } POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap size: %d, used %d\n", cbdata.dirmapn + 1, cbdata.dirmapused); POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap memory usage: %d K\n", (cbdata.dirmapn + 1) * 2 * (int)sizeof(Id) / 1024); POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches); POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap creation took %d ms\n", solv_timems(now)); POOL_DEBUG(SOLV_DEBUG_STATS, "dir conflicts found: %d, idxmap %d of %d\n", cbdata.dirconflicts, idxmapset, pkgs->count); } /* second pass: scan files */ now = solv_timems(0); cflmapn = (cutoff + 3) * 128; while ((cflmapn & (cflmapn - 1)) != 0) cflmapn = cflmapn & (cflmapn - 1); cbdata.cflmap = solv_calloc(cflmapn, 2 * sizeof(Id)); cbdata.cflmapn = cflmapn - 1; /* make it a mask */ cbdata.create = 1; hdrfetches = 0; for (i = 0; i < pkgs->count; i++) { if (i == cutoff) cbdata.create = 0; if (!cbdata.aliases && !MAPTST(&cbdata.idxmap, i)) continue; cbdata.idx = i; p = pkgs->elements[i]; if (!cbdata.create && (flags & FINDFILECONFLICTS_USE_SOLVABLEFILELIST) != 0 && installed) { if (p >= installed->start && p < installed->end && pool->solvables[p].repo == installed) if (!precheck_solvable_files(&cbdata, pool, p)) continue; } /* can't use FINDFILECONFLICTS_USE_SOLVABLEFILELIST because we have to know if * the file is a directory or not */ handle = (*handle_cb)(pool, p, handle_cbdata); if (!handle) continue; hdrfetches++; cbdata.lastdiridx = -1; rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_NOGHOSTS, cbdata.aliases ? findfileconflicts_basename_cb : findfileconflicts_cb, &cbdata); } POOL_DEBUG(SOLV_DEBUG_STATS, "filemap size: %d, used %d\n", cbdata.cflmapn + 1, cbdata.cflmapused); POOL_DEBUG(SOLV_DEBUG_STATS, "filemap memory usage: %d K\n", (cbdata.cflmapn + 1) * 2 * (int)sizeof(Id) / 1024); POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches); POOL_DEBUG(SOLV_DEBUG_STATS, "filemap creation took %d ms\n", solv_timems(now)); POOL_DEBUG(SOLV_DEBUG_STATS, "lookat_dir size: %d\n", cbdata.lookat_dir.count); queue_free(&cbdata.lookat_dir); /* we need another pass for aliases */ if (cbdata.aliases) { now = solv_timems(0); /* make sure the first offset is not zero */ addfilesspace(&cbdata, 1); cflmapn = (cutoff + 3) * 16; while ((cflmapn & (cflmapn - 1)) != 0) cflmapn = cflmapn & (cflmapn - 1); cbdata.normap = solv_calloc(cflmapn, 2 * sizeof(Id)); cbdata.normapn = cflmapn - 1; /* make it a mask */ if (cbdata.usestat) { cbdata.statmap = solv_calloc(cflmapn, 2 * sizeof(Id)); cbdata.statmapn = cflmapn - 1; /* make it a mask */ } cbdata.create = 0; hdrfetches = 0; for (i = 0; i < pkgs->count; i++) { if (!MAPTST(&cbdata.idxmap, i)) continue; p = pkgs->elements[i]; cbdata.idx = i; /* can't use FINDFILECONFLICTS_USE_SOLVABLEFILELIST because we have to know if * the file is a directory or not */ handle = (*handle_cb)(pool, p, handle_cbdata); if (!handle) continue; hdrfetches++; cbdata.lastdiridx = -1; rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_NOGHOSTS, findfileconflicts_alias_cb, &cbdata); } POOL_DEBUG(SOLV_DEBUG_STATS, "normap size: %d, used %d\n", cbdata.normapn + 1, cbdata.normapused); POOL_DEBUG(SOLV_DEBUG_STATS, "normap memory usage: %d K\n", (cbdata.normapn + 1) * 2 * (int)sizeof(Id) / 1024); POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches); POOL_DEBUG(SOLV_DEBUG_STATS, "stats made: %d\n", cbdata.statsmade); if (cbdata.usestat) { POOL_DEBUG(SOLV_DEBUG_STATS, "statmap size: %d, used %d\n", cbdata.statmapn + 1, cbdata.statmapused); POOL_DEBUG(SOLV_DEBUG_STATS, "statmap memory usage: %d K\n", (cbdata.statmapn + 1) * 2 * (int)sizeof(Id) / 1024); } cbdata.statmap = solv_free(cbdata.statmap); cbdata.statmapn = 0; cbdata.canonspace = solv_free(cbdata.canonspace); cbdata.canonspacen = 0; POOL_DEBUG(SOLV_DEBUG_STATS, "alias processing took %d ms\n", solv_timems(now)); } cbdata.dirmap = solv_free(cbdata.dirmap); cbdata.dirmapn = 0; cbdata.dirmapused = 0; cbdata.cflmap = solv_free(cbdata.cflmap); cbdata.cflmapn = 0; cbdata.cflmapused = 0; map_free(&cbdata.idxmap); /* sort and unify/prune */ now = solv_timems(0); POOL_DEBUG(SOLV_DEBUG_STATS, "raw candidates: %d, pruning\n", cbdata.lookat.count / 4); solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_hx_cmp, pool); for (i = j = 0; i < cbdata.lookat.count; ) { int first = 1; Id hx = cbdata.lookat.elements[i]; Id idx = cbdata.lookat.elements[i + 1]; Id dhx = cbdata.lookat.elements[i + 2]; Id dirid = cbdata.lookat.elements[i + 3]; i += 4; for (; i < cbdata.lookat.count && hx == cbdata.lookat.elements[i] && (dirid == cbdata.lookat.elements[i + 3] || dirid == -cbdata.lookat.elements[i + 3]); i += 4) { if (idx == cbdata.lookat.elements[i + 1] && dhx == cbdata.lookat.elements[i + 2]) continue; /* ignore duplicates */ if (first) { if (dirid < 0) continue; /* all have a neg dirid */ cbdata.lookat.elements[j++] = hx; cbdata.lookat.elements[j++] = idx; cbdata.lookat.elements[j++] = dhx; cbdata.lookat.elements[j++] = dirid; first = 0; } idx = cbdata.lookat.elements[i + 1]; dhx = cbdata.lookat.elements[i + 2]; cbdata.lookat.elements[j++] = hx; cbdata.lookat.elements[j++] = idx; cbdata.lookat.elements[j++] = dhx; cbdata.lookat.elements[j++] = dirid; } } queue_truncate(&cbdata.lookat, j); POOL_DEBUG(SOLV_DEBUG_STATS, "candidates now: %d\n", cbdata.lookat.count / 4); POOL_DEBUG(SOLV_DEBUG_STATS, "pruning took %d ms\n", solv_timems(now)); /* third pass: collect file info for all files that match a hx */ now = solv_timems(0); solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_idx_cmp, pool); queue_init(&cbdata.files); hdrfetches = 0; for (i = 0; i < cbdata.lookat.count; i += 4) { Id idx = cbdata.lookat.elements[i + 1]; int iterflags = RPM_ITERATE_FILELIST_WITHMD5 | RPM_ITERATE_FILELIST_NOGHOSTS; if (obsoleteusescolors) iterflags |= RPM_ITERATE_FILELIST_WITHCOL; p = pkgs->elements[idx]; handle = (*handle_cb)(pool, p, handle_cbdata); if (handle) hdrfetches++; for (;; i += 4) { int fstart = cbdata.files.count; queue_push(&cbdata.files, idx); queue_push(&cbdata.files, 0); cbdata.idx = idx; cbdata.hx = cbdata.lookat.elements[i]; cbdata.dirhash = cbdata.lookat.elements[i + 2]; cbdata.dirid = cbdata.lookat.elements[i + 3]; cbdata.lastdiridx = -1; if (handle) rpm_iterate_filelist(handle, iterflags, findfileconflicts2_cb, &cbdata); cbdata.files.elements[fstart + 1] = cbdata.files.count; cbdata.lookat.elements[i + 1] = fstart; if (i + 4 >= cbdata.lookat.count || cbdata.lookat.elements[i + 4 + 1] != idx) break; } } POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches); POOL_DEBUG(SOLV_DEBUG_STATS, "file info fetching took %d ms\n", solv_timems(now)); cbdata.normap = solv_free(cbdata.normap); cbdata.normapn = 0; /* forth pass: for each hx we have, compare all matching files against all other matching files */ now = solv_timems(0); solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_hx_cmp, pool); for (i = 0; i < cbdata.lookat.count - 4; i += 4) { Id hx = cbdata.lookat.elements[i]; Id pstart = cbdata.lookat.elements[i + 1]; Id dirid = cbdata.lookat.elements[i + 3]; Id pidx = cbdata.files.elements[pstart]; Id pend = cbdata.files.elements[pstart + 1]; if (cbdata.lookat.elements[i + 4] != hx) continue; /* no package left with that hx */ for (j = i + 4; j < cbdata.lookat.count && cbdata.lookat.elements[j] == hx && cbdata.lookat.elements[j + 3] == dirid; j += 4) { Id qstart = cbdata.lookat.elements[j + 1]; Id qidx = cbdata.files.elements[qstart]; Id qend = cbdata.files.elements[qstart + 1]; int ii, jj; if (pidx >= cutoff && qidx >= cutoff) continue; /* no conflicts between packages with idx >= cutoff */ for (ii = pstart + 2; ii < pend; ii++) for (jj = qstart + 2; jj < qend; jj++) { char *fsi = (char *)cbdata.filesspace + cbdata.files.elements[ii]; char *fsj = (char *)cbdata.filesspace + cbdata.files.elements[jj]; if (cbdata.aliases) { /* compare just the basenames, the dirs match because of the dirid */ char *bsi = strrchr(fsi + 34, '/'); char *bsj = strrchr(fsj + 34, '/'); if (!bsi || !bsj) continue; if (strcmp(bsi, bsj)) continue; /* different base names */ } else { if (strcmp(fsi + 34, fsj + 34)) continue; /* different file names */ } if (!strcmp(fsi, fsj)) continue; /* file digests match, no conflict */ if (obsoleteusescolors && fsi[33] && fsj[33] && (fsi[33] & fsj[33]) == 0) continue; /* colors do not conflict */ queue_push(conflicts, pool_str2id(pool, fsi + 34, 1)); queue_push(conflicts, pkgs->elements[pidx]); queue_push(conflicts, pool_str2id(pool, fsi, 1)); queue_push(conflicts, pool_str2id(pool, fsj + 34, 1)); queue_push(conflicts, pkgs->elements[qidx]); queue_push(conflicts, pool_str2id(pool, fsj, 1)); } } } POOL_DEBUG(SOLV_DEBUG_STATS, "filespace size: %d K\n", cbdata.filesspacen / 1024); POOL_DEBUG(SOLV_DEBUG_STATS, "candidate check took %d ms\n", solv_timems(now)); cbdata.filesspace = solv_free(cbdata.filesspace); cbdata.filesspacen = 0; queue_free(&cbdata.lookat); queue_free(&cbdata.files); if (conflicts->count > 6) solv_sort(conflicts->elements, conflicts->count / 6, 6 * sizeof(Id), conflicts_cmp, pool); POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file conflicts\n", conflicts->count / 6); POOL_DEBUG(SOLV_DEBUG_STATS, "file conflict detection took %d ms\n", solv_timems(start)); return conflicts->count / 6; }