Example #1
0
void
repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags)
{
  Pool *pool = repo->pool;
  struct parsedata pd;
  char buf[BUFF_SIZE];
  int i, l;
  struct stateswitch *sw;
  Repodata *data;
  unsigned int now;

  now = sat_timems(0);
  data = repo_add_repodata(repo, flags);

  memset(&pd, 0, sizeof(pd));
  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
    {
      if (!pd.swtab[sw->from])
        pd.swtab[sw->from] = sw;
      pd.sbtab[sw->to] = sw->from;
    }
  pd.common.pool = pool;
  pd.common.repo = repo;

  pd.data = data;

  pd.content = sat_malloc(256);
  pd.acontent = 256;
  pd.lcontent = 0;
  pd.common.tmp = 0;
  pd.common.tmpl = 0;
  pd.kind = 0;
  pd.language = language;

  /* initialize the string pool where we will store
     the package checksums we know about, to get an Id
     we can use in a cache */
  stringpool_init_empty(&pd.cspool);
  if ((flags & REPO_EXTEND_SOLVABLES) != 0)
    {
      /* setup join data */
      Dataiterator di;
      dataiterator_init(&di, pool, repo, 0, SOLVABLE_CHECKSUM, 0, 0);
      while (dataiterator_step(&di))
	{
	  const char *str;
	  int index;

	  if (!sat_chksum_len(di.key->type))
	    continue;
	  str = repodata_chk2str(di.data, di.key->type, (const unsigned char *)di.kv.str);
          index = stringpool_str2id(&pd.cspool, str, 1);
	  if (index >= pd.ncscache)
	    {
	      pd.cscache = sat_zextend(pd.cscache, pd.ncscache, index + 1 - pd.ncscache, sizeof(Id), 255);
	      pd.ncscache = index + 1;
	    }
          pd.cscache[index] = di.solvid;
	}
      dataiterator_free(&di);
    }

  XML_Parser parser = XML_ParserCreate(NULL);
  XML_SetUserData(parser, &pd);
  pd.parser = &parser;
  XML_SetElementHandler(parser, startElement, endElement);
  XML_SetCharacterDataHandler(parser, characterData);
  for (;;)
    {
      l = fread(buf, 1, sizeof(buf), fp);
      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
	{
	  pool_debug(pool, SAT_FATAL, "repo_rpmmd: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
	  exit(1);
	}
      if (l == 0)
	break;
    }
  XML_ParserFree(parser);
  sat_free(pd.content);
  sat_free(pd.lastdirstr);
  join_freemem();
  stringpool_free(&pd.cspool);
  sat_free(pd.cscache);

  if (!(flags & REPO_NO_INTERNALIZE))
    repodata_internalize(data);
  POOL_DEBUG(SAT_DEBUG_STATS, "repo_add_rpmmd took %d ms\n", sat_timems(now));
  POOL_DEBUG(SAT_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
  POOL_DEBUG(SAT_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", data->incoredatalen/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
}
Example #2
0
/* edition (e:v-r) compare */
int
pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode)
{
  int r;
  const char *s1, *s2;
  const char *r1, *r2;

  if (evr1 == evr2)
    return 0;

#if 0
  POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode);
#endif
  for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
    ;
  for (s2 = evr2; *s2 >= '0' && *s2 <= '9'; s2++)
    ;
  if (mode == EVRCMP_MATCH && (*evr1 == ':' || *evr2 == ':'))
    {
      /* empty epoch, skip epoch check */
      if (*s1 == ':')
	evr1 = s1 + 1;
      if (*s2 == ':')
	evr2 = s2 + 1;
      s1 = evr1;
      s2 = evr2;
    }
  if (s1 == evr1 || *s1 != ':')
    s1 = 0;
  if (s2 == evr2 || *s2 != ':')
    s2 = 0;
  if (s1 && s2)
    {
      r = vercmp(evr1, s1, evr2, s2);
      if (r)
	return r;
      evr1 = s1 + 1;
      evr2 = s2 + 1;
    }
  else if (s1)
    {
      if (!pool->promoteepoch)
	{
	  while (*evr1 == '0')
	    evr1++;
	  if (*evr1 != ':')
	    return 1;
	}
      evr1 = s1 + 1;
    }
  else if (s2)
    {
      while (*evr2 == '0')
	evr2++;
      if (*evr2 != ':')
	return -1;
      evr2 = s2 + 1;
    }
  for (s1 = evr1, r1 = 0; *s1; s1++)
    if (*s1 == '-')
      r1 = s1;
  for (s2 = evr2, r2 = 0; *s2; s2++)
    if (*s2 == '-')
      r2 = s2;

  r = 0;
  if (mode != EVRCMP_MATCH || (evr1 != (r1 ? r1 : s1) && evr2 != (r2 ? r2 : s2)))
    r = vercmp(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2);
  if (r)
    return r;

  if (mode == EVRCMP_COMPARE)
    {
      if (!r1 && r2)
	return -1;
      if (r1 && !r2)
	return 1;
    }
  if (mode == EVRCMP_COMPARE_EVONLY)
    return 0;
  if (r1 && r2)
    {
      if (s1 != ++r1 && s2 != ++r2)
        r = vercmp(r1, s1, r2, s2);
    }
  return r;
}
Example #3
0
void
pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
{
  Solvable *s;
  Repo *installed, *repo;
  struct searchfiles sf, isf, *isfp;
  struct addfileprovides_cbdata cbd;
  int i;
  unsigned int now;

  installed = pool->installed;
  now = solv_timems(0);
  memset(&cbd, 0, sizeof(cbd));
  memset(&sf, 0, sizeof(sf));
  map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
  memset(&isf, 0, sizeof(isf));
  map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
  pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2;

  if (idq)
    queue_empty(idq);
  if (idqinst)
    queue_empty(idqinst);
  isfp = installed ? &isf : 0;
  for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
    {
      repo = s->repo;
      if (!repo)
	continue;
      if (s->obsoletes)
        pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
      if (s->conflicts)
        pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
      if (s->requires)
        pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
      if (s->recommends)
        pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
      if (s->suggests)
        pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
      if (s->supplements)
        pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
      if (s->enhances)
        pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
    }

  map_free(&sf.seen);
  map_free(&isf.seen);
  POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
  if (sf.nfiles)
    {
#if 0
      for (i = 0; i < sf.nfiles; i++)
	POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i]));
#endif
      FOR_REPOS(i, repo)
        repo_addfileprovides_search(repo, &cbd, &sf);
      if (idq)
	queue_insertn(idq, idq->count, sf.nfiles, sf.ids);
      if (idqinst)
	queue_insertn(idqinst, idqinst->count, sf.nfiles, sf.ids);
      solv_free(sf.ids);
    }
  if (isf.nfiles)
    {
#if 0
      for (i = 0; i < isf.nfiles; i++)
	POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i]));
#endif
      if (installed)
        repo_addfileprovides_search(installed, &cbd, &isf);
      if (installed && idqinst)
        for (i = 0; i < isf.nfiles; i++)
	  queue_pushunique(idqinst, isf.ids[i]);
      solv_free(isf.ids);
    }
  free_dirs_names_array(&cbd);
  solv_free(cbd.dids);
  pool_freewhatprovides(pool);	/* as we have added provides */
  POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now));
}
Example #4
0
File: evr.c Project: korli/libsolv
/* edition (e:v-r) compare */
int
pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode)
{
  int r;
  const char *s1, *s2;
  const char *r1, *r2;

  if (evr1 == evr2)
    return 0;

#if 0
  POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode);
#endif
  for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
    ;
  for (s2 = evr2; *s2 >= '0' && *s2 <= '9'; s2++)
    ;
  if (mode == EVRCMP_MATCH && (*evr1 == ':' || *evr2 == ':'))
    {
      /* empty epoch, skip epoch check */
      if (*s1 == ':')
	evr1 = s1 + 1;
      if (*s2 == ':')
	evr2 = s2 + 1;
      s1 = evr1;
      s2 = evr2;
    }

  /* compare the epoch */
  if (s1 == evr1 || *s1 != ':')
    s1 = 0;
  if (s2 == evr2 || *s2 != ':')
    s2 = 0;
  if (s1 && s2)
    {
      r = solv_vercmp(evr1, s1, evr2, s2);
      if (r)
	return r;
      evr1 = s1 + 1;
      evr2 = s2 + 1;
    }
  else if (s1)
    {
      if (!pool->promoteepoch)
	{
	  while (*evr1 == '0')
	    evr1++;
	  if (*evr1 != ':')
	    return 1;
	}
      evr1 = s1 + 1;
    }
  else if (s2)
    {
      while (*evr2 == '0')
	evr2++;
      if (*evr2 != ':')
	return -1;
      evr2 = s2 + 1;
    }

  /* same epoch, now split into version/release */
  for (s1 = evr1, r1 = 0; *s1; s1++)
    if (*s1 == '-')
      r1 = s1;
  for (s2 = evr2, r2 = 0; *s2; s2++)
    if (*s2 == '-')
      r2 = s2;
  if (pool->disttype == DISTTYPE_HAIKU)
    {
      /* make sure it's really a release, releases always are numeric */
      if (r1 && (r1[1] < '0' || r1[1] > '9'))
	r1 = 0;
      if (r2 && (r2[1] < '0' || r2[1] > '9'))
	r2 = 0;
    }
  r = 0;
  if (mode != EVRCMP_MATCH || (evr1 != (r1 ? r1 : s1) && evr2 != (r2 ? r2 : s2)))
    r = solv_vercmp(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2);
  if (r)
    return r;

  if (mode == EVRCMP_COMPARE)
    {
      if (!r1 && r2)
	return -1;
      if (r1 && !r2)
	return 1;
    }
  if (mode == EVRCMP_COMPARE_EVONLY)
    return 0;
  if (mode == EVRCMP_MATCH_RELEASE)
    {
      /* rpm treats empty releases as missing, i.e "foo = 4-" is the same as "foo = 4" */
      if (r1 && r1 + 1 == s1)
	r1 = 0;
      if (r2 && r2 + 1 == s2)
	r2 = 0;
    }
  if (r1 && r2)
    {
      r1++;
      r2++;
      if (mode != EVRCMP_MATCH || (s1 != r1 && s2 != r2))
	{
	  if (pool->havedistepoch)
	    {
	      const char *d1, *d2;
	      for (d1 = r1; d1 < s1; d1++)
		if (*d1 == ':')
		  break;
	      for (d2 = r2; d2 < s2; d2++)
		if (*d2 == ':')
		  break;
	      /* XXX: promote just in one direction? */
	      r = solv_vercmp(r1, d1 ? d1 : s1, r2, d2 ? d2 : s2);
	      if (r == 0 && d1 < s1 && d2 < s2)
		r = solv_vercmp(d1 + 1, s1, d2 + 1, s2);
	    }
	  else
            r = solv_vercmp(r1, s1, r2, s2);
	}
    }
  else if (mode == EVRCMP_MATCH_RELEASE)
    {
      if (!r1 && r2)
	return -2;
      if (r1 && !r2)
	return 2;
    }
  return r;
}
Example #5
0
static void
refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essentialok)
{
  Pool *pool = solv->pool;
  int i, j;
  Id v;
  Queue disabled;
  int disabledcnt;

  IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
    {
      POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "refine_suggestion start\n");
      for (i = 0; problem[i]; i++)
	{
	  if (problem[i] == sug)
	    POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "=> ");
	  solver_printproblem(solv, problem[i]);
	}
    }
  queue_empty(refined);
  if (!essentialok && sug < 0 && (solv->job.elements[-sug - 1] & SOLVER_ESSENTIAL) != 0)
    return;
  queue_init(&disabled);
  queue_push(refined, sug);

  /* re-enable all problem rules with the exception of "sug"(gestion) */
  solver_reset(solv);

  for (i = 0; problem[i]; i++)
    if (problem[i] != sug)
      solver_enableproblem(solv, problem[i]);

  if (sug < 0)
    solver_reenablepolicyrules(solv, -sug);
  else if (sug >= solv->updaterules && sug < solv->updaterules_end)
    {
      /* enable feature rule */
      Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
      if (r->p)
	solver_enablerule(solv, r);
    }

  enableweakrules(solv);

  for (;;)
    {
      int njob, nfeature, nupdate, pass;
      queue_empty(&solv->problems);
      solver_reset(solv);

      if (!solv->problems.count)
        solver_run_sat(solv, 0, 0);

      if (!solv->problems.count)
	{
	  POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "no more problems!\n");
	  break;		/* great, no more problems */
	}
      disabledcnt = disabled.count;
      /* start with 1 to skip over proof index */
      njob = nfeature = nupdate = 0;
      for (pass = 0; pass < 2; pass++)
	{
	  for (i = 1; i < solv->problems.count - 1; i++)
	    {
	      /* ignore solutions in refined */
	      v = solv->problems.elements[i];
	      if (v == 0)
		break;	/* end of problem reached */
	      if (sug != v)
		{
		  /* check if v is in the given problems list
		   * we allow disabling all problem rules *after* sug in
		   * pass 2, to prevent getting the same solution twice */
		  for (j = 0; problem[j]; j++)
		    if (problem[j] == v || (pass && problem[j] == sug))
		      break;
		  if (problem[j] == v)
		    continue;
		}
	      if (v >= solv->featurerules && v < solv->featurerules_end)
		nfeature++;
	      else if (v > 0)
		nupdate++;
	      else
		{
		  if (!essentialok && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0)
		    continue;	/* not that one! */
		  njob++;
		}
	      queue_push(&disabled, v);
	    }
	  if (disabled.count != disabledcnt)
	    break;
	}
      if (disabled.count == disabledcnt)
	{
	  /* no solution found, this was an invalid suggestion! */
	  POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "no solution found!\n");
	  refined->count = 0;
	  break;
	}
      if (!njob && nupdate && nfeature)
	{
	  /* got only update rules, filter out feature rules */
	  POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "throwing away feature rules\n");
	  for (i = j = disabledcnt; i < disabled.count; i++)
	    {
	      v = disabled.elements[i];
	      if (v < solv->featurerules || v >= solv->featurerules_end)
	        disabled.elements[j++] = v;
	    }
	  disabled.count = j;
	  nfeature = 0;
	}
      if (disabled.count == disabledcnt + 1)
	{
	  /* just one suggestion, add it to refined list */
	  v = disabled.elements[disabledcnt];
	  if (!nfeature && v != sug)
	    queue_push(refined, v);	/* do not record feature rules */
	  solver_disableproblem(solv, v);
	  if (v >= solv->updaterules && v < solv->updaterules_end)
	    {
	      Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
	      if (r->p)
		solver_enablerule(solv, r);	/* enable corresponding feature rule */
	    }
	  if (v < 0)
	    solver_reenablepolicyrules(solv, -v);
	}
      else
	{
	  /* more than one solution, disable all */
	  /* do not push anything on refine list, as we do not know which solution to choose */
	  /* thus, the user will get another problem if he selects this solution, where he
           * can choose the right one */
	  IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
	    {
	      POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "more than one solution found:\n");
	      for (i = disabledcnt; i < disabled.count; i++)
		solver_printproblem(solv, disabled.elements[i]);
	    }
	  for (i = disabledcnt; i < disabled.count; i++)
	    {
	      v = disabled.elements[i];
	      solver_disableproblem(solv, v);
	      if (v >= solv->updaterules && v < solv->updaterules_end)
		{
		  Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
		  if (r->p)
		    solver_enablerule(solv, r);
		}
	    }
	}
    }
  /* all done, get us back into the same state as before */
  /* enable refined rules again */
  for (i = 0; i < disabled.count; i++)
    solver_enableproblem(solv, disabled.elements[i]);
  queue_free(&disabled);
  /* reset policy rules */
  for (i = 0; problem[i]; i++)
    solver_enableproblem(solv, problem[i]);
  solver_disablepolicyrules(solv);
  /* disable problem rules again */
  for (i = 0; problem[i]; i++)
    solver_disableproblem(solv, problem[i]);
  POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "refine_suggestion end\n");
}
Example #6
0
int
repo_add_helix(Repo *repo, FILE *fp, int flags)
{
  Pool *pool = repo->pool;
  Parsedata pd;
  Repodata *data;
  char buf[BUFF_SIZE];
  int i, l;
  struct stateswitch *sw;
  unsigned int now;
  XML_Parser parser;

  now = solv_timems(0);
  data = repo_add_repodata(repo, flags);
  
  /* prepare parsedata */
  memset(&pd, 0, sizeof(pd));
  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
    {
      if (!pd.swtab[sw->from])
        pd.swtab[sw->from] = sw;
      pd.sbtab[sw->to] = sw->from;
    }

  pd.pool = pool;
  pd.repo = repo;

  pd.content = (char *)malloc(256);	/* must hold all solvable kinds! */
  pd.acontent = 256;
  pd.lcontent = 0;

  pd.evrspace = (char *)malloc(256);
  pd.aevrspace= 256;
  pd.levrspace = 1;
  pd.data = data;

  /* set up XML parser */

  parser = XML_ParserCreate(NULL);
  XML_SetUserData(parser, &pd);       /* make parserdata available to XML callbacks */
  XML_SetElementHandler(parser, startElement, endElement);
  XML_SetCharacterDataHandler(parser, characterData);

  /* read/parse XML file */
  for (;;)
    {
      l = fread(buf, 1, sizeof(buf), fp);
      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
	{
	  pd.ret = pool_error(pool, -1, "%s at line %u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser));
	  break;
	}
      if (l == 0)
	break;
    }
  XML_ParserFree(parser);
  free(pd.content);
  free(pd.evrspace);

  if (!(flags & REPO_NO_INTERNALIZE))
    repodata_internalize(data);
  POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_helix took %d ms\n", solv_timems(now));
  POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
  POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", repodata_memused(data)/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
  return pd.ret;
}
Example #7
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;
}