Imported Upstream version 0.7.15
[platform/upstream/libsolv.git] / ext / repo_rpmdb.c
index 9acb400..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)
 {
@@ -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
@@ -1390,6 +1406,7 @@ struct solvable_copy_cbdata {
   Id handle;
   Id subhandle;
   Id *dircache;
+  int bad;
 };
 
 static int
@@ -1410,6 +1427,11 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
     case REPOKEY_TYPE_DIRNUMNUMARRAY:
     case REPOKEY_TYPE_DIRSTRARRAY:
       kv->id = repodata_translate_dir(data, fromdata, kv->id, 1, fromdata->repodataid == 1 ? cbdata->dircache : 0);
+      if (!kv->id)
+       {
+         cbdata->bad = 1;      /* oops, cannot copy this */
+         return 0;
+       }
       break;
     case REPOKEY_TYPE_FIXARRAY:
       cbdata->handle = repodata_new_handle(data);
@@ -1430,7 +1452,7 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
   return 0;
 }
 
-static void
+static int
 solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache, Id **oldkeyskip)
 {
   int p, i;
@@ -1456,25 +1478,36 @@ solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache, Id **oldke
 
   /* 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, 0, solvable_copy_cb, &cbdata);
-      return;
     }
-  keyskip = repo_create_keyskip(repo, p, oldkeyskip);
-  FOR_REPODATAS(fromrepo, i, data)
+  else
     {
-      if (p >= data->start && p < data->end)
-        repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata);
+      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)
+    {
+      repodata_unset_uninternalized(data, cbdata.handle, 0);
+      memset(s, 0, sizeof(*s));
+      s->repo = repo;
+      return 0;
+    }
+  return 1;
 }
 
 /* used to sort entries by package name that got returned in some database order */
@@ -1588,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;
@@ -1607,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);
@@ -1765,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, &oldkeyskip);
-                     continue;
-                   }
+                 if (r->repo == ref && solvable_copy(s, r, data, dircache, &oldkeyskip))
+                   continue;
                }
            }
          res = getrpm_dbid(&state, dbid);
@@ -1896,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;
     }
@@ -1908,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;
     }
@@ -1922,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;
     }
@@ -1932,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;
        }
@@ -1971,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;
            }
@@ -1991,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;
     }
@@ -1999,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;
     }
@@ -2007,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;
     }
@@ -2014,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;
     }
@@ -2364,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)
 {
@@ -2452,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;
@@ -2470,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)