[File] [PATCH] support decompressing lzip archives via lzlib

Michał Górny mgorny at gentoo.org
Thu Sep 15 09:28:45 UTC 2022


---
 configure.ac   | 19 ++++++++++++
 src/compress.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+)

diff --git a/configure.ac b/configure.ac
index f6593917..9a0a2250 100644
--- a/configure.ac
+++ b/configure.ac
@@ -54,6 +54,11 @@ AC_ARG_ENABLE([zstdlib],
 [AS_HELP_STRING([--disable-zstdlib], [disable zstdlib compression support @<:@default=auto@:>@])])
 AC_MSG_RESULT($enable_zstdlib)
 
+AC_MSG_CHECKING(for lzlib support)
+AC_ARG_ENABLE([lzlib],
+[AS_HELP_STRING([--disable-lzlib], [disable liblz (lzip) compression support @<:@default=auto@:>@])])
+AC_MSG_RESULT($enable_lzlib)
+
 AC_MSG_CHECKING(for libseccomp support)
 AC_ARG_ENABLE([libseccomp],
 [AS_HELP_STRING([--disable-libseccomp], [disable libseccomp sandboxing @<:@default=auto@:>@])])
@@ -120,6 +125,9 @@ fi
 if test "$enable_zstdlib" != "no"; then
   AC_CHECK_HEADERS(zstd.h zstd_errors.h)
 fi
+if test "$enable_lzlib" != "no"; then
+  AC_CHECK_HEADERS(lzlib.h)
+fi
 AC_CHECK_TYPE([sig_t],[AC_DEFINE([HAVE_SIG_T],1,[Have sig_t type])],,[#include <signal.h>])
 
 dnl Checks for typedefs, structures, and compiler characteristics.
@@ -191,6 +199,9 @@ fi
 if test "$enable_zstdlib" != "no"; then
   AC_CHECK_LIB(zstd, ZSTD_createDStream)
 fi
+if test "$enable_lzlib" != "no"; then
+  AC_CHECK_LIB(lz, LZ_decompress_open)
+fi
 if test "$enable_libseccomp" != "no"; then
     AC_CHECK_LIB(seccomp, seccomp_init)
 fi
@@ -234,6 +245,14 @@ fi
 if  test "$ac_cv_header_zstd_h$ac_cv_lib_zstd_ZSTD_createDStream" = "yesyes"; then
   AC_DEFINE([ZSTDLIBSUPPORT], 1, [Enable zstdlib compression support])
 fi
+if test "$enable_lzlib" = "yes"; then
+  if test "$ac_cv_header_lzlib_h$ac_cv_lib_lz_LZ_decompress_open" != "yesyes"; then
+    AC_MSG_ERROR([lzlib support requested but not found])
+  fi
+fi
+if  test "$ac_cv_header_lzlib_h$ac_cv_lib_lz_LZ_decompress_open" = "yesyes"; then
+  AC_DEFINE([LZLIBSUPPORT], 1, [Enable lzlib compression support])
+fi
 
 AC_CONFIG_FILES([Makefile src/Makefile magic/Makefile tests/Makefile doc/Makefile python/Makefile libmagic.pc])
 AC_OUTPUT
diff --git a/src/compress.c b/src/compress.c
index fb8ac377..0d4ea705 100644
--- a/src/compress.c
+++ b/src/compress.c
@@ -85,6 +85,11 @@ typedef void (*sig_t)(int);
 #include <zstd_errors.h>
 #endif
 
+#if defined(HAVE_LZLIB_H) && defined(LZLIBSUPPORT)
+#define BUILTIN_LZLIB
+#include <lzlib.h>
+#endif
+
 #ifdef DEBUG
 int tty = -1;
 #define DPRINTF(...)	do { \
@@ -180,6 +185,7 @@ private const struct {
 } compr[] = {
 #define METH_FROZEN	2
 #define METH_BZIP	7
+#define METH_LZIP	8
 #define METH_XZ		9
 #define METH_ZSTD	12
 #define METH_LZMA	13
@@ -234,6 +240,10 @@ private int uncompressxzlib(const unsigned char *, unsigned char **, size_t,
 private int uncompresszstd(const unsigned char *, unsigned char **, size_t,
     size_t *);
 #endif
+#ifdef BUILTIN_LZLIB
+private int uncompresslzlib(const unsigned char *, unsigned char **, size_t,
+    size_t *);
+#endif
 
 static int makeerror(unsigned char **, size_t *, const char *, ...)
     __attribute__((__format__(__printf__, 3, 4)));
@@ -754,6 +764,72 @@ err:
 }
 #endif
 
+#ifdef BUILTIN_LZLIB
+private int
+uncompresslzlib(const unsigned char *old, unsigned char **newch,
+    size_t bytes_max, size_t *n)
+{
+	enum LZ_Errno err;
+	size_t old_remaining = *n;
+	size_t new_remaining = bytes_max;
+	size_t total_read = 0;
+	unsigned char *bufp;
+	struct LZ_Decoder *dec;
+
+	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
+		return makeerror(newch, n, "No buffer, %s", strerror(errno));
+	bufp = *newch;
+
+	dec = LZ_decompress_open();
+	if (!dec) {
+		free(*newch);
+		return makeerror(newch, n, "unable to allocate LZ_Decoder");
+	}
+	if (LZ_decompress_errno(dec) != LZ_ok)
+		goto err;
+
+	while (1) {
+		// LZ_decompress_read() stops at member boundaries, so we may
+		// have more than one successful read after writing all data
+		// we have.
+		if (old_remaining > 0) {
+			int wr = LZ_decompress_write(dec, old, old_remaining);
+			if (wr < 0)
+				goto err;
+			old_remaining -= wr;
+			old += wr;
+		}
+
+		int rd = LZ_decompress_read(dec, bufp, new_remaining);
+		if (rd > 0) {
+			new_remaining -= rd;
+			bufp += rd;
+			total_read += rd;
+		}
+
+		if (rd < 0 || LZ_decompress_errno(dec) != LZ_ok)
+			goto err;
+		if (new_remaining == 0)
+			break;
+		if (old_remaining == 0 && rd == 0)
+			break;
+	}
+
+	LZ_decompress_close(dec);
+	*n = total_read;
+
+	/* let's keep the nul-terminate tradition */
+	*bufp = '\0';
+
+	return OKDATA;
+err:
+	err = LZ_decompress_errno(dec);
+	LZ_decompress_close(dec);
+	free(*newch);
+	return makeerror(newch, n, "lzlib error: %s", LZ_strerror(err));
+}
+#endif
+
 
 static int
 makeerror(unsigned char **buf, size_t *len, const char *fmt, ...)
@@ -924,6 +1000,10 @@ methodname(size_t method)
 #ifdef BUILTIN_ZSTDLIB
 	case METH_ZSTD:
 		return "zstd";
+#endif
+#ifdef BUILTIN_LZLIB
+	case METH_LZIP:
+		return "lzlib";
 #endif
 	default:
 		return compr[method].argv[0];
@@ -964,6 +1044,10 @@ uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
 #ifdef BUILTIN_ZSTDLIB
 	case METH_ZSTD:
 		return uncompresszstd(old, newch, bytes_max, n);
+#endif
+#ifdef BUILTIN_LZLIB
+	case METH_LZIP:
+		return uncompresslzlib(old, newch, bytes_max, n);
 #endif
 	default:
 		break;
-- 
2.37.3



More information about the File mailing list