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

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