From af4a56a06a9e347737077217c37cfdb6c411a6df Mon Sep 17 00:00:00 2001
From: KOLANICH <kolan_n@mail.ru>
Date: Thu, 23 Jul 2020 16:37:06 +0300
Subject: [PATCH] Added passing the needed info through an environment variable
 in bencode serialization. Can be further extended, if we need more info.

---
 src/archives.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++-
 src/main.h     |  19 ++++++++-
 src/unpack.c   |  32 ++++++++++++++-
 3 files changed, 153 insertions(+), 3 deletions(-)

diff --git a/src/archives.c b/src/archives.c
index ee1ae51ed..ea9e7a607 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -1464,6 +1464,106 @@ void cu_fileslist(int argc, void **argv) {
   tar_pool_release();
 }
 
+static struct passed_through_package_info passed_through_package_info_init(){
+	struct passed_through_package_info unpackedInfo;
+	unpackedInfo.count = 0;
+	unpackedInfo.records = NULL;
+	return unpackedInfo;
+}
+
+static void free_pascal_string(struct pascal_str *str){
+	free(str->ptr);
+	str->ptr = NULL;
+	str->size = 0;
+}
+
+static void free_passed_through_package_info_record(struct passed_through_package_info_record *r){
+	free_pascal_string(&r->name);
+	free_pascal_string(&r->arch);
+	free_pascal_string(&r->version);
+}
+
+static void passed_through_package_info_free(struct passed_through_package_info *unpackedInfo){
+	for(unsigned short int i = 0; i< unpackedInfo->count; ++i){
+		free_passed_through_package_info_record(&unpackedInfo->records[i]);
+	}
+	free(unpackedInfo->records);
+	unpackedInfo->records = NULL;
+	unpackedInfo->count = 0;
+}
+
+static size_t measure_benc_pascal_str(struct pascal_str *s){
+	return snprintf(NULL, 0, "%zu:", s->size) + s->size;
+}
+
+static void serialize_benc_pascal_str(char **serPtr, struct pascal_str *s){
+	*serPtr += sprintf(*serPtr, "%zu:%s", s->size, s->ptr);
+}
+static void serialize_benc_tag(char **serPtr, char tag){
+	*serPtr += sprintf(*serPtr, "1:%c", tag);
+}
+
+static void serialize_benc_tag_value_pair(char **serPtr, char tag, struct pascal_str *s){
+	if(s->ptr){
+		serialize_benc_tag(serPtr, tag);
+		serialize_benc_pascal_str(serPtr, s);
+	}
+}
+
+enum {
+	OUR_BENC_KEY_TAG_SIZE = 3,
+	BENC_START_END = 2, // l<...>e
+};
+
+static size_t measure_benc_tag_value_pair(struct pascal_str *s){
+	if(s->ptr){
+		return measure_benc_pascal_str(s) + OUR_BENC_KEY_TAG_SIZE;
+	} else {
+		return 0;
+	}
+}
+
+
+static size_t precompute_the_bencode_serialized_size(struct passed_through_package_info *unpackedInfo){
+    size_t totalSize = BENC_START_END;
+    int i;
+    for(i=0;i<unpackedInfo->count;++i){
+      if(unpackedInfo->records[i].name.size){
+        totalSize += measure_benc_pascal_str(&unpackedInfo->records[i].name);
+        totalSize += BENC_START_END;
+        totalSize += measure_benc_tag_value_pair(&unpackedInfo->records[i].arch);
+        totalSize += measure_benc_tag_value_pair(&unpackedInfo->records[i].version);
+        totalSize += measure_benc_tag_value_pair(&unpackedInfo->records[i].origin);
+      }
+    }
+    totalSize ++; // null termination
+    return totalSize;
+}
+
+static void serialize_the_info_about_triggerers_into_an_env_variable(struct passed_through_package_info *unpackedInfo){
+    unsigned int i;
+    size_t totalSize = precompute_the_bencode_serialized_size(unpackedInfo);
+    char buf4str[totalSize];
+
+    memset(buf4str, ' ', totalSize);
+    buf4str[totalSize - 1] = 0;
+    char * serPtr = &buf4str[0];
+    *(serPtr++) = 'd';
+    for(i=0;i<unpackedInfo->count;++i){
+      serialize_benc_pascal_str(&serPtr, &unpackedInfo->records[i].name);
+      *(serPtr++) = 'd';
+      serialize_benc_tag_value_pair(&serPtr, 'A', &unpackedInfo->records[i].arch);
+      serialize_benc_tag_value_pair(&serPtr, 'V', &unpackedInfo->records[i].version);
+      serialize_benc_tag_value_pair(&serPtr, 'O', &unpackedInfo->records[i].origin);
+      *(serPtr++) = 'e';
+    }
+    *(serPtr++) = 'e';
+    if((unsigned long)((char*) serPtr - (char*) buf4str) > totalSize){
+      ohshit("Buffer overflow %zu > %zu !", (char*) serPtr - (char*) buf4str, totalSize);
+    }
+    setenv("DPKG_TRIGGERER_PACKAGES_INFO", buf4str, 1);
+}
+
 int
 archivefiles(const char *const *argv)
 {
@@ -1472,6 +1572,7 @@ archivefiles(const char *const *argv)
   int i;
   jmp_buf ejbuf;
   enum modstatdb_rw msdbflags;
+  struct passed_through_package_info unpackedInfo = passed_through_package_info_init();
 
   trigproc_install_hooks();
 
@@ -1574,7 +1675,7 @@ archivefiles(const char *const *argv)
 
     dpkg_selabel_load();
 
-    process_archive(argp[i]);
+    process_archive(argp[i], &unpackedInfo);
     onerr_abort++;
     m_output(stdout, _("<standard output>"));
     m_output(stderr, _("<standard error>"));
@@ -1582,6 +1683,8 @@ archivefiles(const char *const *argv)
 
     pop_error_context(ehflag_normaltidy);
   }
+  serialize_the_info_about_triggerers_into_an_env_variable(&unpackedInfo);
+  passed_through_package_info_free(&unpackedInfo);
 
   dpkg_selabel_close();
 
diff --git a/src/main.h b/src/main.h
index e7fe820a7..70fe47d92 100644
--- a/src/main.h
+++ b/src/main.h
@@ -142,6 +142,23 @@ struct invoke_list {
 	struct invoke_hook *head, **tail;
 };
 
+struct pascal_str {
+	size_t size;
+	char * ptr;
+};
+
+struct passed_through_package_info_record {
+	struct pascal_str name;
+	struct pascal_str arch;
+	struct pascal_str version;
+	struct pascal_str origin;
+};
+
+struct passed_through_package_info{
+	unsigned int count;
+	struct passed_through_package_info_record *records;
+};
+
 /* from perpkgstate.c */
 
 void ensure_package_clientdata(struct pkginfo *pkg);
@@ -149,7 +166,7 @@ void ensure_package_clientdata(struct pkginfo *pkg);
 /* from archives.c */
 
 int archivefiles(const char *const *argv);
-void process_archive(const char *filename);
+void process_archive(const char *filename, struct passed_through_package_info *unpackedInfo);
 bool wanttoinstall(struct pkginfo *pkg);
 
 /* from update.c */
diff --git a/src/unpack.c b/src/unpack.c
index 4a143666e..f6a716d11 100644
--- a/src/unpack.c
+++ b/src/unpack.c
@@ -1064,7 +1064,36 @@ pkg_remove_backup_files(struct pkginfo *pkg, struct fsys_namenode_list *newfiles
   }
 }
 
-void process_archive(const char *filename) {
+
+struct pascal_str init_pascal_str(char * s){
+	struct pascal_str res;
+	if(s){
+		res.size = strlen(s);
+		res.ptr = malloc(res.size + 1);
+		strcpy(res.ptr, s);
+	}else{
+		res.size = 0;
+		res.ptr = NULL;
+	}
+	return res;
+}
+
+
+void passed_through_package_info_append(struct passed_through_package_info *unpackedInfo, struct pkginfo *pkg){
+	struct passed_through_package_info_record * rec;
+	unsigned int prevCountAndIndex = unpackedInfo->count;
+	unpackedInfo->records = realloc(unpackedInfo->records, sizeof(struct passed_through_package_info_record) * (++unpackedInfo->count));
+	if(!unpackedInfo->records){
+		ohshite(_("Unable to reallocate in %s"), __func__);
+	}
+	rec = &(unpackedInfo->records[prevCountAndIndex]);
+	rec->name = init_pascal_str(pkg->set->name);
+	rec->version = init_pascal_str(pkg->available.version.version);
+	rec->arch = init_pascal_str(pkg->available.arch->name);
+	rec->origin = init_pascal_str(pkg->available.origin);
+}
+
+void process_archive(const char *filename, struct passed_through_package_info *unpackedInfo) {
   static const struct tar_operations tf = {
     .read = tarfileread,
     .extract_file = tarobject,
@@ -1146,6 +1175,7 @@ void process_archive(const char *filename) {
 
   parsedb(cidir, parsedb_flags, &pkg);
 
+  passed_through_package_info_append(unpackedInfo, pkg);
   if (!pkg->archives) {
     pkg->archives = nfmalloc(sizeof(*pkg->archives));
     pkg->archives->next = NULL;
