Imported Upstream version 0.7.15
[platform/upstream/libsolv.git] / ext / repo_rpmdb.c
index 75bb678..67ce81d 100644 (file)
@@ -172,6 +172,15 @@ typedef struct rpmhead {
 } RpmHead;
 
 
+static inline void
+headinit(RpmHead *h, unsigned int cnt, unsigned int dcnt)
+{
+  h->cnt = (int)cnt;
+  h->dcnt = dcnt;
+  h->dp = h->data + 16 * cnt;
+  h->dp[dcnt] = 0;
+}
+
 static inline unsigned char *
 headfindtag(RpmHead *h, int tag)
 {
@@ -1000,7 +1009,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);
@@ -1180,6 +1189,9 @@ rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhe
       u32 = headint32(rpmhead, TAG_BUILDTIME);
       if (u32)
         repodata_set_num(data, handle, SOLVABLE_BUILDTIME, u32);
+      str = headstring(rpmhead, TAG_BUILDHOST);
+      if (str)
+       repodata_set_str(data, handle, SOLVABLE_BUILDHOST, str);
       u32 = headint32(rpmhead, TAG_INSTALLTIME);
       if (u32)
         repodata_set_num(data, handle, SOLVABLE_INSTALLTIME, u32);
@@ -1240,7 +1252,7 @@ struct rpmdbstate {
   char *rootdir;
 
   RpmHead *rpmhead;    /* header storage space */
-  int rpmheadsize;
+  unsigned int rpmheadsize;
 };
 
 #endif
@@ -1248,49 +1260,55 @@ struct rpmdbstate {
 
 #ifndef ENABLE_RPMPKG_LIBRPM
 
-static int
-headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2)
+static inline RpmHead *
+realloc_head(struct rpmdbstate *state, unsigned int len)
 {
-  RpmHead *rpmhead;
-  unsigned int len = 16 * cnt + dsize + pad;
-  if (len + 1 > state->rpmheadsize)
+  if (len > state->rpmheadsize)
     {
       state->rpmheadsize = len + 128;
       state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
     }
-  rpmhead = state->rpmhead;
+  return state->rpmhead;
+}
+
+static int
+headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2)
+{
+  unsigned int len = 16 * cnt + dsize + pad;
+  RpmHead *rpmhead = realloc_head(state, len + 1);
   if (fread(rpmhead->data, len, 1, fp) != 1)
     return pool_error(state->pool, 0, "%s: unexpected EOF", name);
   if (chk1)
     solv_chksum_add(chk1, rpmhead->data, len);
   if (chk2)
     solv_chksum_add(chk2, rpmhead->data, len);
-  rpmhead->data[len] = 0;
-  rpmhead->cnt = cnt;
-  rpmhead->dcnt = dsize;
-  rpmhead->dp = rpmhead->data + cnt * 16;
+  headinit(rpmhead, cnt, dsize);
   return 1;
 }
 
-#if defined(ENABLE_RPMDB_BYRPMHEADER)
-static void
-headfromblob(struct rpmdbstate *state, const unsigned char *blob, unsigned int cnt, unsigned int dsize)
+# if defined(ENABLE_RPMDB) && (!defined(ENABLE_RPMDB_LIBRPM) || defined(HAVE_RPMDBNEXTITERATORHEADERBLOB))
+
+static int
+headfromhdrblob(struct rpmdbstate *state, const unsigned char *data, unsigned int size)
 {
+  unsigned int dsize, cnt, len;
   RpmHead *rpmhead;
-  unsigned int len = 16 * cnt + dsize;
-  if (len + 1 > state->rpmheadsize)
-    {
-      state->rpmheadsize = len + 128;
-      state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
-    }
-  rpmhead = state->rpmhead;
-  memcpy(rpmhead->data, blob, len);
-  rpmhead->data[len] = 0;
-  rpmhead->cnt = cnt;
-  rpmhead->dcnt = dsize;
-  rpmhead->dp = rpmhead->data + cnt * 16;
+  if (size < 8)
+    return pool_error(state->pool, 0, "corrupt rpm database (size)");
+  cnt = getu32(data);
+  dsize = getu32(data + 4);
+  if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE)
+    return pool_error(state->pool, 0, "corrupt rpm database (cnt/dcnt)");
+  if (8 + cnt * 16 + dsize > size)
+    return pool_error(state->pool, 0, "corrupt rpm database (data size)");
+  len = 16 * cnt + dsize;
+  rpmhead = realloc_head(state, len + 1);
+  memcpy(rpmhead->data, data + 8, len);
+  headinit(rpmhead, cnt, dsize);
+  return 1;
 }
-#endif
+
+# endif
 
 #else
 
@@ -1329,8 +1347,6 @@ freestate(struct rpmdbstate *state)
 {
   /* close down */
 #ifdef ENABLE_RPMDB
-  if (state->pkgdbopened)
-    closepkgdb(state);
   if (state->dbenvopened)
     closedbenv(state);
 #endif
@@ -1385,49 +1401,12 @@ copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
   return ido;
 }
 
-#define COPYDIR_DIRCACHE_SIZE 512
-
-static Id copydir_complex(Repodata *data, Repodata *fromdata, Id did, Id *cache);
-
-static inline Id
-copydir(Repodata *data, Repodata *fromdata, Id did, Id *cache)
-{
-  if (cache && did && cache[did & 255] == did)
-    return cache[(did & 255) + 256];
-  return copydir_complex(data, fromdata, did, cache);
-}
-
-static Id
-copydir_complex(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(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;
   Id subhandle;
   Id *dircache;
+  int bad;
 };
 
 static int
@@ -1447,23 +1426,24 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
       break;
     case REPOKEY_TYPE_DIRNUMNUMARRAY:
     case REPOKEY_TYPE_DIRSTRARRAY:
-      kv->id = copydir(data, fromdata, kv->id, cbdata->dircache);
-      break;
-    case REPOKEY_TYPE_FLEXARRAY:
-      if (kv->eof == 2)
+      kv->id = repodata_translate_dir(data, fromdata, kv->id, 1, fromdata->repodataid == 1 ? cbdata->dircache : 0);
+      if (!kv->id)
        {
-         assert(cbdata->subhandle);
-         cbdata->handle = cbdata->subhandle;
-         cbdata->subhandle = 0;
-         break;
-       }
-      if (!kv->entry)
-        {
-         assert(!cbdata->subhandle);
-         cbdata->subhandle = cbdata->handle;
+         cbdata->bad = 1;      /* oops, cannot copy this */
+         return 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:
       cbdata->handle = repodata_new_handle(data);
-      repodata_add_flexarray(data, cbdata->subhandle, key->name, cbdata->handle);
+      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:
       break;
@@ -1472,14 +1452,15 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
   return 0;
 }
 
-static void
-solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
+static int
+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;
@@ -1497,29 +1478,36 @@ solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
 
   /* copy all attributes */
   if (!data || fromrepo->nrepodata < 2)
-    return;
+    return 1;
   cbdata.data = data;
   cbdata.handle = s - pool->solvables;
   cbdata.subhandle = 0;
   cbdata.dircache = dircache;
+  cbdata.bad = 0;
   p = r - fromrepo->pool->solvables;
   if (fromrepo->nrepodata == 2)
     {
       Repodata *fromdata = repo_id2repodata(fromrepo, 1);
       if (p >= fromdata->start && p < fromdata->end)
-        repodata_search(fromdata, p, 0, SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
-      return;
+        repodata_search(fromdata, p, 0, 0, solvable_copy_cb, &cbdata);
     }
-#if 0
-  repo_search(fromrepo, p, 0, 0, SEARCH_NO_STORAGE_SOLVABLE | SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
-#else
-  FOR_REPODATAS(fromrepo, i, data)
+  else
+    {
+      keyskip = repo_create_keyskip(repo, p, oldkeyskip);
+      FOR_REPODATAS(fromrepo, i, data)
+       {
+         if (p >= data->start && p < data->end)
+           repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata);
+       }
+    }
+  if (cbdata.bad)
     {
-      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_unset_uninternalized(data, cbdata.handle, 0);
+      memset(s, 0, sizeof(*s));
+      s->repo = repo;
+      return 0;
     }
-#endif
+  return 1;
 }
 
 /* used to sort entries by package name that got returned in some database order */
@@ -1633,7 +1621,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
     }
 
   /* XXX: should get ro lock of Packages database! */
-  if (stat_database(&state, "Packages", &packagesstat, 1))
+  if (stat_database(&state, &packagesstat))
     {
       freestate(&state);
       return -1;
@@ -1652,11 +1640,6 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
        repo_empty(ref, 1);     /* get it out of the way */
       if ((flags & RPMDB_REPORT_PROGRESS) != 0)
        count = count_headers(&state);
-      if (!openpkgdb(&state))
-       {
-         freestate(&state);
-         return -1;
-       }
       if (pkgdb_cursor_open(&state))
        {
          freestate(&state);
@@ -1706,9 +1689,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)
@@ -1731,7 +1713,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;
@@ -1739,8 +1722,6 @@ 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, flags & RPMDB_KEEP_GPG_PUBKEY);
       if (!entries)
@@ -1795,10 +1776,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;
@@ -1811,11 +1793,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
              if (id)
                {
                  Solvable *r = ref->pool->solvables + ref->start + (id - 1);
-                 if (r->repo == ref)
-                   {
-                     solvable_copy(s, r, data, dircache);
-                     continue;
-                   }
+                 if (r->repo == ref && solvable_copy(s, r, data, dircache, &oldkeyskip))
+                   continue;
                }
            }
          res = getrpm_dbid(&state, dbid);
@@ -1827,6 +1806,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);
@@ -1838,7 +1818,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);
@@ -1939,6 +1921,8 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
     {
       pool_error(pool, -1, "%s: not a rpm", rpm);
+      solv_chksum_free(leadsigchksumh, 0);
+      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -1951,12 +1935,16 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (lead[78] != 0 || lead[79] != 5)
     {
       pool_error(pool, -1, "%s: not a rpm v5 header", rpm);
+      solv_chksum_free(leadsigchksumh, 0);
+      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
   if (getu32(lead + 96) != 0x8eade801)
     {
       pool_error(pool, -1, "%s: bad signature header", rpm);
+      solv_chksum_free(leadsigchksumh, 0);
+      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -1965,6 +1953,8 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
     {
       pool_error(pool, -1, "%s: bad signature header", rpm);
+      solv_chksum_free(leadsigchksumh, 0);
+      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -1975,6 +1965,8 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
     {
       if (!headfromfp(&state, rpm, fp, lead + 96, sigcnt, sigdsize, sigpad, chksumh, leadsigchksumh))
        {
+      solv_chksum_free(leadsigchksumh, 0);
+      solv_chksum_free(chksumh, 0);
          fclose(fp);
          return 0;
        }
@@ -2014,6 +2006,8 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
          if (fread(lead, l, 1, fp) != 1)
            {
              pool_error(pool, -1, "%s: unexpected EOF", rpm);
+             solv_chksum_free(leadsigchksumh, 0);
+             solv_chksum_free(chksumh, 0);
              fclose(fp);
              return 0;
            }
@@ -2034,6 +2028,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (fread(lead, 16, 1, fp) != 1)
     {
       pool_error(pool, -1, "%s: unexpected EOF", rpm);
+      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -2042,6 +2037,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (getu32(lead) != 0x8eade801)
     {
       pool_error(pool, -1, "%s: bad header", rpm);
+      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -2050,6 +2046,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
     {
       pool_error(pool, -1, "%s: bad header", rpm);
+      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -2057,6 +2054,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
 
   if (!headfromfp(&state, rpm, fp, lead, sigcnt, sigdsize, 0, chksumh, 0))
     {
+      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -2086,7 +2084,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;
@@ -2138,7 +2136,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))
@@ -2407,6 +2405,28 @@ rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queu
   return nentries;
 }
 
+int
+rpm_hash_database_state(void *rpmstate, Chksum *chk)
+{
+  struct rpmdbstate *state = rpmstate;
+  struct stat stb;
+  if (stat_database(state, &stb))
+    return -1;
+  if (state->dbenvopened != 1 && !opendbenv(state))
+    return -1;
+  solv_chksum_add(chk, &stb.st_mtime, sizeof(stb.st_mtime));
+  solv_chksum_add(chk, &stb.st_size, sizeof(stb.st_size));
+  solv_chksum_add(chk, &stb.st_ino, sizeof(stb.st_ino));
+  hash_name_index(rpmstate, chk);
+  return 0;
+}
+
+int
+rpm_stat_database(void *rpmstate, void *stb)
+{
+  return stat_database((struct rpmdbstate *)rpmstate, (struct stat *)stb) ? -1 : 0;
+}
+
 void *
 rpm_byrpmdbid(void *rpmstate, Id rpmdbid)
 {
@@ -2495,7 +2515,8 @@ rpm_byrpmh(void *rpmstate, Header h)
   struct rpmdbstate *state = rpmstate;
 #ifndef ENABLE_RPMPKG_LIBRPM
   const unsigned char *uh;
-  unsigned int dsize, cnt;
+  unsigned int dsize, cnt, len;
+  RpmHead *rpmhead;
 
   if (!h)
     return 0;
@@ -2513,7 +2534,10 @@ rpm_byrpmh(void *rpmstate, Header h)
       free((void *)uh);
       return 0;
     }
-  headfromblob(state, uh + 8, cnt, dsize);
+  len = 16 * cnt + dsize;
+  rpmhead = realloc_head(state, len + 1);;
+  memcpy(rpmhead->data, uh + 8, len);
+  headinit(rpmhead, cnt, dsize);
   free((void *)uh);
 #else
   if (!h)