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

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