Imported Upstream version 0.7.2
[platform/upstream/libsolv.git] / ext / repo_mdk.c
index 6e44c98..4d3e102 100644 (file)
@@ -16,6 +16,7 @@
 #include "repo.h"
 #include "util.h"
 #include "chksum.h"
+#include "solv_xmlparser.h"
 #include "repo_mdk.h"
 
 static Offset
@@ -94,7 +95,9 @@ repo_add_mdk(Repo *repo, FILE *fp, int flags)
   while (fgets(buf + bufl, bufa - bufl, fp) > 0)
     {
       bufl += strlen(buf + bufl);
-      if (bufl && buf[bufl - 1] != '\n')
+      if (!bufl)
+       continue;
+      if (buf[bufl - 1] != '\n')
        {
          if (bufa - bufl < 256)
            {
@@ -103,7 +106,7 @@ repo_add_mdk(Repo *repo, FILE *fp, int flags)
            }
          continue;
        }
-      buf[--bufl] = 0;
+      buf[bufl - 1] = 0;
       bufl = 0;
       if (buf[0] != '@')
        {
@@ -113,16 +116,15 @@ repo_add_mdk(Repo *repo, FILE *fp, int flags)
       if (!s)
        s = pool_id2solvable(pool, repo_add_solvable(repo));
       if (!strncmp(buf + 1, "filesize@", 9))
-       {
-         unsigned long filesize = strtoul(buf + 10, 0, 10);
-         repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned int)((filesize + 1023) / 1024));
-       }
+       repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, strtoull(buf + 10, 0, 10));
       else if (!strncmp(buf + 1, "summary@", 8))
        repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, buf + 9);
       else if (!strncmp(buf + 1, "provides@", 9))
        s->provides = parse_deps(s, buf + 10, 0);
       else if (!strncmp(buf + 1, "requires@", 9))
        s->requires = parse_deps(s, buf + 10, SOLVABLE_PREREQMARKER);
+      else if (!strncmp(buf + 1, "recommends@", 11))
+       s->recommends = parse_deps(s, buf + 10, 0);
       else if (!strncmp(buf + 1, "suggests@", 9))
        s->suggests = parse_deps(s, buf + 10, 0);
       else if (!strncmp(buf + 1, "obsoletes@", 10))
@@ -136,6 +138,8 @@ repo_add_mdk(Repo *repo, FILE *fp, int flags)
          char *arch;
          char *version;
          char *filename;
+         char *disttag = 0;
+         char *distepoch = 0;
          if ((epochstr = strchr(nvra, '@')) != 0)
            {
              char *sizestr;
@@ -143,19 +147,26 @@ repo_add_mdk(Repo *repo, FILE *fp, int flags)
              if ((sizestr = strchr(epochstr, '@')) != 0)
                {
                  char *groupstr;
-                 unsigned long size;
                  *sizestr++ = 0;
                  if ((groupstr = strchr(sizestr, '@')) != 0)
                    {
-                     char *n;
                      *groupstr++ = 0;
-                     if ((n = strchr(groupstr, '@')) != 0)
-                       *n = 0;
+                     if ((disttag = strchr(groupstr, '@')) != 0)
+                       {
+                         *disttag++ = 0;
+                         if ((distepoch = strchr(disttag, '@')) != 0)
+                           {
+                             char *n;
+                             *distepoch++ = 0;
+                             if ((n = strchr(distepoch, '@')) != 0)
+                               *n = 0;
+                           }
+                       }
                      if (*groupstr)
                        repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_GROUP, groupstr);
                    }
-                 size = strtoul(sizestr, 0, 10);
-                 repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, (unsigned int)((size + 1023) / 1024));
+                 if (*sizestr)
+                   repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(sizestr, 0, 10));
                }
            }
           filename = pool_tmpjoin(pool, nvra, ".rpm", 0);
@@ -165,47 +176,21 @@ repo_add_mdk(Repo *repo, FILE *fp, int flags)
              *arch++ = 0;
              s->arch = pool_str2id(pool, arch, 1);
            }
-         /* argh, do we have a distepoch or not, check self-provides */
-         if (s->provides)
+         if (disttag && *disttag)
            {
-             Id id, lastid, *idp = s->repo->idarraydata + s->provides;
-             lastid = 0;
-             for (idp = s->repo->idarraydata + s->provides; (id = *idp) != 0; idp++)
-               {
-                 const char *evr, *name;
-                 int namel;
-                 Reldep *rd;
-                 if (!ISRELDEP(id))
-                   continue;
-                 rd = GETRELDEP(pool, id);
-                 if (rd->flags != REL_EQ)
-                   continue;
-                 name = pool_id2str(pool, rd->name);
-                 namel = strlen(name);
-                 if (strncmp(name, nvra, namel) != 0 || nvra[namel] != '-')
-                   continue;
-                 evr = pool_id2str(pool, rd->evr);
-                 evr = strrchr(evr, '-');
-                 if (evr && strchr(evr, ':') != 0)
-                   lastid = id;
-               }
-             if (lastid)
-               {
-                 /* self provides found, and it contains a distepoch */
-                 /* replace with self-provides distepoch to get rid of the disttag */
-                 char *nvradistepoch = strrchr(nvra, '-');
-                 if (nvradistepoch)
-                   {
-                     Reldep *rd = GETRELDEP(pool, lastid);
-                     const char *evr = pool_id2str(pool, rd->evr);
-                     evr = strrchr(evr, '-');
-                     if (evr && (evr = strchr(evr, ':')) != 0)
-                       {
-                         if (strlen(evr) < strlen(nvradistepoch))
-                           strcpy(nvradistepoch, evr);
-                       }
-                   }
-               }
+             /* strip disttag from release */
+             char *n = strrchr(nvra, '-');
+             if (n && !strncmp(n + 1, disttag, strlen(disttag)))
+               *n = 0;
+           }
+         if (distepoch && *distepoch)
+           {
+             /* add distepoch */
+             int le = strlen(distepoch);
+             int ln = strlen(nvra);
+             nvra[ln++] = ':';
+             memmove(nvra + ln, distepoch, le);        /* may overlap */
+             nvra[le + ln] = 0;
            }
          version = strrchr(nvra, '-');
          if (version)
@@ -245,10 +230,238 @@ repo_add_mdk(Repo *repo, FILE *fp, int flags)
   if (s)
     {
       pool_debug(pool, SOLV_ERROR, "unclosed package at EOF\n");
-      repo_free_solvable_block(s->repo, s - pool->solvables, 1, 1);
+      s = solvable_free(s, 1);
     }
   solv_free(buf);
   if (!(flags & REPO_NO_INTERNALIZE))
     repodata_internalize(data);
   return 0;
 }
+
+enum state {
+  STATE_START,
+  STATE_MEDIA_INFO,
+  STATE_INFO,
+  STATE_FILES,
+  NUMSTATES
+};
+
+static struct solv_xmlparser_element stateswitches[] = {
+  { STATE_START, "media_info", STATE_MEDIA_INFO, 0 },
+  { STATE_MEDIA_INFO, "info", STATE_INFO, 1 },
+  { STATE_MEDIA_INFO, "files", STATE_FILES, 1 },
+  { NUMSTATES }
+};
+
+struct parsedata {
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+  Solvable *solvable;
+  Hashtable joinhash;
+  Hashval joinhashmask;
+  struct solv_xmlparser xmlp;
+};
+
+static Hashtable
+joinhash_init(Repo *repo, Hashval *hmp)
+{
+  Hashval hm = mkmask(repo->nsolvables);
+  Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
+  Hashval h, hh;
+  Solvable *s;
+  int i;
+
+  FOR_REPO_SOLVABLES(repo, i, s)
+    {
+      hh = HASHCHAIN_START;
+      h = s->name & hm;
+      while (ht[h])
+        h = HASHCHAIN_NEXT(h, hh, hm);
+      ht[h] = i;
+    }
+  *hmp = hm;
+  return ht;
+}
+
+static Solvable *
+joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, const char *fn, const char *distepoch)
+{
+  Hashval h, hh;
+  const char *p, *vrstart, *vrend;
+  Id name, arch;
+
+  if (!fn || !*fn)
+    return 0;
+  if (distepoch && !*distepoch)
+    distepoch = 0;
+  p = fn + strlen(fn);
+  while (--p > fn)
+    if (*p == '.')
+      break;
+  if (p == fn)
+    return 0;
+  arch = pool_str2id(repo->pool, p + 1, 0);
+  if (!arch)
+    return 0;
+  if (distepoch)
+    {
+      while (--p > fn)
+        if (*p == '-')
+          break;
+      if (p == fn)
+       return 0;
+    }
+  vrend = p;
+  while (--p > fn)
+    if (*p == '-')
+      break;
+  if (p == fn)
+    return 0;
+  while (--p > fn)
+    if (*p == '-')
+      break;
+  if (p == fn)
+    return 0;
+  vrstart = p + 1;
+  name = pool_strn2id(repo->pool, fn, p - fn, 0);
+  if (!name)
+    return 0;
+  hh = HASHCHAIN_START;
+  h = name & hm;
+  while (ht[h])
+    {
+      Solvable *s = repo->pool->solvables + ht[h];
+      if (s->name == name && s->arch == arch)
+       {
+         /* too bad we don't know the epoch... */
+         const char *evr = pool_id2str(repo->pool, s->evr);
+         for (p = evr; *p >= '0' && *p <= '9'; p++)
+           ;
+         if (p > evr && *p == ':')
+           evr = p + 1;
+         if (distepoch)
+           {
+              if (!strncmp(evr, vrstart, vrend - vrstart) && evr[vrend - vrstart] == ':' && !strcmp(distepoch, evr + (vrend - vrstart + 1)))
+               return s;
+           }
+          else if (!strncmp(evr, vrstart, vrend - vrstart) && evr[vrend - vrstart] == 0)
+           return s;
+       }
+      h = HASHCHAIN_NEXT(h, hh, hm);
+    }
+  return 0;
+}
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+
+  switch (state)
+    {
+    case STATE_INFO:
+      {
+       const char *fn = solv_xmlparser_find_attr("fn", atts);
+       const char *distepoch = solv_xmlparser_find_attr("distepoch", atts);
+       const char *str;
+       pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
+       if (!pd->solvable)
+         break;
+       str = solv_xmlparser_find_attr("url", atts);
+       if (str && *str)
+         repodata_set_str(pd->data, pd->solvable - pool->solvables, SOLVABLE_URL, str);
+       str = solv_xmlparser_find_attr("license", atts);
+       if (str && *str)
+         repodata_set_poolstr(pd->data, pd->solvable - pool->solvables, SOLVABLE_LICENSE, str);
+       str = solv_xmlparser_find_attr("sourcerpm", atts);
+       if (str && *str)
+         repodata_set_sourcepkg(pd->data, pd->solvable - pool->solvables, str);
+        break;
+      }
+    case STATE_FILES:
+      {
+       const char *fn = solv_xmlparser_find_attr("fn", atts);
+       const char *distepoch = solv_xmlparser_find_attr("distepoch", atts);
+       pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
+        break;
+      }
+    default:
+      break;
+    }
+}
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Solvable *s = pd->solvable;
+  switch (state)
+    {
+    case STATE_INFO:
+      if (s && *content)
+        repodata_set_str(pd->data, s - pd->pool->solvables, SOLVABLE_DESCRIPTION, content);
+      break;
+    case STATE_FILES:
+      if (s && *content)
+       {
+         char *np, *p, *sl;
+         for (p = content; p && *p; p = np)
+           {
+             Id id;
+             np = strchr(p, '\n');
+             if (np)
+               *np++ = 0;
+             if (!*p)
+               continue;
+             sl = strrchr(p, '/');
+             if (sl)
+               {
+                 *sl++ = 0;
+                 id = repodata_str2dir(pd->data, p, 1);
+               }
+             else
+               {
+                 sl = p;
+                 id = 0;
+               }
+             if (!id)
+               id = repodata_str2dir(pd->data, "/", 1);
+             repodata_add_dirstr(pd->data, s - pd->pool->solvables, SOLVABLE_FILELIST, id, sl);
+           }
+       }
+      break;
+    default:
+      break;
+    }
+}
+
+int
+repo_add_mdk_info(Repo *repo, FILE *fp, int flags)
+{
+  Repodata *data;
+  struct parsedata pd;
+
+  if (!(flags & REPO_EXTEND_SOLVABLES))
+    {
+      pool_debug(repo->pool, SOLV_ERROR, "repo_add_mdk_info: can only extend existing solvables\n");
+      return -1;
+    }
+
+  data = repo_add_repodata(repo, flags);
+
+  memset(&pd, 0, sizeof(pd));
+  pd.repo = repo;
+  pd.pool = repo->pool;
+  pd.data = data;
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  pd.joinhash = joinhash_init(repo, &pd.joinhashmask);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+  solv_xmlparser_free(&pd.xmlp);
+  solv_free(pd.joinhash);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}