Imported Upstream version 0.6.11
[platform/upstream/libsolv.git] / src / pool.c
index 981c767..f78f71a 100644 (file)
@@ -30,6 +30,7 @@
 
 #define SOLVABLE_BLOCK 255
 
+#undef LIBSOLV_KNOWNID_H
 #define KNOWNID_INITIALIZE
 #include "knownid.h"
 #undef KNOWNID_INITIALIZE
@@ -117,7 +118,7 @@ pool_free(Pool *pool)
     solv_free(pool->tmpspace.buf[i]);
   for (i = 0; i < pool->nlanguages; i++)
     free((char *)pool->languages[i]);
-  solv_free(pool->languages);
+  solv_free((void *)pool->languages);
   solv_free(pool->languagecache);
   solv_free(pool->errstr);
   solv_free(pool->rootdir);
@@ -140,22 +141,33 @@ pool_freeallrepos(Pool *pool, int reuseids)
   pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
 }
 
-#ifdef MULTI_SEMANTICS
-void
+int
 pool_setdisttype(Pool *pool, int disttype)
 {
+#ifdef MULTI_SEMANTICS
+  int olddisttype = pool->disttype;
+  switch(disttype)
+    {
+    case DISTTYPE_RPM:
+      pool->noarchid = ARCH_NOARCH;
+      break;
+    case DISTTYPE_DEB:
+      pool->noarchid = ARCH_ALL;
+      break;
+    case DISTTYPE_ARCH:
+    case DISTTYPE_HAIKU:
+      pool->noarchid = ARCH_ANY;
+      break;
+    default:
+      return -1;
+    }
   pool->disttype = disttype;
-  if (disttype == DISTTYPE_RPM)
-    pool->noarchid = ARCH_NOARCH;
-  if (disttype == DISTTYPE_DEB)
-    pool->noarchid = ARCH_ALL;
-  if (disttype == DISTTYPE_ARCH)
-    pool->noarchid = ARCH_ANY;
-  if (disttype == DISTTYPE_HAIKU)
-    pool->noarchid = ARCH_ANY;
   pool->solvables[SYSTEMSOLVABLE].arch = pool->noarchid;
-}
+  return olddisttype;
+#else
+  return pool->disttype == disttype ? disttype : -1;
 #endif
+}
 
 int
 pool_get_flag(Pool *pool, int flag)
@@ -182,6 +194,8 @@ pool_get_flag(Pool *pool, int flag)
       return pool->noobsoletesmultiversion;
     case POOL_FLAG_ADDFILEPROVIDESFILTERED:
       return pool->addfileprovidesfiltered;
+    case POOL_FLAG_NOWHATPROVIDESAUX:
+      return pool->nowhatprovidesaux;
     default:
       break;
     }
@@ -224,6 +238,9 @@ pool_set_flag(Pool *pool, int flag, int value)
     case POOL_FLAG_ADDFILEPROVIDESFILTERED:
       pool->addfileprovidesfiltered = value;
       break;
+    case POOL_FLAG_NOWHATPROVIDESAUX:
+      pool->nowhatprovidesaux = value;
+      break;
     default:
       break;
     }
@@ -381,6 +398,34 @@ pool_shrink_whatprovides(Pool *pool)
   memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
 }
 
+/* this gets rid of all the zeros in the aux */
+static void
+pool_shrink_whatprovidesaux(Pool *pool)
+{
+  int num = pool->whatprovidesauxoff;
+  Id id;
+  Offset newoff;
+  Id *op, *wp = pool->whatprovidesauxdata + 1;
+  int i;
+
+  for (i = 0; i < num; i++)
+    {
+      Offset o = pool->whatprovidesaux[i];
+      if (o < 2)
+       continue;
+      op = pool->whatprovidesauxdata + o;
+      pool->whatprovidesaux[i] = wp - pool->whatprovidesauxdata;
+      if (op < wp)
+       abort();
+      while ((id = *op++) != 0)
+       *wp++ = id;
+    }
+  newoff = wp - pool->whatprovidesauxdata;
+  solv_realloc(pool->whatprovidesauxdata, newoff * sizeof(Id));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "shrunk whatprovidesauxdata from %d to %d\n", pool->whatprovidesauxdataoff, newoff);
+  pool->whatprovidesauxdataoff = newoff;
+}
+
 
 /*
  * pool_createwhatprovides()
@@ -397,7 +442,8 @@ pool_createwhatprovides(Pool *pool)
   Id id;
   Offset *idp, n;
   Offset *whatprovides;
-  Id *whatprovidesdata, *d;
+  Id *whatprovidesdata, *dp, *whatprovidesauxdata;
+  Offset *whatprovidesaux;
   Repo *installed = pool->installed;
   unsigned int now;
 
@@ -465,6 +511,16 @@ pool_createwhatprovides(Pool *pool)
   whatprovidesdata = solv_calloc(off + extra, sizeof(Id));
   whatprovidesdata[2] = SYSTEMSOLVABLE;
 
+  /* alloc aux vector */
+  whatprovidesauxdata = 0;
+  if (!pool->nowhatprovidesaux)
+    {
+      pool->whatprovidesaux = whatprovidesaux = solv_calloc(num, sizeof(Offset));
+      pool->whatprovidesauxoff = num;
+      pool->whatprovidesauxdataoff = off;
+      pool->whatprovidesauxdata = whatprovidesauxdata = solv_calloc(pool->whatprovidesauxdataoff, sizeof(Id));
+    }
+
   /* now fill data for all provides */
   for (i = pool->nsolvables - 1; i > 0; i--)
     {
@@ -479,24 +535,35 @@ pool_createwhatprovides(Pool *pool)
       pp = s->repo->idarraydata + s->provides;
       while ((id = *pp++) != 0)
        {
+         Id auxid = id;
          while (ISRELDEP(id))
            {
              Reldep *rd = GETRELDEP(pool, id);
              id = rd->name;
            }
-         d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
-         if (*d != i)          /* don't add same solvable twice */
+         dp = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
+         if (*dp != i)         /* don't add same solvable twice */
            {
-             d[-1] = i;
+             dp[-1] = i;
              whatprovides[id]--;
            }
+         else
+           auxid = 1;
+         if (whatprovidesauxdata)
+           whatprovidesauxdata[whatprovides[id]] = auxid;
        }
     }
+  if (pool->whatprovidesaux)
+    memcpy(pool->whatprovidesaux, pool->whatprovides, num * sizeof(Id));
   pool->whatprovidesdata = whatprovidesdata;
   pool->whatprovidesdataoff = off;
   pool->whatprovidesdataleft = extra;
   pool_shrink_whatprovides(pool);
+  if (pool->whatprovidesaux)
+    pool_shrink_whatprovidesaux(pool);
   POOL_DEBUG(SOLV_DEBUG_STATS, "whatprovides memory used: %d K id array, %d K data\n", (pool->ss.nstrings + pool->nrels + WHATPROVIDES_BLOCK) / (int)(1024/sizeof(Id)), (pool->whatprovidesdataoff + pool->whatprovidesdataleft) / (int)(1024/sizeof(Id)));
+  if (pool->whatprovidesaux)
+    POOL_DEBUG(SOLV_DEBUG_STATS, "whatprovidesaux memory used: %d K id array, %d K data\n", pool->whatprovidesauxoff / (int)(1024/sizeof(Id)), pool->whatprovidesauxdataoff / (int)(1024/sizeof(Id)));
 
   queue_empty(&pool->lazywhatprovidesq);
   if ((!pool->addedfileprovides && pool->disttype == DISTTYPE_RPM) || pool->addedfileprovides == 1)
@@ -515,6 +582,8 @@ pool_createwhatprovides(Pool *pool)
          if (pool->whatprovides[i] > 1)
            queue_push2(&pool->lazywhatprovidesq, i, pool->whatprovides[i]);
          pool->whatprovides[i] = 0;
+         if (pool->whatprovidesaux)
+           pool->whatprovidesaux[i] = 0;       /* sorry */
        }
       POOL_DEBUG(SOLV_DEBUG_STATS, "lazywhatprovidesq size: %d entries\n", pool->lazywhatprovidesq.count / 2);
     }
@@ -535,6 +604,10 @@ pool_freewhatprovides(Pool *pool)
   pool->whatprovidesdata = solv_free(pool->whatprovidesdata);
   pool->whatprovidesdataoff = 0;
   pool->whatprovidesdataleft = 0;
+  pool->whatprovidesaux = solv_free(pool->whatprovidesaux);
+  pool->whatprovidesauxdata = solv_free(pool->whatprovidesauxdata);
+  pool->whatprovidesauxoff = 0;
+  pool->whatprovidesauxdataoff = 0;
 }
 
 
@@ -548,15 +621,15 @@ pool_freewhatprovides(Pool *pool)
  * returns: Offset into whatprovidesdata
  *
  */
+
 Id
-pool_queuetowhatprovides(Pool *pool, Queue *q)
+pool_ids2whatprovides(Pool *pool, Id *ids, int count)
 {
   Offset off;
-  int count = q->count;
 
   if (count == 0)                     /* queue empty -> 1 */
     return 1;
-  if (count == 1 && q->elements[0] == SYSTEMSOLVABLE)
+  if (count == 1 && *ids == SYSTEMSOLVABLE)
     return 2;
 
   /* extend whatprovidesdata if needed, +1 for 0-termination */
@@ -569,7 +642,7 @@ pool_queuetowhatprovides(Pool *pool, Queue *q)
 
   /* copy queue to next free slot */
   off = pool->whatprovidesdataoff;
-  memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
+  memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, ids, count * sizeof(Id));
 
   /* adapt count and 0-terminate */
   pool->whatprovidesdataoff += count;
@@ -579,6 +652,17 @@ pool_queuetowhatprovides(Pool *pool, Queue *q)
   return (Id)off;
 }
 
+Id
+pool_queuetowhatprovides(Pool *pool, Queue *q)
+{
+  int count = q->count;
+  if (count == 0)                     /* queue empty -> 1 */
+    return 1;
+  if (count == 1 && q->elements[0] == SYSTEMSOLVABLE)
+    return 2;
+  return pool_ids2whatprovides(pool, q->elements, count);
+}
+
 
 /*************************************************************************/
 
@@ -879,6 +963,10 @@ pool_is_kind(Pool *pool, Id name, Id kind)
  *
  * add packages fulfilling the relation to whatprovides array
  *
+ * some words about REL_AND and REL_IF: we assume the best case
+ * here, so that you get a "potential" result if you ask for a match.
+ * E.g. if you ask for "whatrequires A" and package X contains
+ * "Requires: A & B", you'll get "X" as an answer.
  */
 Id
 pool_addrelproviders(Pool *pool, Id d)
@@ -908,7 +996,6 @@ pool_addrelproviders(Pool *pool, Id d)
 
       switch (flags)
        {
-       case REL_AND:
        case REL_WITH:
          wp = pool_whatprovides(pool, name);
          pp2 = pool_whatprovides_ptr(pool, evr);
@@ -924,24 +1011,43 @@ pool_addrelproviders(Pool *pool, Id d)
                wp = 0;
            }
          break;
+
+       case REL_AND:
        case REL_OR:
          wp = pool_whatprovides(pool, name);
-         pp = pool->whatprovidesdata + wp;
-         if (!*pp)
+         if (!pool->whatprovidesdata[wp])
            wp = pool_whatprovides(pool, evr);
          else
            {
-             int cnt;
-             while ((p = *pp++) != 0)
-               queue_push(&plist, p);
-             cnt = plist.count;
-             pp = pool_whatprovides_ptr(pool, evr);
-             while ((p = *pp++) != 0)
-               queue_pushunique(&plist, p);
-             if (plist.count != cnt)
+             /* sorted merge */
+             pp2 = pool_whatprovides_ptr(pool, evr);
+             pp = pool->whatprovidesdata + wp;
+             while (*pp && *pp2)
+               {
+                 if (*pp < *pp2)
+                   queue_push(&plist, *pp++);
+                 else
+                   {
+                     if (*pp == *pp2)
+                       pp++;
+                     queue_push(&plist, *pp2++);
+                   }
+               }
+             while (*pp)
+               queue_push(&plist, *pp++);
+             while (*pp2)
+               queue_push(&plist, *pp2++);
+             /* if the number of elements did not change, we can reuse wp */
+             if (pp - (pool->whatprovidesdata + wp) != plist.count)
                wp = 0;
            }
          break;
+
+       case REL_COND:
+         /* assume the condition is true */
+         wp = pool_whatprovides(pool, name);
+         break;
+
        case REL_NAMESPACE:
          if (name == NAMESPACE_OTHERPROVIDERS)
            {
@@ -1066,11 +1172,14 @@ pool_addrelproviders(Pool *pool, Id d)
     }
   else if (flags)
     {
+      Id *ppaux = 0;
       /* simple version comparison relation */
 #if 0
       POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: what provides %s?\n", pool_dep2str(pool, name));
 #endif
       pp = pool_whatprovides_ptr(pool, name);
+      if (!ISRELDEP(name) && name < pool->whatprovidesauxoff)
+       ppaux = pool->whatprovidesaux[name] ? pool->whatprovidesauxdata + pool->whatprovidesaux[name] : 0;
       while (ISRELDEP(name))
        {
           rd = GETRELDEP(pool, name);
@@ -1079,6 +1188,34 @@ pool_addrelproviders(Pool *pool, Id d)
       while ((p = *pp++) != 0)
        {
          Solvable *s = pool->solvables + p;
+         if (ppaux)
+           {
+             pid = *ppaux++;
+             if (pid && pid != 1)
+               {
+#if 0
+                 POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: aux hit %d %s\n", p, pool_dep2str(pool, pid));
+#endif
+                 if (!ISRELDEP(pid))
+                   {
+                     if (pid != name)
+                       continue;               /* wrong provides name */
+                     if (pool->disttype == DISTTYPE_DEB)
+                       continue;               /* unversioned provides can never match versioned deps */
+                   }
+                 else
+                   {
+                     prd = GETRELDEP(pool, pid);
+                     if (prd->name != name)
+                       continue;               /* wrong provides name */
+                     /* right package, both deps are rels. check flags/evr */
+                     if (!pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
+                       continue;
+                   }
+                 queue_push(&plist, p);
+                 continue;
+               }
+           }
          if (!s->provides)
            {
              /* no provides - check nevr */
@@ -1273,8 +1410,6 @@ void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id,
 
 struct searchfiles {
   Id *ids;
-  char **dirs;
-  char **names;
   int nfiles;
   Map seen;
 };
@@ -1285,7 +1420,7 @@ static void
 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
 {
   Id dep, sid;
-  const char *s, *sr;
+  const char *s;
   struct searchfiles *csf;
 
   while ((dep = *ida++) != 0)
@@ -1306,7 +1441,7 @@ pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct sea
            dep = rd->name;
          else if (rd->flags == REL_NAMESPACE)
            {
-             if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES)
+             if (rd->name == NAMESPACE_SPLITPROVIDES)
                {
                  csf = isf;
                  if (!csf || MAPTST(&csf->seen, sid))
@@ -1343,16 +1478,7 @@ pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct sea
       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->dirs = solv_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
-      csf->names = solv_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
-      csf->ids[csf->nfiles] = dep;
-      sr = strrchr(s, '/');
-      csf->names[csf->nfiles] = solv_strdup(sr + 1);
-      csf->dirs[csf->nfiles] = solv_malloc(sr - s + 1);
-      if (sr != s)
-        strncpy(csf->dirs[csf->nfiles], s, sr - s);
-      csf->dirs[csf->nfiles][sr - s] = 0;
-      csf->nfiles++;
+      csf->ids[csf->nfiles++] = dep;
     }
 }
 
@@ -1378,6 +1504,19 @@ addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyV
   if (!cbd->useddirs.size)
     {
       map_init(&cbd->useddirs, data->dirpool.ndirs + 1);
+      if (!cbd->dirs)
+       {
+         cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *));
+         cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *));
+         for (i = 0; i < cbd->nfiles; i++)
+           {
+             char *s = solv_strdup(pool_id2str(data->repo->pool, cbd->ids[i]));
+             cbd->dirs[i] = s;
+             s = strrchr(s, '/');
+             *s = 0;
+             cbd->names[i] = s + 1;
+           }
+       }
       for (i = 0; i < cbd->nfiles; i++)
        {
          Id did;
@@ -1396,15 +1535,8 @@ addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyV
   if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id))
     return 0;
   for (i = 0; i < cbd->nfiles; i++)
-    {
-      if (cbd->dids[i] != value->id)
-       continue;
-      if (!strcmp(cbd->names[i], value->str))
-       break;
-    }
-  if (i == cbd->nfiles)
-    return 0;
-  s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
+    if (cbd->dids[i] == value->id && !strcmp(cbd->names[i], value->str))
+      s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
   return 0;
 }
 
@@ -1425,8 +1557,8 @@ pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, stru
 
   cbd->nfiles = sf->nfiles;
   cbd->ids = sf->ids;
-  cbd->dirs = sf->dirs;
-  cbd->names = sf->names;
+  cbd->dirs = 0;
+  cbd->names = 0;
   cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
   map_init(&cbd->providedids, pool->ss.nstrings);
 
@@ -1530,6 +1662,13 @@ pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, stru
   map_free(&donemap);
   queue_free(&fileprovidesq);
   map_free(&cbd->providedids);
+  if (cbd->dirs)
+    {
+      for (i = 0; i < cbd->nfiles; i++)
+       solv_free(cbd->dirs[i]);
+      cbd->dirs = solv_free(cbd->dirs);
+      cbd->names = solv_free(cbd->names);
+    }
 }
 
 void
@@ -1593,13 +1732,6 @@ pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
         for (i = 0; i < sf.nfiles; i++)
          queue_push(idqinst, sf.ids[i]);
       solv_free(sf.ids);
-      for (i = 0; i < sf.nfiles; i++)
-       {
-         solv_free(sf.dirs[i]);
-         solv_free(sf.names[i]);
-       }
-      solv_free(sf.dirs);
-      solv_free(sf.names);
     }
   if (isf.nfiles)
     {
@@ -1613,13 +1745,6 @@ pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
         for (i = 0; i < isf.nfiles; i++)
          queue_pushunique(idqinst, isf.ids[i]);
       solv_free(isf.ids);
-      for (i = 0; i < isf.nfiles; i++)
-       {
-         solv_free(isf.dirs[i]);
-         solv_free(isf.names[i]);
-       }
-      solv_free(isf.dirs);
-      solv_free(isf.names);
     }
   solv_free(cbd.dids);
   pool_freewhatprovides(pool); /* as we have added provides */
@@ -1663,7 +1788,7 @@ pool_set_languages(Pool *pool, const char **languages, int nlanguages)
   pool->languagecacheother = 0;
   for (i = 0; i < pool->nlanguages; i++)
     free((char *)pool->languages[i]);
-  pool->languages = solv_free(pool->languages);
+  pool->languages = solv_free((void *)pool->languages);
   pool->nlanguages = nlanguages;
   if (!nlanguages)
     return;
@@ -1911,7 +2036,7 @@ solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyVa
       cbd->mps[mp].kbytes += value->num;
       cbd->mps[mp].files += value->num2;
     }
-  else
+  else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD))
     {
       cbd->mps[mp].kbytes -= value->num;
       cbd->mps[mp].files -= value->num2;
@@ -2019,13 +2144,17 @@ pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
   struct mptree *mptree;
   struct ducbdata cbd;
   Solvable *s;
-  int sp;
+  int i, sp;
   Map ignoredu;
   Repo *oldinstalled = pool->installed;
+  int haveonlyadd = 0;
 
   map_init(&ignoredu, 0);
   mptree = create_mptree(mps, nmps);
 
+  for (i = 0; i < nmps; i++)
+    if ((mps[i].flags & DUCHANGES_ONLYADD) != 0)
+      haveonlyadd = 1;
   cbd.mps = mps;
   cbd.dirmap = 0;
   cbd.nmap = 0;
@@ -2043,21 +2172,55 @@ pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
       if (!cbd.hasdu && oldinstalled)
        {
          Id op, opp;
+         int didonlyadd = 0;
          /* no du data available, ignore data of all installed solvables we obsolete */
          if (!ignoredu.size)
            map_grow(&ignoredu, oldinstalled->end - oldinstalled->start);
+         FOR_PROVIDES(op, opp, s->name)
+           {
+             Solvable *s2 = pool->solvables + op;
+             if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
+               continue;
+             if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
+               continue;
+             if (op >= oldinstalled->start && op < oldinstalled->end)
+               {
+                 MAPSET(&ignoredu, op - oldinstalled->start);
+                 if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd)
+                   {
+                     repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
+                     cbd.addsub = -1;
+                     repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
+                     cbd.addsub = 1;
+                     didonlyadd = 1;
+                   }
+               }
+           }
          if (s->obsoletes)
            {
              Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
              while ((obs = *obsp++) != 0)
                FOR_PROVIDES(op, opp, obs)
-                 if (op >= oldinstalled->start && op < oldinstalled->end)
-                   MAPSET(&ignoredu, op - oldinstalled->start);
+                 {
+                   Solvable *s2 = pool->solvables + op;
+                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs))
+                     continue;
+                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+                     continue;
+                   if (op >= oldinstalled->start && op < oldinstalled->end)
+                     {
+                       MAPSET(&ignoredu, op - oldinstalled->start);
+                       if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd)
+                         {
+                           repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
+                           cbd.addsub = -1;
+                           repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
+                           cbd.addsub = 1;
+                           didonlyadd = 1;
+                         }
+                     }
+                 }
            }
-         FOR_PROVIDES(op, opp, s->name)
-           if (pool->solvables[op].name == s->name)
-             if (op >= oldinstalled->start && op < oldinstalled->end)
-               MAPSET(&ignoredu, op - oldinstalled->start);
        }
     }
   cbd.addsub = -1;
@@ -2439,6 +2602,8 @@ add_new_provider(Pool *pool, Id id, Id p)
   if (p)
     queue_push(&q, p);
   pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
+  if (id < pool->whatprovidesauxoff)
+    pool->whatprovidesaux[id] = 0;     /* sorry */
   queue_free(&q);
 }