Esempio n. 1
0
int
repo_lookup_deparray(Repo *repo, Id entry, Id keyname, Queue *q, Id marker)
{
  int r = repo_lookup_idarray(repo, entry, keyname, q);
  if (r && marker)
    {
      int i;
      if (marker < 0)
	{
	  marker = -marker;
	  for (i = 0; i < q->count; i++)
	    if (q->elements[i] == marker)
	      {
		queue_truncate(q, i);
		return r;
	      }
	}
      else
	{
	  for (i = 0; i < q->count; i++)
	    if (q->elements[i] == marker)
	      {
		queue_deleten(q, 0, i + 1);
		return r;
	      }
	}
    }
  return r;
}
Esempio n. 2
0
void
transaction_all_obs_pkgs(Transaction *trans, Id p, Queue *pkgs)
{
  Pool *pool = trans->pool;
  Solvable *s = pool->solvables + p;
  Queue *ti = &trans->transaction_info;
  Id q;
  int i;

  queue_empty(pkgs);
  if (p <= 0 || !s->repo)
    return;
  if (s->repo == pool->installed)
    {
      q = trans->transaction_installed[p - pool->installed->start];
      if (!q)
	return;
      if (q > 0)
	{
	  /* only a single obsoleting package */
	  queue_push(pkgs, q);
	  return;
	}
      /* find which packages obsolete us */
      for (i = 0; i < ti->count; i += 2)
	if (ti->elements[i + 1] == p)
	  queue_push2(pkgs, p, ti->elements[i]);
      /* sort obsoleters */
      if (pkgs->count > 2)
	solv_sort(pkgs->elements, pkgs->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool);
      for (i = 0; i < pkgs->count; i += 2)
	pkgs->elements[i / 2] = pkgs->elements[i + 1];
      queue_truncate(pkgs, pkgs->count / 2);
    }
  else
    {
      /* find the packages we obsolete */
      for (i = 0; i < ti->count; i += 2)
	{
	  if (ti->elements[i] == p)
	    queue_push(pkgs, ti->elements[i + 1]);
	  else if (pkgs->count)
	    break;
	}
    }
}
Esempio n. 3
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;
}
Esempio n. 4
0
/*
 * returns:
 *   0: no blocks
 *   1: matches all
 *  -1: at least one block
 */
static int
normalize_dep(Pool *pool, Id dep, Queue *bq, int flags)
{
  int bqcnt = bq->count;
  int bqcnt2;
  int todnf = flags & CPLXDEPS_TODNF ? 1 : 0;
  Id p, dp;

#ifdef CPLXDEBUG
  printf("normalize_dep %s todnf:%d\n", pool_dep2str(pool, dep), todnf);
#endif
  if (pool_is_complex_dep(pool, dep))
    {
      Reldep *rd = GETRELDEP(pool, dep);
      if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_COND)
	{
	  int rdflags = rd->flags;
	  Id name = rd->name;
	  Id evr = rd->evr;
	  int r, mode;
	  
          if (rdflags == REL_COND)
	    {
	      /* check for relly complex ELSE case */
	      if (ISRELDEP(evr))
		{
		  Reldep *rd2 = GETRELDEP(pool, evr);
		  if (rd2->flags == REL_ELSE)
		    {
		      int r2;
		      /* really complex case */
		      if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_AND_1)
			{
			  /* A OR ~B */
			  rdflags = REL_COND;
			  evr = rd2->name;
			}
		      else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_AND_2)
			{
			  /* C OR B */
			  rdflags = REL_OR;
			  name = rd2->evr;
			  evr = rd2->name;
			}
		      else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_1)
			{
			  /* A AND B */
			  rdflags = REL_AND;
			  evr = rd2->name;
			}
		      else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_2)
			{
			  /* A AND C */
			  rdflags = REL_AND;
			  evr = rd2->evr;
			}
		      else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_3)
			{
			  /* C AND ~B */
			  rdflags = REL_ELSE;
			  name = rd2->evr;
			  evr = rd2->name;
			}
		      else if (!todnf)
			{
			  /* we want AND: A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */
			  r = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_AND_1);
			  if (r == 0 && (flags & CPLXDEPS_DONTFIX) == 0)
			    return 0;
			  r2 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_AND_2);
			  if (r2 == 0 && (flags & CPLXDEPS_DONTFIX) == 0)
			    {
			      queue_truncate(bq, bqcnt);
			      return 0;
			    }
			  if (r == -1 || r2 == -1)
			    return -1;
			  return r == 1 || r2 == 1 ? 1 : 0;
			}
		      else
			{
			  int r2, r3;
			  /* we want OR: A IF (B ELSE C) -> (A AND B) OR (A AND C) OR (~B AND C) */
			  r = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_1);
			  if (r == 1)
			    return 1;
			  r2 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_2);
			  if (r2 == 1)
			    {
			      queue_truncate(bq, bqcnt);
			      return 1;
			    }
			  r3 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_3);
			  if (r3 == 1)
			    {
			      queue_truncate(bq, bqcnt);
			      return 1;
			    }
			  if (r == -1 || r2 == -1 || r3 == -1)
			    return -1;
			  return 0;
			}
		    }
		}
	    }
	  mode = rdflags == REL_AND || rdflags == REL_ELSE ? 0 : 1;

	  /* get blocks of first argument */
	  r = normalize_dep(pool, name, bq, flags);
	  if (r == 0)
	    {
	      if (rdflags == REL_ELSE)
		return 0;
	      if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) == 0)
		return 0;
	      if (rdflags == REL_COND)
		{
		  r = normalize_dep(pool, evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX);
		  return invert_depblocks(pool, bq, bqcnt, r);	/* invert block for COND */
		}
	      return normalize_dep(pool, evr, bq, flags);
	    }
	  if (r == 1)
	    {
	      if (rdflags == REL_ELSE)
		{
		  r = normalize_dep(pool, evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX);
		  return invert_depblocks(pool, bq, bqcnt, r);	/* invert block for ELSE */
		}
	      if (rdflags == REL_OR || rdflags == REL_COND)
		return 1;
	      return normalize_dep(pool, evr, bq, flags);
	    }

	  /* get blocks of second argument */
	  bqcnt2 = bq->count;
	  /* COND is OR with NEG on evr block, so we invert the todnf flag in that case */
	  r = normalize_dep(pool, evr, bq, rdflags == REL_COND || rdflags == REL_ELSE ? ((flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX) : flags);
	  if (rdflags == REL_COND || rdflags == REL_ELSE)
	    r = invert_depblocks(pool, bq, bqcnt2, r);	/* invert 2nd block */
	  if (r == 0)
	    {
	      if (rdflags == REL_OR)
		return -1;
	      if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) != 0)
		return -1;
	      queue_truncate(bq, bqcnt);
	      return 0;
	    }
	  if (r == 1)
	    {
	      if (rdflags == REL_COND || rdflags == REL_OR)
		{
		  queue_truncate(bq, bqcnt);
		  return 1;
		}
	      return -1;
	    }
	  if (mode == todnf)
	    {
	      /* simple case: just join em. nothing more to do here. */
#ifdef CPLXDEBUG
	      printf("SIMPLE JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count);
#endif
	      return -1;
	    }
	  else
	    {
	      /* complex case: mix em */
	      int i, j, bqcnt3;
#ifdef CPLXDEBUG
	      printf("COMPLEX JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count);
#endif
	      bqcnt2 = expand_simpledeps(pool, bq, bqcnt, bqcnt2);
	      bqcnt3 = bq->count;
	      for (i = bqcnt; i < bqcnt2; i++)
		{
		  for (j = bqcnt2; j < bqcnt3; j++)
		    {
		      int a, b;
		      int bqcnt4 = bq->count;
		      int k = i;

		      /* mix i block with j block, both blocks are sorted */
		      while (bq->elements[k] && bq->elements[j])
			{
			  if (bq->elements[k] < bq->elements[j])
			    queue_push(bq, bq->elements[k++]);
			  else
			    {
			      if (bq->elements[k] == bq->elements[j])
				k++;
			      queue_push(bq, bq->elements[j++]);
			    }
			}
		      while (bq->elements[j])
			queue_push(bq, bq->elements[j++]);
		      while (bq->elements[k])
			queue_push(bq, bq->elements[k++]);

		      /* block is finished, check for A + -A */
		      for (a = bqcnt4, b = bq->count - 1; a < b; )
			{
			  if (-bq->elements[a] == bq->elements[b])
			    break;
			  if (-bq->elements[a] > bq->elements[b])
			    a++;
			  else
			    b--;
			}
		      if (a < b)
			queue_truncate(bq, bqcnt4);	/* ignore this block */
		      else
			queue_push(bq, 0);	/* finish block */
		    }
		  /* advance to next block */
		  while (bq->elements[i])
		    i++;
		}
	      i = -1;
	      if (bqcnt3 == bq->count)	/* ignored all blocks? */
		i = todnf ? 0 : 1;
	      queue_deleten(bq, bqcnt, bqcnt3 - bqcnt);
	      return i;
	    }
	}
    }

  /* fallback case: just use package list */
  dp = pool_whatprovides(pool, dep);
  if (dp <= 2 || !pool->whatprovidesdata[dp])
    return dp == 2 ? 1 : 0;
  if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE)
    return 1;
  bqcnt = bq->count;
  if ((flags & CPLXDEPS_NAME) != 0)
    {
      while ((p = pool->whatprovidesdata[dp++]) != 0)
	{
	  if (!pool_match_nevr(pool, pool->solvables + p, dep))
	    continue;
	  queue_push(bq, p);
	  if (todnf)
	    queue_push(bq, 0);
	}
    }
  else if (todnf)
    {
      while ((p = pool->whatprovidesdata[dp++]) != 0)
        queue_push2(bq, p, 0);
    }
  else
    queue_push2(bq, pool->nsolvables, dp);	/* not yet expanded marker + offset */
  if (bq->count == bqcnt)
    return 0;	/* no provider */
  if (!todnf)
    queue_push(bq, 0);	/* finish block */
  return -1;
}