Imported Upstream version 0.7.2
[platform/upstream/libsolv.git] / ext / repo_rpmdb.c
index cd14a9b..9acb400 100644 (file)
@@ -457,7 +457,13 @@ headbinary(RpmHead *h, int tag, unsigned int *sizep)
 static int
 headissourceheuristic(RpmHead *h)
 {
-  return headerIsSource(h);
+  struct rpmtd_s td;
+  int issource;
+  if (!headerGet(h, TAG_DIRNAMES, &td, HEADERGET_MINMEM))
+    return 0;
+  issource = td.count == 1 && td.data && ((char **)td.data)[0] && !((char **)td.data)[0][0];
+  rpmtdFreeData(&td);
+  return issource;
 }
 
 static inline void
@@ -480,10 +486,7 @@ static char *headtoevr(RpmHead *h)
   release  = headstring(h, TAG_RELEASE);
   epoch = headint32(h, TAG_EPOCH);
   if (!version || !release)
-    {
-      fprintf(stderr, "headtoevr: bad rpm header\n");
-      return 0;
-    }
+    return 0;
   for (v = version; *v >= '0' && *v <= '9'; v++)
     ;
   if (epoch || (v != version && *v == ':'))
@@ -997,7 +1000,7 @@ addchangelog(Repodata *data, Id handle, RpmHead *rpmhead)
   char **cn;
   char **cx;
   uint32_t *ct;
-  int i, cnc, cxc, ctc;
+  int i, cnc, cxc, ctc = 0;
   Queue hq;
 
   ct = headint32array(rpmhead, TAG_CHANGELOGTIME, &ctc);
@@ -1089,7 +1092,7 @@ rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhe
       pool_error(pool, 0, "package has no name");
       return 0;
     }
-  if (!strcmp(name, "gpg-pubkey"))
+  if (!(flags & RPMDB_KEEP_GPG_PUBKEY) && !strcmp(name, "gpg-pubkey"))
     return 0;
   s->name = pool_str2id(pool, name, 1);
   sourcerpm = headstring(rpmhead, TAG_SOURCERPM);
@@ -1106,6 +1109,7 @@ rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhe
     s->arch = ARCH_NOARCH;
   evr = headtoevr(rpmhead);
   s->evr = pool_str2id(pool, evr, 1);
+  solv_free(evr);
   s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1);
 
   queue_init_buffer(&ignq, ignqbuf, sizeof(ignqbuf)/sizeof(*ignqbuf));
@@ -1203,7 +1207,6 @@ rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhe
       if ((flags & RPM_ADD_WITH_CHANGELOG) != 0)
        addchangelog(data, handle, rpmhead);
     }
-  solv_free(evr);
   return 1;
 }
 
@@ -1257,10 +1260,7 @@ headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *
     }
   rpmhead = state->rpmhead;
   if (fread(rpmhead->data, len, 1, fp) != 1)
-    {
-      fclose(fp);
-      return pool_error(state->pool, 0, "%s: unexpected EOF", name);
-    }
+    return pool_error(state->pool, 0, "%s: unexpected EOF", name);
   if (chk1)
     solv_chksum_add(chk1, rpmhead->data, len);
   if (chk2)
@@ -1385,44 +1385,6 @@ copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
   return ido;
 }
 
-#define COPYDIR_DIRCACHE_SIZE 512
-
-static Id copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache);
-
-static inline Id
-copydir(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache)
-{
-  if (cache && did && cache[did & 255] == did)
-    return cache[(did & 255) + 256];
-  return copydir_complex(pool, data, fromdata, did, cache);
-}
-
-static Id
-copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache)
-{
-  Id parent, compid;
-  if (!did)
-    {
-      /* make sure that the dirpool has an entry */
-      if (!data->dirpool.ndirs)
-        dirpool_add_dir(&data->dirpool, 0, 0, 1);
-      return 0;
-    }
-  parent = dirpool_parent(&fromdata->dirpool, did);
-  compid = dirpool_compid(&fromdata->dirpool, did);
-  if (parent)
-    parent = copydir(pool, data, fromdata, parent, cache);
-  if (data->localpool || fromdata->localpool)
-    compid = repodata_translate_id(data, fromdata, compid, 1);
-  compid = dirpool_add_dir(&data->dirpool, parent, compid, 1);
-  if (cache)
-    {
-      cache[did & 255] = did;
-      cache[(did & 255) + 256] = compid;
-    }
-  return compid;
-}
-
 struct solvable_copy_cbdata {
   Repodata *data;
   Id handle;
@@ -1434,86 +1396,49 @@ static int
 solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, KeyValue *kv)
 {
   struct solvable_copy_cbdata *cbdata = vcbdata;
-  Id id, keyname;
   Repodata *data = cbdata->data;
   Id handle = cbdata->handle;
-  Pool *pool = data->repo->pool;
 
-  keyname = key->name;
-  switch(key->type)
+  switch (key->type)
     {
     case REPOKEY_TYPE_ID:
     case REPOKEY_TYPE_CONSTANTID:
     case REPOKEY_TYPE_IDARRAY: /* used for triggers */
-      id = kv->id;
       if (data->localpool || fromdata->localpool)
-       id = repodata_translate_id(data, fromdata, id, 1);
-      if (key->type == REPOKEY_TYPE_ID)
-        repodata_set_id(data, handle, keyname, id);
-      else if (key->type == REPOKEY_TYPE_CONSTANTID)
-        repodata_set_constantid(data, handle, keyname, id);
-      else
-        repodata_add_idarray(data, handle, keyname, id);
-      break;
-    case REPOKEY_TYPE_STR:
-      repodata_set_str(data, handle, keyname, kv->str);
-      break;
-    case REPOKEY_TYPE_VOID:
-      repodata_set_void(data, handle, keyname);
-      break;
-    case REPOKEY_TYPE_NUM:
-      repodata_set_num(data, handle, keyname, SOLV_KV_NUM64(kv));
-      break;
-    case REPOKEY_TYPE_CONSTANT:
-      repodata_set_constant(data, handle, keyname, kv->num);
+       kv->id = repodata_translate_id(data, fromdata, kv->id, 1);
       break;
     case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      id = kv->id;
-      id = copydir(pool, data, fromdata, id, cbdata->dircache);
-      if (id)
-        repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2);
-      break;
     case REPOKEY_TYPE_DIRSTRARRAY:
-      id = kv->id;
-      id = copydir(pool, data, fromdata, id, cbdata->dircache);
-      if (id)
-        repodata_add_dirstr(data, handle, keyname, id, kv->str);
+      kv->id = repodata_translate_dir(data, fromdata, kv->id, 1, fromdata->repodataid == 1 ? cbdata->dircache : 0);
       break;
+    case REPOKEY_TYPE_FIXARRAY:
+      cbdata->handle = repodata_new_handle(data);
+      repodata_add_fixarray(data, handle, key->name, cbdata->handle);
+      repodata_search_arrayelement(fromdata, 0, 0, 0, kv, &solvable_copy_cb, cbdata);
+      cbdata->handle = handle;
+      return 0;
     case REPOKEY_TYPE_FLEXARRAY:
-      if (kv->eof == 2)
-       {
-         assert(cbdata->subhandle);
-         cbdata->handle = cbdata->subhandle;
-         cbdata->subhandle = 0;
-         break;
-       }
-      if (!kv->entry)
-        {
-         assert(!cbdata->subhandle);
-         cbdata->subhandle = cbdata->handle;
-       }
       cbdata->handle = repodata_new_handle(data);
-      repodata_add_flexarray(data, cbdata->subhandle, keyname, cbdata->handle);
-      break;
+      repodata_add_flexarray(data, handle, key->name, cbdata->handle);
+      repodata_search_arrayelement(fromdata, 0, 0, 0, kv, &solvable_copy_cb, cbdata);
+      cbdata->handle = handle;
+      return 0;
     default:
-      if (solv_chksum_len(key->type))
-       {
-         repodata_set_bin_checksum(data, handle, keyname, key->type, (const unsigned char *)kv->str);
-         break;
-       }
       break;
     }
+  repodata_set_kv(data, handle, key->name, key->type, kv);
   return 0;
 }
 
 static void
-solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
+solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache, Id **oldkeyskip)
 {
   int p, i;
   Repo *repo = s->repo;
   Pool *pool = repo->pool;
   Repo *fromrepo = r->repo;
   struct solvable_copy_cbdata cbdata;
+  Id *keyskip;
 
   /* copy solvable data */
   s->name = r->name;
@@ -1530,23 +1455,26 @@ solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
   s->enhances  = copydeps(pool, repo, r->enhances, fromrepo);
 
   /* copy all attributes */
-  if (!data)
+  if (!data || fromrepo->nrepodata < 2)
     return;
   cbdata.data = data;
   cbdata.handle = s - pool->solvables;
   cbdata.subhandle = 0;
   cbdata.dircache = dircache;
   p = r - fromrepo->pool->solvables;
-#if 0
-  repo_search(fromrepo, p, 0, 0, SEARCH_NO_STORAGE_SOLVABLE | SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
-#else
+  if (fromrepo->nrepodata == 2)
+    {
+      Repodata *fromdata = repo_id2repodata(fromrepo, 1);
+      if (p >= fromdata->start && p < fromdata->end)
+        repodata_search(fromdata, p, 0, 0, solvable_copy_cb, &cbdata);
+      return;
+    }
+  keyskip = repo_create_keyskip(repo, p, oldkeyskip);
   FOR_REPODATAS(fromrepo, i, data)
     {
       if (p >= data->start && p < data->end)
-        repodata_search(data, p, 0, SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
-      cbdata.dircache = 0;     /* only for first repodata */
+        repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata);
     }
-#endif
 }
 
 /* used to sort entries by package name that got returned in some database order */
@@ -1733,9 +1661,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
       if (s)
        {
          /* oops, could not reuse. free it instead */
-          repo_free_solvable(repo, s - pool->solvables, 1);
+          s = solvable_free(s, 1);
          solvend--;
-         s = 0;
        }
       /* now sort all solvables in the new solvstart..solvend block */
       if (solvend - solvstart > 1)
@@ -1758,7 +1685,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
     }
   else
     {
-      Id dircache[COPYDIR_DIRCACHE_SIZE];              /* see copydir */
+      Id *dircache;
+      Id *oldkeyskip = 0;
       struct rpmdbentry *entries = 0, *rp;
       int nentries = 0;
       char *namedata = 0;
@@ -1766,10 +1694,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
       Id id, *refhash;
       int res;
 
-      memset(dircache, 0, sizeof(dircache));
-
       /* get ids of installed rpms */
-      entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata);
+      entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata, flags & RPMDB_KEEP_GPG_PUBKEY);
       if (!entries)
        {
          freestate(&state);
@@ -1822,10 +1748,11 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
       if (!repo->rpmdbid)
         repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
 
+      dircache = repodata_create_dirtranscache(data);
       for (i = 0, rp = entries; i < nentries; i++, rp++, s++)
        {
          Id dbid = rp->rpmdbid;
-         repo->rpmdbid[(s - pool->solvables) - repo->start] = rp->rpmdbid;
+         repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid;
          if (refhash)
            {
              h = dbid & refmask;
@@ -1840,7 +1767,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
                  Solvable *r = ref->pool->solvables + ref->start + (id - 1);
                  if (r->repo == ref)
                    {
-                     solvable_copy(s, r, data, dircache);
+                     solvable_copy(s, r, data, dircache, &oldkeyskip);
                      continue;
                    }
                }
@@ -1854,6 +1781,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
              solv_free(entries);
              solv_free(namedata);
              solv_free(refhash);
+             dircache = repodata_free_dirtranscache(dircache);
              return -1;
            }
          rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS);
@@ -1865,7 +1793,9 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
                pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count);
            }
        }
+      dircache = repodata_free_dirtranscache(dircache);
 
+      solv_free(oldkeyskip);
       solv_free(entries);
       solv_free(namedata);
       solv_free(refhash);
@@ -2113,7 +2043,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   s = pool_id2solvable(pool, repo_add_solvable(repo));
   if (!rpmhead2solv(pool, repo, data, s, state.rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
     {
-      repo_free_solvable(repo, s - pool->solvables, 1);
+      s = solvable_free(s, 1);
       solv_chksum_free(chksumh, 0);
       headfree(state.rpmhead);
       return 0;
@@ -2165,7 +2095,7 @@ repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags)
   s = pool_id2solvable(pool, repo_add_solvable(repo));
   if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags))
     {
-      repo_free_solvable(repo, s - pool->solvables, 1);
+      s = solvable_free(s, 1);
       return 0;
     }
   if (!(flags & REPO_NO_INTERNALIZE))
@@ -2359,7 +2289,7 @@ rpm_query(void *rpmhandle, Id what)
   r = 0;
   switch (what)
     {
-    case 0:
+    case 0:    /* return canonical name of rpm */
       name = headstring(rpmhead, TAG_NAME);
       if (!name)
        name = "";
@@ -2423,7 +2353,7 @@ rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queu
   struct rpmdbentry *entries;
   int nentries, i;
 
-  entries = getinstalledrpmdbids(rpmstate, index ? index : "Name", match, &nentries, 0);
+  entries = getinstalledrpmdbids(rpmstate, index ? index : "Name", match, &nentries, 0, 0);
   if (rpmdbidq)
     {
       queue_empty(rpmdbidq);