Imported Upstream version 0.6.5
[platform/upstream/libsolv.git] / src / pool.c
index 437e53d..8dff38a 100644 (file)
@@ -7,7 +7,7 @@
 
 /*
  * pool.c
- * 
+ *
  * The pool contains information about solvables
  * stored optimized for memory consumption and fast retrieval.
  */
@@ -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);
@@ -130,12 +131,12 @@ pool_freeallrepos(Pool *pool, int reuseids)
   int i;
 
   pool_freewhatprovides(pool);
-  for (i = 1; i < pool->nrepos; i++) 
+  for (i = 1; i < pool->nrepos; i++)
     if (pool->repos[i])
       repo_freedata(pool->repos[i]);
   pool->repos = solv_free(pool->repos);
-  pool->nrepos = 0; 
-  pool->urepos = 0; 
+  pool->nrepos = 0;
+  pool->urepos = 0;
   /* the first two solvables don't belong to a repo */
   pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
 }
@@ -384,9 +385,9 @@ pool_shrink_whatprovides(Pool *pool)
 
 /*
  * pool_createwhatprovides()
- * 
+ *
  * create hashes over pool of solvables to ease provide lookups
- * 
+ *
  */
 void
 pool_createwhatprovides(Pool *pool)
@@ -542,7 +543,7 @@ pool_freewhatprovides(Pool *pool)
 
 /*
  * pool_queuetowhatprovides  - add queue contents to whatprovidesdata
- * 
+ *
  * used for whatprovides, jobs, learnt rules, selections
  * input: q: queue of Ids
  * returns: Offset into whatprovidesdata
@@ -591,6 +592,7 @@ pool_queuetowhatprovides(Pool *pool, Queue *q)
 #endif
 
 /* check if a package's nevr matches a dependency */
+/* semi-private, called from public pool_match_nevr */
 
 int
 pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
@@ -620,6 +622,11 @@ pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
          if (!pool_match_nevr(pool, s, name))
            return 0;
          return pool_match_nevr(pool, s, evr);
+       case REL_MULTIARCH:
+         if (evr != ARCH_ANY)
+           return 0;
+         /* XXX : need to check for Multi-Arch: allowed! */
+         return pool_match_nevr(pool, s, name);
        default:
          return 0;
        }
@@ -707,6 +714,13 @@ pool_match_flags_evr_rel_compat(Pool *pool, Reldep *range, int flags, int evr)
 }
 #endif
 
+/* public (i.e. not inlined) version of pool_match_flags_evr */
+int
+pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, int evr)
+{
+  return pool_match_flags_evr(pool, pflags, pevr, flags, evr);
+}
+
 /* match two dependencies (d1 = provider) */
 
 int
@@ -733,7 +747,7 @@ pool_match_dep(Pool *pool, Id d1, Id d2)
   if (!pool_match_dep(pool, rd1->name, rd2->name))
     return 0;
   /* name matches, check flags and evr */
-  return pool_match_flags_evr(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
+  return pool_intersect_evrs(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
 }
 
 Id
@@ -763,7 +777,7 @@ pool_searchlazywhatprovidesq(Pool *pool, Id d)
 
 /*
  * addstdproviders
- * 
+ *
  * lazy populating of the whatprovides array, non relation case
  */
 static Id
@@ -838,11 +852,38 @@ pool_addstdproviders(Pool *pool, Id d)
 }
 
 
+static inline int
+pool_is_kind(Pool *pool, Id name, Id kind)
+{
+  const char *n;
+  if (!kind)
+    return 1;
+  n = pool_id2str(pool, name);
+  if (kind != 1)
+    {
+      const char *kn = pool_id2str(pool, kind);
+      int knl = strlen(kn);
+      return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0;
+    }
+  else
+    {
+      if (*n == ':')
+       return 1;
+      while(*n >= 'a' && *n <= 'z')
+       n++;
+      return *n == ':' ? 0 : 1;
+    }
+}
+
 /*
  * addrelproviders
- * 
+ *
  * 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)
@@ -872,7 +913,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);
@@ -888,24 +928,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)
            {
@@ -942,7 +1001,19 @@ pool_addrelproviders(Pool *pool, Id d)
                    continue;
                  if (pool_disabled_solvable(pool, s))
                    continue;
-                 if (pool_match_nevr(pool, s, name))
+                 if (!name || pool_match_nevr(pool, s, name))
+                   queue_push(&plist, p);
+               }
+             break;
+           }
+         if (!name)
+           {
+             FOR_POOL_SOLVABLES(p)
+               {
+                 Solvable *s = pool->solvables + p;
+                 if (s->repo != pool->installed && !pool_installable(pool, s))
+                   continue;
+                 if (s->arch == evr)
                    queue_push(&plist, p);
                }
              break;
@@ -958,6 +1029,37 @@ pool_addrelproviders(Pool *pool, Id d)
                wp = 0;
            }
          break;
+       case REL_MULTIARCH:
+         if (evr != ARCH_ANY)
+           break;
+         /* XXX : need to check for Multi-Arch: allowed! */
+         wp = pool_whatprovides(pool, name);
+         break;
+       case REL_KIND:
+         /* package kind filtering */
+         if (!name)
+           {
+             FOR_POOL_SOLVABLES(p)
+               {
+                 Solvable *s = pool->solvables + p;
+                 if (s->repo != pool->installed && !pool_installable(pool, s))
+                   continue;
+                 if (pool_is_kind(pool, s->name, evr))
+                   queue_push(&plist, p);
+               }
+             break;
+           }
+         wp = pool_whatprovides(pool, name);
+         pp = pool->whatprovidesdata + wp;
+         while ((p = *pp++) != 0)
+           {
+             Solvable *s = pool->solvables + p;
+             if (pool_is_kind(pool, s->name, evr))
+               queue_push(&plist, p);
+             else
+               wp = 0;
+           }
+         break;
        case REL_FILECONFLICT:
          pp = pool_whatprovides_ptr(pool, name);
          while ((p = *pp++) != 0)
@@ -1067,7 +1169,7 @@ pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr)
 
 /* intersect dependencies in keyname with dep, return list of matching packages */
 void
-pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q)
+pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
 {
   Id p;
 
@@ -1079,7 +1181,7 @@ pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q)
        continue;
       if (s->repo != pool->installed && !pool_installable(pool, s))
        continue;
-      if (solvable_matchesdep(s, keyname, dep))
+      if (solvable_matchesdep(s, keyname, dep, marker))
        queue_push(q, p);
     }
 }
@@ -1194,8 +1296,6 @@ void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id,
 
 struct searchfiles {
   Id *ids;
-  char **dirs;
-  char **names;
   int nfiles;
   Map seen;
 };
@@ -1206,7 +1306,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)
@@ -1264,16 +1364,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;
     }
 }
 
@@ -1299,6 +1390,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;
@@ -1317,15 +1421,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;
 }
 
@@ -1346,8 +1443,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);
 
@@ -1451,6 +1548,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
@@ -1514,13 +1618,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)
     {
@@ -1534,13 +1631,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 */
@@ -1582,12 +1672,9 @@ pool_set_languages(Pool *pool, const char **languages, int nlanguages)
 
   pool->languagecache = solv_free(pool->languagecache);
   pool->languagecacheother = 0;
-  if (pool->nlanguages)
-    {
-      for (i = 0; i < pool->nlanguages; i++)
-       free((char *)pool->languages[i]);
-      free(pool->languages);
-    }
+  for (i = 0; i < pool->nlanguages; i++)
+    free((char *)pool->languages[i]);
+  pool->languages = solv_free((void *)pool->languages);
   pool->nlanguages = nlanguages;
   if (!nlanguages)
     return;
@@ -1835,7 +1922,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;
@@ -1857,27 +1944,14 @@ propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
 
 #define MPTREE_BLOCK 15
 
-void
-pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
+static struct mptree *
+create_mptree(DUChanges *mps, int nmps)
 {
-  char *p;
-  const char *path, *compstr;
-  struct mptree *mptree;
   int i, nmptree;
+  struct mptree *mptree;
   int pos, compl;
   int mp;
-  struct ducbdata cbd;
-  Solvable *s;
-  Id sp;
-  Map ignoredu;
-  Repo *oldinstalled = pool->installed;
-
-  memset(&ignoredu, 0, sizeof(ignoredu));
-  cbd.mps = mps;
-  cbd.addsub = 0;
-  cbd.dirmap = 0;
-  cbd.nmap = 0;
-  cbd.olddata = 0;
+  const char *p, *path, *compstr;
 
   mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
 
@@ -1888,7 +1962,7 @@ pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
   mptree[0].compl = 0;
   mptree[0].mountpoint = -1;
   nmptree = 1;
-  
+
   /* create component tree */
   for (mp = 0; mp < nmps; mp++)
     {
@@ -1947,6 +2021,30 @@ pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
     }
 #endif
 
+  return mptree;
+}
+
+void
+pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
+{
+  struct mptree *mptree;
+  struct ducbdata cbd;
+  Solvable *s;
+  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;
+  cbd.olddata = 0;
   cbd.mptree = mptree;
   cbd.addsub = 1;
   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
@@ -1960,21 +2058,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.map)
-           map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
+         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;
@@ -1990,8 +2122,7 @@ pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
          repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
        }
     }
-  if (ignoredu.map)
-    map_free(&ignoredu);
+  map_free(&ignoredu);
   solv_free(cbd.dirmap);
   solv_free(mptree);
 }
@@ -2030,25 +2161,25 @@ pool_calc_installsizechange(Pool *pool, Map *installedmap)
  *  8: interesting (only true if installed)
  * 16: undecided
  */
+
 static inline Id dep2name(Pool *pool, Id dep)
 {
   while (ISRELDEP(dep))
     {
-      Reldep *rd = rd = GETRELDEP(pool, dep);
+      Reldep *rd = GETRELDEP(pool, dep);
       dep = rd->name;
     }
   return dep;
 }
 
-static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con) 
+static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con)
 {
   Id p, pp;
-  Solvable *sn = pool->solvables + n; 
+  Solvable *sn = pool->solvables + n;
 
   FOR_PROVIDES(p, pp, sn->name)
-    {    
-      Solvable *s = pool->solvables + p; 
+    {
+      Solvable *s = pool->solvables + p;
       if (s->name != sn->name || s->arch != sn->arch)
         continue;
       if ((map[p] & 9) != 9)