commit 5f33809: [Minor] Fix some issues with the in-place gzip, add gunzip

Vsevolod Stakhov vsevolod at rspamd.com
Sun Mar 26 12:21:05 UTC 2023


Author: Vsevolod Stakhov
Date: 2023-03-26 13:16:24 +0100
URL: https://github.com/rspamd/rspamd/commit/5f338096c1c055587f72ae9d9c93697e1d4dd354

[Minor] Fix some issues with the in-place gzip, add gunzip

---
 src/libutil/util.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 src/libutil/util.h | 10 +++++++-
 2 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/src/libutil/util.c b/src/libutil/util.c
index 539c5070d..253b651ad 100644
--- a/src/libutil/util.c
+++ b/src/libutil/util.c
@@ -2248,12 +2248,17 @@ rspamd_fstring_gzip (rspamd_fstring_t **in)
 
 	memset (&strm, 0, sizeof (strm));
 	ret = deflateInit2 (&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
-			MAX_WBITS + 16, MAX_MEM_LEVEL - 1, Z_DEFAULT_STRATEGY);
+		MAX_WBITS + 16, MAX_MEM_LEVEL - 1, Z_DEFAULT_STRATEGY);
 
 	if (ret != Z_OK) {
 		return FALSE;
 	}
 
+	if (buf->allocated < deflateBound (&strm, buf->len)) {
+		buf = rspamd_fstring_grow (buf, deflateBound (&strm, buf->len));
+		*in = buf;
+	}
+
 	strm.next_in = buf->str;
 	strm.avail_in = buf->len;
 
@@ -2267,16 +2272,17 @@ rspamd_fstring_gzip (rspamd_fstring_t **in)
 	/* Try to compress in-place */
 	tmp_remain = strm.next_out - temp;
 	if (tmp_remain <= (strm.avail_in ? buf->len - strm.avail_in : buf->allocated)) {
-		memcpy(buf, temp, tmp_remain);
+		memcpy(buf->str, temp, tmp_remain);
 		strm.next_out = (unsigned char *)buf->str + tmp_remain;
 		tmp_remain = 0;
 		while (ret == Z_OK) {
 			strm.avail_out = strm.avail_in ? strm.next_in - strm.next_out :
-							  ((unsigned char *)buf->str + buf->allocated) - strm.next_out;
+							 ((unsigned char *)buf->str + buf->allocated) - strm.next_out;
 			ret = deflate(&strm, Z_FINISH);
 		}
 		if (ret != Z_BUF_ERROR || strm.avail_in == 0) {
 			buf->len = strm.next_out - (unsigned char *)buf->str;
+			*in = buf;
 			return ret == Z_STREAM_END;
 		}
 	}
@@ -2289,13 +2295,67 @@ rspamd_fstring_gzip (rspamd_fstring_t **in)
 	memcpy(hold, strm.next_in, strm.avail_in);
 	strm.next_in = hold;
 	if (tmp_remain) {
-		memcpy(buf, temp, tmp_remain);
+		memcpy(buf->str, temp, tmp_remain);
 		strm.next_out = (unsigned char *)buf->str + tmp_remain;
 	}
 	strm.avail_out = ((unsigned char *)buf->str + buf->allocated) - strm.next_out;
 	ret = deflate(&strm, Z_FINISH);
 	g_free (hold);
 	buf->len = strm.next_out - (unsigned char *)buf->str;
+	*in = buf;
+
+	return ret == Z_STREAM_END;
+}
+
+gboolean
+rspamd_fstring_gunzip(rspamd_fstring_t **in)
+{
+	z_stream strm;
+	rspamd_fstring_t *buf = *in, *out = rspamd_fstring_sized_new ((*in)->len);
+	int ret;
+
+	memset(&strm, 0, sizeof(strm));
+	ret = inflateInit2(&strm, MAX_WBITS + 16);
+
+	if (ret != Z_OK) {
+		return FALSE;
+	}
+
+	strm.next_in = buf->str;
+	strm.avail_in = buf->len;
+
+	gsize total_out = 0;
+
+	do {
+		strm.next_out = out->str;
+		strm.avail_out = out->allocated;
+
+		ret = inflate(&strm, Z_NO_FLUSH);
+		if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) {
+			break;
+		}
+
+		gsize out_size = out->allocated - strm.avail_out;
+		if (total_out + out_size > out->allocated) {
+			out = rspamd_fstring_grow (out, total_out + out_size);
+		}
+
+		total_out += out_size;
+
+	} while (ret != Z_STREAM_END);
+
+	if (ret == Z_STREAM_END) {
+		*in = out;
+		out->len = total_out;
+		rspamd_fstring_free (buf);
+	}
+	else {
+		/* Revert */
+		*in = buf;
+		rspamd_fstring_free (out);
+	}
+
+	inflateEnd(&strm);
 
 	return ret == Z_STREAM_END;
 }
diff --git a/src/libutil/util.h b/src/libutil/util.h
index f747bce5b..ccc642adb 100644
--- a/src/libutil/util.h
+++ b/src/libutil/util.h
@@ -448,12 +448,20 @@ void rspamd_localtime (gint64 ts, struct tm *dest);
 
 /**
  * Compresses the input string using gzip+zlib. Old string is replaced and freed
- * if compressed. If not compressed it is untouched.
+ * if compressed.
  * @param in
  * @return TRUE if a string has been compressed
  */
 gboolean rspamd_fstring_gzip (rspamd_fstring_t **in);
 
+/**
+ * Compresses the input string using gzip+zlib. Old string is replaced and freed
+ * if compressed. If not compressed it is untouched.
+ * @param in
+ * @return TRUE if a string has been compressed
+ */
+gboolean rspamd_fstring_gunzip (rspamd_fstring_t **in);
+
 /**
  * Perform globbing searching for the specified path. Allow recursion,
  * returns an error if maximum nesting is reached.


More information about the Commits mailing list