solvsig_verify: error out early if the checksum is finished
[platform/upstream/libsolv.git] / ext / repo_rpmdb.c
index 0c3323e..82961ca 100644 (file)
 #define DEP_GREATER            (1 << 2)
 #define DEP_EQUAL              (1 << 3)
 #define DEP_STRONG             (1 << 27)
-#define DEP_PRE                        ((1 << 6) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12))
+#define DEP_PRE_IN             ((1 << 6) | (1 << 9) | (1 << 10))
+#define DEP_PRE_UN             ((1 << 6) | (1 << 11) | (1 << 12))
 
 #define FILEFLAG_GHOST         (1 <<  6)
 
@@ -148,7 +149,7 @@ typedef struct rpmhead {
   int cnt;
   int dcnt;
   unsigned char *dp;
-  int forcebinary;             /* sigh */
+  int forcebinary;             /* sigh, see rh#478907 */
   unsigned char data[1];
 } RpmHead;
 
@@ -213,6 +214,31 @@ headint32(RpmHead *h, int tag)
   return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
 }
 
+static unsigned long long *
+headint64array(RpmHead *h, int tag, int *cnt)
+{
+  unsigned int i, o;
+  unsigned long long *r;
+  unsigned char *d = headfindtag(h, tag);
+
+  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5)
+    return 0;
+  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+  if (o + 8 * i > h->dcnt)
+    return 0;
+  d = h->dp + o;
+  r = solv_calloc(i ? i : 1, sizeof(unsigned long long));
+  if (cnt)
+    *cnt = i;
+  for (o = 0; o < i; o++, d += 8)
+    {
+      unsigned int x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+      r[o] = (unsigned long long)x << 32 | (d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
+    }
+  return r;
+}
+
 /* returns the first entry of an 64bit integer array */
 static unsigned long long
 headint64(RpmHead *h, int tag)
@@ -355,76 +381,14 @@ static char *headtoevr(RpmHead *h)
 static void
 setutf8string(Repodata *repodata, Id handle, Id tag, const char *str)
 {
-  const unsigned char *cp;
-  int state = 0;
-  int c;
-  unsigned char *buf = 0, *bp;
-
-  /* check if it's already utf8, code taken from screen ;-) */
-  cp = (const unsigned char *)str;
-  while ((c = *cp++) != 0)
-    {
-      if (state)
-       {
-          if ((c & 0xc0) != 0x80)
-            break; /* encoding error */
-          c = (c & 0x3f) | (state << 6);
-          if (!(state & 0x40000000))
-           {
-              /* check for overlong sequences */
-              if ((c & 0x820823e0) == 0x80000000)
-                break;
-              else if ((c & 0x020821f0) == 0x02000000)
-                break;
-              else if ((c & 0x000820f8) == 0x00080000)
-                break;
-              else if ((c & 0x0000207c) == 0x00002000)
-                break;
-            }
-        }
-      else
-       {
-          /* new sequence */
-          if (c >= 0xfe)
-            break;
-          else if (c >= 0xfc)
-            c = (c & 0x01) | 0xbffffffc;    /* 5 bytes to follow */
-          else if (c >= 0xf8)
-            c = (c & 0x03) | 0xbfffff00;    /* 4 */
-          else if (c >= 0xf0)
-            c = (c & 0x07) | 0xbfffc000;    /* 3 */
-          else if (c >= 0xe0)
-            c = (c & 0x0f) | 0xbff00000;    /* 2 */
-          else if (c >= 0xc2)
-            c = (c & 0x1f) | 0xfc000000;    /* 1 */
-          else if (c >= 0x80)
-            break;
-        }
-      state = (c & 0x80000000) ? c : 0;
-    }
-  if (c)
+  if (str[solv_validutf8(str)])
     {
-      /* not utf8, assume latin1 */
-      buf = solv_malloc(2 * strlen(str) + 1);
-      cp = (const unsigned char *)str;
-      str = (char *)buf;
-      bp = buf;
-      while ((c = *cp++) != 0)
-       {
-         if (c >= 0xc0)
-           {
-             *bp++ = 0xc3;
-             c ^= 0x80;
-           }
-         else if (c >= 0x80)
-           *bp++ = 0xc2;
-         *bp++ = c;
-       }
-      *bp++ = 0;
+      char *ustr = solv_latin1toutf8(str);     /* not utf8, assume latin1 */
+      repodata_set_str(repodata, handle, tag, ustr);
+      solv_free(ustr);
     }
-  repodata_set_str(repodata, handle, tag, str);
-  if (buf)
-    solv_free(buf);
+  else
+    repodata_set_str(repodata, handle, tag, str);
 }
 
 
@@ -443,7 +407,7 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf,
   char **n, **v;
   unsigned int *f;
   int i, cc, nc, vc, fc;
-  int haspre;
+  int haspre, premask;
   unsigned int olddeps;
   Id *ida;
   int strong;
@@ -468,6 +432,7 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf,
 
   cc = nc;
   haspre = 0;  /* add no prereq marker */
+  premask = DEP_PRE_IN | DEP_PRE_UN;
   if (flags)
     {
       /* we do filtering */
@@ -479,7 +444,7 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf,
          if ((flags & MAKEDEPS_NO_RPMLIB) != 0)
            if (!strncmp(n[i], "rpmlib(", 7))
              continue;
-         if ((f[i] & DEP_PRE) != 0)
+         if ((f[i] & premask) != 0)
            haspre = 1;
          cc++;
        }
@@ -488,7 +453,7 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf,
     {
       /* no filtering, just look for the first prereq */
       for (i = 0; i < nc; i++)
-       if ((f[i] & DEP_PRE) != 0)
+       if ((f[i] & premask) != 0)
          {
            haspre = 1;
            break;
@@ -501,7 +466,7 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf,
       solv_free(f);
       return 0;
     }
-  cc += haspre;
+  cc += haspre;                /* add slot for the prereq marker */
   olddeps = repo_reserve_ids(repo, 0, cc);
   ida = repo->idarraydata + olddeps;
   for (i = 0; ; i++)
@@ -516,9 +481,9 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf,
        }
       if (strong && (f[i] & DEP_STRONG) != (strong == MAKEDEPS_FILTER_WEAK ? 0 : DEP_STRONG))
        continue;
-      if (haspre == 1 && (f[i] & DEP_PRE) != 0)
+      if (haspre == 1 && (f[i] & premask) != 0)
        continue;
-      if (haspre == 2 && (f[i] & DEP_PRE) == 0)
+      if (haspre == 2 && (f[i] & premask) == 0)
        continue;
       if ((flags & MAKEDEPS_NO_RPMLIB) != 0)
        if (!strncmp(n[i], "rpmlib(", 7))
@@ -528,11 +493,11 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf,
          Id name, evr;
          int flags = 0;
          if ((f[i] & DEP_LESS) != 0)
-           flags |= 4;
+           flags |= REL_LT;
          if ((f[i] & DEP_EQUAL) != 0)
-           flags |= 2;
+           flags |= REL_EQ;
          if ((f[i] & DEP_GREATER) != 0)
-           flags |= 1;
+           flags |= REL_GT;
          name = pool_str2id(pool, n[i], 1);
          if (v[i][0] == '0' && v[i][1] == ':' && v[i][2])
            evr = pool_str2id(pool, v[i] + 2, 1);
@@ -558,17 +523,34 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *
   Id did;
   int i, fszc;
   unsigned int *fkb, *fn, *fsz, *fm, *fino;
+  unsigned long long *fsz64;
   unsigned int inotest[256], inotestok;
 
   if (!fc)
     return;
-  /* XXX: use TAG_LONGFILESIZES if available */
-  fsz = headint32array(rpmhead, TAG_FILESIZES, &fszc);
-  if (!fsz || fc != fszc)
+  if ((fsz64 = headint64array(rpmhead, TAG_LONGFILESIZES, &fszc)) != 0)
+    {
+      /* convert to kbyte */
+      fsz = solv_malloc2(fszc, sizeof(*fsz));
+      for (i = 0; i < fszc; i++)
+        fsz[i] = fsz64[i] ? fsz64[i] / 1024 + 1 : 0;
+      solv_free(fsz64);
+    }
+  else if ((fsz = headint32array(rpmhead, TAG_FILESIZES, &fszc)) != 0)
+    {
+      /* convert to kbyte */
+      for (i = 0; i < fszc; i++)
+        if (fsz[i])
+         fsz[i] = fsz[i] / 1024 + 1;
+    }
+  else
+    return;
+  if (fc != fszc)
     {
       solv_free(fsz);
       return;
     }
+
   /* stupid rpm records sizes of directories, so we have to check the mode */
   fm = headint16array(rpmhead, TAG_FILEMODES, &fszc);
   if (!fm || fc != fszc)
@@ -585,15 +567,18 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *
       solv_free(fino);
       return;
     }
+
+  /* kill hardlinked entries */
   inotestok = 0;
   if (fc < sizeof(inotest))
     {
+      /* quick test just hashing the inode numbers */
       memset(inotest, 0, sizeof(inotest));
       for (i = 0; i < fc; i++)
        {
          int off, bit;
          if (fsz[i] == 0 || !S_ISREG(fm[i]))
-           continue;
+           continue;   /* does not matter */
          off = (fino[i] >> 5) & (sizeof(inotest)/sizeof(*inotest) - 1);
          bit = 1 << (fino[i] & 31);
          if ((inotest[off] & bit) != 0)
@@ -601,10 +586,11 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *
          inotest[off] |= bit;
        }
       if (i == fc)
-       inotestok = 1;
+       inotestok = 1;  /* no conflict found */
     }
   if (!inotestok)
     {
+      /* hardlinked files are possible, check ino/dev pairs */
       unsigned int *fdev = headint32array(rpmhead, TAG_FILEDEVICES, &fszc);
       unsigned int *fx, j;
       unsigned int mask, hash, hh;
@@ -651,6 +637,8 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *
       solv_free(fdev);
     }
   solv_free(fino);
+
+  /* sum up inode count and kbytes for each directory */
   fn = solv_calloc(dc, sizeof(unsigned int));
   fkb = solv_calloc(dc, sizeof(unsigned int));
   for (i = 0; i < fc; i++)
@@ -660,7 +648,7 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *
       fn[di[i]]++;
       if (fsz[i] == 0 || !S_ISREG(fm[i]))
        continue;
-      fkb[di[i]] += fsz[i] / 1024 + 1;
+      fkb[di[i]] += fsz[i];
     }
   solv_free(fsz);
   solv_free(fm);
@@ -772,9 +760,9 @@ addchangelog(Repodata *data, Id handle, RpmHead *rpmhead)
       if (ct[i])
         repodata_set_num(data, h, SOLVABLE_CHANGELOG_TIME, ct[i]);
       if (cn[i])
-        repodata_set_str(data, h, SOLVABLE_CHANGELOG_AUTHOR, cn[i]);
+        setutf8string(data, h, SOLVABLE_CHANGELOG_AUTHOR, cn[i]);
       if (cx[i])
-        repodata_set_str(data, h, SOLVABLE_CHANGELOG_TEXT, cx[i]);
+        setutf8string(data, h, SOLVABLE_CHANGELOG_TEXT, cx[i]);
       queue_push(&hq, h);
     }
   for (i = 0; i < hq.count; i++)
@@ -785,6 +773,49 @@ addchangelog(Repodata *data, Id handle, RpmHead *rpmhead)
   solv_free(cn);
 }
 
+static void
+set_description_author(Repodata *data, Id handle, char *str)
+{
+  char *aut, *p;
+  for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++)
+    if (!strncmp(aut, "\nAuthors:\n--------\n", 19))
+      break;
+  if (aut)
+    {
+      /* oh my, found SUSE special author section */
+      int l = aut - str;
+      str = solv_strdup(str);
+      aut = str + l;
+      str[l] = 0;
+      while (l > 0 && str[l - 1] == '\n')
+       str[--l] = 0;
+      if (l)
+       setutf8string(data, handle, SOLVABLE_DESCRIPTION, str);
+      p = aut + 19;
+      aut = str;       /* copy over */
+      while (*p == ' ' || *p == '\n')
+       p++;
+      while (*p)
+       {
+         if (*p == '\n')
+           {
+             *aut++ = *p++;
+             while (*p == ' ')
+               p++;
+             continue;
+           }
+         *aut++ = *p++;
+       }
+      while (aut != str && aut[-1] == '\n')
+       aut--;
+      *aut = 0;
+      if (*str)
+       setutf8string(data, handle, SOLVABLE_AUTHORS, str);
+      free(str);
+    }
+  else if (*str)
+    setutf8string(data, handle, SOLVABLE_DESCRIPTION, str);
+}
 
 static int
 rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags)
@@ -845,47 +876,7 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead,
         setutf8string(data, handle, SOLVABLE_SUMMARY, str);
       str = headstring(rpmhead, TAG_DESCRIPTION);
       if (str)
-       {
-         char *aut, *p;
-         for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++)
-           if (!strncmp(aut, "\nAuthors:\n--------\n", 19))
-             break;
-         if (aut)
-           {
-             /* oh my, found SUSE special author section */
-             int l = aut - str;
-             str = solv_strdup(str);
-             aut = str + l;
-             str[l] = 0;
-             while (l > 0 && str[l - 1] == '\n')
-               str[--l] = 0;
-             if (l)
-                setutf8string(data, handle, SOLVABLE_DESCRIPTION, str);
-             p = aut + 19;
-             aut = str;        /* copy over */
-             while (*p == ' ' || *p == '\n')
-               p++;
-             while (*p)
-               {
-                 if (*p == '\n')
-                   {
-                     *aut++ = *p++;
-                     while (*p == ' ')
-                       p++;
-                     continue;
-                   }
-                 *aut++ = *p++;
-               }
-             while (aut != str && aut[-1] == '\n')
-               aut--;
-             *aut = 0;
-             if (*str)
-               setutf8string(data, handle, SOLVABLE_AUTHORS, str);
-             free(str);
-           }
-         else if (*str)
-           setutf8string(data, handle, SOLVABLE_DESCRIPTION, str);
-       }
+       set_description_author(data, handle, str);
       str = headstring(rpmhead, TAG_GROUP);
       if (str)
         repodata_set_poolstr(data, handle, SOLVABLE_GROUP, str);
@@ -970,7 +961,7 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead,
  */
 
 struct rpmdbstate {
-  Pool *pool; 
+  Pool *pool;
   char *rootdir;
 
   RpmHead *rpmhead;    /* header storage space */
@@ -1486,6 +1477,7 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
 static void
 solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
 {
+  int p, i;
   Repo *repo = s->repo;
   Pool *pool = repo->pool;
   Repo *fromrepo = r->repo;
@@ -1512,7 +1504,17 @@ solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
   cbdata.handle = s - pool->solvables;
   cbdata.subhandle = 0;
   cbdata.dircache = dircache;
-  repo_search(fromrepo, (r - fromrepo->pool->solvables), 0, 0, SEARCH_NO_STORAGE_SOLVABLE | SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
+  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
+  FOR_REPODATAS(fromrepo, i, data)
+    {
+      if (p < data->start || p >= data->end)
+       continue;
+      repodata_search(data, p, 0, SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
+    }
+#endif
 }
 
 /* used to sort entries by package name that got returned in some database order */