Blame SOURCES/0002-Add-support-for-storing-user-data-in-a-solv-file.patch

56f70c
From 9b89a186e3769631b6cee859be9d69063cfdfb94 Mon Sep 17 00:00:00 2001
56f70c
From: Michael Schroeder <mls@suse.de>
56f70c
Date: Fri, 25 Feb 2022 16:47:21 +0100
56f70c
Subject: [PATCH 2/3] Add support for storing user data in a solv file
56f70c
56f70c
Userdata can be arbritrary (binary)data with a maximum size of
56f70c
65535 bytes. It can be read without reading the complete
56f70c
solv file, but do not forget to rewind the fp after reading
56f70c
the user data.
56f70c
56f70c
New functions:
56f70c
void
56f70c
    void repowriter_set_userdata(Repowriter *writer, const void *data, int len)
56f70c
    int solv_read_userdata(FILE *fp, unsigned char **datap, int *lenp)
56f70c
---
56f70c
 src/libsolv.ver  |  2 ++
56f70c
 src/pooltypes.h  |  6 ++++--
56f70c
 src/repo_solv.c  | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
56f70c
 src/repo_solv.h  |  1 +
56f70c
 src/repo_write.c | 24 ++++++++++++++++++++-
56f70c
 src/repo_write.h |  3 +++
56f70c
 tools/dumpsolv.c | 50 ++++++++++++++++++++++++++++++++++++++++----
56f70c
 7 files changed, 133 insertions(+), 7 deletions(-)
56f70c
56f70c
diff --git a/src/libsolv.ver b/src/libsolv.ver
56f70c
index ee40d0ad..4c6fbf4f 100644
56f70c
--- a/src/libsolv.ver
56f70c
+++ b/src/libsolv.ver
56f70c
@@ -255,6 +255,7 @@ SOLV_1.0 {
56f70c
 		repowriter_set_keyqueue;
56f70c
 		repowriter_set_repodatarange;
56f70c
 		repowriter_set_solvablerange;
56f70c
+		repowriter_set_userdata;
56f70c
 		repowriter_write;
56f70c
 		selection_add;
56f70c
 		selection_filter;
56f70c
@@ -288,6 +289,7 @@ SOLV_1.0 {
56f70c
 		solv_malloc;
56f70c
 		solv_malloc2;
56f70c
 		solv_oom;
56f70c
+		solv_read_userdata;
56f70c
 		solv_realloc;
56f70c
 		solv_realloc2;
56f70c
 		solv_replacebadutf8;
56f70c
diff --git a/src/pooltypes.h b/src/pooltypes.h
56f70c
index e1f77b0e..3bde155a 100644
56f70c
--- a/src/pooltypes.h
56f70c
+++ b/src/pooltypes.h
56f70c
@@ -23,9 +23,11 @@
56f70c
 #define SOLV_VERSION_6 6
56f70c
 #define SOLV_VERSION_7 7
56f70c
 #define SOLV_VERSION_8 8
56f70c
+#define SOLV_VERSION_9 9
56f70c
 
56f70c
-#define SOLV_FLAG_PREFIX_POOL 4
56f70c
-#define SOLV_FLAG_SIZE_BYTES  8
56f70c
+#define SOLV_FLAG_PREFIX_POOL	4
56f70c
+#define SOLV_FLAG_SIZE_BYTES	8
56f70c
+#define SOLV_FLAG_USERDATA	16
56f70c
 
56f70c
 struct s_Stringpool;
56f70c
 typedef struct s_Stringpool Stringpool;
56f70c
diff --git a/src/repo_solv.c b/src/repo_solv.c
56f70c
index 761d06e6..2ba602b2 100644
56f70c
--- a/src/repo_solv.c
56f70c
+++ b/src/repo_solv.c
56f70c
@@ -514,6 +514,7 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
56f70c
   switch (solvversion)
56f70c
     {
56f70c
       case SOLV_VERSION_8:
56f70c
+      case SOLV_VERSION_9:
56f70c
 	break;
56f70c
       default:
56f70c
         return pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported SOLV version");
56f70c
@@ -552,6 +553,18 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
56f70c
 	  return pool_error(pool, SOLV_ERROR_CORRUPT, "main repository contains holes, cannot extend");
56f70c
     }
56f70c
 
56f70c
+  /*******  Part 0: skip optional userdata ******************************/
56f70c
+
56f70c
+  if (solvflags & SOLV_FLAG_USERDATA)
56f70c
+    {
56f70c
+      unsigned int userdatalen = read_u32(&data);
56f70c
+      if (userdatalen >= 65536)
56f70c
+        return pool_error(pool, SOLV_ERROR_CORRUPT, "illegal userdata length");
56f70c
+      while (userdatalen--)
56f70c
+	if (getc(data.fp) == EOF)
56f70c
+	  return pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
56f70c
+    }
56f70c
+
56f70c
   /*******  Part 1: string IDs  *****************************************/
56f70c
 
56f70c
   sizeid = read_u32(&data);	       /* size of string space */
56f70c
@@ -1353,3 +1366,44 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
56f70c
   return 0;
56f70c
 }
56f70c
 
56f70c
+int
56f70c
+solv_read_userdata(FILE *fp, unsigned char **datap, int *lenp)
56f70c
+{
56f70c
+  unsigned char d[4 * 10], *ud = 0;
56f70c
+  unsigned int n;
56f70c
+  if (fread(d, sizeof(d), 1, fp) != 1)
56f70c
+    return SOLV_ERROR_EOF;
56f70c
+  n = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
56f70c
+  if (n != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
56f70c
+    return SOLV_ERROR_NOT_SOLV;
56f70c
+  n = d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7];
56f70c
+  switch(n)
56f70c
+    {
56f70c
+    case SOLV_VERSION_8:
56f70c
+    case SOLV_VERSION_9:
56f70c
+      break;
56f70c
+    default:
56f70c
+      return SOLV_ERROR_UNSUPPORTED;
56f70c
+    }
56f70c
+  n = d[32] << 24 | d[33] << 16 | d[34] << 8 | d[35];
56f70c
+  if (!(n & SOLV_FLAG_USERDATA))
56f70c
+    n = 0;
56f70c
+  else
56f70c
+    n = d[36] << 24 | d[37] << 16 | d[38] << 8 | d[39];
56f70c
+  if (n >= 65536)
56f70c
+    return SOLV_ERROR_CORRUPT;
56f70c
+  if (n)
56f70c
+    {
56f70c
+      ud = solv_malloc(n + 1);
56f70c
+      if (fread(ud, n, 1, fp) != 1)
56f70c
+	{
56f70c
+	  solv_free(ud);
56f70c
+	  return SOLV_ERROR_EOF;
56f70c
+	}
56f70c
+      ud[n] = 0;
56f70c
+    }
56f70c
+  *datap = ud;
56f70c
+  if (lenp)
56f70c
+    *lenp = (int)n;
56f70c
+  return 0;
56f70c
+}
56f70c
diff --git a/src/repo_solv.h b/src/repo_solv.h
56f70c
index 0c663949..57bf1772 100644
56f70c
--- a/src/repo_solv.h
56f70c
+++ b/src/repo_solv.h
56f70c
@@ -23,6 +23,7 @@ extern "C" {
56f70c
 #endif
56f70c
 
56f70c
 extern int repo_add_solv(Repo *repo, FILE *fp, int flags);
56f70c
+extern int solv_read_userdata(FILE *fp, unsigned char **datap, int *lenp);
56f70c
 
56f70c
 #define SOLV_ADD_NO_STUBS	(1 << 8)
56f70c
 
56f70c
diff --git a/src/repo_write.c b/src/repo_write.c
56f70c
index af4e7599..a11de002 100644
56f70c
--- a/src/repo_write.c
56f70c
+++ b/src/repo_write.c
56f70c
@@ -1071,6 +1071,7 @@ repowriter_create(Repo *repo)
56f70c
 Repowriter *
56f70c
 repowriter_free(Repowriter *writer)
56f70c
 {
56f70c
+  solv_free(writer->userdata);
56f70c
   return solv_free(writer);
56f70c
 }
56f70c
 
56f70c
@@ -1107,6 +1108,17 @@ repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvable
56f70c
   writer->solvableend = solvableend;
56f70c
 }
56f70c
 
56f70c
+void
56f70c
+repowriter_set_userdata(Repowriter *writer, const void *data, int len)
56f70c
+{
56f70c
+  writer->userdata = solv_free(writer->userdata);
56f70c
+  writer->userdatalen = 0;
56f70c
+  if (len < 0 || len >= 65536)
56f70c
+    return;
56f70c
+  writer->userdata = len ? solv_memdup(data, len) : 0;
56f70c
+  writer->userdatalen = len;
56f70c
+}
56f70c
+
56f70c
 /*
56f70c
  * the code works the following way:
56f70c
  *
56f70c
@@ -1898,7 +1910,10 @@ for (i = 1; i < target.nkeys; i++)
56f70c
 
56f70c
   /* write file header */
56f70c
   write_u32(&target, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
56f70c
-  write_u32(&target, SOLV_VERSION_8);
56f70c
+  if (writer->userdatalen)
56f70c
+    write_u32(&target, SOLV_VERSION_9);
56f70c
+  else
56f70c
+    write_u32(&target, SOLV_VERSION_8);
56f70c
 
56f70c
 
56f70c
   /* write counts */
56f70c
@@ -1911,7 +1926,14 @@ for (i = 1; i < target.nkeys; i++)
56f70c
   solv_flags = 0;
56f70c
   solv_flags |= SOLV_FLAG_PREFIX_POOL;
56f70c
   solv_flags |= SOLV_FLAG_SIZE_BYTES;
56f70c
+  if (writer->userdatalen)
56f70c
+    solv_flags |= SOLV_FLAG_USERDATA;
56f70c
   write_u32(&target, solv_flags);
56f70c
+  if (writer->userdatalen)
56f70c
+    {
56f70c
+      write_u32(&target, writer->userdatalen);
56f70c
+      write_blob(&target, writer->userdata, writer->userdatalen);
56f70c
+    }
56f70c
 
56f70c
   if (nstrings)
56f70c
     {
56f70c
diff --git a/src/repo_write.h b/src/repo_write.h
56f70c
index 34716705..7734b013 100644
56f70c
--- a/src/repo_write.h
56f70c
+++ b/src/repo_write.h
56f70c
@@ -32,6 +32,8 @@ typedef struct s_Repowriter {
56f70c
   int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
56f70c
   void *kfdata;
56f70c
   Queue *keyq;
56f70c
+  void *userdata;
56f70c
+  int userdatalen;
56f70c
 } Repowriter;
56f70c
 
56f70c
 /* repowriter flags */
56f70c
@@ -46,6 +48,7 @@ void repowriter_set_keyfilter(Repowriter *writer, int (*keyfilter)(Repo *repo, R
56f70c
 void repowriter_set_keyqueue(Repowriter *writer, Queue *keyq);
56f70c
 void repowriter_set_repodatarange(Repowriter *writer, int repodatastart, int repodataend);
56f70c
 void repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvableend);
56f70c
+void repowriter_set_userdata(Repowriter *writer, const void *data, int len);
56f70c
 int repowriter_write(Repowriter *writer, FILE *fp);
56f70c
 
56f70c
 /* convenience functions */
56f70c
diff --git a/tools/dumpsolv.c b/tools/dumpsolv.c
56f70c
index 13076574..49651fbe 100644
56f70c
--- a/tools/dumpsolv.c
56f70c
+++ b/tools/dumpsolv.c
56f70c
@@ -13,6 +13,7 @@
56f70c
 
56f70c
 static int with_attr;
56f70c
 static int dump_json;
56f70c
+static int dump_userdata;
56f70c
 
56f70c
 #include "pool.h"
56f70c
 #include "chksum.h"
56f70c
@@ -394,10 +395,7 @@ int main(int argc, char **argv)
56f70c
   int c, i, j, n;
56f70c
   Solvable *s;
56f70c
   
56f70c
-  pool = pool_create();
56f70c
-  pool_setloadcallback(pool, loadcallback, 0);
56f70c
-
56f70c
-  while ((c = getopt(argc, argv, "haj")) >= 0)
56f70c
+  while ((c = getopt(argc, argv, "uhaj")) >= 0)
56f70c
     {
56f70c
       switch(c)
56f70c
 	{
56f70c
@@ -410,11 +408,55 @@ int main(int argc, char **argv)
56f70c
 	case 'j':
56f70c
 	  dump_json = 1;
56f70c
 	  break;
56f70c
+	case 'u':
56f70c
+	  dump_userdata++;
56f70c
+	  break;
56f70c
 	default:
56f70c
           usage(1);
56f70c
           break;
56f70c
 	}
56f70c
     }
56f70c
+  if (dump_userdata)
56f70c
+    {
56f70c
+      if (optind == argc)
56f70c
+	argc++;
56f70c
+      for (; optind < argc; optind++)
56f70c
+	{
56f70c
+	  unsigned char *userdata = 0;
56f70c
+	  int r, userdatalen = 0;
56f70c
+	  if (argv[optind] && freopen(argv[optind], "r", stdin) == 0)
56f70c
+	    {
56f70c
+	      perror(argv[optind]);
56f70c
+	      exit(1);
56f70c
+	    }
56f70c
+	  r = solv_read_userdata(stdin, &userdata, &userdatalen);
56f70c
+	  if (r)
56f70c
+	    {
56f70c
+	      fprintf(stderr, "could not read userdata: error %d\n", r);
56f70c
+	      exit(1);
56f70c
+	    }
56f70c
+	  if (dump_userdata > 1)
56f70c
+	    {
56f70c
+	      /* dump raw */
56f70c
+	      if (userdatalen && fwrite(userdata, userdatalen, 1, stdout) != 1)
56f70c
+		{
56f70c
+		  perror("fwrite");
56f70c
+		  exit(1);
56f70c
+		}
56f70c
+	    }
56f70c
+	  else
56f70c
+	    {
56f70c
+	      for (r = 0; r < userdatalen; r++)
56f70c
+		printf("%02x", userdata[r]);
56f70c
+	      printf("\n");
56f70c
+	    }
56f70c
+	  solv_free(userdata);
56f70c
+	}
56f70c
+      exit(0);
56f70c
+    }
56f70c
+
56f70c
+  pool = pool_create();
56f70c
+  pool_setloadcallback(pool, loadcallback, 0);
56f70c
   if (!dump_json)
56f70c
     pool_setdebuglevel(pool, 1);
56f70c
   if (dump_json)
56f70c
-- 
56f70c
2.31.1
56f70c