From 183cf393a453cddb689666ce7fb35a97e7f523bf Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Tue, 15 Sep 2020 21:13:56 +0200 Subject: Add bzip2 stream compression support Signed-off-by: David Oberhollenzer --- bin/sqfs2tar/Makemodule.am | 3 +- bin/tar2sqfs/Makemodule.am | 2 +- configure.ac | 14 +++++ include/fstream.h | 4 +- lib/fstream/Makemodule.am | 6 ++ lib/fstream/compress/bzip2.c | 87 +++++++++++++++++++++++++++++ lib/fstream/compress/ostream_compressor.c | 5 ++ lib/fstream/compressor.c | 10 ++++ lib/fstream/internal.h | 4 ++ lib/fstream/uncompress/autodetect.c | 1 + lib/fstream/uncompress/bzip2.c | 87 +++++++++++++++++++++++++++++ lib/fstream/uncompress/istream_compressor.c | 5 ++ 12 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 lib/fstream/compress/bzip2.c create mode 100644 lib/fstream/uncompress/bzip2.c diff --git a/bin/sqfs2tar/Makemodule.am b/bin/sqfs2tar/Makemodule.am index 9dbfbbb..a28c3b8 100644 --- a/bin/sqfs2tar/Makemodule.am +++ b/bin/sqfs2tar/Makemodule.am @@ -4,7 +4,8 @@ sqfs2tar_SOURCES += bin/sqfs2tar/xattr.c sqfs2tar_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) sqfs2tar_LDADD = libcommon.a libutil.a libsquashfs.la libtar.a sqfs2tar_LDADD += libfstream.a libcompat.a libfstree.a -sqfs2tar_LDADD += $(ZLIB_LIBS) $(XZ_LIBS) $(LZO_LIBS) $(PTHREAD_LIBS) +sqfs2tar_LDADD += $(ZLIB_LIBS) $(XZ_LIBS) $(LZO_LIBS) $(BZIP2_LIBS) +sqfs2tar_LDADD += $(PTHREAD_LIBS) if WITH_OWN_ZLIB sqfs2tar_LDADD += libz.la diff --git a/bin/tar2sqfs/Makemodule.am b/bin/tar2sqfs/Makemodule.am index 58d1ef9..ce66e5c 100644 --- a/bin/tar2sqfs/Makemodule.am +++ b/bin/tar2sqfs/Makemodule.am @@ -3,7 +3,7 @@ tar2sqfs_SOURCES += bin/tar2sqfs/options.c bin/tar2sqfs/process_tarball.c tar2sqfs_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) tar2sqfs_LDADD = libcommon.a libsquashfs.la libtar.a libfstream.a tar2sqfs_LDADD += libfstree.a libcompat.a libfstree.a $(LZO_LIBS) -tar2sqfs_LDADD += $(ZLIB_LIBS) $(XZ_LIBS) $(PTHREAD_LIBS) +tar2sqfs_LDADD += $(ZLIB_LIBS) $(XZ_LIBS) $(BZIP2_LIBS) $(PTHREAD_LIBS) if WITH_OWN_ZLIB tar2sqfs_LDADD += libz.la diff --git a/configure.ac b/configure.ac index b3bb300..3de1109 100644 --- a/configure.ac +++ b/configure.ac @@ -59,6 +59,11 @@ AM_CONDITIONAL([WINDOWS], [test "x$build_windows" = "xyes"]) ##### config options ##### +AC_ARG_WITH([bzip2], + [AS_HELP_STRING([--with-bzip2], + [Build with bzip2 compression support])], + [], [with_bzip2="check"]) + AC_ARG_WITH([xz], [AS_HELP_STRING([--with-xz], [Build with xz compression support])], [], [with_xz="check"]) @@ -138,6 +143,13 @@ fi ##### search for dependencies ##### +AS_IF([test "x$with_bzip2" != "xno"], [ + PKG_CHECK_MODULES(BZIP2, [bzip2], [with_bzip2="yes"], + [AS_IF([test "x$with_bzip2" != "xcheck"], + [AC_MSG_ERROR([cannot Bzip2 libs])], + [with_bzip2="no"])]) +], []) + AS_IF([test "x$with_gzip" != "xno" -a "x$with_builtin_zlib" != "xyes"], [ PKG_CHECK_MODULES(ZLIB, [zlib], [with_gzip="yes"], [AS_IF([test "x$with_gzip" != "xcheck"], @@ -206,6 +218,7 @@ AS_IF([test "x$with_pthread" != "xno"], [ [with_pthread="no"])]) ], []) +AM_CONDITIONAL([WITH_BZIP2], [test "x$with_bzip2" = "xyes"]) AM_CONDITIONAL([WITH_GZIP], [test "x$with_gzip" = "xyes"]) AM_CONDITIONAL([WITH_XZ], [test "x$with_xz" = "xyes"]) AM_CONDITIONAL([WITH_LZ4], [test "x$with_lz4" = "xyes"]) @@ -276,6 +289,7 @@ AC_MSG_RESULT([ LZO support: ${with_lzo} LZ4 support: ${with_lz4} ZSTD support: ${with_zstd} + BZIP2 support: ${with_bzip2} SELinux support: ${with_selinux} Using pthreads: ${with_pthread} diff --git a/include/fstream.h b/include/fstream.h index a934c95..8693fff 100644 --- a/include/fstream.h +++ b/include/fstream.h @@ -68,8 +68,10 @@ enum { FSTREAM_COMPRESSOR_ZSTD = 3, + FSTREAM_COMPRESSOR_BZIP2 = 4, + FSTREAM_COMPRESSOR_MIN = 1, - FSTREAM_COMPRESSOR_MAX = 3, + FSTREAM_COMPRESSOR_MAX = 4, }; #ifdef __cplusplus diff --git a/lib/fstream/Makemodule.am b/lib/fstream/Makemodule.am index 8a1254c..1834cb8 100644 --- a/lib/fstream/Makemodule.am +++ b/lib/fstream/Makemodule.am @@ -35,4 +35,10 @@ libfstream_a_SOURCES += lib/fstream/uncompress/zstd.c libfstream_a_CPPFLAGS += -DWITH_ZSTD endif +if WITH_BZIP2 +libfstream_a_SOURCES += lib/fstream/compress/bzip2.c +libfstream_a_SOURCES += lib/fstream/uncompress/bzip2.c +libfstream_a_CPPFLAGS += -DWITH_BZIP2 +endif + noinst_LIBRARIES += libfstream.a diff --git a/lib/fstream/compress/bzip2.c b/lib/fstream/compress/bzip2.c new file mode 100644 index 0000000..3ca425a --- /dev/null +++ b/lib/fstream/compress/bzip2.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * bzip2.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "../internal.h" + +#include + +typedef struct { + ostream_comp_t base; + + bz_stream strm; +} ostream_bzip2_t; + +static int flush_inbuf(ostream_comp_t *base, bool finish) +{ + ostream_bzip2_t *bzip2 = (ostream_bzip2_t *)base; + size_t have; + int ret; + + bzip2->strm.next_in = (char *)base->inbuf; + bzip2->strm.avail_in = base->inbuf_used; + + for (;;) { + bzip2->strm.next_out = (char *)base->outbuf; + bzip2->strm.avail_out = sizeof(base->outbuf); + + ret = BZ2_bzCompress(&bzip2->strm, finish ? BZ_FINISH : BZ_RUN); + + if (ret < 0 && ret != BZ_OUTBUFF_FULL) { + fprintf(stderr, "%s: internal error in bzip2 " + "compressor.\n", + base->wrapped->get_filename(base->wrapped)); + return -1; + } + + have = sizeof(base->outbuf) - bzip2->strm.avail_out; + + if (base->wrapped->append(base->wrapped, base->outbuf, have)) + return -1; + + if (ret == BZ_STREAM_END || ret == BZ_OUTBUFF_FULL || + bzip2->strm.avail_in == 0) { + break; + } + } + + if (bzip2->strm.avail_in > 0) { + memmove(base->inbuf, bzip2->strm.next_in, + bzip2->strm.avail_in); + } + + base->inbuf_used = bzip2->strm.avail_in; + return 0; +} + +static void cleanup(ostream_comp_t *base) +{ + ostream_bzip2_t *bzip2 = (ostream_bzip2_t *)base; + + BZ2_bzCompressEnd(&bzip2->strm); +} + +ostream_comp_t *ostream_bzip2_create(const char *filename) +{ + ostream_bzip2_t *bzip2 = calloc(1, sizeof(*bzip2)); + ostream_comp_t *base = (ostream_comp_t *)bzip2; + + if (bzip2 == NULL) { + fprintf(stderr, "%s: creating bzip2 compressor: %s.\n", + filename, strerror(errno)); + return NULL; + } + + if (BZ2_bzCompressInit(&bzip2->strm, 9, 0, 30) != BZ_OK) { + fprintf(stderr, "%s: error initializing bzip2 compressor.\n", + filename); + free(bzip2); + return NULL; + } + + base->flush_inbuf = flush_inbuf; + base->cleanup = cleanup; + return base; +} diff --git a/lib/fstream/compress/ostream_compressor.c b/lib/fstream/compress/ostream_compressor.c index d1d55e1..7ea7919 100644 --- a/lib/fstream/compress/ostream_compressor.c +++ b/lib/fstream/compress/ostream_compressor.c @@ -80,6 +80,11 @@ ostream_t *ostream_compressor_create(ostream_t *strm, int comp_id) case FSTREAM_COMPRESSOR_ZSTD: #ifdef WITH_ZSTD comp = ostream_zstd_create(strm->get_filename(strm)); +#endif + break; + case FSTREAM_COMPRESSOR_BZIP2: +#ifdef WITH_BZIP2 + comp = ostream_bzip2_create(strm->get_filename(strm)); #endif break; default: diff --git a/lib/fstream/compressor.c b/lib/fstream/compressor.c index 84a859c..903a5f7 100644 --- a/lib/fstream/compressor.c +++ b/lib/fstream/compressor.c @@ -17,6 +17,9 @@ int fstream_compressor_id_from_name(const char *name) if (strcmp(name, "zstd") == 0) return FSTREAM_COMPRESSOR_ZSTD; + if (strcmp(name, "bzip2") == 0) + return FSTREAM_COMPRESSOR_BZIP2; + return -1; } @@ -31,6 +34,9 @@ const char *fstream_compressor_name_from_id(int id) if (id == FSTREAM_COMPRESSOR_ZSTD) return "zstd"; + if (id == FSTREAM_COMPRESSOR_BZIP2) + return "bzip2"; + return NULL; } @@ -48,6 +54,10 @@ bool fstream_compressor_exists(int id) #ifdef WITH_ZSTD case FSTREAM_COMPRESSOR_ZSTD: return true; +#endif +#ifdef WITH_BZIP2 + case FSTREAM_COMPRESSOR_BZIP2: + return true; #endif default: break; diff --git a/lib/fstream/internal.h b/lib/fstream/internal.h index 83ecc64..2dc81e4 100644 --- a/lib/fstream/internal.h +++ b/lib/fstream/internal.h @@ -59,12 +59,16 @@ SQFS_INTERNAL ostream_comp_t *ostream_xz_create(const char *filename); SQFS_INTERNAL ostream_comp_t *ostream_zstd_create(const char *filename); +SQFS_INTERNAL ostream_comp_t *ostream_bzip2_create(const char *filename); + SQFS_INTERNAL istream_comp_t *istream_gzip_create(const char *filename); SQFS_INTERNAL istream_comp_t *istream_xz_create(const char *filename); SQFS_INTERNAL istream_comp_t *istream_zstd_create(const char *filename); +SQFS_INTERNAL istream_comp_t *istream_bzip2_create(const char *filename); + #ifdef __cplusplus } #endif diff --git a/lib/fstream/uncompress/autodetect.c b/lib/fstream/uncompress/autodetect.c index b788518..61628f8 100644 --- a/lib/fstream/uncompress/autodetect.c +++ b/lib/fstream/uncompress/autodetect.c @@ -14,6 +14,7 @@ static const struct { { FSTREAM_COMPRESSOR_GZIP, (const sqfs_u8 *)"\x1F\x8B\x08", 3 }, { FSTREAM_COMPRESSOR_XZ, (const sqfs_u8 *)("\xFD" "7zXZ"), 6 }, { FSTREAM_COMPRESSOR_ZSTD, (const sqfs_u8 *)"\x28\xB5\x2F\xFD", 4 }, + { FSTREAM_COMPRESSOR_BZIP2, (const sqfs_u8 *)"BZh", 3 }, }; int istream_detect_compressor(istream_t *strm, diff --git a/lib/fstream/uncompress/bzip2.c b/lib/fstream/uncompress/bzip2.c new file mode 100644 index 0000000..b5fae5c --- /dev/null +++ b/lib/fstream/uncompress/bzip2.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * bzip2.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "../internal.h" + +#include + +typedef struct { + istream_comp_t base; + + bz_stream strm; +} istream_bzip2_t; + +static int precache(istream_t *base) +{ + istream_bzip2_t *bzip2 = (istream_bzip2_t *)base; + istream_t *wrapped = ((istream_comp_t *)base)->wrapped; + int ret; + + for (;;) { + ret = istream_precache(wrapped); + if (ret != 0) + return ret; + + bzip2->strm.next_in = (char *)wrapped->buffer; + bzip2->strm.avail_in = wrapped->buffer_used; + + bzip2->strm.next_out = (char *)base->buffer + base->buffer_used; + bzip2->strm.avail_out = BUFSZ - base->buffer_used; + + if (bzip2->strm.avail_out < 1) + break; + + ret = BZ2_bzDecompress(&bzip2->strm); + + if (ret < 0) { + fprintf(stderr, "%s: internal error in bzip2 " + "decompressor.\n", + wrapped->get_filename(wrapped)); + return -1; + } + + base->buffer_used = BUFSZ - bzip2->strm.avail_out; + wrapped->buffer_offset = wrapped->buffer_used - + bzip2->strm.avail_in; + + if (ret == BZ_STREAM_END) { + base->eof = true; + break; + } + } + + return 0; +} + +static void cleanup(istream_comp_t *base) +{ + istream_bzip2_t *bzip2 = (istream_bzip2_t *)base; + + BZ2_bzDecompressEnd(&bzip2->strm); +} + +istream_comp_t *istream_bzip2_create(const char *filename) +{ + istream_bzip2_t *bzip2 = calloc(1, sizeof(*bzip2)); + istream_comp_t *base = (istream_comp_t *)bzip2; + + if (bzip2 == NULL) { + fprintf(stderr, "%s: creating bzip2 compressor: %s.\n", + filename, strerror(errno)); + return NULL; + } + + if (BZ2_bzDecompressInit(&bzip2->strm, 0, 0) != BZ_OK) { + fprintf(stderr, "%s: error initializing bzip2 decompressor.\n", + filename); + free(bzip2); + return NULL; + } + + ((istream_t *)base)->precache = precache; + base->cleanup = cleanup; + return base; +} diff --git a/lib/fstream/uncompress/istream_compressor.c b/lib/fstream/uncompress/istream_compressor.c index 2262c9b..bc8ef39 100644 --- a/lib/fstream/uncompress/istream_compressor.c +++ b/lib/fstream/uncompress/istream_compressor.c @@ -42,6 +42,11 @@ istream_t *istream_compressor_create(istream_t *strm, int comp_id) case FSTREAM_COMPRESSOR_ZSTD: #ifdef WITH_ZSTD comp = istream_zstd_create(strm->get_filename(strm)); +#endif + break; + case FSTREAM_COMPRESSOR_BZIP2: +#ifdef WITH_BZIP2 + comp = istream_bzip2_create(strm->get_filename(strm)); #endif break; default: -- cgit v1.2.3