diff -urdN linux-4.19.8/Documentation/00-INDEX linux-4.19.8.new/Documentation/00-INDEX --- linux-4.19.8/Documentation/00-INDEX 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/Documentation/00-INDEX 2018-12-09 18:01:59.000000000 +0100 @@ -242,6 +242,8 @@ - info on creator of above logo & site to get additional images from. lsm.txt - Linux Security Modules: General Security Hooks for Linux +lzip.txt + - info on lzip compression for the linux kernel. lzo.txt - kernel LZO decompressor input formats m68k/ diff -urdN linux-4.19.8/Documentation/dontdiff linux-4.19.8.new/Documentation/dontdiff --- linux-4.19.8/Documentation/dontdiff 2018-12-08 19:33:27.000000000 +0100 +++ linux-4.19.8.new/Documentation/dontdiff 2018-12-09 18:01:59.000000000 +0100 @@ -26,6 +26,7 @@ *.ll *.log *.lst +*.lz *.lzma *.lzo *.mo diff -urdN linux-4.19.8/Documentation/filesystems/squashfs.txt linux-4.19.8.new/Documentation/filesystems/squashfs.txt --- linux-4.19.8/Documentation/filesystems/squashfs.txt 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/Documentation/filesystems/squashfs.txt 2018-12-09 18:01:59.000000000 +0100 @@ -2,7 +2,7 @@ ======================= Squashfs is a compressed read-only filesystem for Linux. -It uses zlib, lz4, lzo, or xz compression to compress files, inodes and +It uses zlib, lz4, lzip, lzo, or xz compression to compress files, inodes and directories. Inodes in the system are very small and all blocks are packed to minimise data overhead. Block sizes greater than 4K are supported up to a maximum of 1Mbytes (default block size 128K). diff -urdN linux-4.19.8/Documentation/lzip.txt linux-4.19.8.new/Documentation/lzip.txt --- linux-4.19.8/Documentation/lzip.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.19.8.new/Documentation/lzip.txt 2018-12-09 19:07:33.000000000 +0100 @@ -0,0 +1,59 @@ +============================== +Lzip data compression in Linux +============================== + +Introduction +============ + +Lzip is a lossless data compressor with a user interface similar to the +one of gzip or bzip2. Lzip can compress about as fast as gzip (lzip -0) +or compress most files more than bzip2 (lzip -9). Decompression speed is +intermediate between gzip and bzip2. Lzip implements the LZMA algorithm. + +Lzip has been designed, written and tested with great care to be the +standard general-purpose compressor for unix-like systems. The lzip +format is as simple as possible (but not simpler). It provides accurate +and robust 3 factor integrity checking. + +Learn more about lzip at http://www.nongnu.org/lzip/lzip.html + +Lzip related components in the kernel +===================================== + +The lzip_decompress module in lib/lzip_decompress.c provides a versatile +lzip decompression function able to do buffer to buffer decompression or +stream decompression with fill and flush callback functions. The usage +of the function is documented in include/linux/lzip.h. + +For decompressing the kernel image, initramfs, and initrd, there is a +wrapper function in lib/decompress_lunzip.c providing the same common +interface as the other decompress_*.c files, which is defined in +include/linux/decompress/generic.h. + +For kernel makefiles, two commands are provided in scripts/Makefile.lib +for use with $(call if_changed). The kernel image must be compressed +with $(call if_changed,klzip) which will append a four-byte trailer +containing the size of the uncompressed data, which is needed by the +boot code. Other things should be compressed with $(call if_changed,lzip). + +Testing +======= + +Lzip-compressed kernel images of multiple linux versions since 2.6.30.10 +have been built and tested, even on machines as modest as an AMD 486-DX2 +at 66 MHz with 64 MiB of RAM. In the worst case (on the slow machine +above), lzip just increased the boot time a 15% compared with gzip. On +more modern machines, lzip may boot slightly faster than gzip. It just +takes 0.2 seconds for lzip to decompress vmlinuz-4.4.16 on my machine. + +Decompression time is usually a small fraction of the total boot time. +For example, using lz4 on a desktop machine in order to save 0.05 +seconds of a total boot time of 20 seconds is probably not worth the +increased image size. + +Xlunzip is a test tool for the lzip_decompress module. It is similar to +lunzip, but it uses the lzip_decompress module as a backend. The xlunzip +home page is at http://www.nongnu.org/lzip/xlunzip.html + +Author: Antonio Diaz Diaz +Updated: 2018-12-09 diff -urdN linux-4.19.8/Documentation/x86/boot.txt linux-4.19.8.new/Documentation/x86/boot.txt --- linux-4.19.8/Documentation/x86/boot.txt 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/Documentation/x86/boot.txt 2018-12-09 18:01:59.000000000 +0100 @@ -665,10 +665,10 @@ The payload may be compressed. The format of both the compressed and uncompressed data should be determined using the standard magic numbers. The currently supported compression formats are gzip - (magic numbers 1F 8B or 1F 9E), bzip2 (magic number 42 5A), LZMA - (magic number 5D 00), XZ (magic number FD 37), and LZ4 (magic number - 02 21). The uncompressed payload is currently always ELF (magic - number 7F 45 4C 46). + (magic numbers 1F 8B or 1F 9E), bzip2 (magic number 42 5A), lzip + (magic number 4C 5A), LZMA (magic number 5D 00), XZ (magic number FD + 37), and LZ4 (magic number 02 21). The uncompressed payload is + currently always ELF (magic number 7F 45 4C 46). Field name: payload_length Type: read diff -urdN linux-4.19.8/Makefile linux-4.19.8.new/Makefile --- linux-4.19.8/Makefile 2018-12-08 19:31:53.000000000 +0100 +++ linux-4.19.8.new/Makefile 2018-12-09 18:01:59.000000000 +0100 @@ -912,14 +912,17 @@ export mod_strip_cmd # CONFIG_MODULE_COMPRESS, if defined, will cause module to be compressed -# after they are installed in agreement with CONFIG_MODULE_COMPRESS_GZIP -# or CONFIG_MODULE_COMPRESS_XZ. +# after they are installed in agreement with CONFIG_MODULE_COMPRESS_GZIP, +# CONFIG_MODULE_COMPRESS_LZIP or CONFIG_MODULE_COMPRESS_XZ. mod_compress_cmd = true ifdef CONFIG_MODULE_COMPRESS ifdef CONFIG_MODULE_COMPRESS_GZIP mod_compress_cmd = gzip -n -f endif # CONFIG_MODULE_COMPRESS_GZIP + ifdef CONFIG_MODULE_COMPRESS_LZIP + mod_compress_cmd = lzip -f + endif # CONFIG_MODULE_COMPRESS_LZIP ifdef CONFIG_MODULE_COMPRESS_XZ mod_compress_cmd = xz -f endif # CONFIG_MODULE_COMPRESS_XZ @@ -931,6 +934,7 @@ # INITRD_COMPRESS-y := gzip INITRD_COMPRESS-$(CONFIG_RD_BZIP2) := bzip2 +INITRD_COMPRESS-$(CONFIG_RD_LZIP) := lzip INITRD_COMPRESS-$(CONFIG_RD_LZMA) := lzma INITRD_COMPRESS-$(CONFIG_RD_XZ) := xz INITRD_COMPRESS-$(CONFIG_RD_LZO) := lzo diff -urdN linux-4.19.8/arch/arm/Kconfig linux-4.19.8.new/arch/arm/Kconfig --- linux-4.19.8/arch/arm/Kconfig 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/arm/Kconfig 2018-12-09 18:01:59.000000000 +0100 @@ -77,6 +77,7 @@ select HAVE_IRQ_TIME_ACCOUNTING select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZ4 + select HAVE_KERNEL_LZIP select HAVE_KERNEL_LZMA select HAVE_KERNEL_LZO select HAVE_KERNEL_XZ diff -urdN linux-4.19.8/arch/arm/boot/compressed/Makefile linux-4.19.8.new/arch/arm/boot/compressed/Makefile --- linux-4.19.8/arch/arm/boot/compressed/Makefile 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/arm/boot/compressed/Makefile 2018-12-09 18:01:59.000000000 +0100 @@ -71,6 +71,7 @@ CPPFLAGS_vmlinux.lds := -DTEXT_START="$(ZTEXTADDR)" -DBSS_START="$(ZBSSADDR)" compress-$(CONFIG_KERNEL_GZIP) = gzip +compress-$(CONFIG_KERNEL_LZIP) = klzip compress-$(CONFIG_KERNEL_LZO) = lzo compress-$(CONFIG_KERNEL_LZMA) = lzma compress-$(CONFIG_KERNEL_XZ) = xzkern diff -urdN linux-4.19.8/arch/arm/boot/compressed/decompress.c linux-4.19.8.new/arch/arm/boot/compressed/decompress.c --- linux-4.19.8/arch/arm/boot/compressed/decompress.c 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/arm/boot/compressed/decompress.c 2018-12-09 18:01:59.000000000 +0100 @@ -37,6 +37,10 @@ #include "../../../../lib/decompress_inflate.c" #endif +#ifdef CONFIG_KERNEL_LZIP +#include "../../../../lib/decompress_lunzip.c" +#endif + #ifdef CONFIG_KERNEL_LZO #include "../../../../lib/decompress_unlzo.c" #endif diff -urdN linux-4.19.8/arch/sh/Kconfig linux-4.19.8.new/arch/sh/Kconfig --- linux-4.19.8/arch/sh/Kconfig 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/sh/Kconfig 2018-12-09 18:01:59.000000000 +0100 @@ -25,6 +25,7 @@ select HAVE_KERNEL_GZIP select CPU_NO_EFFICIENT_FFS select HAVE_KERNEL_BZIP2 + select HAVE_KERNEL_LZIP select HAVE_KERNEL_LZMA select HAVE_KERNEL_XZ select HAVE_KERNEL_LZO diff -urdN linux-4.19.8/arch/sh/Makefile linux-4.19.8.new/arch/sh/Makefile --- linux-4.19.8/arch/sh/Makefile 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/sh/Makefile 2018-12-09 18:01:59.000000000 +0100 @@ -209,9 +209,9 @@ libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y) libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y) -BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.xz uImage.lzo \ - uImage.srec uImage.bin zImage vmlinux.bin vmlinux.srec \ - romImage +BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lz uImage.lzma uImage.xz \ + uImage.lzo uImage.srec uImage.bin zImage vmlinux.bin \ + vmlinux.srec romImage PHONY += $(BOOT_TARGETS) all: $(notdir $(KBUILD_IMAGE)) @@ -238,6 +238,7 @@ @echo ' uImage.bin - Kernel-only image for U-Boot (bin)' @echo '* uImage.gz - Kernel-only image for U-Boot (gzip)' @echo ' uImage.bz2 - Kernel-only image for U-Boot (bzip2)' + @echo ' uImage.lz - Kernel-only image for U-Boot (lzip)' @echo ' uImage.lzma - Kernel-only image for U-Boot (lzma)' @echo ' uImage.xz - Kernel-only image for U-Boot (xz)' @echo ' uImage.lzo - Kernel-only image for U-Boot (lzo)' diff -urdN linux-4.19.8/arch/sh/boot/Makefile linux-4.19.8.new/arch/sh/boot/Makefile --- linux-4.19.8/arch/sh/boot/Makefile 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/sh/boot/Makefile 2018-12-09 18:01:59.000000000 +0100 @@ -22,14 +22,15 @@ suffix-y := bin suffix-$(CONFIG_KERNEL_GZIP) := gz suffix-$(CONFIG_KERNEL_BZIP2) := bz2 +suffix-$(CONFIG_KERNEL_LZIP) := lz suffix-$(CONFIG_KERNEL_LZMA) := lzma suffix-$(CONFIG_KERNEL_XZ) := xz suffix-$(CONFIG_KERNEL_LZO) := lzo targets := zImage vmlinux.srec romImage uImage uImage.srec uImage.gz \ - uImage.bz2 uImage.lzma uImage.xz uImage.lzo uImage.bin -extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ - vmlinux.bin.xz vmlinux.bin.lzo + uImage.bz2 uImage.lz uImage.lzma uImage.xz uImage.lzo uImage.bin +extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lz \ + vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo subdir- := compressed romimage $(obj)/zImage: $(obj)/compressed/vmlinux FORCE @@ -71,6 +72,9 @@ $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE $(call if_changed,bzip2) +$(obj)/vmlinux.bin.lz: $(obj)/vmlinux.bin FORCE + $(call if_changed,klzip) + $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE $(call if_changed,lzma) @@ -86,6 +90,9 @@ $(obj)/uImage.gz: $(obj)/vmlinux.bin.gz $(call if_changed,uimage,gzip) +$(obj)/uImage.lz: $(obj)/vmlinux.bin.lz + $(call if_changed,uimage,lzip) + $(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma $(call if_changed,uimage,lzma) diff -urdN linux-4.19.8/arch/sh/boot/compressed/Makefile linux-4.19.8.new/arch/sh/boot/compressed/Makefile --- linux-4.19.8/arch/sh/boot/compressed/Makefile 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/sh/boot/compressed/Makefile 2018-12-09 18:01:59.000000000 +0100 @@ -5,10 +5,9 @@ # create a compressed vmlinux image from the original vmlinux # -targets := vmlinux vmlinux.bin vmlinux.bin.gz \ - vmlinux.bin.bz2 vmlinux.bin.lzma \ - vmlinux.bin.xz vmlinux.bin.lzo \ - head_$(BITS).o misc.o piggy.o +targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \ + vmlinux.bin.lz vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo \ + head_$(BITS).o misc.o piggy.o OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/cache.o @@ -66,6 +65,8 @@ $(call if_changed,gzip) $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE $(call if_changed,bzip2) +$(obj)/vmlinux.bin.lz: $(vmlinux.bin.all-y) FORCE + $(call if_changed,klzip) $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE $(call if_changed,lzma) $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE diff -urdN linux-4.19.8/arch/sh/boot/compressed/misc.c linux-4.19.8.new/arch/sh/boot/compressed/misc.c --- linux-4.19.8/arch/sh/boot/compressed/misc.c 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/sh/boot/compressed/misc.c 2018-12-09 18:01:59.000000000 +0100 @@ -58,6 +58,10 @@ #include "../../../../lib/decompress_bunzip2.c" #endif +#ifdef CONFIG_KERNEL_LZIP +#include "../../../../lib/decompress_lunzip.c" +#endif + #ifdef CONFIG_KERNEL_LZMA #include "../../../../lib/decompress_unlzma.c" #endif diff -urdN linux-4.19.8/arch/x86/Kconfig linux-4.19.8.new/arch/x86/Kconfig --- linux-4.19.8/arch/x86/Kconfig 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/x86/Kconfig 2018-12-09 18:01:59.000000000 +0100 @@ -158,6 +158,7 @@ select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZ4 + select HAVE_KERNEL_LZIP select HAVE_KERNEL_LZMA select HAVE_KERNEL_LZO select HAVE_KERNEL_XZ diff -urdN linux-4.19.8/arch/x86/boot/compressed/Makefile linux-4.19.8.new/arch/x86/boot/compressed/Makefile --- linux-4.19.8/arch/x86/boot/compressed/Makefile 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/x86/boot/compressed/Makefile 2018-12-09 18:01:59.000000000 +0100 @@ -23,8 +23,8 @@ # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. KCOV_INSTRUMENT := n -targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ - vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 +targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lz \ + vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 KBUILD_CFLAGS := -m$(BITS) -O2 KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC) @@ -134,6 +134,8 @@ $(call if_changed,gzip) $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE $(call if_changed,bzip2) +$(obj)/vmlinux.bin.lz: $(vmlinux.bin.all-y) FORCE + $(call if_changed,klzip) $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE $(call if_changed,lzma) $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE @@ -145,6 +147,7 @@ suffix-$(CONFIG_KERNEL_GZIP) := gz suffix-$(CONFIG_KERNEL_BZIP2) := bz2 +suffix-$(CONFIG_KERNEL_LZIP) := lz suffix-$(CONFIG_KERNEL_LZMA) := lzma suffix-$(CONFIG_KERNEL_XZ) := xz suffix-$(CONFIG_KERNEL_LZO) := lzo diff -urdN linux-4.19.8/arch/x86/boot/compressed/misc.c linux-4.19.8.new/arch/x86/boot/compressed/misc.c --- linux-4.19.8/arch/x86/boot/compressed/misc.c 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/arch/x86/boot/compressed/misc.c 2018-12-09 18:01:59.000000000 +0100 @@ -61,6 +61,10 @@ #include "../../../../lib/decompress_bunzip2.c" #endif +#ifdef CONFIG_KERNEL_LZIP +#include "../../../../lib/decompress_lunzip.c" +#endif + #ifdef CONFIG_KERNEL_LZMA #include "../../../../lib/decompress_unlzma.c" #endif diff -urdN linux-4.19.8/fs/squashfs/Kconfig linux-4.19.8.new/fs/squashfs/Kconfig --- linux-4.19.8/fs/squashfs/Kconfig 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/fs/squashfs/Kconfig 2018-12-09 18:01:59.000000000 +0100 @@ -4,7 +4,7 @@ help Saying Y here includes support for SquashFS 4.0 (a Compressed Read-Only File System). Squashfs is a highly compressed read-only - filesystem for Linux. It uses zlib, lzo or xz compression to + filesystem for Linux. It uses zlib, lzip, lzo or xz compression to compress both files, inodes and directories. Inodes in the system are very small and all blocks are packed to minimise data overhead. Block sizes greater than 4K are supported up to a maximum of 1 Mbytes @@ -134,6 +134,21 @@ file systems will be readable without selecting this option. If unsure, say N. + +config SQUASHFS_LZIP + bool "Include support for LZIP compressed file systems" + depends on SQUASHFS + select LZIP_DECOMPRESS + help + Saying Y here includes support for reading Squashfs file systems + compressed with LZIP compression. LZIP gives better compression + than the default zlib compression, at the expense of greater CPU + and memory overhead. + + LZIP is not the standard compression used in Squashfs and so most + file systems will be readable without selecting this option. + + If unsure, say N. config SQUASHFS_LZO bool "Include support for LZO compressed file systems" diff -urdN linux-4.19.8/fs/squashfs/Makefile linux-4.19.8.new/fs/squashfs/Makefile --- linux-4.19.8/fs/squashfs/Makefile 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/fs/squashfs/Makefile 2018-12-09 18:01:59.000000000 +0100 @@ -13,6 +13,7 @@ squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o squashfs-$(CONFIG_SQUASHFS_LZ4) += lz4_wrapper.o +squashfs-$(CONFIG_SQUASHFS_LZIP) += lzip_wrapper.o squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o squashfs-$(CONFIG_SQUASHFS_ZLIB) += zlib_wrapper.o diff -urdN linux-4.19.8/fs/squashfs/decompressor.c linux-4.19.8.new/fs/squashfs/decompressor.c --- linux-4.19.8/fs/squashfs/decompressor.c 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/fs/squashfs/decompressor.c 2018-12-09 18:01:59.000000000 +0100 @@ -47,6 +47,12 @@ }; #endif +#ifndef CONFIG_SQUASHFS_LZIP +static const struct squashfs_decompressor squashfs_lzip_comp_ops = { + NULL, NULL, NULL, NULL, LZIP_COMPRESSION, "lzip", 0 +}; +#endif + #ifndef CONFIG_SQUASHFS_LZO static const struct squashfs_decompressor squashfs_lzo_comp_ops = { NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 @@ -78,6 +84,7 @@ static const struct squashfs_decompressor *decompressor[] = { &squashfs_zlib_comp_ops, &squashfs_lz4_comp_ops, + &squashfs_lzip_comp_ops, &squashfs_lzo_comp_ops, &squashfs_xz_comp_ops, &squashfs_lzma_unsupported_comp_ops, diff -urdN linux-4.19.8/fs/squashfs/decompressor.h linux-4.19.8.new/fs/squashfs/decompressor.h --- linux-4.19.8/fs/squashfs/decompressor.h 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/fs/squashfs/decompressor.h 2018-12-09 18:01:59.000000000 +0100 @@ -50,6 +50,10 @@ extern const struct squashfs_decompressor squashfs_lz4_comp_ops; #endif +#ifdef CONFIG_SQUASHFS_LZIP +extern const struct squashfs_decompressor squashfs_lzip_comp_ops; +#endif + #ifdef CONFIG_SQUASHFS_LZO extern const struct squashfs_decompressor squashfs_lzo_comp_ops; #endif diff -urdN linux-4.19.8/fs/squashfs/lzip_wrapper.c linux-4.19.8.new/fs/squashfs/lzip_wrapper.c --- linux-4.19.8/fs/squashfs/lzip_wrapper.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.19.8.new/fs/squashfs/lzip_wrapper.c 2018-12-09 18:01:59.000000000 +0100 @@ -0,0 +1,129 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2014 + * Phillip Lougher + * Copyright (C) 2018 Antonio Diaz Diaz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * lzip_wrapper.c + */ + +#include +#include +#include +#include +#include + +#include "squashfs_fs.h" +#include "squashfs_fs_sb.h" +#include "squashfs.h" +#include "decompressor.h" +#include "page_actor.h" + +struct squashfs_lzip { + void *input; + void *output; +}; + + +static void *lzip_init(struct squashfs_sb_info *msblk, void *buff) +{ + int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); + struct squashfs_lzip *stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (stream == NULL) + goto failed; + stream->input = vmalloc(block_size); + if (stream->input == NULL) + goto failed2; + stream->output = vmalloc(block_size); + if (stream->output == NULL) + goto failed3; + + return stream; + +failed3: + vfree(stream->input); +failed2: + kfree(stream); +failed: + ERROR("Failed to initialise LZIP decompressor\n"); + return ERR_PTR(-ENOMEM); +} + + +static void lzip_free(void *strm) +{ + struct squashfs_lzip *stream = strm; + + if (stream) { + vfree(stream->input); + vfree(stream->output); + } + kfree(stream); +} + + +static int lzip_uncompress(struct squashfs_sb_info *msblk, void *strm, + struct buffer_head **bh, int b, int offset, int length, + struct squashfs_page_actor *output) +{ + struct squashfs_lzip *stream = strm; + void *buff = stream->input, *data; + long out_pos; + int avail, i, bytes = length, res; + + for (i = 0; i < b; i++) { + avail = min(bytes, msblk->devblksize - offset); + memcpy(buff, bh[i]->b_data + offset, avail); + buff += avail; + bytes -= avail; + offset = 0; + put_bh(bh[i]); + } + + res = lzip_decompress(stream->input, length, 0, 0, stream->output, + output->length, 0, &out_pos); + if (res < 0) { + ERROR("LZIP error code %d\n", res); + return -EIO; + } + bytes = out_pos; + data = squashfs_first_page(output); + buff = stream->output; + while (data) { + if (bytes <= PAGE_SIZE) { + memcpy(data, buff, bytes); + break; + } + memcpy(data, buff, PAGE_SIZE); + buff += PAGE_SIZE; + bytes -= PAGE_SIZE; + data = squashfs_next_page(output); + } + squashfs_finish_page(output); + + return out_pos; +} + + +const struct squashfs_decompressor squashfs_lzip_comp_ops = { + .init = lzip_init, + .free = lzip_free, + .decompress = lzip_uncompress, + .id = LZIP_COMPRESSION, + .name = "lzip", + .supported = 1 +}; diff -urdN linux-4.19.8/fs/squashfs/squashfs_fs.h linux-4.19.8.new/fs/squashfs/squashfs_fs.h --- linux-4.19.8/fs/squashfs/squashfs_fs.h 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/fs/squashfs/squashfs_fs.h 2018-12-09 18:01:59.000000000 +0100 @@ -248,6 +248,7 @@ #define XZ_COMPRESSION 4 #define LZ4_COMPRESSION 5 #define ZSTD_COMPRESSION 6 +#define LZIP_COMPRESSION 7 struct squashfs_super_block { __le32 s_magic; diff -urdN linux-4.19.8/include/linux/decompress/lunzip.h linux-4.19.8.new/include/linux/decompress/lunzip.h --- linux-4.19.8/include/linux/decompress/lunzip.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.19.8.new/include/linux/decompress/lunzip.h 2018-12-09 18:01:59.000000000 +0100 @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DECOMPRESS_LUNZIP_H +#define LINUX_DECOMPRESS_LUNZIP_H + +int lunzip(unsigned char *inbuf, long in_len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *outbuf, + long *in_posp, + void (*error)(char *x)); +#endif diff -urdN linux-4.19.8/include/linux/lzip.h linux-4.19.8.new/include/linux/lzip.h --- linux-4.19.8/include/linux/lzip.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.19.8.new/include/linux/lzip.h 2018-12-09 18:01:59.000000000 +0100 @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LZIP_H__ +#define __LZIP_H__ +/* + * LZIP decompressor + * + * Copyright (C) 2016-2018 Antonio Diaz Diaz. + */ + +/* Return values (< 0 = Error) */ +enum { + LZIP_OOM_INBUF = -1, + LZIP_HEADER1_EOF = -2, + LZIP_HEADER2_EOF = -3, + LZIP_BAD_MAGIC1 = -4, + LZIP_BAD_MAGIC2 = -5, + LZIP_BAD_VERSION = -6, + LZIP_BAD_DICT_SIZE = -7, + LZIP_OOM_OUTBUF = -8, + LZIP_WRITE_ERROR = -9, + LZIP_BAD_DATA = -10, + LZIP_DATA_EOF = -11, + LZIP_BAD_CRC = -12 +}; + +int lzip_decompress(unsigned char *inbuf, long in_len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *outbuf, long out_size, + long *in_posp, long *out_posp); + +/* inbuf - input buffer. If null or in_len <= 0, fill must be non-null + * in_len - len of pre-read data in inbuf if inbuf is non-null + * fill - if non-null, function to fill inbuf when empty + * flush - if non-null, function to write out outbuf when full + * outbuf - output buffer. If null or out_size <= 0, flush must be non-null + * out_size - size of outbuf if outbuf is non-null + * in_posp - if non-null, the number of bytes consumed will be returned here + * out_posp - if non-null, the number of bytes produced will be returned here + * + * fill will be called (repeatedly) to read data. in_len bytes will be read + * per call (or 16384 bytes per call if inbuf is null or in_len <= 0). + * + * If flush is null, outbuf must be large enough to buffer all the expected + * output. Else the flush function will be called to flush the output buffer + * at the appropriate time (stream dependent). + * If out_size > 0 but is not large enough to buffer all the expected output, + * it must be at least as large as the dictionary size of the data. + * + * inbuf and outbuf may overlap (in-place decompression). + */ + +#endif diff -urdN linux-4.19.8/init/Kconfig linux-4.19.8.new/init/Kconfig --- linux-4.19.8/init/Kconfig 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/init/Kconfig 2018-12-09 19:01:32.000000000 +0100 @@ -122,6 +122,9 @@ config HAVE_KERNEL_BZIP2 bool +config HAVE_KERNEL_LZIP + bool + config HAVE_KERNEL_LZMA bool @@ -140,7 +143,7 @@ choice prompt "Kernel compression mode" default KERNEL_GZIP - depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 || HAVE_KERNEL_UNCOMPRESSED + depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZIP || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 || HAVE_KERNEL_UNCOMPRESSED help The linux kernel is a kind of self-extracting executable. Several compression algorithms are available, which differ @@ -176,6 +179,15 @@ Bzip2 uses a large amount of memory. For modern kernels you will need at least 8MB RAM or more for booting. +config KERNEL_LZIP + bool "Lzip" + depends on HAVE_KERNEL_LZIP + help + Lzip's compression ratio is better than that of gzip and bzip2. + Decompression speed is between gzip and bzip2. Compression can + be as fast as gzip or slower than bzip2 depending on compression + level. Lzip can produce a kernel about a 16% smaller than gzip. + config KERNEL_LZMA bool "LZMA" depends on HAVE_KERNEL_LZMA @@ -1919,8 +1931,8 @@ depends on MODULES help - Compresses kernel modules when 'make modules_install' is run; gzip or - xz depending on "Compression algorithm" below. + Compresses kernel modules when 'make modules_install' is run; gzip, + lzip or xz are used depending on "Compression algorithm" below. module-init-tools MAY support gzip, and kmod MAY support gzip and xz. @@ -1942,11 +1954,14 @@ This determines which sort of compression will be used during 'make modules_install'. - GZIP (default) and XZ are supported. + GZIP (default), LZIP and XZ are supported. config MODULE_COMPRESS_GZIP bool "GZIP" +config MODULE_COMPRESS_LZIP + bool "LZIP" + config MODULE_COMPRESS_XZ bool "XZ" diff -urdN linux-4.19.8/init/do_mounts_rd.c linux-4.19.8.new/init/do_mounts_rd.c --- linux-4.19.8/init/do_mounts_rd.c 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/init/do_mounts_rd.c 2018-12-09 18:01:59.000000000 +0100 @@ -49,6 +49,7 @@ * squashfs * gzip * bzip2 + * lzip * lzma * xz * lzo diff -urdN linux-4.19.8/lib/Kconfig linux-4.19.8.new/lib/Kconfig --- linux-4.19.8/lib/Kconfig 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/lib/Kconfig 2018-12-09 18:01:59.000000000 +0100 @@ -253,6 +253,12 @@ tristate select BITREVERSE +config LZIP_DECOMPRESS + tristate "LZIP decompression support" + help + LZMA compression algorithm is supported using the .lz file format. + See Documentation/lzip.txt for more information. + config LZO_COMPRESS tristate @@ -289,6 +295,10 @@ config DECOMPRESS_BZIP2 tristate +config DECOMPRESS_LZIP + select LZIP_DECOMPRESS + tristate + config DECOMPRESS_LZMA tristate diff -urdN linux-4.19.8/lib/Makefile linux-4.19.8.new/lib/Makefile --- linux-4.19.8/lib/Makefile 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/lib/Makefile 2018-12-09 18:01:59.000000000 +0100 @@ -119,6 +119,7 @@ obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ obj-$(CONFIG_BCH) += bch.o +obj-$(CONFIG_LZIP_DECOMPRESS) += lzip_decompress.o obj-$(CONFIG_LZO_COMPRESS) += lzo/ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ obj-$(CONFIG_LZ4_COMPRESS) += lz4/ @@ -131,6 +132,7 @@ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o +lib-$(CONFIG_DECOMPRESS_LZIP) += decompress_lunzip.o lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o diff -urdN linux-4.19.8/lib/decompress.c linux-4.19.8.new/lib/decompress.c --- linux-4.19.8/lib/decompress.c 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/lib/decompress.c 2018-12-09 18:01:59.000000000 +0100 @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,9 @@ #ifndef CONFIG_DECOMPRESS_BZIP2 # define bunzip2 NULL #endif +#ifndef CONFIG_DECOMPRESS_LZIP +# define lunzip NULL +#endif #ifndef CONFIG_DECOMPRESS_LZMA # define unlzma NULL #endif @@ -48,6 +52,7 @@ { {0x1f, 0x8b}, "gzip", gunzip }, { {0x1f, 0x9e}, "gzip", gunzip }, { {0x42, 0x5a}, "bzip2", bunzip2 }, + { {0x4c, 0x5a}, "lzip", lunzip }, { {0x5d, 0x00}, "lzma", unlzma }, { {0xfd, 0x37}, "xz", unxz }, { {0x89, 0x4c}, "lzo", unlzo }, diff -urdN linux-4.19.8/lib/decompress_lunzip.c linux-4.19.8.new/lib/decompress_lunzip.c --- linux-4.19.8/lib/decompress_lunzip.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.19.8.new/lib/decompress_lunzip.c 2018-12-09 18:01:59.000000000 +0100 @@ -0,0 +1,100 @@ +/* + * Wrapper for decompressing LZIP-compressed kernel, initramfs, and initrd + * + * Copyright (C) 2016-2018 Antonio Diaz Diaz. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#ifdef STATIC +#define PREBOOT +#include "lzip_decompress.c" +#else +#include +#include +#include +#endif + +STATIC int INIT __lunzip(unsigned char *inbuf, long in_len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *outbuf, long out_size, + long *in_posp, long *out_posp, + void (*error)(char *x)) +{ + const int retval = lzip_decompress(inbuf, in_len, fill, flush, + outbuf, out_size, in_posp, out_posp); + switch (retval) { + case 0: break; + case LZIP_OOM_INBUF: + error("Out of memory while allocating input buffer."); + break; + case LZIP_HEADER1_EOF: + error("File ends unexpectedly at member header."); + break; + case LZIP_HEADER2_EOF: + error("Truncated header in multimember file."); + break; + case LZIP_BAD_MAGIC1: + error("Bad magic number (file not in lzip format)."); + break; + case LZIP_BAD_MAGIC2: + error("Corrupt header in multimember file."); + break; + case LZIP_BAD_VERSION: + error("Version of lzip member format not supported."); + break; + case LZIP_BAD_DICT_SIZE: + error("Invalid dictionary size in member header."); + break; + case LZIP_OOM_OUTBUF: + error("Out of memory while allocating output buffer."); + break; + case LZIP_WRITE_ERROR: + error("Write error."); + break; + case LZIP_BAD_DATA: + error("LZIP-compressed data is corrupt."); + break; + case LZIP_DATA_EOF: + error("LZIP-compressed data ends unexpectedly."); + break; + case LZIP_BAD_CRC: + error("CRC mismatch in LZIP-compressed data."); + break; + default: + error("Bug in the LZIP decompressor."); + } + return retval; +} + +#ifndef PREBOOT +/* decompress_fn (see include/linux/decompress/generic.h) should have an + * out_size argument to prevent overflowing outbuf in case of corruption + * of the compressed data. + */ +STATIC int INIT lunzip(unsigned char *inbuf, long in_len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *outbuf, + long *in_posp, + void (*error)(char *x)) +{ + return __lunzip(inbuf, in_len, fill, flush, outbuf, LONG_MAX, + in_posp, 0, error); +} +#else +STATIC int INIT __decompress(unsigned char *inbuf, long in_len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *outbuf, long out_size, + long *in_posp, + void (*error)(char *x)) +{ +/* Some archs pass out_size = 0 (to mean unlimited size), which is unsafe + * in case of corruption of the compressed data. + */ + return __lunzip(inbuf, in_len - 4, fill, flush, outbuf, + out_size ? out_size : LONG_MAX, in_posp, 0, error); +} +#endif diff -urdN linux-4.19.8/lib/lzip_decompress.c linux-4.19.8.new/lib/lzip_decompress.c --- linux-4.19.8/lib/lzip_decompress.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-4.19.8.new/lib/lzip_decompress.c 2018-12-09 18:01:59.000000000 +0100 @@ -0,0 +1,882 @@ +/* + * LZIP decompressor + * + * Copyright (C) 2016-2018 Antonio Diaz Diaz. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include +#include +#include + +/* + * STATIC_RW_DATA is used in the pre-boot environment on some architectures. + * See include/linux/decompress/mm.h for details. + */ +#ifndef STATIC_RW_DATA +#define STATIC_RW_DATA static +#endif + +typedef int State; + +enum { states = 12 }; + +static inline bool St_is_char(const State st) { return st < 7; } + +static inline State St_set_char(const State st) +{ + STATIC_RW_DATA const State next[states] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; + return next[st]; +} + +static inline State St_set_match(const State st) +{ + return ((st < 7) ? 7 : 10); +} + +static inline State St_set_rep(const State st) +{ + return ((st < 7) ? 8 : 11); +} + +static inline State St_set_short_rep(const State st) +{ + return ((st < 7) ? 9 : 11); +} + + +enum { + min_dictionary_bits = 12, + min_dictionary_size = 1 << min_dictionary_bits, + max_dictionary_bits = 29, + max_dictionary_size = 1 << max_dictionary_bits, + literal_context_bits = 3, + pos_state_bits = 2, + pos_states = 1 << pos_state_bits, + pos_state_mask = pos_states - 1, + + len_states = 4, + dis_slot_bits = 6, + start_dis_model = 4, + end_dis_model = 14, + modeled_distances = 1 << (end_dis_model / 2), /* 128 */ + dis_align_bits = 4, + dis_align_size = 1 << dis_align_bits, + + len_low_bits = 3, + len_mid_bits = 3, + len_high_bits = 8, + len_low_symbols = 1 << len_low_bits, + len_mid_symbols = 1 << len_mid_bits, + len_high_symbols = 1 << len_high_bits, + max_len_symbols = len_low_symbols + len_mid_symbols + len_high_symbols, + + min_match_len = 2, /* must be 2 */ + max_match_len = min_match_len + max_len_symbols - 1, /* 273 */ + min_match_len_limit = 5 +}; + +static inline int get_len_state(const int len) +{ + return min(len - min_match_len, len_states - 1); +} + +static inline int get_lit_state(const uint8_t prev_byte) +{ + return (prev_byte >> (8 - literal_context_bits)); +} + + +enum { bit_model_move_bits = 5, + bit_model_total_bits = 11, + bit_model_total = 1 << bit_model_total_bits +}; + +typedef int Bit_model; + +static inline void Bm_init(Bit_model * const probability) +{ + *probability = bit_model_total / 2; +} + +static inline void Bm_array_init(Bit_model bm[], const int size) +{ + int i; + + for (i = 0; i < size; ++i) + Bm_init(&bm[i]); +} + +struct Len_model { + Bit_model choice1; + Bit_model choice2; + Bit_model bm_low[pos_states][len_low_symbols]; + Bit_model bm_mid[pos_states][len_mid_symbols]; + Bit_model bm_high[len_high_symbols]; +}; + +static inline void Lm_init(struct Len_model * const lm) +{ + Bm_init(&lm->choice1); + Bm_init(&lm->choice2); + Bm_array_init(lm->bm_low[0], pos_states * len_low_symbols); + Bm_array_init(lm->bm_mid[0], pos_states * len_mid_symbols); + Bm_array_init(lm->bm_high, len_high_symbols); +} + + +/* Table of CRCs of all 8-bit messages. */ +STATIC_RW_DATA const uint32_t crc32[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; + + +static inline void CRC32_update_buf(uint32_t * const crc, + const uint8_t * const buffer, + const long size) +{ + long i; + uint32_t c = *crc; + + for (i = 0; i < size; ++i) + c = crc32[(c^buffer[i])&0xFF] ^ (c >> 8); + *crc = c; +} + + +STATIC_RW_DATA const uint8_t lzip_magic[4] = { 0x4C, 0x5A, 0x49, 0x50 }; /* "LZIP" */ + +typedef uint8_t Lzip_header[6]; /* 0-3 magic bytes */ + /* 4 version */ + /* 5 coded_dict_size */ +enum { Lh_size = 6 }; + +static inline bool Lh_verify_magic(const Lzip_header data) +{ + int i; + + for (i = 0; i < 4; ++i) + if (data[i] != lzip_magic[i]) + return false; + return true; +} + +/* detect (truncated) header */ +static inline bool Lh_verify_prefix(const Lzip_header data, const int sz) +{ + int i; + for (i = 0; i < sz && i < 4; ++i) + if (data[i] != lzip_magic[i]) + return false; + return (sz > 0); +} + +/* detect corrupt header */ +static inline bool Lh_verify_corrupt(const Lzip_header data) +{ + int matches = 0; + int i; + for (i = 0; i < 4; ++i) + if (data[i] == lzip_magic[i]) + ++matches; + return (matches > 1 && matches < 4); +} + +static inline bool Lh_verify_version(const Lzip_header data) +{ + return (data[4] == 1); +} + +static inline unsigned Lh_get_dictionary_size(const Lzip_header data) +{ + unsigned sz = (1 << (data[5] & 0x1F)); + + if (sz > min_dictionary_size) + sz -= (sz / 16) * ((data[5] >> 5) & 7); + return sz; +} + + +typedef uint8_t Lzip_trailer[20]; + /* 0-3 CRC32 of the uncompressed data */ + /* 4-11 size of the uncompressed data */ + /* 12-19 member size including header and trailer */ +enum { Lt_size = 20 }; + +static inline unsigned Lt_get_data_crc(const Lzip_trailer data) +{ + unsigned tmp = 0; + int i; + + for (i = 3; i >= 0; --i) { + tmp <<= 8; + tmp += data[i]; + } + return tmp; +} + +static inline unsigned long long Lt_get_data_size(const Lzip_trailer data) +{ + unsigned long long tmp = 0; + int i; + + for (i = 11; i >= 4; --i) { + tmp <<= 8; + tmp += data[i]; + } + return tmp; +} + +static inline unsigned long long Lt_get_member_size(const Lzip_trailer data) +{ + unsigned long long tmp = 0; + int i; + + for (i = 19; i >= 12; --i) { + tmp <<= 8; + tmp += data[i]; + } + return tmp; +} + + +struct Range_decoder { + unsigned long long partial_member_pos; + uint8_t *buffer; /* input buffer */ + long buffer_size; + long pos; /* current pos in buffer */ + long stream_pos; /* when reached, a new block must be read */ + uint32_t code; + uint32_t range; + long (*fill)(void*, unsigned long); + bool at_stream_end; + bool buffer_given; +}; + + +static bool Rd_read_block(struct Range_decoder * const rdec) +{ + if (!rdec->at_stream_end) { + rdec->stream_pos = rdec->fill ? + rdec->fill(rdec->buffer, rdec->buffer_size) : 0; + rdec->at_stream_end = (rdec->stream_pos < rdec->buffer_size); + rdec->partial_member_pos += rdec->pos; + rdec->pos = 0; + } + return rdec->pos < rdec->stream_pos; +} + + +static inline bool Rd_init(struct Range_decoder * const rdec, + uint8_t * const inbuf, const long in_len, + long (*fill)(void*, unsigned long)) +{ + rdec->partial_member_pos = 0; + rdec->buffer_given = (inbuf && in_len > 0); + rdec->buffer_size = rdec->buffer_given ? in_len : 16384; + rdec->buffer = rdec->buffer_given ? inbuf : malloc(rdec->buffer_size); + if (!rdec->buffer) + return false; + rdec->pos = 0; + rdec->stream_pos = rdec->buffer_given ? in_len : 0; + rdec->code = 0; + rdec->range = 0xFFFFFFFFU; + rdec->fill = fill; + rdec->at_stream_end = false; + return true; +} + +static inline void Rd_free(struct Range_decoder * const rdec) +{ + if (!rdec->buffer_given) + free(rdec->buffer); +} + +static inline bool Rd_finished(struct Range_decoder * const rdec) +{ + return rdec->pos >= rdec->stream_pos && !Rd_read_block(rdec); +} + +static inline unsigned long long +Rd_member_position(const struct Range_decoder * const rdec) +{ + return rdec->partial_member_pos + rdec->pos; +} + +static inline void Rd_reset_member_position(struct Range_decoder * const rdec) +{ + rdec->partial_member_pos = 0; rdec->partial_member_pos -= rdec->pos; +} + +static inline uint8_t Rd_get_byte(struct Range_decoder * const rdec) +{ + /* 0xFF avoids decoder error if member is truncated at EOS marker */ + if (Rd_finished(rdec)) + return 0xFF; + return rdec->buffer[rdec->pos++]; +} + +static inline void Rd_load(struct Range_decoder * const rdec) +{ + int i; + + rdec->code = 0; + for (i = 0; i < 5; ++i) + rdec->code = (rdec->code << 8) | Rd_get_byte(rdec); + rdec->range = 0xFFFFFFFFU; +} + +static inline void Rd_normalize(struct Range_decoder * const rdec) +{ + if (rdec->range <= 0x00FFFFFFU) { + rdec->range <<= 8; + rdec->code = (rdec->code << 8) | Rd_get_byte(rdec); + } +} + +static inline unsigned Rd_decode(struct Range_decoder * const rdec, + const int num_bits) +{ + unsigned symbol = 0; + int i; + + for (i = num_bits; i > 0; --i) { + bool bit; + + Rd_normalize(rdec); + rdec->range >>= 1; + /* symbol <<= 1; */ + /* if(rdec->code >= rdec->range) { rdec->code -= rdec->range; symbol |= 1; } */ + bit = (rdec->code >= rdec->range); + symbol = (symbol << 1) + bit; + rdec->code -= rdec->range & (0U - bit); + } + return symbol; +} + +static inline unsigned Rd_decode_bit(struct Range_decoder * const rdec, + Bit_model * const probability) +{ + uint32_t bound; + + Rd_normalize(rdec); + bound = (rdec->range >> bit_model_total_bits) * *probability; + if (rdec->code < bound) { + rdec->range = bound; + *probability += (bit_model_total - *probability) >> bit_model_move_bits; + return 0; + } else { + rdec->range -= bound; + rdec->code -= bound; + *probability -= *probability >> bit_model_move_bits; + return 1; + } +} + +static inline unsigned Rd_decode_tree3(struct Range_decoder * const rdec, + Bit_model bm[]) +{ + unsigned symbol = 1; + + symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]); + symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]); + symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]); + return symbol & 7; +} + +static inline unsigned Rd_decode_tree6(struct Range_decoder * const rdec, + Bit_model bm[]) +{ + unsigned symbol = 1; + + symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]); + symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]); + symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]); + symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]); + symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]); + symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]); + return symbol & 0x3F; +} + +static inline unsigned Rd_decode_tree8(struct Range_decoder * const rdec, + Bit_model bm[]) +{ + unsigned symbol = 1; + int i; + + for (i = 0; i < 8; ++i) + symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]); + return symbol & 0xFF; +} + +static inline unsigned +Rd_decode_tree_reversed(struct Range_decoder * const rdec, + Bit_model bm[], const int num_bits) +{ + unsigned model = 1; + unsigned symbol = 0; + int i; + + for (i = 0; i < num_bits; ++i) { + const unsigned bit = Rd_decode_bit(rdec, &bm[model]); + + model = (model << 1) + bit; + symbol |= (bit << i); + } + return symbol; +} + +static inline unsigned +Rd_decode_tree_reversed4(struct Range_decoder * const rdec, Bit_model bm[]) +{ + unsigned symbol = Rd_decode_bit(rdec, &bm[1]); + unsigned model = 2 + symbol; + unsigned bit = Rd_decode_bit(rdec, &bm[model]); + + model = (model << 1) + bit; symbol |= (bit << 1); + bit = Rd_decode_bit(rdec, &bm[model]); + model = (model << 1) + bit; symbol |= (bit << 2); + symbol |= (Rd_decode_bit(rdec, &bm[model]) << 3); + return symbol; +} + +static inline unsigned Rd_decode_matched(struct Range_decoder * const rdec, + Bit_model bm[], unsigned match_byte) +{ + unsigned symbol = 1; + unsigned mask = 0x100; + + while (true) { + const unsigned match_bit = (match_byte <<= 1) & mask; + const unsigned bit = Rd_decode_bit(rdec, &bm[symbol+match_bit+mask]); + + symbol = (symbol << 1) + bit; + if (symbol > 0xFF) + return symbol & 0xFF; + mask &= ~(match_bit ^ (bit << 8)); /* if( match_bit != bit ) mask = 0; */ + } +} + +static inline unsigned Rd_decode_len(struct Range_decoder * const rdec, + struct Len_model * const lm, + const int pos_state) +{ + if (Rd_decode_bit(rdec, &lm->choice1) == 0) + return Rd_decode_tree3(rdec, lm->bm_low[pos_state]); + if (Rd_decode_bit(rdec, &lm->choice2) == 0) + return len_low_symbols + + Rd_decode_tree3(rdec, lm->bm_mid[pos_state]); + return len_low_symbols + len_mid_symbols + + Rd_decode_tree8(rdec, lm->bm_high); +} + + +struct LZ_decoder { + unsigned long long partial_data_pos; + struct Range_decoder *rdec; + /* Don't move bm_* to LZd_decode_member; makes frame too large. */ + Bit_model bm_literal[1 << literal_context_bits][0x300]; + Bit_model bm_match[states][pos_states]; + Bit_model bm_rep[states]; + Bit_model bm_rep0[states]; + Bit_model bm_rep1[states]; + Bit_model bm_rep2[states]; + Bit_model bm_len[states][pos_states]; + Bit_model bm_dis_slot[len_states][1 << dis_slot_bits]; + Bit_model bm_dis[modeled_distances-end_dis_model+1]; + Bit_model bm_align[dis_align_size]; + struct Len_model match_len_model; + struct Len_model rep_len_model; + + unsigned long buffer_size; + unsigned dictionary_size; + uint8_t *buffer; /* output buffer */ + unsigned long pos; /* current pos in buffer */ + unsigned long stream_pos; /* first byte not yet written to file */ + uint32_t crc; + long (*flush)(void*, unsigned long); + bool pos_wrapped; + bool buffer_given; + bool write_error; +}; + +static void LZd_flush_data(struct LZ_decoder * const d) +{ + if (d->pos > d->stream_pos) { + const long size = d->pos - d->stream_pos; + + CRC32_update_buf(&d->crc, d->buffer + d->stream_pos, size); + if ((d->flush && + d->flush(d->buffer + d->stream_pos, size) != size) || + (!d->flush && d->pos_wrapped)) + d->write_error = true; + if (d->pos >= d->buffer_size) { + d->partial_data_pos += d->pos; + d->pos = 0; + d->pos_wrapped = true; + } + d->stream_pos = d->pos; + } +} + +static inline uint8_t LZd_peek_prev(const struct LZ_decoder * const d) +{ + if (d->pos > 0) + return d->buffer[d->pos-1]; + if (d->pos_wrapped) + return d->buffer[d->buffer_size-1]; + return 0; /* prev_byte of first byte */ +} + +static inline uint8_t LZd_peek(const struct LZ_decoder * const d, + const unsigned distance) +{ + const unsigned long i = ((d->pos > distance) ? 0 : d->buffer_size) + + d->pos - distance - 1; + return d->buffer[i]; +} + +static inline void LZd_put_byte(struct LZ_decoder * const d, const uint8_t b) +{ + d->buffer[d->pos] = b; + if (++d->pos >= d->buffer_size) + LZd_flush_data(d); +} + +static inline void LZd_copy_block(struct LZ_decoder * const d, + const unsigned distance, unsigned len) +{ + unsigned long lpos = d->pos, i = lpos - distance - 1; + bool fast, fast2; + + if (lpos > distance) { + fast = (len < d->buffer_size - lpos); + fast2 = (fast && len <= lpos - i); + } else { + i += d->buffer_size; + fast = (len < d->buffer_size - i); /* (i == pos) may happen */ + fast2 = (fast && len <= i - lpos); + } + if (fast) { /* no wrap */ + d->pos += len; + if (fast2) /* no wrap, no overlap */ + memcpy(d->buffer + lpos, d->buffer + i, len); + else + for (; len > 0; --len) + d->buffer[lpos++] = d->buffer[i++]; + } else + for (; len > 0; --len) { + d->buffer[d->pos] = d->buffer[i]; + if (++d->pos >= d->buffer_size) + LZd_flush_data(d); + if (++i >= d->buffer_size) + i = 0; + } +} + +static inline bool LZd_init(struct LZ_decoder * const d, + struct Range_decoder * const rde, + const unsigned dict_size, uint8_t * const outbuf, + long out_size, long (*flush)(void*, unsigned long)) +{ + d->partial_data_pos = 0; + d->rdec = rde; + Bm_array_init(d->bm_literal[0], (1 << literal_context_bits) * 0x300); + Bm_array_init(d->bm_match[0], states * pos_states); + Bm_array_init(d->bm_rep, states); + Bm_array_init(d->bm_rep0, states); + Bm_array_init(d->bm_rep1, states); + Bm_array_init(d->bm_rep2, states); + Bm_array_init(d->bm_len[0], states * pos_states); + Bm_array_init(d->bm_dis_slot[0], len_states * (1 << dis_slot_bits)); + Bm_array_init(d->bm_dis, modeled_distances - end_dis_model + 1); + Bm_array_init(d->bm_align, dis_align_size); + Lm_init(&d->match_len_model); + Lm_init(&d->rep_len_model); + + d->buffer_given = (outbuf && out_size > 0); + d->buffer_size = d->buffer_given ? (unsigned long)out_size : dict_size; + d->dictionary_size = min_t(unsigned long, d->buffer_size, dict_size); + d->buffer = d->buffer_given ? outbuf : large_malloc(d->buffer_size); + if (!d->buffer) + return false; + d->pos = 0; + d->stream_pos = 0; + d->crc = 0xFFFFFFFFU; + d->flush = flush; + d->pos_wrapped = false; + d->write_error = false; + /* prev_byte of first byte; also for LZd_peek( 0 ) on corrupt file */ + if (!d->buffer_given) /* inbuf and outbuf may overlap */ + d->buffer[d->buffer_size-1] = 0; + return true; +} + +static inline void LZd_free(struct LZ_decoder * const d) +{ + if (!d->buffer_given) + large_free(d->buffer); +} + +static inline unsigned LZd_crc(const struct LZ_decoder * const d) +{ + return d->crc ^ 0xFFFFFFFFU; +} + +static inline unsigned long long +LZd_data_position(const struct LZ_decoder * const d) +{ + return d->partial_data_pos + d->pos; +} + + +static bool LZd_verify_trailer(struct LZ_decoder * const d) +{ + Lzip_trailer trailer; + int i = 0; + + while (i < Lt_size) + trailer[i++] = Rd_get_byte(d->rdec); + + return (Lt_get_data_crc(trailer) == LZd_crc(d) && + Lt_get_data_size(trailer) == LZd_data_position(d) && + Lt_get_member_size(trailer) == Rd_member_position(d->rdec)); +} + + +/* Return value: 0 = OK, < 0 = error (see include/linux/lzip.h). */ +static int LZd_decode_member(struct LZ_decoder * const d) +{ + struct Range_decoder * const rdec = d->rdec; + unsigned rep0 = 0; /* rep[0-3] latest four distances */ + unsigned rep1 = 0; /* used for efficient coding of */ + unsigned rep2 = 0; /* repeated distances */ + unsigned rep3 = 0; + State state = 0; + + Rd_load(rdec); + while (!Rd_finished(rdec)) { + int len; + const int pos_state = LZd_data_position(d) & pos_state_mask; + + if (Rd_decode_bit(rdec, &d->bm_match[state][pos_state]) == 0) { + /* literal byte */ + Bit_model * const bm = d->bm_literal[get_lit_state(LZd_peek_prev(d))]; + + if (St_is_char(state)) { + state -= (state < 4) ? state : 3; + LZd_put_byte(d, Rd_decode_tree8(rdec, bm)); + } else { + state -= (state < 10) ? 3 : 6; + LZd_put_byte(d, Rd_decode_matched(rdec, bm, LZd_peek(d, rep0))); + } + continue; + } + /* match or repeated match */ + if (Rd_decode_bit(rdec, &d->bm_rep[state]) != 0) { + if (Rd_decode_bit(rdec, &d->bm_rep0[state]) == 0) { + if (Rd_decode_bit(rdec, &d->bm_len[state][pos_state]) == 0) { + state = St_set_short_rep(state); + LZd_put_byte(d, LZd_peek(d, rep0)); + continue; + } + } else { + unsigned distance; + + if (Rd_decode_bit(rdec, &d->bm_rep1[state]) == 0) + distance = rep1; + else { + if (Rd_decode_bit(rdec, &d->bm_rep2[state]) == 0) + distance = rep2; + else { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = St_set_rep(state); + len = min_match_len + Rd_decode_len(rdec, &d->rep_len_model, pos_state); + } else { /* match */ + unsigned distance; + + len = min_match_len + Rd_decode_len(rdec, &d->match_len_model, pos_state); + distance = Rd_decode_tree6(rdec, d->bm_dis_slot[get_len_state(len)]); + if (distance >= start_dis_model) { + const unsigned dis_slot = distance; + const int direct_bits = (dis_slot >> 1) - 1; + + distance = (2 | (dis_slot & 1)) << direct_bits; + if (dis_slot < end_dis_model) + distance += Rd_decode_tree_reversed(rdec, + d->bm_dis + (distance - dis_slot), direct_bits); + else { + distance += + Rd_decode(rdec, direct_bits - dis_align_bits) << dis_align_bits; + distance += Rd_decode_tree_reversed4(rdec, d->bm_align); + if (distance == 0xFFFFFFFFU) { /* marker found */ + Rd_normalize(rdec); + LZd_flush_data(d); + if (d->write_error) + return LZIP_WRITE_ERROR; + if (len == min_match_len) { /* End Of Stream marker */ + if (LZd_verify_trailer(d)) + return 0; + else + return LZIP_BAD_CRC; + } + if (len == min_match_len + 1) { /* Sync Flush marker */ + Rd_load(rdec); + continue; + } + return LZIP_BAD_DATA; /* unknown marker */ + } + } + } + rep3 = rep2; rep2 = rep1; rep1 = rep0; rep0 = distance; + state = St_set_match(state); + if (rep0 >= d->dictionary_size || + (rep0 >= d->pos && !d->pos_wrapped)) { + LZd_flush_data(d); + return LZIP_BAD_DATA; + } + } + LZd_copy_block(d, rep0, len); + } + LZd_flush_data(d); + return LZIP_DATA_EOF; +} + + +int lzip_decompress(unsigned char *inbuf, long in_len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *outbuf, long out_size, + long *in_posp, long *out_posp) +{ + unsigned char *outptr = outbuf; + struct Range_decoder rdec; + struct LZ_decoder *decoder = 0; + int retval = 0; + bool first_member; + + if (in_posp) + *in_posp = 0; + if (out_posp) + *out_posp = 0; + + if (!Rd_init(&rdec, inbuf, in_len, fill)) + return LZIP_OOM_INBUF; + + for (first_member = true;; first_member = false) { + long data_pos; + int size; + unsigned dictionary_size; + Lzip_header header; + + Rd_reset_member_position(&rdec); + for (size = 0; size < Lh_size && !Rd_finished(&rdec); ++size) + header[size] = Rd_get_byte(&rdec); + if (Rd_finished(&rdec)) { /* End Of File */ + if (first_member) + retval = LZIP_HEADER1_EOF; + else if (Lh_verify_prefix(header, size)) + retval = LZIP_HEADER2_EOF; + break; + } + if (!Lh_verify_magic(header)) { + if (first_member) + retval = LZIP_BAD_MAGIC1; + else if (Lh_verify_corrupt(header)) + retval = LZIP_BAD_MAGIC2; + break; + } + if (!Lh_verify_version(header)) { + retval = LZIP_BAD_VERSION; + break; + } + dictionary_size = Lh_get_dictionary_size(header); + if (dictionary_size < min_dictionary_size || + dictionary_size > max_dictionary_size) { + retval = LZIP_BAD_DICT_SIZE; + break; + } + + if (!decoder) + decoder = malloc(sizeof *decoder); + if (!decoder || !LZd_init(decoder, &rdec, dictionary_size, + outptr, out_size, flush)) { + retval = LZIP_OOM_OUTBUF; + break; + } + retval = LZd_decode_member(decoder); + if (in_posp) + *in_posp += Rd_member_position(&rdec); + data_pos = LZd_data_position(decoder); + if (outptr) + outptr += data_pos; + if (out_posp) + *out_posp += data_pos; + if (out_size > 0) + out_size -= data_pos; + LZd_free(decoder); + if (retval != 0) + break; + } + if (decoder) + free(decoder); + Rd_free(&rdec); + return retval; +} + +#ifndef STATIC +EXPORT_SYMBOL_GPL(lzip_decompress); +#endif +MODULE_DESCRIPTION("LZIP Decompressor"); +MODULE_AUTHOR("Antonio Diaz Diaz "); +MODULE_LICENSE("GPL"); diff -urdN linux-4.19.8/scripts/Makefile.lib linux-4.19.8.new/scripts/Makefile.lib --- linux-4.19.8/scripts/Makefile.lib 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/scripts/Makefile.lib 2018-12-09 18:01:59.000000000 +0100 @@ -319,6 +319,21 @@ bzip2 -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ (rm -f $@ ; false) +# Lzip +# --------------------------------------------------------------------------- +# The .lz format has the uncompressed size available at the end of the +# file, but at offset (member_size - 16). So we append a gzip-style size. +# Use klzip to compress the kernel image and lzip to compress other things. + +quiet_cmd_klzip = LZIP $@ +cmd_klzip = (cat $(filter-out FORCE,$^) | \ + lzip -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + +quiet_cmd_lzip = LZIP $@ +cmd_lzip = (cat $(filter-out FORCE,$^) | lzip -9) > $@ || \ + (rm -f $@ ; false) + # Lzma # --------------------------------------------------------------------------- diff -urdN linux-4.19.8/scripts/extract-ikconfig linux-4.19.8.new/scripts/extract-ikconfig --- linux-4.19.8/scripts/extract-ikconfig 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/scripts/extract-ikconfig 2018-12-09 18:01:59.000000000 +0100 @@ -59,6 +59,7 @@ try_decompress '\037\213\010' xy gunzip try_decompress '\3757zXZ\000' abcde unxz try_decompress 'BZh' xy bunzip2 +try_decompress 'LZIP' xyz 'lzip -d' try_decompress '\135\0\0\0' xxx unlzma try_decompress '\211\114\132' xy 'lzop -d' try_decompress '\002\041\114\030' xyy 'lz4 -d -l' diff -urdN linux-4.19.8/scripts/extract-vmlinux linux-4.19.8.new/scripts/extract-vmlinux --- linux-4.19.8/scripts/extract-vmlinux 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/scripts/extract-vmlinux 2018-12-09 18:01:59.000000000 +0100 @@ -55,6 +55,7 @@ try_decompress '\037\213\010' xy gunzip try_decompress '\3757zXZ\000' abcde unxz try_decompress 'BZh' xy bunzip2 +try_decompress 'LZIP' xyz 'lzip -d' try_decompress '\135\0\0\0' xxx unlzma try_decompress '\211\114\132' xy 'lzop -d' try_decompress '\002!L\030' xxx 'lz4 -d' diff -urdN linux-4.19.8/scripts/package/Makefile linux-4.19.8.new/scripts/package/Makefile --- linux-4.19.8/scripts/package/Makefile 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/scripts/package/Makefile 2018-12-09 18:01:59.000000000 +0100 @@ -129,8 +129,9 @@ $(if $(findstring tar-src,$@),, \ $(if $(findstring bz2,$@),bzip2, \ $(if $(findstring gz,$@),gzip, \ +$(if $(findstring lz,$@),lzip, \ $(if $(findstring xz,$@),xz, \ -$(error unknown target $@)))) \ +$(error unknown target $@))))) \ -f -9 $(perf-tar).tar) perf-%pkg: FORCE @@ -147,8 +148,10 @@ @echo ' tar-pkg - Build the kernel as an uncompressed tarball' @echo ' targz-pkg - Build the kernel as a gzip compressed tarball' @echo ' tarbz2-pkg - Build the kernel as a bzip2 compressed tarball' + @echo ' tarlz-pkg - Build the kernel as a lzip compressed tarball' @echo ' tarxz-pkg - Build the kernel as a xz compressed tarball' @echo ' perf-tar-src-pkg - Build $(perf-tar).tar source tarball' @echo ' perf-targz-src-pkg - Build $(perf-tar).tar.gz source tarball' @echo ' perf-tarbz2-src-pkg - Build $(perf-tar).tar.bz2 source tarball' + @echo ' perf-tarlz-src-pkg - Build $(perf-tar).tar.lz source tarball' @echo ' perf-tarxz-src-pkg - Build $(perf-tar).tar.xz source tarball' diff -urdN linux-4.19.8/scripts/package/buildtar linux-4.19.8.new/scripts/package/buildtar --- linux-4.19.8/scripts/package/buildtar 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/scripts/package/buildtar 2018-12-09 18:01:59.000000000 +0100 @@ -35,6 +35,10 @@ opts=--bzip2 tarball=${tarball}.bz2 ;; + tarlz-pkg) + opts=--lzip + tarball=${tarball}.lz + ;; tarxz-pkg) opts=--xz tarball=${tarball}.xz diff -urdN linux-4.19.8/scripts/patch-kernel linux-4.19.8.new/scripts/patch-kernel --- linux-4.19.8/scripts/patch-kernel 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/scripts/patch-kernel 2018-12-09 18:01:59.000000000 +0100 @@ -117,6 +117,10 @@ ext=".bz2" name="bzip2" uncomp="bunzip2 -dc" + elif [ -r ${filebase}.lz ]; then + ext=".lz" + name="lzip" + uncomp="lzip -dc" elif [ -r ${filebase}.xz ]; then ext=".xz" name="xz" diff -urdN linux-4.19.8/tools/testing/selftests/gen_kselftest_tar.sh linux-4.19.8.new/tools/testing/selftests/gen_kselftest_tar.sh --- linux-4.19.8/tools/testing/selftests/gen_kselftest_tar.sh 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/tools/testing/selftests/gen_kselftest_tar.sh 2018-12-09 18:01:59.000000000 +0100 @@ -27,6 +27,10 @@ copts="cvjf" ext=".tar.bz2" ;; + tarlz) + copts="cv --lzip -f" + ext=".tar.lz" + ;; tarxz) copts="cvJf" ext=".tar.xz" diff -urdN linux-4.19.8/usr/.gitignore linux-4.19.8.new/usr/.gitignore --- linux-4.19.8/usr/.gitignore 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/usr/.gitignore 2018-12-09 18:01:59.000000000 +0100 @@ -5,6 +5,7 @@ initramfs_data.cpio initramfs_data.cpio.gz initramfs_data.cpio.bz2 +initramfs_data.cpio.lz initramfs_data.cpio.lzma initramfs_list include diff -urdN linux-4.19.8/usr/Kconfig linux-4.19.8.new/usr/Kconfig --- linux-4.19.8/usr/Kconfig 2018-12-08 12:59:10.000000000 +0100 +++ linux-4.19.8.new/usr/Kconfig 2018-12-09 18:01:59.000000000 +0100 @@ -70,6 +70,15 @@ Support loading of a bzip2 encoded initial ramdisk or cpio buffer If unsure, say N. +config RD_LZIP + bool "Support initial ramdisk/ramfs compressed using lzip" + default y + depends on BLK_DEV_INITRD + select DECOMPRESS_LZIP + help + Support loading of a lzip encoded initial ramdisk or cpio buffer. + If unsure, say N. + config RD_LZMA bool "Support initial ramdisk/ramfs compressed using LZMA" default y @@ -165,6 +174,18 @@ If you choose this, keep in mind that you need to have the bzip2 tool available to be able to compress the initram. +config INITRAMFS_COMPRESSION_LZIP + bool "Lzip" + depends on RD_LZIP + help + Lzip's compression ratio is better than that of gzip and bzip2. + Decompression speed is between gzip and bzip2. Compression can + be as fast as gzip or slower than bzip2 depending on compression + level. Lzip can produce a initramfs about a 16% smaller than gzip. + + If you choose this, keep in mind that you need to have the lzip tool + available to be able to compress the initram. + config INITRAMFS_COMPRESSION_LZMA bool "LZMA" depends on RD_LZMA @@ -222,12 +243,14 @@ default "" if INITRAMFS_COMPRESSION_NONE default ".gz" if INITRAMFS_COMPRESSION_GZIP default ".bz2" if INITRAMFS_COMPRESSION_BZIP2 + default ".lz" if INITRAMFS_COMPRESSION_LZIP default ".lzma" if INITRAMFS_COMPRESSION_LZMA default ".xz" if INITRAMFS_COMPRESSION_XZ default ".lzo" if INITRAMFS_COMPRESSION_LZO default ".lz4" if INITRAMFS_COMPRESSION_LZ4 default ".gz" if RD_GZIP default ".lz4" if RD_LZ4 + default ".lz" if RD_LZIP default ".lzo" if RD_LZO default ".xz" if RD_XZ default ".lzma" if RD_LZMA