Imported Upstream version 0.7.2
[platform/upstream/libsolv.git] / ext / repo_deb.c
index 5af0c70..5dd79f4 100644 (file)
 #include <string.h>
 #include <unistd.h>
 #include <zlib.h>
+#include <lzma.h>
 #include <errno.h>
 
 #include "pool.h"
 #include "repo.h"
 #include "util.h"
+#include "solver.h"    /* for GET_USERINSTALLED_ flags */
 #include "chksum.h"
 #include "repo_deb.h"
 
 static unsigned char *
-decompress(unsigned char *in, int inl, int *outlp)
+decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
 {
   z_stream strm;
   int outl, ret;
-  unsigned char *out;
+  unsigned char *bp, *out;
+
+  /* first skip the gz header */
+  if (inl <= 10 || in[0] != 0x1f || in[1] != 0x8b)
+    return 0;
+  if (in[2] != 8 || (in[3] & 0xe0) != 0)
+    return 0;
+  bp = in + 4;
+  bp += 6;     /* skip time, xflags and OS code */
+  if (in[3] & 0x04)
+    {
+      /* skip extra field */
+      int l = bp + 2 >= in + inl ? 0 : (bp[0] | bp[1] << 8);
+      bp += l + 2;
+    }
+  if (in[3] & 0x08)    /* orig filename */
+    while (bp < in + inl && *bp++)
+      ;
+  if (in[3] & 0x10)    /* file comment */
+    while (bp < in + inl && *bp++)
+      ;
+  if (in[3] & 0x02)    /* header crc */
+    bp += 2;
+  if (bp >= in + inl)
+    return 0;
+  inl -= bp - in;
+  in = bp;
 
   memset(&strm, 0, sizeof(strm));
   strm.next_in = in;
@@ -45,6 +73,12 @@ decompress(unsigned char *in, int inl, int *outlp)
       if (strm.avail_out == 0)
        {
          outl += 4096;
+         if (outl >= maxoutl)
+           {
+             inflateEnd(&strm);
+             free(out);
+             return 0;
+           }
          out = solv_realloc(out, outl + 4096);
          strm.next_out = out + outl;
          strm.avail_out = 4096;
@@ -54,6 +88,7 @@ decompress(unsigned char *in, int inl, int *outlp)
        break;
       if (ret != Z_OK)
        {
+         inflateEnd(&strm);
          free(out);
          return 0;
        }
@@ -64,6 +99,58 @@ decompress(unsigned char *in, int inl, int *outlp)
   return out;
 }
 
+static unsigned char *
+decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  static lzma_stream stream_init = LZMA_STREAM_INIT;
+  lzma_stream strm;
+  int outl, ret;
+  unsigned char *out;
+
+  strm = stream_init;
+  strm.next_in = in;
+  strm.avail_in = inl;
+  out = solv_malloc(4096);
+  strm.next_out = out;
+  strm.avail_out = 4096;
+  outl = 0;
+  ret = lzma_auto_decoder(&strm, 100 << 20, 0);
+  if (ret != LZMA_OK)
+    {
+      free(out);
+      return 0;
+    }
+  for (;;)
+    {
+      if (strm.avail_out == 0)
+       {
+         outl += 4096;
+         if (outl >= maxoutl)
+           {
+             lzma_end(&strm);
+             free(out);
+             return 0;
+           }
+         out = solv_realloc(out, outl + 4096);
+         strm.next_out = out + outl;
+         strm.avail_out = 4096;
+       }
+      ret = lzma_code(&strm, LZMA_RUN);
+      if (ret == LZMA_STREAM_END)
+       break;
+      if (ret != LZMA_OK)
+       {
+         lzma_end(&strm);
+         free(out);
+         return 0;
+       }
+    }
+  outl += 4096 - strm.avail_out;
+  lzma_end(&strm);
+  *outlp = outl;
+  return out;
+}
+
 static Id
 parseonedep(Pool *pool, char *p)
 {
@@ -204,7 +291,7 @@ control2solvable(Solvable *s, Repodata *data, char *control)
       if (*p)
         *p++ = 0;
       /* strip trailing space */
-      while (end >= control && *end == ' ' && *end == '\t')
+      while (end >= control && (*end == ' ' || *end == '\t'))
        *end-- = 0;
       tag = control;
       control = p;
@@ -313,6 +400,10 @@ control2solvable(Solvable *s, Repodata *data, char *control)
              havesource = 1;
            }
          break;
+       case 'S' << 8 | 'T':
+         if (!strcasecmp(tag, "status"))
+           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_INSTALLSTATUS, q);
+         break;
        case 'S' << 8 | 'U':
          if (!strcasecmp(tag, "suggests"))
            s->suggests = makedeps(repo, q, s->suggests, 0);
@@ -383,12 +474,10 @@ repo_add_debpackages(Repo *repo, FILE *fp, int flags)
       if (!(p = strchr(p, '\n')))
        {
          int l3;
-         if (l + 1024 >= bufl)
+         while (l + 1024 >= bufl)
            {
              buf = solv_realloc(buf, bufl + 4096);
              bufl += 4096;
-             p = buf + l;
-             continue;
            }
          p = buf + l;
          ll = fread(p, 1, bufl - l - 1, fp);
@@ -398,6 +487,8 @@ repo_add_debpackages(Repo *repo, FILE *fp, int flags)
          while ((l3 = strlen(p)) < ll)
            p[l3] = '\n';
          l += ll;
+         if (p != buf)
+           p--;
          continue;
        }
       p++;
@@ -408,7 +499,7 @@ repo_add_debpackages(Repo *repo, FILE *fp, int flags)
       s = pool_id2solvable(pool, repo_add_solvable(repo));
       control2solvable(s, data, buf);
       if (!s->name)
-       repo_free_solvable(repo, s - pool->solvables, 1);
+       s = solvable_free(s, 1);
       if (l > ll)
         memmove(buf, p + 1, l - ll);
       l -= ll;
@@ -420,7 +511,7 @@ repo_add_debpackages(Repo *repo, FILE *fp, int flags)
       s = pool_id2solvable(pool, repo_add_solvable(repo));
       control2solvable(s, data, buf);
       if (!s->name)
-       repo_free_solvable(repo, s - pool->solvables, 1);
+       s = solvable_free(s, 1);
     }
   solv_free(buf);
   if (!(flags & REPO_NO_INTERNALIZE))
@@ -442,6 +533,10 @@ repo_add_debdb(Repo *repo, int flags)
   return 0;
 }
 
+#define CONTROL_COMP_NONE      0
+#define CONTROL_COMP_GZIP      1
+#define CONTROL_COMP_XZ                2
+
 Id
 repo_add_deb(Repo *repo, const char *deb, int flags)
 {
@@ -449,6 +544,7 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
   Repodata *data;
   unsigned char buf[4096], *bp;
   int l, l2, vlen, clen, ctarlen;
+  int control_comp;
   unsigned char *ctgz;
   unsigned char pkgid[16];
   unsigned char *ctar;
@@ -470,7 +566,7 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
       return 0;
     }
   l = fread(buf, 1, sizeof(buf), fp);
-  if (l < 8 + 60 || strncmp((char *)buf, "!<arch>\ndebian-binary   ", 8 + 16) != 0)
+  if (l < 8 + 60 || (strncmp((char *)buf, "!<arch>\ndebian-binary   ", 8 + 16) != 0 && strncmp((char *)buf, "!<arch>\ndebian-binary/  ", 8 + 16) != 0))
     {
       pool_error(pool, -1, "%s: not a deb package", deb);
       fclose(fp);
@@ -490,16 +586,26 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
       fclose(fp);
       return 0;
     }
-  if (strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz  ", 16) != 0)
+  control_comp = 0;
+  if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz/ ", 16))
+    control_comp = CONTROL_COMP_GZIP;
+  else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz/ ", 16))
+    control_comp = CONTROL_COMP_XZ;
+  else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar     ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar/    ", 16))
+    control_comp = CONTROL_COMP_NONE;
+  else
     {
-      pool_error(pool, -1, "%s: control.tar.gz is not second entry", deb);
+      pool_error(pool, -1, "%s: control.tar is not second entry", deb);
       fclose(fp);
       return 0;
     }
+  /* dpkg has no actual maximum size for the control.tar member, so this
+   * just keeps from allocating arbitrarily large amounts of memory.
+   */
   clen = atoi((char *)buf + 8 + 60 + vlen + 48);
-  if (clen <= 0 || clen >= 0x100000)
+  if (clen <= 0 || clen >= 0x1000000)
     {
-      pool_error(pool, -1, "%s: control.tar.gz has illegal size", deb);
+      pool_error(pool, -1, "%s: control.tar has illegal size", deb);
       fclose(fp);
       return 0;
     }
@@ -529,55 +635,25 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
       solv_chksum_free(chk, pkgid);
       gotpkgid = 1;
     }
-  if (ctgz[0] != 0x1f || ctgz[1] != 0x8b)
-    {
-      pool_error(pool, -1, "%s: control.tar.gz is not gzipped", deb);
-      solv_free(ctgz);
-      return 0;
-    }
-  if (ctgz[2] != 8 || (ctgz[3] & 0xe0) != 0)
-    {
-      pool_error(pool, -1, "%s: control.tar.gz is compressed in a strange way", deb);
-      solv_free(ctgz);
-      return 0;
-    }
-  bp = ctgz + 4;
-  bp += 6;     /* skip time, xflags and OS code */
-  if (ctgz[3] & 0x04)
-    {
-      /* skip extra field */
-      l = bp[0] | bp[1] << 8;
-      bp += l + 2;
-      if (bp >= ctgz + clen)
-       {
-          pool_error(pool, -1, "%s: control.tar.gz is corrupt", deb);
-         solv_free(ctgz);
-         return 0;
-       }
-    }
-  if (ctgz[3] & 0x08)  /* orig filename */
-    while (*bp)
-      bp++;
-  if (ctgz[3] & 0x10)  /* file comment */
-    while (*bp)
-      bp++;
-  if (ctgz[3] & 0x02)  /* header crc */
-    bp += 2;
-  if (bp >= ctgz + clen)
+  ctar = 0;
+  if (control_comp == CONTROL_COMP_GZIP)
+    ctar = decompress_gz(ctgz, clen, &ctarlen, 0x1000000);
+  else if (control_comp == CONTROL_COMP_XZ)
+    ctar = decompress_xz(ctgz, clen, &ctarlen, 0x1000000);
+  else
     {
-      pool_error(pool, -1, "%s: control.tar.gz is corrupt", deb);
-      solv_free(ctgz);
-      return 0;
+      ctarlen = clen;
+      ctar = solv_memdup(ctgz, clen);
     }
-  ctar = decompress(bp, ctgz + clen - bp, &ctarlen);
   solv_free(ctgz);
   if (!ctar)
     {
-      pool_error(pool, -1, "%s: control.tar.gz is corrupt", deb);
+      pool_error(pool, -1, "%s: control.tar is corrupt", deb);
       return 0;
     }
   bp = ctar;
   l = ctarlen;
+  l2 = 0;
   while (l > 512)
     {
       int j;
@@ -585,6 +661,12 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
       for (j = 124; j < 124 + 12; j++)
        if (bp[j] >= '0' && bp[j] <= '7')
          l2 = l2 * 8 + (bp[j] - '0');
+      if (l2 < 0 || l2 > l)
+       {
+         l2 = 0;
+         break;
+       }
+      bp[124] = 0;
       if (!strcmp((char *)bp, "./control") || !strcmp((char *)bp, "control"))
        break;
       l2 = 512 + ((l2 + 511) & ~511);
@@ -593,7 +675,7 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
     }
   if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0)
     {
-      pool_error(pool, -1, "%s: control.tar.gz contains no control file", deb);
+      pool_error(pool, -1, "%s: control.tar contains no control file", deb);
       free(ctar);
       return 0;
     }
@@ -613,3 +695,94 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
     repodata_internalize(data);
   return s - pool->solvables;
 }
+
+void
+pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags)
+{
+  Id name = 0, arch = 0;
+  int autoinstalled = -1;
+  char *buf, *bp;
+  int x, l, bufl, eof = 0;
+  Id p, pp;
+
+  queue_empty(q);
+  buf = solv_malloc(4096);
+  bufl = 4096;
+  l = 0;
+  while (!eof)
+    {
+      while (bufl - l < 1024)
+       {
+         bufl += 4096;
+         if (bufl > 1024 * 64)
+           break;      /* hmm? */
+         buf = solv_realloc(buf, bufl);
+       }
+      if (!fgets(buf + l, bufl - l, fp))
+       {
+         eof = 1;
+         buf[l] = '\n';
+         buf[l + 1] = 0;
+       }
+      l = strlen(buf);
+      if (l && buf[l - 1] == '\n')
+       buf[--l] = 0;
+      if (!*buf || eof)
+       {
+         l = 0;
+         if (name && autoinstalled > 0)
+           {
+             if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+               queue_push2(q, name, arch);
+             else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+               queue_push(q, name);
+             else
+               {
+                 FOR_PROVIDES(p, pp, name)
+                   {
+                     Solvable *s = pool->solvables + p;
+                     if (s->name != name)
+                       continue;
+                     if (arch && s->arch != arch)
+                       continue;
+                     queue_push(q, p);
+                   }
+               }
+           }
+         name = arch = 0;
+         autoinstalled = -1;
+         continue;
+       }
+      /* strip trailing space */
+      while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+       buf[--l] = 0;
+      l = 0;
+
+      bp = strchr(buf, ':');
+      if (!bp || bp - buf < 4)
+       continue;
+      *bp++ = 0;
+      while (*bp == ' ' || *bp == '\t')
+       bp++;
+      x = '@' + (buf[0] & 0x1f);
+      x = (x << 8) + '@' + (buf[1] & 0x1f);
+      switch(x)
+       {
+       case 'P' << 8 | 'A':
+         if (!strcasecmp(buf, "package"))
+           name = pool_str2id(pool, bp, 1);
+         break;
+       case 'A' << 8 | 'R':
+         if (!strcasecmp(buf, "architecture"))
+           arch = pool_str2id(pool, bp, 1);
+         break;
+       case 'A' << 8 | 'U':
+         if (!strcasecmp(buf, "auto-installed"))
+           autoinstalled = atoi(bp);
+         break;
+       default:
+         break;
+       }
+    }
+}
+