Add functions to create IDARRAY attributes.
[platform/upstream/libsolv.git] / src / repo_solv.c
index 2723465..8dfcc76 100644 (file)
@@ -465,8 +465,9 @@ key_cmp (const void *pa, const void *pb)
 static void repodata_load_solv(Repodata *data);
 
 static void
-parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned numid, unsigned numrel, Repo *repo)
+parse_external_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned numid, unsigned numrel)
 {
+  Repo *repo = maindata->repo;
   Id key, id;
   Id *ida, *ide;
   Repodata *data;
@@ -476,6 +477,7 @@ parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned
   data = repo->repodata + repo->nrepodata++;
   memset(data, 0, sizeof(*data));
   data->repo = repo;
+  data->pagefd = -1;
   data->state = REPODATA_STUB;
   data->loadcallback = repodata_load_solv;
 
@@ -492,12 +494,12 @@ parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned
            }
          /* read_idarray writes a terminating 0, that's why the + 1 */
          ida = sat_calloc(keys[key].size + 1, sizeof(Id));
-         ide = read_idarray(maindata, 0, 0, ida, ida + keys[key].size + 1);
+         ide = read_idarray(maindata, numid, idmap, ida, ida + keys[key].size + 1);
          n = ide - ida - 1;
          if (n & 1)
            {
              pool_debug (mypool, SAT_ERROR, "invalid attribute data\n");
-             data->error = SOLV_ERROR_CORRUPT;
+             maindata->error = SOLV_ERROR_CORRUPT;
              return;
            }
          data->nkeys = 1 + (n >> 1);
@@ -505,14 +507,8 @@ parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned
          memset(data->keys, 0, sizeof(Repokey));
          for (i = 1, ide = ida; i < data->nkeys; i++)
            {
-             if (*ide >= numid)
-               {
-                 pool_debug (mypool, SAT_ERROR, "invalid attribute data\n");
-                 data->error = SOLV_ERROR_CORRUPT;
-                 return;
-               }
-             data->keys[i].name = idmap ? idmap[*ide++] : *ide++;
-             data->keys[i].type = idmap ? idmap[*ide++] : *ide++;
+             data->keys[i].name = *ide++;
+             data->keys[i].type = *ide++;
              data->keys[i].size = 0;
              data->keys[i].storage = 0;
            }
@@ -526,7 +522,7 @@ parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned
          else
            {
              char buf[1024];
-             unsigned len = sizeof (buf);
+             unsigned len = sizeof(buf);
              char *filename = buf;
              read_str(maindata, &filename, &len);
              data->location = strdup(filename);
@@ -541,6 +537,37 @@ parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned
     }
 }
 
+static void
+parse_info_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned numid, unsigned numrel)
+{
+  Id key, id;
+  Id *ida;
+  while ((key = *keyp++) != 0)
+    {
+      id = keys[key].name;
+      if (id == REPODATA_ADDEDFILEPROVIDES && keys[key].type == REPOKEY_TYPE_REL_IDARRAY)
+       {
+         Id old = 0;
+         /* + 1 just in case */
+         ida = sat_calloc(keys[key].size + 1, sizeof(Id));
+         read_idarray(maindata, 0, 0, ida, ida + keys[key].size + 1);
+         maindata->addedfileprovides = ida;
+         for (; *ida; ida++)
+           {
+             old += *ida - 1;
+             if (old >= numid)
+               {
+                 *ida = 0;
+                 break;
+               }
+             *ida = idmap ? idmap[old] : old;
+           }
+         continue;
+       }
+      skip_item(maindata, keys[key].type, numid, numrel);
+    }
+}
+
 /*-----------------------------------------------------------------*/
 
 
@@ -596,6 +623,32 @@ incore_add_blob(Repodata *data, unsigned char *buf, int len)
 }
 
 static void
+incore_map_idarray(Repodata *data, unsigned char *dp, Id *map, Id max)
+{
+  /* We have to map the IDs, which might also change
+     the necessary number of bytes, so we can't just copy
+     over the blob and adjust it.  */
+  for (;;)
+    {
+      Id id;
+      int eof;
+      dp = data_read_ideof(dp, &id, &eof);
+      if (max && id >= max)
+       {
+         pool_debug(mypool, SAT_ERROR, "incore_map_idarray: id too large (%u/%u)\n", id, max);
+         data->error = SOLV_ERROR_ID_RANGE;
+         break;
+       }
+      id = map[id];
+      if (id >= 64)
+       id = (id & 63) | ((id & ~63) << 1);
+      incore_add_id(data, eof ? id : id | 64);
+      if (eof)
+       break;
+    }
+}
+
+static void
 incore_add_u32(Repodata *data, unsigned int x)
 {
   unsigned char *dp;
@@ -796,6 +849,8 @@ repo_add_solv_parent(Repo *repo, FILE *fp, Repodata *parent)
       char *pp = prefix;
       char *old_str = 0;
       char *dest = strsp;
+      int freesp = sizeid;
+
       if (pfsize && fread(prefix, pfsize, 1, fp) != 1)
         {
          pool_debug(pool, SAT_ERROR, "read error while reading strings\n");
@@ -805,7 +860,14 @@ repo_add_solv_parent(Repo *repo, FILE *fp, Repodata *parent)
       for (i = 1; i < numid; i++)
         {
          int same = (unsigned char)*pp++;
-         size_t len = strlen (pp) + 1;
+         size_t len = strlen(pp) + 1;
+         freesp -= same + len;
+         if (freesp < 0)
+           {
+             pool_debug(pool, SAT_ERROR, "overflow while expanding strings\n");
+             sat_free(prefix);
+             return SOLV_ERROR_OVERFLOW;
+           }
          if (same)
            memcpy(dest, old_str, same);
          memcpy(dest + same, pp, len);
@@ -814,6 +876,11 @@ repo_add_solv_parent(Repo *repo, FILE *fp, Repodata *parent)
          dest += same + len;
        }
       sat_free(prefix);
+      if (freesp != 0)
+       {
+         pool_debug(pool, SAT_ERROR, "expanding strings size mismatch\n");
+         return SOLV_ERROR_CORRUPT;
+       }
     }
   strsp[sizeid] = 0;                  /* make string space \0 terminated */
   sp = strsp;
@@ -887,7 +954,7 @@ repo_add_solv_parent(Repo *repo, FILE *fp, Repodata *parent)
            {
              sat_free(hashtbl);
              sat_free(idmap);
-             pool_debug(pool, SAT_ERROR, "not enough strings\n");
+             pool_debug(pool, SAT_ERROR, "not enough strings %d %d\n", i, numid);
              return SOLV_ERROR_OVERFLOW;
            }
          if (!*sp)                            /* empty string */
@@ -1112,10 +1179,16 @@ repo_add_solv_parent(Repo *repo, FILE *fp, Repodata *parent)
       if (keys[key].name == REPODATA_EXTERNAL && keys[key].type == REPOKEY_TYPE_VOID)
        {
          /* external data for some ids */
-         parse_repodata(&data, keyp, keys, idmap, numid, numrel, repo);
+         parse_external_repodata(&data, keyp, keys, idmap, numid, numrel);
+       }
+      else if (keys[key].name == REPODATA_INFO)
+       {
+         parse_info_repodata(&data, keyp, keys, idmap, numid, numrel);
        }
       else
-       skip_schema(&data, keyp, keys, numid, numrel);
+       {
+         skip_schema(&data, keyp, keys, numid, numrel);
+       }
     }
 
 
@@ -1174,7 +1247,11 @@ repo_add_solv_parent(Repo *repo, FILE *fp, Repodata *parent)
     s = 0;
 
   if (have_xdata)
-    repodata_extend_block(&data, data.start, numsolv);
+    {
+      /* reserve one byte so that all offsets are not zero */
+      incore_add_id(&data, 0);
+      repodata_extend_block(&data, data.start, numsolv);
+    }
 
   left = 0;
   buf = sat_calloc(maxsize + 4, 1);
@@ -1271,8 +1348,8 @@ fprintf(stderr, "solv %d name %d type %d class %d\n", i, id, keys[key].type, key
                  dps = dp;
                  dp = data_skip(dp, REPOKEY_TYPE_IDARRAY);
                  if (keys[key].storage == KEY_STORAGE_INCORE && idmap)
-                   abort();
-                 if (keys[key].storage == KEY_STORAGE_INCORE)
+                   incore_map_idarray(&data, dps, idmap, numid);
+                 else if (keys[key].storage == KEY_STORAGE_INCORE)
                    incore_add_blob(&data, dps, dp - dps);
                  break;
                }