Example #1
0
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;
}
Example #2
0
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);
    }
Example #3
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);
    }
}
Example #4
0
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;
}
Example #5
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)); }
Example #8
0
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;
}
Example #9
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;
    }
}
Example #10
0
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);
}
Example #11
0
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);
}
Example #12
0
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;
}
Example #13
0
/*
 * 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);
	    }
	}
Example #14
0
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;
    }
}
Example #15
0
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;
}