Support new types for MD5 and SHA1 checksums (stored in binary, but with
[platform/upstream/libsolv.git] / src / repodata.c
index 53571c7..456b055 100644 (file)
@@ -87,6 +87,7 @@ repodata_free(Repodata *data)
   sat_free(data->attriddata);
   
   sat_free(data->location);
+  sat_free(data->addedfileprovides);
 
   if (data->pagefd != -1)
     close(data->pagefd);
@@ -872,8 +873,7 @@ repodata_extend_block(Repodata *data, Id start, Id num)
     return;
   if (!data->incoreoffset)
     {
-      data->incoreoffset = sat_extend_resize(data->incoreoffset, num, sizeof(Id), REPODATA_BLOCK);
-      memset(data->incoreoffset, 0, num * sizeof(Id));
+      data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
       data->start = start;
       data->end = start + num;
       return;
@@ -896,8 +896,8 @@ repodata_insert_keyid(Repodata *data, Id entry, Id keyid, Id val, int overwrite)
   int i;
   if (!data->attrs)
     {
-      data->attrs = sat_extend_resize(0, data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
-      memset(data->attrs, 0, (data->end - data->start) * sizeof(Id *));
+      data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *),
+                                    REPODATA_BLOCK);
     }
   i = 0;
   if (data->attrs[entry])
@@ -1040,52 +1040,147 @@ repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str)
   data->attrdatalen += l;
 }
 
-void
-repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
+static void
+repoadata_add_array(Repodata *data, Id entry, Id keyname, Id keytype, int entrysize)
 {
+  int oldsize;
   Id *ida, *pp;
-  Repokey key;
 
-#if 0
-fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
-#endif
+  pp = 0;
   if (data->attrs && data->attrs[entry])
+    for (pp = data->attrs[entry]; *pp; pp += 2)
+      if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
+        break;
+  if (!pp || !*pp)
     {
-      for (pp = data->attrs[entry]; *pp; pp += 2)
-        if (data->keys[*pp].name == keyname && data->keys[*pp].type == REPOKEY_TYPE_DIRNUMNUMARRAY)
-         break;
-      if (*pp)
-       {
-         int oldsize = 0;
-         for (ida = data->attriddata + pp[1]; *ida; ida += 3)
-           oldsize += 3;
-         if (ida + 1 == data->attriddata + data->attriddatalen)
-           {
-             /* this was the last entry, just append it */
-             data->attriddata = sat_extend(data->attriddata, data->attriddatalen, 3, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-             data->attriddatalen--;    /* overwrite terminating 0  */
-           }
-         else
-           {
-             /* too bad. move to back. */
-             data->attriddata = sat_extend(data->attriddata, data->attriddatalen,  oldsize + 4, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-             memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
-             pp[1] = data->attriddatalen;
-             data->attriddatalen += oldsize;
-           }
-         data->attriddata[data->attriddatalen++] = dir;
-         data->attriddata[data->attriddatalen++] = num;
-         data->attriddata[data->attriddatalen++] = num2;
-         data->attriddata[data->attriddatalen++] = 0;
-         return;
-       }
+      /* not found. allocate new key */
+      Repokey key;
+      key.name = keyname;
+      key.type = keytype;
+      key.size = 0;
+      key.storage = KEY_STORAGE_INCORE;
+      data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+      repodata_set(data, entry, &key, data->attriddatalen);
+      return;
+    }
+  oldsize = 0;
+  for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
+    oldsize += entrysize;
+  if (ida + 1 == data->attriddata + data->attriddatalen)
+    {
+      /* this was the last entry, just append it */
+      data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+      data->attriddatalen--;   /* overwrite terminating 0  */
+    }
+  else
+    {
+      /* too bad. move to back. */
+      data->attriddata = sat_extend(data->attriddata, data->attriddatalen,  oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+      memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
+      pp[1] = data->attriddatalen;
+      data->attriddatalen += oldsize;
+    }
+}
+
+void
+repodata_set_bin_checksum(Repodata *data, Id entry, Id keyname, Id type,
+                     const unsigned char *str)
+{
+  Repokey key;
+  int l;
+  switch (type)
+    {
+      case REPOKEY_TYPE_MD5: l = SIZEOF_MD5; break;
+      case REPOKEY_TYPE_SHA1: l = SIZEOF_SHA1; break;
+      default: return;
     }
   key.name = keyname;
-  key.type = REPOKEY_TYPE_DIRNUMNUMARRAY;
+  key.type = type;
   key.size = 0;
   key.storage = KEY_STORAGE_INCORE;
-  data->attriddata = sat_extend(data->attriddata, data->attriddatalen, 4, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-  repodata_set(data, entry, &key, data->attriddatalen);
+  data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
+  memcpy(data->attrdata + data->attrdatalen, str, l);
+  repodata_set(data, entry, &key, data->attrdatalen);
+  data->attrdatalen += l;
+}
+
+static int
+hexstr2bytes(unsigned char *buf, const char *str, int buflen)
+{
+  int i;
+  for (i = 0; i < buflen; i++)
+    {
+#define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0')     \
+               : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
+               : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
+               : -1)
+      int v = c2h(*str);
+      str++;
+      if (v < 0)
+       return 0;
+      buf[i] = v;
+      v = c2h(*str);
+      str++;
+      if (v < 0)
+       return 0;
+      buf[i] = (buf[i] << 4) | v;
+#undef c2h
+    }
+  return buflen;
+}
+
+void
+repodata_set_checksum(Repodata *data, Id entry, Id keyname, Id type,
+                     const char *str)
+{
+  int l;
+  switch (type)
+    {
+      case REPOKEY_TYPE_MD5: l = SIZEOF_MD5; break;
+      case REPOKEY_TYPE_SHA1: l = SIZEOF_SHA1; break;
+      default: return;
+    }
+  unsigned char buf[l];
+  if (hexstr2bytes(buf, str, l) != l)
+    {
+      fprintf(stderr, "Invalid hex character in %s\n", str);
+      return;
+    }
+  repodata_set_bin_checksum(data, entry, keyname, type, buf);
+}
+
+const char *
+repodata_chk2str(Repodata *data, Id type, const char *buf)
+{
+  int i, l;
+  char *str, *s;
+  switch (type)
+    {
+      case REPOKEY_TYPE_MD5: l = SIZEOF_MD5; break;
+      case REPOKEY_TYPE_SHA1: l = SIZEOF_SHA1; break;
+      default: return id2str(data->repo->pool, ID_EMPTY);
+    }
+  s = str = pool_alloctmpspace(data->repo->pool, 2*l + 1);
+  for (i = 0; i < l; i++, s+=2)
+    {
+      unsigned char v = buf[i];
+      unsigned char w = v >> 4;
+      s[0] = w >= 10 ? (w-10)+'a' : w + '0';
+      w = v & 15;
+      s[1] = w >= 10 ? (w-10)+'a' : w + '0';
+    }
+  *s = 0;
+  return str;
+}
+
+void
+repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
+{
+
+#if 0
+fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
+#endif
+  repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
   data->attriddata[data->attriddatalen++] = dir;
   data->attriddata[data->attriddatalen++] = num;
   data->attriddata[data->attriddatalen++] = num2;
@@ -1095,8 +1190,7 @@ fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, nu
 void
 repodata_add_dirstr(Repodata *data, Id entry, Id keyname, Id dir, const char *str)
 {
-  Id *ida, *pp, stroff;
-  Repokey key;
+  Id stroff;
   int l;
 
   l = strlen(str) + 1;
@@ -1108,48 +1202,36 @@ repodata_add_dirstr(Repodata *data, Id entry, Id keyname, Id dir, const char *st
 #if 0
 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", entry, dir, str,  data->attriddatalen);
 #endif
-  if (data->attrs && data->attrs[entry])
-    {
-      for (pp = data->attrs[entry]; *pp; pp += 2)
-        if (data->keys[*pp].name == keyname && data->keys[*pp].type == REPOKEY_TYPE_DIRSTRARRAY)
-         break;
-      if (*pp)
-       {
-         int oldsize = 0;
-         for (ida = data->attriddata + pp[1]; *ida; ida += 2)
-           oldsize += 2;
-         if (ida + 1 == data->attriddata + data->attriddatalen)
-           {
-             /* this was the last entry, just append it */
-             data->attriddata = sat_extend(data->attriddata, data->attriddatalen, 2, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-             data->attriddatalen--;    /* overwrite terminating 0  */
-           }
-         else
-           {
-             /* too bad. move to back. */
-             data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + 3, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-             memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
-             pp[1] = data->attriddatalen;
-             data->attriddatalen += oldsize;
-           }
-         data->attriddata[data->attriddatalen++] = dir;
-         data->attriddata[data->attriddatalen++] = stroff;
-         data->attriddata[data->attriddatalen++] = 0;
-         return;
-       }
-    }
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_DIRSTRARRAY;
-  key.size = 0;
-  key.storage = KEY_STORAGE_INCORE;
-  data->attriddata = sat_extend(data->attriddata, data->attriddatalen, 3, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-  repodata_set(data, entry, &key, data->attriddatalen);
+  repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
   data->attriddata[data->attriddatalen++] = dir;
   data->attriddata[data->attriddatalen++] = stroff;
   data->attriddata[data->attriddatalen++] = 0;
 }
 
 void
+repodata_add_idarray(Repodata *data, Id entry, Id keyname, Id id)
+{
+#if 0
+fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", entry, id, data->attriddatalen);
+#endif
+  repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_IDARRAY, 1);
+  data->attriddata[data->attriddatalen++] = id;
+  data->attriddata[data->attriddatalen++] = 0;
+}
+
+void
+repodata_add_poolstr_array(Repodata *data, Id entry, Id keyname,
+                          const char *str)
+{
+  Id id;
+  if (data->localpool)
+    id = stringpool_str2id(&data->spool, str, 1);
+  else
+    id = str2id(data->repo->pool, str, 1);
+  repodata_add_idarray(data, entry, keyname, id);
+}
+
+void
 repodata_merge_attrs(Repodata *data, Id dest, Id src)
 {
   Id *keyp;
@@ -1292,6 +1374,7 @@ repodata_internalize(Repodata *data)
   nentry = data->end - data->start;
   addschema_prepare(data, schematacache);
   memset(&newincore, 0, sizeof(newincore));
+  data_addid(&newincore, 0);
   for (entry = 0; entry < nentry; entry++)
     {
       memset(seen, 0, data->nkeys * sizeof(Id));
@@ -1399,11 +1482,21 @@ fprintf(stderr, "schemadata %p\n", data->schemadata);
                case REPOKEY_TYPE_STR:
                  data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
                  break;
+               case REPOKEY_TYPE_MD5:
+                 data_addblob(xd, data->attrdata + id, SIZEOF_MD5);
+                 break;
+               case REPOKEY_TYPE_SHA1:
+                 data_addblob(xd, data->attrdata + id, SIZEOF_SHA1);
+                 break;
                case REPOKEY_TYPE_ID:
                case REPOKEY_TYPE_NUM:
                case REPOKEY_TYPE_DIR:
                  data_addid(xd, id);
                  break;
+               case REPOKEY_TYPE_IDARRAY:
+                 for (ida = data->attriddata + id; *ida; ida++)
+                   data_addideof(xd, ida[0], ida[1] ? 0 : 1);
+                 break;
                case REPOKEY_TYPE_DIRNUMNUMARRAY:
                  for (ida = data->attriddata + id; *ida; ida += 3)
                    {
@@ -1487,6 +1580,52 @@ repodata_str2dir(Repodata *data, const char *dir, int create)
   return parent;
 }
 
+const char *
+repodata_dir2str(Repodata *data, Id did, const char *suf)
+{
+  Pool *pool = data->repo->pool;
+  int l = 0;
+  Id parent, comp;
+  const char *comps;
+  char *p;
+
+  if (!did)
+    return suf ? suf : "";
+  parent = did;
+  while (parent)
+    {
+      comp = dirpool_compid(&data->dirpool, parent);
+      comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
+      l += strlen(comps);
+      parent = dirpool_parent(&data->dirpool, parent);
+      if (parent)
+       l++;
+    }
+  if (suf)
+    l += strlen(suf) + 1;
+  p = pool_alloctmpspace(pool, l + 1) + l;
+  *p = 0;
+  if (suf)
+    {
+      p -= strlen(suf);
+      strcpy(p, suf);
+      *--p = '/';
+    }
+  parent = did;
+  while (parent)
+    {
+      comp = dirpool_compid(&data->dirpool, parent);
+      comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
+      l = strlen(comps);
+      p -= l;
+      strncpy(p, comps, l);
+      parent = dirpool_parent(&data->dirpool, parent);
+      if (parent)
+        *--p = '/';
+    }
+  return p;
+}
+
 unsigned int
 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
 {