[PATCH 3/4] jffsX-utils: add lzma support on jffs2reader

Frederic Germain frederic.germain at gmail.com
Tue Nov 9 00:17:50 PST 2021


Signed-off-by: Frederic Germain <frederic.germain at gmail.com>
---
 Makefile.am               |  4 ++++
 configure.ac              | 24 +++++++++++++++++++++
 include/linux/jffs2.h     |  2 ++
 include/mtd/jffs2-user.h  |  1 +
 jffsX-utils/Makemodule.am |  2 +-
 jffsX-utils/jffs2reader.c | 45 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/Makefile.am b/Makefile.am
index 9da38af..02a3073 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,6 +11,10 @@ if WITHOUT_LZO
 AM_CPPFLAGS += -DWITHOUT_LZO
 endif
 
+if WITHOUT_LZMA
+AM_CPPFLAGS += -DWITHOUT_LZMA
+endif
+
 if WITHOUT_ZSTD
 AM_CPPFLAGS += -DWITHOUT_ZSTD
 endif
diff --git a/configure.ac b/configure.ac
index f47100f..e5035c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -65,6 +65,7 @@ need_clock_gettime="no"
 need_pthread="no"
 need_uuid="no"
 need_zlib="no"
+need_lzma=""
 need_lzo="no"
 need_zstd="no"
 need_xattr="no"
@@ -158,6 +159,14 @@ AC_ARG_WITH([lzo],
 	*) AC_MSG_ERROR([bad value ${withval} for --without-lzo]) ;;
 	esac])
 
+AC_ARG_WITH([lzma],
+	[AS_HELP_STRING([--without-lzma], [Disable support for LZMA compression])],
+	[case "${withval}" in
+	yes) need_lzma="yes";;
+	no) need_lzma="no" ;;
+	*) AC_MSG_ERROR([bad value ${withval} for --without-lzma]) ;;
+	esac])
+
 AC_ARG_WITH([zstd],
 	[AS_HELP_STRING([--without-zstd], [Disable support for ZSTD compression])],
 	[case "${withval}" in
@@ -190,6 +199,7 @@ clock_gettime_missing="no"
 pthread_missing="no"
 uuid_missing="no"
 zlib_missing="no"
+lzma_missing="no"
 lzo_missing="no"
 zstd_missing="no"
 xattr_missing="no"
@@ -219,6 +229,14 @@ if test "x$need_pthread" = "xyes"; then
 	AX_PTHREAD([], [pthread_missing="yes"])
 fi
 
+if test "x$need_lzma" != "xno"; then
+	AC_ARG_VAR([LZMA_CFLAGS], [C compiler flags for lzma])
+	AC_ARG_VAR([LZMA_LIBS], [linker flags for lzma])
+	AC_CHECK_LIB([lzma], [lzma_alone_decoder], [LZMA_LIBS="-llzma"],
+		[lzma_missing="yes"]
+	)
+fi
+
 if test "x$need_lzo" = "xyes"; then
 	AC_ARG_VAR([LZO_CFLAGS], [C compiler flags for lzo])
 	AC_ARG_VAR([LZO_LIBS], [linker flags for lzo])
@@ -287,6 +305,11 @@ if test "x$zlib_missing" = "xyes"; then
 	dep_missing="yes"
 fi
 
+if test "x$need_lzma" = "xyes" -a "x$lzma_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find LZMA library required by options])
+	dep_missing="yes"
+fi
+
 if test "x$lzo_missing" = "xyes"; then
 	AC_MSG_WARN([cannot find LZO library required for mkfs programs])
 	AC_MSG_NOTICE([mtd-utils can optionally be built without mkfs.ubifs])
@@ -339,6 +362,7 @@ fi
 ##### generate output #####
 
 AM_CONDITIONAL([WITHOUT_LZO], [test "x$need_lzo" != "xyes"])
+AM_CONDITIONAL([WITHOUT_LZMA], [test "x$need_lzma" == "xno" -o "x$missing_lzma" == "xyes" ])
 AM_CONDITIONAL([WITHOUT_ZSTD], [test "x$need_zstd" != "xyes"])
 AM_CONDITIONAL([WITHOUT_XATTR], [test "x$need_xattr" != "xyes"])
 AM_CONDITIONAL([WITH_SELINUX], [test "x$need_selinux" == "xyes"])
diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h
index 7306f86..47abf62 100644
--- a/include/linux/jffs2.h
+++ b/include/linux/jffs2.h
@@ -47,6 +47,8 @@
 #define JFFS2_COMPR_DYNRUBIN	0x05
 #define JFFS2_COMPR_ZLIB	0x06
 #define JFFS2_COMPR_LZO		0x07
+// diff --git a/target/linux/generic/patches-4.1/530-jffs2_make_lzma_available.patch b/target/linux/generic/patches-4.1/530-jffs2_make_lzma_available.patch
+#define JFFS2_COMPR_LZMA	0x08 // https://git.openwrt.org/project/ubus.git;git://git.openwrt.org/project/ubox.git?p=openwrt/openwrt.git;a=commitdiff;h=a0c49ef46f7caf5eb02c635d446218201008ecff;hp=518ab154e059c9f39684f8c78159c9caf333716b
 /* Compatibility flags. */
 #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
 #define JFFS2_NODE_ACCURATE 0x2000
diff --git a/include/mtd/jffs2-user.h b/include/mtd/jffs2-user.h
index bc5d99a..7228b5f 100644
--- a/include/mtd/jffs2-user.h
+++ b/include/mtd/jffs2-user.h
@@ -36,6 +36,7 @@ extern int target_endian;
 #define le32_to_cpu(x)	(__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
 #define cpu_to_le16(x)	(__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
 #define cpu_to_le32(x)	(__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
+#define cpu_to_le64(x)	(__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_64(x))
 
 /* XATTR/POSIX-ACL related definition */
 /* Namespaces copied from xattr.h and posix_acl_xattr.h */
diff --git a/jffsX-utils/Makemodule.am b/jffsX-utils/Makemodule.am
index 96389f6..0c93c18 100644
--- a/jffsX-utils/Makemodule.am
+++ b/jffsX-utils/Makemodule.am
@@ -16,7 +16,7 @@ mkfs_jffs2_LDADD = libmtd.a $(ZLIB_LIBS) $(LZO_LIBS)
 mkfs_jffs2_CPPFLAGS = $(AM_CPPFLAGS) $(ZLIB_CFLAGS) $(LZO_CFLAGS)
 
 jffs2reader_SOURCES = jffsX-utils/jffs2reader.c	include/mtd/jffs2-user.h
-jffs2reader_LDADD = libmtd.a $(ZLIB_LIBS) $(LZO_LIBS)
+jffs2reader_LDADD = libmtd.a $(ZLIB_LIBS) $(LZO_LIBS) $(LZMA_LIBS)
 jffs2reader_CPPFLAGS = $(AM_CPPFLAGS) $(ZLIB_CFLAGS) $(LZO_CFLAGS)
 
 jffs2dump_SOURCES = jffsX-utils/jffs2dump.c include/mtd/jffs2-user.h
diff --git a/jffsX-utils/jffs2reader.c b/jffsX-utils/jffs2reader.c
index 33c5577..2aa2137 100644
--- a/jffsX-utils/jffs2reader.c
+++ b/jffsX-utils/jffs2reader.c
@@ -76,6 +76,9 @@ BUGS:
 #include <sys/stat.h>
 #include <dirent.h>
 #include <zlib.h>
+#ifndef WITHOUT_LZMA
+#include <lzma.h>
+#endif
 
 #include "mtd/jffs2-user.h"
 #include "common.h"
@@ -147,6 +150,48 @@ static void putblock(char *b, size_t bsize, size_t * rsize,
 			bzero(b + je32_to_cpu(n->offset), dlen);
 			break;
 
+#ifndef WITHOUT_LZMA
+		case JFFS2_COMPR_LZMA: {
+			// https://sourceforge.net/p/lzmautils/discussion/708858/thread/d02ebb9386/
+			lzma_stream strm = LZMA_STREAM_INIT;
+			size_t csize = je32_to_cpu(n->csize);
+			Bytef *in = (Bytef *) ((char *) n) + sizeof(struct jffs2_raw_inode);
+			Bytef *out = (Bytef *) b + je32_to_cpu(n->offset);
+			Bytef *compressed_with_header = xmalloc(13 + csize);
+
+			// LZMA properties byte (lc/lp/pb). typical 3/0/2 is 0x5D.
+			// But here works with 0/0/0
+			compressed_with_header[0] = 0;
+
+			// dictionary size as bytes[4], using value from preset 1
+			lzma_options_lzma opt_lzma;
+			if (lzma_lzma_preset(&opt_lzma, 1)) {
+				fprintf(stderr, "preset failed\n");
+				exit(1);
+			}
+			uint32_t dict_size_le = cpu_to_le32(opt_lzma.dict_size);
+			memcpy(&compressed_with_header[1], &dict_size_le, sizeof(dict_size_le));
+
+			// uncompressed size as unsigned 60-bit little endian integer
+			uint64_t uncompressed_size_le = cpu_to_le64(dlen);
+			memcpy(&compressed_with_header[5], &uncompressed_size_le, sizeof(uncompressed_size_le));
+
+			memcpy(&compressed_with_header[13], in, csize);
+			lzma_ret ret = lzma_alone_decoder(&strm, UINT64_MAX);
+			// lzma_ret ret = lzma_alone_decoder(&strm, hardware_memlimit_get(MODE_DECOMPRESS));
+			strm.next_in = compressed_with_header;
+			strm.avail_in = 13 + csize;
+			strm.next_out = out;
+			strm.avail_out = dlen;
+			ret = lzma_code(&strm, LZMA_RUN);
+			if (ret == LZMA_OK) {
+				printf("lzma_code ret:%d in:%ld\n", ret, strm.total_in);
+			}
+			free(compressed_with_header);
+		}
+			break;
+#endif
+
 			/* [DYN]RUBIN support required! */
 
 		default:
-- 
2.25.1




More information about the linux-mtd mailing list