[AS_HELP_STRING([--enable-lzma], [enable LZMA compression support @<:@default=no@:>@])],
[enable_lzma="$enableval"], [enable_lzma="no"])
+AC_ARG_WITH(zlib,
+ [AS_HELP_STRING([--without-zlib],
+ [Ignore presence of zlib inflate support @<:@default=enabled@:>@])])
+
+AC_ARG_WITH(libdeflate,
+ [AS_HELP_STRING([--with-libdeflate],
+ [Enable and build with libdeflate inflate support @<:@default=disabled@:>@])], [],
+ [with_libdeflate="no"])
+
AC_ARG_ENABLE(fuse,
[AS_HELP_STRING([--enable-fuse], [enable erofsfuse @<:@default=no@:>@])],
[enable_fuse="$enableval"], [enable_fuse="no"])
CPPFLAGS="${saved_CPPFLAGS}"
fi
+# Configure zlib
+AS_IF([test "x$with_zlib" != "xno"], [
+ PKG_CHECK_MODULES([zlib], [zlib])
+ # Paranoia: don't trust the result reported by pkgconfig before trying out
+ saved_LIBS="$LIBS"
+ saved_CPPFLAGS=${CPPFLAGS}
+ CPPFLAGS="${zlib_CFLAGS} ${CPPFLAGS}"
+ LIBS="${zlib_LIBS} $LIBS"
+ AC_CHECK_LIB(z, inflate, [
+ have_zlib="yes" ], [
+ AC_MSG_ERROR([zlib doesn't work properly])])
+ LIBS="${saved_LIBS}"
+ CPPFLAGS="${saved_CPPFLAGS}"], [have_zlib="no"])
+
+# Configure libdeflate
+AS_IF([test "x$with_libdeflate" != "xno"], [
+ PKG_CHECK_MODULES([libdeflate], [libdeflate])
+ # Paranoia: don't trust the result reported by pkgconfig before trying out
+ saved_LIBS="$LIBS"
+ saved_CPPFLAGS=${CPPFLAGS}
+ CPPFLAGS="${libdeflate_CFLAGS} ${CPPFLAGS}"
+ LIBS="${libdeflate_LIBS} $LIBS"
+ AC_CHECK_LIB(deflate, libdeflate_deflate_decompress, [
+ have_libdeflate="yes" ], [
+ AC_MSG_ERROR([libdeflate doesn't work properly])])
+ LIBS="${saved_LIBS}"
+ CPPFLAGS="${saved_CPPFLAGS}"], [have_libdeflate="no"])
+
# Enable 64-bit off_t
CFLAGS+=" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
AC_SUBST([liblzma_CFLAGS])
fi
+if test "x$have_zlib" = "xyes"; then
+ AC_DEFINE([HAVE_ZLIB], 1, [Define to 1 if zlib is found])
+fi
+
+if test "x$have_libdeflate" = "xyes"; then
+ AC_DEFINE([HAVE_LIBDEFLATE], 1, [Define to 1 if libdeflate is found])
+fi
+
# Dump maximum block size
AS_IF([test "x$erofs_cv_max_block_size" = "x"],
[$erofs_cv_max_block_size = 4096], [])
dump_erofs_SOURCES = main.c
dump_erofs_CFLAGS = -Wall -I$(top_srcdir)/include
dump_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libselinux_LIBS} \
- ${liblz4_LIBS} ${liblzma_LIBS}
+ ${liblz4_LIBS} ${liblzma_LIBS} ${zlib_LIBS} ${libdeflate_LIBS}
fsck_erofs_SOURCES = main.c
fsck_erofs_CFLAGS = -Wall -I$(top_srcdir)/include
fsck_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libselinux_LIBS} \
- ${liblz4_LIBS} ${liblzma_LIBS}
+ ${liblz4_LIBS} ${liblzma_LIBS} ${zlib_LIBS} ${libdeflate_LIBS}
if ENABLE_FUZZING
noinst_PROGRAMS = fuzz_erofsfsck
fuzz_erofsfsck_CFLAGS = -Wall -I$(top_srcdir)/include -DFUZZING
fuzz_erofsfsck_LDFLAGS = -fsanitize=address,fuzzer
fuzz_erofsfsck_LDADD = $(top_builddir)/lib/liberofs.la ${libselinux_LIBS} \
- ${liblz4_LIBS} ${liblzma_LIBS}
+ ${liblz4_LIBS} ${liblzma_LIBS} ${zlib_LIBS} ${libdeflate_LIBS}
endif
erofsfuse_CFLAGS = -Wall -I$(top_srcdir)/include
erofsfuse_CFLAGS += -DFUSE_USE_VERSION=26 ${libfuse_CFLAGS} ${libselinux_CFLAGS}
erofsfuse_LDADD = $(top_builddir)/lib/liberofs.la ${libfuse_LIBS} ${liblz4_LIBS} \
- ${libselinux_LIBS} ${liblzma_LIBS}
+ ${libselinux_LIBS} ${liblzma_LIBS} ${zlib_LIBS} ${libdeflate_LIBS}
enum {
Z_EROFS_COMPRESSION_LZ4 = 0,
Z_EROFS_COMPRESSION_LZMA = 1,
+ Z_EROFS_COMPRESSION_DEFLATE = 2,
Z_EROFS_COMPRESSION_MAX
};
#define Z_EROFS_ALL_COMPR_ALGS ((1 << Z_EROFS_COMPRESSION_MAX) - 1)
#define Z_EROFS_LZMA_MAX_DICT_SIZE (8 * Z_EROFS_PCLUSTER_MAX_SIZE)
+/* 6 bytes (+ length field = 8 bytes) */
+struct z_erofs_deflate_cfgs {
+ u8 windowbits; /* 8..15 for DEFLATE */
+ u8 reserved[5];
+} __packed;
+
/*
* bit 0 : COMPACTED_2B indexes (0 - off; 1 - on)
* e.g. for 4k logical cluster size, 4B if compacted 2B is off;
#include "erofs/err.h"
#include "erofs/print.h"
+#ifdef HAVE_LIBDEFLATE
+/* if libdeflate is available, use libdeflate instead. */
+#include <libdeflate.h>
+
+static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq)
+{
+ u8 *dest = (u8 *)rq->out;
+ u8 *src = (u8 *)rq->in;
+ u8 *buff = NULL;
+ size_t actual_out;
+ unsigned int inputmargin = 0;
+ struct libdeflate_decompressor *inf;
+ enum libdeflate_result ret;
+
+ while (!src[inputmargin & (erofs_blksiz() - 1)])
+ if (!(++inputmargin & (erofs_blksiz() - 1)))
+ break;
+
+ if (inputmargin >= rq->inputsize)
+ return -EFSCORRUPTED;
+
+ if (rq->decodedskip) {
+ buff = malloc(rq->decodedlength);
+ if (!buff)
+ return -ENOMEM;
+ dest = buff;
+ }
+
+ inf = libdeflate_alloc_decompressor();
+ if (!inf)
+ return -ENOMEM;
+
+ if (rq->partial_decoding) {
+ ret = libdeflate_deflate_decompress(inf, src + inputmargin,
+ rq->inputsize - inputmargin, dest,
+ rq->decodedlength, &actual_out);
+ if (ret && ret != LIBDEFLATE_INSUFFICIENT_SPACE) {
+ ret = -EIO;
+ goto out_inflate_end;
+ }
+
+ if (actual_out != rq->decodedlength) {
+ ret = -EIO;
+ goto out_inflate_end;
+ }
+ } else {
+ ret = libdeflate_deflate_decompress(inf, src + inputmargin,
+ rq->inputsize - inputmargin, dest,
+ rq->decodedlength, NULL);
+ if (ret) {
+ ret = -EIO;
+ goto out_inflate_end;
+ }
+ }
+
+ if (rq->decodedskip)
+ memcpy(rq->out, dest + rq->decodedskip,
+ rq->decodedlength - rq->decodedskip);
+
+out_inflate_end:
+ libdeflate_free_decompressor(inf);
+ if (buff)
+ free(buff);
+ return ret;
+}
+#elif defined(HAVE_ZLIB)
+#include <zlib.h>
+
+/* report a zlib or i/o error */
+static int zerr(int ret)
+{
+ switch (ret) {
+ case Z_STREAM_ERROR:
+ return -EINVAL;
+ case Z_DATA_ERROR:
+ return -EIO;
+ case Z_MEM_ERROR:
+ return -ENOMEM;
+ case Z_ERRNO:
+ case Z_VERSION_ERROR:
+ default:
+ return -EFAULT;
+ }
+}
+
+static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq)
+{
+ int ret = 0;
+ u8 *dest = (u8 *)rq->out;
+ u8 *src = (u8 *)rq->in;
+ u8 *buff = NULL;
+ unsigned int inputmargin = 0;
+ z_stream strm;
+
+ while (!src[inputmargin & (erofs_blksiz() - 1)])
+ if (!(++inputmargin & (erofs_blksiz() - 1)))
+ break;
+
+ if (inputmargin >= rq->inputsize)
+ return -EFSCORRUPTED;
+
+ if (rq->decodedskip) {
+ buff = malloc(rq->decodedlength);
+ if (!buff)
+ return -ENOMEM;
+ dest = buff;
+ }
+
+ /* allocate inflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit2(&strm, -15);
+ if (ret != Z_OK)
+ return zerr(ret);
+
+ strm.next_in = src + inputmargin;
+ strm.avail_in = rq->inputsize - inputmargin;
+ strm.next_out = dest;
+ strm.avail_out = rq->decodedlength;
+
+ ret = inflate(&strm, rq->partial_decoding ? Z_SYNC_FLUSH : Z_FINISH);
+ if (ret != Z_STREAM_END || strm.total_out != rq->decodedlength) {
+ if (ret != Z_OK || !rq->partial_decoding) {
+ ret = zerr(ret);
+ goto out_inflate_end;
+ }
+ }
+
+ if (rq->decodedskip)
+ memcpy(rq->out, dest + rq->decodedskip,
+ rq->decodedlength - rq->decodedskip);
+
+out_inflate_end:
+ inflateEnd(&strm);
+ if (buff)
+ free(buff);
+ return ret;
+}
+#endif
+
#ifdef HAVE_LIBLZMA
#include <lzma.h>
#ifdef HAVE_LIBLZMA
if (rq->alg == Z_EROFS_COMPRESSION_LZMA)
return z_erofs_decompress_lzma(rq);
+#endif
+#if defined(HAVE_ZLIB) || defined(HAVE_LIBDEFLATE)
+ if (rq->alg == Z_EROFS_COMPRESSION_DEFLATE)
+ return z_erofs_decompress_deflate(rq);
#endif
return -EOPNOTSUPP;
}