[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/app/busybox/src/archival/Config.src b/ap/app/busybox/src/archival/Config.src
new file mode 100644
index 0000000..ae1afc5
--- /dev/null
+++ b/ap/app/busybox/src/archival/Config.src
@@ -0,0 +1,388 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Archival Utilities"
+
+INSERT
+
+config FEATURE_SEAMLESS_XZ
+	bool "Make tar, rpm, modprobe etc understand .xz data"
+	default y
+	help
+	  Make tar, rpm, modprobe etc understand .xz data.
+
+config FEATURE_SEAMLESS_LZMA
+	bool "Make tar, rpm, modprobe etc understand .lzma data"
+	default y
+	help
+	  Make tar, rpm, modprobe etc understand .lzma data.
+
+config FEATURE_SEAMLESS_BZ2
+	bool "Make tar, rpm, modprobe etc understand .bz2 data"
+	default y
+	help
+	  Make tar, rpm, modprobe etc understand .bz2 data.
+
+config FEATURE_SEAMLESS_GZ
+	bool "Make tar, rpm, modprobe etc understand .gz data"
+	default y
+	help
+	  Make tar, rpm, modprobe etc understand .gz data.
+
+config FEATURE_SEAMLESS_Z
+	bool "tar, rpm, modprobe etc understand .Z data"
+	default n
+	help
+	  Make tar, rpm, modprobe etc understand .Z data.
+
+config AR
+	bool "ar"
+	default n  # needs to be improved to be able to replace binutils ar
+	help
+	  ar is an archival utility program used to create, modify, and
+	  extract contents from archives. An archive is a single file holding
+	  a collection of other files in a structure that makes it possible to
+	  retrieve the original individual files (called archive members).
+	  The original files' contents, mode (permissions), timestamp, owner,
+	  and group are preserved in the archive, and can be restored on
+	  extraction.
+
+	  The stored filename is limited to 15 characters. (for more information
+	  see long filename support).
+	  ar has 60 bytes of overheads for every stored file.
+
+	  This implementation of ar can extract archives, it cannot create or
+	  modify them.
+	  On an x86 system, the ar applet adds about 1K.
+
+	  Unless you have a specific application which requires ar, you should
+	  probably say N here.
+
+config FEATURE_AR_LONG_FILENAMES
+	bool "Support for long filenames (not needed for debs)"
+	default y
+	depends on AR
+	help
+	  By default the ar format can only store the first 15 characters
+	  of the filename, this option removes that limitation.
+	  It supports the GNU ar long filename method which moves multiple long
+	  filenames into a the data section of a new ar entry.
+
+config FEATURE_AR_CREATE
+	bool "Support archive creation"
+	default y
+	depends on AR
+	help
+	  This enables archive creation (-c and -r) with busybox ar.
+
+config BUNZIP2
+	bool "bunzip2"
+	default y
+	help
+	  bunzip2 is a compression utility using the Burrows-Wheeler block
+	  sorting text compression algorithm, and Huffman coding. Compression
+	  is generally considerably better than that achieved by more
+	  conventional LZ77/LZ78-based compressors, and approaches the
+	  performance of the PPM family of statistical compressors.
+
+	  Unless you have a specific application which requires bunzip2, you
+	  should probably say N here.
+
+config BZIP2
+	bool "bzip2"
+	default y
+	help
+	  bzip2 is a compression utility using the Burrows-Wheeler block
+	  sorting text compression algorithm, and Huffman coding. Compression
+	  is generally considerably better than that achieved by more
+	  conventional LZ77/LZ78-based compressors, and approaches the
+	  performance of the PPM family of statistical compressors.
+
+	  Unless you have a specific application which requires bzip2, you
+	  should probably say N here.
+
+config CPIO
+	bool "cpio"
+	default y
+	help
+	  cpio is an archival utility program used to create, modify, and
+	  extract contents from archives.
+	  cpio has 110 bytes of overheads for every stored file.
+
+	  This implementation of cpio can extract cpio archives created in the
+	  "newc" or "crc" format, it cannot create or modify them.
+
+	  Unless you have a specific application which requires cpio, you
+	  should probably say N here.
+
+config FEATURE_CPIO_O
+	bool "Support for archive creation"
+	default y
+	depends on CPIO
+	help
+	  This implementation of cpio can create cpio archives in the "newc"
+	  format only.
+
+config FEATURE_CPIO_P
+	bool "Support for passthrough mode"
+	default y
+	depends on FEATURE_CPIO_O
+	help
+	  Passthrough mode. Rarely used.
+
+config DPKG
+	bool "dpkg"
+	default n
+	select FEATURE_SEAMLESS_GZ
+	help
+	  dpkg is a medium-level tool to install, build, remove and manage
+	  Debian packages.
+
+	  This implementation of dpkg has a number of limitations,
+	  you should use the official dpkg if possible.
+
+config DPKG_DEB
+	bool "dpkg_deb"
+	default n
+	select FEATURE_SEAMLESS_GZ
+	help
+	  dpkg-deb unpacks and provides information about Debian archives.
+
+	  This implementation of dpkg-deb cannot pack archives.
+
+	  Unless you have a specific application which requires dpkg-deb,
+	  say N here.
+
+config FEATURE_DPKG_DEB_EXTRACT_ONLY
+	bool "Extract only (-x)"
+	default n
+	depends on DPKG_DEB
+	help
+	  This reduces dpkg-deb to the equivalent of
+	  "ar -p <deb> data.tar.gz | tar -zx". However it saves space as none
+	  of the extra dpkg-deb, ar or tar options are needed, they are linked
+	  to internally.
+
+config GUNZIP
+	bool "gunzip"
+	default y
+	help
+	  gunzip is used to decompress archives created by gzip.
+	  You can use the `-t' option to test the integrity of
+	  an archive, without decompressing it.
+
+config GZIP
+	bool "gzip"
+	default y
+	help
+	  gzip is used to compress files.
+	  It's probably the most widely used UNIX compression program.
+
+config FEATURE_GZIP_LONG_OPTIONS
+	bool "Enable long options"
+	default y
+	depends on GZIP && LONG_OPTS
+	help
+	  Enable use of long options, increases size by about 106 Bytes
+
+config GZIP_FAST
+	int "Trade memory for gzip speed (0:small,slow - 2:fast,big)"
+	default 0
+	range 0 2
+	depends on GZIP
+	help
+	  Enable big memory options for gzip.
+	  0: small buffers, small hash-tables
+	  1: larger buffers, larger hash-tables
+	  2: larger buffers, largest hash-tables
+	  Larger models may give slightly better compression
+
+config LZOP
+	bool "lzop"
+	default y
+	help
+	  Lzop compression/decompresion.
+
+config LZOP_COMPR_HIGH
+	bool "lzop compression levels 7,8,9 (not very useful)"
+	default n
+	depends on LZOP
+	help
+	  High levels (7,8,9) of lzop compression. These levels
+	  are actually slower than gzip at equivalent compression ratios
+	  and take up 3.2K of code.
+
+config RPM2CPIO
+	bool "rpm2cpio"
+	default y
+	help
+	  Converts a RPM file into a CPIO archive.
+
+config RPM
+	bool "rpm"
+	default y
+	help
+	  Mini RPM applet - queries and extracts RPM packages.
+
+config TAR
+	bool "tar"
+	default y
+	help
+	  tar is an archiving program. It's commonly used with gzip to
+	  create compressed archives. It's probably the most widely used
+	  UNIX archive program.
+
+config FEATURE_TAR_CREATE
+	bool "Enable archive creation"
+	default y
+	depends on TAR
+	help
+	  If you enable this option you'll be able to create
+	  tar archives using the `-c' option.
+
+config FEATURE_TAR_AUTODETECT
+	bool "Autodetect compressed tarballs"
+	default y
+	depends on TAR && (FEATURE_SEAMLESS_Z || FEATURE_SEAMLESS_GZ || FEATURE_SEAMLESS_BZ2 || FEATURE_SEAMLESS_LZMA || FEATURE_SEAMLESS_XZ)
+	help
+	  With this option tar can automatically detect compressed
+	  tarballs. Currently it works only on files (not pipes etc).
+
+config FEATURE_TAR_FROM
+	bool "Enable -X (exclude from) and -T (include from) options)"
+	default y
+	depends on TAR
+	help
+	  If you enable this option you'll be able to specify
+	  a list of files to include or exclude from an archive.
+
+config FEATURE_TAR_OLDGNU_COMPATIBILITY
+	bool "Support for old tar header format"
+	default y
+	depends on TAR || DPKG
+	help
+	  This option is required to unpack archives created in
+	  the old GNU format; help to kill this old format by
+	  repacking your ancient archives with the new format.
+
+config FEATURE_TAR_OLDSUN_COMPATIBILITY
+	bool "Enable untarring of tarballs with checksums produced by buggy Sun tar"
+	default y
+	depends on TAR || DPKG
+	help
+	  This option is required to unpack archives created by some old
+	  version of Sun's tar (it was calculating checksum using signed
+	  arithmetic). It is said to be fixed in newer Sun tar, but "old"
+	  tarballs still exist.
+
+config FEATURE_TAR_GNU_EXTENSIONS
+	bool "Support for GNU tar extensions (long filenames)"
+	default y
+	depends on TAR || DPKG
+	help
+	  With this option busybox supports GNU long filenames and
+	  linknames.
+
+config FEATURE_TAR_LONG_OPTIONS
+	bool "Enable long options"
+	default y
+	depends on TAR && LONG_OPTS
+	help
+	  Enable use of long options, increases size by about 400 Bytes
+
+config FEATURE_TAR_TO_COMMAND
+	bool "Support for writing to an external program"
+	default y
+	depends on TAR && FEATURE_TAR_LONG_OPTIONS
+	help
+	  If you enable this option you'll be able to instruct tar to send
+	  the contents of each extracted file to the standard input of an
+	  external program.
+
+config FEATURE_TAR_UNAME_GNAME
+	bool "Enable use of user and group names"
+	default y
+	depends on TAR
+	help
+	  Enables use of user and group names in tar. This affects contents
+	  listings (-t) and preserving permissions when unpacking (-p).
+	  +200 bytes.
+
+config FEATURE_TAR_NOPRESERVE_TIME
+	bool "Enable -m (do not preserve time) option"
+	default y
+	depends on TAR
+	help
+	  With this option busybox supports GNU tar -m
+	  (do not preserve time) option.
+
+config FEATURE_TAR_SELINUX
+	bool "Support for extracting SELinux labels"
+	default n
+	depends on TAR && SELINUX
+	help
+	  With this option busybox supports restoring SELinux labels
+	  when extracting files from tar archives.
+
+config UNCOMPRESS
+	bool "uncompress"
+	default n
+	help
+	  uncompress is used to decompress archives created by compress.
+	  Not much used anymore, replaced by gzip/gunzip.
+
+config UNLZMA
+	bool "unlzma"
+	default y
+	help
+	  unlzma is a compression utility using the Lempel-Ziv-Markov chain
+	  compression algorithm, and range coding. Compression
+	  is generally considerably better than that achieved by the bzip2
+	  compressors.
+
+	  The BusyBox unlzma applet is limited to decompression only.
+	  On an x86 system, this applet adds about 4K.
+
+config FEATURE_LZMA_FAST
+	bool "Optimize unlzma for speed"
+	default n
+	depends on UNLZMA
+	help
+	  This option reduces decompression time by about 25% at the cost of
+	  a 1K bigger binary.
+
+config LZMA
+	bool "Provide lzma alias which supports only unpacking"
+	default y
+	depends on UNLZMA
+	help
+	  Enable this option if you want commands like "lzma -d" to work.
+	  IOW: you'll get lzma applet, but it will always require -d option.
+
+config UNXZ
+	bool "unxz"
+	default y
+	help
+	  unxz is a unlzma successor.
+
+config XZ
+	bool "Provide xz alias which supports only unpacking"
+	default y
+	depends on UNXZ
+	help
+	  Enable this option if you want commands like "xz -d" to work.
+	  IOW: you'll get xz applet, but it will always require -d option.
+
+config UNZIP
+	bool "unzip"
+	default y
+	help
+	  unzip will list or extract files from a ZIP archive,
+	  commonly found on DOS/WIN systems. The default behavior
+	  (with no options) is to extract the archive into the
+	  current directory. Use the `-d' option to extract to a
+	  directory of your choice.
+
+endmenu
diff --git a/ap/app/busybox/src/archival/Kbuild.src b/ap/app/busybox/src/archival/Kbuild.src
new file mode 100644
index 0000000..3466452
--- /dev/null
+++ b/ap/app/busybox/src/archival/Kbuild.src
@@ -0,0 +1,30 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under GPLv2, see file LICENSE in this source tree.
+
+libs-y				+= libarchive/
+
+lib-y:=
+
+INSERT
+
+lib-$(CONFIG_AR)		+= ar.o
+lib-$(CONFIG_CPIO)		+= cpio.o
+lib-$(CONFIG_DPKG)		+= dpkg.o
+lib-$(CONFIG_DPKG_DEB)		+= dpkg_deb.o
+lib-$(CONFIG_RPM2CPIO)		+= rpm2cpio.o
+lib-$(CONFIG_RPM)		+= rpm.o
+lib-$(CONFIG_TAR)		+= tar.o
+lib-$(CONFIG_UNZIP)		+= unzip.o
+
+lib-$(CONFIG_LZOP)		+= lzop.o bbunzip.o
+lib-$(CONFIG_GZIP)		+= gzip.o bbunzip.o
+lib-$(CONFIG_BZIP2)		+= bzip2.o bbunzip.o
+
+lib-$(CONFIG_UNXZ)		+= bbunzip.o
+lib-$(CONFIG_UNLZMA)		+= bbunzip.o
+lib-$(CONFIG_BUNZIP2)		+= bbunzip.o
+lib-$(CONFIG_GUNZIP)		+= bbunzip.o
+lib-$(CONFIG_UNCOMPRESS)	+= bbunzip.o
diff --git a/ap/app/busybox/src/archival/ar.c b/ap/app/busybox/src/archival/ar.c
new file mode 100644
index 0000000..88236e8
--- /dev/null
+++ b/ap/app/busybox/src/archival/ar.c
@@ -0,0 +1,261 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini ar implementation for busybox
+ *
+ * Copyright (C) 2000 by Glenn McGrath
+ *
+ * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ *
+ * Archive creation support:
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ * Written by Alexander Shishkin.
+ *
+ * There is no single standard to adhere to so ar may not portable
+ * between different systems
+ * http://www.unix-systems.org/single_unix_specification_v2/xcu/ar.html
+ */
+
+//usage:#define ar_trivial_usage
+//usage:       "[-o] [-v] [-p] [-t] [-x] ARCHIVE FILES"
+//usage:#define ar_full_usage "\n\n"
+//usage:       "Extract or list FILES from an ar archive\n"
+//usage:     "\n	-o	Preserve original dates"
+//usage:     "\n	-p	Extract to stdout"
+//usage:     "\n	-t	List"
+//usage:     "\n	-x	Extract"
+//usage:     "\n	-v	Verbose"
+
+#include "libbb.h"
+#include "bb_archive.h"
+#include "ar.h"
+
+#if ENABLE_FEATURE_AR_CREATE
+/* filter out entries with same names as specified on the command line */
+static char FAST_FUNC filter_replaceable(archive_handle_t *handle)
+{
+	if (find_list_entry(handle->accept, handle->file_header->name))
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
+
+static void output_ar_header(archive_handle_t *handle)
+{
+	/* GNU ar 2.19.51.0.14 creates malformed archives
+	 * if input files are >10G. It also truncates files >4GB
+	 * (uses "size mod 4G"). We abort in this case:
+	 * We could add support for up to 10G files, but this is unlikely to be useful.
+	 * Note that unpacking side limits all fields to "unsigned int" data type,
+	 * and treats "all ones" as an error indicator. Thus max we allow here is UINT_MAX-1.
+	 */
+	enum {
+		/* for 2nd field: mtime */
+		MAX11CHARS = UINT_MAX > 0xffffffff ? (unsigned)99999999999 : UINT_MAX-1,
+		/* for last field: filesize */
+		MAX10CHARS = UINT_MAX > 0xffffffff ? (unsigned)9999999999 : UINT_MAX-1,
+	};
+
+	struct file_header_t *fh = handle->file_header;
+
+	if (handle->offset & 1) {
+		xwrite(handle->src_fd, "\n", 1);
+		handle->offset++;
+	}
+
+	/* Careful! The widths should be exact. Fields must be separated */
+	if (sizeof(off_t) > 4 && fh->size > (off_t)MAX10CHARS) {
+		bb_error_msg_and_die("'%s' is bigger than ar can handle", fh->name);
+	}
+	fdprintf(handle->src_fd, "%-16.16s%-12lu%-6u%-6u%-8o%-10"OFF_FMT"u`\n",
+			fh->name,
+			(sizeof(time_t) > 4 && fh->mtime > MAX11CHARS) ? (long)0 : (long)fh->mtime,
+			fh->uid > 99999 ? 0 : (int)fh->uid,
+			fh->gid > 99999 ? 0 : (int)fh->gid,
+			(int)fh->mode & 07777777,
+			fh->size
+	);
+
+	handle->offset += AR_HEADER_LEN;
+}
+
+/*
+ * when replacing files in an existing archive, copy from the
+ * original archive those files that are to be left intact
+ */
+static void FAST_FUNC copy_data(archive_handle_t *handle)
+{
+	archive_handle_t *out_handle = handle->ar__out;
+	struct file_header_t *fh = handle->file_header;
+
+	out_handle->file_header = fh;
+	output_ar_header(out_handle);
+
+	bb_copyfd_exact_size(handle->src_fd, out_handle->src_fd, fh->size);
+	out_handle->offset += fh->size;
+}
+
+static int write_ar_header(archive_handle_t *handle)
+{
+	char *fn;
+	char fn_h[17]; /* 15 + "/" + NUL */
+	struct stat st;
+	int fd;
+
+	fn = llist_pop(&handle->accept);
+	if (!fn)
+		return -1;
+
+	xstat(fn, &st);
+
+	handle->file_header->mtime = st.st_mtime;
+	handle->file_header->uid = st.st_uid;
+	handle->file_header->gid = st.st_gid;
+	handle->file_header->mode = st.st_mode;
+	handle->file_header->size = st.st_size;
+	handle->file_header->name = fn_h;
+//TODO: if ENABLE_FEATURE_AR_LONG_FILENAMES...
+	sprintf(fn_h, "%.15s/", bb_basename(fn));
+
+	output_ar_header(handle);
+
+	fd = xopen(fn, O_RDONLY);
+	bb_copyfd_exact_size(fd, handle->src_fd, st.st_size);
+	close(fd);
+	handle->offset += st.st_size;
+
+	return 0;
+}
+
+static int write_ar_archive(archive_handle_t *handle)
+{
+	struct stat st;
+	archive_handle_t *out_handle;
+
+	xfstat(handle->src_fd, &st, handle->ar__name);
+
+	/* if archive exists, create a new handle for output.
+	 * we create it in place of the old one.
+	 */
+	if (st.st_size != 0) {
+		out_handle = init_handle();
+		xunlink(handle->ar__name);
+		out_handle->src_fd = xopen(handle->ar__name, O_WRONLY | O_CREAT | O_TRUNC);
+		out_handle->accept = handle->accept;
+	} else {
+		out_handle = handle;
+	}
+
+	handle->ar__out = out_handle;
+
+	xwrite(out_handle->src_fd, AR_MAGIC "\n", AR_MAGIC_LEN + 1);
+	out_handle->offset += AR_MAGIC_LEN + 1;
+
+	/* skip to the end of the archive if we have to append stuff */
+	if (st.st_size != 0) {
+		handle->filter = filter_replaceable;
+		handle->action_data = copy_data;
+		unpack_ar_archive(handle);
+	}
+
+	while (write_ar_header(out_handle) == 0)
+		continue;
+
+	/* optional, since we exit right after we return */
+	if (ENABLE_FEATURE_CLEAN_UP) {
+		close(handle->src_fd);
+		if (out_handle->src_fd != handle->src_fd)
+			close(out_handle->src_fd);
+	}
+
+	return EXIT_SUCCESS;
+}
+#endif /* FEATURE_AR_CREATE */
+
+static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header)
+{
+	const char *mode = bb_mode_string(file_header->mode);
+	char *mtime;
+
+	mtime = ctime(&file_header->mtime);
+	mtime[16] = ' ';
+	memmove(&mtime[17], &mtime[20], 4);
+	mtime[21] = '\0';
+	printf("%s %u/%u%7"OFF_FMT"u %s %s\n", &mode[1],
+			(int)file_header->uid, (int)file_header->gid,
+			file_header->size,
+			&mtime[4], file_header->name
+	);
+}
+
+#define AR_OPT_VERBOSE          (1 << 0)
+#define AR_OPT_PRESERVE_DATE    (1 << 1)
+/* "ar r" implies create, but warns about it. c suppresses warning.
+ * bbox accepts but ignores it: */
+#define AR_OPT_CREATE           (1 << 2)
+
+#define AR_CMD_PRINT            (1 << 3)
+#define FIRST_CMD               AR_CMD_PRINT
+#define AR_CMD_LIST             (1 << 4)
+#define AR_CMD_EXTRACT          (1 << 5)
+#define AR_CMD_INSERT           (1 << 6)
+
+int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ar_main(int argc UNUSED_PARAM, char **argv)
+{
+	archive_handle_t *archive_handle;
+	unsigned opt, t;
+
+	archive_handle = init_handle();
+
+	/* --: prepend '-' to the first argument if required */
+	/* -1: at least one param is reqd */
+	/* one of p,t,x[,r] is required */
+	opt_complementary = "--:-1:p:t:x"IF_FEATURE_AR_CREATE(":r");
+	opt = getopt32(argv, "voc""ptx"IF_FEATURE_AR_CREATE("r"));
+	argv += optind;
+
+	t = opt / FIRST_CMD;
+	if (t & (t-1)) /* more than one of p,t,x[,r] are specified */
+		bb_show_usage();
+
+	if (opt & AR_CMD_PRINT) {
+		archive_handle->action_data = data_extract_to_stdout;
+	}
+	if (opt & AR_CMD_LIST) {
+		archive_handle->action_header = header_list;
+	}
+	if (opt & AR_CMD_EXTRACT) {
+		archive_handle->action_data = data_extract_all;
+	}
+	if (opt & AR_OPT_PRESERVE_DATE) {
+		archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
+	}
+	if (opt & AR_OPT_VERBOSE) {
+		archive_handle->action_header = header_verbose_list_ar;
+	}
+#if ENABLE_FEATURE_AR_CREATE
+	archive_handle->ar__name = *argv;
+#endif
+	archive_handle->src_fd = xopen(*argv++,
+			(opt & AR_CMD_INSERT)
+				? O_RDWR | O_CREAT
+				: O_RDONLY
+	);
+
+	if (*argv)
+		archive_handle->filter = filter_accept_list;
+	while (*argv) {
+		llist_add_to_end(&archive_handle->accept, *argv++);
+	}
+
+#if ENABLE_FEATURE_AR_CREATE
+	if (opt & AR_CMD_INSERT)
+		return write_ar_archive(archive_handle);
+#endif
+
+	unpack_ar_archive(archive_handle);
+
+	return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/archival/bbunzip.c b/ap/app/busybox/src/archival/bbunzip.c
new file mode 100644
index 0000000..94d8a81
--- /dev/null
+++ b/ap/app/busybox/src/archival/bbunzip.c
@@ -0,0 +1,439 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Common code for gunzip-like applets
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+#include "bb_archive.h"
+
+enum {
+	OPT_STDOUT     = 1 << 0,
+	OPT_FORCE      = 1 << 1,
+	/* only some decompressors: */
+	OPT_VERBOSE    = 1 << 2,
+	OPT_DECOMPRESS = 1 << 3,
+	OPT_TEST       = 1 << 4,
+};
+
+static
+int open_to_or_warn(int to_fd, const char *filename, int flags, int mode)
+{
+	int fd = open3_or_warn(filename, flags, mode);
+	if (fd < 0) {
+		return 1;
+	}
+	xmove_fd(fd, to_fd);
+	return 0;
+}
+
+char* FAST_FUNC append_ext(char *filename, const char *expected_ext)
+{
+	return xasprintf("%s.%s", filename, expected_ext);
+}
+
+int FAST_FUNC bbunpack(char **argv,
+	IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux),
+	char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
+	const char *expected_ext
+)
+{
+	struct stat stat_buf;
+	IF_DESKTOP(long long) int status;
+	char *filename, *new_name;
+	smallint exitcode = 0;
+	transformer_aux_data_t aux;
+
+	do {
+		/* NB: new_name is *maybe* malloc'ed! */
+		new_name = NULL;
+		filename = *argv; /* can be NULL - 'streaming' bunzip2 */
+
+		if (filename && LONE_DASH(filename))
+			filename = NULL;
+
+		/* Open src */
+		if (filename) {
+			if (stat(filename, &stat_buf) != 0) {
+				bb_simple_perror_msg(filename);
+ err:
+				exitcode = 1;
+				goto free_name;
+			}
+			if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0))
+				goto err;
+		}
+
+		/* Special cases: test, stdout */
+		if (option_mask32 & (OPT_STDOUT|OPT_TEST)) {
+			if (option_mask32 & OPT_TEST)
+				if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0))
+					goto err;
+			filename = NULL;
+		}
+
+		/* Open dst if we are going to unpack to file */
+		if (filename) {
+			new_name = make_new_name(filename, expected_ext);
+			if (!new_name) {
+				bb_error_msg("%s: unknown suffix - ignored", filename);
+				goto err;
+			}
+
+			/* -f: overwrite existing output files */
+			if (option_mask32 & OPT_FORCE) {
+				unlink(new_name);
+			}
+
+			/* O_EXCL: "real" bunzip2 doesn't overwrite files */
+			/* GNU gunzip does not bail out, but goes to next file */
+			if (open_to_or_warn(STDOUT_FILENO, new_name, O_WRONLY | O_CREAT | O_EXCL,
+					stat_buf.st_mode))
+				goto err;
+		}
+
+		/* Check that the input is sane */
+		if (isatty(STDIN_FILENO) && (option_mask32 & OPT_FORCE) == 0) {
+			bb_error_msg_and_die("compressed data not read from terminal, "
+					"use -f to force it");
+		}
+
+		init_transformer_aux_data(&aux);
+		aux.check_signature = 1;
+		status = unpacker(&aux);
+		if (status < 0)
+			exitcode = 1;
+
+		if (!(option_mask32 & OPT_STDOUT))
+			xclose(STDOUT_FILENO); /* with error check! */
+
+		if (filename) {
+			char *del = new_name;
+			if (status >= 0) {
+				/* TODO: restore other things? */
+				if (aux.mtime != 0) {
+					struct timeval times[2];
+
+					times[1].tv_sec = times[0].tv_sec = aux.mtime;
+					times[1].tv_usec = times[0].tv_usec = 0;
+					/* Note: we closed it first.
+					 * On some systems calling utimes
+					 * then closing resets the mtime
+					 * back to current time. */
+					utimes(new_name, times); /* ignoring errors */
+				}
+
+				/* Delete _compressed_ file */
+				del = filename;
+				/* restore extension (unless tgz -> tar case) */
+				if (new_name == filename)
+					filename[strlen(filename)] = '.';
+			}
+			xunlink(del);
+
+#if 0 /* Currently buggy - wrong name: "a.gz: 261% - replaced with a.gz" */
+			/* Extreme bloat for gunzip compat */
+			if (ENABLE_DESKTOP && (option_mask32 & OPT_VERBOSE) && status >= 0) {
+				fprintf(stderr, "%s: %u%% - replaced with %s\n",
+					filename, (unsigned)(stat_buf.st_size*100 / (status+1)), new_name);
+			}
+#endif
+
+ free_name:
+			if (new_name != filename)
+				free(new_name);
+		}
+	} while (*argv && *++argv);
+
+	if (option_mask32 & OPT_STDOUT)
+		xclose(STDOUT_FILENO); /* with error check! */
+
+	return exitcode;
+}
+
+#if ENABLE_UNCOMPRESS || ENABLE_BUNZIP2 || ENABLE_UNLZMA || ENABLE_UNXZ
+static
+char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
+{
+	char *extension = strrchr(filename, '.');
+	if (!extension || strcmp(extension + 1, expected_ext) != 0) {
+		/* Mimic GNU gunzip - "real" bunzip2 tries to */
+		/* unpack file anyway, to file.out */
+		return NULL;
+	}
+	*extension = '\0';
+	return filename;
+}
+#endif
+
+
+/*
+ * Uncompress applet for busybox (c) 2002 Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//usage:#define uncompress_trivial_usage
+//usage:       "[-cf] [FILE]..."
+//usage:#define uncompress_full_usage "\n\n"
+//usage:       "Decompress .Z file[s]\n"
+//usage:     "\n	-c	Write to stdout"
+//usage:     "\n	-f	Overwrite"
+
+#if ENABLE_UNCOMPRESS
+static
+IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux)
+{
+	return unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO);
+}
+int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int uncompress_main(int argc UNUSED_PARAM, char **argv)
+{
+	getopt32(argv, "cf");
+	argv += optind;
+
+	return bbunpack(argv, unpack_uncompress, make_new_name_generic, "Z");
+}
+#endif
+
+
+/*
+ * Gzip implementation for busybox
+ *
+ * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
+ * based on gzip sources
+ *
+ * Adjusted further by Erik Andersen <andersen@codepoet.org> to support files as
+ * well as stdin/stdout, and to generally behave itself wrt command line
+ * handling.
+ *
+ * General cleanup to better adhere to the style guide and make use of standard
+ * busybox functions by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ *
+ * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+//usage:#define gunzip_trivial_usage
+//usage:       "[-cft] [FILE]..."
+//usage:#define gunzip_full_usage "\n\n"
+//usage:       "Decompress FILEs (or stdin)\n"
+//usage:     "\n	-c	Write to stdout"
+//usage:     "\n	-f	Force"
+//usage:     "\n	-t	Test file integrity"
+//usage:
+//usage:#define gunzip_example_usage
+//usage:       "$ ls -la /tmp/BusyBox*\n"
+//usage:       "-rw-rw-r--    1 andersen andersen   557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n"
+//usage:       "$ gunzip /tmp/BusyBox-0.43.tar.gz\n"
+//usage:       "$ ls -la /tmp/BusyBox*\n"
+//usage:       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
+//usage:
+//usage:#define zcat_trivial_usage
+//usage:       "FILE"
+//usage:#define zcat_full_usage "\n\n"
+//usage:       "Decompress to stdout"
+
+#if ENABLE_GUNZIP
+static
+char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM)
+{
+	char *extension = strrchr(filename, '.');
+
+	if (!extension)
+		return NULL;
+
+	extension++;
+	if (strcmp(extension, "tgz" + 1) == 0
+#if ENABLE_FEATURE_SEAMLESS_Z
+	 || (extension[0] == 'Z' && extension[1] == '\0')
+#endif
+	) {
+		extension[-1] = '\0';
+	} else if (strcmp(extension, "tgz") == 0) {
+		filename = xstrdup(filename);
+		extension = strrchr(filename, '.');
+		extension[2] = 'a';
+		extension[3] = 'r';
+	} else {
+		return NULL;
+	}
+	return filename;
+}
+static
+IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux)
+{
+	return unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
+}
+/*
+ * Linux kernel build uses gzip -d -n. We accept and ignore it.
+ * Man page says:
+ * -n --no-name
+ * gzip: do not save the original file name and time stamp.
+ * (The original name is always saved if the name had to be truncated.)
+ * gunzip: do not restore the original file name/time even if present
+ * (remove only the gzip suffix from the compressed file name).
+ * This option is the default when decompressing.
+ * -N --name
+ * gzip: always save the original file name and time stamp (this is the default)
+ * gunzip: restore the original file name and time stamp if present.
+ */
+int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int gunzip_main(int argc UNUSED_PARAM, char **argv)
+{
+	getopt32(argv, "cfvdtn");
+	argv += optind;
+	/* if called as zcat */
+	if (applet_name[1] == 'c')
+		option_mask32 |= OPT_STDOUT;
+
+	return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL);
+}
+#endif
+
+
+/*
+ * Modified for busybox by Glenn McGrath
+ * Added support output to stdout by Thomas Lundquist <thomasez@zelow.no>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+//usage:#define bunzip2_trivial_usage
+//usage:       "[-cf] [FILE]..."
+//usage:#define bunzip2_full_usage "\n\n"
+//usage:       "Decompress FILEs (or stdin)\n"
+//usage:     "\n	-c	Write to stdout"
+//usage:     "\n	-f	Force"
+//usage:#define bzcat_trivial_usage
+//usage:       "FILE"
+//usage:#define bzcat_full_usage "\n\n"
+//usage:       "Decompress to stdout"
+//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
+//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat))
+#if ENABLE_BUNZIP2
+static
+IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux)
+{
+	return unpack_bz2_stream(aux, STDIN_FILENO, STDOUT_FILENO);
+}
+int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int bunzip2_main(int argc UNUSED_PARAM, char **argv)
+{
+	getopt32(argv, "cfvdt");
+	argv += optind;
+	if (applet_name[2] == 'c') /* bzcat */
+		option_mask32 |= OPT_STDOUT;
+
+	return bbunpack(argv, unpack_bunzip2, make_new_name_generic, "bz2");
+}
+#endif
+
+
+/*
+ * Small lzma deflate implementation.
+ * Copyright (C) 2006  Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * Based on bunzip.c from busybox
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define unlzma_trivial_usage
+//usage:       "[-cf] [FILE]..."
+//usage:#define unlzma_full_usage "\n\n"
+//usage:       "Decompress FILE (or stdin)\n"
+//usage:     "\n	-c	Write to stdout"
+//usage:     "\n	-f	Force"
+//usage:
+//usage:#define lzma_trivial_usage
+//usage:       "-d [-cf] [FILE]..."
+//usage:#define lzma_full_usage "\n\n"
+//usage:       "Decompress FILE (or stdin)\n"
+//usage:     "\n	-d	Decompress"
+//usage:     "\n	-c	Write to stdout"
+//usage:     "\n	-f	Force"
+//usage:
+//usage:#define lzcat_trivial_usage
+//usage:       "FILE"
+//usage:#define lzcat_full_usage "\n\n"
+//usage:       "Decompress to stdout"
+//usage:
+//usage:#define unxz_trivial_usage
+//usage:       "[-cf] [FILE]..."
+//usage:#define unxz_full_usage "\n\n"
+//usage:       "Decompress FILE (or stdin)\n"
+//usage:     "\n	-c	Write to stdout"
+//usage:     "\n	-f	Force"
+//usage:
+//usage:#define xz_trivial_usage
+//usage:       "-d [-cf] [FILE]..."
+//usage:#define xz_full_usage "\n\n"
+//usage:       "Decompress FILE (or stdin)\n"
+//usage:     "\n	-d	Decompress"
+//usage:     "\n	-c	Write to stdout"
+//usage:     "\n	-f	Force"
+//usage:
+//usage:#define xzcat_trivial_usage
+//usage:       "FILE"
+//usage:#define xzcat_full_usage "\n\n"
+//usage:       "Decompress to stdout"
+
+#if ENABLE_UNLZMA
+static
+IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux)
+{
+	return unpack_lzma_stream(aux, STDIN_FILENO, STDOUT_FILENO);
+}
+int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int unlzma_main(int argc UNUSED_PARAM, char **argv)
+{
+	IF_LZMA(int opts =) getopt32(argv, "cfvdt");
+# if ENABLE_LZMA
+	/* lzma without -d or -t? */
+	if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST)))
+		bb_show_usage();
+# endif
+	/* lzcat? */
+	if (applet_name[2] == 'c')
+		option_mask32 |= OPT_STDOUT;
+
+	argv += optind;
+	return bbunpack(argv, unpack_unlzma, make_new_name_generic, "lzma");
+}
+#endif
+
+
+#if ENABLE_UNXZ
+static
+IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux)
+{
+	return unpack_xz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
+}
+int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int unxz_main(int argc UNUSED_PARAM, char **argv)
+{
+	IF_XZ(int opts =) getopt32(argv, "cfvdt");
+# if ENABLE_XZ
+	/* xz without -d or -t? */
+	if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST)))
+		bb_show_usage();
+# endif
+	/* xzcat? */
+	if (applet_name[2] == 'c')
+		option_mask32 |= OPT_STDOUT;
+
+	argv += optind;
+	return bbunpack(argv, unpack_unxz, make_new_name_generic, "xz");
+}
+#endif
diff --git a/ap/app/busybox/src/archival/bbunzip_test.sh b/ap/app/busybox/src/archival/bbunzip_test.sh
new file mode 100644
index 0000000..b8e31bf
--- /dev/null
+++ b/ap/app/busybox/src/archival/bbunzip_test.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+# Test that concatenated gz files are unpacking correctly.
+# It also tests that unpacking in general is working right.
+# Since zip code has many corner cases, run it for a few hours
+# to get a decent coverage (200000 tests or more).
+
+gzip="gzip"
+gunzip="../busybox gunzip"
+# Or the other way around:
+#gzip="../busybox gzip"
+#gunzip="gunzip"
+
+c=0
+i=$PID
+while true; do
+    c=$((c+1))
+
+    # RANDOM is not very random on some shells. Spice it up.
+    # 100003 is prime
+    len1=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 ))
+    i=$((i * 1664525 + 1013904223))
+    len2=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 ))
+
+    # Just using urandom will make gzip use method 0 (store) -
+    # not good for test coverage!
+    cat /dev/urandom | while true; do read junk; echo "junk $c $i $junk"; done \
+    | dd bs=$len1 count=1 >z1 2>/dev/null
+    cat /dev/urandom | while true; do read junk; echo "junk $c $i $junk"; done \
+    | dd bs=$len2 count=1 >z2 2>/dev/null
+
+    $gzip <z1 >zz.gz
+    $gzip <z2 >>zz.gz
+    $gunzip -c zz.gz >z9 || {
+	echo "Exitcode $?"
+	exit
+    }
+    sum=`cat z1 z2 | md5sum`
+    sum9=`md5sum <z9`
+    test "$sum" == "$sum9" || {
+	echo "md5sums don't match"
+	exit
+    }
+    echo "Test $c ok: len1=$len1 len2=$len2 sum=$sum"
+
+    sum=`cat z1 z2 z1 z2 | md5sum`
+    rm z1.gz z2.gz 2>/dev/null
+    $gzip z1
+    $gzip z2
+    cat z1.gz z2.gz z1.gz z2.gz >zz.gz
+    $gunzip -c zz.gz >z9 || {
+	echo "Exitcode $? (2)"
+	exit
+    }
+    sum9=`md5sum <z9`
+    test "$sum" == "$sum9" || {
+	echo "md5sums don't match (1)"
+	exit
+    }
+
+    echo "Test $c ok: len1=$len1 len2=$len2 sum=$sum (2)"
+done
diff --git a/ap/app/busybox/src/archival/bbunzip_test2.sh b/ap/app/busybox/src/archival/bbunzip_test2.sh
new file mode 100644
index 0000000..5b7e83e
--- /dev/null
+++ b/ap/app/busybox/src/archival/bbunzip_test2.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Leak test for gunzip. Watch top for growing process size.
+
+# Just using urandom will make gzip use method 0 (store) -
+# not good for test coverage!
+
+cat /dev/urandom \
+| while true; do read junk; echo "junk $RANDOM $junk"; done \
+| ../busybox gzip \
+| ../busybox gunzip -c >/dev/null
diff --git a/ap/app/busybox/src/archival/bbunzip_test3.sh b/ap/app/busybox/src/archival/bbunzip_test3.sh
new file mode 100644
index 0000000..2dc4afd
--- /dev/null
+++ b/ap/app/busybox/src/archival/bbunzip_test3.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Leak test for gunzip. Watch top for growing process size.
+# In this case we look for leaks in "concatenated .gz" code -
+# we feed gunzip with a stream of .gz files.
+
+i=$PID
+c=0
+while true; do
+    c=$((c + 1))
+    echo "Block# $c" >&2
+    # RANDOM is not very random on some shells. Spice it up.
+    i=$((i * 1664525 + 1013904223))
+    # 100003 is prime
+    len=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 ))
+
+    # Just using urandom will make gzip use method 0 (store) -
+    # not good for test coverage!
+    cat /dev/urandom \
+    | while true; do read junk; echo "junk $c $i $junk"; done \
+    | dd bs=$len count=1 2>/dev/null \
+    | gzip >xxx.gz
+    cat xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz
+done | ../busybox gunzip -c >/dev/null
diff --git a/ap/app/busybox/src/archival/bzip2.c b/ap/app/busybox/src/archival/bzip2.c
new file mode 100644
index 0000000..dd77c8e
--- /dev/null
+++ b/ap/app/busybox/src/archival/bzip2.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * This file uses bzip2 library code which is written
+ * by Julian Seward <jseward@bzip.org>.
+ * See README and LICENSE files in bz/ directory for more information
+ * about bzip2 library code.
+ */
+
+//usage:#define bzip2_trivial_usage
+//usage:       "[OPTIONS] [FILE]..."
+//usage:#define bzip2_full_usage "\n\n"
+//usage:       "Compress FILEs (or stdin) with bzip2 algorithm\n"
+//usage:     "\n	-1..9	Compression level"
+//usage:     "\n	-d	Decompress"
+//usage:     "\n	-c	Write to stdout"
+//usage:     "\n	-f	Force"
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+#define CONFIG_BZIP2_FAST 1
+
+/* Speed test:
+ * Compiled with gcc 4.2.1, run on Athlon 64 1800 MHz (512K L2 cache).
+ * Stock bzip2 is 26.4% slower than bbox bzip2 at SPEED 1
+ * (time to compress gcc-4.2.1.tar is 126.4% compared to bbox).
+ * At SPEED 5 difference is 32.7%.
+ *
+ * Test run of all CONFIG_BZIP2_FAST values on a 11Mb text file:
+ *     Size   Time (3 runs)
+ * 0:  10828  4.145 4.146 4.148
+ * 1:  11097  3.845 3.860 3.861
+ * 2:  11392  3.763 3.767 3.768
+ * 3:  11892  3.722 3.724 3.727
+ * 4:  12740  3.637 3.640 3.644
+ * 5:  17273  3.497 3.509 3.509
+ */
+
+
+#define BZ_DEBUG 0
+/* Takes ~300 bytes, detects corruption caused by bad RAM etc */
+#define BZ_LIGHT_DEBUG 0
+
+#include "libarchive/bz/bzlib.h"
+
+#include "libarchive/bz/bzlib_private.h"
+
+#include "libarchive/bz/blocksort.c"
+#include "libarchive/bz/bzlib.c"
+#include "libarchive/bz/compress.c"
+#include "libarchive/bz/huffman.c"
+
+/* No point in being shy and having very small buffer here.
+ * bzip2 internal buffers are much bigger anyway, hundreds of kbytes.
+ * If iobuf is several pages long, malloc() may use mmap,
+ * making iobuf is page aligned and thus (maybe) have one memcpy less
+ * if kernel is clever enough.
+ */
+enum {
+	IOBUF_SIZE = 8 * 1024
+};
+
+static uint8_t level;
+
+/* NB: compressStream() has to return -1 on errors, not die.
+ * bbunpack() will correctly clean up in this case
+ * (delete incomplete .bz2 file)
+ */
+
+/* Returns:
+ * -1 on errors
+ * total written bytes so far otherwise
+ */
+static
+IF_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, void *wbuf)
+{
+	int n, n2, ret;
+
+	strm->avail_in = rlen;
+	strm->next_in = rbuf;
+	while (1) {
+		strm->avail_out = IOBUF_SIZE;
+		strm->next_out = wbuf;
+
+		ret = BZ2_bzCompress(strm, rlen ? BZ_RUN : BZ_FINISH);
+		if (ret != BZ_RUN_OK /* BZ_RUNning */
+		 && ret != BZ_FINISH_OK /* BZ_FINISHing, but not done yet */
+		 && ret != BZ_STREAM_END /* BZ_FINISHed */
+		) {
+			bb_error_msg_and_die("internal error %d", ret);
+		}
+
+		n = IOBUF_SIZE - strm->avail_out;
+		if (n) {
+			n2 = full_write(STDOUT_FILENO, wbuf, n);
+			if (n2 != n) {
+				if (n2 >= 0)
+					errno = 0; /* prevent bogus error message */
+				bb_perror_msg(n2 >= 0 ? "short write" : bb_msg_write_error);
+				return -1;
+			}
+		}
+
+		if (ret == BZ_STREAM_END)
+			break;
+		if (rlen && strm->avail_in == 0)
+			break;
+	}
+	return 0 IF_DESKTOP( + strm->total_out );
+}
+
+static
+IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_aux_data_t *aux UNUSED_PARAM)
+{
+	IF_DESKTOP(long long) int total;
+	ssize_t count;
+	bz_stream bzs; /* it's small */
+#define strm (&bzs)
+	char *iobuf;
+#define rbuf iobuf
+#define wbuf (iobuf + IOBUF_SIZE)
+
+	iobuf = xmalloc(2 * IOBUF_SIZE);
+	BZ2_bzCompressInit(strm, level);
+
+	while (1) {
+		count = full_read(STDIN_FILENO, rbuf, IOBUF_SIZE);
+		if (count < 0) {
+			bb_perror_msg(bb_msg_read_error);
+			total = -1;
+			break;
+		}
+		/* if count == 0, bz_write finalizes compression */
+		total = bz_write(strm, rbuf, count, wbuf);
+		if (count == 0 || total < 0)
+			break;
+	}
+
+	/* Can't be conditional on ENABLE_FEATURE_CLEAN_UP -
+	 * we are called repeatedly
+	 */
+	BZ2_bzCompressEnd(strm);
+	free(iobuf);
+
+	return total;
+}
+
+int bzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int bzip2_main(int argc UNUSED_PARAM, char **argv)
+{
+	unsigned opt;
+
+	/* standard bzip2 flags
+	 * -d --decompress force decompression
+	 * -z --compress force compression
+	 * -k --keep     keep (don't delete) input files
+	 * -f --force    overwrite existing output files
+	 * -t --test     test compressed file integrity
+	 * -c --stdout   output to standard out
+	 * -q --quiet    suppress noncritical error messages
+	 * -v --verbose  be verbose (a 2nd -v gives more)
+	 * -s --small    use less memory (at most 2500k)
+	 * -1 .. -9      set block size to 100k .. 900k
+	 * --fast        alias for -1
+	 * --best        alias for -9
+	 */
+
+	opt_complementary = "s2"; /* -s means -2 (compatibility) */
+	/* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
+	opt = getopt32(argv, "cfv" IF_BUNZIP2("dt") "123456789qzs");
+#if ENABLE_BUNZIP2 /* bunzip2_main may not be visible... */
+	if (opt & 0x18) // -d and/or -t
+		return bunzip2_main(argc, argv);
+	opt >>= 5;
+#else
+	opt >>= 3;
+#endif
+	opt = (uint8_t)opt; /* isolate bits for -1..-8 */
+	opt |= 0x100; /* if nothing else, assume -9 */
+	level = 1;
+	while (!(opt & 1)) {
+		level++;
+		opt >>= 1;
+	}
+
+	argv += optind;
+	option_mask32 &= 0x7; /* ignore all except -cfv */
+	return bbunpack(argv, compressStream, append_ext, "bz2");
+}
diff --git a/ap/app/busybox/src/archival/cpio.c b/ap/app/busybox/src/archival/cpio.c
new file mode 100644
index 0000000..699c6db
--- /dev/null
+++ b/ap/app/busybox/src/archival/cpio.c
@@ -0,0 +1,459 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini cpio implementation for busybox
+ *
+ * Copyright (C) 2001 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ *
+ * Limitations:
+ * Doesn't check CRC's
+ * Only supports new ASCII and CRC formats
+ *
+ */
+#include "libbb.h"
+#include "bb_archive.h"
+
+//usage:#define cpio_trivial_usage
+//usage:       "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]")
+//usage:       " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]")
+//usage:       " [EXTR_FILE]..."
+//usage:#define cpio_full_usage "\n\n"
+//usage:       "Extract or list files from a cpio archive"
+//usage:	IF_FEATURE_CPIO_O(", or"
+//usage:     "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)")
+//usage:		" using file list on stdin"
+//usage:	)
+//usage:     "\n"
+//usage:     "\nMain operation mode:"
+//usage:     "\n	-t	List"
+//usage:     "\n	-i	Extract EXTR_FILEs (or all)"
+//usage:	IF_FEATURE_CPIO_O(
+//usage:     "\n	-o	Create (requires -H newc)"
+//usage:	)
+//usage:	IF_FEATURE_CPIO_P(
+//usage:     "\n	-p DIR	Copy files to DIR"
+//usage:	)
+//usage:     "\n	-d	Make leading directories"
+//usage:     "\n	-m	Preserve mtime"
+//usage:     "\n	-v	Verbose"
+//usage:     "\n	-u	Overwrite"
+//usage:     "\n	-F FILE	Input (-t,-i,-p) or output (-o) file"
+//usage:	IF_FEATURE_CPIO_O(
+//usage:     "\n	-H newc	Archive format"
+//usage:	)
+
+/* GNU cpio 2.9 --help (abridged):
+
+ Modes:
+  -t, --list                 List the archive
+  -i, --extract              Extract files from an archive
+  -o, --create               Create the archive
+  -p, --pass-through         Copy-pass mode
+
+ Options valid in any mode:
+      --block-size=SIZE      I/O block size = SIZE * 512 bytes
+  -B                         I/O block size = 5120 bytes
+  -c                         Use the old portable (ASCII) archive format
+  -C, --io-size=NUMBER       I/O block size in bytes
+  -f, --nonmatching          Only copy files that do not match given pattern
+  -F, --file=FILE            Use FILE instead of standard input or output
+  -H, --format=FORMAT        Use given archive FORMAT
+  -M, --message=STRING       Print STRING when the end of a volume of the
+                             backup media is reached
+  -n, --numeric-uid-gid      If -v, show numeric UID and GID
+      --quiet                Do not print the number of blocks copied
+      --rsh-command=COMMAND  Use remote COMMAND instead of rsh
+  -v, --verbose              Verbosely list the files processed
+  -V, --dot                  Print a "." for each file processed
+  -W, --warning=FLAG         Control warning display: 'none','truncate','all';
+                             multiple options accumulate
+
+ Options valid only in --extract mode:
+  -b, --swap                 Swap both halfwords of words and bytes of
+                             halfwords in the data (equivalent to -sS)
+  -r, --rename               Interactively rename files
+  -s, --swap-bytes           Swap the bytes of each halfword in the files
+  -S, --swap-halfwords       Swap the halfwords of each word (4 bytes)
+      --to-stdout            Extract files to standard output
+  -E, --pattern-file=FILE    Read additional patterns specifying filenames to
+                             extract or list from FILE
+      --only-verify-crc      Verify CRC's, don't actually extract the files
+
+ Options valid only in --create mode:
+  -A, --append               Append to an existing archive
+  -O FILE                    File to use instead of standard output
+
+ Options valid only in --pass-through mode:
+  -l, --link                 Link files instead of copying them, when possible
+
+ Options valid in --extract and --create modes:
+      --absolute-filenames   Do not strip file system prefix components from
+                             the file names
+      --no-absolute-filenames Create all files relative to the current dir
+
+ Options valid in --create and --pass-through modes:
+  -0, --null                 A list of filenames is terminated by a NUL
+  -a, --reset-access-time    Reset the access times of files after reading them
+  -I FILE                    File to use instead of standard input
+  -L, --dereference          Dereference symbolic links (copy the files
+                             that they point to instead of copying the links)
+  -R, --owner=[USER][:.][GROUP] Set owner of created files
+
+ Options valid in --extract and --pass-through modes:
+  -d, --make-directories     Create leading directories where needed
+  -m, --preserve-modification-time  Retain mtime when creating files
+      --no-preserve-owner    Do not change the ownership of the files
+      --sparse               Write files with blocks of zeros as sparse files
+  -u, --unconditional        Replace all files unconditionally
+ */
+
+enum {
+	OPT_EXTRACT            = (1 << 0),
+	OPT_TEST               = (1 << 1),
+	OPT_NUL_TERMINATED     = (1 << 2),
+	OPT_UNCONDITIONAL      = (1 << 3),
+	OPT_VERBOSE            = (1 << 4),
+	OPT_CREATE_LEADING_DIR = (1 << 5),
+	OPT_PRESERVE_MTIME     = (1 << 6),
+	OPT_DEREF              = (1 << 7),
+	OPT_FILE               = (1 << 8),
+	OPTBIT_FILE = 8,
+	IF_FEATURE_CPIO_O(OPTBIT_CREATE     ,)
+	IF_FEATURE_CPIO_O(OPTBIT_FORMAT     ,)
+	IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,)
+	IF_LONG_OPTS(     OPTBIT_QUIET      ,)
+	IF_LONG_OPTS(     OPTBIT_2STDOUT    ,)
+	OPT_CREATE             = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE     )) + 0,
+	OPT_FORMAT             = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT     )) + 0,
+	OPT_PASSTHROUGH        = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0,
+	OPT_QUIET              = IF_LONG_OPTS(     (1 << OPTBIT_QUIET      )) + 0,
+	OPT_2STDOUT            = IF_LONG_OPTS(     (1 << OPTBIT_2STDOUT    )) + 0,
+};
+
+#define OPTION_STR "it0uvdmLF:"
+
+#if ENABLE_FEATURE_CPIO_O
+static off_t cpio_pad4(off_t size)
+{
+	int i;
+
+	i = (- size) & 3;
+	size += i;
+	while (--i >= 0)
+		bb_putchar('\0');
+	return size;
+}
+
+/* Return value will become exit code.
+ * It's ok to exit instead of return. */
+static NOINLINE int cpio_o(void)
+{
+	static const char trailer[] ALIGN1 = "TRAILER!!!";
+	struct name_s {
+		struct name_s *next;
+		char name[1];
+	};
+	struct inodes_s {
+		struct inodes_s *next;
+		struct name_s *names;
+		struct stat st;
+	};
+
+	struct inodes_s *links = NULL;
+	off_t bytes = 0; /* output bytes count */
+
+	while (1) {
+		const char *name;
+		char *line;
+		struct stat st;
+
+		line = (option_mask32 & OPT_NUL_TERMINATED)
+				? bb_get_chunk_from_file(stdin, NULL)
+				: xmalloc_fgetline(stdin);
+
+		if (line) {
+			/* Strip leading "./[./]..." from the filename */
+			name = line;
+			while (name[0] == '.' && name[1] == '/') {
+				while (*++name == '/')
+					continue;
+			}
+			if (!*name) { /* line is empty */
+				free(line);
+				continue;
+			}
+			if ((option_mask32 & OPT_DEREF)
+					? stat(name, &st)
+					: lstat(name, &st)
+			) {
+ abort_cpio_o:
+				bb_simple_perror_msg_and_die(name);
+			}
+
+			if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
+				st.st_size = 0; /* paranoia */
+
+			/* Store hardlinks for later processing, dont output them */
+			if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
+				struct name_s *n;
+				struct inodes_s *l;
+
+				/* Do we have this hardlink remembered? */
+				l = links;
+				while (1) {
+					if (l == NULL) {
+						/* Not found: add new item to "links" list */
+						l = xzalloc(sizeof(*l));
+						l->st = st;
+						l->next = links;
+						links = l;
+						break;
+					}
+					if (l->st.st_ino == st.st_ino) {
+						/* found */
+						break;
+					}
+					l = l->next;
+				}
+				/* Add new name to "l->names" list */
+				n = xmalloc(sizeof(*n) + strlen(name));
+				strcpy(n->name, name);
+				n->next = l->names;
+				l->names = n;
+
+				free(line);
+				continue;
+			}
+
+		} else { /* line == NULL: EOF */
+ next_link:
+			if (links) {
+				/* Output hardlink's data */
+				st = links->st;
+				name = links->names->name;
+				links->names = links->names->next;
+				/* GNU cpio is reported to emit file data
+				 * only for the last instance. Mimic that. */
+				if (links->names == NULL)
+					links = links->next;
+				else
+					st.st_size = 0;
+				/* NB: we leak links->names and/or links,
+				 * this is intended (we exit soon anyway) */
+			} else {
+				/* If no (more) hardlinks to output,
+				 * output "trailer" entry */
+				name = trailer;
+				/* st.st_size == 0 is a must, but for uniformity
+				 * in the output, we zero out everything */
+				memset(&st, 0, sizeof(st));
+				/* st.st_nlink = 1; - GNU cpio does this */
+			}
+		}
+
+		bytes += printf("070701"
+				"%08X%08X%08X%08X%08X%08X%08X"
+				"%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
+				/* strlen+1: */ "%08X"
+				/* chksum: */   "00000000" /* (only for "070702" files) */
+				/* name,NUL: */ "%s%c",
+				(unsigned)(uint32_t) st.st_ino,
+				(unsigned)(uint32_t) st.st_mode,
+				(unsigned)(uint32_t) st.st_uid,
+				(unsigned)(uint32_t) st.st_gid,
+				(unsigned)(uint32_t) st.st_nlink,
+				(unsigned)(uint32_t) st.st_mtime,
+				(unsigned)(uint32_t) st.st_size,
+				(unsigned)(uint32_t) major(st.st_dev),
+				(unsigned)(uint32_t) minor(st.st_dev),
+				(unsigned)(uint32_t) major(st.st_rdev),
+				(unsigned)(uint32_t) minor(st.st_rdev),
+				(unsigned)(strlen(name) + 1),
+				name, '\0');
+		bytes = cpio_pad4(bytes);
+
+		if (st.st_size) {
+			if (S_ISLNK(st.st_mode)) {
+				char *lpath = xmalloc_readlink_or_warn(name);
+				if (!lpath)
+					goto abort_cpio_o;
+				bytes += printf("%s", lpath);
+				free(lpath);
+			} else { /* S_ISREG */
+				int fd = xopen(name, O_RDONLY);
+				fflush_all();
+				/* We must abort if file got shorter too! */
+				bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
+				bytes += st.st_size;
+				close(fd);
+			}
+			bytes = cpio_pad4(bytes);
+		}
+
+		if (!line) {
+			if (name != trailer)
+				goto next_link;
+			/* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
+			return EXIT_SUCCESS;
+		}
+
+		free(line);
+	} /* end of "while (1)" */
+}
+#endif
+
+int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cpio_main(int argc UNUSED_PARAM, char **argv)
+{
+	archive_handle_t *archive_handle;
+	char *cpio_filename;
+	IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
+	unsigned opt;
+
+#if ENABLE_LONG_OPTS
+	applet_long_options =
+		"extract\0"      No_argument       "i"
+		"list\0"         No_argument       "t"
+#if ENABLE_FEATURE_CPIO_O
+		"create\0"       No_argument       "o"
+		"format\0"       Required_argument "H"
+#if ENABLE_FEATURE_CPIO_P
+		"pass-through\0" No_argument       "p"
+#endif
+#endif
+		"verbose\0"      No_argument       "v"
+		"quiet\0"        No_argument       "\xff"
+		"to-stdout\0"    No_argument       "\xfe"
+		;
+#endif
+
+	archive_handle = init_handle();
+	/* archive_handle->src_fd = STDIN_FILENO; - done by init_handle */
+	archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
+
+	/* As of now we do not enforce this: */
+	/* -i,-t,-o,-p are mutually exclusive */
+	/* -u,-d,-m make sense only with -i or -p */
+	/* -L makes sense only with -o or -p */
+
+#if !ENABLE_FEATURE_CPIO_O
+	opt = getopt32(argv, OPTION_STR, &cpio_filename);
+	argv += optind;
+	if (opt & OPT_FILE) { /* -F */
+		xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
+	}
+#else
+	opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
+	argv += optind;
+	if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) { /* -F without -o */
+		xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
+	}
+	if (opt & OPT_PASSTHROUGH) {
+		pid_t pid;
+		struct fd_pair pp;
+
+		if (argv[0] == NULL)
+			bb_show_usage();
+		if (opt & OPT_CREATE_LEADING_DIR)
+			mkdir(argv[0], 0777);
+		/* Crude existence check:
+		 * close(xopen(argv[0], O_RDONLY | O_DIRECTORY));
+		 * We can also xopen, fstat, IS_DIR, later fchdir.
+		 * This would check for existence earlier and cleaner.
+		 * As it stands now, if we fail xchdir later,
+		 * child dies on EPIPE, unless it caught
+		 * a diffrerent problem earlier.
+		 * This is good enough for now.
+		 */
+#if !BB_MMU
+		pp.rd = 3;
+		pp.wr = 4;
+		if (!re_execed) {
+			close(3);
+			close(4);
+			xpiped_pair(pp);
+		}
+#else
+		xpiped_pair(pp);
+#endif
+		pid = fork_or_rexec(argv - optind);
+		if (pid == 0) { /* child */
+			close(pp.rd);
+			xmove_fd(pp.wr, STDOUT_FILENO);
+			goto dump;
+		}
+		/* parent */
+		USE_FOR_NOMMU(argv[-optind][0] &= 0x7f); /* undo fork_or_rexec() damage */
+		xchdir(*argv++);
+		close(pp.wr);
+		xmove_fd(pp.rd, STDIN_FILENO);
+		//opt &= ~OPT_PASSTHROUGH;
+		opt |= OPT_EXTRACT;
+		goto skip;
+	}
+	/* -o */
+	if (opt & OPT_CREATE) {
+		if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */
+			bb_show_usage();
+		if (opt & OPT_FILE) {
+			xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
+		}
+ dump:
+		return cpio_o();
+	}
+ skip:
+#endif
+
+	/* One of either extract or test options must be given */
+	if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) {
+		bb_show_usage();
+	}
+
+	if (opt & OPT_TEST) {
+		/* if both extract and test options are given, ignore extract option */
+		opt &= ~OPT_EXTRACT;
+		archive_handle->action_header = header_list;
+	}
+	if (opt & OPT_EXTRACT) {
+		archive_handle->action_data = data_extract_all;
+		if (opt & OPT_2STDOUT)
+			archive_handle->action_data = data_extract_to_stdout;
+	}
+	if (opt & OPT_UNCONDITIONAL) {
+		archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
+		archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
+	}
+	if (opt & OPT_VERBOSE) {
+		if (archive_handle->action_header == header_list) {
+			archive_handle->action_header = header_verbose_list;
+		} else {
+			archive_handle->action_header = header_list;
+		}
+	}
+	if (opt & OPT_CREATE_LEADING_DIR) {
+		archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
+	}
+	if (opt & OPT_PRESERVE_MTIME) {
+		archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
+	}
+
+	while (*argv) {
+		archive_handle->filter = filter_accept_list;
+		llist_add_to(&archive_handle->accept, *argv);
+		argv++;
+	}
+
+	/* see get_header_cpio */
+	archive_handle->cpio__blocks = (off_t)-1;
+	while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
+		continue;
+
+	if (archive_handle->cpio__blocks != (off_t)-1
+	 && !(opt & OPT_QUIET)
+	) {
+		fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
+	}
+
+	return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/archival/dpkg.c b/ap/app/busybox/src/archival/dpkg.c
new file mode 100644
index 0000000..ed86f33
--- /dev/null
+++ b/ap/app/busybox/src/archival/dpkg.c
@@ -0,0 +1,1925 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *  mini dpkg implementation for busybox.
+ *  this is not meant as a replacement for dpkg
+ *
+ *  written by glenn mcgrath with the help of others
+ *  copyright (c) 2001 by glenn mcgrath
+ *
+ *  parts of the version comparison code is plucked from the real dpkg
+ *  application which is licensed GPLv2 and
+ *  copyright (c) 1995 Ian Jackson <ian@chiark.greenend.org.uk>
+ *
+ *  started life as a busybox implementation of udpkg
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/*
+ * known difference between busybox dpkg and the official dpkg that i don't
+ * consider important, its worth keeping a note of differences anyway, just to
+ * make it easier to maintain.
+ *  - the first value for the confflile: field isnt placed on a new line.
+ *  - when installing a package the status: field is placed at the end of the
+ *      section, rather than just after the package: field.
+ *
+ * bugs that need to be fixed
+ *  - (unknown, please let me know when you find any)
+ *
+ */
+
+//usage:#define dpkg_trivial_usage
+//usage:       "[-ilCPru] [-F OPT] PACKAGE"
+//usage:#define dpkg_full_usage "\n\n"
+//usage:       "Install, remove and manage Debian packages\n"
+//usage:	IF_LONG_OPTS(
+//usage:     "\n	-i,--install	Install the package"
+//usage:     "\n	-l,--list	List of installed packages"
+//usage:     "\n	--configure	Configure an unpackaged package"
+//usage:     "\n	-P,--purge	Purge all files of a package"
+//usage:     "\n	-r,--remove	Remove all but the configuration files for a package"
+//usage:     "\n	--unpack	Unpack a package, but don't configure it"
+//usage:     "\n	--force-depends	Ignore dependency problems"
+//usage:     "\n	--force-confnew	Overwrite existing config files when installing"
+//usage:     "\n	--force-confold	Keep old config files when installing"
+//usage:	)
+//usage:	IF_NOT_LONG_OPTS(
+//usage:     "\n	-i		Install the package"
+//usage:     "\n	-l		List of installed packages"
+//usage:     "\n	-C		Configure an unpackaged package"
+//usage:     "\n	-P		Purge all files of a package"
+//usage:     "\n	-r		Remove all but the configuration files for a package"
+//usage:     "\n	-u		Unpack a package, but don't configure it"
+//usage:     "\n	-F depends	Ignore dependency problems"
+//usage:     "\n	-F confnew	Overwrite existing config files when installing"
+//usage:     "\n	-F confold	Keep old config files when installing"
+//usage:	)
+
+#include "libbb.h"
+#include <fnmatch.h>
+#include "bb_archive.h"
+
+/* note: if you vary hash_prime sizes be aware,
+ * 1) tweaking these will have a big effect on how much memory this program uses.
+ * 2) for computational efficiency these hash tables should be at least 20%
+ *    larger than the maximum number of elements stored in it.
+ * 3) all _hash_prime's must be a prime number or chaos is assured, if your looking
+ *    for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt
+ * 4) if you go bigger than 15 bits you may get into trouble (untested) as its
+ *    sometimes cast to an unsigned, if you go to 16 bit you will overlap
+ *    int's and chaos is assured, 16381 is the max prime for 14 bit field
+ */
+
+/* NAME_HASH_PRIME, Stores package names and versions,
+ * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME,
+ * as there a lot of duplicate version numbers */
+#define NAME_HASH_PRIME 16381
+
+/* PACKAGE_HASH_PRIME, Maximum number of unique packages,
+ * It must not be smaller than STATUS_HASH_PRIME,
+ * Currently only packages from status_hashtable are stored in here, but in
+ * future this may be used to store packages not only from a status file,
+ * but an available_hashtable, and even multiple packages files.
+ * Package can be stored more than once if they have different versions.
+ * e.g. The same package may have different versions in the status file
+ *      and available file */
+#define PACKAGE_HASH_PRIME 10007
+typedef struct edge_s {
+	unsigned operator:4; /* was:3 */
+	unsigned type:4;
+	unsigned name:16; /* was:14 */
+	unsigned version:16; /* was:14 */
+} edge_t;
+
+typedef struct common_node_s {
+	unsigned name:16; /* was:14 */
+	unsigned version:16; /* was:14 */
+	unsigned num_of_edges:16; /* was:14 */
+	edge_t **edge;
+} common_node_t;
+
+/* Currently it doesnt store packages that have state-status of not-installed
+ * So it only really has to be the size of the maximum number of packages
+ * likely to be installed at any one time, so there is a bit of leeway here */
+#define STATUS_HASH_PRIME 8191
+typedef struct status_node_s {
+	unsigned package:16; /* was:14 */       /* has to fit PACKAGE_HASH_PRIME */
+	unsigned status:16; /* was:14 */        /* has to fit STATUS_HASH_PRIME */
+} status_node_t;
+
+
+/* Globals */
+struct globals {
+	char          *name_hashtable[NAME_HASH_PRIME + 1];
+	common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1];
+	status_node_t *status_hashtable[STATUS_HASH_PRIME + 1];
+};
+#define G (*ptr_to_globals)
+#define name_hashtable    (G.name_hashtable   )
+#define package_hashtable (G.package_hashtable)
+#define status_hashtable  (G.status_hashtable )
+#define INIT_G() do { \
+	SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+} while (0)
+
+
+/* Even numbers are for 'extras', like ored dependencies or null */
+enum edge_type_e {
+	EDGE_NULL = 0,
+	EDGE_PRE_DEPENDS = 1,
+	EDGE_OR_PRE_DEPENDS = 2,
+	EDGE_DEPENDS = 3,
+	EDGE_OR_DEPENDS = 4,
+	EDGE_REPLACES = 5,
+	EDGE_PROVIDES = 7,
+	EDGE_CONFLICTS = 9,
+	EDGE_SUGGESTS = 11,
+	EDGE_RECOMMENDS = 13,
+	EDGE_ENHANCES = 15
+};
+enum operator_e {
+	VER_NULL = 0,
+	VER_EQUAL = 1,
+	VER_LESS = 2,
+	VER_LESS_EQUAL = 3,
+	VER_MORE = 4,
+	VER_MORE_EQUAL = 5,
+	VER_ANY = 6
+};
+
+typedef struct deb_file_s {
+	char *control_file;
+	char *filename;
+	unsigned package:16; /* was:14 */
+} deb_file_t;
+
+
+static void make_hash(const char *key, unsigned *start, unsigned *decrement, const int hash_prime)
+{
+	unsigned long hash_num = key[0];
+	int len = strlen(key);
+	int i;
+
+	/* Maybe i should have uses a "proper" hashing algorithm here instead
+	 * of making one up myself, seems to be working ok though. */
+	for (i = 1; i < len; i++) {
+		/* shifts the ascii based value and adds it to previous value
+		 * shift amount is mod 24 because long int is 32 bit and data
+		 * to be shifted is 8, don't want to shift data to where it has
+		 * no effect */
+		hash_num += (key[i] + key[i-1]) << ((key[i] * i) % 24);
+	}
+	*start = (unsigned) hash_num % hash_prime;
+	*decrement = (unsigned) 1 + (hash_num % (hash_prime - 1));
+}
+
+/* this adds the key to the hash table */
+static int search_name_hashtable(const char *key)
+{
+	unsigned probe_address;
+	unsigned probe_decrement;
+
+	make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME);
+	while (name_hashtable[probe_address] != NULL) {
+		if (strcmp(name_hashtable[probe_address], key) == 0) {
+			return probe_address;
+		}
+		probe_address -= probe_decrement;
+		if ((int)probe_address < 0) {
+			probe_address += NAME_HASH_PRIME;
+		}
+	}
+	name_hashtable[probe_address] = xstrdup(key);
+	return probe_address;
+}
+
+/* this DOESNT add the key to the hashtable
+ * TODO make it consistent with search_name_hashtable
+ */
+static unsigned search_status_hashtable(const char *key)
+{
+	unsigned probe_address;
+	unsigned probe_decrement;
+
+	make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME);
+	while (status_hashtable[probe_address] != NULL) {
+		if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) {
+			break;
+		}
+		probe_address -= probe_decrement;
+		if ((int)probe_address < 0) {
+			probe_address += STATUS_HASH_PRIME;
+		}
+	}
+	return probe_address;
+}
+
+static int order(char x)
+{
+	return (x == '~' ? -1
+		: x == '\0' ? 0
+		: isdigit(x) ? 0
+		: isalpha(x) ? x
+		: (unsigned char)x + 256
+	);
+}
+
+/* This code is taken from dpkg and modified slightly to work with busybox */
+static int version_compare_part(const char *val, const char *ref)
+{
+	if (!val) val = "";
+	if (!ref) ref = "";
+
+	while (*val || *ref) {
+		int first_diff;
+
+		while ((*val && !isdigit(*val)) || (*ref && !isdigit(*ref))) {
+			int vc = order(*val);
+			int rc = order(*ref);
+			if (vc != rc)
+				return vc - rc;
+			val++;
+			ref++;
+		}
+
+		while (*val == '0')
+			val++;
+		while (*ref == '0')
+			ref++;
+
+		first_diff = 0;
+		while (isdigit(*val) && isdigit(*ref)) {
+			if (first_diff == 0)
+				first_diff = *val - *ref;
+			val++;
+			ref++;
+		}
+		if (isdigit(*val))
+			return 1;
+		if (isdigit(*ref))
+			return -1;
+		if (first_diff)
+			return first_diff;
+	}
+	return 0;
+}
+
+/* if ver1 < ver2 return -1,
+ * if ver1 = ver2 return 0,
+ * if ver1 > ver2 return 1,
+ */
+static int version_compare(const unsigned ver1, const unsigned ver2)
+{
+	char *ch_ver1 = name_hashtable[ver1];
+	char *ch_ver2 = name_hashtable[ver2];
+	unsigned epoch1 = 0, epoch2 = 0;
+	char *colon;
+	char *deb_ver1, *deb_ver2;
+	char *upstream_ver1;
+	char *upstream_ver2;
+	int result;
+
+	/* Compare epoch */
+	colon = strchr(ch_ver1, ':');
+	if (colon) {
+		epoch1 = atoi(ch_ver1);
+		ch_ver1 = colon + 1;
+	}
+	colon = strchr(ch_ver2, ':');
+	if (colon) {
+		epoch2 = atoi(ch_ver2);
+		ch_ver2 = colon + 1;
+	}
+	if (epoch1 < epoch2) {
+		return -1;
+	}
+	if (epoch1 > epoch2) {
+		return 1;
+	}
+
+	/* Compare upstream version */
+	upstream_ver1 = xstrdup(ch_ver1);
+	upstream_ver2 = xstrdup(ch_ver2);
+
+	/* Chop off debian version, and store for later use */
+	deb_ver1 = strrchr(upstream_ver1, '-');
+	deb_ver2 = strrchr(upstream_ver2, '-');
+	if (deb_ver1) {
+		*deb_ver1++ = '\0';
+	}
+	if (deb_ver2) {
+		*deb_ver2++ = '\0';
+	}
+	result = version_compare_part(upstream_ver1, upstream_ver2);
+	if (result == 0) {
+		/* Compare debian versions */
+		result = version_compare_part(deb_ver1, deb_ver2);
+	}
+
+	free(upstream_ver1);
+	free(upstream_ver2);
+	return result;
+}
+
+static int test_version(const unsigned version1, const unsigned version2, const unsigned operator)
+{
+	const int version_result = version_compare(version1, version2);
+	switch (operator) {
+	case VER_ANY:
+		return TRUE;
+	case VER_EQUAL:
+		return (version_result == 0);
+	case VER_LESS:
+		return (version_result < 0);
+	case VER_LESS_EQUAL:
+		return (version_result <= 0);
+	case VER_MORE:
+		return (version_result > 0);
+	case VER_MORE_EQUAL:
+		return (version_result >= 0);
+	}
+	return FALSE;
+}
+
+static int search_package_hashtable(const unsigned name, const unsigned version, const unsigned operator)
+{
+	unsigned probe_address;
+	unsigned probe_decrement;
+
+	make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME);
+	while (package_hashtable[probe_address] != NULL) {
+		if (package_hashtable[probe_address]->name == name) {
+			if (operator == VER_ANY) {
+				return probe_address;
+			}
+			if (test_version(package_hashtable[probe_address]->version, version, operator)) {
+				return probe_address;
+			}
+		}
+		probe_address -= probe_decrement;
+		if ((int)probe_address < 0) {
+			probe_address += PACKAGE_HASH_PRIME;
+		}
+	}
+	return probe_address;
+}
+
+/*
+ * This function searches through the entire package_hashtable looking
+ * for a package which provides "needle". It returns the index into
+ * the package_hashtable for the providing package.
+ *
+ * needle is the index into name_hashtable of the package we are
+ * looking for.
+ *
+ * start_at is the index in the package_hashtable to start looking
+ * at. If start_at is -1 then start at the beginning. This is to allow
+ * for repeated searches since more than one package might provide
+ * needle.
+ *
+ * FIXME: I don't think this is very efficient, but I thought I'd keep
+ * it simple for now until it proves to be a problem.
+ */
+static int search_for_provides(int needle, int start_at)
+{
+	int i, j;
+	common_node_t *p;
+	for (i = start_at + 1; i < PACKAGE_HASH_PRIME; i++) {
+		p = package_hashtable[i];
+		if (p == NULL)
+			continue;
+		for (j = 0; j < p->num_of_edges; j++)
+			if (p->edge[j]->type == EDGE_PROVIDES && p->edge[j]->name == needle)
+				return i;
+	}
+	return -1;
+}
+
+/*
+ * Add an edge to a node
+ */
+static void add_edge_to_node(common_node_t *node, edge_t *edge)
+{
+	node->edge = xrealloc_vector(node->edge, 2, node->num_of_edges);
+	node->edge[node->num_of_edges++] = edge;
+}
+
+/*
+ * Create one new node and one new edge for every dependency.
+ *
+ * Dependencies which contain multiple alternatives are represented as
+ * an EDGE_OR_PRE_DEPENDS or EDGE_OR_DEPENDS node, followed by a
+ * number of EDGE_PRE_DEPENDS or EDGE_DEPENDS nodes. The name field of
+ * the OR edge contains the full dependency string while the version
+ * field contains the number of EDGE nodes which follow as part of
+ * this alternative.
+ */
+static void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned edge_type)
+{
+	char *line = xstrdup(whole_line);
+	char *line2;
+	char *line_ptr1 = NULL;
+	char *line_ptr2 = NULL;
+	char *field;
+	char *field2;
+	char *version;
+	edge_t *edge;
+	edge_t *or_edge;
+	int offset_ch;
+
+	field = strtok_r(line, ",", &line_ptr1);
+	do {
+		/* skip leading spaces */
+		field += strspn(field, " ");
+		line2 = xstrdup(field);
+		field2 = strtok_r(line2, "|", &line_ptr2);
+		or_edge = NULL;
+		if ((edge_type == EDGE_DEPENDS || edge_type == EDGE_PRE_DEPENDS)
+		 && (strcmp(field, field2) != 0)
+		) {
+			or_edge = xzalloc(sizeof(edge_t));
+			or_edge->type = edge_type + 1;
+			or_edge->name = search_name_hashtable(field);
+			//or_edge->version = 0; // tracks the number of alternatives
+			add_edge_to_node(parent_node, or_edge);
+		}
+
+		do {
+			edge = xmalloc(sizeof(edge_t));
+			edge->type = edge_type;
+
+			/* Skip any extra leading spaces */
+			field2 += strspn(field2, " ");
+
+			/* Get dependency version info */
+			version = strchr(field2, '(');
+			if (version == NULL) {
+				edge->operator = VER_ANY;
+				/* Get the versions hash number, adding it if the number isnt already in there */
+				edge->version = search_name_hashtable("ANY");
+			} else {
+				/* Skip leading ' ' or '(' */
+				version += strspn(version, " (");
+				/* Calculate length of any operator characters */
+				offset_ch = strspn(version, "<=>");
+				/* Determine operator */
+				if (offset_ch > 0) {
+					if (strncmp(version, "=", offset_ch) == 0) {
+						edge->operator = VER_EQUAL;
+					} else if (strncmp(version, "<<", offset_ch) == 0) {
+						edge->operator = VER_LESS;
+					} else if (strncmp(version, "<=", offset_ch) == 0) {
+						edge->operator = VER_LESS_EQUAL;
+					} else if (strncmp(version, ">>", offset_ch) == 0) {
+						edge->operator = VER_MORE;
+					} else if (strncmp(version, ">=", offset_ch) == 0) {
+						edge->operator = VER_MORE_EQUAL;
+					} else {
+						bb_error_msg_and_die("illegal operator");
+					}
+				}
+				/* skip to start of version numbers */
+				version += offset_ch;
+				version += strspn(version, " ");
+
+				/* Truncate version at trailing ' ' or ')' */
+				version[strcspn(version, " )")] = '\0';
+				/* Get the versions hash number, adding it if the number isnt already in there */
+				edge->version = search_name_hashtable(version);
+			}
+
+			/* Get the dependency name */
+			field2[strcspn(field2, " (")] = '\0';
+			edge->name = search_name_hashtable(field2);
+
+			if (or_edge)
+				or_edge->version++;
+
+			add_edge_to_node(parent_node, edge);
+			field2 = strtok_r(NULL, "|", &line_ptr2);
+		} while (field2 != NULL);
+
+		free(line2);
+		field = strtok_r(NULL, ",", &line_ptr1);
+	} while (field != NULL);
+
+	free(line);
+}
+
+static void free_package(common_node_t *node)
+{
+	unsigned i;
+	if (node) {
+		for (i = 0; i < node->num_of_edges; i++) {
+			free(node->edge[i]);
+		}
+		free(node->edge);
+		free(node);
+	}
+}
+
+/*
+ * Gets the next package field from package_buffer, separated into the field name
+ * and field value, it returns the int offset to the first character of the next field
+ */
+static int read_package_field(const char *package_buffer, char **field_name, char **field_value)
+{
+	int offset_name_start = 0;
+	int offset_name_end = 0;
+	int offset_value_start = 0;
+	int offset_value_end = 0;
+	int offset = 0;
+	int next_offset;
+	int name_length;
+	int value_length;
+	int exit_flag = FALSE;
+
+	if (package_buffer == NULL) {
+		*field_name = NULL;
+		*field_value = NULL;
+		return -1;
+	}
+	while (1) {
+		next_offset = offset + 1;
+		switch (package_buffer[offset]) {
+			case '\0':
+				exit_flag = TRUE;
+				break;
+			case ':':
+				if (offset_name_end == 0) {
+					offset_name_end = offset;
+					offset_value_start = next_offset;
+				}
+				/* TODO: Name might still have trailing spaces if ':' isnt
+				 * immediately after name */
+				break;
+			case '\n':
+				/* TODO: The char next_offset may be out of bounds */
+				if (package_buffer[next_offset] != ' ') {
+					exit_flag = TRUE;
+					break;
+				}
+			case '\t':
+			case ' ':
+				/* increment the value start point if its a just filler */
+				if (offset_name_start == offset) {
+					offset_name_start++;
+				}
+				if (offset_value_start == offset) {
+					offset_value_start++;
+				}
+				break;
+		}
+		if (exit_flag) {
+			/* Check that the names are valid */
+			offset_value_end = offset;
+			name_length = offset_name_end - offset_name_start;
+			value_length = offset_value_end - offset_value_start;
+			if (name_length == 0) {
+				break;
+			}
+			if ((name_length > 0) && (value_length > 0)) {
+				break;
+			}
+
+			/* If not valid, start fresh with next field */
+			exit_flag = FALSE;
+			offset_name_start = offset + 1;
+			offset_name_end = 0;
+			offset_value_start = offset + 1;
+			offset_value_end = offset + 1;
+			offset++;
+		}
+		offset++;
+	}
+	*field_name = NULL;
+	if (name_length) {
+		*field_name = xstrndup(&package_buffer[offset_name_start], name_length);
+	}
+	*field_value = NULL;
+	if (value_length > 0) {
+		*field_value = xstrndup(&package_buffer[offset_value_start], value_length);
+	}
+	return next_offset;
+}
+
+static unsigned fill_package_struct(char *control_buffer)
+{
+	static const char field_names[] ALIGN1 =
+		"Package\0""Version\0"
+		"Pre-Depends\0""Depends\0""Replaces\0""Provides\0"
+		"Conflicts\0""Suggests\0""Recommends\0""Enhances\0";
+
+	common_node_t *new_node = xzalloc(sizeof(common_node_t));
+	char *field_name;
+	char *field_value;
+	int field_start = 0;
+	int num = -1;
+	int buffer_length = strlen(control_buffer);
+
+	new_node->version = search_name_hashtable("unknown");
+	while (field_start < buffer_length) {
+		unsigned field_num;
+
+		field_start += read_package_field(&control_buffer[field_start],
+				&field_name, &field_value);
+
+		if (field_name == NULL) {
+			goto fill_package_struct_cleanup;
+		}
+
+		field_num = index_in_strings(field_names, field_name);
+		switch (field_num) {
+		case 0: /* Package */
+			new_node->name = search_name_hashtable(field_value);
+			break;
+		case 1: /* Version */
+			new_node->version = search_name_hashtable(field_value);
+			break;
+		case 2: /* Pre-Depends */
+			add_split_dependencies(new_node, field_value, EDGE_PRE_DEPENDS);
+			break;
+		case 3: /* Depends */
+			add_split_dependencies(new_node, field_value, EDGE_DEPENDS);
+			break;
+		case 4: /* Replaces */
+			add_split_dependencies(new_node, field_value, EDGE_REPLACES);
+			break;
+		case 5: /* Provides */
+			add_split_dependencies(new_node, field_value, EDGE_PROVIDES);
+			break;
+		case 6: /* Conflicts */
+			add_split_dependencies(new_node, field_value, EDGE_CONFLICTS);
+			break;
+		case 7: /* Suggests */
+			add_split_dependencies(new_node, field_value, EDGE_SUGGESTS);
+			break;
+		case 8: /* Recommends */
+			add_split_dependencies(new_node, field_value, EDGE_RECOMMENDS);
+			break;
+		case 9: /* Enhances */
+			add_split_dependencies(new_node, field_value, EDGE_ENHANCES);
+			break;
+		}
+ fill_package_struct_cleanup:
+		free(field_name);
+		free(field_value);
+	}
+
+	if (new_node->version == search_name_hashtable("unknown")) {
+		free_package(new_node);
+		return -1;
+	}
+	num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL);
+	free_package(package_hashtable[num]);
+	package_hashtable[num] = new_node;
+	return num;
+}
+
+/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */
+static unsigned get_status(const unsigned status_node, const int num)
+{
+	char *status_string = name_hashtable[status_hashtable[status_node]->status];
+	char *state_sub_string;
+	unsigned state_sub_num;
+	int len;
+	int i;
+
+	/* set tmp_string to point to the start of the word number */
+	for (i = 1; i < num; i++) {
+		/* skip past a word */
+		status_string += strcspn(status_string, " ");
+		/* skip past the separating spaces */
+		status_string += strspn(status_string, " ");
+	}
+	len = strcspn(status_string, " \n");
+	state_sub_string = xstrndup(status_string, len);
+	state_sub_num = search_name_hashtable(state_sub_string);
+	free(state_sub_string);
+	return state_sub_num;
+}
+
+static void set_status(const unsigned status_node_num, const char *new_value, const int position)
+{
+	const unsigned new_value_num = search_name_hashtable(new_value);
+	unsigned want = get_status(status_node_num, 1);
+	unsigned flag = get_status(status_node_num, 2);
+	unsigned status = get_status(status_node_num, 3);
+	char *new_status;
+
+	switch (position) {
+		case 1:
+			want = new_value_num;
+			break;
+		case 2:
+			flag = new_value_num;
+			break;
+		case 3:
+			status = new_value_num;
+			break;
+		default:
+			bb_error_msg_and_die("DEBUG ONLY: this shouldnt happen");
+	}
+
+	new_status = xasprintf("%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]);
+	status_hashtable[status_node_num]->status = search_name_hashtable(new_status);
+	free(new_status);
+}
+
+static const char *describe_status(int status_num)
+{
+	int status_want, status_state;
+	if (status_hashtable[status_num] == NULL || status_hashtable[status_num]->status == 0)
+		return "is not installed or flagged to be installed";
+
+	status_want = get_status(status_num, 1);
+	status_state = get_status(status_num, 3);
+
+	if (status_state == search_name_hashtable("installed")) {
+		if (status_want == search_name_hashtable("install"))
+			return "is installed";
+		if (status_want == search_name_hashtable("deinstall"))
+			return "is marked to be removed";
+		if (status_want == search_name_hashtable("purge"))
+			return "is marked to be purged";
+	}
+	if (status_want == search_name_hashtable("unknown"))
+		return "is in an indeterminate state";
+	if (status_want == search_name_hashtable("install"))
+		return "is marked to be installed";
+
+	return "is not installed or flagged to be installed";
+}
+
+static void index_status_file(const char *filename)
+{
+	FILE *status_file;
+	char *control_buffer;
+	char *status_line;
+	status_node_t *status_node = NULL;
+	unsigned status_num;
+
+	status_file = xfopen_for_read(filename);
+	while ((control_buffer = xmalloc_fgetline_str(status_file, "\n\n")) != NULL) {
+		const unsigned package_num = fill_package_struct(control_buffer);
+		if (package_num != -1) {
+			status_node = xmalloc(sizeof(status_node_t));
+			/* fill_package_struct doesnt handle the status field */
+			status_line = strstr(control_buffer, "Status:");
+			if (status_line != NULL) {
+				status_line += 7;
+				status_line += strspn(status_line, " \n\t");
+				status_line = xstrndup(status_line, strcspn(status_line, "\n"));
+				status_node->status = search_name_hashtable(status_line);
+				free(status_line);
+			}
+			status_node->package = package_num;
+			status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]);
+			status_hashtable[status_num] = status_node;
+		}
+		free(control_buffer);
+	}
+	fclose(status_file);
+}
+
+static void write_buffer_no_status(FILE *new_status_file, const char *control_buffer)
+{
+	char *name;
+	char *value;
+	int start = 0;
+	while (1) {
+		start += read_package_field(&control_buffer[start], &name, &value);
+		if (name == NULL) {
+			break;
+		}
+		if (strcmp(name, "Status") != 0) {
+			fprintf(new_status_file, "%s: %s\n", name, value);
+		}
+	}
+}
+
+/* This could do with a cleanup */
+static void write_status_file(deb_file_t **deb_file)
+{
+	FILE *old_status_file = xfopen_for_read("/var/lib/dpkg/status");
+	FILE *new_status_file = xfopen_for_write("/var/lib/dpkg/status.udeb");
+	char *package_name;
+	char *status_from_file;
+	char *control_buffer = NULL;
+	char *tmp_string;
+	int status_num;
+	int field_start = 0;
+	int write_flag;
+	int i = 0;
+
+	/* Update previously known packages */
+	while ((control_buffer = xmalloc_fgetline_str(old_status_file, "\n\n")) != NULL) {
+		tmp_string = strstr(control_buffer, "Package:");
+		if (tmp_string == NULL) {
+			continue;
+		}
+
+		tmp_string += 8;
+		tmp_string += strspn(tmp_string, " \n\t");
+		package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n"));
+		write_flag = FALSE;
+		tmp_string = strstr(control_buffer, "Status:");
+		if (tmp_string != NULL) {
+			/* Separate the status value from the control buffer */
+			tmp_string += 7;
+			tmp_string += strspn(tmp_string, " \n\t");
+			status_from_file = xstrndup(tmp_string, strcspn(tmp_string, "\n"));
+		} else {
+			status_from_file = NULL;
+		}
+
+		/* Find this package in the status hashtable */
+		status_num = search_status_hashtable(package_name);
+		if (status_hashtable[status_num] != NULL) {
+			const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status];
+			if (strcmp(status_from_file, status_from_hashtable) != 0) {
+				/* New status isnt exactly the same as old status */
+				const int state_status = get_status(status_num, 3);
+				if ((strcmp("installed", name_hashtable[state_status]) == 0)
+				 || (strcmp("unpacked", name_hashtable[state_status]) == 0)
+				) {
+					/* We need to add the control file from the package */
+					i = 0;
+					while (deb_file[i] != NULL) {
+						if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) {
+							/* Write a status file entry with a modified status */
+							/* remove trailing \n's */
+							write_buffer_no_status(new_status_file, deb_file[i]->control_file);
+							set_status(status_num, "ok", 2);
+							fprintf(new_status_file, "Status: %s\n\n",
+									name_hashtable[status_hashtable[status_num]->status]);
+							write_flag = TRUE;
+							break;
+						}
+						i++;
+					}
+					/* This is temperary, debugging only */
+					if (deb_file[i] == NULL) {
+						bb_error_msg_and_die("ALERT: cannot find a control file, "
+							"your status file may be broken, status may be "
+							"incorrect for %s", package_name);
+					}
+				}
+				else if (strcmp("not-installed", name_hashtable[state_status]) == 0) {
+					/* Only write the Package, Status, Priority and Section lines */
+					fprintf(new_status_file, "Package: %s\n", package_name);
+					fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
+
+					while (1) {
+						char *field_name;
+						char *field_value;
+						field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
+						if (field_name == NULL) {
+							break;
+						}
+						if ((strcmp(field_name, "Priority") == 0)
+						 || (strcmp(field_name, "Section") == 0)
+						) {
+							fprintf(new_status_file, "%s: %s\n", field_name, field_value);
+						}
+					}
+					write_flag = TRUE;
+					fputs("\n", new_status_file);
+				}
+				else if (strcmp("config-files", name_hashtable[state_status]) == 0) {
+					/* only change the status line */
+					while (1) {
+						char *field_name;
+						char *field_value;
+						field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
+						if (field_name == NULL) {
+							break;
+						}
+						/* Setup start point for next field */
+						if (strcmp(field_name, "Status") == 0) {
+							fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
+						} else {
+							fprintf(new_status_file, "%s: %s\n", field_name, field_value);
+						}
+					}
+					write_flag = TRUE;
+					fputs("\n", new_status_file);
+				}
+			}
+		}
+		/* If the package from the status file wasnt handle above, do it now*/
+		if (!write_flag) {
+			fprintf(new_status_file, "%s\n\n", control_buffer);
+		}
+
+		free(status_from_file);
+		free(package_name);
+		free(control_buffer);
+	}
+
+	/* Write any new packages */
+	for (i = 0; deb_file[i] != NULL; i++) {
+		status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]);
+		if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) {
+			write_buffer_no_status(new_status_file, deb_file[i]->control_file);
+			set_status(status_num, "ok", 2);
+			fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]);
+		}
+	}
+	fclose(old_status_file);
+	fclose(new_status_file);
+
+	/* Create a separate backfile to dpkg */
+	if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) {
+		if (errno != ENOENT)
+			bb_error_msg_and_die("can't create backup status file");
+		/* Its ok if renaming the status file fails because status
+		 * file doesnt exist, maybe we are starting from scratch */
+		bb_error_msg("no status file found, creating new one");
+	}
+
+	xrename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status");
+}
+
+/* This function returns TRUE if the given package can satisfy a
+ * dependency of type depend_type.
+ *
+ * A pre-depends is satisfied only if a package is already installed,
+ * which a regular depends can be satisfied by a package which we want
+ * to install.
+ */
+static int package_satisfies_dependency(int package, int depend_type)
+{
+	int status_num = search_status_hashtable(name_hashtable[package_hashtable[package]->name]);
+
+	/* status could be unknown if package is a pure virtual
+	 * provides which cannot satisfy any dependency by itself.
+	 */
+	if (status_hashtable[status_num] == NULL)
+		return 0;
+
+	switch (depend_type) {
+	case EDGE_PRE_DEPENDS: return get_status(status_num, 3) == search_name_hashtable("installed");
+	case EDGE_DEPENDS:     return get_status(status_num, 1) == search_name_hashtable("install");
+	}
+	return 0;
+}
+
+static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count - ?? */)
+{
+	int *conflicts = NULL;
+	int conflicts_num = 0;
+	int i = deb_start;
+	int j;
+
+	/* Check for conflicts
+	 * TODO: TEST if conflicts with other packages to be installed
+	 *
+	 * Add install packages and the packages they provide
+	 * to the list of files to check conflicts for
+	 */
+
+	/* Create array of package numbers to check against
+	 * installed package for conflicts*/
+	while (deb_file[i] != NULL) {
+		const unsigned package_num = deb_file[i]->package;
+		conflicts = xrealloc_vector(conflicts, 2, conflicts_num);
+		conflicts[conflicts_num] = package_num;
+		conflicts_num++;
+		/* add provides to conflicts list */
+		for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
+			if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) {
+				const int conflicts_package_num = search_package_hashtable(
+					package_hashtable[package_num]->edge[j]->name,
+					package_hashtable[package_num]->edge[j]->version,
+					package_hashtable[package_num]->edge[j]->operator);
+				if (package_hashtable[conflicts_package_num] == NULL) {
+					/* create a new package */
+					common_node_t *new_node = xzalloc(sizeof(common_node_t));
+					new_node->name = package_hashtable[package_num]->edge[j]->name;
+					new_node->version = package_hashtable[package_num]->edge[j]->version;
+					package_hashtable[conflicts_package_num] = new_node;
+				}
+				conflicts = xrealloc_vector(conflicts, 2, conflicts_num);
+				conflicts[conflicts_num] = conflicts_package_num;
+				conflicts_num++;
+			}
+		}
+		i++;
+	}
+
+	/* Check conflicts */
+	i = 0;
+	while (deb_file[i] != NULL) {
+		const common_node_t *package_node = package_hashtable[deb_file[i]->package];
+		int status_num = 0;
+		status_num = search_status_hashtable(name_hashtable[package_node->name]);
+
+		if (get_status(status_num, 3) == search_name_hashtable("installed")) {
+			i++;
+			continue;
+		}
+
+		for (j = 0; j < package_node->num_of_edges; j++) {
+			const edge_t *package_edge = package_node->edge[j];
+
+			if (package_edge->type == EDGE_CONFLICTS) {
+				const unsigned package_num =
+					search_package_hashtable(package_edge->name,
+								package_edge->version,
+								package_edge->operator);
+				int result = 0;
+				if (package_hashtable[package_num] != NULL) {
+					status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]);
+
+					if (get_status(status_num, 1) == search_name_hashtable("install")) {
+						result = test_version(package_hashtable[deb_file[i]->package]->version,
+							package_edge->version, package_edge->operator);
+					}
+				}
+
+				if (result) {
+					bb_error_msg_and_die("package %s conflicts with %s",
+						name_hashtable[package_node->name],
+						name_hashtable[package_edge->name]);
+				}
+			}
+		}
+		i++;
+	}
+
+
+	/* Check dependendcies */
+	for (i = 0; i < PACKAGE_HASH_PRIME; i++) {
+		int status_num = 0;
+		int number_of_alternatives = 0;
+		const edge_t * root_of_alternatives = NULL;
+		const common_node_t *package_node = package_hashtable[i];
+
+		/* If the package node does not exist then this
+		 * package is a virtual one. In which case there are
+		 * no dependencies to check.
+		 */
+		if (package_node == NULL) continue;
+
+		status_num = search_status_hashtable(name_hashtable[package_node->name]);
+
+		/* If there is no status then this package is a
+		 * virtual one provided by something else. In which
+		 * case there are no dependencies to check.
+		 */
+		if (status_hashtable[status_num] == NULL) continue;
+
+		/* If we don't want this package installed then we may
+		 * as well ignore it's dependencies.
+		 */
+		if (get_status(status_num, 1) != search_name_hashtable("install")) {
+			continue;
+		}
+
+		/* This code is tested only for EDGE_DEPENDS, since I
+		 * have no suitable pre-depends available. There is no
+		 * reason that it shouldn't work though :-)
+		 */
+		for (j = 0; j < package_node->num_of_edges; j++) {
+			const edge_t *package_edge = package_node->edge[j];
+			unsigned package_num;
+
+			if (package_edge->type == EDGE_OR_PRE_DEPENDS
+			 || package_edge->type == EDGE_OR_DEPENDS
+			) {
+				/* start an EDGE_OR_ list */
+				number_of_alternatives = package_edge->version;
+				root_of_alternatives = package_edge;
+				continue;
+			}
+			if (number_of_alternatives == 0) {  /* not in the middle of an EDGE_OR_ list */
+				number_of_alternatives = 1;
+				root_of_alternatives = NULL;
+			}
+
+			package_num = search_package_hashtable(package_edge->name, package_edge->version, package_edge->operator);
+
+			if (package_edge->type == EDGE_PRE_DEPENDS
+			 || package_edge->type == EDGE_DEPENDS
+			) {
+				int result=1;
+				status_num = 0;
+
+				/* If we are inside an alternative then check
+				 * this edge is the right type.
+				 *
+				 * EDGE_DEPENDS == OR_DEPENDS -1
+				 * EDGE_PRE_DEPENDS == OR_PRE_DEPENDS -1
+				 */
+				if (root_of_alternatives && package_edge->type != root_of_alternatives->type - 1)
+					bb_error_msg_and_die("fatal error, package dependencies corrupt: %d != %d - 1",
+							package_edge->type, root_of_alternatives->type);
+
+				if (package_hashtable[package_num] != NULL)
+					result = !package_satisfies_dependency(package_num, package_edge->type);
+
+				if (result) { /* check for other package which provide what we are looking for */
+					int provider = -1;
+
+					while ((provider = search_for_provides(package_edge->name, provider)) > -1) {
+						if (package_hashtable[provider] == NULL) {
+							puts("Have a provider but no package information for it");
+							continue;
+						}
+						result = !package_satisfies_dependency(provider, package_edge->type);
+
+						if (result == 0)
+							break;
+					}
+				}
+
+				/* It must be already installed, or to be installed */
+				number_of_alternatives--;
+				if (result && number_of_alternatives == 0) {
+					if (root_of_alternatives)
+						bb_error_msg_and_die(
+							"package %s %sdepends on %s, "
+							"which cannot be satisfied",
+							name_hashtable[package_node->name],
+							package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "",
+							name_hashtable[root_of_alternatives->name]);
+					bb_error_msg_and_die(
+						"package %s %sdepends on %s, which %s\n",
+						name_hashtable[package_node->name],
+						package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "",
+						name_hashtable[package_edge->name],
+						describe_status(status_num));
+				}
+				if (result == 0 && number_of_alternatives) {
+					/* we've found a package which
+					 * satisfies the dependency,
+					 * so skip over the rest of
+					 * the alternatives.
+					 */
+					j += number_of_alternatives;
+					number_of_alternatives = 0;
+				}
+			}
+		}
+	}
+	free(conflicts);
+	return TRUE;
+}
+
+static char **create_list(const char *filename)
+{
+	FILE *list_stream;
+	char **file_list;
+	char *line;
+	int count;
+
+	/* don't use [xw]fopen here, handle error ourself */
+	list_stream = fopen_for_read(filename);
+	if (list_stream == NULL) {
+		return NULL;
+	}
+
+	file_list = NULL;
+	count = 0;
+	while ((line = xmalloc_fgetline(list_stream)) != NULL) {
+		file_list = xrealloc_vector(file_list, 2, count);
+		file_list[count++] = line;
+		/*file_list[count] = NULL; - xrealloc_vector did it */
+	}
+	fclose(list_stream);
+
+	return file_list;
+}
+
+/* maybe i should try and hook this into remove_file.c somehow */
+static int remove_file_array(char **remove_names, char **exclude_names)
+{
+	struct stat path_stat;
+	int remove_flag = 1; /* not removed anything yet */
+	int i, j;
+
+	if (remove_names == NULL) {
+		return 0;
+	}
+	for (i = 0; remove_names[i] != NULL; i++) {
+		if (exclude_names != NULL) {
+			for (j = 0; exclude_names[j] != NULL; j++) {
+				if (strcmp(remove_names[i], exclude_names[j]) == 0) {
+					goto skip;
+				}
+			}
+		}
+		/* TODO: why we are checking lstat? we can just try rm/rmdir */
+		if (lstat(remove_names[i], &path_stat) < 0) {
+			continue;
+		}
+		if (S_ISDIR(path_stat.st_mode)) {
+			remove_flag &= rmdir(remove_names[i]); /* 0 if no error */
+		} else {
+			remove_flag &= unlink(remove_names[i]); /* 0 if no error */
+		}
+ skip:
+		continue;
+	}
+	return (remove_flag == 0);
+}
+
+static void run_package_script_or_die(const char *package_name, const char *script_type)
+{
+	char *script_path;
+	int result;
+
+	script_path = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, script_type);
+
+	/* If the file doesnt exist is isnt fatal */
+	result = access(script_path, F_OK) ? EXIT_SUCCESS : system(script_path);
+	free(script_path);
+	if (result)
+		bb_error_msg_and_die("%s failed, exit code %d", script_type, result);
+}
+
+/*
+The policy manual defines what scripts get called when and with
+what arguments. I realize that busybox does not support all of
+these scenarios, but it does support some of them; it does not,
+however, run them with any parameters in run_package_script_or_die().
+Here are the scripts:
+
+preinst install
+preinst install <old_version>
+preinst upgrade <old_version>
+preinst abort_upgrade <new_version>
+postinst configure <most_recent_version>
+postinst abort-upgade <new_version>
+postinst abort-remove
+postinst abort-remove in-favour <package> <version>
+postinst abort-deconfigure in-favor <failed_install_package> removing <conflicting_package> <version>
+prerm remove
+prerm upgrade <new_version>
+prerm failed-upgrade <old_version>
+prerm remove in-favor <package> <new_version>
+prerm deconfigure in-favour <package> <version> removing <package> <version>
+postrm remove
+postrm purge
+postrm upgrade <new_version>
+postrm failed-upgrade <old_version>
+postrm abort-install
+postrm abort-install <old_version>
+postrm abort-upgrade <old_version>
+postrm disappear <overwriter> <version>
+*/
+static const char *const all_control_files[] = {
+	"preinst", "postinst", "prerm", "postrm",
+	"list", "md5sums", "shlibs", "conffiles",
+	"config", "templates"
+};
+
+static char **all_control_list(const char *package_name)
+{
+	unsigned i = 0;
+	char **remove_files;
+
+	/* Create a list of all /var/lib/dpkg/info/<package> files */
+	remove_files = xzalloc(sizeof(all_control_files) + sizeof(char*));
+	while (i < ARRAY_SIZE(all_control_files)) {
+		remove_files[i] = xasprintf("/var/lib/dpkg/info/%s.%s",
+				package_name, all_control_files[i]);
+		i++;
+	}
+
+	return remove_files;
+}
+
+static void free_array(char **array)
+{
+	if (array) {
+		unsigned i = 0;
+		while (array[i]) {
+			free(array[i]);
+			i++;
+		}
+		free(array);
+	}
+}
+
+/* This function lists information on the installed packages. It loops through
+ * the status_hashtable to retrieve the info. This results in smaller code than
+ * scanning the status file. The resulting list, however, is unsorted.
+ */
+static void list_packages(const char *pattern)
+{
+	int i;
+
+	puts("    Name           Version");
+	puts("+++-==============-==============");
+
+	/* go through status hash, dereference package hash and finally strings */
+	for (i = 0; i < STATUS_HASH_PRIME+1; i++) {
+		if (status_hashtable[i]) {
+			const char *stat_str;  /* status string */
+			const char *name_str;  /* package name */
+			const char *vers_str;  /* version */
+			char  s1, s2;          /* status abbreviations */
+			int   spccnt;          /* space count */
+			int   j;
+
+			stat_str = name_hashtable[status_hashtable[i]->status];
+			name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name];
+			vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version];
+
+			if (pattern && fnmatch(pattern, name_str, 0) != 0)
+				continue;
+
+			/* get abbreviation for status field 1 */
+			s1 = stat_str[0] == 'i' ? 'i' : 'r';
+
+			/* get abbreviation for status field 2 */
+			for (j = 0, spccnt = 0; stat_str[j] && spccnt < 2; j++) {
+				if (stat_str[j] == ' ') spccnt++;
+			}
+			s2 = stat_str[j];
+
+			/* print out the line formatted like Debian dpkg */
+			printf("%c%c  %-14s %s\n", s1, s2, name_str, vers_str);
+		}
+	}
+}
+
+static void remove_package(const unsigned package_num, int noisy)
+{
+	const char *package_name = name_hashtable[package_hashtable[package_num]->name];
+	const char *package_version = name_hashtable[package_hashtable[package_num]->version];
+	const unsigned status_num = search_status_hashtable(package_name);
+	const int package_name_length = strlen(package_name);
+	char **remove_files;
+	char **exclude_files;
+	char list_name[package_name_length + 25];
+	char conffile_name[package_name_length + 30];
+
+	if (noisy)
+		printf("Removing %s (%s)...\n", package_name, package_version);
+
+	/* Run prerm script */
+	run_package_script_or_die(package_name, "prerm");
+
+	/* Create a list of files to remove, and a separate list of those to keep */
+	sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list");
+	remove_files = create_list(list_name);
+
+	sprintf(conffile_name, "/var/lib/dpkg/info/%s.%s", package_name, "conffiles");
+	exclude_files = create_list(conffile_name);
+
+	/* Some directories can't be removed straight away, so do multiple passes */
+	while (remove_file_array(remove_files, exclude_files))
+		continue;
+	free_array(exclude_files);
+	free_array(remove_files);
+
+	/* Create a list of files in /var/lib/dpkg/info/<package>.* to keep */
+	exclude_files = xzalloc(sizeof(exclude_files[0]) * 3);
+	exclude_files[0] = xstrdup(conffile_name);
+	exclude_files[1] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm");
+
+	/* Create a list of all /var/lib/dpkg/info/<package> files */
+	remove_files = all_control_list(package_name);
+
+	remove_file_array(remove_files, exclude_files);
+	free_array(remove_files);
+	free_array(exclude_files);
+
+	/* rename <package>.conffiles to <package>.list
+	 * The conffiles control file isn't required in Debian packages, so don't
+	 * error out if it's missing.  */
+	rename(conffile_name, list_name);
+
+	/* Change package status */
+	set_status(status_num, "config-files", 3);
+}
+
+static void purge_package(const unsigned package_num)
+{
+	const char *package_name = name_hashtable[package_hashtable[package_num]->name];
+	const char *package_version = name_hashtable[package_hashtable[package_num]->version];
+	const unsigned status_num = search_status_hashtable(package_name);
+	char **remove_files;
+	char **exclude_files;
+	char list_name[strlen(package_name) + 25];
+
+	printf("Purging %s (%s)...\n", package_name, package_version);
+
+	/* Run prerm script */
+	run_package_script_or_die(package_name, "prerm");
+
+	/* Create a list of files to remove */
+	sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list");
+	remove_files = create_list(list_name);
+
+	/* Some directories cant be removed straight away, so do multiple passes */
+	while (remove_file_array(remove_files, NULL))
+		continue;
+	free_array(remove_files);
+
+	/* Create a list of all /var/lib/dpkg/info/<package> files */
+	remove_files = all_control_list(package_name);
+
+	/* Delete all of them except the postrm script */
+	exclude_files = xzalloc(sizeof(exclude_files[0]) * 2);
+	exclude_files[0] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm");
+	remove_file_array(remove_files, exclude_files);
+	free_array(exclude_files);
+
+	/* Run and remove postrm script */
+	run_package_script_or_die(package_name, "postrm");
+	remove_file_array(remove_files, NULL);
+
+	free_array(remove_files);
+
+	/* Change package status */
+	set_status(status_num, "not-installed", 3);
+}
+
+static archive_handle_t *init_archive_deb_ar(const char *filename)
+{
+	archive_handle_t *ar_handle;
+
+	/* Setup an ar archive handle that refers to the gzip sub archive */
+	ar_handle = init_handle();
+	ar_handle->filter = filter_accept_list_reassign;
+	ar_handle->src_fd = xopen(filename, O_RDONLY);
+
+	return ar_handle;
+}
+
+static void init_archive_deb_control(archive_handle_t *ar_handle)
+{
+	archive_handle_t *tar_handle;
+
+	/* Setup the tar archive handle */
+	tar_handle = init_handle();
+	tar_handle->src_fd = ar_handle->src_fd;
+
+	/* We don't care about data.tar.* or debian-binary, just control.tar.* */
+#if ENABLE_FEATURE_SEAMLESS_GZ
+	llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz");
+#endif
+#if ENABLE_FEATURE_SEAMLESS_BZ2
+	llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2");
+#endif
+
+	/* Assign the tar handle as a subarchive of the ar handle */
+	ar_handle->dpkg__sub_archive = tar_handle;
+}
+
+static void init_archive_deb_data(archive_handle_t *ar_handle)
+{
+	archive_handle_t *tar_handle;
+
+	/* Setup the tar archive handle */
+	tar_handle = init_handle();
+	tar_handle->src_fd = ar_handle->src_fd;
+
+	/* We don't care about control.tar.* or debian-binary, just data.tar.* */
+#if ENABLE_FEATURE_SEAMLESS_GZ
+	llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz");
+#endif
+#if ENABLE_FEATURE_SEAMLESS_BZ2
+	llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2");
+#endif
+
+	/* Assign the tar handle as a subarchive of the ar handle */
+	ar_handle->dpkg__sub_archive = tar_handle;
+}
+
+static void FAST_FUNC data_extract_to_buffer(archive_handle_t *archive_handle)
+{
+	unsigned size = archive_handle->file_header->size;
+
+	archive_handle->dpkg__buffer = xzalloc(size + 1);
+	xread(archive_handle->src_fd, archive_handle->dpkg__buffer, size);
+}
+
+static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept)
+{
+	ar_handle->dpkg__sub_archive->action_data = data_extract_to_buffer;
+	ar_handle->dpkg__sub_archive->accept = myaccept;
+	ar_handle->dpkg__sub_archive->filter = filter_accept_list;
+
+	unpack_ar_archive(ar_handle);
+	close(ar_handle->src_fd);
+
+	return ar_handle->dpkg__sub_archive->dpkg__buffer;
+}
+
+static void append_control_file_to_llist(const char *package_name, const char *control_name, llist_t **ll)
+{
+	FILE *fp;
+	char *filename, *line;
+
+	filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, control_name);
+	fp = fopen_for_read(filename);
+	free(filename);
+	if (fp != NULL) {
+		while ((line = xmalloc_fgetline(fp)) != NULL)
+			llist_add_to(ll, line);
+		fclose(fp);
+	}
+}
+
+static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle)
+{
+	int fd;
+	char *name_ptr = archive_handle->file_header->name + 1;
+
+	/* Is this file marked as config file? */
+	if (!find_list_entry(archive_handle->accept, name_ptr))
+		return EXIT_SUCCESS; /* no */
+
+	fd = open(name_ptr, O_RDONLY);
+	if (fd >= 0) {
+		md5_ctx_t md5;
+		char *md5line, *buf;
+		int count;
+
+		/* Calculate MD5 of existing file */
+		buf = xmalloc(4096);
+		md5_begin(&md5);
+		while ((count = safe_read(fd, buf, 4096)) > 0)
+			md5_hash(&md5, buf, count);
+		md5_end(&md5, buf); /* using buf as result storage */
+		close(fd);
+
+		md5line = xmalloc(16 * 2 + 2 + strlen(name_ptr) + 1);
+		sprintf(bin2hex(md5line, buf, 16), "  %s", name_ptr);
+		free(buf);
+
+		/* Is it changed after install? */
+		if (find_list_entry(archive_handle->accept, md5line) == NULL) {
+			printf("Warning: Creating %s as %s.dpkg-new\n", name_ptr, name_ptr);
+			archive_handle->file_header->name = xasprintf("%s.dpkg-new", archive_handle->file_header->name);
+		}
+		free(md5line);
+	}
+	return EXIT_SUCCESS;
+}
+
+static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle)
+{
+	char *name_ptr = archive_handle->file_header->name;
+
+	/* Skip all leading "/" */
+	while (*name_ptr == '/')
+		name_ptr++;
+	/* Skip all leading "./" and "../" */
+	while (name_ptr[0] == '.') {
+		if (name_ptr[1] == '.')
+			name_ptr++;
+		if (name_ptr[1] != '/')
+			break;
+		name_ptr += 2;
+	}
+
+	if (name_ptr[0] != '\0') {
+		archive_handle->file_header->name = xasprintf("%s%s", archive_handle->dpkg__buffer, name_ptr);
+		data_extract_all(archive_handle);
+		if (fnmatch("*.dpkg-new", archive_handle->file_header->name, 0) == 0) {
+			/* remove .dpkg-new suffix */
+			archive_handle->file_header->name[strlen(archive_handle->file_header->name) - 9] = '\0';
+		}
+	}
+}
+
+enum {
+	/* Commands */
+	OPT_configure            = (1 << 0),
+	OPT_install              = (1 << 1),
+	OPT_list_installed       = (1 << 2),
+	OPT_purge                = (1 << 3),
+	OPT_remove               = (1 << 4),
+	OPT_unpack               = (1 << 5),
+	OPTMASK_cmd              = (1 << 6) - 1,
+	/* Options */
+	OPT_force                = (1 << 6),
+	OPT_force_ignore_depends = (1 << 7),
+	OPT_force_confnew        = (1 << 8),
+	OPT_force_confold        = (1 << 9),
+};
+
+static void unpack_package(deb_file_t *deb_file)
+{
+	const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
+	const unsigned status_num = search_status_hashtable(package_name);
+	const unsigned status_package_num = status_hashtable[status_num]->package;
+	char *info_prefix;
+	char *list_filename;
+	archive_handle_t *archive_handle;
+	FILE *out_stream;
+	llist_t *accept_list;
+	llist_t *conffile_list;
+	int i;
+
+	/* If existing version, remove it first */
+	conffile_list = NULL;
+	if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) {
+		/* Package is already installed, remove old version first */
+		printf("Preparing to replace %s %s (using %s)...\n", package_name,
+			name_hashtable[package_hashtable[status_package_num]->version],
+			deb_file->filename);
+
+		/* Read md5sums from old package */
+		if (!(option_mask32 & OPT_force_confold))
+			append_control_file_to_llist(package_name, "md5sums", &conffile_list);
+
+		remove_package(status_package_num, 0);
+	} else {
+		printf("Unpacking %s (from %s)...\n", package_name, deb_file->filename);
+	}
+
+	/* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */
+	info_prefix = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "");
+	archive_handle = init_archive_deb_ar(deb_file->filename);
+	init_archive_deb_control(archive_handle);
+
+	accept_list = NULL;
+	i = 0;
+	while (i < ARRAY_SIZE(all_control_files)) {
+		char *c = xasprintf("./%s", all_control_files[i]);
+		llist_add_to(&accept_list, c);
+		i++;
+	}
+	archive_handle->dpkg__sub_archive->accept = accept_list;
+	archive_handle->dpkg__sub_archive->filter = filter_accept_list;
+	archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix;
+	archive_handle->dpkg__sub_archive->dpkg__buffer = info_prefix;
+	archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD;
+	unpack_ar_archive(archive_handle);
+
+	/* Run the preinst prior to extracting */
+	run_package_script_or_die(package_name, "preinst");
+
+	/* Don't overwrite existing config files */
+	if (!(option_mask32 & OPT_force_confnew))
+		append_control_file_to_llist(package_name, "conffiles", &conffile_list);
+
+	/* Extract data.tar.gz to the root directory */
+	archive_handle = init_archive_deb_ar(deb_file->filename);
+	init_archive_deb_data(archive_handle);
+	archive_handle->dpkg__sub_archive->accept = conffile_list;
+	/* Why ARCHIVE_REMEMBER_NAMES?
+	 * We want names collected in ->passed list even if conffile_list
+	 * is NULL (otherwise get_header_tar may optimize name saving out):
+	 */
+	archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_REMEMBER_NAMES | ARCHIVE_UNLINK_OLD;
+	archive_handle->dpkg__sub_archive->filter = filter_rename_config;
+	archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix;
+	archive_handle->dpkg__sub_archive->dpkg__buffer = (char*)"/"; /* huh? */
+	unpack_ar_archive(archive_handle);
+
+	/* Create the list file */
+	list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list");
+	out_stream = xfopen_for_write(list_filename);
+	archive_handle->dpkg__sub_archive->passed = llist_rev(archive_handle->dpkg__sub_archive->passed);
+	while (archive_handle->dpkg__sub_archive->passed) {
+		char *filename = llist_pop(&archive_handle->dpkg__sub_archive->passed);
+		/* the leading . has been stripped by data_extract_all_prefix already */
+		fprintf(out_stream, "%s\n", filename);
+		free(filename);
+	}
+	fclose(out_stream);
+
+	/* change status */
+	set_status(status_num, "install", 1);
+	set_status(status_num, "unpacked", 3);
+
+	free(info_prefix);
+	free(list_filename);
+}
+
+static void configure_package(deb_file_t *deb_file)
+{
+	const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
+	const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version];
+	const int status_num = search_status_hashtable(package_name);
+
+	printf("Setting up %s (%s)...\n", package_name, package_version);
+
+	/* Run the postinst script */
+	/* TODO: handle failure gracefully */
+	run_package_script_or_die(package_name, "postinst");
+
+	/* Change status to reflect success */
+	set_status(status_num, "install", 1);
+	set_status(status_num, "installed", 3);
+}
+
+int dpkg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dpkg_main(int argc UNUSED_PARAM, char **argv)
+{
+	deb_file_t **deb_file = NULL;
+	status_node_t *status_node;
+	char *str_f;
+	int opt;
+	int package_num;
+	int deb_count = 0;
+	int state_status;
+	int status_num;
+	int i;
+#if ENABLE_LONG_OPTS
+	static const char dpkg_longopts[] ALIGN1 =
+// FIXME: we use -C non-compatibly, should be:
+// "-C|--audit Check for broken package(s)"
+		"configure\0"      No_argument        "C"
+		"force\0"          Required_argument  "F"
+		"install\0"        No_argument        "i"
+		"list\0"           No_argument        "l"
+		"purge\0"          No_argument        "P"
+		"remove\0"         No_argument        "r"
+		"unpack\0"         No_argument        "u"
+		"force-depends\0"  No_argument        "\xff"
+		"force-confnew\0"  No_argument        "\xfe"
+		"force-confold\0"  No_argument        "\xfd"
+		;
+#endif
+
+	INIT_G();
+
+	IF_LONG_OPTS(applet_long_options = dpkg_longopts);
+	opt = getopt32(argv, "CilPruF:", &str_f);
+	argv += optind;
+	//if (opt & OPT_configure) ... // -C
+	if (opt & OPT_force) { // -F (--force in official dpkg)
+		if (strcmp(str_f, "depends") == 0)
+			opt |= OPT_force_ignore_depends;
+		else if (strcmp(str_f, "confnew") == 0)
+			opt |= OPT_force_confnew;
+		else if (strcmp(str_f, "confold") == 0)
+			opt |= OPT_force_confold;
+		else
+			bb_show_usage();
+		option_mask32 = opt;
+	}
+	//if (opt & OPT_install) ... // -i
+	//if (opt & OPT_list_installed) ... // -l
+	//if (opt & OPT_purge) ... // -P
+	//if (opt & OPT_remove) ... // -r
+	//if (opt & OPT_unpack) ... // -u (--unpack in official dpkg)
+	if (!(opt & OPTMASK_cmd) /* no cmd */
+	 || ((opt & OPTMASK_cmd) & ((opt & OPTMASK_cmd)-1)) /* more than one cmd */
+	) {
+		bb_show_usage();
+	}
+
+/*	puts("(Reading database ... xxxxx files and directories installed.)"); */
+	index_status_file("/var/lib/dpkg/status");
+
+	/* if the list action was given print the installed packages and exit */
+	if (opt & OPT_list_installed) {
+		list_packages(argv[0]); /* param can be NULL */
+		return EXIT_SUCCESS;
+	}
+
+	/* Read arguments and store relevant info in structs */
+	while (*argv) {
+		/* deb_count = nb_elem - 1 and we need nb_elem + 1 to allocate terminal node [NULL pointer] */
+		deb_file = xrealloc_vector(deb_file, 2, deb_count);
+		deb_file[deb_count] = xzalloc(sizeof(deb_file[0][0]));
+		if (opt & (OPT_install | OPT_unpack)) {
+			/* -i/-u: require filename */
+			archive_handle_t *archive_handle;
+			llist_t *control_list = NULL;
+
+			/* Extract the control file */
+			llist_add_to(&control_list, (char*)"./control");
+			archive_handle = init_archive_deb_ar(argv[0]);
+			init_archive_deb_control(archive_handle);
+			deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list);
+			if (deb_file[deb_count]->control_file == NULL) {
+				bb_error_msg_and_die("can't extract control file");
+			}
+			deb_file[deb_count]->filename = xstrdup(argv[0]);
+			package_num = fill_package_struct(deb_file[deb_count]->control_file);
+
+			if (package_num == -1) {
+				bb_error_msg("invalid control file in %s", argv[0]);
+				argv++;
+				continue;
+			}
+			deb_file[deb_count]->package = (unsigned) package_num;
+
+			/* Add the package to the status hashtable */
+			if (opt & (OPT_unpack | OPT_install)) {
+				/* Try and find a currently installed version of this package */
+				status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
+				/* If no previous entry was found initialise a new entry */
+				if (status_hashtable[status_num] == NULL
+				 || status_hashtable[status_num]->status == 0
+				) {
+					status_node = xmalloc(sizeof(status_node_t));
+					status_node->package = deb_file[deb_count]->package;
+					/* reinstreq isnt changed to "ok" until the package control info
+					 * is written to the status file*/
+					status_node->status = search_name_hashtable("install reinstreq not-installed");
+					status_hashtable[status_num] = status_node;
+				} else {
+					set_status(status_num, "install", 1);
+					set_status(status_num, "reinstreq", 2);
+				}
+			}
+		} else if (opt & (OPT_configure | OPT_purge | OPT_remove)) {
+			/* -C/-p/-r: require package name */
+			deb_file[deb_count]->package = search_package_hashtable(
+					search_name_hashtable(argv[0]),
+					search_name_hashtable("ANY"), VER_ANY);
+			if (package_hashtable[deb_file[deb_count]->package] == NULL) {
+				bb_error_msg_and_die("package %s is uninstalled or unknown", argv[0]);
+			}
+			package_num = deb_file[deb_count]->package;
+			status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]);
+			state_status = get_status(status_num, 3);
+
+			/* check package status is "installed" */
+			if (opt & OPT_remove) {
+				if (strcmp(name_hashtable[state_status], "not-installed") == 0
+				 || strcmp(name_hashtable[state_status], "config-files") == 0
+				) {
+					bb_error_msg_and_die("%s is already removed", name_hashtable[package_hashtable[package_num]->name]);
+				}
+				set_status(status_num, "deinstall", 1);
+			} else if (opt & OPT_purge) {
+				/* if package status is "conf-files" then its ok */
+				if (strcmp(name_hashtable[state_status], "not-installed") == 0) {
+					bb_error_msg_and_die("%s is already purged", name_hashtable[package_hashtable[package_num]->name]);
+				}
+				set_status(status_num, "purge", 1);
+			}
+		}
+		deb_count++;
+		argv++;
+	}
+	if (!deb_count)
+		bb_error_msg_and_die("no package files specified");
+	deb_file[deb_count] = NULL;
+
+	/* Check that the deb file arguments are installable */
+	if (!(opt & OPT_force_ignore_depends)) {
+		if (!check_deps(deb_file, 0 /*, deb_count*/)) {
+			bb_error_msg_and_die("dependency check failed");
+		}
+	}
+
+	/* TODO: install or remove packages in the correct dependency order */
+	for (i = 0; i < deb_count; i++) {
+		/* Remove or purge packages */
+		if (opt & OPT_remove) {
+			remove_package(deb_file[i]->package, 1);
+		}
+		else if (opt & OPT_purge) {
+			purge_package(deb_file[i]->package);
+		}
+		else if (opt & OPT_unpack) {
+			unpack_package(deb_file[i]);
+		}
+		else if (opt & OPT_install) {
+			unpack_package(deb_file[i]);
+			/* package is configured in second pass below */
+		}
+		else if (opt & OPT_configure) {
+			configure_package(deb_file[i]);
+		}
+	}
+	/* configure installed packages */
+	if (opt & OPT_install) {
+		for (i = 0; i < deb_count; i++)
+			configure_package(deb_file[i]);
+	}
+
+	write_status_file(deb_file);
+
+	if (ENABLE_FEATURE_CLEAN_UP) {
+		for (i = 0; i < deb_count; i++) {
+			free(deb_file[i]->control_file);
+			free(deb_file[i]->filename);
+			free(deb_file[i]);
+		}
+
+		free(deb_file);
+
+		for (i = 0; i < NAME_HASH_PRIME; i++) {
+			free(name_hashtable[i]);
+		}
+
+		for (i = 0; i < PACKAGE_HASH_PRIME; i++) {
+			free_package(package_hashtable[i]);
+		}
+
+		for (i = 0; i < STATUS_HASH_PRIME; i++) {
+			free(status_hashtable[i]);
+		}
+
+		free(status_hashtable);
+		free(package_hashtable);
+		free(name_hashtable);
+	}
+
+	return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/archival/dpkg_deb.c b/ap/app/busybox/src/archival/dpkg_deb.c
new file mode 100644
index 0000000..a04ec94
--- /dev/null
+++ b/ap/app/busybox/src/archival/dpkg_deb.c
@@ -0,0 +1,121 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * dpkg-deb packs, unpacks and provides information about Debian archives.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//usage:#define dpkg_deb_trivial_usage
+//usage:       "[-cefxX] FILE [argument"
+//usage:#define dpkg_deb_full_usage "\n\n"
+//usage:       "Perform actions on Debian packages (.debs)\n"
+//usage:     "\n	-c	List contents of filesystem tree"
+//usage:     "\n	-e	Extract control files to [argument] directory"
+//usage:     "\n	-f	Display control field name starting with [argument]"
+//usage:     "\n	-x	Extract packages filesystem tree to directory"
+//usage:     "\n	-X	Verbose extract"
+//usage:
+//usage:#define dpkg_deb_example_usage
+//usage:       "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+#define DPKG_DEB_OPT_CONTENTS         1
+#define DPKG_DEB_OPT_CONTROL          2
+#define DPKG_DEB_OPT_FIELD            4
+#define DPKG_DEB_OPT_EXTRACT          8
+#define DPKG_DEB_OPT_EXTRACT_VERBOSE 16
+
+int dpkg_deb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dpkg_deb_main(int argc, char **argv)
+{
+	archive_handle_t *ar_archive;
+	archive_handle_t *tar_archive;
+	llist_t *control_tar_llist = NULL;
+	unsigned opt;
+	const char *extract_dir;
+	int need_args;
+
+	/* Setup the tar archive handle */
+	tar_archive = init_handle();
+
+	/* Setup an ar archive handle that refers to the gzip sub archive */
+	ar_archive = init_handle();
+	ar_archive->dpkg__sub_archive = tar_archive;
+	ar_archive->filter = filter_accept_list_reassign;
+
+#if ENABLE_FEATURE_SEAMLESS_GZ
+	llist_add_to(&ar_archive->accept, (char*)"data.tar.gz");
+	llist_add_to(&control_tar_llist, (char*)"control.tar.gz");
+#endif
+#if ENABLE_FEATURE_SEAMLESS_BZ2
+	llist_add_to(&ar_archive->accept, (char*)"data.tar.bz2");
+	llist_add_to(&control_tar_llist, (char*)"control.tar.bz2");
+#endif
+#if ENABLE_FEATURE_SEAMLESS_LZMA
+	llist_add_to(&ar_archive->accept, (char*)"data.tar.lzma");
+	llist_add_to(&control_tar_llist, (char*)"control.tar.lzma");
+#endif
+
+	opt_complementary = "c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX";
+	opt = getopt32(argv, "cefXx");
+	argv += optind;
+	argc -= optind;
+
+	if (opt & DPKG_DEB_OPT_CONTENTS) {
+		tar_archive->action_header = header_verbose_list;
+	}
+	extract_dir = NULL;
+	need_args = 1;
+	if (opt & DPKG_DEB_OPT_CONTROL) {
+		ar_archive->accept = control_tar_llist;
+		tar_archive->action_data = data_extract_all;
+		if (1 == argc) {
+			extract_dir = "./DEBIAN";
+		} else {
+			need_args++;
+		}
+	}
+	if (opt & DPKG_DEB_OPT_FIELD) {
+		/* Print the entire control file
+		 * it should accept a second argument which specifies a
+		 * specific field to print */
+		ar_archive->accept = control_tar_llist;
+		llist_add_to(&(tar_archive->accept), (char*)"./control");
+		tar_archive->filter = filter_accept_list;
+		tar_archive->action_data = data_extract_to_stdout;
+	}
+	if (opt & DPKG_DEB_OPT_EXTRACT) {
+		tar_archive->action_header = header_list;
+	}
+	if (opt & (DPKG_DEB_OPT_EXTRACT_VERBOSE | DPKG_DEB_OPT_EXTRACT)) {
+		tar_archive->action_data = data_extract_all;
+		need_args = 2;
+	}
+
+	if (need_args != argc) {
+		bb_show_usage();
+	}
+
+	tar_archive->src_fd = ar_archive->src_fd = xopen(argv[0], O_RDONLY);
+
+	/* Work out where to extract the files */
+	/* 2nd argument is a dir name */
+	if (argv[1]) {
+		extract_dir = argv[1];
+	}
+	if (extract_dir) {
+		mkdir(extract_dir, 0777); /* bb_make_directory(extract_dir, 0777, 0) */
+		xchdir(extract_dir);
+	}
+
+	/* Do it */
+	unpack_ar_archive(ar_archive);
+
+	/* Cleanup */
+	if (ENABLE_FEATURE_CLEAN_UP)
+		close(ar_archive->src_fd);
+
+	return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/archival/gzip.c b/ap/app/busybox/src/archival/gzip.c
new file mode 100644
index 0000000..44a3c7e
--- /dev/null
+++ b/ap/app/busybox/src/archival/gzip.c
@@ -0,0 +1,2128 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Gzip implementation for busybox
+ *
+ * Based on GNU gzip Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Charles P. Wright <cpw@unix.asb.com>
+ * "this is a stripped down version of gzip I put into busybox, it does
+ * only standard in to standard out with -9 compression.  It also requires
+ * the zcat module for some important functions."
+ *
+ * Adjusted further by Erik Andersen <andersen@codepoet.org> to support
+ * files as well as stdin/stdout, and to generally behave itself wrt
+ * command line handling.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* big objects in bss:
+ * 00000020 b bl_count
+ * 00000074 b base_length
+ * 00000078 b base_dist
+ * 00000078 b static_dtree
+ * 0000009c b bl_tree
+ * 000000f4 b dyn_dtree
+ * 00000100 b length_code
+ * 00000200 b dist_code
+ * 0000023d b depth
+ * 00000400 b flag_buf
+ * 0000047a b heap
+ * 00000480 b static_ltree
+ * 000008f4 b dyn_ltree
+ */
+
+/* TODO: full support for -v for DESKTOP
+ * "/usr/bin/gzip -v a bogus aa" should say:
+a:       85.1% -- replaced with a.gz
+gzip: bogus: No such file or directory
+aa:      85.1% -- replaced with aa.gz
+*/
+
+//usage:#define gzip_trivial_usage
+//usage:       "[-cfd] [FILE]..."
+//usage:#define gzip_full_usage "\n\n"
+//usage:       "Compress FILEs (or stdin)\n"
+//usage:     "\n	-d	Decompress"
+//usage:     "\n	-c	Write to stdout"
+//usage:     "\n	-f	Force"
+//usage:
+//usage:#define gzip_example_usage
+//usage:       "$ ls -la /tmp/busybox*\n"
+//usage:       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/busybox.tar\n"
+//usage:       "$ gzip /tmp/busybox.tar\n"
+//usage:       "$ ls -la /tmp/busybox*\n"
+//usage:       "-rw-rw-r--    1 andersen andersen   554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+
+/* ===========================================================================
+ */
+//#define DEBUG 1
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) { if (!(cond)) bb_error_msg(msg); }
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x; }
+#  define Tracevv(x) {if (verbose > 1) fprintf x; }
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x; }
+#  define Tracecv(c,x) {if (verbose > 1 && (c)) fprintf x; }
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+/* ===========================================================================
+ */
+#if   CONFIG_GZIP_FAST == 0
+# define SMALL_MEM
+#elif CONFIG_GZIP_FAST == 1
+# define MEDIUM_MEM
+#elif CONFIG_GZIP_FAST == 2
+# define BIG_MEM
+#else
+# error "Invalid CONFIG_GZIP_FAST value"
+#endif
+
+#ifndef INBUFSIZ
+#  ifdef SMALL_MEM
+#    define INBUFSIZ  0x2000	/* input buffer size */
+#  else
+#    define INBUFSIZ  0x8000	/* input buffer size */
+#  endif
+#endif
+
+#ifndef OUTBUFSIZ
+#  ifdef SMALL_MEM
+#    define OUTBUFSIZ   8192	/* output buffer size */
+#  else
+#    define OUTBUFSIZ  16384	/* output buffer size */
+#  endif
+#endif
+
+#ifndef DIST_BUFSIZE
+#  ifdef SMALL_MEM
+#    define DIST_BUFSIZE 0x2000	/* buffer for distances, see trees.c */
+#  else
+#    define DIST_BUFSIZE 0x8000	/* buffer for distances, see trees.c */
+#  endif
+#endif
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01	/* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02	/* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04	/* bit 2 set: extra field present */
+#define ORIG_NAME    0x08	/* bit 3 set: original file name present */
+#define COMMENT      0x10	/* bit 4 set: file comment present */
+#define RESERVED     0xC0	/* bit 6,7:   reserved */
+
+/* internal file attribute */
+#define UNKNOWN 0xffff
+#define BINARY  0
+#define ASCII   1
+
+#ifndef WSIZE
+#  define WSIZE 0x8000  /* window size--must be a power of two, and */
+#endif                  /*  at least 32K for zip's deflate method */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#ifndef MAX_PATH_LEN
+#  define MAX_PATH_LEN   1024	/* max pathname length */
+#endif
+
+#define seekable()    0	/* force sequential output */
+#define translate_eol 0	/* no option -a yet */
+
+#ifndef BITS
+#  define BITS 16
+#endif
+#define INIT_BITS 9		/* Initial number of bits per code */
+
+#define BIT_MASK    0x1f	/* Mask for 'number of compression bits' */
+/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
+ * It's a pity that old uncompress does not check bit 0x20. That makes
+ * extension of the format actually undesirable because old compress
+ * would just crash on the new format instead of giving a meaningful
+ * error message. It does check the number of bits, but it's more
+ * helpful to say "unsupported format, get a new version" than
+ * "can only handle 16 bits".
+ */
+
+#ifdef MAX_EXT_CHARS
+#  define MAX_SUFFIX  MAX_EXT_CHARS
+#else
+#  define MAX_SUFFIX  30
+#endif
+
+
+/* ===========================================================================
+ * Compile with MEDIUM_MEM to reduce the memory requirements or
+ * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
+ * entire input file can be held in memory (not possible on 16 bit systems).
+ * Warning: defining these symbols affects HASH_BITS (see below) and thus
+ * affects the compression ratio. The compressed output
+ * is still correct, and might even be smaller in some cases.
+ */
+
+#ifdef SMALL_MEM
+#   define HASH_BITS  13	/* Number of bits used to hash strings */
+#endif
+#ifdef MEDIUM_MEM
+#   define HASH_BITS  14
+#endif
+#ifndef HASH_BITS
+#   define HASH_BITS  15
+   /* For portability to 16 bit machines, do not use values above 15. */
+#endif
+
+#define HASH_SIZE (unsigned)(1<<HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+#define WMASK     (WSIZE-1)
+/* HASH_SIZE and WSIZE must be powers of two */
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+
+/* ===========================================================================
+ * These types are not really 'char', 'short' and 'long'
+ */
+typedef uint8_t uch;
+typedef uint16_t ush;
+typedef uint32_t ulg;
+typedef int32_t lng;
+
+typedef ush Pos;
+typedef unsigned IPos;
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+enum {
+	WINDOW_SIZE = 2 * WSIZE,
+/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
+ * input file length plus MIN_LOOKAHEAD.
+ */
+
+	max_chain_length = 4096,
+/* To speed up deflation, hash chains are never searched beyond this length.
+ * A higher limit improves compression ratio but degrades the speed.
+ */
+
+	max_lazy_match = 258,
+/* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+
+	max_insert_length = max_lazy_match,
+/* Insert new strings in the hash table only if the match length
+ * is not greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+	good_match = 32,
+/* Use a faster search when the previous match is longer than this */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+
+	nice_match = 258,	/* Stop searching when current match exceeds this */
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+};
+
+
+struct globals {
+
+	lng block_start;
+
+/* window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+	unsigned ins_h;	/* hash index of string to be inserted */
+
+#define H_SHIFT  ((HASH_BITS+MIN_MATCH-1) / MIN_MATCH)
+/* Number of bits by which ins_h and del_h must be shifted at each
+ * input step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * H_SHIFT * MIN_MATCH >= HASH_BITS
+ */
+
+	unsigned prev_length;
+
+/* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+	unsigned strstart;	/* start of string to insert */
+	unsigned match_start;	/* start of matching string */
+	unsigned lookahead;	/* number of valid bytes ahead in window */
+
+/* ===========================================================================
+ */
+#define DECLARE(type, array, size) \
+	type * array
+#define ALLOC(type, array, size) \
+	array = xzalloc((size_t)(((size)+1L)/2) * 2*sizeof(type))
+#define FREE(array) \
+	do { free(array); array = NULL; } while (0)
+
+	/* global buffers */
+
+	/* buffer for literals or lengths */
+	/* DECLARE(uch, l_buf, LIT_BUFSIZE); */
+	DECLARE(uch, l_buf, INBUFSIZ);
+
+	DECLARE(ush, d_buf, DIST_BUFSIZE);
+	DECLARE(uch, outbuf, OUTBUFSIZ);
+
+/* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least WSIZE
+ * bytes. With this organization, matches are limited to a distance of
+ * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
+ * be less efficient).
+ */
+	DECLARE(uch, window, 2L * WSIZE);
+
+/* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+	/* DECLARE(Pos, prev, WSIZE); */
+	DECLARE(ush, prev, 1L << BITS);
+
+/* Heads of the hash chains or 0. */
+	/* DECLARE(Pos, head, 1<<HASH_BITS); */
+#define head (G1.prev + WSIZE) /* hash head (see deflate.c) */
+
+/* number of input bytes */
+	ulg isize;		/* only 32 bits stored in .gz file */
+
+/* bbox always use stdin/stdout */
+#define ifd STDIN_FILENO	/* input file descriptor */
+#define ofd STDOUT_FILENO	/* output file descriptor */
+
+#ifdef DEBUG
+	unsigned insize;	/* valid bytes in l_buf */
+#endif
+	unsigned outcnt;	/* bytes in output buffer */
+
+	smallint eofile;	/* flag set at end of input file */
+
+/* ===========================================================================
+ * Local data used by the "bit string" routines.
+ */
+
+	unsigned short bi_buf;
+
+/* Output buffer. bits are inserted starting at the bottom (least significant
+ * bits).
+ */
+
+#undef BUF_SIZE
+#define BUF_SIZE (8 * sizeof(G1.bi_buf))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+	int bi_valid;
+
+/* Current input function. Set to mem_read for in-memory compression */
+
+#ifdef DEBUG
+	ulg bits_sent;			/* bit length of the compressed data */
+#endif
+
+	/*uint32_t *crc_32_tab;*/
+	uint32_t crc;	/* shift register contents */
+};
+
+#define G1 (*(ptr_to_globals - 1))
+
+
+/* ===========================================================================
+ * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
+ * (used for the compressed data only)
+ */
+static void flush_outbuf(void)
+{
+	if (G1.outcnt == 0)
+		return;
+
+	xwrite(ofd, (char *) G1.outbuf, G1.outcnt);
+	G1.outcnt = 0;
+}
+
+
+/* ===========================================================================
+ */
+/* put_8bit is used for the compressed output */
+#define put_8bit(c) \
+do { \
+	G1.outbuf[G1.outcnt++] = (c); \
+	if (G1.outcnt == OUTBUFSIZ) flush_outbuf(); \
+} while (0)
+
+/* Output a 16 bit value, lsb first */
+static void put_16bit(ush w)
+{
+	if (G1.outcnt < OUTBUFSIZ - 2) {
+		G1.outbuf[G1.outcnt++] = w;
+		G1.outbuf[G1.outcnt++] = w >> 8;
+	} else {
+		put_8bit(w);
+		put_8bit(w >> 8);
+	}
+}
+
+static void put_32bit(ulg n)
+{
+	put_16bit(n);
+	put_16bit(n >> 16);
+}
+
+/* ===========================================================================
+ * Run a set of bytes through the crc shift register.  If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ */
+static void updcrc(uch * s, unsigned n)
+{
+	G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/);
+}
+
+
+/* ===========================================================================
+ * Read a new buffer from the current input file, perform end-of-line
+ * translation, and update the crc and input file size.
+ * IN assertion: size >= 2 (for end-of-line translation)
+ */
+static unsigned file_read(void *buf, unsigned size)
+{
+	unsigned len;
+
+	Assert(G1.insize == 0, "l_buf not empty");
+
+	len = safe_read(ifd, buf, size);
+	if (len == (unsigned)(-1) || len == 0)
+		return len;
+
+	updcrc(buf, len);
+	G1.isize += len;
+	return len;
+}
+
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+static void send_bits(int value, int length)
+{
+#ifdef DEBUG
+	Tracev((stderr, " l %2d v %4x ", length, value));
+	Assert(length > 0 && length <= 15, "invalid length");
+	G1.bits_sent += length;
+#endif
+	/* If not enough room in bi_buf, use (valid) bits from bi_buf and
+	 * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+	 * unused bits in value.
+	 */
+	if (G1.bi_valid > (int) BUF_SIZE - length) {
+		G1.bi_buf |= (value << G1.bi_valid);
+		put_16bit(G1.bi_buf);
+		G1.bi_buf = (ush) value >> (BUF_SIZE - G1.bi_valid);
+		G1.bi_valid += length - BUF_SIZE;
+	} else {
+		G1.bi_buf |= value << G1.bi_valid;
+		G1.bi_valid += length;
+	}
+}
+
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+static unsigned bi_reverse(unsigned code, int len)
+{
+	unsigned res = 0;
+
+	while (1) {
+		res |= code & 1;
+		if (--len <= 0) return res;
+		code >>= 1;
+		res <<= 1;
+	}
+}
+
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+static void bi_windup(void)
+{
+	if (G1.bi_valid > 8) {
+		put_16bit(G1.bi_buf);
+	} else if (G1.bi_valid > 0) {
+		put_8bit(G1.bi_buf);
+	}
+	G1.bi_buf = 0;
+	G1.bi_valid = 0;
+#ifdef DEBUG
+	G1.bits_sent = (G1.bits_sent + 7) & ~7;
+#endif
+}
+
+
+/* ===========================================================================
+ * Copy a stored block to the zip file, storing first the length and its
+ * one's complement if requested.
+ */
+static void copy_block(char *buf, unsigned len, int header)
+{
+	bi_windup();		/* align on byte boundary */
+
+	if (header) {
+		put_16bit(len);
+		put_16bit(~len);
+#ifdef DEBUG
+		G1.bits_sent += 2 * 16;
+#endif
+	}
+#ifdef DEBUG
+	G1.bits_sent += (ulg) len << 3;
+#endif
+	while (len--) {
+		put_8bit(*buf++);
+	}
+}
+
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: at least one byte has been read, or eofile is set;
+ *    file reads are performed for at least two bytes (required for the
+ *    translate_eol option).
+ */
+static void fill_window(void)
+{
+	unsigned n, m;
+	unsigned more =	WINDOW_SIZE - G1.lookahead - G1.strstart;
+	/* Amount of free space at the end of the window. */
+
+	/* If the window is almost full and there is insufficient lookahead,
+	 * move the upper half to the lower one to make room in the upper half.
+	 */
+	if (more == (unsigned) -1) {
+		/* Very unlikely, but possible on 16 bit machine if strstart == 0
+		 * and lookahead == 1 (input done one byte at time)
+		 */
+		more--;
+	} else if (G1.strstart >= WSIZE + MAX_DIST) {
+		/* By the IN assertion, the window is not empty so we can't confuse
+		 * more == 0 with more == 64K on a 16 bit machine.
+		 */
+		Assert(WINDOW_SIZE == 2 * WSIZE, "no sliding with BIG_MEM");
+
+		memcpy(G1.window, G1.window + WSIZE, WSIZE);
+		G1.match_start -= WSIZE;
+		G1.strstart -= WSIZE;	/* we now have strstart >= MAX_DIST: */
+
+		G1.block_start -= WSIZE;
+
+		for (n = 0; n < HASH_SIZE; n++) {
+			m = head[n];
+			head[n] = (Pos) (m >= WSIZE ? m - WSIZE : 0);
+		}
+		for (n = 0; n < WSIZE; n++) {
+			m = G1.prev[n];
+			G1.prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : 0);
+			/* If n is not on any hash chain, prev[n] is garbage but
+			 * its value will never be used.
+			 */
+		}
+		more += WSIZE;
+	}
+	/* At this point, more >= 2 */
+	if (!G1.eofile) {
+		n = file_read(G1.window + G1.strstart + G1.lookahead, more);
+		if (n == 0 || n == (unsigned) -1) {
+			G1.eofile = 1;
+		} else {
+			G1.lookahead += n;
+		}
+	}
+}
+
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
+ * match.s. The code is functionally equivalent, so you can use the C version
+ * if desired.
+ */
+static int longest_match(IPos cur_match)
+{
+	unsigned chain_length = max_chain_length;	/* max hash chain length */
+	uch *scan = G1.window + G1.strstart;	/* current string */
+	uch *match;	/* matched string */
+	int len;	/* length of current match */
+	int best_len = G1.prev_length;	/* best match length so far */
+	IPos limit = G1.strstart > (IPos) MAX_DIST ? G1.strstart - (IPos) MAX_DIST : 0;
+	/* Stop when cur_match becomes <= limit. To simplify the code,
+	 * we prevent matches with the string of window index 0.
+	 */
+
+/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+#if HASH_BITS < 8 || MAX_MATCH != 258
+#  error Code too clever
+#endif
+	uch *strend = G1.window + G1.strstart + MAX_MATCH;
+	uch scan_end1 = scan[best_len - 1];
+	uch scan_end = scan[best_len];
+
+	/* Do not waste too much time if we already have a good match: */
+	if (G1.prev_length >= good_match) {
+		chain_length >>= 2;
+	}
+	Assert(G1.strstart <= WINDOW_SIZE - MIN_LOOKAHEAD, "insufficient lookahead");
+
+	do {
+		Assert(cur_match < G1.strstart, "no future");
+		match = G1.window + cur_match;
+
+		/* Skip to next match if the match length cannot increase
+		 * or if the match length is less than 2:
+		 */
+		if (match[best_len] != scan_end
+		 || match[best_len - 1] != scan_end1
+		 || *match != *scan || *++match != scan[1]
+		) {
+			continue;
+		}
+
+		/* The check at best_len-1 can be removed because it will be made
+		 * again later. (This heuristic is not always a win.)
+		 * It is not necessary to compare scan[2] and match[2] since they
+		 * are always equal when the other bytes match, given that
+		 * the hash keys are equal and that HASH_BITS >= 8.
+		 */
+		scan += 2, match++;
+
+		/* We check for insufficient lookahead only every 8th comparison;
+		 * the 256th check will be made at strstart+258.
+		 */
+		do {
+		} while (*++scan == *++match && *++scan == *++match &&
+				 *++scan == *++match && *++scan == *++match &&
+				 *++scan == *++match && *++scan == *++match &&
+				 *++scan == *++match && *++scan == *++match && scan < strend);
+
+		len = MAX_MATCH - (int) (strend - scan);
+		scan = strend - MAX_MATCH;
+
+		if (len > best_len) {
+			G1.match_start = cur_match;
+			best_len = len;
+			if (len >= nice_match)
+				break;
+			scan_end1 = scan[best_len - 1];
+			scan_end = scan[best_len];
+		}
+	} while ((cur_match = G1.prev[cur_match & WMASK]) > limit
+			 && --chain_length != 0);
+
+	return best_len;
+}
+
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+static void check_match(IPos start, IPos match, int length)
+{
+	/* check that the match is indeed a match */
+	if (memcmp(G1.window + match, G1.window + start, length) != 0) {
+		bb_error_msg(" start %d, match %d, length %d", start, match, length);
+		bb_error_msg("invalid match");
+	}
+	if (verbose > 1) {
+		bb_error_msg("\\[%d,%d]", start - match, length);
+		do {
+			bb_putchar_stderr(G1.window[start++]);
+		} while (--length != 0);
+	}
+}
+#else
+#  define check_match(start, match, length) ((void)0)
+#endif
+
+
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*  PURPOSE
+ *      Encode various sets of source values using variable-length
+ *      binary code trees.
+ *
+ *  DISCUSSION
+ *      The PKZIP "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in the ZIP file in a compressed form
+ *      which is itself a Huffman encoding of the lengths of
+ *      all the code strings (in ascending order by source values).
+ *      The actual code strings are reconstructed from the lengths in
+ *      the UNZIP process, as described in the "application note"
+ *      (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
+ *
+ *  REFERENCES
+ *      Lynch, Thomas J.
+ *          Data Compression:  Techniques and Applications, pp. 53-55.
+ *          Lifetime Learning Publications, 1985.  ISBN 0-534-03418-7.
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ *
+ *  INTERFACE
+ *      void ct_init()
+ *          Allocate the match buffer, initialize the various tables [and save
+ *          the location of the internal file attribute (ascii/binary) and
+ *          method (DEFLATE/STORE) -- deleted in bbox]
+ *
+ *      void ct_tally(int dist, int lc);
+ *          Save the match info and tally the frequency counts.
+ *
+ *      ulg flush_block(char *buf, ulg stored_len, int eof)
+ *          Determine the best encoding for the current block: dynamic trees,
+ *          static trees or store, and output the encoded block to the zip
+ *          file. Returns the total compressed length for the file so far.
+ */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+/* extra bits for each length code */
+static const uint8_t extra_lbits[LENGTH_CODES] ALIGN1 = {
+	0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
+	4, 4, 5, 5, 5, 5, 0
+};
+
+/* extra bits for each distance code */
+static const uint8_t extra_dbits[D_CODES] ALIGN1 = {
+	0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
+	10, 10, 11, 11, 12, 12, 13, 13
+};
+
+/* extra bits for each bit length code */
+static const uint8_t extra_blbits[BL_CODES] ALIGN1 = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 };
+
+/* number of codes at each bit length for an optimal tree */
+static const uint8_t bl_order[BL_CODES] ALIGN1 = {
+	16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#ifndef LIT_BUFSIZE
+#  ifdef SMALL_MEM
+#    define LIT_BUFSIZE  0x2000
+#  else
+#  ifdef MEDIUM_MEM
+#    define LIT_BUFSIZE  0x4000
+#  else
+#    define LIT_BUFSIZE  0x8000
+#  endif
+#  endif
+#endif
+#ifndef DIST_BUFSIZE
+#  define DIST_BUFSIZE  LIT_BUFSIZE
+#endif
+/* Sizes of match buffers for literals/lengths and distances.  There are
+ * 4 reasons for limiting LIT_BUFSIZE to 64K:
+ *   - frequencies can be kept in 16 bit counters
+ *   - if compression is not successful for the first block, all input data is
+ *     still in the window so we can still emit a stored block even when input
+ *     comes from standard input.  (This can also be done for all blocks if
+ *     LIT_BUFSIZE is not greater than 32K.)
+ *   - if compression is not successful for a file smaller than 64K, we can
+ *     even emit a stored file instead of a stored block (saving 5 bytes).
+ *   - creating new Huffman trees less frequently may not provide fast
+ *     adaptation to changes in the input data statistics. (Take for
+ *     example a binary file with poorly compressible code followed by
+ *     a highly compressible string table.) Smaller buffer sizes give
+ *     fast adaptation but have of course the overhead of transmitting trees
+ *     more frequently.
+ *   - I can't count above 4
+ * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
+ * memory at the expense of compression). Some optimizations would be possible
+ * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+/* ===========================================================================
+*/
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data {
+	union {
+		ush freq;		/* frequency count */
+		ush code;		/* bit string */
+	} fc;
+	union {
+		ush dad;		/* father node in Huffman tree */
+		ush len;		/* length of bit string */
+	} dl;
+} ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+#define HEAP_SIZE (2*L_CODES + 1)
+/* maximum heap size */
+
+typedef struct tree_desc {
+	ct_data *dyn_tree;	/* the dynamic tree */
+	ct_data *static_tree;	/* corresponding static tree or NULL */
+	const uint8_t *extra_bits;	/* extra bits for each code or NULL */
+	int extra_base;		/* base index for extra_bits */
+	int elems;			/* max number of elements in the tree */
+	int max_length;		/* max bit length for the codes */
+	int max_code;		/* largest code with non zero frequency */
+} tree_desc;
+
+struct globals2 {
+
+	ush heap[HEAP_SIZE];     /* heap used to build the Huffman trees */
+	int heap_len;            /* number of elements in the heap */
+	int heap_max;            /* element of largest frequency */
+
+/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+	ct_data dyn_ltree[HEAP_SIZE];	/* literal and length tree */
+	ct_data dyn_dtree[2 * D_CODES + 1];	/* distance tree */
+
+	ct_data static_ltree[L_CODES + 2];
+
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
+ * below).
+ */
+
+	ct_data static_dtree[D_CODES];
+
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+	ct_data bl_tree[2 * BL_CODES + 1];
+
+/* Huffman tree for the bit lengths */
+
+	tree_desc l_desc;
+	tree_desc d_desc;
+	tree_desc bl_desc;
+
+	ush bl_count[MAX_BITS + 1];
+
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+	uch depth[2 * L_CODES + 1];
+
+/* Depth of each subtree used as tie breaker for trees of equal frequency */
+
+	uch length_code[MAX_MATCH - MIN_MATCH + 1];
+
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+	uch dist_code[512];
+
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+	int base_length[LENGTH_CODES];
+
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+	int base_dist[D_CODES];
+
+/* First normalized distance for each code (0 = distance of 1) */
+
+	uch flag_buf[LIT_BUFSIZE / 8];
+
+/* flag_buf is a bit array distinguishing literals from lengths in
+ * l_buf, thus indicating the presence or absence of a distance.
+ */
+
+	unsigned last_lit;       /* running index in l_buf */
+	unsigned last_dist;      /* running index in d_buf */
+	unsigned last_flags;     /* running index in flag_buf */
+	uch flags;               /* current flags not yet saved in flag_buf */
+	uch flag_bit;            /* current bit used in flags */
+
+/* bits are filled in flags starting at bit 0 (least significant).
+ * Note: these flags are overkill in the current code since we don't
+ * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+	ulg opt_len;             /* bit length of current block with optimal trees */
+	ulg static_len;          /* bit length of current block with static trees */
+
+	ulg compressed_len;      /* total bit length of compressed file */
+};
+
+#define G2ptr ((struct globals2*)(ptr_to_globals))
+#define G2 (*G2ptr)
+
+
+/* ===========================================================================
+ */
+static void gen_codes(ct_data * tree, int max_code);
+static void build_tree(tree_desc * desc);
+static void scan_tree(ct_data * tree, int max_code);
+static void send_tree(ct_data * tree, int max_code);
+static const int build_bl_tree(void);
+static void send_all_trees(int lcodes, int dcodes, int blcodes);
+static void compress_block(ct_data * ltree, ct_data * dtree);
+
+
+#ifndef DEBUG
+/* Send a code of the given tree. c and tree must not have side effects */
+#  define SEND_CODE(c, tree) send_bits(tree[c].Code, tree[c].Len)
+#else
+#  define SEND_CODE(c, tree) \
+{ \
+	if (verbose > 1) bb_error_msg("\ncd %3d ", (c)); \
+	send_bits(tree[c].Code, tree[c].Len); \
+}
+#endif
+
+#define D_CODE(dist) \
+	((dist) < 256 ? G2.dist_code[dist] : G2.dist_code[256 + ((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ * The arguments must not have side effects.
+ */
+
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+static void init_block(void)
+{
+	int n; /* iterates over tree elements */
+
+	/* Initialize the trees. */
+	for (n = 0; n < L_CODES; n++)
+		G2.dyn_ltree[n].Freq = 0;
+	for (n = 0; n < D_CODES; n++)
+		G2.dyn_dtree[n].Freq = 0;
+	for (n = 0; n < BL_CODES; n++)
+		G2.bl_tree[n].Freq = 0;
+
+	G2.dyn_ltree[END_BLOCK].Freq = 1;
+	G2.opt_len = G2.static_len = 0;
+	G2.last_lit = G2.last_dist = G2.last_flags = 0;
+	G2.flags = 0;
+	G2.flag_bit = 1;
+}
+
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+
+/* Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length. */
+#define SMALLER(tree, n, m) \
+	(tree[n].Freq < tree[m].Freq \
+	|| (tree[n].Freq == tree[m].Freq && G2.depth[n] <= G2.depth[m]))
+
+static void pqdownheap(ct_data * tree, int k)
+{
+	int v = G2.heap[k];
+	int j = k << 1;		/* left son of k */
+
+	while (j <= G2.heap_len) {
+		/* Set j to the smallest of the two sons: */
+		if (j < G2.heap_len && SMALLER(tree, G2.heap[j + 1], G2.heap[j]))
+			j++;
+
+		/* Exit if v is smaller than both sons */
+		if (SMALLER(tree, v, G2.heap[j]))
+			break;
+
+		/* Exchange v with the smallest son */
+		G2.heap[k] = G2.heap[j];
+		k = j;
+
+		/* And continue down the tree, setting j to the left son of k */
+		j <<= 1;
+	}
+	G2.heap[k] = v;
+}
+
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+static void gen_bitlen(tree_desc * desc)
+{
+	ct_data *tree = desc->dyn_tree;
+	const uint8_t *extra = desc->extra_bits;
+	int base = desc->extra_base;
+	int max_code = desc->max_code;
+	int max_length = desc->max_length;
+	ct_data *stree = desc->static_tree;
+	int h;				/* heap index */
+	int n, m;			/* iterate over the tree elements */
+	int bits;			/* bit length */
+	int xbits;			/* extra bits */
+	ush f;				/* frequency */
+	int overflow = 0;	/* number of elements with bit length too large */
+
+	for (bits = 0; bits <= MAX_BITS; bits++)
+		G2.bl_count[bits] = 0;
+
+	/* In a first pass, compute the optimal bit lengths (which may
+	 * overflow in the case of the bit length tree).
+	 */
+	tree[G2.heap[G2.heap_max]].Len = 0;	/* root of the heap */
+
+	for (h = G2.heap_max + 1; h < HEAP_SIZE; h++) {
+		n = G2.heap[h];
+		bits = tree[tree[n].Dad].Len + 1;
+		if (bits > max_length) {
+			bits = max_length;
+			overflow++;
+		}
+		tree[n].Len = (ush) bits;
+		/* We overwrite tree[n].Dad which is no longer needed */
+
+		if (n > max_code)
+			continue;	/* not a leaf node */
+
+		G2.bl_count[bits]++;
+		xbits = 0;
+		if (n >= base)
+			xbits = extra[n - base];
+		f = tree[n].Freq;
+		G2.opt_len += (ulg) f *(bits + xbits);
+
+		if (stree)
+			G2.static_len += (ulg) f * (stree[n].Len + xbits);
+	}
+	if (overflow == 0)
+		return;
+
+	Trace((stderr, "\nbit length overflow\n"));
+	/* This happens for example on obj2 and pic of the Calgary corpus */
+
+	/* Find the first bit length which could increase: */
+	do {
+		bits = max_length - 1;
+		while (G2.bl_count[bits] == 0)
+			bits--;
+		G2.bl_count[bits]--;	/* move one leaf down the tree */
+		G2.bl_count[bits + 1] += 2;	/* move one overflow item as its brother */
+		G2.bl_count[max_length]--;
+		/* The brother of the overflow item also moves one step up,
+		 * but this does not affect bl_count[max_length]
+		 */
+		overflow -= 2;
+	} while (overflow > 0);
+
+	/* Now recompute all bit lengths, scanning in increasing frequency.
+	 * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+	 * lengths instead of fixing only the wrong ones. This idea is taken
+	 * from 'ar' written by Haruhiko Okumura.)
+	 */
+	for (bits = max_length; bits != 0; bits--) {
+		n = G2.bl_count[bits];
+		while (n != 0) {
+			m = G2.heap[--h];
+			if (m > max_code)
+				continue;
+			if (tree[m].Len != (unsigned) bits) {
+				Trace((stderr, "code %d bits %d->%d\n", m, tree[m].Len, bits));
+				G2.opt_len += ((int32_t) bits - tree[m].Len) * tree[m].Freq;
+				tree[m].Len = bits;
+			}
+			n--;
+		}
+	}
+}
+
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+static void gen_codes(ct_data * tree, int max_code)
+{
+	ush next_code[MAX_BITS + 1];	/* next code value for each bit length */
+	ush code = 0;		/* running code value */
+	int bits;			/* bit index */
+	int n;				/* code index */
+
+	/* The distribution counts are first used to generate the code values
+	 * without bit reversal.
+	 */
+	for (bits = 1; bits <= MAX_BITS; bits++) {
+		next_code[bits] = code = (code + G2.bl_count[bits - 1]) << 1;
+	}
+	/* Check that the bit counts in bl_count are consistent. The last code
+	 * must be all ones.
+	 */
+	Assert(code + G2.bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
+			"inconsistent bit counts");
+	Tracev((stderr, "\ngen_codes: max_code %d ", max_code));
+
+	for (n = 0; n <= max_code; n++) {
+		int len = tree[n].Len;
+
+		if (len == 0)
+			continue;
+		/* Now reverse the bits */
+		tree[n].Code = bi_reverse(next_code[len]++, len);
+
+		Tracec(tree != G2.static_ltree,
+			   (stderr, "\nn %3d %c l %2d c %4x (%x) ", n,
+				(n > ' ' ? n : ' '), len, tree[n].Code,
+				next_code[len] - 1));
+	}
+}
+
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+
+/* Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len. */
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+#define PQREMOVE(tree, top) \
+do { \
+	top = G2.heap[SMALLEST]; \
+	G2.heap[SMALLEST] = G2.heap[G2.heap_len--]; \
+	pqdownheap(tree, SMALLEST); \
+} while (0)
+
+static void build_tree(tree_desc * desc)
+{
+	ct_data *tree = desc->dyn_tree;
+	ct_data *stree = desc->static_tree;
+	int elems = desc->elems;
+	int n, m;			/* iterate over heap elements */
+	int max_code = -1;	/* largest code with non zero frequency */
+	int node = elems;	/* next internal node of the tree */
+
+	/* Construct the initial heap, with least frequent element in
+	 * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+	 * heap[0] is not used.
+	 */
+	G2.heap_len = 0;
+	G2.heap_max = HEAP_SIZE;
+
+	for (n = 0; n < elems; n++) {
+		if (tree[n].Freq != 0) {
+			G2.heap[++G2.heap_len] = max_code = n;
+			G2.depth[n] = 0;
+		} else {
+			tree[n].Len = 0;
+		}
+	}
+
+	/* The pkzip format requires that at least one distance code exists,
+	 * and that at least one bit should be sent even if there is only one
+	 * possible code. So to avoid special checks later on we force at least
+	 * two codes of non zero frequency.
+	 */
+	while (G2.heap_len < 2) {
+		int new = G2.heap[++G2.heap_len] = (max_code < 2 ? ++max_code : 0);
+
+		tree[new].Freq = 1;
+		G2.depth[new] = 0;
+		G2.opt_len--;
+		if (stree)
+			G2.static_len -= stree[new].Len;
+		/* new is 0 or 1 so it does not have extra bits */
+	}
+	desc->max_code = max_code;
+
+	/* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+	 * establish sub-heaps of increasing lengths:
+	 */
+	for (n = G2.heap_len / 2; n >= 1; n--)
+		pqdownheap(tree, n);
+
+	/* Construct the Huffman tree by repeatedly combining the least two
+	 * frequent nodes.
+	 */
+	do {
+		PQREMOVE(tree, n);	/* n = node of least frequency */
+		m = G2.heap[SMALLEST];	/* m = node of next least frequency */
+
+		G2.heap[--G2.heap_max] = n;	/* keep the nodes sorted by frequency */
+		G2.heap[--G2.heap_max] = m;
+
+		/* Create a new node father of n and m */
+		tree[node].Freq = tree[n].Freq + tree[m].Freq;
+		G2.depth[node] = MAX(G2.depth[n], G2.depth[m]) + 1;
+		tree[n].Dad = tree[m].Dad = (ush) node;
+#ifdef DUMP_BL_TREE
+		if (tree == G2.bl_tree) {
+			bb_error_msg("\nnode %d(%d), sons %d(%d) %d(%d)",
+					node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+		}
+#endif
+		/* and insert the new node in the heap */
+		G2.heap[SMALLEST] = node++;
+		pqdownheap(tree, SMALLEST);
+
+	} while (G2.heap_len >= 2);
+
+	G2.heap[--G2.heap_max] = G2.heap[SMALLEST];
+
+	/* At this point, the fields freq and dad are set. We can now
+	 * generate the bit lengths.
+	 */
+	gen_bitlen((tree_desc *) desc);
+
+	/* The field len is now set, we can generate the bit codes */
+	gen_codes((ct_data *) tree, max_code);
+}
+
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+static void scan_tree(ct_data * tree, int max_code)
+{
+	int n;				/* iterates over all tree elements */
+	int prevlen = -1;	/* last emitted length */
+	int curlen;			/* length of current code */
+	int nextlen = tree[0].Len;	/* length of next code */
+	int count = 0;		/* repeat count of the current code */
+	int max_count = 7;	/* max repeat count */
+	int min_count = 4;	/* min repeat count */
+
+	if (nextlen == 0) {
+		max_count = 138;
+		min_count = 3;
+	}
+	tree[max_code + 1].Len = 0xffff; /* guard */
+
+	for (n = 0; n <= max_code; n++) {
+		curlen = nextlen;
+		nextlen = tree[n + 1].Len;
+		if (++count < max_count && curlen == nextlen)
+			continue;
+
+		if (count < min_count) {
+			G2.bl_tree[curlen].Freq += count;
+		} else if (curlen != 0) {
+			if (curlen != prevlen)
+				G2.bl_tree[curlen].Freq++;
+			G2.bl_tree[REP_3_6].Freq++;
+		} else if (count <= 10) {
+			G2.bl_tree[REPZ_3_10].Freq++;
+		} else {
+			G2.bl_tree[REPZ_11_138].Freq++;
+		}
+		count = 0;
+		prevlen = curlen;
+
+		max_count = 7;
+		min_count = 4;
+		if (nextlen == 0) {
+			max_count = 138;
+			min_count = 3;
+		} else if (curlen == nextlen) {
+			max_count = 6;
+			min_count = 3;
+		}
+	}
+}
+
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+static void send_tree(ct_data * tree, int max_code)
+{
+	int n;				/* iterates over all tree elements */
+	int prevlen = -1;	/* last emitted length */
+	int curlen;			/* length of current code */
+	int nextlen = tree[0].Len;	/* length of next code */
+	int count = 0;		/* repeat count of the current code */
+	int max_count = 7;	/* max repeat count */
+	int min_count = 4;	/* min repeat count */
+
+/* tree[max_code+1].Len = -1; *//* guard already set */
+	if (nextlen == 0)
+		max_count = 138, min_count = 3;
+
+	for (n = 0; n <= max_code; n++) {
+		curlen = nextlen;
+		nextlen = tree[n + 1].Len;
+		if (++count < max_count && curlen == nextlen) {
+			continue;
+		} else if (count < min_count) {
+			do {
+				SEND_CODE(curlen, G2.bl_tree);
+			} while (--count);
+		} else if (curlen != 0) {
+			if (curlen != prevlen) {
+				SEND_CODE(curlen, G2.bl_tree);
+				count--;
+			}
+			Assert(count >= 3 && count <= 6, " 3_6?");
+			SEND_CODE(REP_3_6, G2.bl_tree);
+			send_bits(count - 3, 2);
+		} else if (count <= 10) {
+			SEND_CODE(REPZ_3_10, G2.bl_tree);
+			send_bits(count - 3, 3);
+		} else {
+			SEND_CODE(REPZ_11_138, G2.bl_tree);
+			send_bits(count - 11, 7);
+		}
+		count = 0;
+		prevlen = curlen;
+		if (nextlen == 0) {
+			max_count = 138;
+			min_count = 3;
+		} else if (curlen == nextlen) {
+			max_count = 6;
+			min_count = 3;
+		} else {
+			max_count = 7;
+			min_count = 4;
+		}
+	}
+}
+
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+static const int build_bl_tree(void)
+{
+	int max_blindex;	/* index of last bit length code of non zero freq */
+
+	/* Determine the bit length frequencies for literal and distance trees */
+	scan_tree(G2.dyn_ltree, G2.l_desc.max_code);
+	scan_tree(G2.dyn_dtree, G2.d_desc.max_code);
+
+	/* Build the bit length tree: */
+	build_tree(&G2.bl_desc);
+	/* opt_len now includes the length of the tree representations, except
+	 * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+	 */
+
+	/* Determine the number of bit length codes to send. The pkzip format
+	 * requires that at least 4 bit length codes be sent. (appnote.txt says
+	 * 3 but the actual value used is 4.)
+	 */
+	for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
+		if (G2.bl_tree[bl_order[max_blindex]].Len != 0)
+			break;
+	}
+	/* Update opt_len to include the bit length tree and counts */
+	G2.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
+	Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", G2.opt_len, G2.static_len));
+
+	return max_blindex;
+}
+
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+static void send_all_trees(int lcodes, int dcodes, int blcodes)
+{
+	int rank;			/* index in bl_order */
+
+	Assert(lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+	Assert(lcodes <= L_CODES && dcodes <= D_CODES
+		   && blcodes <= BL_CODES, "too many codes");
+	Tracev((stderr, "\nbl counts: "));
+	send_bits(lcodes - 257, 5);	/* not +255 as stated in appnote.txt */
+	send_bits(dcodes - 1, 5);
+	send_bits(blcodes - 4, 4);	/* not -3 as stated in appnote.txt */
+	for (rank = 0; rank < blcodes; rank++) {
+		Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+		send_bits(G2.bl_tree[bl_order[rank]].Len, 3);
+	}
+	Tracev((stderr, "\nbl tree: sent %ld", G1.bits_sent));
+
+	send_tree((ct_data *) G2.dyn_ltree, lcodes - 1);	/* send the literal tree */
+	Tracev((stderr, "\nlit tree: sent %ld", G1.bits_sent));
+
+	send_tree((ct_data *) G2.dyn_dtree, dcodes - 1);	/* send the distance tree */
+	Tracev((stderr, "\ndist tree: sent %ld", G1.bits_sent));
+}
+
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+static int ct_tally(int dist, int lc)
+{
+	G1.l_buf[G2.last_lit++] = lc;
+	if (dist == 0) {
+		/* lc is the unmatched char */
+		G2.dyn_ltree[lc].Freq++;
+	} else {
+		/* Here, lc is the match length - MIN_MATCH */
+		dist--;			/* dist = match distance - 1 */
+		Assert((ush) dist < (ush) MAX_DIST
+		 && (ush) lc <= (ush) (MAX_MATCH - MIN_MATCH)
+		 && (ush) D_CODE(dist) < (ush) D_CODES, "ct_tally: bad match"
+		);
+
+		G2.dyn_ltree[G2.length_code[lc] + LITERALS + 1].Freq++;
+		G2.dyn_dtree[D_CODE(dist)].Freq++;
+
+		G1.d_buf[G2.last_dist++] = dist;
+		G2.flags |= G2.flag_bit;
+	}
+	G2.flag_bit <<= 1;
+
+	/* Output the flags if they fill a byte: */
+	if ((G2.last_lit & 7) == 0) {
+		G2.flag_buf[G2.last_flags++] = G2.flags;
+		G2.flags = 0;
+		G2.flag_bit = 1;
+	}
+	/* Try to guess if it is profitable to stop the current block here */
+	if ((G2.last_lit & 0xfff) == 0) {
+		/* Compute an upper bound for the compressed length */
+		ulg out_length = G2.last_lit * 8L;
+		ulg in_length = (ulg) G1.strstart - G1.block_start;
+		int dcode;
+
+		for (dcode = 0; dcode < D_CODES; dcode++) {
+			out_length += G2.dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]);
+		}
+		out_length >>= 3;
+		Trace((stderr,
+				"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+				G2.last_lit, G2.last_dist, in_length, out_length,
+				100L - out_length * 100L / in_length));
+		if (G2.last_dist < G2.last_lit / 2 && out_length < in_length / 2)
+			return 1;
+	}
+	return (G2.last_lit == LIT_BUFSIZE - 1 || G2.last_dist == DIST_BUFSIZE);
+	/* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+	 * on 16 bit machines and because stored blocks are restricted to
+	 * 64K-1 bytes.
+	 */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+static void compress_block(ct_data * ltree, ct_data * dtree)
+{
+	unsigned dist;          /* distance of matched string */
+	int lc;                 /* match length or unmatched char (if dist == 0) */
+	unsigned lx = 0;        /* running index in l_buf */
+	unsigned dx = 0;        /* running index in d_buf */
+	unsigned fx = 0;        /* running index in flag_buf */
+	uch flag = 0;           /* current flags */
+	unsigned code;          /* the code to send */
+	int extra;              /* number of extra bits to send */
+
+	if (G2.last_lit != 0) do {
+		if ((lx & 7) == 0)
+			flag = G2.flag_buf[fx++];
+		lc = G1.l_buf[lx++];
+		if ((flag & 1) == 0) {
+			SEND_CODE(lc, ltree);	/* send a literal byte */
+			Tracecv(lc > ' ', (stderr, " '%c' ", lc));
+		} else {
+			/* Here, lc is the match length - MIN_MATCH */
+			code = G2.length_code[lc];
+			SEND_CODE(code + LITERALS + 1, ltree);	/* send the length code */
+			extra = extra_lbits[code];
+			if (extra != 0) {
+				lc -= G2.base_length[code];
+				send_bits(lc, extra);	/* send the extra length bits */
+			}
+			dist = G1.d_buf[dx++];
+			/* Here, dist is the match distance - 1 */
+			code = D_CODE(dist);
+			Assert(code < D_CODES, "bad d_code");
+
+			SEND_CODE(code, dtree);	/* send the distance code */
+			extra = extra_dbits[code];
+			if (extra != 0) {
+				dist -= G2.base_dist[code];
+				send_bits(dist, extra);	/* send the extra distance bits */
+			}
+		}			/* literal or match pair ? */
+		flag >>= 1;
+	} while (lx < G2.last_lit);
+
+	SEND_CODE(END_BLOCK, ltree);
+}
+
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+static ulg flush_block(char *buf, ulg stored_len, int eof)
+{
+	ulg opt_lenb, static_lenb;      /* opt_len and static_len in bytes */
+	int max_blindex;                /* index of last bit length code of non zero freq */
+
+	G2.flag_buf[G2.last_flags] = G2.flags;   /* Save the flags for the last 8 items */
+
+	/* Construct the literal and distance trees */
+	build_tree(&G2.l_desc);
+	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", G2.opt_len, G2.static_len));
+
+	build_tree(&G2.d_desc);
+	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", G2.opt_len, G2.static_len));
+	/* At this point, opt_len and static_len are the total bit lengths of
+	 * the compressed block data, excluding the tree representations.
+	 */
+
+	/* Build the bit length tree for the above two trees, and get the index
+	 * in bl_order of the last bit length code to send.
+	 */
+	max_blindex = build_bl_tree();
+
+	/* Determine the best encoding. Compute first the block length in bytes */
+	opt_lenb = (G2.opt_len + 3 + 7) >> 3;
+	static_lenb = (G2.static_len + 3 + 7) >> 3;
+
+	Trace((stderr,
+			"\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+			opt_lenb, G2.opt_len, static_lenb, G2.static_len, stored_len,
+			G2.last_lit, G2.last_dist));
+
+	if (static_lenb <= opt_lenb)
+		opt_lenb = static_lenb;
+
+	/* If compression failed and this is the first and last block,
+	 * and if the zip file can be seeked (to rewrite the local header),
+	 * the whole file is transformed into a stored file:
+	 */
+	if (stored_len <= opt_lenb && eof && G2.compressed_len == 0L && seekable()) {
+		/* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+		if (buf == NULL)
+			bb_error_msg("block vanished");
+
+		copy_block(buf, (unsigned) stored_len, 0);	/* without header */
+		G2.compressed_len = stored_len << 3;
+
+	} else if (stored_len + 4 <= opt_lenb && buf != NULL) {
+		/* 4: two words for the lengths */
+		/* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+		 * Otherwise we can't have processed more than WSIZE input bytes since
+		 * the last block flush, because compression would have been
+		 * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+		 * transform a block into a stored block.
+		 */
+		send_bits((STORED_BLOCK << 1) + eof, 3);	/* send block type */
+		G2.compressed_len = (G2.compressed_len + 3 + 7) & ~7L;
+		G2.compressed_len += (stored_len + 4) << 3;
+
+		copy_block(buf, (unsigned) stored_len, 1);	/* with header */
+
+	} else if (static_lenb == opt_lenb) {
+		send_bits((STATIC_TREES << 1) + eof, 3);
+		compress_block((ct_data *) G2.static_ltree, (ct_data *) G2.static_dtree);
+		G2.compressed_len += 3 + G2.static_len;
+	} else {
+		send_bits((DYN_TREES << 1) + eof, 3);
+		send_all_trees(G2.l_desc.max_code + 1, G2.d_desc.max_code + 1,
+					max_blindex + 1);
+		compress_block((ct_data *) G2.dyn_ltree, (ct_data *) G2.dyn_dtree);
+		G2.compressed_len += 3 + G2.opt_len;
+	}
+	Assert(G2.compressed_len == G1.bits_sent, "bad compressed size");
+	init_block();
+
+	if (eof) {
+		bi_windup();
+		G2.compressed_len += 7;	/* align on byte boundary */
+	}
+	Tracev((stderr, "\ncomprlen %lu(%lu) ", G2.compressed_len >> 3,
+			G2.compressed_len - 7 * eof));
+
+	return G2.compressed_len >> 3;
+}
+
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(h, c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ *
+ * Processes a new input file and return its compressed length. Sets
+ * the compressed length, crc, deflate flags and internal file
+ * attributes.
+ */
+
+/* Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match. */
+#define FLUSH_BLOCK(eof) \
+	flush_block( \
+		G1.block_start >= 0L \
+			? (char*)&G1.window[(unsigned)G1.block_start] \
+			: (char*)NULL, \
+		(ulg)G1.strstart - G1.block_start, \
+		(eof) \
+	)
+
+/* Insert string s in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of s are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file). */
+#define INSERT_STRING(s, match_head) \
+do { \
+	UPDATE_HASH(G1.ins_h, G1.window[(s) + MIN_MATCH-1]); \
+	G1.prev[(s) & WMASK] = match_head = head[G1.ins_h]; \
+	head[G1.ins_h] = (s); \
+} while (0)
+
+static ulg deflate(void)
+{
+	IPos hash_head;		/* head of hash chain */
+	IPos prev_match;	/* previous match */
+	int flush;			/* set if current block must be flushed */
+	int match_available = 0;	/* set if previous match exists */
+	unsigned match_length = MIN_MATCH - 1;	/* length of best match */
+
+	/* Process the input block. */
+	while (G1.lookahead != 0) {
+		/* Insert the string window[strstart .. strstart+2] in the
+		 * dictionary, and set hash_head to the head of the hash chain:
+		 */
+		INSERT_STRING(G1.strstart, hash_head);
+
+		/* Find the longest match, discarding those <= prev_length.
+		 */
+		G1.prev_length = match_length;
+		prev_match = G1.match_start;
+		match_length = MIN_MATCH - 1;
+
+		if (hash_head != 0 && G1.prev_length < max_lazy_match
+		 && G1.strstart - hash_head <= MAX_DIST
+		) {
+			/* To simplify the code, we prevent matches with the string
+			 * of window index 0 (in particular we have to avoid a match
+			 * of the string with itself at the start of the input file).
+			 */
+			match_length = longest_match(hash_head);
+			/* longest_match() sets match_start */
+			if (match_length > G1.lookahead)
+				match_length = G1.lookahead;
+
+			/* Ignore a length 3 match if it is too distant: */
+			if (match_length == MIN_MATCH && G1.strstart - G1.match_start > TOO_FAR) {
+				/* If prev_match is also MIN_MATCH, G1.match_start is garbage
+				 * but we will ignore the current match anyway.
+				 */
+				match_length--;
+			}
+		}
+		/* If there was a match at the previous step and the current
+		 * match is not better, output the previous match:
+		 */
+		if (G1.prev_length >= MIN_MATCH && match_length <= G1.prev_length) {
+			check_match(G1.strstart - 1, prev_match, G1.prev_length);
+			flush = ct_tally(G1.strstart - 1 - prev_match, G1.prev_length - MIN_MATCH);
+
+			/* Insert in hash table all strings up to the end of the match.
+			 * strstart-1 and strstart are already inserted.
+			 */
+			G1.lookahead -= G1.prev_length - 1;
+			G1.prev_length -= 2;
+			do {
+				G1.strstart++;
+				INSERT_STRING(G1.strstart, hash_head);
+				/* strstart never exceeds WSIZE-MAX_MATCH, so there are
+				 * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+				 * these bytes are garbage, but it does not matter since the
+				 * next lookahead bytes will always be emitted as literals.
+				 */
+			} while (--G1.prev_length != 0);
+			match_available = 0;
+			match_length = MIN_MATCH - 1;
+			G1.strstart++;
+			if (flush) {
+				FLUSH_BLOCK(0);
+				G1.block_start = G1.strstart;
+			}
+		} else if (match_available) {
+			/* If there was no match at the previous position, output a
+			 * single literal. If there was a match but the current match
+			 * is longer, truncate the previous match to a single literal.
+			 */
+			Tracevv((stderr, "%c", G1.window[G1.strstart - 1]));
+			if (ct_tally(0, G1.window[G1.strstart - 1])) {
+				FLUSH_BLOCK(0);
+				G1.block_start = G1.strstart;
+			}
+			G1.strstart++;
+			G1.lookahead--;
+		} else {
+			/* There is no previous match to compare with, wait for
+			 * the next step to decide.
+			 */
+			match_available = 1;
+			G1.strstart++;
+			G1.lookahead--;
+		}
+		Assert(G1.strstart <= G1.isize && lookahead <= G1.isize, "a bit too far");
+
+		/* Make sure that we always have enough lookahead, except
+		 * at the end of the input file. We need MAX_MATCH bytes
+		 * for the next match, plus MIN_MATCH bytes to insert the
+		 * string following the next match.
+		 */
+		while (G1.lookahead < MIN_LOOKAHEAD && !G1.eofile)
+			fill_window();
+	}
+	if (match_available)
+		ct_tally(0, G1.window[G1.strstart - 1]);
+
+	return FLUSH_BLOCK(1);	/* eof */
+}
+
+
+/* ===========================================================================
+ * Initialize the bit string routines.
+ */
+static void bi_init(void)
+{
+	G1.bi_buf = 0;
+	G1.bi_valid = 0;
+#ifdef DEBUG
+	G1.bits_sent = 0L;
+#endif
+}
+
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new file
+ */
+static void lm_init(ush * flagsp)
+{
+	unsigned j;
+
+	/* Initialize the hash table. */
+	memset(head, 0, HASH_SIZE * sizeof(*head));
+	/* prev will be initialized on the fly */
+
+	/* speed options for the general purpose bit flag */
+	*flagsp |= 2;	/* FAST 4, SLOW 2 */
+	/* ??? reduce max_chain_length for binary files */
+
+	G1.strstart = 0;
+	G1.block_start = 0L;
+
+	G1.lookahead = file_read(G1.window,
+			sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE);
+
+	if (G1.lookahead == 0 || G1.lookahead == (unsigned) -1) {
+		G1.eofile = 1;
+		G1.lookahead = 0;
+		return;
+	}
+	G1.eofile = 0;
+	/* Make sure that we always have enough lookahead. This is important
+	 * if input comes from a device such as a tty.
+	 */
+	while (G1.lookahead < MIN_LOOKAHEAD && !G1.eofile)
+		fill_window();
+
+	G1.ins_h = 0;
+	for (j = 0; j < MIN_MATCH - 1; j++)
+		UPDATE_HASH(G1.ins_h, G1.window[j]);
+	/* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+	 * not important since only literal bytes will be emitted.
+	 */
+}
+
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ * One callsite in zip()
+ */
+static void ct_init(void)
+{
+	int n;				/* iterates over tree elements */
+	int length;			/* length value */
+	int code;			/* code value */
+	int dist;			/* distance index */
+
+	G2.compressed_len = 0L;
+
+#ifdef NOT_NEEDED
+	if (G2.static_dtree[0].Len != 0)
+		return;			/* ct_init already called */
+#endif
+
+	/* Initialize the mapping length (0..255) -> length code (0..28) */
+	length = 0;
+	for (code = 0; code < LENGTH_CODES - 1; code++) {
+		G2.base_length[code] = length;
+		for (n = 0; n < (1 << extra_lbits[code]); n++) {
+			G2.length_code[length++] = code;
+		}
+	}
+	Assert(length == 256, "ct_init: length != 256");
+	/* Note that the length 255 (match length 258) can be represented
+	 * in two different ways: code 284 + 5 bits or code 285, so we
+	 * overwrite length_code[255] to use the best encoding:
+	 */
+	G2.length_code[length - 1] = code;
+
+	/* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+	dist = 0;
+	for (code = 0; code < 16; code++) {
+		G2.base_dist[code] = dist;
+		for (n = 0; n < (1 << extra_dbits[code]); n++) {
+			G2.dist_code[dist++] = code;
+		}
+	}
+	Assert(dist == 256, "ct_init: dist != 256");
+	dist >>= 7;			/* from now on, all distances are divided by 128 */
+	for (; code < D_CODES; code++) {
+		G2.base_dist[code] = dist << 7;
+		for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
+			G2.dist_code[256 + dist++] = code;
+		}
+	}
+	Assert(dist == 256, "ct_init: 256+dist != 512");
+
+	/* Construct the codes of the static literal tree */
+	/* already zeroed - it's in bss
+	for (n = 0; n <= MAX_BITS; n++)
+		G2.bl_count[n] = 0; */
+
+	n = 0;
+	while (n <= 143) {
+		G2.static_ltree[n++].Len = 8;
+		G2.bl_count[8]++;
+	}
+	while (n <= 255) {
+		G2.static_ltree[n++].Len = 9;
+		G2.bl_count[9]++;
+	}
+	while (n <= 279) {
+		G2.static_ltree[n++].Len = 7;
+		G2.bl_count[7]++;
+	}
+	while (n <= 287) {
+		G2.static_ltree[n++].Len = 8;
+		G2.bl_count[8]++;
+	}
+	/* Codes 286 and 287 do not exist, but we must include them in the
+	 * tree construction to get a canonical Huffman tree (longest code
+	 * all ones)
+	 */
+	gen_codes((ct_data *) G2.static_ltree, L_CODES + 1);
+
+	/* The static distance tree is trivial: */
+	for (n = 0; n < D_CODES; n++) {
+		G2.static_dtree[n].Len = 5;
+		G2.static_dtree[n].Code = bi_reverse(n, 5);
+	}
+
+	/* Initialize the first block of the first file: */
+	init_block();
+}
+
+
+/* ===========================================================================
+ * Deflate in to out.
+ * IN assertions: the input and output buffers are cleared.
+ */
+
+static void zip(ulg time_stamp)
+{
+	ush deflate_flags = 0;  /* pkzip -es, -en or -ex equivalent */
+
+	G1.outcnt = 0;
+
+	/* Write the header to the gzip file. See algorithm.doc for the format */
+	/* magic header for gzip files: 1F 8B */
+	/* compression method: 8 (DEFLATED) */
+	/* general flags: 0 */
+	put_32bit(0x00088b1f);
+	put_32bit(time_stamp);
+
+	/* Write deflated file to zip file */
+	G1.crc = ~0;
+
+	bi_init();
+	ct_init();
+	lm_init(&deflate_flags);
+
+	put_8bit(deflate_flags);	/* extra flags */
+	put_8bit(3);	/* OS identifier = 3 (Unix) */
+
+	deflate();
+
+	/* Write the crc and uncompressed size */
+	put_32bit(~G1.crc);
+	put_32bit(G1.isize);
+
+	flush_outbuf();
+}
+
+
+/* ======================================================================== */
+static
+IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_aux_data_t *aux UNUSED_PARAM)
+{
+	struct stat s;
+
+	/* Clear input and output buffers */
+	G1.outcnt = 0;
+#ifdef DEBUG
+	G1.insize = 0;
+#endif
+	G1.isize = 0;
+
+	/* Reinit G2.xxx */
+	memset(&G2, 0, sizeof(G2));
+	G2.l_desc.dyn_tree     = G2.dyn_ltree;
+	G2.l_desc.static_tree  = G2.static_ltree;
+	G2.l_desc.extra_bits   = extra_lbits;
+	G2.l_desc.extra_base   = LITERALS + 1;
+	G2.l_desc.elems        = L_CODES;
+	G2.l_desc.max_length   = MAX_BITS;
+	//G2.l_desc.max_code     = 0;
+	G2.d_desc.dyn_tree     = G2.dyn_dtree;
+	G2.d_desc.static_tree  = G2.static_dtree;
+	G2.d_desc.extra_bits   = extra_dbits;
+	//G2.d_desc.extra_base   = 0;
+	G2.d_desc.elems        = D_CODES;
+	G2.d_desc.max_length   = MAX_BITS;
+	//G2.d_desc.max_code     = 0;
+	G2.bl_desc.dyn_tree    = G2.bl_tree;
+	//G2.bl_desc.static_tree = NULL;
+	G2.bl_desc.extra_bits  = extra_blbits,
+	//G2.bl_desc.extra_base  = 0;
+	G2.bl_desc.elems       = BL_CODES;
+	G2.bl_desc.max_length  = MAX_BL_BITS;
+	//G2.bl_desc.max_code    = 0;
+
+	s.st_ctime = 0;
+	fstat(STDIN_FILENO, &s);
+	zip(s.st_ctime);
+	return 0;
+}
+
+#if ENABLE_FEATURE_GZIP_LONG_OPTIONS
+static const char gzip_longopts[] ALIGN1 =
+	"stdout\0"              No_argument       "c"
+	"to-stdout\0"           No_argument       "c"
+	"force\0"               No_argument       "f"
+	"verbose\0"             No_argument       "v"
+#if ENABLE_GUNZIP
+	"decompress\0"          No_argument       "d"
+	"uncompress\0"          No_argument       "d"
+	"test\0"                No_argument       "t"
+#endif
+	"quiet\0"               No_argument       "q"
+	"fast\0"                No_argument       "1"
+	"best\0"                No_argument       "9"
+	;
+#endif
+
+/*
+ * Linux kernel build uses gzip -d -n. We accept and ignore -n.
+ * Man page says:
+ * -n --no-name
+ * gzip: do not save the original file name and time stamp.
+ * (The original name is always saved if the name had to be truncated.)
+ * gunzip: do not restore the original file name/time even if present
+ * (remove only the gzip suffix from the compressed file name).
+ * This option is the default when decompressing.
+ * -N --name
+ * gzip: always save the original file name and time stamp (this is the default)
+ * gunzip: restore the original file name and time stamp if present.
+ */
+
+int gzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+#if ENABLE_GUNZIP
+int gzip_main(int argc, char **argv)
+#else
+int gzip_main(int argc UNUSED_PARAM, char **argv)
+#endif
+{
+	unsigned opt;
+
+#if ENABLE_FEATURE_GZIP_LONG_OPTIONS
+	applet_long_options = gzip_longopts;
+#endif
+	/* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
+	opt = getopt32(argv, "cfv" IF_GUNZIP("dt") "q123456789n");
+#if ENABLE_GUNZIP /* gunzip_main may not be visible... */
+	if (opt & 0x18) // -d and/or -t
+		return gunzip_main(argc, argv);
+#endif
+	option_mask32 &= 0x7; /* ignore -q, -0..9 */
+	//if (opt & 0x1) // -c
+	//if (opt & 0x2) // -f
+	//if (opt & 0x4) // -v
+	argv += optind;
+
+	SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2))
+			+ sizeof(struct globals));
+
+	/* Allocate all global buffers (for DYN_ALLOC option) */
+	ALLOC(uch, G1.l_buf, INBUFSIZ);
+	ALLOC(uch, G1.outbuf, OUTBUFSIZ);
+	ALLOC(ush, G1.d_buf, DIST_BUFSIZE);
+	ALLOC(uch, G1.window, 2L * WSIZE);
+	ALLOC(ush, G1.prev, 1L << BITS);
+
+	/* Initialize the CRC32 table */
+	global_crc32_table = crc32_filltable(NULL, 0);
+
+	return bbunpack(argv, pack_gzip, append_ext, "gz");
+}
diff --git a/ap/app/busybox/src/archival/libarchive/Kbuild.src b/ap/app/busybox/src/archival/libarchive/Kbuild.src
new file mode 100644
index 0000000..58457fc
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/Kbuild.src
@@ -0,0 +1,69 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under GPLv2 or later, see file LICENSE in this source tree.
+
+lib-y:=
+
+COMMON_FILES:= \
+\
+	data_skip.o \
+	data_extract_all.o \
+	data_extract_to_stdout.o \
+\
+	filter_accept_all.o \
+	filter_accept_list.o \
+	filter_accept_reject_list.o \
+\
+	header_skip.o \
+	header_list.o \
+	header_verbose_list.o \
+\
+	seek_by_read.o \
+	seek_by_jump.o \
+\
+	data_align.o \
+	find_list_entry.o \
+	init_handle.o
+
+DPKG_FILES:= \
+	unpack_ar_archive.o \
+	filter_accept_list_reassign.o \
+	get_header_ar.o \
+	get_header_tar.o \
+	get_header_tar_gz.o \
+	get_header_tar_bz2.o \
+	get_header_tar_lzma.o \
+
+INSERT
+
+lib-$(CONFIG_AR)                        += get_header_ar.o unpack_ar_archive.o
+lib-$(CONFIG_BUNZIP2)                   += decompress_bunzip2.o
+lib-$(CONFIG_UNLZMA)                    += decompress_unlzma.o
+lib-$(CONFIG_UNXZ)                      += decompress_unxz.o
+lib-$(CONFIG_CPIO)                      += get_header_cpio.o
+lib-$(CONFIG_DPKG)                      += $(DPKG_FILES)
+lib-$(CONFIG_DPKG_DEB)                  += $(DPKG_FILES)
+lib-$(CONFIG_GUNZIP)                    += open_transformer.o decompress_gunzip.o
+lib-$(CONFIG_RPM2CPIO)                  += decompress_gunzip.o get_header_cpio.o
+lib-$(CONFIG_RPM)                       += open_transformer.o decompress_gunzip.o get_header_cpio.o
+lib-$(CONFIG_TAR)                       += get_header_tar.o
+lib-$(CONFIG_UNCOMPRESS)                += decompress_uncompress.o
+lib-$(CONFIG_UNZIP)                     += decompress_gunzip.o
+lib-$(CONFIG_LZOP)                      += lzo1x_1.o lzo1x_1o.o lzo1x_d.o
+lib-$(CONFIG_LZOP_COMPR_HIGH)           += lzo1x_9x.o
+lib-$(CONFIG_MODINFO)                   += open_transformer.o
+lib-$(CONFIG_INSMOD)                    += open_transformer.o
+lib-$(CONFIG_FEATURE_SEAMLESS_Z)        += open_transformer.o decompress_uncompress.o
+lib-$(CONFIG_FEATURE_SEAMLESS_GZ)       += open_transformer.o decompress_gunzip.o
+lib-$(CONFIG_FEATURE_SEAMLESS_BZ2)      += open_transformer.o decompress_bunzip2.o
+lib-$(CONFIG_FEATURE_SEAMLESS_LZMA)     += open_transformer.o decompress_unlzma.o
+lib-$(CONFIG_FEATURE_SEAMLESS_XZ)       += open_transformer.o decompress_unxz.o
+lib-$(CONFIG_FEATURE_COMPRESS_USAGE)    += open_transformer.o decompress_bunzip2.o
+lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += decompress_bunzip2.o
+lib-$(CONFIG_FEATURE_TAR_TO_COMMAND)    += data_extract_to_command.o
+
+ifneq ($(lib-y),)
+lib-y += $(COMMON_FILES)
+endif
diff --git a/ap/app/busybox/src/archival/libarchive/bz/LICENSE b/ap/app/busybox/src/archival/libarchive/bz/LICENSE
new file mode 100644
index 0000000..da43465
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/bz/LICENSE
@@ -0,0 +1,44 @@
+bzip2 applet in busybox is based on lightly-modified source
+of bzip2 version 1.0.4. bzip2 source is distributed
+under the following conditions (copied verbatim from LICENSE file)
+===========================================================
+
+
+This program, "bzip2", the associated library "libbzip2", and all
+documentation, are copyright (C) 1996-2006 Julian R Seward.  All
+rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. The origin of this software must not be misrepresented; you must
+   not claim that you wrote the original software.  If you use this
+   software in a product, an acknowledgment in the product
+   documentation would be appreciated but is not required.
+
+3. Altered source versions must be plainly marked as such, and must
+   not be misrepresented as being the original software.
+
+4. The name of the author may not be used to endorse or promote
+   products derived from this software without specific prior written
+   permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Julian Seward, Cambridge, UK.
+jseward@bzip.org
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
diff --git a/ap/app/busybox/src/archival/libarchive/bz/README b/ap/app/busybox/src/archival/libarchive/bz/README
new file mode 100644
index 0000000..fffd47b
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/bz/README
@@ -0,0 +1,90 @@
+This file is an abridged version of README from bzip2 1.0.4
+Build instructions (which are not relevant to busyboxed bzip2)
+are removed.
+===========================================================
+
+
+This is the README for bzip2/libzip2.
+This version is fully compatible with the previous public releases.
+
+------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in this file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------
+
+Please read and be aware of the following:
+
+
+WARNING:
+
+   This program and library (attempts to) compress data by
+   performing several non-trivial transformations on it.
+   Unless you are 100% familiar with *all* the algorithms
+   contained herein, and with the consequences of modifying them,
+   you should NOT meddle with the compression or decompression
+   machinery.  Incorrect changes can and very likely *will*
+   lead to disastrous loss of data.
+
+
+DISCLAIMER:
+
+   I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
+   USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED.
+
+   Every compression of a file implies an assumption that the
+   compressed file can be decompressed to reproduce the original.
+   Great efforts in design, coding and testing have been made to
+   ensure that this program works correctly.  However, the complexity
+   of the algorithms, and, in particular, the presence of various
+   special cases in the code which occur with very low but non-zero
+   probability make it impossible to rule out the possibility of bugs
+   remaining in the program.  DO NOT COMPRESS ANY DATA WITH THIS
+   PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER
+   SMALL, THAT THE DATA WILL NOT BE RECOVERABLE.
+
+   That is not to say this program is inherently unreliable.
+   Indeed, I very much hope the opposite is true.  bzip2/libbzip2
+   has been carefully constructed and extensively tested.
+
+
+PATENTS:
+
+   To the best of my knowledge, bzip2/libbzip2 does not use any
+   patented algorithms.  However, I do not have the resources
+   to carry out a patent search.  Therefore I cannot give any
+   guarantee of the above statement.
+
+
+I hope you find bzip2 useful.  Feel free to contact me at
+   jseward@bzip.org
+if you have any suggestions or queries.  Many people mailed me with
+comments, suggestions and patches after the releases of bzip-0.15,
+bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1,
+1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this
+feedback.  I thank you for your comments.
+
+bzip2's "home" is http://www.bzip.org/
+
+Julian Seward
+jseward@bzip.org
+Cambridge, UK.
+
+18     July 1996 (version 0.15)
+25   August 1996 (version 0.21)
+ 7   August 1997 (bzip2, version 0.1)
+29   August 1997 (bzip2, version 0.1pl2)
+23   August 1998 (bzip2, version 0.9.0)
+ 8     June 1999 (bzip2, version 0.9.5)
+ 4     Sept 1999 (bzip2, version 0.9.5d)
+ 5      May 2000 (bzip2, version 1.0pre8)
+30 December 2001 (bzip2, version 1.0.2pre1)
+15 February 2005 (bzip2, version 1.0.3)
+20 December 2006 (bzip2, version 1.0.4)
diff --git a/ap/app/busybox/src/archival/libarchive/bz/blocksort.c b/ap/app/busybox/src/archival/libarchive/bz/blocksort.c
new file mode 100644
index 0000000..e600cb7
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/bz/blocksort.c
@@ -0,0 +1,1072 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Block sorting machinery                               ---*/
+/*---                                           blocksort.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+/* #include "bzlib_private.h" */
+
+#define mswap(zz1, zz2) \
+{ \
+	int32_t zztmp = zz1; \
+	zz1 = zz2; \
+	zz2 = zztmp; \
+}
+
+static
+/* No measurable speed gain with inlining */
+/* ALWAYS_INLINE */
+void mvswap(uint32_t* ptr, int32_t zzp1, int32_t zzp2, int32_t zzn)
+{
+	while (zzn > 0) {
+		mswap(ptr[zzp1], ptr[zzp2]);
+		zzp1++;
+		zzp2++;
+		zzn--;
+	}
+}
+
+static
+ALWAYS_INLINE
+int32_t mmin(int32_t a, int32_t b)
+{
+	return (a < b) ? a : b;
+}
+
+
+/*---------------------------------------------*/
+/*--- Fallback O(N log(N)^2) sorting        ---*/
+/*--- algorithm, for repetitive blocks      ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+inline
+void fallbackSimpleSort(uint32_t* fmap,
+		uint32_t* eclass,
+		int32_t   lo,
+		int32_t   hi)
+{
+	int32_t i, j, tmp;
+	uint32_t ec_tmp;
+
+	if (lo == hi) return;
+
+	if (hi - lo > 3) {
+		for (i = hi-4; i >= lo; i--) {
+			tmp = fmap[i];
+			ec_tmp = eclass[tmp];
+			for (j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4)
+				fmap[j-4] = fmap[j];
+			fmap[j-4] = tmp;
+		}
+	}
+
+	for (i = hi-1; i >= lo; i--) {
+		tmp = fmap[i];
+		ec_tmp = eclass[tmp];
+		for (j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++)
+			fmap[j-1] = fmap[j];
+		fmap[j-1] = tmp;
+	}
+}
+
+
+/*---------------------------------------------*/
+#define fpush(lz,hz) { \
+	stackLo[sp] = lz; \
+	stackHi[sp] = hz; \
+	sp++; \
+}
+
+#define fpop(lz,hz) { \
+	sp--; \
+	lz = stackLo[sp]; \
+	hz = stackHi[sp]; \
+}
+
+#define FALLBACK_QSORT_SMALL_THRESH 10
+#define FALLBACK_QSORT_STACK_SIZE   100
+
+static
+void fallbackQSort3(uint32_t* fmap,
+		uint32_t* eclass,
+		int32_t   loSt,
+		int32_t   hiSt)
+{
+	int32_t unLo, unHi, ltLo, gtHi, n, m;
+	int32_t sp, lo, hi;
+	uint32_t med, r, r3;
+	int32_t stackLo[FALLBACK_QSORT_STACK_SIZE];
+	int32_t stackHi[FALLBACK_QSORT_STACK_SIZE];
+
+	r = 0;
+
+	sp = 0;
+	fpush(loSt, hiSt);
+
+	while (sp > 0) {
+		AssertH(sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004);
+
+		fpop(lo, hi);
+		if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
+			fallbackSimpleSort(fmap, eclass, lo, hi);
+			continue;
+		}
+
+		/* Random partitioning.  Median of 3 sometimes fails to
+		 * avoid bad cases.  Median of 9 seems to help but
+		 * looks rather expensive.  This too seems to work but
+		 * is cheaper.  Guidance for the magic constants
+		 * 7621 and 32768 is taken from Sedgewick's algorithms
+		 * book, chapter 35.
+		 */
+		r = ((r * 7621) + 1) % 32768;
+		r3 = r % 3;
+		if (r3 == 0)
+			med = eclass[fmap[lo]];
+		else if (r3 == 1)
+			med = eclass[fmap[(lo+hi)>>1]];
+		else
+			med = eclass[fmap[hi]];
+
+		unLo = ltLo = lo;
+		unHi = gtHi = hi;
+
+		while (1) {
+			while (1) {
+				if (unLo > unHi) break;
+				n = (int32_t)eclass[fmap[unLo]] - (int32_t)med;
+				if (n == 0) {
+					mswap(fmap[unLo], fmap[ltLo]);
+					ltLo++;
+					unLo++;
+					continue;
+				};
+				if (n > 0) break;
+				unLo++;
+			}
+			while (1) {
+				if (unLo > unHi) break;
+				n = (int32_t)eclass[fmap[unHi]] - (int32_t)med;
+				if (n == 0) {
+					mswap(fmap[unHi], fmap[gtHi]);
+					gtHi--; unHi--;
+					continue;
+				};
+				if (n < 0) break;
+				unHi--;
+			}
+			if (unLo > unHi) break;
+			mswap(fmap[unLo], fmap[unHi]); unLo++; unHi--;
+		}
+
+		AssertD(unHi == unLo-1, "fallbackQSort3(2)");
+
+		if (gtHi < ltLo) continue;
+
+		n = mmin(ltLo-lo, unLo-ltLo); mvswap(fmap, lo, unLo-n, n);
+		m = mmin(hi-gtHi, gtHi-unHi); mvswap(fmap, unLo, hi-m+1, m);
+
+		n = lo + unLo - ltLo - 1;
+		m = hi - (gtHi - unHi) + 1;
+
+		if (n - lo > hi - m) {
+			fpush(lo, n);
+			fpush(m, hi);
+		} else {
+			fpush(m, hi);
+			fpush(lo, n);
+		}
+	}
+}
+
+#undef fpush
+#undef fpop
+#undef FALLBACK_QSORT_SMALL_THRESH
+#undef FALLBACK_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+ *	nblock > 0
+ *	eclass exists for [0 .. nblock-1]
+ *	((uint8_t*)eclass) [0 .. nblock-1] holds block
+ *	ptr exists for [0 .. nblock-1]
+ *
+ * Post:
+ *	((uint8_t*)eclass) [0 .. nblock-1] holds block
+ *	All other areas of eclass destroyed
+ *	fmap [0 .. nblock-1] holds sorted order
+ *	bhtab[0 .. 2+(nblock/32)] destroyed
+*/
+
+#define       SET_BH(zz)  bhtab[(zz) >> 5] |= (1 << ((zz) & 31))
+#define     CLEAR_BH(zz)  bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31))
+#define     ISSET_BH(zz)  (bhtab[(zz) >> 5] & (1 << ((zz) & 31)))
+#define      WORD_BH(zz)  bhtab[(zz) >> 5]
+#define UNALIGNED_BH(zz)  ((zz) & 0x01f)
+
+static
+void fallbackSort(uint32_t* fmap,
+		uint32_t* eclass,
+		uint32_t* bhtab,
+		int32_t   nblock)
+{
+	int32_t ftab[257];
+	int32_t ftabCopy[256];
+	int32_t H, i, j, k, l, r, cc, cc1;
+	int32_t nNotDone;
+	int32_t nBhtab;
+	uint8_t* eclass8 = (uint8_t*)eclass;
+
+	/*
+	 * Initial 1-char radix sort to generate
+	 * initial fmap and initial BH bits.
+	 */
+	for (i = 0; i < 257;    i++) ftab[i] = 0;
+	for (i = 0; i < nblock; i++) ftab[eclass8[i]]++;
+	for (i = 0; i < 256;    i++) ftabCopy[i] = ftab[i];
+
+	j = ftab[0];  /* bbox: optimized */
+	for (i = 1; i < 257;    i++) {
+		j += ftab[i];
+		ftab[i] = j;
+	}
+
+	for (i = 0; i < nblock; i++) {
+		j = eclass8[i];
+		k = ftab[j] - 1;
+		ftab[j] = k;
+		fmap[k] = i;
+	}
+
+	nBhtab = 2 + ((uint32_t)nblock / 32); /* bbox: unsigned div is easier */
+	for (i = 0; i < nBhtab; i++) bhtab[i] = 0;
+	for (i = 0; i < 256; i++) SET_BH(ftab[i]);
+
+	/*
+	 * Inductively refine the buckets.  Kind-of an
+	 * "exponential radix sort" (!), inspired by the
+	 * Manber-Myers suffix array construction algorithm.
+	 */
+
+	/*-- set sentinel bits for block-end detection --*/
+	for (i = 0; i < 32; i++) {
+		SET_BH(nblock + 2*i);
+		CLEAR_BH(nblock + 2*i + 1);
+	}
+
+	/*-- the log(N) loop --*/
+	H = 1;
+	while (1) {
+		j = 0;
+		for (i = 0; i < nblock; i++) {
+			if (ISSET_BH(i))
+				j = i;
+			k = fmap[i] - H;
+			if (k < 0)
+				k += nblock;
+			eclass[k] = j;
+		}
+
+		nNotDone = 0;
+		r = -1;
+		while (1) {
+
+		/*-- find the next non-singleton bucket --*/
+			k = r + 1;
+			while (ISSET_BH(k) && UNALIGNED_BH(k))
+				k++;
+			if (ISSET_BH(k)) {
+				while (WORD_BH(k) == 0xffffffff) k += 32;
+				while (ISSET_BH(k)) k++;
+			}
+			l = k - 1;
+			if (l >= nblock)
+				break;
+			while (!ISSET_BH(k) && UNALIGNED_BH(k))
+				k++;
+			if (!ISSET_BH(k)) {
+				while (WORD_BH(k) == 0x00000000) k += 32;
+				while (!ISSET_BH(k)) k++;
+			}
+			r = k - 1;
+			if (r >= nblock)
+				break;
+
+			/*-- now [l, r] bracket current bucket --*/
+			if (r > l) {
+				nNotDone += (r - l + 1);
+				fallbackQSort3(fmap, eclass, l, r);
+
+				/*-- scan bucket and generate header bits-- */
+				cc = -1;
+				for (i = l; i <= r; i++) {
+					cc1 = eclass[fmap[i]];
+					if (cc != cc1) {
+						SET_BH(i);
+						cc = cc1;
+					};
+				}
+			}
+		}
+
+		H *= 2;
+		if (H > nblock || nNotDone == 0)
+			break;
+	}
+
+	/*
+	 * Reconstruct the original block in
+	 * eclass8 [0 .. nblock-1], since the
+	 * previous phase destroyed it.
+	 */
+	j = 0;
+	for (i = 0; i < nblock; i++) {
+		while (ftabCopy[j] == 0)
+			j++;
+		ftabCopy[j]--;
+		eclass8[fmap[i]] = (uint8_t)j;
+	}
+	AssertH(j < 256, 1005);
+}
+
+#undef       SET_BH
+#undef     CLEAR_BH
+#undef     ISSET_BH
+#undef      WORD_BH
+#undef UNALIGNED_BH
+
+
+/*---------------------------------------------*/
+/*--- The main, O(N^2 log(N)) sorting       ---*/
+/*--- algorithm.  Faster for "normal"       ---*/
+/*--- non-repetitive blocks.                ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+NOINLINE
+int mainGtU(
+		uint32_t  i1,
+		uint32_t  i2,
+		uint8_t*  block,
+		uint16_t* quadrant,
+		uint32_t  nblock,
+		int32_t*  budget)
+{
+	int32_t  k;
+	uint8_t  c1, c2;
+	uint16_t s1, s2;
+
+/* Loop unrolling here is actually very useful
+ * (generated code is much simpler),
+ * code size increase is only 270 bytes (i386)
+ * but speeds up compression 10% overall
+ */
+
+#if CONFIG_BZIP2_FAST >= 1
+
+#define TIMES_8(code) \
+	code; code; code; code; \
+	code; code; code; code;
+#define TIMES_12(code) \
+	code; code; code; code; \
+	code; code; code; code; \
+	code; code; code; code;
+
+#else
+
+#define TIMES_8(code) \
+{ \
+	int nn = 8; \
+	do { \
+		code; \
+	} while (--nn); \
+}
+#define TIMES_12(code) \
+{ \
+	int nn = 12; \
+	do { \
+		code; \
+	} while (--nn); \
+}
+
+#endif
+
+	AssertD(i1 != i2, "mainGtU");
+	TIMES_12(
+		c1 = block[i1]; c2 = block[i2];
+		if (c1 != c2) return (c1 > c2);
+		i1++; i2++;
+	)
+
+	k = nblock + 8;
+
+	do {
+		TIMES_8(
+			c1 = block[i1]; c2 = block[i2];
+			if (c1 != c2) return (c1 > c2);
+			s1 = quadrant[i1]; s2 = quadrant[i2];
+			if (s1 != s2) return (s1 > s2);
+			i1++; i2++;
+		)
+
+		if (i1 >= nblock) i1 -= nblock;
+		if (i2 >= nblock) i2 -= nblock;
+
+		(*budget)--;
+		k -= 8;
+	} while (k >= 0);
+
+	return False;
+}
+#undef TIMES_8
+#undef TIMES_12
+
+/*---------------------------------------------*/
+/*
+ * Knuth's increments seem to work better
+ * than Incerpi-Sedgewick here.  Possibly
+ * because the number of elems to sort is
+ * usually small, typically <= 20.
+ */
+static
+const int32_t incs[14] = {
+	1, 4, 13, 40, 121, 364, 1093, 3280,
+	9841, 29524, 88573, 265720,
+	797161, 2391484
+};
+
+static
+void mainSimpleSort(uint32_t* ptr,
+		uint8_t*  block,
+		uint16_t* quadrant,
+		int32_t   nblock,
+		int32_t   lo,
+		int32_t   hi,
+		int32_t   d,
+		int32_t*  budget)
+{
+	int32_t i, j, h, bigN, hp;
+	uint32_t v;
+
+	bigN = hi - lo + 1;
+	if (bigN < 2) return;
+
+	hp = 0;
+	while (incs[hp] < bigN) hp++;
+	hp--;
+
+	for (; hp >= 0; hp--) {
+		h = incs[hp];
+
+		i = lo + h;
+		while (1) {
+			/*-- copy 1 --*/
+			if (i > hi) break;
+			v = ptr[i];
+			j = i;
+			while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) {
+				ptr[j] = ptr[j-h];
+				j = j - h;
+				if (j <= (lo + h - 1)) break;
+			}
+			ptr[j] = v;
+			i++;
+
+/* 1.5% overall speedup, +290 bytes */
+#if CONFIG_BZIP2_FAST >= 3
+			/*-- copy 2 --*/
+			if (i > hi) break;
+			v = ptr[i];
+			j = i;
+			while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) {
+				ptr[j] = ptr[j-h];
+				j = j - h;
+				if (j <= (lo + h - 1)) break;
+			}
+			ptr[j] = v;
+			i++;
+
+			/*-- copy 3 --*/
+			if (i > hi) break;
+			v = ptr[i];
+			j = i;
+			while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) {
+				ptr[j] = ptr[j-h];
+				j = j - h;
+				if (j <= (lo + h - 1)) break;
+			}
+			ptr[j] = v;
+			i++;
+#endif
+			if (*budget < 0) return;
+		}
+	}
+}
+
+
+/*---------------------------------------------*/
+/*
+ * The following is an implementation of
+ * an elegant 3-way quicksort for strings,
+ * described in a paper "Fast Algorithms for
+ * Sorting and Searching Strings", by Robert
+ * Sedgewick and Jon L. Bentley.
+ */
+
+static
+ALWAYS_INLINE
+uint8_t mmed3(uint8_t a, uint8_t b, uint8_t c)
+{
+	uint8_t t;
+	if (a > b) {
+		t = a;
+		a = b;
+		b = t;
+	};
+	/* here b >= a */
+	if (b > c) {
+		b = c;
+		if (a > b)
+			b = a;
+	}
+	return b;
+}
+
+#define mpush(lz,hz,dz) \
+{ \
+	stackLo[sp] = lz; \
+	stackHi[sp] = hz; \
+	stackD [sp] = dz; \
+	sp++; \
+}
+
+#define mpop(lz,hz,dz) \
+{ \
+	sp--; \
+	lz = stackLo[sp]; \
+	hz = stackHi[sp]; \
+	dz = stackD [sp]; \
+}
+
+#define mnextsize(az) (nextHi[az] - nextLo[az])
+
+#define mnextswap(az,bz) \
+{ \
+	int32_t tz; \
+	tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \
+	tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \
+	tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; \
+}
+
+#define MAIN_QSORT_SMALL_THRESH 20
+#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT)
+#define MAIN_QSORT_STACK_SIZE   100
+
+static NOINLINE
+void mainQSort3(uint32_t* ptr,
+		uint8_t*  block,
+		uint16_t* quadrant,
+		int32_t   nblock,
+		int32_t   loSt,
+		int32_t   hiSt,
+		int32_t   dSt,
+		int32_t*  budget)
+{
+	int32_t unLo, unHi, ltLo, gtHi, n, m, med;
+	int32_t sp, lo, hi, d;
+
+	int32_t stackLo[MAIN_QSORT_STACK_SIZE];
+	int32_t stackHi[MAIN_QSORT_STACK_SIZE];
+	int32_t stackD [MAIN_QSORT_STACK_SIZE];
+
+	int32_t nextLo[3];
+	int32_t nextHi[3];
+	int32_t nextD [3];
+
+	sp = 0;
+	mpush(loSt, hiSt, dSt);
+
+	while (sp > 0) {
+		AssertH(sp < MAIN_QSORT_STACK_SIZE - 2, 1001);
+
+		mpop(lo, hi, d);
+		if (hi - lo < MAIN_QSORT_SMALL_THRESH
+		 || d > MAIN_QSORT_DEPTH_THRESH
+		) {
+			mainSimpleSort(ptr, block, quadrant, nblock, lo, hi, d, budget);
+			if (*budget < 0)
+				return;
+			continue;
+		}
+		med = (int32_t)	mmed3(block[ptr[lo          ] + d],
+		                      block[ptr[hi          ] + d],
+		                      block[ptr[(lo+hi) >> 1] + d]);
+
+		unLo = ltLo = lo;
+		unHi = gtHi = hi;
+
+		while (1) {
+			while (1) {
+				if (unLo > unHi)
+					break;
+				n = ((int32_t)block[ptr[unLo]+d]) - med;
+				if (n == 0) {
+					mswap(ptr[unLo], ptr[ltLo]);
+					ltLo++;
+					unLo++;
+					continue;
+				};
+				if (n >  0) break;
+				unLo++;
+			}
+			while (1) {
+				if (unLo > unHi)
+					break;
+				n = ((int32_t)block[ptr[unHi]+d]) - med;
+				if (n == 0) {
+					mswap(ptr[unHi], ptr[gtHi]);
+					gtHi--;
+					unHi--;
+					continue;
+				};
+				if (n <  0) break;
+				unHi--;
+			}
+			if (unLo > unHi)
+				break;
+			mswap(ptr[unLo], ptr[unHi]);
+			unLo++;
+			unHi--;
+		}
+
+		AssertD(unHi == unLo-1, "mainQSort3(2)");
+
+		if (gtHi < ltLo) {
+			mpush(lo, hi, d + 1);
+			continue;
+		}
+
+		n = mmin(ltLo-lo, unLo-ltLo); mvswap(ptr, lo, unLo-n, n);
+		m = mmin(hi-gtHi, gtHi-unHi); mvswap(ptr, unLo, hi-m+1, m);
+
+		n = lo + unLo - ltLo - 1;
+		m = hi - (gtHi - unHi) + 1;
+
+		nextLo[0] = lo;  nextHi[0] = n;   nextD[0] = d;
+		nextLo[1] = m;   nextHi[1] = hi;  nextD[1] = d;
+		nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1;
+
+		if (mnextsize(0) < mnextsize(1)) mnextswap(0, 1);
+		if (mnextsize(1) < mnextsize(2)) mnextswap(1, 2);
+		if (mnextsize(0) < mnextsize(1)) mnextswap(0, 1);
+
+		AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)");
+		AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)");
+
+		mpush(nextLo[0], nextHi[0], nextD[0]);
+		mpush(nextLo[1], nextHi[1], nextD[1]);
+		mpush(nextLo[2], nextHi[2], nextD[2]);
+	}
+}
+
+#undef mpush
+#undef mpop
+#undef mnextsize
+#undef mnextswap
+#undef MAIN_QSORT_SMALL_THRESH
+#undef MAIN_QSORT_DEPTH_THRESH
+#undef MAIN_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+ *	nblock > N_OVERSHOOT
+ *	block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ *	((uint8_t*)block32) [0 .. nblock-1] holds block
+ *	ptr exists for [0 .. nblock-1]
+ *
+ * Post:
+ *	((uint8_t*)block32) [0 .. nblock-1] holds block
+ *	All other areas of block32 destroyed
+ *	ftab[0 .. 65536] destroyed
+ *	ptr [0 .. nblock-1] holds sorted order
+ *	if (*budget < 0), sorting was abandoned
+ */
+
+#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8])
+#define SETMASK (1 << 21)
+#define CLEARMASK (~(SETMASK))
+
+static NOINLINE
+void mainSort(EState* state,
+		uint32_t* ptr,
+		uint8_t*  block,
+		uint16_t* quadrant,
+		uint32_t* ftab,
+		int32_t   nblock,
+		int32_t*  budget)
+{
+	int32_t  i, j, k, ss, sb;
+	uint8_t  c1;
+	int32_t  numQSorted;
+	uint16_t s;
+	Bool     bigDone[256];
+	/* bbox: moved to EState to save stack
+	int32_t  runningOrder[256];
+	int32_t  copyStart[256];
+	int32_t  copyEnd  [256];
+	*/
+#define runningOrder (state->mainSort__runningOrder)
+#define copyStart    (state->mainSort__copyStart)
+#define copyEnd      (state->mainSort__copyEnd)
+
+	/*-- set up the 2-byte frequency table --*/
+	/* was: for (i = 65536; i >= 0; i--) ftab[i] = 0; */
+	memset(ftab, 0, 65537 * sizeof(ftab[0]));
+
+	j = block[0] << 8;
+	i = nblock - 1;
+/* 3%, +300 bytes */
+#if CONFIG_BZIP2_FAST >= 2
+	for (; i >= 3; i -= 4) {
+		quadrant[i] = 0;
+		j = (j >> 8) | (((uint16_t)block[i]) << 8);
+		ftab[j]++;
+		quadrant[i-1] = 0;
+		j = (j >> 8) | (((uint16_t)block[i-1]) << 8);
+		ftab[j]++;
+		quadrant[i-2] = 0;
+		j = (j >> 8) | (((uint16_t)block[i-2]) << 8);
+		ftab[j]++;
+		quadrant[i-3] = 0;
+		j = (j >> 8) | (((uint16_t)block[i-3]) << 8);
+		ftab[j]++;
+	}
+#endif
+	for (; i >= 0; i--) {
+		quadrant[i] = 0;
+		j = (j >> 8) | (((uint16_t)block[i]) << 8);
+		ftab[j]++;
+	}
+
+	/*-- (emphasises close relationship of block & quadrant) --*/
+	for (i = 0; i < BZ_N_OVERSHOOT; i++) {
+		block   [nblock+i] = block[i];
+		quadrant[nblock+i] = 0;
+	}
+
+	/*-- Complete the initial radix sort --*/
+	j = ftab[0]; /* bbox: optimized */
+	for (i = 1; i <= 65536; i++) {
+		j += ftab[i];
+		ftab[i] = j;
+	}
+
+	s = block[0] << 8;
+	i = nblock - 1;
+#if CONFIG_BZIP2_FAST >= 2
+	for (; i >= 3; i -= 4) {
+		s = (s >> 8) | (block[i] << 8);
+		j = ftab[s] - 1;
+		ftab[s] = j;
+		ptr[j] = i;
+		s = (s >> 8) | (block[i-1] << 8);
+		j = ftab[s] - 1;
+		ftab[s] = j;
+		ptr[j] = i-1;
+		s = (s >> 8) | (block[i-2] << 8);
+		j = ftab[s] - 1;
+		ftab[s] = j;
+		ptr[j] = i-2;
+		s = (s >> 8) | (block[i-3] << 8);
+		j = ftab[s] - 1;
+		ftab[s] = j;
+		ptr[j] = i-3;
+	}
+#endif
+	for (; i >= 0; i--) {
+		s = (s >> 8) | (block[i] << 8);
+		j = ftab[s] - 1;
+		ftab[s] = j;
+		ptr[j] = i;
+	}
+
+	/*
+	 * Now ftab contains the first loc of every small bucket.
+	 * Calculate the running order, from smallest to largest
+	 * big bucket.
+	 */
+	for (i = 0; i <= 255; i++) {
+		bigDone     [i] = False;
+		runningOrder[i] = i;
+	}
+
+	{
+		int32_t vv;
+		/* bbox: was: int32_t h = 1; */
+		/* do h = 3 * h + 1; while (h <= 256); */
+		uint32_t h = 364;
+
+		do {
+			/*h = h / 3;*/
+			h = (h * 171) >> 9; /* bbox: fast h/3 */
+			for (i = h; i <= 255; i++) {
+				vv = runningOrder[i];
+				j = i;
+				while (BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv)) {
+					runningOrder[j] = runningOrder[j-h];
+					j = j - h;
+					if (j <= (h - 1))
+						goto zero;
+				}
+ zero:
+				runningOrder[j] = vv;
+			}
+		} while (h != 1);
+	}
+
+	/*
+	 * The main sorting loop.
+	 */
+
+	numQSorted = 0;
+
+	for (i = 0; i <= 255; i++) {
+
+		/*
+		 * Process big buckets, starting with the least full.
+		 * Basically this is a 3-step process in which we call
+		 * mainQSort3 to sort the small buckets [ss, j], but
+		 * also make a big effort to avoid the calls if we can.
+		 */
+		ss = runningOrder[i];
+
+		/*
+		 * Step 1:
+		 * Complete the big bucket [ss] by quicksorting
+		 * any unsorted small buckets [ss, j], for j != ss.
+		 * Hopefully previous pointer-scanning phases have already
+		 * completed many of the small buckets [ss, j], so
+		 * we don't have to sort them at all.
+		 */
+		for (j = 0; j <= 255; j++) {
+			if (j != ss) {
+				sb = (ss << 8) + j;
+				if (!(ftab[sb] & SETMASK)) {
+					int32_t lo =  ftab[sb]   & CLEARMASK;
+					int32_t hi = (ftab[sb+1] & CLEARMASK) - 1;
+					if (hi > lo) {
+						mainQSort3(
+							ptr, block, quadrant, nblock,
+							lo, hi, BZ_N_RADIX, budget
+						);
+						if (*budget < 0) return;
+						numQSorted += (hi - lo + 1);
+					}
+				}
+				ftab[sb] |= SETMASK;
+			}
+		}
+
+		AssertH(!bigDone[ss], 1006);
+
+		/*
+		 * Step 2:
+		 * Now scan this big bucket [ss] so as to synthesise the
+		 * sorted order for small buckets [t, ss] for all t,
+		 * including, magically, the bucket [ss,ss] too.
+		 * This will avoid doing Real Work in subsequent Step 1's.
+		 */
+		{
+			for (j = 0; j <= 255; j++) {
+				copyStart[j] =  ftab[(j << 8) + ss]     & CLEARMASK;
+				copyEnd  [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
+			}
+			for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
+				k = ptr[j] - 1;
+				if (k < 0)
+					k += nblock;
+				c1 = block[k];
+				if (!bigDone[c1])
+					ptr[copyStart[c1]++] = k;
+			}
+			for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
+				k = ptr[j]-1;
+				if (k < 0)
+					k += nblock;
+				c1 = block[k];
+				if (!bigDone[c1])
+					ptr[copyEnd[c1]--] = k;
+			}
+		}
+
+		/* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
+		 * Necessity for this case is demonstrated by compressing
+		 * a sequence of approximately 48.5 million of character
+		 * 251; 1.0.0/1.0.1 will then die here. */
+		AssertH((copyStart[ss]-1 == copyEnd[ss]) \
+		     || (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), 1007);
+
+		for (j = 0; j <= 255; j++)
+			ftab[(j << 8) + ss] |= SETMASK;
+
+		/*
+		 * Step 3:
+		 * The [ss] big bucket is now done.  Record this fact,
+		 * and update the quadrant descriptors.  Remember to
+		 * update quadrants in the overshoot area too, if
+		 * necessary.  The "if (i < 255)" test merely skips
+		 * this updating for the last bucket processed, since
+		 * updating for the last bucket is pointless.
+		 *
+		 * The quadrant array provides a way to incrementally
+		 * cache sort orderings, as they appear, so as to
+		 * make subsequent comparisons in fullGtU() complete
+		 * faster.  For repetitive blocks this makes a big
+		 * difference (but not big enough to be able to avoid
+		 * the fallback sorting mechanism, exponential radix sort).
+		 *
+		 * The precise meaning is: at all times:
+		 *
+		 *	for 0 <= i < nblock and 0 <= j <= nblock
+		 *
+		 *	if block[i] != block[j],
+		 *
+		 *		then the relative values of quadrant[i] and
+		 *			  quadrant[j] are meaningless.
+		 *
+		 *		else {
+		 *			if quadrant[i] < quadrant[j]
+		 *				then the string starting at i lexicographically
+		 *				precedes the string starting at j
+		 *
+		 *			else if quadrant[i] > quadrant[j]
+		 *				then the string starting at j lexicographically
+		 *				precedes the string starting at i
+		 *
+		 *			else
+		 *				the relative ordering of the strings starting
+		 *				at i and j has not yet been determined.
+		 *		}
+		 */
+		bigDone[ss] = True;
+
+		if (i < 255) {
+			int32_t bbStart = ftab[ss << 8] & CLEARMASK;
+			int32_t bbSize  = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+			int32_t shifts  = 0;
+
+			while ((bbSize >> shifts) > 65534) shifts++;
+
+			for (j = bbSize-1; j >= 0; j--) {
+				int32_t a2update   = ptr[bbStart + j];
+				uint16_t qVal      = (uint16_t)(j >> shifts);
+				quadrant[a2update] = qVal;
+				if (a2update < BZ_N_OVERSHOOT)
+					quadrant[a2update + nblock] = qVal;
+			}
+			AssertH(((bbSize-1) >> shifts) <= 65535, 1002);
+		}
+	}
+#undef runningOrder
+#undef copyStart
+#undef copyEnd
+}
+
+#undef BIGFREQ
+#undef SETMASK
+#undef CLEARMASK
+
+
+/*---------------------------------------------*/
+/* Pre:
+ *	nblock > 0
+ *	arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ *	  ((uint8_t*)arr2)[0 .. nblock-1] holds block
+ *	arr1 exists for [0 .. nblock-1]
+ *
+ * Post:
+ *	((uint8_t*)arr2) [0 .. nblock-1] holds block
+ *	All other areas of block destroyed
+ *	ftab[0 .. 65536] destroyed
+ *	arr1[0 .. nblock-1] holds sorted order
+ */
+static NOINLINE
+void BZ2_blockSort(EState* s)
+{
+	/* In original bzip2 1.0.4, it's a parameter, but 30
+	 * (which was the default) should work ok. */
+	enum { wfact = 30 };
+
+	uint32_t* ptr    = s->ptr;
+	uint8_t*  block  = s->block;
+	uint32_t* ftab   = s->ftab;
+	int32_t   nblock = s->nblock;
+	uint16_t* quadrant;
+	int32_t   budget;
+	int32_t   i;
+
+	if (nblock < 10000) {
+		fallbackSort(s->arr1, s->arr2, ftab, nblock);
+	} else {
+		/* Calculate the location for quadrant, remembering to get
+		 * the alignment right.  Assumes that &(block[0]) is at least
+		 * 2-byte aligned -- this should be ok since block is really
+		 * the first section of arr2.
+		 */
+		i = nblock + BZ_N_OVERSHOOT;
+		if (i & 1) i++;
+		quadrant = (uint16_t*)(&(block[i]));
+
+		/* (wfact-1) / 3 puts the default-factor-30
+		 * transition point at very roughly the same place as
+		 * with v0.1 and v0.9.0.
+		 * Not that it particularly matters any more, since the
+		 * resulting compressed stream is now the same regardless
+		 * of whether or not we use the main sort or fallback sort.
+		 */
+		budget = nblock * ((wfact-1) / 3);
+
+		mainSort(s, ptr, block, quadrant, ftab, nblock, &budget);
+		if (budget < 0) {
+			fallbackSort(s->arr1, s->arr2, ftab, nblock);
+		}
+	}
+
+	s->origPtr = -1;
+	for (i = 0; i < s->nblock; i++)
+		if (ptr[i] == 0) {
+			s->origPtr = i;
+			break;
+		};
+
+	AssertH(s->origPtr != -1, 1003);
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                       blocksort.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/ap/app/busybox/src/archival/libarchive/bz/bzlib.c b/ap/app/busybox/src/archival/libarchive/bz/bzlib.c
new file mode 100644
index 0000000..5f7db74
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/bz/bzlib.c
@@ -0,0 +1,429 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Library top-level functions.                          ---*/
+/*---                                               bzlib.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+/* CHANGES
+ * 0.9.0    -- original version.
+ * 0.9.0a/b -- no changes in this file.
+ * 0.9.0c   -- made zero-length BZ_FLUSH work correctly in bzCompress().
+ *             fixed bzWrite/bzRead to ignore zero-length requests.
+ *             fixed bzread to correctly handle read requests after EOF.
+ *             wrong parameter order in call to bzDecompressInit in
+ *             bzBuffToBuffDecompress.  Fixed.
+ */
+
+/* #include "bzlib_private.h" */
+
+/*---------------------------------------------------*/
+/*--- Compression stuff                           ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+#if BZ_LIGHT_DEBUG
+static
+void bz_assert_fail(int errcode)
+{
+	/* if (errcode == 1007) bb_error_msg_and_die("probably bad RAM"); */
+	bb_error_msg_and_die("internal error %d", errcode);
+}
+#endif
+
+/*---------------------------------------------------*/
+static
+void prepare_new_block(EState* s)
+{
+	int i;
+	s->nblock = 0;
+	s->numZ = 0;
+	s->state_out_pos = 0;
+	BZ_INITIALISE_CRC(s->blockCRC);
+	/* inlined memset would be nice to have here */
+	for (i = 0; i < 256; i++)
+		s->inUse[i] = 0;
+	s->blockNo++;
+}
+
+
+/*---------------------------------------------------*/
+static
+ALWAYS_INLINE
+void init_RL(EState* s)
+{
+	s->state_in_ch = 256;
+	s->state_in_len = 0;
+}
+
+
+static
+int isempty_RL(EState* s)
+{
+	return (s->state_in_ch >= 256 || s->state_in_len <= 0);
+}
+
+
+/*---------------------------------------------------*/
+static
+void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k)
+{
+	int32_t n;
+	EState* s;
+
+	s = xzalloc(sizeof(EState));
+	s->strm = strm;
+
+	n        = 100000 * blockSize100k;
+	s->arr1  = xmalloc(n                    * sizeof(uint32_t));
+	s->mtfv  = (uint16_t*)s->arr1;
+	s->ptr   = (uint32_t*)s->arr1;
+	s->arr2  = xmalloc((n + BZ_N_OVERSHOOT) * sizeof(uint32_t));
+	s->block = (uint8_t*)s->arr2;
+	s->ftab  = xmalloc(65537                * sizeof(uint32_t));
+
+	s->crc32table = crc32_filltable(NULL, 1);
+
+	s->state             = BZ_S_INPUT;
+	s->mode              = BZ_M_RUNNING;
+	s->blockSize100k     = blockSize100k;
+	s->nblockMAX         = n - 19;
+
+	strm->state          = s;
+	/*strm->total_in     = 0;*/
+	strm->total_out      = 0;
+	init_RL(s);
+	prepare_new_block(s);
+}
+
+
+/*---------------------------------------------------*/
+static
+void add_pair_to_block(EState* s)
+{
+	int32_t i;
+	uint8_t ch = (uint8_t)(s->state_in_ch);
+	for (i = 0; i < s->state_in_len; i++) {
+		BZ_UPDATE_CRC(s, s->blockCRC, ch);
+	}
+	s->inUse[s->state_in_ch] = 1;
+	switch (s->state_in_len) {
+		case 3:
+			s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+			/* fall through */
+		case 2:
+			s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+			/* fall through */
+		case 1:
+			s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+			break;
+		default:
+			s->inUse[s->state_in_len - 4] = 1;
+			s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+			s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+			s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+			s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+			s->block[s->nblock] = (uint8_t)(s->state_in_len - 4);
+			s->nblock++;
+			break;
+	}
+}
+
+
+/*---------------------------------------------------*/
+static
+void flush_RL(EState* s)
+{
+	if (s->state_in_ch < 256) add_pair_to_block(s);
+	init_RL(s);
+}
+
+
+/*---------------------------------------------------*/
+#define ADD_CHAR_TO_BLOCK(zs, zchh0) \
+{ \
+	uint32_t zchh = (uint32_t)(zchh0); \
+	/*-- fast track the common case --*/ \
+	if (zchh != zs->state_in_ch && zs->state_in_len == 1) { \
+		uint8_t ch = (uint8_t)(zs->state_in_ch); \
+		BZ_UPDATE_CRC(zs, zs->blockCRC, ch); \
+		zs->inUse[zs->state_in_ch] = 1; \
+		zs->block[zs->nblock] = (uint8_t)ch; \
+		zs->nblock++; \
+		zs->state_in_ch = zchh; \
+	} \
+	else \
+	/*-- general, uncommon cases --*/ \
+	if (zchh != zs->state_in_ch || zs->state_in_len == 255) { \
+		if (zs->state_in_ch < 256) \
+			add_pair_to_block(zs); \
+		zs->state_in_ch = zchh; \
+		zs->state_in_len = 1; \
+	} else { \
+		zs->state_in_len++; \
+	} \
+}
+
+
+/*---------------------------------------------------*/
+static
+void /*Bool*/ copy_input_until_stop(EState* s)
+{
+	/*Bool progress_in = False;*/
+
+#ifdef SAME_CODE_AS_BELOW
+	if (s->mode == BZ_M_RUNNING) {
+		/*-- fast track the common case --*/
+		while (1) {
+			/*-- no input? --*/
+			if (s->strm->avail_in == 0) break;
+			/*-- block full? --*/
+			if (s->nblock >= s->nblockMAX) break;
+			/*progress_in = True;*/
+			ADD_CHAR_TO_BLOCK(s, (uint32_t)(*(uint8_t*)(s->strm->next_in)));
+			s->strm->next_in++;
+			s->strm->avail_in--;
+			/*s->strm->total_in++;*/
+		}
+	} else
+#endif
+	{
+		/*-- general, uncommon case --*/
+		while (1) {
+			/*-- no input? --*/
+			if (s->strm->avail_in == 0) break;
+			/*-- block full? --*/
+			if (s->nblock >= s->nblockMAX) break;
+		//#	/*-- flush/finish end? --*/
+		//#	if (s->avail_in_expect == 0) break;
+			/*progress_in = True;*/
+			ADD_CHAR_TO_BLOCK(s, *(uint8_t*)(s->strm->next_in));
+			s->strm->next_in++;
+			s->strm->avail_in--;
+			/*s->strm->total_in++;*/
+		//#	s->avail_in_expect--;
+		}
+	}
+	/*return progress_in;*/
+}
+
+
+/*---------------------------------------------------*/
+static
+void /*Bool*/ copy_output_until_stop(EState* s)
+{
+	/*Bool progress_out = False;*/
+
+	while (1) {
+		/*-- no output space? --*/
+		if (s->strm->avail_out == 0) break;
+
+		/*-- block done? --*/
+		if (s->state_out_pos >= s->numZ) break;
+
+		/*progress_out = True;*/
+		*(s->strm->next_out) = s->zbits[s->state_out_pos];
+		s->state_out_pos++;
+		s->strm->avail_out--;
+		s->strm->next_out++;
+		s->strm->total_out++;
+	}
+	/*return progress_out;*/
+}
+
+
+/*---------------------------------------------------*/
+static
+void /*Bool*/ handle_compress(bz_stream *strm)
+{
+	/*Bool progress_in  = False;*/
+	/*Bool progress_out = False;*/
+	EState* s = strm->state;
+
+	while (1) {
+		if (s->state == BZ_S_OUTPUT) {
+			/*progress_out |=*/ copy_output_until_stop(s);
+			if (s->state_out_pos < s->numZ) break;
+			if (s->mode == BZ_M_FINISHING
+			//# && s->avail_in_expect == 0
+			 && s->strm->avail_in == 0
+			 && isempty_RL(s))
+				break;
+			prepare_new_block(s);
+			s->state = BZ_S_INPUT;
+#ifdef FLUSH_IS_UNUSED
+			if (s->mode == BZ_M_FLUSHING
+			 && s->avail_in_expect == 0
+			 && isempty_RL(s))
+				break;
+#endif
+		}
+
+		if (s->state == BZ_S_INPUT) {
+			/*progress_in |=*/ copy_input_until_stop(s);
+			//#if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
+			if (s->mode != BZ_M_RUNNING && s->strm->avail_in == 0) {
+				flush_RL(s);
+				BZ2_compressBlock(s, (s->mode == BZ_M_FINISHING));
+				s->state = BZ_S_OUTPUT;
+			} else
+			if (s->nblock >= s->nblockMAX) {
+				BZ2_compressBlock(s, 0);
+				s->state = BZ_S_OUTPUT;
+			} else
+			if (s->strm->avail_in == 0) {
+				break;
+			}
+		}
+	}
+
+	/*return progress_in || progress_out;*/
+}
+
+
+/*---------------------------------------------------*/
+static
+int BZ2_bzCompress(bz_stream *strm, int action)
+{
+	/*Bool progress;*/
+	EState* s;
+
+	s = strm->state;
+
+	switch (s->mode) {
+		case BZ_M_RUNNING:
+			if (action == BZ_RUN) {
+				/*progress =*/ handle_compress(strm);
+				/*return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;*/
+				return BZ_RUN_OK;
+			}
+#ifdef FLUSH_IS_UNUSED
+			else
+			if (action == BZ_FLUSH) {
+				//#s->avail_in_expect = strm->avail_in;
+				s->mode = BZ_M_FLUSHING;
+				goto case_BZ_M_FLUSHING;
+			}
+#endif
+			else
+			/*if (action == BZ_FINISH)*/ {
+				//#s->avail_in_expect = strm->avail_in;
+				s->mode = BZ_M_FINISHING;
+				goto case_BZ_M_FINISHING;
+			}
+
+#ifdef FLUSH_IS_UNUSED
+ case_BZ_M_FLUSHING:
+		case BZ_M_FLUSHING:
+			/*if (s->avail_in_expect != s->strm->avail_in)
+				return BZ_SEQUENCE_ERROR;*/
+			/*progress =*/ handle_compress(strm);
+			if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
+				return BZ_FLUSH_OK;
+			s->mode = BZ_M_RUNNING;
+			return BZ_RUN_OK;
+#endif
+
+ case_BZ_M_FINISHING:
+		/*case BZ_M_FINISHING:*/
+		default:
+			/*if (s->avail_in_expect != s->strm->avail_in)
+				return BZ_SEQUENCE_ERROR;*/
+			/*progress =*/ handle_compress(strm);
+			/*if (!progress) return BZ_SEQUENCE_ERROR;*/
+			//#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
+			//#	return BZ_FINISH_OK;
+			if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
+				return BZ_FINISH_OK;
+			/*s->mode = BZ_M_IDLE;*/
+			return BZ_STREAM_END;
+	}
+	/* return BZ_OK; --not reached--*/
+}
+
+
+/*---------------------------------------------------*/
+static
+void BZ2_bzCompressEnd(bz_stream *strm)
+{
+	EState* s;
+
+	s = strm->state;
+	free(s->arr1);
+	free(s->arr2);
+	free(s->ftab);
+	free(s->crc32table);
+	free(s);
+}
+
+
+/*---------------------------------------------------*/
+/*--- Misc convenience stuff                      ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+#ifdef EXAMPLE_CODE_FOR_MEM_TO_MEM_COMPRESSION
+static
+int BZ2_bzBuffToBuffCompress(char* dest,
+		unsigned int* destLen,
+		char*         source,
+		unsigned int  sourceLen,
+		int           blockSize100k)
+{
+	bz_stream strm;
+	int ret;
+
+	if (dest == NULL || destLen == NULL
+	 || source == NULL
+	 || blockSize100k < 1 || blockSize100k > 9
+	) {
+		return BZ_PARAM_ERROR;
+	}
+
+	BZ2_bzCompressInit(&strm, blockSize100k);
+
+	strm.next_in = source;
+	strm.next_out = dest;
+	strm.avail_in = sourceLen;
+	strm.avail_out = *destLen;
+
+	ret = BZ2_bzCompress(&strm, BZ_FINISH);
+	if (ret == BZ_FINISH_OK) goto output_overflow;
+	if (ret != BZ_STREAM_END) goto errhandler;
+
+	/* normal termination */
+	*destLen -= strm.avail_out;
+	BZ2_bzCompressEnd(&strm);
+	return BZ_OK;
+
+ output_overflow:
+	BZ2_bzCompressEnd(&strm);
+	return BZ_OUTBUFF_FULL;
+
+ errhandler:
+	BZ2_bzCompressEnd(&strm);
+	return ret;
+}
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/ap/app/busybox/src/archival/libarchive/bz/bzlib.h b/ap/app/busybox/src/archival/libarchive/bz/bzlib.h
new file mode 100644
index 0000000..1bb811c
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/bz/bzlib.h
@@ -0,0 +1,65 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Public header file for the library.                   ---*/
+/*---                                               bzlib.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+#define BZ_RUN               0
+#define BZ_FLUSH             1
+#define BZ_FINISH            2
+
+#define BZ_OK                0
+#define BZ_RUN_OK            1
+#define BZ_FLUSH_OK          2
+#define BZ_FINISH_OK         3
+#define BZ_STREAM_END        4
+#define BZ_SEQUENCE_ERROR    (-1)
+#define BZ_PARAM_ERROR       (-2)
+#define BZ_MEM_ERROR         (-3)
+#define BZ_DATA_ERROR        (-4)
+#define BZ_DATA_ERROR_MAGIC  (-5)
+#define BZ_IO_ERROR          (-6)
+#define BZ_UNEXPECTED_EOF    (-7)
+#define BZ_OUTBUFF_FULL      (-8)
+#define BZ_CONFIG_ERROR      (-9)
+
+typedef struct bz_stream {
+	void *state;
+	char *next_in;
+	char *next_out;
+	unsigned avail_in;
+	unsigned avail_out;
+	/*unsigned long long total_in;*/
+	unsigned long long total_out;
+} bz_stream;
+
+/*-- Core (low-level) library functions --*/
+
+static void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k);
+static int BZ2_bzCompress(bz_stream *strm, int action);
+#if ENABLE_FEATURE_CLEAN_UP
+static void BZ2_bzCompressEnd(bz_stream *strm);
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/ap/app/busybox/src/archival/libarchive/bz/bzlib_private.h b/ap/app/busybox/src/archival/libarchive/bz/bzlib_private.h
new file mode 100644
index 0000000..43e674b
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/bz/bzlib_private.h
@@ -0,0 +1,219 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Private header file for the library.                  ---*/
+/*---                                       bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+/* #include "bzlib.h" */
+
+/*-- General stuff. --*/
+
+typedef unsigned char Bool;
+
+#define True  ((Bool)1)
+#define False ((Bool)0)
+
+#if BZ_LIGHT_DEBUG
+static void bz_assert_fail(int errcode) NORETURN;
+#define AssertH(cond, errcode) \
+do { \
+	if (!(cond)) \
+		bz_assert_fail(errcode); \
+} while (0)
+#else
+#define AssertH(cond, msg) do { } while (0)
+#endif
+
+#if BZ_DEBUG
+#define AssertD(cond, msg) \
+do { \
+	if (!(cond)) \
+		bb_error_msg_and_die("(debug build): internal error %s", msg); \
+} while (0)
+#else
+#define AssertD(cond, msg) do { } while (0)
+#endif
+
+
+/*-- Header bytes. --*/
+
+#define BZ_HDR_B 0x42   /* 'B' */
+#define BZ_HDR_Z 0x5a   /* 'Z' */
+#define BZ_HDR_h 0x68   /* 'h' */
+#define BZ_HDR_0 0x30   /* '0' */
+
+#define BZ_HDR_BZh0 0x425a6830
+
+/*-- Constants for the back end. --*/
+
+#define BZ_MAX_ALPHA_SIZE 258
+#define BZ_MAX_CODE_LEN    23
+
+#define BZ_RUNA 0
+#define BZ_RUNB 1
+
+#define BZ_N_GROUPS 6
+#define BZ_G_SIZE   50
+#define BZ_N_ITERS  4
+
+#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
+
+
+/*-- Stuff for doing CRCs. --*/
+
+#define BZ_INITIALISE_CRC(crcVar) \
+{ \
+	crcVar = 0xffffffffL; \
+}
+
+#define BZ_FINALISE_CRC(crcVar) \
+{ \
+	crcVar = ~(crcVar); \
+}
+
+#define BZ_UPDATE_CRC(s, crcVar, cha) \
+{ \
+	crcVar = (crcVar << 8) ^ s->crc32table[(crcVar >> 24) ^ ((uint8_t)cha)]; \
+}
+
+
+/*-- States and modes for compression. --*/
+
+#define BZ_M_IDLE      1
+#define BZ_M_RUNNING   2
+#define BZ_M_FLUSHING  3
+#define BZ_M_FINISHING 4
+
+#define BZ_S_OUTPUT    1
+#define BZ_S_INPUT     2
+
+#define BZ_N_RADIX 2
+#define BZ_N_QSORT 12
+#define BZ_N_SHELL 18
+#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
+
+
+/*-- Structure holding all the compression-side stuff. --*/
+
+typedef struct EState {
+	/* pointer back to the struct bz_stream */
+	bz_stream *strm;
+
+	/* mode this stream is in, and whether inputting */
+	/* or outputting data */
+	int32_t  mode;
+	int32_t  state;
+
+	/* remembers avail_in when flush/finish requested */
+/* bbox: not needed, strm->avail_in always has the same value */
+/* commented out with '//#' throughout the code */
+	/* uint32_t avail_in_expect; */
+
+	/* for doing the block sorting */
+	int32_t  origPtr;
+	uint32_t *arr1;
+	uint32_t *arr2;
+	uint32_t *ftab;
+
+	/* aliases for arr1 and arr2 */
+	uint32_t *ptr;
+	uint8_t  *block;
+	uint16_t *mtfv;
+	uint8_t  *zbits;
+
+	/* guess what */
+	uint32_t *crc32table;
+
+	/* run-length-encoding of the input */
+	uint32_t state_in_ch;
+	int32_t  state_in_len;
+
+	/* input and output limits and current posns */
+	int32_t  nblock;
+	int32_t  nblockMAX;
+	int32_t  numZ;
+	int32_t  state_out_pos;
+
+	/* the buffer for bit stream creation */
+	uint32_t bsBuff;
+	int32_t  bsLive;
+
+	/* block and combined CRCs */
+	uint32_t blockCRC;
+	uint32_t combinedCRC;
+
+	/* misc administratium */
+	int32_t  blockNo;
+	int32_t  blockSize100k;
+
+	/* stuff for coding the MTF values */
+	int32_t  nMTF;
+
+	/* map of bytes used in block */
+	int32_t  nInUse;
+	Bool     inUse[256] ALIGNED(sizeof(long));
+	uint8_t  unseqToSeq[256];
+
+	/* stuff for coding the MTF values */
+	int32_t  mtfFreq    [BZ_MAX_ALPHA_SIZE];
+	uint8_t  selector   [BZ_MAX_SELECTORS];
+	uint8_t  selectorMtf[BZ_MAX_SELECTORS];
+
+	uint8_t  len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+
+	/* stack-saving measures: these can be local, but they are too big */
+	int32_t  sendMTFValues__code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+	int32_t  sendMTFValues__rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+#if CONFIG_BZIP2_FAST >= 5
+	/* second dimension: only 3 needed; 4 makes index calculations faster */
+	uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4];
+#endif
+	int32_t  BZ2_hbMakeCodeLengths__heap  [BZ_MAX_ALPHA_SIZE + 2];
+	int32_t  BZ2_hbMakeCodeLengths__weight[BZ_MAX_ALPHA_SIZE * 2];
+	int32_t  BZ2_hbMakeCodeLengths__parent[BZ_MAX_ALPHA_SIZE * 2];
+
+	int32_t  mainSort__runningOrder[256];
+	int32_t  mainSort__copyStart[256];
+	int32_t  mainSort__copyEnd[256];
+} EState;
+
+
+/*-- compression. --*/
+
+static void
+BZ2_blockSort(EState*);
+
+static void
+BZ2_compressBlock(EState*, int);
+
+static void
+BZ2_bsInitWrite(EState*);
+
+static void
+BZ2_hbAssignCodes(int32_t*, uint8_t*, int32_t, int32_t, int32_t);
+
+static void
+BZ2_hbMakeCodeLengths(EState*, uint8_t*, int32_t*, int32_t, int32_t);
+
+/*-------------------------------------------------------------*/
+/*--- end                                   bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/ap/app/busybox/src/archival/libarchive/bz/compress.c b/ap/app/busybox/src/archival/libarchive/bz/compress.c
new file mode 100644
index 0000000..e9f1afd
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/bz/compress.c
@@ -0,0 +1,680 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Compression machinery (not incl block sorting)        ---*/
+/*---                                            compress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+/* CHANGES
+ * 0.9.0    -- original version.
+ * 0.9.0a/b -- no changes in this file.
+ * 0.9.0c   -- changed setting of nGroups in sendMTFValues()
+ *             so as to do a bit better on small files
+*/
+
+/* #include "bzlib_private.h" */
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O                              ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void BZ2_bsInitWrite(EState* s)
+{
+	s->bsLive = 0;
+	s->bsBuff = 0;
+}
+
+
+/*---------------------------------------------------*/
+static NOINLINE
+void bsFinishWrite(EState* s)
+{
+	while (s->bsLive > 0) {
+		s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24);
+		s->numZ++;
+		s->bsBuff <<= 8;
+		s->bsLive -= 8;
+	}
+}
+
+
+/*---------------------------------------------------*/
+static
+/* Helps only on level 5, on other levels hurts. ? */
+#if CONFIG_BZIP2_FAST >= 5
+ALWAYS_INLINE
+#endif
+void bsW(EState* s, int32_t n, uint32_t v)
+{
+	while (s->bsLive >= 8) {
+		s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24);
+		s->numZ++;
+		s->bsBuff <<= 8;
+		s->bsLive -= 8;
+	}
+	s->bsBuff |= (v << (32 - s->bsLive - n));
+	s->bsLive += n;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutU32(EState* s, unsigned u)
+{
+	bsW(s, 8, (u >> 24) & 0xff);
+	bsW(s, 8, (u >> 16) & 0xff);
+	bsW(s, 8, (u >>  8) & 0xff);
+	bsW(s, 8,  u        & 0xff);
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutU16(EState* s, unsigned u)
+{
+	bsW(s, 8, (u >>  8) & 0xff);
+	bsW(s, 8,  u        & 0xff);
+}
+
+
+/*---------------------------------------------------*/
+/*--- The back end proper                         ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void makeMaps_e(EState* s)
+{
+	int i;
+	s->nInUse = 0;
+	for (i = 0; i < 256; i++) {
+		if (s->inUse[i]) {
+			s->unseqToSeq[i] = s->nInUse;
+			s->nInUse++;
+		}
+	}
+}
+
+
+/*---------------------------------------------------*/
+static NOINLINE
+void generateMTFValues(EState* s)
+{
+	uint8_t yy[256];
+	int32_t i, j;
+	int32_t zPend;
+	int32_t wr;
+	int32_t EOB;
+
+	/*
+	 * After sorting (eg, here),
+	 * s->arr1[0 .. s->nblock-1] holds sorted order,
+	 * and
+	 * ((uint8_t*)s->arr2)[0 .. s->nblock-1]
+	 * holds the original block data.
+	 *
+	 * The first thing to do is generate the MTF values,
+	 * and put them in ((uint16_t*)s->arr1)[0 .. s->nblock-1].
+	 *
+	 * Because there are strictly fewer or equal MTF values
+	 * than block values, ptr values in this area are overwritten
+	 * with MTF values only when they are no longer needed.
+	 *
+	 * The final compressed bitstream is generated into the
+	 * area starting at &((uint8_t*)s->arr2)[s->nblock]
+	 *
+	 * These storage aliases are set up in bzCompressInit(),
+	 * except for the last one, which is arranged in
+	 * compressBlock().
+	 */
+	uint32_t* ptr   = s->ptr;
+	uint8_t*  block = s->block;
+	uint16_t* mtfv  = s->mtfv;
+
+	makeMaps_e(s);
+	EOB = s->nInUse+1;
+
+	for (i = 0; i <= EOB; i++)
+		s->mtfFreq[i] = 0;
+
+	wr = 0;
+	zPend = 0;
+	for (i = 0; i < s->nInUse; i++)
+		yy[i] = (uint8_t) i;
+
+	for (i = 0; i < s->nblock; i++) {
+		uint8_t ll_i;
+		AssertD(wr <= i, "generateMTFValues(1)");
+		j = ptr[i] - 1;
+		if (j < 0)
+			j += s->nblock;
+		ll_i = s->unseqToSeq[block[j]];
+		AssertD(ll_i < s->nInUse, "generateMTFValues(2a)");
+
+		if (yy[0] == ll_i) {
+			zPend++;
+		} else {
+			if (zPend > 0) {
+				zPend--;
+				while (1) {
+					if (zPend & 1) {
+						mtfv[wr] = BZ_RUNB; wr++;
+						s->mtfFreq[BZ_RUNB]++;
+					} else {
+						mtfv[wr] = BZ_RUNA; wr++;
+						s->mtfFreq[BZ_RUNA]++;
+					}
+					if (zPend < 2) break;
+					zPend = (uint32_t)(zPend - 2) / 2;
+					/* bbox: unsigned div is easier */
+				};
+				zPend = 0;
+			}
+			{
+				register uint8_t  rtmp;
+				register uint8_t* ryy_j;
+				register uint8_t  rll_i;
+				rtmp  = yy[1];
+				yy[1] = yy[0];
+				ryy_j = &(yy[1]);
+				rll_i = ll_i;
+				while (rll_i != rtmp) {
+					register uint8_t rtmp2;
+					ryy_j++;
+					rtmp2  = rtmp;
+					rtmp   = *ryy_j;
+					*ryy_j = rtmp2;
+				};
+				yy[0] = rtmp;
+				j = ryy_j - &(yy[0]);
+				mtfv[wr] = j+1;
+				wr++;
+				s->mtfFreq[j+1]++;
+			}
+		}
+	}
+
+	if (zPend > 0) {
+		zPend--;
+		while (1) {
+			if (zPend & 1) {
+				mtfv[wr] = BZ_RUNB;
+				wr++;
+				s->mtfFreq[BZ_RUNB]++;
+			} else {
+				mtfv[wr] = BZ_RUNA;
+				wr++;
+				s->mtfFreq[BZ_RUNA]++;
+			}
+			if (zPend < 2)
+				break;
+			zPend = (uint32_t)(zPend - 2) / 2;
+			/* bbox: unsigned div is easier */
+		};
+		zPend = 0;
+	}
+
+	mtfv[wr] = EOB;
+	wr++;
+	s->mtfFreq[EOB]++;
+
+	s->nMTF = wr;
+}
+
+
+/*---------------------------------------------------*/
+#define BZ_LESSER_ICOST  0
+#define BZ_GREATER_ICOST 15
+
+static NOINLINE
+void sendMTFValues(EState* s)
+{
+	int32_t v, t, i, j, gs, ge, totc, bt, bc, iter;
+	int32_t nSelectors, alphaSize, minLen, maxLen, selCtr;
+	int32_t nGroups;
+
+	/*
+	 * uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+	 * is a global since the decoder also needs it.
+	 *
+	 * int32_t  code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+	 * int32_t  rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+	 * are also globals only used in this proc.
+	 * Made global to keep stack frame size small.
+	 */
+#define code     sendMTFValues__code
+#define rfreq    sendMTFValues__rfreq
+#define len_pack sendMTFValues__len_pack
+
+	uint16_t cost[BZ_N_GROUPS];
+	int32_t  fave[BZ_N_GROUPS];
+
+	uint16_t* mtfv = s->mtfv;
+
+	alphaSize = s->nInUse + 2;
+	for (t = 0; t < BZ_N_GROUPS; t++)
+		for (v = 0; v < alphaSize; v++)
+			s->len[t][v] = BZ_GREATER_ICOST;
+
+	/*--- Decide how many coding tables to use ---*/
+	AssertH(s->nMTF > 0, 3001);
+	if (s->nMTF < 200)  nGroups = 2; else
+	if (s->nMTF < 600)  nGroups = 3; else
+	if (s->nMTF < 1200) nGroups = 4; else
+	if (s->nMTF < 2400) nGroups = 5; else
+	nGroups = 6;
+
+	/*--- Generate an initial set of coding tables ---*/
+	{
+		int32_t nPart, remF, tFreq, aFreq;
+
+		nPart = nGroups;
+		remF  = s->nMTF;
+		gs = 0;
+		while (nPart > 0) {
+			tFreq = remF / nPart;
+			ge = gs - 1;
+			aFreq = 0;
+			while (aFreq < tFreq && ge < alphaSize-1) {
+				ge++;
+				aFreq += s->mtfFreq[ge];
+			}
+
+			if (ge > gs
+			 && nPart != nGroups && nPart != 1
+			 && ((nGroups - nPart) % 2 == 1) /* bbox: can this be replaced by x & 1? */
+			) {
+				aFreq -= s->mtfFreq[ge];
+				ge--;
+			}
+
+			for (v = 0; v < alphaSize; v++)
+				if (v >= gs && v <= ge)
+					s->len[nPart-1][v] = BZ_LESSER_ICOST;
+				else
+					s->len[nPart-1][v] = BZ_GREATER_ICOST;
+
+			nPart--;
+			gs = ge + 1;
+			remF -= aFreq;
+		}
+	}
+
+	/*
+	 * Iterate up to BZ_N_ITERS times to improve the tables.
+	 */
+	for (iter = 0; iter < BZ_N_ITERS; iter++) {
+		for (t = 0; t < nGroups; t++)
+			fave[t] = 0;
+
+		for (t = 0; t < nGroups; t++)
+			for (v = 0; v < alphaSize; v++)
+				s->rfreq[t][v] = 0;
+
+#if CONFIG_BZIP2_FAST >= 5
+		/*
+		 * Set up an auxiliary length table which is used to fast-track
+		 * the common case (nGroups == 6).
+		 */
+		if (nGroups == 6) {
+			for (v = 0; v < alphaSize; v++) {
+				s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
+				s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
+				s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
+			}
+		}
+#endif
+		nSelectors = 0;
+		totc = 0;
+		gs = 0;
+		while (1) {
+			/*--- Set group start & end marks. --*/
+			if (gs >= s->nMTF)
+				break;
+			ge = gs + BZ_G_SIZE - 1;
+			if (ge >= s->nMTF)
+				ge = s->nMTF-1;
+
+			/*
+			 * Calculate the cost of this group as coded
+			 * by each of the coding tables.
+			 */
+			for (t = 0; t < nGroups; t++)
+				cost[t] = 0;
+#if CONFIG_BZIP2_FAST >= 5
+			if (nGroups == 6 && 50 == ge-gs+1) {
+				/*--- fast track the common case ---*/
+				register uint32_t cost01, cost23, cost45;
+				register uint16_t icv;
+				cost01 = cost23 = cost45 = 0;
+#define BZ_ITER(nn) \
+	icv = mtfv[gs+(nn)]; \
+	cost01 += s->len_pack[icv][0]; \
+	cost23 += s->len_pack[icv][1]; \
+	cost45 += s->len_pack[icv][2];
+				BZ_ITER(0);  BZ_ITER(1);  BZ_ITER(2);  BZ_ITER(3);  BZ_ITER(4);
+				BZ_ITER(5);  BZ_ITER(6);  BZ_ITER(7);  BZ_ITER(8);  BZ_ITER(9);
+				BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
+				BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
+				BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
+				BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
+				BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
+				BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
+				BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
+				BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
+#undef BZ_ITER
+				cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
+				cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
+				cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
+
+			} else
+#endif
+			{
+				/*--- slow version which correctly handles all situations ---*/
+				for (i = gs; i <= ge; i++) {
+					uint16_t icv = mtfv[i];
+					for (t = 0; t < nGroups; t++)
+						cost[t] += s->len[t][icv];
+				}
+			}
+			/*
+			 * Find the coding table which is best for this group,
+			 * and record its identity in the selector table.
+			 */
+			/*bc = 999999999;*/
+			/*bt = -1;*/
+			bc = cost[0];
+			bt = 0;
+			for (t = 1 /*0*/; t < nGroups; t++) {
+				if (cost[t] < bc) {
+					bc = cost[t];
+					bt = t;
+				}
+			}
+			totc += bc;
+			fave[bt]++;
+			s->selector[nSelectors] = bt;
+			nSelectors++;
+
+			/*
+			 * Increment the symbol frequencies for the selected table.
+			 */
+/* 1% faster compress. +800 bytes */
+#if CONFIG_BZIP2_FAST >= 4
+			if (nGroups == 6 && 50 == ge-gs+1) {
+				/*--- fast track the common case ---*/
+#define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++
+				BZ_ITUR(0);  BZ_ITUR(1);  BZ_ITUR(2);  BZ_ITUR(3);  BZ_ITUR(4);
+				BZ_ITUR(5);  BZ_ITUR(6);  BZ_ITUR(7);  BZ_ITUR(8);  BZ_ITUR(9);
+				BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
+				BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
+				BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
+				BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
+				BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
+				BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
+				BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
+				BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
+#undef BZ_ITUR
+				gs = ge + 1;
+			} else
+#endif
+			{
+				/*--- slow version which correctly handles all situations ---*/
+				while (gs <= ge) {
+					s->rfreq[bt][mtfv[gs]]++;
+					gs++;
+				}
+				/* already is: gs = ge + 1; */
+			}
+		}
+
+		/*
+		 * Recompute the tables based on the accumulated frequencies.
+		 */
+		/* maxLen was changed from 20 to 17 in bzip2-1.0.3.  See
+		 * comment in huffman.c for details. */
+		for (t = 0; t < nGroups; t++)
+			BZ2_hbMakeCodeLengths(s, &(s->len[t][0]), &(s->rfreq[t][0]), alphaSize, 17 /*20*/);
+	}
+
+	AssertH(nGroups < 8, 3002);
+	AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003);
+
+	/*--- Compute MTF values for the selectors. ---*/
+	{
+		uint8_t pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
+
+		for (i = 0; i < nGroups; i++)
+			pos[i] = i;
+		for (i = 0; i < nSelectors; i++) {
+			ll_i = s->selector[i];
+			j = 0;
+			tmp = pos[j];
+			while (ll_i != tmp) {
+				j++;
+				tmp2 = tmp;
+				tmp = pos[j];
+				pos[j] = tmp2;
+			};
+			pos[0] = tmp;
+			s->selectorMtf[i] = j;
+		}
+	};
+
+	/*--- Assign actual codes for the tables. --*/
+	for (t = 0; t < nGroups; t++) {
+		minLen = 32;
+		maxLen = 0;
+		for (i = 0; i < alphaSize; i++) {
+			if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+			if (s->len[t][i] < minLen) minLen = s->len[t][i];
+		}
+		AssertH(!(maxLen > 17 /*20*/), 3004);
+		AssertH(!(minLen < 1), 3005);
+		BZ2_hbAssignCodes(&(s->code[t][0]), &(s->len[t][0]), minLen, maxLen, alphaSize);
+	}
+
+	/*--- Transmit the mapping table. ---*/
+	{
+		/* bbox: optimized a bit more than in bzip2 */
+		int inUse16 = 0;
+		for (i = 0; i < 16; i++) {
+			if (sizeof(long) <= 4) {
+				inUse16 = inUse16*2 +
+					((*(uint32_t*)&(s->inUse[i * 16 + 0])
+					| *(uint32_t*)&(s->inUse[i * 16 + 4])
+					| *(uint32_t*)&(s->inUse[i * 16 + 8])
+					| *(uint32_t*)&(s->inUse[i * 16 + 12])) != 0);
+			} else { /* Our CPU can do better */
+				inUse16 = inUse16*2 +
+					((*(uint64_t*)&(s->inUse[i * 16 + 0])
+					| *(uint64_t*)&(s->inUse[i * 16 + 8])) != 0);
+			}
+		}
+
+		bsW(s, 16, inUse16);
+
+		inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */
+		for (i = 0; i < 16; i++) {
+			if (inUse16 < 0) {
+				unsigned v16 = 0;
+				for (j = 0; j < 16; j++)
+					v16 = v16*2 + s->inUse[i * 16 + j];
+				bsW(s, 16, v16);
+			}
+			inUse16 <<= 1;
+		}
+	}
+
+	/*--- Now the selectors. ---*/
+	bsW(s, 3, nGroups);
+	bsW(s, 15, nSelectors);
+	for (i = 0; i < nSelectors; i++) {
+		for (j = 0; j < s->selectorMtf[i]; j++)
+			bsW(s, 1, 1);
+		bsW(s, 1, 0);
+	}
+
+	/*--- Now the coding tables. ---*/
+	for (t = 0; t < nGroups; t++) {
+		int32_t curr = s->len[t][0];
+		bsW(s, 5, curr);
+		for (i = 0; i < alphaSize; i++) {
+			while (curr < s->len[t][i]) { bsW(s, 2, 2); curr++; /* 10 */ };
+			while (curr > s->len[t][i]) { bsW(s, 2, 3); curr--; /* 11 */ };
+			bsW(s, 1, 0);
+		}
+	}
+
+	/*--- And finally, the block data proper ---*/
+	selCtr = 0;
+	gs = 0;
+	while (1) {
+		if (gs >= s->nMTF)
+			break;
+		ge = gs + BZ_G_SIZE - 1;
+		if (ge >= s->nMTF)
+			ge = s->nMTF-1;
+		AssertH(s->selector[selCtr] < nGroups, 3006);
+
+/* Costs 1300 bytes and is _slower_ (on Intel Core 2) */
+#if 0
+		if (nGroups == 6 && 50 == ge-gs+1) {
+			/*--- fast track the common case ---*/
+			uint16_t mtfv_i;
+			uint8_t* s_len_sel_selCtr  = &(s->len[s->selector[selCtr]][0]);
+			int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]);
+#define BZ_ITAH(nn) \
+	mtfv_i = mtfv[gs+(nn)]; \
+	bsW(s, s_len_sel_selCtr[mtfv_i], s_code_sel_selCtr[mtfv_i])
+			BZ_ITAH(0);  BZ_ITAH(1);  BZ_ITAH(2);  BZ_ITAH(3);  BZ_ITAH(4);
+			BZ_ITAH(5);  BZ_ITAH(6);  BZ_ITAH(7);  BZ_ITAH(8);  BZ_ITAH(9);
+			BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
+			BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
+			BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
+			BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
+			BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
+			BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
+			BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
+			BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
+#undef BZ_ITAH
+			gs = ge+1;
+		} else
+#endif
+		{
+			/*--- slow version which correctly handles all situations ---*/
+			/* code is bit bigger, but moves multiply out of the loop */
+			uint8_t* s_len_sel_selCtr  = &(s->len [s->selector[selCtr]][0]);
+			int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]);
+			while (gs <= ge) {
+				bsW(s,
+					s_len_sel_selCtr[mtfv[gs]],
+					s_code_sel_selCtr[mtfv[gs]]
+				);
+				gs++;
+			}
+			/* already is: gs = ge+1; */
+		}
+		selCtr++;
+	}
+	AssertH(selCtr == nSelectors, 3007);
+#undef code
+#undef rfreq
+#undef len_pack
+}
+
+
+/*---------------------------------------------------*/
+static
+void BZ2_compressBlock(EState* s, int is_last_block)
+{
+	if (s->nblock > 0) {
+		BZ_FINALISE_CRC(s->blockCRC);
+		s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
+		s->combinedCRC ^= s->blockCRC;
+		if (s->blockNo > 1)
+			s->numZ = 0;
+
+		BZ2_blockSort(s);
+	}
+
+	s->zbits = &((uint8_t*)s->arr2)[s->nblock];
+
+	/*-- If this is the first block, create the stream header. --*/
+	if (s->blockNo == 1) {
+		BZ2_bsInitWrite(s);
+		/*bsPutU8(s, BZ_HDR_B);*/
+		/*bsPutU8(s, BZ_HDR_Z);*/
+		/*bsPutU8(s, BZ_HDR_h);*/
+		/*bsPutU8(s, BZ_HDR_0 + s->blockSize100k);*/
+		bsPutU32(s, BZ_HDR_BZh0 + s->blockSize100k);
+	}
+
+	if (s->nblock > 0) {
+		/*bsPutU8(s, 0x31);*/
+		/*bsPutU8(s, 0x41);*/
+		/*bsPutU8(s, 0x59);*/
+		/*bsPutU8(s, 0x26);*/
+		bsPutU32(s, 0x31415926);
+		/*bsPutU8(s, 0x53);*/
+		/*bsPutU8(s, 0x59);*/
+		bsPutU16(s, 0x5359);
+
+		/*-- Now the block's CRC, so it is in a known place. --*/
+		bsPutU32(s, s->blockCRC);
+
+		/*
+		 * Now a single bit indicating (non-)randomisation.
+		 * As of version 0.9.5, we use a better sorting algorithm
+		 * which makes randomisation unnecessary.  So always set
+		 * the randomised bit to 'no'.  Of course, the decoder
+		 * still needs to be able to handle randomised blocks
+		 * so as to maintain backwards compatibility with
+		 * older versions of bzip2.
+		 */
+		bsW(s, 1, 0);
+
+		bsW(s, 24, s->origPtr);
+		generateMTFValues(s);
+		sendMTFValues(s);
+	}
+
+	/*-- If this is the last block, add the stream trailer. --*/
+	if (is_last_block) {
+		/*bsPutU8(s, 0x17);*/
+		/*bsPutU8(s, 0x72);*/
+		/*bsPutU8(s, 0x45);*/
+		/*bsPutU8(s, 0x38);*/
+		bsPutU32(s, 0x17724538);
+		/*bsPutU8(s, 0x50);*/
+		/*bsPutU8(s, 0x90);*/
+		bsPutU16(s, 0x5090);
+		bsPutU32(s, s->combinedCRC);
+		bsFinishWrite(s);
+	}
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                        compress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/ap/app/busybox/src/archival/libarchive/bz/huffman.c b/ap/app/busybox/src/archival/libarchive/bz/huffman.c
new file mode 100644
index 0000000..bbec11a
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/bz/huffman.c
@@ -0,0 +1,229 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Huffman coding low-level stuff                        ---*/
+/*---                                             huffman.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+/* #include "bzlib_private.h" */
+
+/*---------------------------------------------------*/
+#define WEIGHTOF(zz0)  ((zz0) & 0xffffff00)
+#define DEPTHOF(zz1)   ((zz1) & 0x000000ff)
+#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
+
+#define ADDWEIGHTS(zw1,zw2) \
+	(WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \
+	(1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
+
+#define UPHEAP(z) \
+{ \
+	int32_t zz, tmp; \
+	zz = z; \
+	tmp = heap[zz]; \
+	while (weight[tmp] < weight[heap[zz >> 1]]) { \
+		heap[zz] = heap[zz >> 1]; \
+		zz >>= 1; \
+	} \
+	heap[zz] = tmp; \
+}
+
+
+/* 90 bytes, 0.3% of overall compress speed */
+#if CONFIG_BZIP2_FAST >= 1
+
+/* macro works better than inline (gcc 4.2.1) */
+#define DOWNHEAP1(heap, weight, Heap) \
+{ \
+	int32_t zz, yy, tmp; \
+	zz = 1; \
+	tmp = heap[zz]; \
+	while (1) { \
+		yy = zz << 1; \
+		if (yy > nHeap) \
+			break; \
+		if (yy < nHeap \
+		 && weight[heap[yy+1]] < weight[heap[yy]]) \
+			yy++; \
+		if (weight[tmp] < weight[heap[yy]]) \
+			break; \
+		heap[zz] = heap[yy]; \
+		zz = yy; \
+	} \
+	heap[zz] = tmp; \
+}
+
+#else
+
+static
+void DOWNHEAP1(int32_t *heap, int32_t *weight, int32_t nHeap)
+{
+	int32_t zz, yy, tmp;
+	zz = 1;
+	tmp = heap[zz];
+	while (1) {
+		yy = zz << 1;
+		if (yy > nHeap)
+			break;
+		if (yy < nHeap
+		 && weight[heap[yy + 1]] < weight[heap[yy]])
+			yy++;
+		if (weight[tmp] < weight[heap[yy]])
+			break;
+		heap[zz] = heap[yy];
+		zz = yy;
+	}
+	heap[zz] = tmp;
+}
+
+#endif
+
+/*---------------------------------------------------*/
+static
+void BZ2_hbMakeCodeLengths(EState *s,
+		uint8_t *len,
+		int32_t *freq,
+		int32_t alphaSize,
+		int32_t maxLen)
+{
+	/*
+	 * Nodes and heap entries run from 1.  Entry 0
+	 * for both the heap and nodes is a sentinel.
+	 */
+	int32_t nNodes, nHeap, n1, n2, i, j, k;
+	Bool  tooLong;
+
+	/* bbox: moved to EState to save stack
+	int32_t heap  [BZ_MAX_ALPHA_SIZE + 2];
+	int32_t weight[BZ_MAX_ALPHA_SIZE * 2];
+	int32_t parent[BZ_MAX_ALPHA_SIZE * 2];
+	*/
+#define heap   (s->BZ2_hbMakeCodeLengths__heap)
+#define weight (s->BZ2_hbMakeCodeLengths__weight)
+#define parent (s->BZ2_hbMakeCodeLengths__parent)
+
+	for (i = 0; i < alphaSize; i++)
+		weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+
+	while (1) {
+		nNodes = alphaSize;
+		nHeap = 0;
+
+		heap[0] = 0;
+		weight[0] = 0;
+		parent[0] = -2;
+
+		for (i = 1; i <= alphaSize; i++) {
+			parent[i] = -1;
+			nHeap++;
+			heap[nHeap] = i;
+			UPHEAP(nHeap);
+		}
+
+		AssertH(nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001);
+
+		while (nHeap > 1) {
+			n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap);
+			n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap);
+			nNodes++;
+			parent[n1] = parent[n2] = nNodes;
+			weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
+			parent[nNodes] = -1;
+			nHeap++;
+			heap[nHeap] = nNodes;
+			UPHEAP(nHeap);
+		}
+
+		AssertH(nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002);
+
+		tooLong = False;
+		for (i = 1; i <= alphaSize; i++) {
+			j = 0;
+			k = i;
+			while (parent[k] >= 0) {
+				k = parent[k];
+				j++;
+			}
+			len[i-1] = j;
+			if (j > maxLen)
+				tooLong = True;
+		}
+
+		if (!tooLong)
+			break;
+
+		/* 17 Oct 04: keep-going condition for the following loop used
+		to be 'i < alphaSize', which missed the last element,
+		theoretically leading to the possibility of the compressor
+		looping.  However, this count-scaling step is only needed if
+		one of the generated Huffman code words is longer than
+		maxLen, which up to and including version 1.0.2 was 20 bits,
+		which is extremely unlikely.  In version 1.0.3 maxLen was
+		changed to 17 bits, which has minimal effect on compression
+		ratio, but does mean this scaling step is used from time to
+		time, enough to verify that it works.
+
+		This means that bzip2-1.0.3 and later will only produce
+		Huffman codes with a maximum length of 17 bits.  However, in
+		order to preserve backwards compatibility with bitstreams
+		produced by versions pre-1.0.3, the decompressor must still
+		handle lengths of up to 20. */
+
+		for (i = 1; i <= alphaSize; i++) {
+			j = weight[i] >> 8;
+			/* bbox: yes, it is a signed division.
+			 * don't replace with shift! */
+			j = 1 + (j / 2);
+			weight[i] = j << 8;
+		}
+	}
+#undef heap
+#undef weight
+#undef parent
+}
+
+
+/*---------------------------------------------------*/
+static
+void BZ2_hbAssignCodes(int32_t *code,
+		uint8_t *length,
+		int32_t minLen,
+		int32_t maxLen,
+		int32_t alphaSize)
+{
+	int32_t n, vec, i;
+
+	vec = 0;
+	for (n = minLen; n <= maxLen; n++) {
+		for (i = 0; i < alphaSize; i++) {
+			if (length[i] == n) {
+				code[i] = vec;
+				vec++;
+			};
+		}
+		vec <<= 1;
+	}
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                         huffman.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/ap/app/busybox/src/archival/libarchive/data_align.c b/ap/app/busybox/src/archival/libarchive/data_align.c
new file mode 100644
index 0000000..a6b84a4
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/data_align.c
@@ -0,0 +1,15 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary)
+{
+	unsigned skip_amount = (boundary - (archive_handle->offset % boundary)) % boundary;
+
+	archive_handle->seek(archive_handle->src_fd, skip_amount);
+	archive_handle->offset += skip_amount;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/data_extract_all.c b/ap/app/busybox/src/archival/libarchive/data_extract_all.c
new file mode 100644
index 0000000..3f67b83
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/data_extract_all.c
@@ -0,0 +1,200 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
+{
+	file_header_t *file_header = archive_handle->file_header;
+	int dst_fd;
+	int res;
+
+#if ENABLE_FEATURE_TAR_SELINUX
+	char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
+	if (!sctx)
+		sctx = archive_handle->tar__sctx[PAX_GLOBAL];
+	if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
+		setfscreatecon(sctx);
+		free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
+		archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
+	}
+#endif
+
+	if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) {
+		char *slash = strrchr(file_header->name, '/');
+		if (slash) {
+			*slash = '\0';
+			bb_make_directory(file_header->name, -1, FILEUTILS_RECUR);
+			*slash = '/';
+		}
+	}
+
+	if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) {
+		/* Remove the entry if it exists */
+		if (!S_ISDIR(file_header->mode)) {
+			/* Is it hardlink?
+			 * We encode hard links as regular files of size 0 with a symlink */
+			if (S_ISREG(file_header->mode)
+			 && file_header->link_target
+			 && file_header->size == 0
+			) {
+				/* Ugly special case:
+				 * tar cf t.tar hardlink1 hardlink2 hardlink1
+				 * results in this tarball structure:
+				 * hardlink1
+				 * hardlink2 -> hardlink1
+				 * hardlink1 -> hardlink1 <== !!!
+				 */
+				if (strcmp(file_header->link_target, file_header->name) == 0)
+					goto ret;
+			}
+			/* Proceed with deleting */
+			if (unlink(file_header->name) == -1
+			 && errno != ENOENT
+			) {
+				bb_perror_msg_and_die("can't remove old file %s",
+						file_header->name);
+			}
+		}
+	}
+	else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) {
+		/* Remove the existing entry if its older than the extracted entry */
+		struct stat existing_sb;
+		if (lstat(file_header->name, &existing_sb) == -1) {
+			if (errno != ENOENT) {
+				bb_perror_msg_and_die("can't stat old file");
+			}
+		}
+		else if (existing_sb.st_mtime >= file_header->mtime) {
+			if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
+			 && !S_ISDIR(file_header->mode)
+			) {
+				bb_error_msg("%s not created: newer or "
+					"same age file exists", file_header->name);
+			}
+			data_skip(archive_handle);
+			goto ret;
+		}
+		else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
+			bb_perror_msg_and_die("can't remove old file %s",
+					file_header->name);
+		}
+	}
+
+	/* Handle hard links separately
+	 * We encode hard links as regular files of size 0 with a symlink */
+	if (S_ISREG(file_header->mode)
+	 && file_header->link_target
+	 && file_header->size == 0
+	) {
+		/* hard link */
+		res = link(file_header->link_target, file_header->name);
+		if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
+			bb_perror_msg("can't create %slink "
+					"from %s to %s", "hard",
+					file_header->name,
+					file_header->link_target);
+		}
+		/* Hardlinks have no separate mode/ownership, skip chown/chmod */
+		goto ret;
+	}
+
+	/* Create the filesystem entry */
+	switch (file_header->mode & S_IFMT) {
+	case S_IFREG: {
+		/* Regular file */
+		int flags = O_WRONLY | O_CREAT | O_EXCL;
+		if (archive_handle->ah_flags & ARCHIVE_O_TRUNC)
+			flags = O_WRONLY | O_CREAT | O_TRUNC;
+		dst_fd = xopen3(file_header->name,
+			flags,
+			file_header->mode
+			);
+		bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size);
+		close(dst_fd);
+		break;
+	}
+	case S_IFDIR:
+		res = mkdir(file_header->name, file_header->mode);
+		if ((res == -1)
+		 && (errno != EISDIR) /* btw, Linux doesn't return this */
+		 && (errno != EEXIST)
+		 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
+		) {
+			bb_perror_msg("can't make dir %s", file_header->name);
+		}
+		break;
+	case S_IFLNK:
+		/* Symlink */
+//TODO: what if file_header->link_target == NULL (say, corrupted tarball?)
+		res = symlink(file_header->link_target, file_header->name);
+		if ((res == -1)
+		 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
+		) {
+			bb_perror_msg("can't create %slink "
+				"from %s to %s", "sym",
+				file_header->name,
+				file_header->link_target);
+		}
+		break;
+	case S_IFSOCK:
+	case S_IFBLK:
+	case S_IFCHR:
+	case S_IFIFO:
+		res = mknod(file_header->name, file_header->mode, file_header->device);
+		if ((res == -1)
+		 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
+		) {
+			bb_perror_msg("can't create node %s", file_header->name);
+		}
+		break;
+	default:
+		bb_error_msg_and_die("unrecognized file type");
+	}
+
+	if (!S_ISLNK(file_header->mode)) {
+		if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) {
+			uid_t uid = file_header->uid;
+			gid_t gid = file_header->gid;
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+			if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) {
+				if (file_header->tar__uname) {
+//TODO: cache last name/id pair?
+					struct passwd *pwd = getpwnam(file_header->tar__uname);
+					if (pwd) uid = pwd->pw_uid;
+				}
+				if (file_header->tar__gname) {
+					struct group *grp = getgrnam(file_header->tar__gname);
+					if (grp) gid = grp->gr_gid;
+				}
+			}
+#endif
+			/* GNU tar 1.15.1 uses chown, not lchown */
+			chown(file_header->name, uid, gid);
+		}
+		/* uclibc has no lchmod, glibc is even stranger -
+		 * it has lchmod which seems to do nothing!
+		 * so we use chmod... */
+		if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) {
+			chmod(file_header->name, file_header->mode);
+		}
+		if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) {
+			struct timeval t[2];
+
+			t[1].tv_sec = t[0].tv_sec = file_header->mtime;
+			t[1].tv_usec = t[0].tv_usec = 0;
+			utimes(file_header->name, t);
+		}
+	}
+
+ ret: ;
+#if ENABLE_FEATURE_TAR_SELINUX
+	if (sctx) {
+		/* reset the context after creating an entry */
+		setfscreatecon(NULL);
+	}
+#endif
+}
diff --git a/ap/app/busybox/src/archival/libarchive/data_extract_to_command.c b/ap/app/busybox/src/archival/libarchive/data_extract_to_command.c
new file mode 100644
index 0000000..a2ce33b
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/data_extract_to_command.c
@@ -0,0 +1,138 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+enum {
+	//TAR_FILETYPE,
+	TAR_MODE,
+	TAR_FILENAME,
+	TAR_REALNAME,
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+	TAR_UNAME,
+	TAR_GNAME,
+#endif
+	TAR_SIZE,
+	TAR_UID,
+	TAR_GID,
+	TAR_MAX,
+};
+
+static const char *const tar_var[] = {
+	// "FILETYPE",
+	"MODE",
+	"FILENAME",
+	"REALNAME",
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+	"UNAME",
+	"GNAME",
+#endif
+	"SIZE",
+	"UID",
+	"GID",
+};
+
+static void xputenv(char *str)
+{
+	if (putenv(str))
+		bb_error_msg_and_die(bb_msg_memory_exhausted);
+}
+
+static void str2env(char *env[], int idx, const char *str)
+{
+	env[idx] = xasprintf("TAR_%s=%s", tar_var[idx], str);
+	xputenv(env[idx]);
+}
+
+static void dec2env(char *env[], int idx, unsigned long long val)
+{
+	env[idx] = xasprintf("TAR_%s=%llu", tar_var[idx], val);
+	xputenv(env[idx]);
+}
+
+static void oct2env(char *env[], int idx, unsigned long val)
+{
+	env[idx] = xasprintf("TAR_%s=%lo", tar_var[idx], val);
+	xputenv(env[idx]);
+}
+
+void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle)
+{
+	file_header_t *file_header = archive_handle->file_header;
+
+#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */
+	char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
+	if (!sctx)
+		sctx = archive_handle->tar__sctx[PAX_GLOBAL];
+	if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
+		setfscreatecon(sctx);
+		free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
+		archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
+	}
+#endif
+
+	if ((file_header->mode & S_IFMT) == S_IFREG) {
+		pid_t pid;
+		int p[2], status;
+		char *tar_env[TAR_MAX];
+
+		memset(tar_env, 0, sizeof(tar_env));
+
+		xpipe(p);
+		pid = BB_MMU ? xfork() : xvfork();
+		if (pid == 0) {
+			/* Child */
+			/* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */
+			oct2env(tar_env, TAR_MODE, file_header->mode);
+			str2env(tar_env, TAR_FILENAME, file_header->name);
+			str2env(tar_env, TAR_REALNAME, file_header->name);
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+			str2env(tar_env, TAR_UNAME, file_header->tar__uname);
+			str2env(tar_env, TAR_GNAME, file_header->tar__gname);
+#endif
+			dec2env(tar_env, TAR_SIZE, file_header->size);
+			dec2env(tar_env, TAR_UID, file_header->uid);
+			dec2env(tar_env, TAR_GID, file_header->gid);
+			close(p[1]);
+			xdup2(p[0], STDIN_FILENO);
+			signal(SIGPIPE, SIG_DFL);
+			execl(archive_handle->tar__to_command_shell,
+				archive_handle->tar__to_command_shell,
+				"-c",
+				archive_handle->tar__to_command,
+				NULL);
+			bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell);
+		}
+		close(p[0]);
+		/* Our caller is expected to do signal(SIGPIPE, SIG_IGN)
+		 * so that we don't die if child don't read all the input: */
+		bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size);
+		close(p[1]);
+
+		if (safe_waitpid(pid, &status, 0) == -1)
+			bb_perror_msg_and_die("waitpid");
+		if (WIFEXITED(status) && WEXITSTATUS(status))
+			bb_error_msg_and_die("'%s' returned status %d",
+				archive_handle->tar__to_command, WEXITSTATUS(status));
+		if (WIFSIGNALED(status))
+			bb_error_msg_and_die("'%s' terminated on signal %d",
+				archive_handle->tar__to_command, WTERMSIG(status));
+
+		if (!BB_MMU) {
+			int i;
+			for (i = 0; i < TAR_MAX; i++) {
+				if (tar_env[i])
+					bb_unsetenv_and_free(tar_env[i]);
+			}
+		}
+	}
+
+#if 0 /* ENABLE_FEATURE_TAR_SELINUX */
+	if (sctx)
+		/* reset the context after creating an entry */
+		setfscreatecon(NULL);
+#endif
+}
diff --git a/ap/app/busybox/src/archival/libarchive/data_extract_to_stdout.c b/ap/app/busybox/src/archival/libarchive/data_extract_to_stdout.c
new file mode 100644
index 0000000..f849f3b
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/data_extract_to_stdout.c
@@ -0,0 +1,14 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle)
+{
+	bb_copyfd_exact_size(archive_handle->src_fd,
+			STDOUT_FILENO,
+			archive_handle->file_header->size);
+}
diff --git a/ap/app/busybox/src/archival/libarchive/data_skip.c b/ap/app/busybox/src/archival/libarchive/data_skip.c
new file mode 100644
index 0000000..588167f
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/data_skip.c
@@ -0,0 +1,12 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+void FAST_FUNC data_skip(archive_handle_t *archive_handle)
+{
+	archive_handle->seek(archive_handle->src_fd, archive_handle->file_header->size);
+}
diff --git a/ap/app/busybox/src/archival/libarchive/decompress_bunzip2.c b/ap/app/busybox/src/archival/libarchive/decompress_bunzip2.c
new file mode 100644
index 0000000..dc252bb
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/decompress_bunzip2.c
@@ -0,0 +1,821 @@
+/* vi: set sw=4 ts=4: */
+/* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net).
+
+   Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
+   which also acknowledges contributions by Mike Burrows, David Wheeler,
+   Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
+   Robert Sedgewick, and Jon L. Bentley.
+
+   Licensed under GPLv2 or later, see file LICENSE in this source tree.
+*/
+
+/*
+	Size and speed optimizations by Manuel Novoa III  (mjn3@codepoet.org).
+
+	More efficient reading of Huffman codes, a streamlined read_bunzip()
+	function, and various other tweaks.  In (limited) tests, approximately
+	20% faster than bzcat on x86 and about 10% faster on arm.
+
+	Note that about 2/3 of the time is spent in read_bunzip() reversing
+	the Burrows-Wheeler transformation.  Much of that time is delay
+	resulting from cache misses.
+
+	(2010 update by vda: profiled "bzcat <84mbyte.bz2 >/dev/null"
+	on x86-64 CPU with L2 > 1M: get_next_block is hotter than read_bunzip:
+	%time seconds   calls function
+	71.01   12.69     444 get_next_block
+	28.65    5.12   93065 read_bunzip
+	00.22    0.04 7736490 get_bits
+	00.11    0.02      47 dealloc_bunzip
+	00.00    0.00   93018 full_write
+	...)
+
+
+	I would ask that anyone benefiting from this work, especially those
+	using it in commercial products, consider making a donation to my local
+	non-profit hospice organization (www.hospiceacadiana.com) in the name of
+	the woman I loved, Toni W. Hagan, who passed away Feb. 12, 2003.
+
+	Manuel
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+/* Constants for Huffman coding */
+#define MAX_GROUPS          6
+#define GROUP_SIZE          50      /* 64 would have been more efficient */
+#define MAX_HUFCODE_BITS    20      /* Longest Huffman code allowed */
+#define MAX_SYMBOLS         258     /* 256 literals + RUNA + RUNB */
+#define SYMBOL_RUNA         0
+#define SYMBOL_RUNB         1
+
+/* Status return values */
+#define RETVAL_OK                       0
+#define RETVAL_LAST_BLOCK               (-1)
+#define RETVAL_NOT_BZIP_DATA            (-2)
+#define RETVAL_UNEXPECTED_INPUT_EOF     (-3)
+#define RETVAL_SHORT_WRITE              (-4)
+#define RETVAL_DATA_ERROR               (-5)
+#define RETVAL_OUT_OF_MEMORY            (-6)
+#define RETVAL_OBSOLETE_INPUT           (-7)
+
+/* Other housekeeping constants */
+#define IOBUF_SIZE          4096
+
+/* This is what we know about each Huffman coding group */
+struct group_data {
+	/* We have an extra slot at the end of limit[] for a sentinel value. */
+	int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS];
+	int minLen, maxLen;
+};
+
+/* Structure holding all the housekeeping data, including IO buffers and
+ * memory that persists between calls to bunzip
+ * Found the most used member:
+ *  cat this_file.c | sed -e 's/"/ /g' -e "s/'/ /g" | xargs -n1 \
+ *  | grep 'bd->' | sed 's/^.*bd->/bd->/' | sort | $PAGER
+ * and moved it (inbufBitCount) to offset 0.
+ */
+struct bunzip_data {
+	/* I/O tracking data (file handles, buffers, positions, etc.) */
+	unsigned inbufBitCount, inbufBits;
+	int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/;
+	uint8_t *inbuf /*,*outbuf*/;
+
+	/* State for interrupting output loop */
+	int writeCopies, writePos, writeRunCountdown, writeCount;
+	int writeCurrent; /* actually a uint8_t */
+
+	/* The CRC values stored in the block header and calculated from the data */
+	uint32_t headerCRC, totalCRC, writeCRC;
+
+	/* Intermediate buffer and its size (in bytes) */
+	uint32_t *dbuf;
+	unsigned dbufSize;
+
+	/* For I/O error handling */
+	jmp_buf jmpbuf;
+
+	/* Big things go last (register-relative addressing can be larger for big offsets) */
+	uint32_t crc32Table[256];
+	uint8_t selectors[32768];  /* nSelectors=15 bits */
+	struct group_data groups[MAX_GROUPS];  /* Huffman coding tables */
+};
+/* typedef struct bunzip_data bunzip_data; -- done in .h file */
+
+
+/* Return the next nnn bits of input.  All reads from the compressed input
+   are done through this function.  All reads are big endian */
+static unsigned get_bits(bunzip_data *bd, int bits_wanted)
+{
+	unsigned bits = 0;
+	/* Cache bd->inbufBitCount in a CPU register (hopefully): */
+	int bit_count = bd->inbufBitCount;
+
+	/* If we need to get more data from the byte buffer, do so.  (Loop getting
+	   one byte at a time to enforce endianness and avoid unaligned access.) */
+	while (bit_count < bits_wanted) {
+
+		/* If we need to read more data from file into byte buffer, do so */
+		if (bd->inbufPos == bd->inbufCount) {
+			/* if "no input fd" case: in_fd == -1, read fails, we jump */
+			bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE);
+			if (bd->inbufCount <= 0)
+				longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF);
+			bd->inbufPos = 0;
+		}
+
+		/* Avoid 32-bit overflow (dump bit buffer to top of output) */
+		if (bit_count >= 24) {
+			bits = bd->inbufBits & ((1 << bit_count) - 1);
+			bits_wanted -= bit_count;
+			bits <<= bits_wanted;
+			bit_count = 0;
+		}
+
+		/* Grab next 8 bits of input from buffer. */
+		bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
+		bit_count += 8;
+	}
+
+	/* Calculate result */
+	bit_count -= bits_wanted;
+	bd->inbufBitCount = bit_count;
+	bits |= (bd->inbufBits >> bit_count) & ((1 << bits_wanted) - 1);
+
+	return bits;
+}
+
+/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */
+static int get_next_block(bunzip_data *bd)
+{
+	struct group_data *hufGroup;
+	int dbufCount, dbufSize, groupCount, *base, *limit, selector,
+		i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256];
+	int runCnt = runCnt; /* for compiler */
+	uint8_t uc, symToByte[256], mtfSymbol[256], *selectors;
+	uint32_t *dbuf;
+	unsigned origPtr;
+
+	dbuf = bd->dbuf;
+	dbufSize = bd->dbufSize;
+	selectors = bd->selectors;
+
+/* In bbox, we are ok with aborting through setjmp which is set up in start_bunzip */
+#if 0
+	/* Reset longjmp I/O error handling */
+	i = setjmp(bd->jmpbuf);
+	if (i) return i;
+#endif
+
+	/* Read in header signature and CRC, then validate signature.
+	   (last block signature means CRC is for whole file, return now) */
+	i = get_bits(bd, 24);
+	j = get_bits(bd, 24);
+	bd->headerCRC = get_bits(bd, 32);
+	if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK;
+	if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA;
+
+	/* We can add support for blockRandomised if anybody complains.  There was
+	   some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
+	   it didn't actually work. */
+	if (get_bits(bd, 1)) return RETVAL_OBSOLETE_INPUT;
+	origPtr = get_bits(bd, 24);
+	if ((int)origPtr > dbufSize) return RETVAL_DATA_ERROR;
+
+	/* mapping table: if some byte values are never used (encoding things
+	   like ascii text), the compression code removes the gaps to have fewer
+	   symbols to deal with, and writes a sparse bitfield indicating which
+	   values were present.  We make a translation table to convert the symbols
+	   back to the corresponding bytes. */
+	symTotal = 0;
+	i = 0;
+	t = get_bits(bd, 16);
+	do {
+		if (t & (1 << 15)) {
+			unsigned inner_map = get_bits(bd, 16);
+			do {
+				if (inner_map & (1 << 15))
+					symToByte[symTotal++] = i;
+				inner_map <<= 1;
+				i++;
+			} while (i & 15);
+			i -= 16;
+		}
+		t <<= 1;
+		i += 16;
+	} while (i < 256);
+
+	/* How many different Huffman coding groups does this block use? */
+	groupCount = get_bits(bd, 3);
+	if (groupCount < 2 || groupCount > MAX_GROUPS)
+		return RETVAL_DATA_ERROR;
+
+	/* nSelectors: Every GROUP_SIZE many symbols we select a new Huffman coding
+	   group.  Read in the group selector list, which is stored as MTF encoded
+	   bit runs.  (MTF=Move To Front, as each value is used it's moved to the
+	   start of the list.) */
+	for (i = 0; i < groupCount; i++)
+		mtfSymbol[i] = i;
+	nSelectors = get_bits(bd, 15);
+	if (!nSelectors)
+		return RETVAL_DATA_ERROR;
+	for (i = 0; i < nSelectors; i++) {
+		uint8_t tmp_byte;
+		/* Get next value */
+		int n = 0;
+		while (get_bits(bd, 1)) {
+			if (n >= groupCount) return RETVAL_DATA_ERROR;
+			n++;
+		}
+		/* Decode MTF to get the next selector */
+		tmp_byte = mtfSymbol[n];
+		while (--n >= 0)
+			mtfSymbol[n + 1] = mtfSymbol[n];
+		mtfSymbol[0] = selectors[i] = tmp_byte;
+	}
+
+	/* Read the Huffman coding tables for each group, which code for symTotal
+	   literal symbols, plus two run symbols (RUNA, RUNB) */
+	symCount = symTotal + 2;
+	for (j = 0; j < groupCount; j++) {
+		uint8_t length[MAX_SYMBOLS];
+		/* 8 bits is ALMOST enough for temp[], see below */
+		unsigned temp[MAX_HUFCODE_BITS+1];
+		int minLen, maxLen, pp, len_m1;
+
+		/* Read Huffman code lengths for each symbol.  They're stored in
+		   a way similar to mtf; record a starting value for the first symbol,
+		   and an offset from the previous value for every symbol after that.
+		   (Subtracting 1 before the loop and then adding it back at the end is
+		   an optimization that makes the test inside the loop simpler: symbol
+		   length 0 becomes negative, so an unsigned inequality catches it.) */
+		len_m1 = get_bits(bd, 5) - 1;
+		for (i = 0; i < symCount; i++) {
+			for (;;) {
+				int two_bits;
+				if ((unsigned)len_m1 > (MAX_HUFCODE_BITS-1))
+					return RETVAL_DATA_ERROR;
+
+				/* If first bit is 0, stop.  Else second bit indicates whether
+				   to increment or decrement the value.  Optimization: grab 2
+				   bits and unget the second if the first was 0. */
+				two_bits = get_bits(bd, 2);
+				if (two_bits < 2) {
+					bd->inbufBitCount++;
+					break;
+				}
+
+				/* Add one if second bit 1, else subtract 1.  Avoids if/else */
+				len_m1 += (((two_bits+1) & 2) - 1);
+			}
+
+			/* Correct for the initial -1, to get the final symbol length */
+			length[i] = len_m1 + 1;
+		}
+
+		/* Find largest and smallest lengths in this group */
+		minLen = maxLen = length[0];
+		for (i = 1; i < symCount; i++) {
+			if (length[i] > maxLen) maxLen = length[i];
+			else if (length[i] < minLen) minLen = length[i];
+		}
+
+		/* Calculate permute[], base[], and limit[] tables from length[].
+		 *
+		 * permute[] is the lookup table for converting Huffman coded symbols
+		 * into decoded symbols.  base[] is the amount to subtract from the
+		 * value of a Huffman symbol of a given length when using permute[].
+		 *
+		 * limit[] indicates the largest numerical value a symbol with a given
+		 * number of bits can have.  This is how the Huffman codes can vary in
+		 * length: each code with a value>limit[length] needs another bit.
+		 */
+		hufGroup = bd->groups + j;
+		hufGroup->minLen = minLen;
+		hufGroup->maxLen = maxLen;
+
+		/* Note that minLen can't be smaller than 1, so we adjust the base
+		   and limit array pointers so we're not always wasting the first
+		   entry.  We do this again when using them (during symbol decoding). */
+		base = hufGroup->base - 1;
+		limit = hufGroup->limit - 1;
+
+		/* Calculate permute[].  Concurently, initialize temp[] and limit[]. */
+		pp = 0;
+		for (i = minLen; i <= maxLen; i++) {
+			int k;
+			temp[i] = limit[i] = 0;
+			for (k = 0; k < symCount; k++)
+				if (length[k] == i)
+					hufGroup->permute[pp++] = k;
+		}
+
+		/* Count symbols coded for at each bit length */
+		/* NB: in pathological cases, temp[8] can end ip being 256.
+		 * That's why uint8_t is too small for temp[]. */
+		for (i = 0; i < symCount; i++) temp[length[i]]++;
+
+		/* Calculate limit[] (the largest symbol-coding value at each bit
+		 * length, which is (previous limit<<1)+symbols at this level), and
+		 * base[] (number of symbols to ignore at each bit length, which is
+		 * limit minus the cumulative count of symbols coded for already). */
+		pp = t = 0;
+		for (i = minLen; i < maxLen;) {
+			unsigned temp_i = temp[i];
+
+			pp += temp_i;
+
+			/* We read the largest possible symbol size and then unget bits
+			   after determining how many we need, and those extra bits could
+			   be set to anything.  (They're noise from future symbols.)  At
+			   each level we're really only interested in the first few bits,
+			   so here we set all the trailing to-be-ignored bits to 1 so they
+			   don't affect the value>limit[length] comparison. */
+			limit[i] = (pp << (maxLen - i)) - 1;
+			pp <<= 1;
+			t += temp_i;
+			base[++i] = pp - t;
+		}
+		limit[maxLen] = pp + temp[maxLen] - 1;
+		limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */
+		base[minLen] = 0;
+	}
+
+	/* We've finished reading and digesting the block header.  Now read this
+	   block's Huffman coded symbols from the file and undo the Huffman coding
+	   and run length encoding, saving the result into dbuf[dbufCount++] = uc */
+
+	/* Initialize symbol occurrence counters and symbol Move To Front table */
+	/*memset(byteCount, 0, sizeof(byteCount)); - smaller, but slower */
+	for (i = 0; i < 256; i++) {
+		byteCount[i] = 0;
+		mtfSymbol[i] = (uint8_t)i;
+	}
+
+	/* Loop through compressed symbols. */
+
+	runPos = dbufCount = selector = 0;
+	for (;;) {
+		int nextSym;
+
+		/* Fetch next Huffman coding group from list. */
+		symCount = GROUP_SIZE - 1;
+		if (selector >= nSelectors) return RETVAL_DATA_ERROR;
+		hufGroup = bd->groups + selectors[selector++];
+		base = hufGroup->base - 1;
+		limit = hufGroup->limit - 1;
+
+ continue_this_group:
+		/* Read next Huffman-coded symbol. */
+
+		/* Note: It is far cheaper to read maxLen bits and back up than it is
+		   to read minLen bits and then add additional bit at a time, testing
+		   as we go.  Because there is a trailing last block (with file CRC),
+		   there is no danger of the overread causing an unexpected EOF for a
+		   valid compressed file.
+		 */
+		if (1) {
+			/* As a further optimization, we do the read inline
+			   (falling back to a call to get_bits if the buffer runs dry).
+			 */
+			int new_cnt;
+			while ((new_cnt = bd->inbufBitCount - hufGroup->maxLen) < 0) {
+				/* bd->inbufBitCount < hufGroup->maxLen */
+				if (bd->inbufPos == bd->inbufCount) {
+					nextSym = get_bits(bd, hufGroup->maxLen);
+					goto got_huff_bits;
+				}
+				bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
+				bd->inbufBitCount += 8;
+			};
+			bd->inbufBitCount = new_cnt; /* "bd->inbufBitCount -= hufGroup->maxLen;" */
+			nextSym = (bd->inbufBits >> new_cnt) & ((1 << hufGroup->maxLen) - 1);
+ got_huff_bits: ;
+		} else { /* unoptimized equivalent */
+			nextSym = get_bits(bd, hufGroup->maxLen);
+		}
+		/* Figure how many bits are in next symbol and unget extras */
+		i = hufGroup->minLen;
+		while (nextSym > limit[i]) ++i;
+		j = hufGroup->maxLen - i;
+		if (j < 0)
+			return RETVAL_DATA_ERROR;
+		bd->inbufBitCount += j;
+
+		/* Huffman decode value to get nextSym (with bounds checking) */
+		nextSym = (nextSym >> j) - base[i];
+		if ((unsigned)nextSym >= MAX_SYMBOLS)
+			return RETVAL_DATA_ERROR;
+		nextSym = hufGroup->permute[nextSym];
+
+		/* We have now decoded the symbol, which indicates either a new literal
+		   byte, or a repeated run of the most recent literal byte.  First,
+		   check if nextSym indicates a repeated run, and if so loop collecting
+		   how many times to repeat the last literal. */
+		if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */
+
+			/* If this is the start of a new run, zero out counter */
+			if (runPos == 0) {
+				runPos = 1;
+				runCnt = 0;
+			}
+
+			/* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
+			   each bit position, add 1 or 2 instead.  For example,
+			   1011 is 1<<0 + 1<<1 + 2<<2.  1010 is 2<<0 + 2<<1 + 1<<2.
+			   You can make any bit pattern that way using 1 less symbol than
+			   the basic or 0/1 method (except all bits 0, which would use no
+			   symbols, but a run of length 0 doesn't mean anything in this
+			   context).  Thus space is saved. */
+			runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
+			if (runPos < dbufSize) runPos <<= 1;
+			goto end_of_huffman_loop;
+		}
+
+		/* When we hit the first non-run symbol after a run, we now know
+		   how many times to repeat the last literal, so append that many
+		   copies to our buffer of decoded symbols (dbuf) now.  (The last
+		   literal used is the one at the head of the mtfSymbol array.) */
+		if (runPos != 0) {
+			uint8_t tmp_byte;
+			if (dbufCount + runCnt >= dbufSize) return RETVAL_DATA_ERROR;
+			tmp_byte = symToByte[mtfSymbol[0]];
+			byteCount[tmp_byte] += runCnt;
+			while (--runCnt >= 0) dbuf[dbufCount++] = (uint32_t)tmp_byte;
+			runPos = 0;
+		}
+
+		/* Is this the terminating symbol? */
+		if (nextSym > symTotal) break;
+
+		/* At this point, nextSym indicates a new literal character.  Subtract
+		   one to get the position in the MTF array at which this literal is
+		   currently to be found.  (Note that the result can't be -1 or 0,
+		   because 0 and 1 are RUNA and RUNB.  But another instance of the
+		   first symbol in the mtf array, position 0, would have been handled
+		   as part of a run above.  Therefore 1 unused mtf position minus
+		   2 non-literal nextSym values equals -1.) */
+		if (dbufCount >= dbufSize) return RETVAL_DATA_ERROR;
+		i = nextSym - 1;
+		uc = mtfSymbol[i];
+
+		/* Adjust the MTF array.  Since we typically expect to move only a
+		 * small number of symbols, and are bound by 256 in any case, using
+		 * memmove here would typically be bigger and slower due to function
+		 * call overhead and other assorted setup costs. */
+		do {
+			mtfSymbol[i] = mtfSymbol[i-1];
+		} while (--i);
+		mtfSymbol[0] = uc;
+		uc = symToByte[uc];
+
+		/* We have our literal byte.  Save it into dbuf. */
+		byteCount[uc]++;
+		dbuf[dbufCount++] = (uint32_t)uc;
+
+		/* Skip group initialization if we're not done with this group.  Done
+		 * this way to avoid compiler warning. */
+ end_of_huffman_loop:
+		if (--symCount >= 0) goto continue_this_group;
+	}
+
+	/* At this point, we've read all the Huffman-coded symbols (and repeated
+	   runs) for this block from the input stream, and decoded them into the
+	   intermediate buffer.  There are dbufCount many decoded bytes in dbuf[].
+	   Now undo the Burrows-Wheeler transform on dbuf.
+	   See http://dogma.net/markn/articles/bwt/bwt.htm
+	 */
+
+	/* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
+	j = 0;
+	for (i = 0; i < 256; i++) {
+		int tmp_count = j + byteCount[i];
+		byteCount[i] = j;
+		j = tmp_count;
+	}
+
+	/* Figure out what order dbuf would be in if we sorted it. */
+	for (i = 0; i < dbufCount; i++) {
+		uint8_t tmp_byte = (uint8_t)dbuf[i];
+		int tmp_count = byteCount[tmp_byte];
+		dbuf[tmp_count] |= (i << 8);
+		byteCount[tmp_byte] = tmp_count + 1;
+	}
+
+	/* Decode first byte by hand to initialize "previous" byte.  Note that it
+	   doesn't get output, and if the first three characters are identical
+	   it doesn't qualify as a run (hence writeRunCountdown=5). */
+	if (dbufCount) {
+		uint32_t tmp;
+		if ((int)origPtr >= dbufCount) return RETVAL_DATA_ERROR;
+		tmp = dbuf[origPtr];
+		bd->writeCurrent = (uint8_t)tmp;
+		bd->writePos = (tmp >> 8);
+		bd->writeRunCountdown = 5;
+	}
+	bd->writeCount = dbufCount;
+
+	return RETVAL_OK;
+}
+
+/* Undo Burrows-Wheeler transform on intermediate buffer to produce output.
+   If start_bunzip was initialized with out_fd=-1, then up to len bytes of
+   data are written to outbuf.  Return value is number of bytes written or
+   error (all errors are negative numbers).  If out_fd!=-1, outbuf and len
+   are ignored, data is written to out_fd and return is RETVAL_OK or error.
+
+   NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes
+   in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0.
+   (Why? This allows to get rid of one local variable)
+*/
+int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len)
+{
+	const uint32_t *dbuf;
+	int pos, current, previous;
+	uint32_t CRC;
+
+	/* If we already have error/end indicator, return it */
+	if (bd->writeCount < 0)
+		return bd->writeCount;
+
+	dbuf = bd->dbuf;
+
+	/* Register-cached state (hopefully): */
+	pos = bd->writePos;
+	current = bd->writeCurrent;
+	CRC = bd->writeCRC; /* small loss on x86-32 (not enough regs), win on x86-64 */
+
+	/* We will always have pending decoded data to write into the output
+	   buffer unless this is the very first call (in which case we haven't
+	   Huffman-decoded a block into the intermediate buffer yet). */
+	if (bd->writeCopies) {
+
+ dec_writeCopies:
+		/* Inside the loop, writeCopies means extra copies (beyond 1) */
+		--bd->writeCopies;
+
+		/* Loop outputting bytes */
+		for (;;) {
+
+			/* If the output buffer is full, save cached state and return */
+			if (--len < 0) {
+				/* Unlikely branch.
+				 * Use of "goto" instead of keeping code here
+				 * helps compiler to realize this. */
+				goto outbuf_full;
+			}
+
+			/* Write next byte into output buffer, updating CRC */
+			*outbuf++ = current;
+			CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current];
+
+			/* Loop now if we're outputting multiple copies of this byte */
+			if (bd->writeCopies) {
+				/* Unlikely branch */
+				/*--bd->writeCopies;*/
+				/*continue;*/
+				/* Same, but (ab)using other existing --writeCopies operation
+				 * (and this if() compiles into just test+branch pair): */
+				goto dec_writeCopies;
+			}
+ decode_next_byte:
+			if (--bd->writeCount < 0)
+				break; /* input block is fully consumed, need next one */
+
+			/* Follow sequence vector to undo Burrows-Wheeler transform */
+			previous = current;
+			pos = dbuf[pos];
+			current = (uint8_t)pos;
+			pos >>= 8;
+
+			/* After 3 consecutive copies of the same byte, the 4th
+			 * is a repeat count.  We count down from 4 instead
+			 * of counting up because testing for non-zero is faster */
+			if (--bd->writeRunCountdown != 0) {
+				if (current != previous)
+					bd->writeRunCountdown = 4;
+			} else {
+				/* Unlikely branch */
+				/* We have a repeated run, this byte indicates the count */
+				bd->writeCopies = current;
+				current = previous;
+				bd->writeRunCountdown = 5;
+
+				/* Sometimes there are just 3 bytes (run length 0) */
+				if (!bd->writeCopies) goto decode_next_byte;
+
+				/* Subtract the 1 copy we'd output anyway to get extras */
+				--bd->writeCopies;
+			}
+		} /* for(;;) */
+
+		/* Decompression of this input block completed successfully */
+		bd->writeCRC = CRC = ~CRC;
+		bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ CRC;
+
+		/* If this block had a CRC error, force file level CRC error */
+		if (CRC != bd->headerCRC) {
+			bd->totalCRC = bd->headerCRC + 1;
+			return RETVAL_LAST_BLOCK;
+		}
+	}
+
+	/* Refill the intermediate buffer by Huffman-decoding next block of input */
+	{
+		int r = get_next_block(bd);
+		if (r) { /* error/end */
+			bd->writeCount = r;
+			return (r != RETVAL_LAST_BLOCK) ? r : len;
+		}
+	}
+
+	CRC = ~0;
+	pos = bd->writePos;
+	current = bd->writeCurrent;
+	goto decode_next_byte;
+
+ outbuf_full:
+	/* Output buffer is full, save cached state and return */
+	bd->writePos = pos;
+	bd->writeCurrent = current;
+	bd->writeCRC = CRC;
+
+	bd->writeCopies++;
+
+	return 0;
+}
+
+/* Allocate the structure, read file header.  If in_fd==-1, inbuf must contain
+   a complete bunzip file (len bytes long).  If in_fd!=-1, inbuf and len are
+   ignored, and data is read from file handle into temporary buffer. */
+
+/* Because bunzip2 is used for help text unpacking, and because bb_show_usage()
+   should work for NOFORK applets too, we must be extremely careful to not leak
+   any allocations! */
+int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd,
+		const void *inbuf, int len)
+{
+	bunzip_data *bd;
+	unsigned i;
+	enum {
+		BZh0 = ('B' << 24) + ('Z' << 16) + ('h' << 8) + '0',
+		h0 = ('h' << 8) + '0',
+	};
+
+	/* Figure out how much data to allocate */
+	i = sizeof(bunzip_data);
+	if (in_fd != -1) i += IOBUF_SIZE;
+
+	/* Allocate bunzip_data.  Most fields initialize to zero. */
+	bd = *bdp = xzalloc(i);
+
+	/* Setup input buffer */
+	bd->in_fd = in_fd;
+	if (-1 == in_fd) {
+		/* in this case, bd->inbuf is read-only */
+		bd->inbuf = (void*)inbuf; /* cast away const-ness */
+	} else {
+		bd->inbuf = (uint8_t*)(bd + 1);
+		memcpy(bd->inbuf, inbuf, len);
+	}
+	bd->inbufCount = len;
+
+	/* Init the CRC32 table (big endian) */
+	crc32_filltable(bd->crc32Table, 1);
+
+	/* Setup for I/O error handling via longjmp */
+	i = setjmp(bd->jmpbuf);
+	if (i) return i;
+
+	/* Ensure that file starts with "BZh['1'-'9']." */
+	/* Update: now caller verifies 1st two bytes, makes .gz/.bz2
+	 * integration easier */
+	/* was: */
+	/* i = get_bits(bd, 32); */
+	/* if ((unsigned)(i - BZh0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA; */
+	i = get_bits(bd, 16);
+	if ((unsigned)(i - h0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA;
+
+	/* Fourth byte (ascii '1'-'9') indicates block size in units of 100k of
+	   uncompressed data.  Allocate intermediate buffer for block. */
+	/* bd->dbufSize = 100000 * (i - BZh0); */
+	bd->dbufSize = 100000 * (i - h0);
+
+	/* Cannot use xmalloc - may leak bd in NOFORK case! */
+	bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(bd->dbuf[0]));
+	if (!bd->dbuf) {
+		free(bd);
+		xfunc_die();
+	}
+	return RETVAL_OK;
+}
+
+void FAST_FUNC dealloc_bunzip(bunzip_data *bd)
+{
+	free(bd->dbuf);
+	free(bd);
+}
+
+
+/* Decompress src_fd to dst_fd.  Stops at end of bzip data, not end of file. */
+IF_DESKTOP(long long) int FAST_FUNC
+unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
+{
+	IF_DESKTOP(long long total_written = 0;)
+	bunzip_data *bd;
+	char *outbuf;
+	int i;
+	unsigned len;
+
+	if (check_signature16(aux, src_fd, BZIP2_MAGIC))
+		return -1;
+
+	outbuf = xmalloc(IOBUF_SIZE);
+	len = 0;
+	while (1) { /* "Process one BZ... stream" loop */
+
+		i = start_bunzip(&bd, src_fd, outbuf + 2, len);
+
+		if (i == 0) {
+			while (1) { /* "Produce some output bytes" loop */
+				i = read_bunzip(bd, outbuf, IOBUF_SIZE);
+				if (i < 0) /* error? */
+					break;
+				i = IOBUF_SIZE - i; /* number of bytes produced */
+				if (i == 0) /* EOF? */
+					break;
+				if (i != full_write(dst_fd, outbuf, i)) {
+					bb_error_msg("short write");
+					i = RETVAL_SHORT_WRITE;
+					goto release_mem;
+				}
+				IF_DESKTOP(total_written += i;)
+			}
+		}
+
+		if (i != RETVAL_LAST_BLOCK
+		/* Observed case when i == RETVAL_OK:
+		 * "bzcat z.bz2", where "z.bz2" is a bzipped zero-length file
+		 * (to be exact, z.bz2 is exactly these 14 bytes:
+		 * 42 5a 68 39 17 72 45 38  50 90 00 00 00 00).
+		 */
+		 && i != RETVAL_OK
+		) {
+			bb_error_msg("bunzip error %d", i);
+			break;
+		}
+		if (bd->headerCRC != bd->totalCRC) {
+			bb_error_msg("CRC error");
+			break;
+		}
+
+		/* Successfully unpacked one BZ stream */
+		i = RETVAL_OK;
+
+		/* Do we have "BZ..." after last processed byte?
+		 * pbzip2 (parallelized bzip2) produces such files.
+		 */
+		len = bd->inbufCount - bd->inbufPos;
+		memcpy(outbuf, &bd->inbuf[bd->inbufPos], len);
+		if (len < 2) {
+			if (safe_read(src_fd, outbuf + len, 2 - len) != 2 - len)
+				break;
+			len = 2;
+		}
+		if (*(uint16_t*)outbuf != BZIP2_MAGIC) /* "BZ"? */
+			break;
+		dealloc_bunzip(bd);
+		len -= 2;
+	}
+
+ release_mem:
+	dealloc_bunzip(bd);
+	free(outbuf);
+
+	return i ? i : IF_DESKTOP(total_written) + 0;
+}
+
+#ifdef TESTING
+
+static char *const bunzip_errors[] = {
+	NULL, "Bad file checksum", "Not bzip data",
+	"Unexpected input EOF", "Unexpected output EOF", "Data error",
+	"Out of memory", "Obsolete (pre 0.9.5) bzip format not supported"
+};
+
+/* Dumb little test thing, decompress stdin to stdout */
+int main(int argc, char **argv)
+{
+	int i;
+	char c;
+
+	int i = unpack_bz2_stream(0, 1);
+	if (i < 0)
+		fprintf(stderr, "%s\n", bunzip_errors[-i]);
+	else if (read(STDIN_FILENO, &c, 1))
+		fprintf(stderr, "Trailing garbage ignored\n");
+	return -i;
+}
+#endif
diff --git a/ap/app/busybox/src/archival/libarchive/decompress_gunzip.c b/ap/app/busybox/src/archival/libarchive/decompress_gunzip.c
new file mode 100755
index 0000000..f65738f
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/decompress_gunzip.c
@@ -0,0 +1,1282 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * gunzip implementation for busybox
+ *
+ * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
+ * based on gzip sources
+ *
+ * Adjusted further by Erik Andersen <andersen@codepoet.org> to support
+ * files as well as stdin/stdout, and to generally behave itself wrt
+ * command line handling.
+ *
+ * General cleanup to better adhere to the style guide and make use of standard
+ * busybox functions by Glenn McGrath
+ *
+ * read_gz interface + associated hacking by Laurence Anderson
+ *
+ * Fixed huft_build() so decoding end-of-block code does not grab more bits
+ * than necessary (this is required by unzip applet), added inflate_cleanup()
+ * to free leaked bytebuffer memory (used in unzip.c), and some minor style
+ * guide cleanups by Ed Clark
+ *
+ * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include <setjmp.h>
+#include "libbb.h"
+#include "bb_archive.h"
+
+typedef struct huft_t {
+	unsigned char e;	/* number of extra bits or operation */
+	unsigned char b;	/* number of bits in this code or subcode */
+	union {
+		unsigned short n;	/* literal, length base, or distance base */
+		struct huft_t *t;	/* pointer to next level of table */
+	} v;
+} huft_t;
+
+enum {
+	/* gunzip_window size--must be a power of two, and
+	 * at least 32K for zip's deflate method */
+	GUNZIP_WSIZE = 0x8000,
+	/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+	BMAX = 16,	/* maximum bit length of any code (16 for explode) */
+	N_MAX = 288,	/* maximum number of codes in any set */
+};
+
+
+/* This is somewhat complex-looking arrangement, but it allows
+ * to place decompressor state either in bss or in
+ * malloc'ed space simply by changing #defines below.
+ * Sizes on i386:
+ * text    data     bss     dec     hex
+ * 5256       0     108    5364    14f4 - bss
+ * 4915       0       0    4915    1333 - malloc
+ */
+#define STATE_IN_BSS 0
+#define STATE_IN_MALLOC 1
+
+
+typedef struct state_t {
+	off_t gunzip_bytes_out; /* number of output bytes */
+	uint32_t gunzip_crc;
+
+	int gunzip_src_fd;
+	unsigned gunzip_outbuf_count; /* bytes in output buffer */
+
+	unsigned char *gunzip_window;
+
+	uint32_t *gunzip_crc_table;
+
+	/* bitbuffer */
+	unsigned gunzip_bb; /* bit buffer */
+	unsigned char gunzip_bk; /* bits in bit buffer */
+
+	/* input (compressed) data */
+	unsigned char *bytebuffer;      /* buffer itself */
+	off_t to_read;			/* compressed bytes to read (unzip only, -1 for gunzip) */
+//	unsigned bytebuffer_max;        /* buffer size */
+	unsigned bytebuffer_offset;     /* buffer position */
+	unsigned bytebuffer_size;       /* how much data is there (size <= max) */
+
+	/* private data of inflate_codes() */
+	unsigned inflate_codes_ml; /* masks for bl and bd bits */
+	unsigned inflate_codes_md; /* masks for bl and bd bits */
+	unsigned inflate_codes_bb; /* bit buffer */
+	unsigned inflate_codes_k; /* number of bits in bit buffer */
+	unsigned inflate_codes_w; /* current gunzip_window position */
+	huft_t *inflate_codes_tl;
+	huft_t *inflate_codes_td;
+	unsigned inflate_codes_bl;
+	unsigned inflate_codes_bd;
+	unsigned inflate_codes_nn; /* length and index for copy */
+	unsigned inflate_codes_dd;
+
+	smallint resume_copy;
+
+	/* private data of inflate_get_next_window() */
+	smallint method; /* method == -1 for stored, -2 for codes */
+	smallint need_another_block;
+	smallint end_reached;
+
+	/* private data of inflate_stored() */
+	unsigned inflate_stored_n;
+	unsigned inflate_stored_b;
+	unsigned inflate_stored_k;
+	unsigned inflate_stored_w;
+
+	const char *error_msg;
+	jmp_buf error_jmp;
+} state_t;
+#define gunzip_bytes_out    (S()gunzip_bytes_out   )
+#define gunzip_crc          (S()gunzip_crc         )
+#define gunzip_src_fd       (S()gunzip_src_fd      )
+#define gunzip_outbuf_count (S()gunzip_outbuf_count)
+#define gunzip_window       (S()gunzip_window      )
+#define gunzip_crc_table    (S()gunzip_crc_table   )
+#define gunzip_bb           (S()gunzip_bb          )
+#define gunzip_bk           (S()gunzip_bk          )
+#define to_read             (S()to_read            )
+// #define bytebuffer_max   (S()bytebuffer_max     )
+// Both gunzip and unzip can use constant buffer size now (16k):
+#define bytebuffer_max      0x4000
+#define bytebuffer          (S()bytebuffer         )
+#define bytebuffer_offset   (S()bytebuffer_offset  )
+#define bytebuffer_size     (S()bytebuffer_size    )
+#define inflate_codes_ml    (S()inflate_codes_ml   )
+#define inflate_codes_md    (S()inflate_codes_md   )
+#define inflate_codes_bb    (S()inflate_codes_bb   )
+#define inflate_codes_k     (S()inflate_codes_k    )
+#define inflate_codes_w     (S()inflate_codes_w    )
+#define inflate_codes_tl    (S()inflate_codes_tl   )
+#define inflate_codes_td    (S()inflate_codes_td   )
+#define inflate_codes_bl    (S()inflate_codes_bl   )
+#define inflate_codes_bd    (S()inflate_codes_bd   )
+#define inflate_codes_nn    (S()inflate_codes_nn   )
+#define inflate_codes_dd    (S()inflate_codes_dd   )
+#define resume_copy         (S()resume_copy        )
+#define method              (S()method             )
+#define need_another_block  (S()need_another_block )
+#define end_reached         (S()end_reached        )
+#define inflate_stored_n    (S()inflate_stored_n   )
+#define inflate_stored_b    (S()inflate_stored_b   )
+#define inflate_stored_k    (S()inflate_stored_k   )
+#define inflate_stored_w    (S()inflate_stored_w   )
+#define error_msg           (S()error_msg          )
+#define error_jmp           (S()error_jmp          )
+
+/* This is a generic part */
+#if STATE_IN_BSS /* Use global data segment */
+#define DECLARE_STATE /*nothing*/
+#define ALLOC_STATE /*nothing*/
+#define DEALLOC_STATE ((void)0)
+#define S() state.
+#define PASS_STATE /*nothing*/
+#define PASS_STATE_ONLY /*nothing*/
+#define STATE_PARAM /*nothing*/
+#define STATE_PARAM_ONLY void
+static state_t state;
+#endif
+
+#if STATE_IN_MALLOC /* Use malloc space */
+#define DECLARE_STATE state_t *state
+#define ALLOC_STATE (state = xzalloc(sizeof(*state)))
+#define DEALLOC_STATE free(state)
+#define S() state->
+#define PASS_STATE state,
+#define PASS_STATE_ONLY state
+#define STATE_PARAM state_t *state,
+#define STATE_PARAM_ONLY state_t *state
+#endif
+
+
+static const uint16_t mask_bits[] ALIGN2 = {
+	0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+	0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+/* Copy lengths for literal codes 257..285 */
+static const uint16_t cplens[] ALIGN2 = {
+	3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
+	67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+};
+
+/* note: see note #13 above about the 258 in this list. */
+/* Extra bits for literal codes 257..285 */
+static const uint8_t cplext[] ALIGN1 = {
+	0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
+	5, 5, 5, 0, 99, 99
+}; /* 99 == invalid */
+
+/* Copy offsets for distance codes 0..29 */
+static const uint16_t cpdist[] ALIGN2 = {
+	1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
+	769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
+};
+
+/* Extra bits for distance codes */
+static const uint8_t cpdext[] ALIGN1 = {
+	0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
+	11, 11, 12, 12, 13, 13
+};
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+/* Order of the bit length code lengths */
+static const uint8_t border[] ALIGN1 = {
+	16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+};
+
+
+/*
+ * Free the malloc'ed tables built by huft_build(), which makes a linked
+ * list of the tables it made, with the links in a dummy first entry of
+ * each table.
+ * t: table to free
+ */
+ /*fix for hub CVE-2021-28831*/
+#define BAD_HUFT(p) ((uintptr_t)(p) & 1)
+#define ERR_RET ((huft_t*)(uintptr_t)1)
+static void huft_free(huft_t *p)
+{
+	huft_t *q;
+
+	/*
+	 * If 'p' has the error bit set we have to clear it, otherwise we might run
+	 * into a segmentation fault or an invalid pointer to free(p)
+	 */
+	if (BAD_HUFT(p)) {
+		p = (huft_t*)((uintptr_t)(p) ^ (uintptr_t)(ERR_RET));
+	}
+
+	/* Go through linked list, freeing from the malloced (t[-1]) address. */
+	while (p) {
+		q = (--p)->v.t;
+		free(p);
+		p = q;
+	}
+}
+
+static void huft_free_all(STATE_PARAM_ONLY)
+{
+	huft_free(inflate_codes_tl);
+	huft_free(inflate_codes_td);
+	inflate_codes_tl = NULL;
+	inflate_codes_td = NULL;
+}
+
+static void abort_unzip(STATE_PARAM_ONLY) NORETURN;
+static void abort_unzip(STATE_PARAM_ONLY)
+{
+	huft_free_all(PASS_STATE_ONLY);
+	longjmp(error_jmp, 1);
+}
+
+static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current, const unsigned required)
+{
+	while (*current < required) {
+		if (bytebuffer_offset >= bytebuffer_size) {
+			unsigned sz = bytebuffer_max - 4;
+			if (to_read >= 0 && to_read < sz) /* unzip only */
+				sz = to_read;
+			/* Leave the first 4 bytes empty so we can always unwind the bitbuffer
+			 * to the front of the bytebuffer */
+			bytebuffer_size = safe_read(gunzip_src_fd, &bytebuffer[4], sz);
+			if ((int)bytebuffer_size < 1) {
+				error_msg = "unexpected end of file";
+				abort_unzip(PASS_STATE_ONLY);
+			}
+			if (to_read >= 0) /* unzip only */
+				to_read -= bytebuffer_size;
+			bytebuffer_size += 4;
+			bytebuffer_offset = 4;
+		}
+		bitbuffer |= ((unsigned) bytebuffer[bytebuffer_offset]) << *current;
+		bytebuffer_offset++;
+		*current += 8;
+	}
+	return bitbuffer;
+}
+
+
+/* Given a list of code lengths and a maximum table size, make a set of
+ * tables to decode that set of codes.  Return zero on success, one if
+ * the given code set is incomplete (the tables are still built in this
+ * case), two if the input is invalid (all zero length codes or an
+ * oversubscribed set of lengths) - in this case stores NULL in *t.
+ *
+ * b:	code lengths in bits (all assumed <= BMAX)
+ * n:	number of codes (assumed <= N_MAX)
+ * s:	number of simple-valued codes (0..s-1)
+ * d:	list of base values for non-simple codes
+ * e:	list of extra bits for non-simple codes
+ * t:	result: starting table
+ * m:	maximum lookup bits, returns actual
+ */
+static int huft_build(const unsigned *b, const unsigned n,
+			const unsigned s, const unsigned short *d,
+			const unsigned char *e, huft_t **t, unsigned *m)
+{
+	unsigned a;             /* counter for codes of length k */
+	unsigned c[BMAX + 1];   /* bit length count table */
+	unsigned eob_len;       /* length of end-of-block code (value 256) */
+	unsigned f;             /* i repeats in table every f entries */
+	int g;                  /* maximum code length */
+	int htl;                /* table level */
+	unsigned i;             /* counter, current code */
+	unsigned j;             /* counter */
+	int k;                  /* number of bits in current code */
+	unsigned *p;            /* pointer into c[], b[], or v[] */
+	huft_t *q;              /* points to current table */
+	huft_t r;               /* table entry for structure assignment */
+	huft_t *u[BMAX];        /* table stack */
+	unsigned v[N_MAX];      /* values in order of bit length */
+	int ws[BMAX + 1];       /* bits decoded stack */
+	int w;                  /* bits decoded */
+	unsigned x[BMAX + 1];   /* bit offsets, then code stack */
+	unsigned *xp;           /* pointer into x */
+	int y;                  /* number of dummy codes added */
+	unsigned z;             /* number of entries in current table */
+
+	/* Length of EOB code, if any */
+	eob_len = n > 256 ? b[256] : BMAX;
+
+	*t = NULL;
+
+	/* Generate counts for each bit length */
+	memset(c, 0, sizeof(c));
+	p = (unsigned *) b; /* cast allows us to reuse p for pointing to b */
+	i = n;
+	do {
+		c[*p]++; /* assume all entries <= BMAX */
+		p++;     /* can't combine with above line (Solaris bug) */
+	} while (--i);
+	if (c[0] == n) {  /* null input - all zero length codes */
+		*m = 0;
+		return 2;
+	}
+
+	/* Find minimum and maximum length, bound *m by those */
+	for (j = 1; (c[j] == 0) && (j <= BMAX); j++)
+		continue;
+	k = j; /* minimum code length */
+	for (i = BMAX; (c[i] == 0) && i; i--)
+		continue;
+	g = i; /* maximum code length */
+	*m = (*m < j) ? j : ((*m > i) ? i : *m);
+
+	/* Adjust last length count to fill out codes, if needed */
+	for (y = 1 << j; j < i; j++, y <<= 1) {
+		y -= c[j];
+		if (y < 0)
+			return 2; /* bad input: more codes than bits */
+	}
+	y -= c[i];
+	if (y < 0)
+		return 2;
+	c[i] += y;
+
+	/* Generate starting offsets into the value table for each length */
+	x[1] = j = 0;
+	p = c + 1;
+	xp = x + 2;
+	while (--i) { /* note that i == g from above */
+		j += *p++;
+		*xp++ = j;
+	}
+
+	/* Make a table of values in order of bit lengths */
+	p = (unsigned *) b;
+	i = 0;
+	do {
+		j = *p++;
+		if (j != 0) {
+			v[x[j]++] = i;
+		}
+	} while (++i < n);
+
+	/* Generate the Huffman codes and for each, make the table entries */
+	x[0] = i = 0;   /* first Huffman code is zero */
+	p = v;          /* grab values in bit order */
+	htl = -1;       /* no tables yet--level -1 */
+	w = ws[0] = 0;  /* bits decoded */
+	u[0] = NULL;    /* just to keep compilers happy */
+	q = NULL;       /* ditto */
+	z = 0;          /* ditto */
+
+	/* go through the bit lengths (k already is bits in shortest code) */
+	for (; k <= g; k++) {
+		a = c[k];
+		while (a--) {
+			/* here i is the Huffman code of length k bits for value *p */
+			/* make tables up to required level */
+			while (k > ws[htl + 1]) {
+				w = ws[++htl];
+
+				/* compute minimum size table less than or equal to *m bits */
+				z = g - w;
+				z = z > *m ? *m : z; /* upper limit on table size */
+				j = k - w;
+				f = 1 << j;
+				if (f > a + 1) { /* try a k-w bit table */
+					/* too few codes for k-w bit table */
+					f -= a + 1; /* deduct codes from patterns left */
+					xp = c + k;
+					while (++j < z) { /* try smaller tables up to z bits */
+						f <<= 1;
+						if (f <= *++xp) {
+							break; /* enough codes to use up j bits */
+						}
+						f -= *xp; /* else deduct codes from patterns */
+					}
+				}
+				j = (w + j > eob_len && w < eob_len) ? eob_len - w : j;	/* make EOB code end at table */
+				z = 1 << j;	/* table entries for j-bit table */
+				ws[htl+1] = w + j;	/* set bits decoded in stack */
+
+				/* allocate and link in new table */
+				q = xzalloc((z + 1) * sizeof(huft_t));
+				*t = q + 1;	/* link to list for huft_free() */
+				t = &(q->v.t);
+				u[htl] = ++q;	/* table starts after link */
+
+				/* connect to last table, if there is one */
+				if (htl) {
+					x[htl] = i; /* save pattern for backing up */
+					r.b = (unsigned char) (w - ws[htl - 1]); /* bits to dump before this table */
+					r.e = (unsigned char) (16 + j); /* bits in this table */
+					r.v.t = q; /* pointer to this table */
+					j = (i & ((1 << w) - 1)) >> ws[htl - 1];
+					u[htl - 1][j] = r; /* connect to last table */
+				}
+			}
+
+			/* set up table entry in r */
+			r.b = (unsigned char) (k - w);
+			if (p >= v + n) {
+				r.e = 99; /* out of values--invalid code */
+			} else if (*p < s) {
+				r.e = (unsigned char) (*p < 256 ? 16 : 15);	/* 256 is EOB code */
+				r.v.n = (unsigned short) (*p++); /* simple code is just the value */
+			} else {
+				r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */
+				r.v.n = d[*p++ - s];
+			}
+
+			/* fill code-like entries with r */
+			f = 1 << (k - w);
+			for (j = i >> w; j < z; j += f) {
+				q[j] = r;
+			}
+
+			/* backwards increment the k-bit code i */
+			for (j = 1 << (k - 1); i & j; j >>= 1) {
+				i ^= j;
+			}
+			i ^= j;
+
+			/* backup over finished tables */
+			while ((i & ((1 << w) - 1)) != x[htl]) {
+				w = ws[--htl];
+			}
+		}
+	}
+
+	/* return actual size of base table */
+	*m = ws[1];
+
+	/* Return 1 if we were given an incomplete table */
+	return y != 0 && g != 1;
+}
+
+
+/*
+ * inflate (decompress) the codes in a deflated (compressed) block.
+ * Return an error code or zero if it all goes ok.
+ *
+ * tl, td: literal/length and distance decoder tables
+ * bl, bd: number of bits decoded by tl[] and td[]
+ */
+/* called once from inflate_block */
+
+/* map formerly local static variables to globals */
+#define ml inflate_codes_ml
+#define md inflate_codes_md
+#define bb inflate_codes_bb
+#define k  inflate_codes_k
+#define w  inflate_codes_w
+#define tl inflate_codes_tl
+#define td inflate_codes_td
+#define bl inflate_codes_bl
+#define bd inflate_codes_bd
+#define nn inflate_codes_nn
+#define dd inflate_codes_dd
+static void inflate_codes_setup(STATE_PARAM unsigned my_bl, unsigned my_bd)
+{
+	bl = my_bl;
+	bd = my_bd;
+	/* make local copies of globals */
+	bb = gunzip_bb;			/* initialize bit buffer */
+	k = gunzip_bk;
+	w = gunzip_outbuf_count;	/* initialize gunzip_window position */
+	/* inflate the coded data */
+	ml = mask_bits[bl];		/* precompute masks for speed */
+	md = mask_bits[bd];
+}
+/* called once from inflate_get_next_window */
+static NOINLINE int inflate_codes(STATE_PARAM_ONLY)
+{
+	unsigned e;	/* table entry flag/number of extra bits */
+	huft_t *t;	/* pointer to table entry */
+
+	if (resume_copy)
+		goto do_copy;
+
+	while (1) {			/* do until end of block */
+		bb = fill_bitbuffer(PASS_STATE bb, &k, bl);
+		t = tl + ((unsigned) bb & ml);
+		e = t->e;
+		if (e > 16)
+			do {
+				if (e == 99)
+					abort_unzip(PASS_STATE_ONLY);;
+				bb >>= t->b;
+				k -= t->b;
+				e -= 16;
+				bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+				t = t->v.t + ((unsigned) bb & mask_bits[e]);
+				e = t->e;
+			} while (e > 16);
+		bb >>= t->b;
+		k -= t->b;
+		if (e == 16) {	/* then it's a literal */
+			gunzip_window[w++] = (unsigned char) t->v.n;
+			if (w == GUNZIP_WSIZE) {
+				gunzip_outbuf_count = w;
+				//flush_gunzip_window();
+				w = 0;
+				return 1; // We have a block to read
+			}
+		} else {		/* it's an EOB or a length */
+			/* exit if end of block */
+			if (e == 15) {
+				break;
+			}
+
+			/* get length of block to copy */
+			bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+			nn = t->v.n + ((unsigned) bb & mask_bits[e]);
+			bb >>= e;
+			k -= e;
+
+			/* decode distance of block to copy */
+			bb = fill_bitbuffer(PASS_STATE bb, &k, bd);
+			t = td + ((unsigned) bb & md);
+			e = t->e;
+			if (e > 16)
+				do {
+					if (e == 99)
+						abort_unzip(PASS_STATE_ONLY);
+					bb >>= t->b;
+					k -= t->b;
+					e -= 16;
+					bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+					t = t->v.t + ((unsigned) bb & mask_bits[e]);
+					e = t->e;
+				} while (e > 16);
+			bb >>= t->b;
+			k -= t->b;
+			bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+			dd = w - t->v.n - ((unsigned) bb & mask_bits[e]);
+			bb >>= e;
+			k -= e;
+
+			/* do the copy */
+ do_copy:
+			do {
+				/* Was: nn -= (e = (e = GUNZIP_WSIZE - ((dd &= GUNZIP_WSIZE - 1) > w ? dd : w)) > nn ? nn : e); */
+				/* Who wrote THAT?? rewritten as: */
+				unsigned delta;
+
+				dd &= GUNZIP_WSIZE - 1;
+				e = GUNZIP_WSIZE - (dd > w ? dd : w);
+				delta = w > dd ? w - dd : dd - w;
+				if (e > nn) e = nn;
+				nn -= e;
+
+				/* copy to new buffer to prevent possible overwrite */
+				if (delta >= e) {
+					memcpy(gunzip_window + w, gunzip_window + dd, e);
+					w += e;
+					dd += e;
+				} else {
+					/* do it slow to avoid memcpy() overlap */
+					/* !NOMEMCPY */
+					do {
+						gunzip_window[w++] = gunzip_window[dd++];
+					} while (--e);
+				}
+				if (w == GUNZIP_WSIZE) {
+					gunzip_outbuf_count = w;
+					resume_copy = (nn != 0);
+					//flush_gunzip_window();
+					w = 0;
+					return 1;
+				}
+			} while (nn);
+			resume_copy = 0;
+		}
+	}
+
+	/* restore the globals from the locals */
+	gunzip_outbuf_count = w;	/* restore global gunzip_window pointer */
+	gunzip_bb = bb;			/* restore global bit buffer */
+	gunzip_bk = k;
+
+	/* normally just after call to inflate_codes, but save code by putting it here */
+	/* free the decoding tables (tl and td), return */
+	huft_free_all(PASS_STATE_ONLY);
+
+	/* done */
+	return 0;
+}
+#undef ml
+#undef md
+#undef bb
+#undef k
+#undef w
+#undef tl
+#undef td
+#undef bl
+#undef bd
+#undef nn
+#undef dd
+
+
+/* called once from inflate_block */
+static void inflate_stored_setup(STATE_PARAM int my_n, int my_b, int my_k)
+{
+	inflate_stored_n = my_n;
+	inflate_stored_b = my_b;
+	inflate_stored_k = my_k;
+	/* initialize gunzip_window position */
+	inflate_stored_w = gunzip_outbuf_count;
+}
+/* called once from inflate_get_next_window */
+static int inflate_stored(STATE_PARAM_ONLY)
+{
+	/* read and output the compressed data */
+	while (inflate_stored_n--) {
+		inflate_stored_b = fill_bitbuffer(PASS_STATE inflate_stored_b, &inflate_stored_k, 8);
+		gunzip_window[inflate_stored_w++] = (unsigned char) inflate_stored_b;
+		if (inflate_stored_w == GUNZIP_WSIZE) {
+			gunzip_outbuf_count = inflate_stored_w;
+			//flush_gunzip_window();
+			inflate_stored_w = 0;
+			inflate_stored_b >>= 8;
+			inflate_stored_k -= 8;
+			return 1; /* We have a block */
+		}
+		inflate_stored_b >>= 8;
+		inflate_stored_k -= 8;
+	}
+
+	/* restore the globals from the locals */
+	gunzip_outbuf_count = inflate_stored_w;		/* restore global gunzip_window pointer */
+	gunzip_bb = inflate_stored_b;	/* restore global bit buffer */
+	gunzip_bk = inflate_stored_k;
+	return 0; /* Finished */
+}
+
+
+/*
+ * decompress an inflated block
+ * e: last block flag
+ *
+ * GLOBAL VARIABLES: bb, kk,
+ */
+/* Return values: -1 = inflate_stored, -2 = inflate_codes */
+/* One callsite in inflate_get_next_window */
+static int inflate_block(STATE_PARAM smallint *e)
+{
+	unsigned ll[286 + 30];  /* literal/length and distance code lengths */
+	unsigned t;     /* block type */
+	unsigned b;     /* bit buffer */
+	unsigned k;     /* number of bits in bit buffer */
+
+	/* make local bit buffer */
+
+	b = gunzip_bb;
+	k = gunzip_bk;
+
+	/* read in last block bit */
+	b = fill_bitbuffer(PASS_STATE b, &k, 1);
+	*e = b & 1;
+	b >>= 1;
+	k -= 1;
+
+	/* read in block type */
+	b = fill_bitbuffer(PASS_STATE b, &k, 2);
+	t = (unsigned) b & 3;
+	b >>= 2;
+	k -= 2;
+
+	/* restore the global bit buffer */
+	gunzip_bb = b;
+	gunzip_bk = k;
+
+	/* Do we see block type 1 often? Yes!
+	 * TODO: fix performance problem (see below) */
+	//bb_error_msg("blktype %d", t);
+
+	/* inflate that block type */
+	switch (t) {
+	case 0: /* Inflate stored */
+	{
+		unsigned n;	/* number of bytes in block */
+		unsigned b_stored;	/* bit buffer */
+		unsigned k_stored;	/* number of bits in bit buffer */
+
+		/* make local copies of globals */
+		b_stored = gunzip_bb;	/* initialize bit buffer */
+		k_stored = gunzip_bk;
+
+		/* go to byte boundary */
+		n = k_stored & 7;
+		b_stored >>= n;
+		k_stored -= n;
+
+		/* get the length and its complement */
+		b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16);
+		n = ((unsigned) b_stored & 0xffff);
+		b_stored >>= 16;
+		k_stored -= 16;
+
+		b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16);
+		if (n != (unsigned) ((~b_stored) & 0xffff)) {
+			abort_unzip(PASS_STATE_ONLY);	/* error in compressed data */
+		}
+		b_stored >>= 16;
+		k_stored -= 16;
+
+		inflate_stored_setup(PASS_STATE n, b_stored, k_stored);
+
+		return -1;
+	}
+	case 1:
+	/* Inflate fixed
+	 * decompress an inflated type 1 (fixed Huffman codes) block. We should
+	 * either replace this with a custom decoder, or at least precompute the
+	 * Huffman tables. TODO */
+	{
+		int i;                  /* temporary variable */
+		unsigned bl;            /* lookup bits for tl */
+		unsigned bd;            /* lookup bits for td */
+		/* gcc 4.2.1 is too dumb to reuse stackspace. Moved up... */
+		//unsigned ll[288];     /* length list for huft_build */
+
+		/* set up literal table */
+		for (i = 0; i < 144; i++)
+			ll[i] = 8;
+		for (; i < 256; i++)
+			ll[i] = 9;
+		for (; i < 280; i++)
+			ll[i] = 7;
+		for (; i < 288; i++) /* make a complete, but wrong code set */
+			ll[i] = 8;
+		bl = 7;
+		huft_build(ll, 288, 257, cplens, cplext, &inflate_codes_tl, &bl);
+		/* huft_build() never return nonzero - we use known data */
+
+		/* set up distance table */
+		for (i = 0; i < 30; i++) /* make an incomplete code set */
+			ll[i] = 5;
+		bd = 5;
+		huft_build(ll, 30, 0, cpdist, cpdext, &inflate_codes_td, &bd);
+
+		/* set up data for inflate_codes() */
+		inflate_codes_setup(PASS_STATE bl, bd);
+
+		/* huft_free code moved into inflate_codes */
+
+		return -2;
+	}
+	case 2: /* Inflate dynamic */
+	{
+		enum { dbits = 6 };     /* bits in base distance lookup table */
+		enum { lbits = 9 };     /* bits in base literal/length lookup table */
+
+		huft_t *td;             /* distance code table */
+		unsigned i;             /* temporary variables */
+		unsigned j;
+		unsigned l;             /* last length */
+		unsigned m;             /* mask for bit lengths table */
+		unsigned n;             /* number of lengths to get */
+		unsigned bl;            /* lookup bits for tl */
+		unsigned bd;            /* lookup bits for td */
+		unsigned nb;            /* number of bit length codes */
+		unsigned nl;            /* number of literal/length codes */
+		unsigned nd;            /* number of distance codes */
+
+		//unsigned ll[286 + 30];/* literal/length and distance code lengths */
+		unsigned b_dynamic;     /* bit buffer */
+		unsigned k_dynamic;     /* number of bits in bit buffer */
+
+		/* make local bit buffer */
+		b_dynamic = gunzip_bb;
+		k_dynamic = gunzip_bk;
+
+		/* read in table lengths */
+		b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5);
+		nl = 257 + ((unsigned) b_dynamic & 0x1f);	/* number of literal/length codes */
+
+		b_dynamic >>= 5;
+		k_dynamic -= 5;
+		b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5);
+		nd = 1 + ((unsigned) b_dynamic & 0x1f);	/* number of distance codes */
+
+		b_dynamic >>= 5;
+		k_dynamic -= 5;
+		b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 4);
+		nb = 4 + ((unsigned) b_dynamic & 0xf);	/* number of bit length codes */
+
+		b_dynamic >>= 4;
+		k_dynamic -= 4;
+		if (nl > 286 || nd > 30)
+			abort_unzip(PASS_STATE_ONLY);	/* bad lengths */
+
+		/* read in bit-length-code lengths */
+		for (j = 0; j < nb; j++) {
+			b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3);
+			ll[border[j]] = (unsigned) b_dynamic & 7;
+			b_dynamic >>= 3;
+			k_dynamic -= 3;
+		}
+		for (; j < 19; j++)
+			ll[border[j]] = 0;
+
+		/* build decoding table for trees - single level, 7 bit lookup */
+		bl = 7;
+		i = huft_build(ll, 19, 19, NULL, NULL, &inflate_codes_tl, &bl);
+		if (i != 0) {
+			abort_unzip(PASS_STATE_ONLY); //return i;	/* incomplete code set */
+		}
+
+		/* read in literal and distance code lengths */
+		n = nl + nd;
+		m = mask_bits[bl];
+		i = l = 0;
+		while ((unsigned) i < n) {
+			b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, (unsigned)bl);
+			td = inflate_codes_tl + ((unsigned) b_dynamic & m);
+			j = td->b;
+			b_dynamic >>= j;
+			k_dynamic -= j;
+			j = td->v.n;
+			if (j < 16) {	/* length of code in bits (0..15) */
+				ll[i++] = l = j;	/* save last length in l */
+			} else if (j == 16) {	/* repeat last length 3 to 6 times */
+				b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 2);
+				j = 3 + ((unsigned) b_dynamic & 3);
+				b_dynamic >>= 2;
+				k_dynamic -= 2;
+				if ((unsigned) i + j > n) {
+					abort_unzip(PASS_STATE_ONLY); //return 1;
+				}
+				while (j--) {
+					ll[i++] = l;
+				}
+			} else if (j == 17) {	/* 3 to 10 zero length codes */
+				b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3);
+				j = 3 + ((unsigned) b_dynamic & 7);
+				b_dynamic >>= 3;
+				k_dynamic -= 3;
+				if ((unsigned) i + j > n) {
+					abort_unzip(PASS_STATE_ONLY); //return 1;
+				}
+				while (j--) {
+					ll[i++] = 0;
+				}
+				l = 0;
+			} else {	/* j == 18: 11 to 138 zero length codes */
+				b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 7);
+				j = 11 + ((unsigned) b_dynamic & 0x7f);
+				b_dynamic >>= 7;
+				k_dynamic -= 7;
+				if ((unsigned) i + j > n) {
+					abort_unzip(PASS_STATE_ONLY); //return 1;
+				}
+				while (j--) {
+					ll[i++] = 0;
+				}
+				l = 0;
+			}
+		}
+
+		/* free decoding table for trees */
+		huft_free(inflate_codes_tl);
+
+		/* restore the global bit buffer */
+		gunzip_bb = b_dynamic;
+		gunzip_bk = k_dynamic;
+
+		/* build the decoding tables for literal/length and distance codes */
+		bl = lbits;
+
+		i = huft_build(ll, nl, 257, cplens, cplext, &inflate_codes_tl, &bl);
+		if (i != 0)
+			abort_unzip(PASS_STATE_ONLY);
+		bd = dbits;
+		i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd);
+		if (i != 0)
+			abort_unzip(PASS_STATE_ONLY);
+
+		/* set up data for inflate_codes() */
+		inflate_codes_setup(PASS_STATE bl, bd);
+
+		/* huft_free code moved into inflate_codes */
+
+		return -2;
+	}
+	default:
+		abort_unzip(PASS_STATE_ONLY);
+	}
+}
+
+/* Two callsites, both in inflate_get_next_window */
+static void calculate_gunzip_crc(STATE_PARAM_ONLY)
+{
+	gunzip_crc = crc32_block_endian0(gunzip_crc, gunzip_window, gunzip_outbuf_count, gunzip_crc_table);
+	gunzip_bytes_out += gunzip_outbuf_count;
+}
+
+/* One callsite in inflate_unzip_internal */
+static int inflate_get_next_window(STATE_PARAM_ONLY)
+{
+	gunzip_outbuf_count = 0;
+
+	while (1) {
+		int ret;
+
+		if (need_another_block) {
+			if (end_reached) {
+				calculate_gunzip_crc(PASS_STATE_ONLY);
+				end_reached = 0;
+				/* NB: need_another_block is still set */
+				return 0; /* Last block */
+			}
+			method = inflate_block(PASS_STATE &end_reached);
+			need_another_block = 0;
+		}
+
+		switch (method) {
+		case -1:
+			ret = inflate_stored(PASS_STATE_ONLY);
+			break;
+		case -2:
+			ret = inflate_codes(PASS_STATE_ONLY);
+			break;
+		default: /* cannot happen */
+			abort_unzip(PASS_STATE_ONLY);
+		}
+
+		if (ret == 1) {
+			calculate_gunzip_crc(PASS_STATE_ONLY);
+			return 1; /* more data left */
+		}
+		need_another_block = 1; /* end of that block */
+	}
+	/* Doesnt get here */
+}
+
+
+/* Called from unpack_gz_stream() and inflate_unzip() */
+static IF_DESKTOP(long long) int
+inflate_unzip_internal(STATE_PARAM int in, int out)
+{
+	IF_DESKTOP(long long) int n = 0;
+	ssize_t nwrote;
+
+	/* Allocate all global buffers (for DYN_ALLOC option) */
+	gunzip_window = xmalloc(GUNZIP_WSIZE);
+	gunzip_outbuf_count = 0;
+	gunzip_bytes_out = 0;
+	gunzip_src_fd = in;
+
+	/* (re) initialize state */
+	method = -1;
+	need_another_block = 1;
+	resume_copy = 0;
+	gunzip_bk = 0;
+	gunzip_bb = 0;
+
+	/* Create the crc table */
+	gunzip_crc_table = crc32_filltable(NULL, 0);
+	gunzip_crc = ~0;
+
+	error_msg = "corrupted data";
+	if (setjmp(error_jmp)) {
+		/* Error from deep inside zip machinery */
+		n = -1;
+		goto ret;
+	}
+
+	while (1) {
+		int r = inflate_get_next_window(PASS_STATE_ONLY);
+		nwrote = full_write(out, gunzip_window, gunzip_outbuf_count);
+		if (nwrote != (ssize_t)gunzip_outbuf_count) {
+			bb_perror_msg("write");
+			n = -1;
+			goto ret;
+		}
+		IF_DESKTOP(n += nwrote;)
+		if (r == 0) break;
+	}
+
+	/* Store unused bytes in a global buffer so calling applets can access it */
+	if (gunzip_bk >= 8) {
+		/* Undo too much lookahead. The next read will be byte aligned
+		 * so we can discard unused bits in the last meaningful byte. */
+		bytebuffer_offset--;
+		bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff;
+		gunzip_bb >>= 8;
+		gunzip_bk -= 8;
+	}
+ ret:
+	/* Cleanup */
+	free(gunzip_window);
+	free(gunzip_crc_table);
+	return n;
+}
+
+
+/* External entry points */
+
+/* For unzip */
+
+IF_DESKTOP(long long) int FAST_FUNC
+inflate_unzip(transformer_aux_data_t *aux, int in, int out)
+{
+	IF_DESKTOP(long long) int n;
+	DECLARE_STATE;
+
+	ALLOC_STATE;
+
+	to_read = aux->bytes_in;
+//	bytebuffer_max = 0x8000;
+	bytebuffer_offset = 4;
+	bytebuffer = xmalloc(bytebuffer_max);
+	n = inflate_unzip_internal(PASS_STATE in, out);
+	free(bytebuffer);
+
+	aux->crc32 = gunzip_crc;
+	aux->bytes_out = gunzip_bytes_out;
+	DEALLOC_STATE;
+	return n;
+}
+
+
+/* For gunzip */
+
+/* helpers first */
+
+/* Top up the input buffer with at least n bytes. */
+static int top_up(STATE_PARAM unsigned n)
+{
+	int count = bytebuffer_size - bytebuffer_offset;
+
+	if (count < (int)n) {
+		memmove(bytebuffer, &bytebuffer[bytebuffer_offset], count);
+		bytebuffer_offset = 0;
+		bytebuffer_size = full_read(gunzip_src_fd, &bytebuffer[count], bytebuffer_max - count);
+		if ((int)bytebuffer_size < 0) {
+			bb_error_msg(bb_msg_read_error);
+			return 0;
+		}
+		bytebuffer_size += count;
+		if (bytebuffer_size < n)
+			return 0;
+	}
+	return 1;
+}
+
+static uint16_t buffer_read_le_u16(STATE_PARAM_ONLY)
+{
+	uint16_t res;
+#if BB_LITTLE_ENDIAN
+	move_from_unaligned16(res, &bytebuffer[bytebuffer_offset]);
+#else
+	res = bytebuffer[bytebuffer_offset];
+	res |= bytebuffer[bytebuffer_offset + 1] << 8;
+#endif
+	bytebuffer_offset += 2;
+	return res;
+}
+
+static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY)
+{
+	uint32_t res;
+#if BB_LITTLE_ENDIAN
+	move_from_unaligned32(res, &bytebuffer[bytebuffer_offset]);
+#else
+	res = bytebuffer[bytebuffer_offset];
+	res |= bytebuffer[bytebuffer_offset + 1] << 8;
+	res |= bytebuffer[bytebuffer_offset + 2] << 16;
+	res |= bytebuffer[bytebuffer_offset + 3] << 24;
+#endif
+	bytebuffer_offset += 4;
+	return res;
+}
+
+static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux)
+{
+	union {
+		unsigned char raw[8];
+		struct {
+			uint8_t gz_method;
+			uint8_t flags;
+			uint32_t mtime;
+			uint8_t xtra_flags_UNUSED;
+			uint8_t os_flags_UNUSED;
+		} PACKED formatted;
+	} header;
+	struct BUG_header {
+		char BUG_header[sizeof(header) == 8 ? 1 : -1];
+	};
+
+	/*
+	 * Rewind bytebuffer. We use the beginning because the header has 8
+	 * bytes, leaving enough for unwinding afterwards.
+	 */
+	bytebuffer_size -= bytebuffer_offset;
+	memmove(bytebuffer, &bytebuffer[bytebuffer_offset], bytebuffer_size);
+	bytebuffer_offset = 0;
+
+	if (!top_up(PASS_STATE 8))
+		return 0;
+	memcpy(header.raw, &bytebuffer[bytebuffer_offset], 8);
+	bytebuffer_offset += 8;
+
+	/* Check the compression method */
+	if (header.formatted.gz_method != 8) {
+		return 0;
+	}
+
+	if (header.formatted.flags & 0x04) {
+		/* bit 2 set: extra field present */
+		unsigned extra_short;
+
+		if (!top_up(PASS_STATE 2))
+			return 0;
+		extra_short = buffer_read_le_u16(PASS_STATE_ONLY);
+		if (!top_up(PASS_STATE extra_short))
+			return 0;
+		/* Ignore extra field */
+		bytebuffer_offset += extra_short;
+	}
+
+	/* Discard original name and file comment if any */
+	/* bit 3 set: original file name present */
+	/* bit 4 set: file comment present */
+	if (header.formatted.flags & 0x18) {
+		while (1) {
+			do {
+				if (!top_up(PASS_STATE 1))
+					return 0;
+			} while (bytebuffer[bytebuffer_offset++] != 0);
+			if ((header.formatted.flags & 0x18) != 0x18)
+				break;
+			header.formatted.flags &= ~0x18;
+		}
+	}
+
+	if (aux)
+		aux->mtime = SWAP_LE32(header.formatted.mtime);
+
+	/* Read the header checksum */
+	if (header.formatted.flags & 0x02) {
+		if (!top_up(PASS_STATE 2))
+			return 0;
+		bytebuffer_offset += 2;
+	}
+	return 1;
+}
+
+IF_DESKTOP(long long) int FAST_FUNC
+unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
+{
+	uint32_t v32;
+	IF_DESKTOP(long long) int total, n;
+	DECLARE_STATE;
+
+#if !ENABLE_FEATURE_SEAMLESS_Z
+	if (check_signature16(aux, src_fd, GZIP_MAGIC))
+		return -1;
+#else
+	if (aux && aux->check_signature) {
+		uint16_t magic2;
+
+		if (full_read(src_fd, &magic2, 2) != 2) {
+ bad_magic:
+			bb_error_msg("invalid magic");
+			return -1;
+		}
+		if (magic2 == COMPRESS_MAGIC) {
+			aux->check_signature = 0;
+			return unpack_Z_stream(aux, src_fd, dst_fd);
+		}
+		if (magic2 != GZIP_MAGIC)
+			goto bad_magic;
+	}
+#endif
+
+	total = 0;
+
+	ALLOC_STATE;
+	to_read = -1;
+//	bytebuffer_max = 0x8000;
+	bytebuffer = xmalloc(bytebuffer_max);
+	gunzip_src_fd = src_fd;
+
+ again:
+	if (!check_header_gzip(PASS_STATE aux)) {
+		bb_error_msg("corrupted data");
+		total = -1;
+		goto ret;
+	}
+
+	n = inflate_unzip_internal(PASS_STATE src_fd, dst_fd);
+	if (n < 0) {
+		total = -1;
+		goto ret;
+	}
+	total += n;
+
+	if (!top_up(PASS_STATE 8)) {
+		bb_error_msg("corrupted data");
+		total = -1;
+		goto ret;
+	}
+
+	/* Validate decompression - crc */
+	v32 = buffer_read_le_u32(PASS_STATE_ONLY);
+	if ((~gunzip_crc) != v32) {
+		bb_error_msg("crc error");
+		total = -1;
+		goto ret;
+	}
+
+	/* Validate decompression - size */
+	v32 = buffer_read_le_u32(PASS_STATE_ONLY);
+	if ((uint32_t)gunzip_bytes_out != v32) {
+		bb_error_msg("incorrect length");
+		total = -1;
+	}
+
+	if (!top_up(PASS_STATE 2))
+		goto ret; /* EOF */
+
+	if (bytebuffer[bytebuffer_offset] == 0x1f
+	 && bytebuffer[bytebuffer_offset + 1] == 0x8b
+	) {
+		bytebuffer_offset += 2;
+		goto again;
+	}
+	/* GNU gzip says: */
+	/*bb_error_msg("decompression OK, trailing garbage ignored");*/
+
+ ret:
+	free(bytebuffer);
+	DEALLOC_STATE;
+	return total;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/decompress_uncompress.c b/ap/app/busybox/src/archival/libarchive/decompress_uncompress.c
new file mode 100644
index 0000000..53c2708
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/decompress_uncompress.c
@@ -0,0 +1,315 @@
+/* vi: set sw=4 ts=4: */
+/* uncompress for busybox -- (c) 2002 Robert Griebl
+ *
+ * based on the original compress42.c source
+ * (see disclaimer below)
+ */
+
+/* (N)compress42.c - File compression ala IEEE Computer, Mar 1992.
+ *
+ * Authors:
+ *   Spencer W. Thomas   (decvax!harpo!utah-cs!utah-gr!thomas)
+ *   Jim McKie           (decvax!mcvax!jim)
+ *   Steve Davies        (decvax!vax135!petsd!peora!srd)
+ *   Ken Turkowski       (decvax!decwrl!turtlevax!ken)
+ *   James A. Woods      (decvax!ihnp4!ames!jaw)
+ *   Joe Orost           (decvax!vax135!petsd!joe)
+ *   Dave Mack           (csu@alembic.acs.com)
+ *   Peter Jannesen, Network Communication Systems
+ *                       (peter@ncs.nl)
+ *
+ * marc@suse.de : a small security fix for a buffer overflow
+ *
+ * [... History snipped ...]
+ *
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+
+/* Default input buffer size */
+#define IBUFSIZ 2048
+
+/* Default output buffer size */
+#define OBUFSIZ 2048
+
+/* Defines for third byte of header */
+#define BIT_MASK        0x1f    /* Mask for 'number of compresssion bits'       */
+                                /* Masks 0x20 and 0x40 are free.                */
+                                /* I think 0x20 should mean that there is       */
+                                /* a fourth header byte (for expansion).        */
+#define BLOCK_MODE      0x80    /* Block compression if table is full and       */
+                                /* compression rate is dropping flush tables    */
+                                /* the next two codes should not be changed lightly, as they must not   */
+                                /* lie within the contiguous general code space.                        */
+#define FIRST   257     /* first free entry */
+#define CLEAR   256     /* table clear output code */
+
+#define INIT_BITS 9     /* initial number of bits/code */
+
+
+/* machine variants which require cc -Dmachine:  pdp11, z8000, DOS */
+#define HBITS      17   /* 50% occupancy */
+#define HSIZE      (1<<HBITS)
+#define HMASK      (HSIZE-1)    /* unused */
+#define HPRIME     9941         /* unused */
+#define BITS       16
+#define BITS_STR   "16"
+#undef  MAXSEG_64K              /* unused */
+#define MAXCODE(n) (1L << (n))
+
+#define htabof(i)               htab[i]
+#define codetabof(i)            codetab[i]
+#define tab_prefixof(i)         codetabof(i)
+#define tab_suffixof(i)         ((unsigned char *)(htab))[i]
+#define de_stack                ((unsigned char *)&(htab[HSIZE-1]))
+#define clear_tab_prefixof()    memset(codetab, 0, 256)
+
+/*
+ * Decompress stdin to stdout.  This routine adapts to the codes in the
+ * file building the "string" table on-the-fly; requiring no table to
+ * be stored in the compressed file.
+ */
+
+IF_DESKTOP(long long) int FAST_FUNC
+unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
+{
+	IF_DESKTOP(long long total_written = 0;)
+	IF_DESKTOP(long long) int retval = -1;
+	unsigned char *stackp;
+	int finchar;
+	long oldcode;
+	long incode;
+	int inbits;
+	int posbits;
+	int outpos;
+	int insize;
+	int bitmask;
+	long free_ent;
+	long maxcode;
+	long maxmaxcode;
+	int n_bits;
+	int rsize = 0;
+	unsigned char *inbuf; /* were eating insane amounts of stack - */
+	unsigned char *outbuf; /* bad for some embedded targets */
+	unsigned char *htab;
+	unsigned short *codetab;
+
+	/* Hmm, these were statics - why?! */
+	/* user settable max # bits/code */
+	int maxbits; /* = BITS; */
+	/* block compress mode -C compatible with 2.0 */
+	int block_mode; /* = BLOCK_MODE; */
+
+	if (check_signature16(aux, src_fd, COMPRESS_MAGIC))
+		return -1;
+
+	inbuf = xzalloc(IBUFSIZ + 64);
+	outbuf = xzalloc(OBUFSIZ + 2048);
+	htab = xzalloc(HSIZE);  /* wasn't zeroed out before, maybe can xmalloc? */
+	codetab = xzalloc(HSIZE * sizeof(codetab[0]));
+
+	insize = 0;
+
+	/* xread isn't good here, we have to return - caller may want
+	 * to do some cleanup (e.g. delete incomplete unpacked file etc) */
+	if (full_read(src_fd, inbuf, 1) != 1) {
+		bb_error_msg("short read");
+		goto err;
+	}
+
+	maxbits = inbuf[0] & BIT_MASK;
+	block_mode = inbuf[0] & BLOCK_MODE;
+	maxmaxcode = MAXCODE(maxbits);
+
+	if (maxbits > BITS) {
+		bb_error_msg("compressed with %d bits, can only handle "
+				BITS_STR" bits", maxbits);
+		goto err;
+	}
+
+	n_bits = INIT_BITS;
+	maxcode = MAXCODE(INIT_BITS) - 1;
+	bitmask = (1 << INIT_BITS) - 1;
+	oldcode = -1;
+	finchar = 0;
+	outpos = 0;
+	posbits = 0 << 3;
+
+	free_ent = ((block_mode) ? FIRST : 256);
+
+	/* As above, initialize the first 256 entries in the table. */
+	/*clear_tab_prefixof(); - done by xzalloc */
+
+	{
+		int i;
+		for (i = 255; i >= 0; --i)
+			tab_suffixof(i) = (unsigned char) i;
+	}
+
+	do {
+ resetbuf:
+		{
+			int i;
+			int e;
+			int o;
+
+			o = posbits >> 3;
+			e = insize - o;
+
+			for (i = 0; i < e; ++i)
+				inbuf[i] = inbuf[i + o];
+
+			insize = e;
+			posbits = 0;
+		}
+
+		if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) {
+			rsize = safe_read(src_fd, inbuf + insize, IBUFSIZ);
+			if (rsize < 0)
+				bb_error_msg_and_die(bb_msg_read_error);
+			insize += rsize;
+		}
+
+		inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 :
+				  (insize << 3) - (n_bits - 1));
+
+		while (inbits > posbits) {
+			long code;
+
+			if (free_ent > maxcode) {
+				posbits =
+					((posbits - 1) +
+					 ((n_bits << 3) -
+					  (posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
+				++n_bits;
+				if (n_bits == maxbits) {
+					maxcode = maxmaxcode;
+				} else {
+					maxcode = MAXCODE(n_bits) - 1;
+				}
+				bitmask = (1 << n_bits) - 1;
+				goto resetbuf;
+			}
+			{
+				unsigned char *p = &inbuf[posbits >> 3];
+				code = ((p[0]
+					| ((long) (p[1]) << 8)
+					| ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask;
+			}
+			posbits += n_bits;
+
+			if (oldcode == -1) {
+				if (code >= 256)
+					bb_error_msg_and_die("corrupted data"); /* %ld", code); */
+				oldcode = code;
+				finchar = (int) oldcode;
+				outbuf[outpos++] = (unsigned char) finchar;
+				continue;
+			}
+
+			if (code == CLEAR && block_mode) {
+				clear_tab_prefixof();
+				free_ent = FIRST - 1;
+				posbits =
+					((posbits - 1) +
+					 ((n_bits << 3) -
+					  (posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
+				n_bits = INIT_BITS;
+				maxcode = MAXCODE(INIT_BITS) - 1;
+				bitmask = (1 << INIT_BITS) - 1;
+				goto resetbuf;
+			}
+
+			incode = code;
+			stackp = de_stack;
+
+			/* Special case for KwKwK string. */
+			if (code >= free_ent) {
+				if (code > free_ent) {
+/*
+					unsigned char *p;
+
+					posbits -= n_bits;
+					p = &inbuf[posbits >> 3];
+					bb_error_msg
+						("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)",
+						insize, posbits, p[-1], p[0], p[1], p[2], p[3],
+						(posbits & 07));
+*/
+					bb_error_msg("corrupted data");
+					goto err;
+				}
+
+				*--stackp = (unsigned char) finchar;
+				code = oldcode;
+			}
+
+			/* Generate output characters in reverse order */
+			while (code >= 256) {
+				if (stackp <= &htabof(0))
+					bb_error_msg_and_die("corrupted data");
+				*--stackp = tab_suffixof(code);
+				code = tab_prefixof(code);
+			}
+
+			finchar = tab_suffixof(code);
+			*--stackp = (unsigned char) finchar;
+
+			/* And put them out in forward order */
+			{
+				int i;
+
+				i = de_stack - stackp;
+				if (outpos + i >= OBUFSIZ) {
+					do {
+						if (i > OBUFSIZ - outpos) {
+							i = OBUFSIZ - outpos;
+						}
+
+						if (i > 0) {
+							memcpy(outbuf + outpos, stackp, i);
+							outpos += i;
+						}
+
+						if (outpos >= OBUFSIZ) {
+							xwrite(dst_fd, outbuf, outpos);
+							IF_DESKTOP(total_written += outpos;)
+							outpos = 0;
+						}
+						stackp += i;
+						i = de_stack - stackp;
+					} while (i > 0);
+				} else {
+					memcpy(outbuf + outpos, stackp, i);
+					outpos += i;
+				}
+			}
+
+			/* Generate the new entry. */
+			if (free_ent < maxmaxcode) {
+				tab_prefixof(free_ent) = (unsigned short) oldcode;
+				tab_suffixof(free_ent) = (unsigned char) finchar;
+				free_ent++;
+			}
+
+			/* Remember previous code.  */
+			oldcode = incode;
+		}
+
+	} while (rsize > 0);
+
+	if (outpos > 0) {
+		xwrite(dst_fd, outbuf, outpos);
+		IF_DESKTOP(total_written += outpos;)
+	}
+
+	retval = IF_DESKTOP(total_written) + 0;
+ err:
+	free(inbuf);
+	free(outbuf);
+	free(htab);
+	free(codetab);
+	return retval;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/decompress_unlzma.c b/ap/app/busybox/src/archival/libarchive/decompress_unlzma.c
new file mode 100644
index 0000000..cfde8ea
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/decompress_unlzma.c
@@ -0,0 +1,465 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Small lzma deflate implementation.
+ * Copyright (C) 2006  Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
+ * Copyright (C) 1999-2005  Igor Pavlov
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+#include "bb_archive.h"
+
+#if ENABLE_FEATURE_LZMA_FAST
+#  define speed_inline ALWAYS_INLINE
+#  define size_inline
+#else
+#  define speed_inline
+#  define size_inline ALWAYS_INLINE
+#endif
+
+
+typedef struct {
+	int fd;
+	uint8_t *ptr;
+
+/* Was keeping rc on stack in unlzma and separately allocating buffer,
+ * but with "buffer 'attached to' allocated rc" code is smaller: */
+	/* uint8_t *buffer; */
+#define RC_BUFFER ((uint8_t*)(rc+1))
+
+	uint8_t *buffer_end;
+
+/* Had provisions for variable buffer, but we don't need it here */
+	/* int buffer_size; */
+#define RC_BUFFER_SIZE 0x10000
+
+	uint32_t code;
+	uint32_t range;
+	uint32_t bound;
+} rc_t;
+
+#define RC_TOP_BITS 24
+#define RC_MOVE_BITS 5
+#define RC_MODEL_TOTAL_BITS 11
+
+
+/* Called twice: once at startup (LZMA_FAST only) and once in rc_normalize() */
+static size_inline void rc_read(rc_t *rc)
+{
+	int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE);
+//TODO: return -1 instead
+//This will make unlzma delete broken unpacked file on unpack errors
+	if (buffer_size <= 0)
+		bb_error_msg_and_die("unexpected EOF");
+	rc->ptr = RC_BUFFER;
+	rc->buffer_end = RC_BUFFER + buffer_size;
+}
+
+/* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */
+static void rc_do_normalize(rc_t *rc)
+{
+	if (rc->ptr >= rc->buffer_end)
+		rc_read(rc);
+	rc->range <<= 8;
+	rc->code = (rc->code << 8) | *rc->ptr++;
+}
+
+/* Called once */
+static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */
+{
+	int i;
+	rc_t *rc;
+
+	rc = xzalloc(sizeof(*rc) + RC_BUFFER_SIZE);
+
+	rc->fd = fd;
+	/* rc->ptr = rc->buffer_end; */
+
+	for (i = 0; i < 5; i++) {
+#if ENABLE_FEATURE_LZMA_FAST
+		if (rc->ptr >= rc->buffer_end)
+			rc_read(rc);
+		rc->code = (rc->code << 8) | *rc->ptr++;
+#else
+		rc_do_normalize(rc);
+#endif
+	}
+	rc->range = 0xFFFFFFFF;
+	return rc;
+}
+
+/* Called once  */
+static ALWAYS_INLINE void rc_free(rc_t *rc)
+{
+	free(rc);
+}
+
+static ALWAYS_INLINE void rc_normalize(rc_t *rc)
+{
+	if (rc->range < (1 << RC_TOP_BITS)) {
+		rc_do_normalize(rc);
+	}
+}
+
+/* rc_is_bit_1 is called 9 times */
+static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p)
+{
+	rc_normalize(rc);
+	rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
+	if (rc->code < rc->bound) {
+		rc->range = rc->bound;
+		*p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
+		return 0;
+	}
+	rc->range -= rc->bound;
+	rc->code -= rc->bound;
+	*p -= *p >> RC_MOVE_BITS;
+	return 1;
+}
+
+/* Called 4 times in unlzma loop */
+static speed_inline int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol)
+{
+	int ret = rc_is_bit_1(rc, p);
+	*symbol = *symbol * 2 + ret;
+	return ret;
+}
+
+/* Called once */
+static ALWAYS_INLINE int rc_direct_bit(rc_t *rc)
+{
+	rc_normalize(rc);
+	rc->range >>= 1;
+	if (rc->code >= rc->range) {
+		rc->code -= rc->range;
+		return 1;
+	}
+	return 0;
+}
+
+/* Called twice */
+static speed_inline void
+rc_bit_tree_decode(rc_t *rc, uint16_t *p, int num_levels, int *symbol)
+{
+	int i = num_levels;
+
+	*symbol = 1;
+	while (i--)
+		rc_get_bit(rc, p + *symbol, symbol);
+	*symbol -= 1 << num_levels;
+}
+
+
+typedef struct {
+	uint8_t pos;
+	uint32_t dict_size;
+	uint64_t dst_size;
+} PACKED lzma_header_t;
+
+
+/* #defines will force compiler to compute/optimize each one with each usage.
+ * Have heart and use enum instead. */
+enum {
+	LZMA_BASE_SIZE = 1846,
+	LZMA_LIT_SIZE  = 768,
+
+	LZMA_NUM_POS_BITS_MAX = 4,
+
+	LZMA_LEN_NUM_LOW_BITS  = 3,
+	LZMA_LEN_NUM_MID_BITS  = 3,
+	LZMA_LEN_NUM_HIGH_BITS = 8,
+
+	LZMA_LEN_CHOICE     = 0,
+	LZMA_LEN_CHOICE_2   = (LZMA_LEN_CHOICE + 1),
+	LZMA_LEN_LOW        = (LZMA_LEN_CHOICE_2 + 1),
+	LZMA_LEN_MID        = (LZMA_LEN_LOW \
+	                      + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS))),
+	LZMA_LEN_HIGH       = (LZMA_LEN_MID \
+	                      + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS))),
+	LZMA_NUM_LEN_PROBS  = (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS)),
+
+	LZMA_NUM_STATES     = 12,
+	LZMA_NUM_LIT_STATES = 7,
+
+	LZMA_START_POS_MODEL_INDEX = 4,
+	LZMA_END_POS_MODEL_INDEX   = 14,
+	LZMA_NUM_FULL_DISTANCES    = (1 << (LZMA_END_POS_MODEL_INDEX >> 1)),
+
+	LZMA_NUM_POS_SLOT_BITS = 6,
+	LZMA_NUM_LEN_TO_POS_STATES = 4,
+
+	LZMA_NUM_ALIGN_BITS = 4,
+
+	LZMA_MATCH_MIN_LEN  = 2,
+
+	LZMA_IS_MATCH       = 0,
+	LZMA_IS_REP         = (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)),
+	LZMA_IS_REP_G0      = (LZMA_IS_REP + LZMA_NUM_STATES),
+	LZMA_IS_REP_G1      = (LZMA_IS_REP_G0 + LZMA_NUM_STATES),
+	LZMA_IS_REP_G2      = (LZMA_IS_REP_G1 + LZMA_NUM_STATES),
+	LZMA_IS_REP_0_LONG  = (LZMA_IS_REP_G2 + LZMA_NUM_STATES),
+	LZMA_POS_SLOT       = (LZMA_IS_REP_0_LONG \
+	                      + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)),
+	LZMA_SPEC_POS       = (LZMA_POS_SLOT \
+	                      + (LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS)),
+	LZMA_ALIGN          = (LZMA_SPEC_POS \
+	                      + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX),
+	LZMA_LEN_CODER      = (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS)),
+	LZMA_REP_LEN_CODER  = (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS),
+	LZMA_LITERAL        = (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS),
+};
+
+
+IF_DESKTOP(long long) int FAST_FUNC
+unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst_fd)
+{
+	IF_DESKTOP(long long total_written = 0;)
+	lzma_header_t header;
+	int lc, pb, lp;
+	uint32_t pos_state_mask;
+	uint32_t literal_pos_mask;
+	uint16_t *p;
+	int num_bits;
+	int num_probs;
+	rc_t *rc;
+	int i;
+	uint8_t *buffer;
+	uint8_t previous_byte = 0;
+	size_t buffer_pos = 0, global_pos = 0;
+	int len = 0;
+	int state = 0;
+	uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+
+	if (full_read(src_fd, &header, sizeof(header)) != sizeof(header)
+	 || header.pos >= (9 * 5 * 5)
+	) {
+		bb_error_msg("bad lzma header");
+		return -1;
+	}
+
+	i = header.pos / 9;
+	lc = header.pos % 9;
+	pb = i / 5;
+	lp = i % 5;
+	pos_state_mask = (1 << pb) - 1;
+	literal_pos_mask = (1 << lp) - 1;
+
+	header.dict_size = SWAP_LE32(header.dict_size);
+	header.dst_size = SWAP_LE64(header.dst_size);
+
+	if (header.dict_size == 0)
+		header.dict_size++;
+
+	buffer = xmalloc(MIN(header.dst_size, header.dict_size));
+
+	num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
+	p = xmalloc(num_probs * sizeof(*p));
+	num_probs += LZMA_LITERAL - LZMA_BASE_SIZE;
+	for (i = 0; i < num_probs; i++)
+		p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
+
+	rc = rc_init(src_fd); /*, RC_BUFFER_SIZE); */
+
+	while (global_pos + buffer_pos < header.dst_size) {
+		int pos_state = (buffer_pos + global_pos) & pos_state_mask;
+		uint16_t *prob = p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state;
+
+		if (!rc_is_bit_1(rc, prob)) {
+			static const char next_state[LZMA_NUM_STATES] =
+				{ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 };
+			int mi = 1;
+
+			prob = (p + LZMA_LITERAL
+			        + (LZMA_LIT_SIZE * ((((buffer_pos + global_pos) & literal_pos_mask) << lc)
+			                            + (previous_byte >> (8 - lc))
+			                           )
+			          )
+			);
+
+			if (state >= LZMA_NUM_LIT_STATES) {
+				int match_byte;
+				uint32_t pos = buffer_pos - rep0;
+
+				while (pos >= header.dict_size)
+					pos += header.dict_size;
+				match_byte = buffer[pos];
+				do {
+					int bit;
+
+					match_byte <<= 1;
+					bit = match_byte & 0x100;
+					bit ^= (rc_get_bit(rc, prob + 0x100 + bit + mi, &mi) << 8); /* 0x100 or 0 */
+					if (bit)
+						break;
+				} while (mi < 0x100);
+			}
+			while (mi < 0x100) {
+				rc_get_bit(rc, prob + mi, &mi);
+			}
+
+			state = next_state[state];
+
+			previous_byte = (uint8_t) mi;
+#if ENABLE_FEATURE_LZMA_FAST
+ one_byte1:
+			buffer[buffer_pos++] = previous_byte;
+			if (buffer_pos == header.dict_size) {
+				buffer_pos = 0;
+				global_pos += header.dict_size;
+				if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size)
+					goto bad;
+				IF_DESKTOP(total_written += header.dict_size;)
+			}
+#else
+			len = 1;
+			goto one_byte2;
+#endif
+		} else {
+			int offset;
+			uint16_t *prob2;
+#define prob_len prob2
+
+			prob2 = p + LZMA_IS_REP + state;
+			if (!rc_is_bit_1(rc, prob2)) {
+				rep3 = rep2;
+				rep2 = rep1;
+				rep1 = rep0;
+				state = state < LZMA_NUM_LIT_STATES ? 0 : 3;
+				prob2 = p + LZMA_LEN_CODER;
+			} else {
+				prob2 += LZMA_IS_REP_G0 - LZMA_IS_REP;
+				if (!rc_is_bit_1(rc, prob2)) {
+					prob2 = (p + LZMA_IS_REP_0_LONG
+					        + (state << LZMA_NUM_POS_BITS_MAX)
+					        + pos_state
+					);
+					if (!rc_is_bit_1(rc, prob2)) {
+#if ENABLE_FEATURE_LZMA_FAST
+						uint32_t pos = buffer_pos - rep0;
+						state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
+						while (pos >= header.dict_size)
+							pos += header.dict_size;
+						previous_byte = buffer[pos];
+						goto one_byte1;
+#else
+						state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
+						len = 1;
+						goto string;
+#endif
+					}
+				} else {
+					uint32_t distance;
+
+					prob2 += LZMA_IS_REP_G1 - LZMA_IS_REP_G0;
+					distance = rep1;
+					if (rc_is_bit_1(rc, prob2)) {
+						prob2 += LZMA_IS_REP_G2 - LZMA_IS_REP_G1;
+						distance = rep2;
+						if (rc_is_bit_1(rc, prob2)) {
+							distance = rep3;
+							rep3 = rep2;
+						}
+						rep2 = rep1;
+					}
+					rep1 = rep0;
+					rep0 = distance;
+				}
+				state = state < LZMA_NUM_LIT_STATES ? 8 : 11;
+				prob2 = p + LZMA_REP_LEN_CODER;
+			}
+
+			prob_len = prob2 + LZMA_LEN_CHOICE;
+			num_bits = LZMA_LEN_NUM_LOW_BITS;
+			if (!rc_is_bit_1(rc, prob_len)) {
+				prob_len += LZMA_LEN_LOW - LZMA_LEN_CHOICE
+				            + (pos_state << LZMA_LEN_NUM_LOW_BITS);
+				offset = 0;
+			} else {
+				prob_len += LZMA_LEN_CHOICE_2 - LZMA_LEN_CHOICE;
+				if (!rc_is_bit_1(rc, prob_len)) {
+					prob_len += LZMA_LEN_MID - LZMA_LEN_CHOICE_2
+					            + (pos_state << LZMA_LEN_NUM_MID_BITS);
+					offset = 1 << LZMA_LEN_NUM_LOW_BITS;
+					num_bits += LZMA_LEN_NUM_MID_BITS - LZMA_LEN_NUM_LOW_BITS;
+				} else {
+					prob_len += LZMA_LEN_HIGH - LZMA_LEN_CHOICE_2;
+					offset = ((1 << LZMA_LEN_NUM_LOW_BITS)
+					          + (1 << LZMA_LEN_NUM_MID_BITS));
+					num_bits += LZMA_LEN_NUM_HIGH_BITS - LZMA_LEN_NUM_LOW_BITS;
+				}
+			}
+			rc_bit_tree_decode(rc, prob_len, num_bits, &len);
+			len += offset;
+
+			if (state < 4) {
+				int pos_slot;
+				uint16_t *prob3;
+
+				state += LZMA_NUM_LIT_STATES;
+				prob3 = p + LZMA_POS_SLOT +
+				       ((len < LZMA_NUM_LEN_TO_POS_STATES ? len :
+				         LZMA_NUM_LEN_TO_POS_STATES - 1)
+				         << LZMA_NUM_POS_SLOT_BITS);
+				rc_bit_tree_decode(rc, prob3,
+					LZMA_NUM_POS_SLOT_BITS, &pos_slot);
+				rep0 = pos_slot;
+				if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
+					int i2, mi2, num_bits2 = (pos_slot >> 1) - 1;
+					rep0 = 2 | (pos_slot & 1);
+					if (pos_slot < LZMA_END_POS_MODEL_INDEX) {
+						rep0 <<= num_bits2;
+						prob3 = p + LZMA_SPEC_POS + rep0 - pos_slot - 1;
+					} else {
+						for (; num_bits2 != LZMA_NUM_ALIGN_BITS; num_bits2--)
+							rep0 = (rep0 << 1) | rc_direct_bit(rc);
+						rep0 <<= LZMA_NUM_ALIGN_BITS;
+						prob3 = p + LZMA_ALIGN;
+					}
+					i2 = 1;
+					mi2 = 1;
+					while (num_bits2--) {
+						if (rc_get_bit(rc, prob3 + mi2, &mi2))
+							rep0 |= i2;
+						i2 <<= 1;
+					}
+				}
+				if (++rep0 == 0)
+					break;
+			}
+
+			len += LZMA_MATCH_MIN_LEN;
+ IF_NOT_FEATURE_LZMA_FAST(string:)
+			do {
+				uint32_t pos = buffer_pos - rep0;
+				while (pos >= header.dict_size)
+					pos += header.dict_size;
+				previous_byte = buffer[pos];
+ IF_NOT_FEATURE_LZMA_FAST(one_byte2:)
+				buffer[buffer_pos++] = previous_byte;
+				if (buffer_pos == header.dict_size) {
+					buffer_pos = 0;
+					global_pos += header.dict_size;
+					if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size)
+						goto bad;
+					IF_DESKTOP(total_written += header.dict_size;)
+				}
+				len--;
+			} while (len != 0 && buffer_pos < header.dst_size);
+		}
+	}
+
+	{
+		IF_NOT_DESKTOP(int total_written = 0; /* success */)
+		IF_DESKTOP(total_written += buffer_pos;)
+		if (full_write(dst_fd, buffer, buffer_pos) != (ssize_t)buffer_pos) {
+ bad:
+			total_written = -1; /* failure */
+		}
+		rc_free(rc);
+		free(p);
+		free(buffer);
+		return total_written;
+	}
+}
diff --git a/ap/app/busybox/src/archival/libarchive/decompress_unxz.c b/ap/app/busybox/src/archival/libarchive/decompress_unxz.c
new file mode 100644
index 0000000..79b48a1
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/decompress_unxz.c
@@ -0,0 +1,102 @@
+/*
+ * This file uses XZ Embedded library code which is written
+ * by Lasse Collin <lasse.collin@tukaani.org>
+ * and Igor Pavlov <http://7-zip.org/>
+ *
+ * See README file in unxz/ directory for more information.
+ *
+ * This file is:
+ * Copyright (C) 2010 Denys Vlasenko <vda.linux@googlemail.com>
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+#include "bb_archive.h"
+
+#define XZ_FUNC FAST_FUNC
+#define XZ_EXTERN static
+
+#define XZ_DEC_DYNALLOC
+
+/* Skip check (rather than fail) of unsupported hash functions */
+#define XZ_DEC_ANY_CHECK  1
+
+/* We use our own crc32 function */
+#define XZ_INTERNAL_CRC32 0
+static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
+{
+	return ~crc32_block_endian0(~crc, buf, size, global_crc32_table);
+}
+
+/* We use arch-optimized unaligned accessors */
+#define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); })
+#define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); })
+#define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val))
+#define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val))
+
+#include "unxz/xz_dec_bcj.c"
+#include "unxz/xz_dec_lzma2.c"
+#include "unxz/xz_dec_stream.c"
+
+IF_DESKTOP(long long) int FAST_FUNC
+unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
+{
+	struct xz_buf iobuf;
+	struct xz_dec *state;
+	unsigned char *membuf;
+	IF_DESKTOP(long long) int total = 0;
+
+	if (!global_crc32_table)
+		global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0);
+
+	memset(&iobuf, 0, sizeof(iobuf));
+	membuf = xmalloc(2 * BUFSIZ);
+	iobuf.in = membuf;
+	iobuf.out = membuf + BUFSIZ;
+	iobuf.out_size = BUFSIZ;
+
+	if (!aux || aux->check_signature == 0) {
+		/* Preload XZ file signature */
+		strcpy((char*)membuf, HEADER_MAGIC);
+		iobuf.in_size = HEADER_MAGIC_SIZE;
+	} /* else: let xz code read & check it */
+
+	/* Limit memory usage to about 64 MiB. */
+	state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024);
+
+	while (1) {
+		enum xz_ret r;
+
+		if (iobuf.in_pos == iobuf.in_size) {
+			int rd = safe_read(src_fd, membuf, BUFSIZ);
+			if (rd < 0) {
+				bb_error_msg(bb_msg_read_error);
+				total = -1;
+				break;
+			}
+			iobuf.in_size = rd;
+			iobuf.in_pos = 0;
+		}
+//		bb_error_msg(">in pos:%d size:%d out pos:%d size:%d",
+//				iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size);
+		r = xz_dec_run(state, &iobuf);
+//		bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d",
+//				iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, r);
+		if (iobuf.out_pos) {
+			xwrite(dst_fd, iobuf.out, iobuf.out_pos);
+			IF_DESKTOP(total += iobuf.out_pos;)
+			iobuf.out_pos = 0;
+		}
+		if (r == XZ_STREAM_END) {
+			break;
+		}
+		if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) {
+			bb_error_msg("corrupted data");
+			total = -1;
+			break;
+		}
+	}
+	xz_dec_end(state);
+	free(membuf);
+
+	return total;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/filter_accept_all.c b/ap/app/busybox/src/archival/libarchive/filter_accept_all.c
new file mode 100644
index 0000000..c33f7d3
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/filter_accept_all.c
@@ -0,0 +1,17 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2002 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+/* Accept any non-null name, its not really a filter at all */
+char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle)
+{
+	if (archive_handle->file_header->name)
+		return EXIT_SUCCESS;
+	return EXIT_FAILURE;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/filter_accept_list.c b/ap/app/busybox/src/archival/libarchive/filter_accept_list.c
new file mode 100644
index 0000000..a2d4b23
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/filter_accept_list.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2002 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+/*
+ * Accept names that are in the accept list, ignoring reject list.
+ */
+char FAST_FUNC filter_accept_list(archive_handle_t *archive_handle)
+{
+	if (find_list_entry(archive_handle->accept, archive_handle->file_header->name))
+		return EXIT_SUCCESS;
+	return EXIT_FAILURE;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/filter_accept_list_reassign.c b/ap/app/busybox/src/archival/libarchive/filter_accept_list_reassign.c
new file mode 100644
index 0000000..3d19abe
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/filter_accept_list_reassign.c
@@ -0,0 +1,51 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *  Copyright (C) 2002 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+/* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */
+
+/*
+ * Reassign the subarchive metadata parser based on the filename extension
+ * e.g. if its a .tar.gz modify archive_handle->sub_archive to process a .tar.gz
+ * or if its a .tar.bz2 make archive_handle->sub_archive handle that
+ */
+char FAST_FUNC filter_accept_list_reassign(archive_handle_t *archive_handle)
+{
+	/* Check the file entry is in the accept list */
+	if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) {
+		const char *name_ptr;
+
+		/* Find extension */
+		name_ptr = strrchr(archive_handle->file_header->name, '.');
+		if (!name_ptr)
+			return EXIT_FAILURE;
+		name_ptr++;
+
+		/* Modify the subarchive handler based on the extension */
+		if (ENABLE_FEATURE_SEAMLESS_GZ
+		 && strcmp(name_ptr, "gz") == 0
+		) {
+			archive_handle->dpkg__action_data_subarchive = get_header_tar_gz;
+			return EXIT_SUCCESS;
+		}
+		if (ENABLE_FEATURE_SEAMLESS_BZ2
+		 && strcmp(name_ptr, "bz2") == 0
+		) {
+			archive_handle->dpkg__action_data_subarchive = get_header_tar_bz2;
+			return EXIT_SUCCESS;
+		}
+		if (ENABLE_FEATURE_SEAMLESS_LZMA
+		 && strcmp(name_ptr, "lzma") == 0
+		) {
+			archive_handle->dpkg__action_data_subarchive = get_header_tar_lzma;
+			return EXIT_SUCCESS;
+		}
+	}
+	return EXIT_FAILURE;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/filter_accept_reject_list.c b/ap/app/busybox/src/archival/libarchive/filter_accept_reject_list.c
new file mode 100644
index 0000000..2483749
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/filter_accept_reject_list.c
@@ -0,0 +1,38 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2002 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+/*
+ * Accept names that are in the accept list and not in the reject list
+ */
+char FAST_FUNC filter_accept_reject_list(archive_handle_t *archive_handle)
+{
+	const char *key;
+	const llist_t *reject_entry;
+	const llist_t *accept_entry;
+
+	key = archive_handle->file_header->name;
+
+	/* If the key is in a reject list fail */
+	reject_entry = find_list_entry2(archive_handle->reject, key);
+	if (reject_entry) {
+		return EXIT_FAILURE;
+	}
+
+	/* Fail if an accept list was specified and the key wasnt in there */
+	if (archive_handle->accept) {
+		accept_entry = find_list_entry2(archive_handle->accept, key);
+		if (!accept_entry) {
+			return EXIT_FAILURE;
+		}
+	}
+
+	/* Accepted */
+	return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/find_list_entry.c b/ap/app/busybox/src/archival/libarchive/find_list_entry.c
new file mode 100644
index 0000000..56032c6
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/find_list_entry.c
@@ -0,0 +1,54 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2002 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include <fnmatch.h>
+#include "libbb.h"
+#include "bb_archive.h"
+
+/* Find a string in a shell pattern list */
+const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename)
+{
+	while (list) {
+		if (fnmatch(list->data, filename, 0) == 0) {
+			return list;
+		}
+		list = list->link;
+	}
+	return NULL;
+}
+
+/* Same, but compares only path components present in pattern
+ * (extra trailing path components in filename are assumed to match)
+ */
+const llist_t* FAST_FUNC find_list_entry2(const llist_t *list, const char *filename)
+{
+	char buf[PATH_MAX];
+	int pattern_slash_cnt;
+	const char *c;
+	char *d;
+
+	while (list) {
+		c = list->data;
+		pattern_slash_cnt = 0;
+		while (*c)
+			if (*c++ == '/') pattern_slash_cnt++;
+		c = filename;
+		d = buf;
+		/* paranoia is better than buffer overflows */
+		while (*c && d != buf + sizeof(buf)-1) {
+			if (*c == '/' && --pattern_slash_cnt < 0)
+				break;
+			*d++ = *c++;
+		}
+		*d = '\0';
+		if (fnmatch(list->data, buf, 0) == 0) {
+			return list;
+		}
+		list = list->link;
+	}
+	return NULL;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/get_header_ar.c b/ap/app/busybox/src/archival/libarchive/get_header_ar.c
new file mode 100644
index 0000000..23c4124
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/get_header_ar.c
@@ -0,0 +1,133 @@
+/* vi: set sw=4 ts=4: */
+/* Copyright 2001 Glenn McGrath.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+#include "ar.h"
+
+static unsigned read_num(const char *str, int base)
+{
+	/* This code works because
+	 * on misformatted numbers bb_strtou returns all-ones */
+	int err = bb_strtou(str, NULL, base);
+	if (err == -1)
+		bb_error_msg_and_die("invalid ar header");
+	return err;
+}
+
+char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
+{
+	file_header_t *typed = archive_handle->file_header;
+	unsigned size;
+	union {
+		char raw[60];
+		struct ar_header formatted;
+	} ar;
+#if ENABLE_FEATURE_AR_LONG_FILENAMES
+	static char *ar_long_names;
+	static unsigned ar_long_name_size;
+#endif
+
+	/* dont use xread as we want to handle the error ourself */
+	if (read(archive_handle->src_fd, ar.raw, 60) != 60) {
+		/* End Of File */
+		return EXIT_FAILURE;
+	}
+
+	/* ar header starts on an even byte (2 byte aligned)
+	 * '\n' is used for padding
+	 */
+	if (ar.raw[0] == '\n') {
+		/* fix up the header, we started reading 1 byte too early */
+		memmove(ar.raw, &ar.raw[1], 59);
+		ar.raw[59] = xread_char(archive_handle->src_fd);
+		archive_handle->offset++;
+	}
+	archive_handle->offset += 60;
+
+	if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n')
+		bb_error_msg_and_die("invalid ar header");
+
+	/* FIXME: more thorough routine would be in order here
+	 * (we have something like that in tar)
+	 * but for now we are lax. */
+	ar.formatted.magic[0] = '\0'; /* else 4G-2 file will have size="4294967294`\n..." */
+	typed->size = size = read_num(ar.formatted.size, 10);
+
+	/* special filenames have '/' as the first character */
+	if (ar.formatted.name[0] == '/') {
+		if (ar.formatted.name[1] == ' ') {
+			/* This is the index of symbols in the file for compilers */
+			data_skip(archive_handle);
+			archive_handle->offset += size;
+			return get_header_ar(archive_handle); /* Return next header */
+		}
+#if ENABLE_FEATURE_AR_LONG_FILENAMES
+		if (ar.formatted.name[1] == '/') {
+			/* If the second char is a '/' then this entries data section
+			 * stores long filename for multiple entries, they are stored
+			 * in static variable long_names for use in future entries
+			 */
+			ar_long_name_size = size;
+			free(ar_long_names);
+			ar_long_names = xmalloc(size);
+			xread(archive_handle->src_fd, ar_long_names, size);
+			archive_handle->offset += size;
+			/* Return next header */
+			return get_header_ar(archive_handle);
+		}
+#else
+		bb_error_msg_and_die("long filenames not supported");
+#endif
+	}
+	/* Only size is always present, the rest may be missing in
+	 * long filename pseudo file. Thus we decode the rest
+	 * after dealing with long filename pseudo file.
+	 */
+	typed->mode = read_num(ar.formatted.mode, 8);
+	typed->mtime = read_num(ar.formatted.date, 10);
+	typed->uid = read_num(ar.formatted.uid, 10);
+	typed->gid = read_num(ar.formatted.gid, 10);
+
+#if ENABLE_FEATURE_AR_LONG_FILENAMES
+	if (ar.formatted.name[0] == '/') {
+		unsigned long_offset;
+
+		/* The number after the '/' indicates the offset in the ar data section
+		 * (saved in ar_long_names) that conatains the real filename */
+		long_offset = read_num(&ar.formatted.name[1], 10);
+		if (long_offset >= ar_long_name_size) {
+			bb_error_msg_and_die("can't resolve long filename");
+		}
+		typed->name = xstrdup(ar_long_names + long_offset);
+	} else
+#endif
+	{
+		/* short filenames */
+		typed->name = xstrndup(ar.formatted.name, 16);
+	}
+
+	typed->name[strcspn(typed->name, " /")] = '\0';
+
+	if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
+		archive_handle->action_header(typed);
+#if ENABLE_DPKG || ENABLE_DPKG_DEB
+		if (archive_handle->dpkg__sub_archive) {
+			while (archive_handle->dpkg__action_data_subarchive(archive_handle->dpkg__sub_archive) == EXIT_SUCCESS)
+				continue;
+		} else
+#endif
+			archive_handle->action_data(archive_handle);
+	} else {
+		data_skip(archive_handle);
+	}
+
+	archive_handle->offset += typed->size;
+	/* Set the file pointer to the correct spot, we may have been reading a compressed file */
+	lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET);
+
+	return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/get_header_cpio.c b/ap/app/busybox/src/archival/libarchive/get_header_cpio.c
new file mode 100644
index 0000000..1a0058b
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/get_header_cpio.c
@@ -0,0 +1,186 @@
+/* vi: set sw=4 ts=4: */
+/* Copyright 2002 Laurence Anderson
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+typedef struct hardlinks_t {
+	struct hardlinks_t *next;
+	int inode; /* TODO: must match maj/min too! */
+	int mode ;
+	int mtime; /* These three are useful only in corner case */
+	int uid  ; /* of hardlinks with zero size body */
+	int gid  ;
+	char name[1];
+} hardlinks_t;
+
+char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
+{
+	file_header_t *file_header = archive_handle->file_header;
+	char cpio_header[110];
+	int namesize;
+	int major, minor, nlink, mode, inode;
+	unsigned size, uid, gid, mtime;
+
+	/* There can be padding before archive header */
+	data_align(archive_handle, 4);
+
+	size = full_read(archive_handle->src_fd, cpio_header, 110);
+	if (size == 0) {
+		goto create_hardlinks;
+	}
+	if (size != 110) {
+		bb_error_msg_and_die("short read");
+	}
+	archive_handle->offset += 110;
+
+	if (strncmp(&cpio_header[0], "07070", 5) != 0
+	 || (cpio_header[5] != '1' && cpio_header[5] != '2')
+	) {
+		bb_error_msg_and_die("unsupported cpio format, use newc or crc");
+	}
+
+	if (sscanf(cpio_header + 6,
+			"%8x" "%8x" "%8x" "%8x"
+			"%8x" "%8x" "%8x" /*maj,min:*/ "%*16c"
+			/*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum: "%*8c"*/,
+			&inode, &mode, &uid, &gid,
+			&nlink, &mtime, &size,
+			&major, &minor, &namesize) != 10)
+		bb_error_msg_and_die("damaged cpio file");
+	file_header->mode = mode;
+	file_header->uid = uid;
+	file_header->gid = gid;
+	file_header->mtime = mtime;
+	file_header->size = size;
+
+	namesize &= 0x1fff; /* paranoia: limit names to 8k chars */
+	file_header->name = xzalloc(namesize + 1);
+	/* Read in filename */
+	xread(archive_handle->src_fd, file_header->name, namesize);
+	if (file_header->name[0] == '/') {
+		/* Testcase: echo /etc/hosts | cpio -pvd /tmp
+		 * Without this code, it tries to unpack /etc/hosts
+		 * into "/etc/hosts", not "etc/hosts".
+		 */
+		char *p = file_header->name;
+		do p++; while (*p == '/');
+		overlapping_strcpy(file_header->name, p);
+	}
+	archive_handle->offset += namesize;
+
+	/* Update offset amount and skip padding before file contents */
+	data_align(archive_handle, 4);
+
+	if (strcmp(file_header->name, "TRAILER!!!") == 0) {
+		/* Always round up. ">> 9" divides by 512 */
+		archive_handle->cpio__blocks = (uoff_t)(archive_handle->offset + 511) >> 9;
+		goto create_hardlinks;
+	}
+
+	file_header->link_target = NULL;
+	if (S_ISLNK(file_header->mode)) {
+		file_header->size &= 0x1fff; /* paranoia: limit names to 8k chars */
+		file_header->link_target = xzalloc(file_header->size + 1);
+		xread(archive_handle->src_fd, file_header->link_target, file_header->size);
+		archive_handle->offset += file_header->size;
+		file_header->size = 0; /* Stop possible seeks in future */
+	}
+
+// TODO: data_extract_all can't deal with hardlinks to non-files...
+// when fixed, change S_ISREG to !S_ISDIR here
+
+	if (nlink > 1 && S_ISREG(file_header->mode)) {
+		hardlinks_t *new = xmalloc(sizeof(*new) + namesize);
+		new->inode = inode;
+		new->mode  = mode ;
+		new->mtime = mtime;
+		new->uid   = uid  ;
+		new->gid   = gid  ;
+		strcpy(new->name, file_header->name);
+		/* Put file on a linked list for later */
+		if (size == 0) {
+			new->next = archive_handle->cpio__hardlinks_to_create;
+			archive_handle->cpio__hardlinks_to_create = new;
+			return EXIT_SUCCESS; /* Skip this one */
+			/* TODO: this breaks cpio -t (it does not show hardlinks) */
+		}
+		new->next = archive_handle->cpio__created_hardlinks;
+		archive_handle->cpio__created_hardlinks = new;
+	}
+	file_header->device = makedev(major, minor);
+
+	if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
+		archive_handle->action_data(archive_handle);
+//TODO: run "echo /etc/hosts | cpio -pv /tmp" twice. On 2nd run:
+//cpio: etc/hosts not created: newer or same age file exists
+//etc/hosts  <-- should NOT show it
+//2 blocks <-- should say "0 blocks"
+		archive_handle->action_header(file_header);
+	} else {
+		data_skip(archive_handle);
+	}
+
+	archive_handle->offset += file_header->size;
+
+	free(file_header->link_target);
+	free(file_header->name);
+	file_header->link_target = NULL;
+	file_header->name = NULL;
+
+	return EXIT_SUCCESS;
+
+ create_hardlinks:
+	free(file_header->link_target);
+	free(file_header->name);
+
+	while (archive_handle->cpio__hardlinks_to_create) {
+		hardlinks_t *cur;
+		hardlinks_t *make_me = archive_handle->cpio__hardlinks_to_create;
+
+		archive_handle->cpio__hardlinks_to_create = make_me->next;
+
+		memset(file_header, 0, sizeof(*file_header));
+		file_header->mtime = make_me->mtime;
+		file_header->name = make_me->name;
+		file_header->mode = make_me->mode;
+		file_header->uid = make_me->uid;
+		file_header->gid = make_me->gid;
+		/*file_header->size = 0;*/
+		/*file_header->link_target = NULL;*/
+
+		/* Try to find a file we are hardlinked to */
+		cur = archive_handle->cpio__created_hardlinks;
+		while (cur) {
+			/* TODO: must match maj/min too! */
+			if (cur->inode == make_me->inode) {
+				file_header->link_target = cur->name;
+				 /* link_target != NULL, size = 0: "I am a hardlink" */
+				if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
+					archive_handle->action_data(archive_handle);
+				free(make_me);
+				goto next_link;
+			}
+			cur = cur->next;
+		}
+		/* Oops... no file with such inode was created... do it now
+		 * (happens when hardlinked files are empty (zero length)) */
+		if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
+			archive_handle->action_data(archive_handle);
+		/* Move to the list of created hardlinked files */
+		make_me->next = archive_handle->cpio__created_hardlinks;
+		archive_handle->cpio__created_hardlinks = make_me;
+ next_link: ;
+	}
+
+	while (archive_handle->cpio__created_hardlinks) {
+		hardlinks_t *p = archive_handle->cpio__created_hardlinks;
+		archive_handle->cpio__created_hardlinks = p->next;
+		free(p);
+	}
+
+	return EXIT_FAILURE; /* "No more files to process" */
+}
diff --git a/ap/app/busybox/src/archival/libarchive/get_header_tar.c b/ap/app/busybox/src/archival/libarchive/get_header_tar.c
new file mode 100644
index 0000000..bc09756
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/get_header_tar.c
@@ -0,0 +1,475 @@
+/* vi: set sw=4 ts=4: */
+/* Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ *
+ * FIXME:
+ *    In privileged mode if uname and gname map to a uid and gid then use the
+ *    mapped value instead of the uid/gid values in tar header
+ *
+ * References:
+ *    GNU tar and star man pages,
+ *    Opengroup's ustar interchange format,
+ *    http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+typedef uint32_t aliased_uint32_t FIX_ALIASING;
+typedef off_t    aliased_off_t    FIX_ALIASING;
+
+
+const char* FAST_FUNC strip_unsafe_prefix(const char *str)
+{
+	const char *cp = str;
+	while (1) {
+		char *cp2;
+		if (*cp == '/') {
+			cp++;
+			continue;
+		}
+		if (strncmp(cp, "/../"+1, 3) == 0) {
+			cp += 3;
+			continue;
+		}
+		cp2 = strstr(cp, "/../");
+		if (!cp2)
+			break;
+		cp = cp2 + 4;
+	}
+	if (cp != str) {
+		static smallint warned = 0;
+		if (!warned) {
+			warned = 1;
+			bb_error_msg("removing leading '%.*s' from member names",
+				(int)(cp - str), str);
+		}
+	}
+	return cp;
+}
+
+/* NB: _DESTROYS_ str[len] character! */
+static unsigned long long getOctal(char *str, int len)
+{
+	unsigned long long v;
+	char *end;
+	/* NB: leading spaces are allowed. Using strtoull to handle that.
+	 * The downside is that we accept e.g. "-123" too :(
+	 */
+	str[len] = '\0';
+	v = strtoull(str, &end, 8);
+	/* std: "Each numeric field is terminated by one or more
+	 * <space> or NUL characters". We must support ' '! */
+	if (*end != '\0' && *end != ' ') {
+		int8_t first = str[0];
+		if (!(first & 0x80))
+			bb_error_msg_and_die("corrupted octal value in tar header");
+		/*
+		 * GNU tar uses "base-256 encoding" for very large numbers.
+		 * Encoding is binary, with highest bit always set as a marker
+		 * and sign in next-highest bit:
+		 * 80 00 .. 00 - zero
+		 * bf ff .. ff - largest positive number
+		 * ff ff .. ff - minus 1
+		 * c0 00 .. 00 - smallest negative number
+		 *
+		 * Example of tar file with 8914993153 (0x213600001) byte file.
+		 * Field starts at offset 7c:
+		 * 00070  30 30 30 00 30 30 30 30  30 30 30 00 80 00 00 00  |000.0000000.....|
+		 * 00080  00 00 00 02 13 60 00 01  31 31 31 32 30 33 33 36  |.....`..11120336|
+		 *
+		 * NB: tarballs with NEGATIVE unix times encoded that way were seen!
+		 */
+		/* Sign-extend 7bit 'first' to 64bit 'v' (that is, using 6th bit as sign): */
+		first <<= 1;
+		first >>= 1; /* now 7th bit = 6th bit */
+		v = first;   /* sign-extend 8 bits to 64 */
+		while (--len != 0)
+			v = (v << 8) + (uint8_t) *++str;
+	}
+	return v;
+}
+#define GET_OCTAL(a) getOctal((a), sizeof(a))
+
+/* "global" is 0 or 1 */
+static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global)
+{
+	char *buf, *p;
+	unsigned blk_sz;
+
+	blk_sz = (sz + 511) & (~511);
+	p = buf = xmalloc(blk_sz + 1);
+	xread(archive_handle->src_fd, buf, blk_sz);
+	archive_handle->offset += blk_sz;
+
+	/* prevent bb_strtou from running off the buffer */
+	buf[sz] = '\0';
+
+	while (sz != 0) {
+		char *end, *value;
+		unsigned len;
+
+		/* Every record has this format: "LEN NAME=VALUE\n" */
+		len = bb_strtou(p, &end, 10);
+		/* expect errno to be EINVAL, because the character
+		 * following the digits should be a space
+		 */
+		p += len;
+		sz -= len;
+		if ((int)sz < 0
+		 || len == 0
+		 || errno != EINVAL
+		 || *end != ' '
+		) {
+			bb_error_msg("malformed extended header, skipped");
+			// More verbose version:
+			//bb_error_msg("malformed extended header at %"OFF_FMT"d, skipped",
+			//		archive_handle->offset - (sz + len));
+			break;
+		}
+		/* overwrite the terminating newline with NUL
+		 * (we do not bother to check that it *was* a newline)
+		 */
+		p[-1] = '\0';
+		value = end + 1;
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+		if (!global && strncmp(value, "path=", sizeof("path=") - 1) == 0) {
+			value += sizeof("path=") - 1;
+			free(archive_handle->tar__longname);
+			archive_handle->tar__longname = xstrdup(value);
+			continue;
+		}
+#endif
+
+#if ENABLE_FEATURE_TAR_SELINUX
+		/* Scan for SELinux contexts, via "RHT.security.selinux" keyword.
+		 * This is what Red Hat's patched version of tar uses.
+		 */
+# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
+		if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) {
+			value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1;
+			free(archive_handle->tar__sctx[global]);
+			archive_handle->tar__sctx[global] = xstrdup(value);
+			continue;
+		}
+#endif
+	}
+
+	free(buf);
+}
+
+char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
+{
+	file_header_t *file_header = archive_handle->file_header;
+	struct tar_header_t tar;
+	char *cp;
+	int i, sum_u, sum;
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+	int sum_s;
+#endif
+	int parse_names;
+
+	/* Our "private data" */
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+# define p_longname (archive_handle->tar__longname)
+# define p_linkname (archive_handle->tar__linkname)
+#else
+# define p_longname 0
+# define p_linkname 0
+#endif
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX
+ again:
+#endif
+	/* Align header */
+	data_align(archive_handle, 512);
+
+ again_after_align:
+
+#if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT
+	/* to prevent misdetection of bz2 sig */
+	*(aliased_uint32_t*)&tar = 0;
+	i = full_read(archive_handle->src_fd, &tar, 512);
+	/* If GNU tar sees EOF in above read, it says:
+	 * "tar: A lone zero block at N", where N = kilobyte
+	 * where EOF was met (not EOF block, actual EOF!),
+	 * and exits with EXIT_SUCCESS.
+	 * We will mimic exit(EXIT_SUCCESS), although we will not mimic
+	 * the message and we don't check whether we indeed
+	 * saw zero block directly before this. */
+	if (i == 0) {
+		xfunc_error_retval = 0;
+ short_read:
+		bb_error_msg_and_die("short read");
+	}
+	if (i != 512) {
+		IF_FEATURE_TAR_AUTODETECT(goto autodetect;)
+		goto short_read;
+	}
+
+#else
+	i = 512;
+	xread(archive_handle->src_fd, &tar, i);
+#endif
+	archive_handle->offset += i;
+
+	/* If there is no filename its an empty header */
+	if (tar.name[0] == 0 && tar.prefix[0] == 0) {
+		if (archive_handle->tar__end) {
+			/* Second consecutive empty header - end of archive.
+			 * Read until the end to empty the pipe from gz or bz2
+			 */
+			while (full_read(archive_handle->src_fd, &tar, 512) == 512)
+				continue;
+			return EXIT_FAILURE;
+		}
+		archive_handle->tar__end = 1;
+		return EXIT_SUCCESS;
+	}
+	archive_handle->tar__end = 0;
+
+	/* Check header has valid magic, "ustar" is for the proper tar,
+	 * five NULs are for the old tar format  */
+	if (strncmp(tar.magic, "ustar", 5) != 0
+	 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
+	     || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
+	) {
+#if ENABLE_FEATURE_TAR_AUTODETECT
+ autodetect:
+		/* Two different causes for lseek() != 0:
+		 * unseekable fd (would like to support that too, but...),
+		 * or not first block (false positive, it's not .gz/.bz2!) */
+		if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0)
+			goto err;
+		if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 0) != 0)
+ err:
+			bb_error_msg_and_die("invalid tar magic");
+		archive_handle->offset = 0;
+		goto again_after_align;
+#endif
+		bb_error_msg_and_die("invalid tar magic");
+	}
+
+	/* Do checksum on headers.
+	 * POSIX says that checksum is done on unsigned bytes, but
+	 * Sun and HP-UX gets it wrong... more details in
+	 * GNU tar source. */
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+	sum_s = ' ' * sizeof(tar.chksum);
+#endif
+	sum_u = ' ' * sizeof(tar.chksum);
+	for (i = 0; i < 148; i++) {
+		sum_u += ((unsigned char*)&tar)[i];
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+		sum_s += ((signed char*)&tar)[i];
+#endif
+	}
+	for (i = 156; i < 512; i++) {
+		sum_u += ((unsigned char*)&tar)[i];
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+		sum_s += ((signed char*)&tar)[i];
+#endif
+	}
+	/* This field does not need special treatment (getOctal) */
+	{
+		char *endp; /* gcc likes temp var for &endp */
+		sum = strtoul(tar.chksum, &endp, 8);
+		if ((*endp != '\0' && *endp != ' ')
+		 || (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
+		) {
+			bb_error_msg_and_die("invalid tar header checksum");
+		}
+	}
+	/* don't use xstrtoul, tar.chksum may have leading spaces */
+	sum = strtoul(tar.chksum, NULL, 8);
+	if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
+		bb_error_msg_and_die("invalid tar header checksum");
+	}
+
+	/* 0 is reserved for high perf file, treat as normal file */
+	if (!tar.typeflag) tar.typeflag = '0';
+	parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7');
+
+	/* getOctal trashes subsequent field, therefore we call it
+	 * on fields in reverse order */
+	if (tar.devmajor[0]) {
+		char t = tar.prefix[0];
+		/* we trash prefix[0] here, but we DO need it later! */
+		unsigned minor = GET_OCTAL(tar.devminor);
+		unsigned major = GET_OCTAL(tar.devmajor);
+		file_header->device = makedev(major, minor);
+		tar.prefix[0] = t;
+	}
+	file_header->link_target = NULL;
+	if (!p_linkname && parse_names && tar.linkname[0]) {
+		file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname));
+		/* FIXME: what if we have non-link object with link_target? */
+		/* Will link_target be free()ed? */
+	}
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+	file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL;
+	file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;
+#endif
+	file_header->mtime = GET_OCTAL(tar.mtime);
+	file_header->size = GET_OCTAL(tar.size);
+	file_header->gid = GET_OCTAL(tar.gid);
+	file_header->uid = GET_OCTAL(tar.uid);
+	/* Set bits 0-11 of the files mode */
+	file_header->mode = 07777 & GET_OCTAL(tar.mode);
+
+	file_header->name = NULL;
+	if (!p_longname && parse_names) {
+		/* we trash mode[0] here, it's ok */
+		//tar.name[sizeof(tar.name)] = '\0'; - gcc 4.3.0 would complain
+		tar.mode[0] = '\0';
+		if (tar.prefix[0]) {
+			/* and padding[0] */
+			//tar.prefix[sizeof(tar.prefix)] = '\0'; - gcc 4.3.0 would complain
+			tar.padding[0] = '\0';
+			file_header->name = concat_path_file(tar.prefix, tar.name);
+		} else
+			file_header->name = xstrdup(tar.name);
+	}
+
+	/* Set bits 12-15 of the files mode */
+	/* (typeflag was not trashed because chksum does not use getOctal) */
+	switch (tar.typeflag) {
+	case '1': /* hardlink */
+		/* we mark hardlinks as regular files with zero size and a link name */
+		file_header->mode |= S_IFREG;
+		/* on size of link fields from star(4)
+		 * ... For tar archives written by pre POSIX.1-1988
+		 * implementations, the size field usually contains the size of
+		 * the file and needs to be ignored as no data may follow this
+		 * header type.  For POSIX.1- 1988 compliant archives, the size
+		 * field needs to be 0.  For POSIX.1-2001 compliant archives,
+		 * the size field may be non zero, indicating that file data is
+		 * included in the archive.
+		 * i.e; always assume this is zero for safety.
+		 */
+		goto size0;
+	case '7':
+	/* case 0: */
+	case '0':
+#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
+		if (last_char_is(file_header->name, '/')) {
+			goto set_dir;
+		}
+#endif
+		file_header->mode |= S_IFREG;
+		break;
+	case '2':
+		file_header->mode |= S_IFLNK;
+		/* have seen tarballs with size field containing
+		 * the size of the link target's name */
+ size0:
+		file_header->size = 0;
+		break;
+	case '3':
+		file_header->mode |= S_IFCHR;
+		goto size0; /* paranoia */
+	case '4':
+		file_header->mode |= S_IFBLK;
+		goto size0;
+	case '5':
+ IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:)
+		file_header->mode |= S_IFDIR;
+		goto size0;
+	case '6':
+		file_header->mode |= S_IFIFO;
+		goto size0;
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+	case 'L':
+		/* free: paranoia: tar with several consecutive longnames */
+		free(p_longname);
+		/* For paranoia reasons we allocate extra NUL char */
+		p_longname = xzalloc(file_header->size + 1);
+		/* We read ASCIZ string, including NUL */
+		xread(archive_handle->src_fd, p_longname, file_header->size);
+		archive_handle->offset += file_header->size;
+		/* return get_header_tar(archive_handle); */
+		/* gcc 4.1.1 didn't optimize it into jump */
+		/* so we will do it ourself, this also saves stack */
+		goto again;
+	case 'K':
+		free(p_linkname);
+		p_linkname = xzalloc(file_header->size + 1);
+		xread(archive_handle->src_fd, p_linkname, file_header->size);
+		archive_handle->offset += file_header->size;
+		/* return get_header_tar(archive_handle); */
+		goto again;
+	case 'D':	/* GNU dump dir */
+	case 'M':	/* Continuation of multi volume archive */
+	case 'N':	/* Old GNU for names > 100 characters */
+	case 'S':	/* Sparse file */
+	case 'V':	/* Volume header */
+#endif
+	case 'g':	/* pax global header */
+	case 'x': {	/* pax extended header */
+		if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
+			goto skip_ext_hdr;
+		process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g'));
+		goto again_after_align;
+	}
+ skip_ext_hdr:
+	{
+		off_t sz;
+		bb_error_msg("warning: skipping header '%c'", tar.typeflag);
+		sz = (file_header->size + 511) & ~(off_t)511;
+		archive_handle->offset += sz;
+		sz >>= 9; /* sz /= 512 but w/o contortions for signed div */
+		while (sz--)
+			xread(archive_handle->src_fd, &tar, 512);
+		/* return get_header_tar(archive_handle); */
+		goto again_after_align;
+	}
+	default:
+		bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
+	}
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+	if (p_longname) {
+		file_header->name = p_longname;
+		p_longname = NULL;
+	}
+	if (p_linkname) {
+		file_header->link_target = p_linkname;
+		p_linkname = NULL;
+	}
+#endif
+
+	/* Everything up to and including last ".." component is stripped */
+	overlapping_strcpy(file_header->name, strip_unsafe_prefix(file_header->name));
+
+	/* Strip trailing '/' in directories */
+	/* Must be done after mode is set as '/' is used to check if it's a directory */
+	cp = last_char_is(file_header->name, '/');
+
+	if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
+		archive_handle->action_header(/*archive_handle->*/ file_header);
+		/* Note that we kill the '/' only after action_header() */
+		/* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
+		if (cp)
+			*cp = '\0';
+		archive_handle->action_data(archive_handle);
+		if (archive_handle->accept || archive_handle->reject
+		 || (archive_handle->ah_flags & ARCHIVE_REMEMBER_NAMES)
+		) {
+			llist_add_to(&archive_handle->passed, file_header->name);
+		} else /* Caller isn't interested in list of unpacked files */
+			free(file_header->name);
+	} else {
+		data_skip(archive_handle);
+		free(file_header->name);
+	}
+	archive_handle->offset += file_header->size;
+
+	free(file_header->link_target);
+	/* Do not free(file_header->name)!
+	 * It might be inserted in archive_handle->passed - see above */
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+	free(file_header->tar__uname);
+	free(file_header->tar__gname);
+#endif
+	return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/get_header_tar_bz2.c b/ap/app/busybox/src/archival/libarchive/get_header_tar_bz2.c
new file mode 100644
index 0000000..0ee00df
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/get_header_tar_bz2.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle)
+{
+	/* Can't lseek over pipes */
+	archive_handle->seek = seek_by_read;
+
+	open_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2");
+	archive_handle->offset = 0;
+	while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+		continue;
+
+	/* Can only do one file at a time */
+	return EXIT_FAILURE;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/get_header_tar_gz.c b/ap/app/busybox/src/archival/libarchive/get_header_tar_gz.c
new file mode 100644
index 0000000..0328434
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/get_header_tar_gz.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle)
+{
+	/* Can't lseek over pipes */
+	archive_handle->seek = seek_by_read;
+
+	open_transformer_with_sig(archive_handle->src_fd, unpack_gz_stream, "gunzip");
+	archive_handle->offset = 0;
+	while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+		continue;
+
+	/* Can only do one file at a time */
+	return EXIT_FAILURE;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/get_header_tar_lzma.c b/ap/app/busybox/src/archival/libarchive/get_header_tar_lzma.c
new file mode 100644
index 0000000..d565a21
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/get_header_tar_lzma.c
@@ -0,0 +1,24 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Small lzma deflate implementation.
+ * Copyright (C) 2006  Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle)
+{
+	/* Can't lseek over pipes */
+	archive_handle->seek = seek_by_read;
+
+	open_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma");
+	archive_handle->offset = 0;
+	while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+		continue;
+
+	/* Can only do one file at a time */
+	return EXIT_FAILURE;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/header_list.c b/ap/app/busybox/src/archival/libarchive/header_list.c
new file mode 100644
index 0000000..0621aa4
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/header_list.c
@@ -0,0 +1,12 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+#include "bb_archive.h"
+
+void FAST_FUNC header_list(const file_header_t *file_header)
+{
+//TODO: cpio -vp DIR should output "DIR/NAME", not just "NAME" */
+	puts(file_header->name);
+}
diff --git a/ap/app/busybox/src/archival/libarchive/header_skip.c b/ap/app/busybox/src/archival/libarchive/header_skip.c
new file mode 100644
index 0000000..f5987bf
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/header_skip.c
@@ -0,0 +1,10 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+#include "bb_archive.h"
+
+void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM)
+{
+}
diff --git a/ap/app/busybox/src/archival/libarchive/header_verbose_list.c b/ap/app/busybox/src/archival/libarchive/header_verbose_list.c
new file mode 100644
index 0000000..87dd821
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/header_verbose_list.c
@@ -0,0 +1,69 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+void FAST_FUNC header_verbose_list(const file_header_t *file_header)
+{
+	struct tm tm_time;
+	struct tm *ptm = &tm_time; //localtime(&file_header->mtime);
+
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+	char uid[sizeof(int)*3 + 2];
+	/*char gid[sizeof(int)*3 + 2];*/
+	char *user;
+	char *group;
+
+	localtime_r(&file_header->mtime, ptm);
+
+	user = file_header->tar__uname;
+	if (user == NULL) {
+		sprintf(uid, "%u", (unsigned)file_header->uid);
+		user = uid;
+	}
+	group = file_header->tar__gname;
+	if (group == NULL) {
+		/*sprintf(gid, "%u", (unsigned)file_header->gid);*/
+		group = utoa(file_header->gid);
+	}
+	printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s",
+		bb_mode_string(file_header->mode),
+		user,
+		group,
+		file_header->size,
+		1900 + ptm->tm_year,
+		1 + ptm->tm_mon,
+		ptm->tm_mday,
+		ptm->tm_hour,
+		ptm->tm_min,
+		ptm->tm_sec,
+		file_header->name);
+
+#else /* !FEATURE_TAR_UNAME_GNAME */
+
+	localtime_r(&file_header->mtime, ptm);
+
+	printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s",
+		bb_mode_string(file_header->mode),
+		(unsigned)file_header->uid,
+		(unsigned)file_header->gid,
+		file_header->size,
+		1900 + ptm->tm_year,
+		1 + ptm->tm_mon,
+		ptm->tm_mday,
+		ptm->tm_hour,
+		ptm->tm_min,
+		ptm->tm_sec,
+		file_header->name);
+
+#endif /* FEATURE_TAR_UNAME_GNAME */
+
+	/* NB: GNU tar shows "->" for symlinks and "link to" for hardlinks */
+	if (file_header->link_target) {
+		printf(" -> %s", file_header->link_target);
+	}
+	bb_putchar('\n');
+}
diff --git a/ap/app/busybox/src/archival/libarchive/init_handle.c b/ap/app/busybox/src/archival/libarchive/init_handle.c
new file mode 100644
index 0000000..cbae06a
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/init_handle.c
@@ -0,0 +1,22 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+archive_handle_t* FAST_FUNC init_handle(void)
+{
+	archive_handle_t *archive_handle;
+
+	/* Initialize default values */
+	archive_handle = xzalloc(sizeof(archive_handle_t));
+	archive_handle->file_header = xzalloc(sizeof(file_header_t));
+	archive_handle->action_header = header_skip;
+	archive_handle->action_data = data_skip;
+	archive_handle->filter = filter_accept_all;
+	archive_handle->seek = seek_by_jump;
+
+	return archive_handle;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/liblzo.h b/ap/app/busybox/src/archival/libarchive/liblzo.h
new file mode 100644
index 0000000..843997c
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/liblzo.h
@@ -0,0 +1,93 @@
+/*
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library 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 of
+   the License, or (at your option) any later version.
+
+   The LZO library 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 the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "liblzo_interface.h"
+
+/* lzo-2.03/src/config1x.h */
+#define M2_MIN_LEN      3
+#define M2_MAX_LEN      8
+#define M3_MAX_LEN      33
+#define M4_MAX_LEN      9
+#define M1_MAX_OFFSET   0x0400
+#define M2_MAX_OFFSET   0x0800
+#define M3_MAX_OFFSET   0x4000
+#define M4_MAX_OFFSET   0xbfff
+#define M1_MARKER       0
+#define M3_MARKER       32
+#define M4_MARKER       16
+
+#define MX_MAX_OFFSET   (M1_MAX_OFFSET + M2_MAX_OFFSET)
+#define MIN_LOOKAHEAD   (M2_MAX_LEN + 1)
+
+#define LZO_EOF_CODE
+
+/* lzo-2.03/src/lzo_dict.h */
+#define GINDEX(m_pos,m_off,dict,dindex,in)    m_pos = dict[dindex]
+#define DX2(p,s1,s2) \
+        (((((unsigned)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
+//#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
+//#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
+#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
+
+#define D_SIZE        (1U << D_BITS)
+#define D_MASK        ((1U << D_BITS) - 1)
+#define D_HIGH        ((D_MASK >> 1) + 1)
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+    ( \
+        m_pos = ip - (unsigned)(ip - m_pos), \
+        ((uintptr_t)m_pos < (uintptr_t)in \
+	|| (m_off = (unsigned)(ip - m_pos)) <= 0 \
+	|| m_off > max_offset) \
+    )
+
+#define DENTRY(p,in)                      (p)
+#define UPDATE_I(dict,drun,index,p,in)    dict[index] = DENTRY(p,in)
+
+#define DMS(v,s)  ((unsigned) (((v) & (D_MASK >> (s))) << (s)))
+#define DM(v)     ((unsigned) ((v) & D_MASK))
+#define DMUL(a,b) ((unsigned) ((a) * (b)))
+
+/* lzo-2.03/src/lzo_ptr.h */
+#define pd(a,b)  ((unsigned)((a)-(b)))
+
+#    define TEST_IP             (ip < ip_end)
+#    define NEED_IP(x) \
+            if ((unsigned)(ip_end - ip) < (unsigned)(x))  goto input_overrun
+
+#    undef TEST_OP              /* don't need both of the tests here */
+#    define TEST_OP             1
+#    define NEED_OP(x) \
+            if ((unsigned)(op_end - op) < (unsigned)(x))  goto output_overrun
+
+#define HAVE_ANY_OP 1
+
+//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+#  define TEST_LB(m_pos)        if (m_pos < out || m_pos >= op) goto lookbehind_overrun
+//#  define TEST_LBO(m_pos,o)     if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun
+//#else
+//#  define TEST_LB(m_pos)        ((void) 0)
+//#  define TEST_LBO(m_pos,o)     ((void) 0)
+//#endif
diff --git a/ap/app/busybox/src/archival/libarchive/lzo1x_1.c b/ap/app/busybox/src/archival/libarchive/lzo1x_1.c
new file mode 100644
index 0000000..a888398
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/lzo1x_1.c
@@ -0,0 +1,35 @@
+/* LZO1X-1 compression
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library 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 of
+   the License, or (at your option) any later version.
+
+   The LZO library 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 the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "libbb.h"
+#include "liblzo.h"
+
+#define D_BITS          14
+#define D_INDEX1(d,p)   d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p)   d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#define DO_COMPRESS     lzo1x_1_compress
+
+#include "lzo1x_c.c"
diff --git a/ap/app/busybox/src/archival/libarchive/lzo1x_1o.c b/ap/app/busybox/src/archival/libarchive/lzo1x_1o.c
new file mode 100644
index 0000000..3c61253
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/lzo1x_1o.c
@@ -0,0 +1,35 @@
+/* LZO1X-1(15) compression
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library 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 of
+   the License, or (at your option) any later version.
+
+   The LZO library 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 the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "libbb.h"
+#include "liblzo.h"
+
+#define D_BITS          15
+#define D_INDEX1(d,p)   d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p)   d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#define DO_COMPRESS     lzo1x_1_15_compress
+
+#include "lzo1x_c.c"
diff --git a/ap/app/busybox/src/archival/libarchive/lzo1x_9x.c b/ap/app/busybox/src/archival/libarchive/lzo1x_9x.c
new file mode 100644
index 0000000..8971329
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/lzo1x_9x.c
@@ -0,0 +1,921 @@
+/* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library 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 of
+   the License, or (at your option) any later version.
+
+   The LZO library 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 the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+*/
+#include "libbb.h"
+
+/* The following is probably only safe on Intel-compatible processors ... */
+#define LZO_UNALIGNED_OK_2
+#define LZO_UNALIGNED_OK_4
+
+#include "liblzo.h"
+
+#define LZO_MAX(a,b)        ((a) >= (b) ? (a) : (b))
+#define LZO_MIN(a,b)        ((a) <= (b) ? (a) : (b))
+#define LZO_MAX3(a,b,c)     ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
+
+/***********************************************************************
+//
+************************************************************************/
+#define SWD_N           M4_MAX_OFFSET   /* size of ring buffer */
+#define SWD_F           2048           /* upper limit for match length */
+
+#define SWD_BEST_OFF    (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1)
+
+typedef struct {
+	int init;
+
+	unsigned look;          /* bytes in lookahead buffer */
+
+	unsigned m_len;
+	unsigned m_off;
+
+	const uint8_t *bp;
+	const uint8_t *ip;
+	const uint8_t *in;
+	const uint8_t *in_end;
+	uint8_t *out;
+
+	unsigned r1_lit;
+
+} lzo1x_999_t;
+
+#define getbyte(c)  ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
+
+/* lzo_swd.c -- sliding window dictionary */
+
+/***********************************************************************
+//
+************************************************************************/
+#define SWD_UINT_MAX      USHRT_MAX
+
+#ifndef SWD_HSIZE
+#  define SWD_HSIZE         16384
+#endif
+#ifndef SWD_MAX_CHAIN
+#  define SWD_MAX_CHAIN     2048
+#endif
+
+#define HEAD3(b, p) \
+	( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) )
+
+#if defined(LZO_UNALIGNED_OK_2)
+#  define HEAD2(b,p)      (* (uint16_t *) &(b[p]))
+#else
+#  define HEAD2(b,p)      (b[p] ^ ((unsigned)b[p+1]<<8))
+#endif
+#define NIL2              SWD_UINT_MAX
+
+typedef struct lzo_swd {
+	/* public - "built-in" */
+
+	/* public - configuration */
+	unsigned max_chain;
+	int use_best_off;
+
+	/* public - output */
+	unsigned m_len;
+	unsigned m_off;
+	unsigned look;
+	int b_char;
+#if defined(SWD_BEST_OFF)
+	unsigned best_off[SWD_BEST_OFF];
+#endif
+
+	/* semi public */
+	lzo1x_999_t *c;
+	unsigned m_pos;
+#if defined(SWD_BEST_OFF)
+	unsigned best_pos[SWD_BEST_OFF];
+#endif
+
+	/* private */
+	unsigned ip;                /* input pointer (lookahead) */
+	unsigned bp;                /* buffer pointer */
+	unsigned rp;                /* remove pointer */
+
+	unsigned node_count;
+	unsigned first_rp;
+
+	uint8_t b[SWD_N + SWD_F];
+	uint8_t b_wrap[SWD_F]; /* must follow b */
+	uint16_t head3[SWD_HSIZE];
+	uint16_t succ3[SWD_N + SWD_F];
+	uint16_t best3[SWD_N + SWD_F];
+	uint16_t llen3[SWD_HSIZE];
+#ifdef HEAD2
+	uint16_t head2[65536L];
+#endif
+} lzo_swd_t, *lzo_swd_p;
+
+#define SIZEOF_LZO_SWD_T    (sizeof(lzo_swd_t))
+
+
+/* Access macro for head3.
+ * head3[key] may be uninitialized, but then its value will never be used.
+ */
+#define s_get_head3(s,key)    s->head3[key]
+
+
+/***********************************************************************
+//
+************************************************************************/
+#define B_SIZE (SWD_N + SWD_F)
+
+static int swd_init(lzo_swd_p s)
+{
+	/* defaults */
+	s->node_count = SWD_N;
+
+	memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE);
+#ifdef HEAD2
+	memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L);
+	assert(s->head2[0] == NIL2);
+#endif
+
+	s->ip = 0;
+	s->bp = s->ip;
+	s->first_rp = s->ip;
+
+	assert(s->ip + SWD_F <= B_SIZE);
+	s->look = (unsigned) (s->c->in_end - s->c->ip);
+	if (s->look > 0) {
+		if (s->look > SWD_F)
+			s->look = SWD_F;
+		memcpy(&s->b[s->ip], s->c->ip, s->look);
+		s->c->ip += s->look;
+		s->ip += s->look;
+	}
+	if (s->ip == B_SIZE)
+		s->ip = 0;
+
+	s->rp = s->first_rp;
+	if (s->rp >= s->node_count)
+		s->rp -= s->node_count;
+	else
+		s->rp += B_SIZE - s->node_count;
+
+	return LZO_E_OK;
+}
+
+#define swd_pos2off(s,pos) \
+	(s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp))
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_getbyte(lzo_swd_p s)
+{
+	int c;
+
+	if ((c = getbyte(*(s->c))) < 0) {
+		if (s->look > 0)
+			--s->look;
+	} else {
+		s->b[s->ip] = c;
+		if (s->ip < SWD_F)
+			s->b_wrap[s->ip] = c;
+	}
+	if (++s->ip == B_SIZE)
+		s->ip = 0;
+	if (++s->bp == B_SIZE)
+		s->bp = 0;
+	if (++s->rp == B_SIZE)
+		s->rp = 0;
+}
+
+
+/***********************************************************************
+// remove node from lists
+************************************************************************/
+static void swd_remove_node(lzo_swd_p s, unsigned node)
+{
+	if (s->node_count == 0) {
+		unsigned key;
+
+		key = HEAD3(s->b,node);
+		assert(s->llen3[key] > 0);
+		--s->llen3[key];
+
+#ifdef HEAD2
+		key = HEAD2(s->b,node);
+		assert(s->head2[key] != NIL2);
+		if ((unsigned) s->head2[key] == node)
+			s->head2[key] = NIL2;
+#endif
+	} else
+		--s->node_count;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_accept(lzo_swd_p s, unsigned n)
+{
+	assert(n <= s->look);
+
+	while (n--) {
+		unsigned key;
+
+		swd_remove_node(s,s->rp);
+
+		/* add bp into HEAD3 */
+		key = HEAD3(s->b, s->bp);
+		s->succ3[s->bp] = s_get_head3(s, key);
+		s->head3[key] = s->bp;
+		s->best3[s->bp] = SWD_F + 1;
+		s->llen3[key]++;
+		assert(s->llen3[key] <= SWD_N);
+
+#ifdef HEAD2
+		/* add bp into HEAD2 */
+		key = HEAD2(s->b, s->bp);
+		s->head2[key] = s->bp;
+#endif
+
+		swd_getbyte(s);
+	}
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt)
+{
+	const uint8_t *p1;
+	const uint8_t *p2;
+	const uint8_t *px;
+	unsigned m_len = s->m_len;
+	const uint8_t *b  = s->b;
+	const uint8_t *bp = s->b + s->bp;
+	const uint8_t *bx = s->b + s->bp + s->look;
+	unsigned char scan_end1;
+
+	assert(s->m_len > 0);
+
+	scan_end1 = bp[m_len - 1];
+	for ( ; cnt-- > 0; node = s->succ3[node]) {
+		p1 = bp;
+		p2 = b + node;
+		px = bx;
+
+		assert(m_len < s->look);
+
+		if (p2[m_len - 1] == scan_end1
+		 && p2[m_len] == p1[m_len]
+		 && p2[0] == p1[0]
+		 && p2[1] == p1[1]
+		) {
+			unsigned i;
+			assert(lzo_memcmp(bp, &b[node], 3) == 0);
+
+			p1 += 2; p2 += 2;
+			do {} while (++p1 < px && *p1 == *++p2);
+			i = p1-bp;
+
+			assert(lzo_memcmp(bp, &b[node], i) == 0);
+
+#if defined(SWD_BEST_OFF)
+			if (i < SWD_BEST_OFF) {
+				if (s->best_pos[i] == 0)
+					s->best_pos[i] = node + 1;
+			}
+#endif
+			if (i > m_len) {
+				s->m_len = m_len = i;
+				s->m_pos = node;
+				if (m_len == s->look)
+					return;
+				if (m_len >= SWD_F)
+					return;
+				if (m_len > (unsigned) s->best3[node])
+					return;
+				scan_end1 = bp[m_len - 1];
+			}
+		}
+	}
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+#ifdef HEAD2
+
+static int swd_search2(lzo_swd_p s)
+{
+	unsigned key;
+
+	assert(s->look >= 2);
+	assert(s->m_len > 0);
+
+	key = s->head2[HEAD2(s->b, s->bp)];
+	if (key == NIL2)
+		return 0;
+	assert(lzo_memcmp(&s->b[s->bp], &s->b[key], 2) == 0);
+#if defined(SWD_BEST_OFF)
+	if (s->best_pos[2] == 0)
+		s->best_pos[2] = key + 1;
+#endif
+
+	if (s->m_len < 2) {
+		s->m_len = 2;
+		s->m_pos = key;
+	}
+	return 1;
+}
+
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_findbest(lzo_swd_p s)
+{
+	unsigned key;
+	unsigned cnt, node;
+	unsigned len;
+
+	assert(s->m_len > 0);
+
+	/* get current head, add bp into HEAD3 */
+	key = HEAD3(s->b,s->bp);
+	node = s->succ3[s->bp] = s_get_head3(s, key);
+	cnt = s->llen3[key]++;
+	assert(s->llen3[key] <= SWD_N + SWD_F);
+	if (cnt > s->max_chain)
+		cnt = s->max_chain;
+	s->head3[key] = s->bp;
+
+	s->b_char = s->b[s->bp];
+	len = s->m_len;
+	if (s->m_len >= s->look) {
+		if (s->look == 0)
+			s->b_char = -1;
+		s->m_off = 0;
+		s->best3[s->bp] = SWD_F + 1;
+	} else {
+#ifdef HEAD2
+		if (swd_search2(s))
+#endif
+			if (s->look >= 3)
+				swd_search(s, node, cnt);
+		if (s->m_len > len)
+			s->m_off = swd_pos2off(s,s->m_pos);
+		s->best3[s->bp] = s->m_len;
+
+#if defined(SWD_BEST_OFF)
+		if (s->use_best_off) {
+			int i;
+			for (i = 2; i < SWD_BEST_OFF; i++) {
+				if (s->best_pos[i] > 0)
+					s->best_off[i] = swd_pos2off(s, s->best_pos[i]-1);
+				else
+					s->best_off[i] = 0;
+			}
+		}
+#endif
+	}
+
+	swd_remove_node(s,s->rp);
+
+#ifdef HEAD2
+	/* add bp into HEAD2 */
+	key = HEAD2(s->b, s->bp);
+	s->head2[key] = s->bp;
+#endif
+}
+
+#undef HEAD3
+#undef HEAD2
+#undef s_get_head3
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off)
+{
+	int r;
+
+	assert(!c->init);
+	c->init = 1;
+
+	s->c = c;
+
+	r = swd_init(s);
+	if (r != 0)
+		return r;
+
+	s->use_best_off = use_best_off;
+	return r;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int find_match(lzo1x_999_t *c, lzo_swd_p s,
+		unsigned this_len, unsigned skip)
+{
+	assert(c->init);
+
+	if (skip > 0) {
+		assert(this_len >= skip);
+		swd_accept(s, this_len - skip);
+	} else {
+		assert(this_len <= 1);
+	}
+
+	s->m_len = 1;
+	s->m_len = 1;
+#ifdef SWD_BEST_OFF
+	if (s->use_best_off)
+		memset(s->best_pos, 0, sizeof(s->best_pos));
+#endif
+	swd_findbest(s);
+	c->m_len = s->m_len;
+	c->m_off = s->m_off;
+
+	swd_getbyte(s);
+
+	if (s->b_char < 0) {
+		c->look = 0;
+		c->m_len = 0;
+	} else {
+		c->look = s->look + 1;
+	}
+	c->bp = c->ip - c->look;
+
+	return LZO_E_OK;
+}
+
+/* this is a public functions, but there is no prototype in a header file */
+static int lzo1x_999_compress_internal(const uint8_t *in , unsigned in_len,
+		uint8_t *out, unsigned *out_len,
+		void *wrkmem,
+		unsigned good_length,
+		unsigned max_lazy,
+		unsigned max_chain,
+		uint32_t use_best_off);
+
+
+/***********************************************************************
+//
+************************************************************************/
+static uint8_t *code_match(lzo1x_999_t *c,
+		uint8_t *op, unsigned m_len, unsigned m_off)
+{
+	assert(op > c->out);
+	if (m_len == 2) {
+		assert(m_off <= M1_MAX_OFFSET);
+		assert(c->r1_lit > 0);
+		assert(c->r1_lit < 4);
+		m_off -= 1;
+		*op++ = M1_MARKER | ((m_off & 3) << 2);
+		*op++ = m_off >> 2;
+	} else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
+		assert(m_len >= 3);
+		m_off -= 1;
+		*op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2);
+		*op++ = m_off >> 3;
+		assert(op[-2] >= M2_MARKER);
+	} else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) {
+		assert(m_len == 3);
+		assert(m_off > M2_MAX_OFFSET);
+		m_off -= 1 + M2_MAX_OFFSET;
+		*op++ = M1_MARKER | ((m_off & 3) << 2);
+		*op++ = m_off >> 2;
+	} else if (m_off <= M3_MAX_OFFSET) {
+		assert(m_len >= 3);
+		m_off -= 1;
+		if (m_len <= M3_MAX_LEN)
+			*op++ = M3_MARKER | (m_len - 2);
+		else {
+			m_len -= M3_MAX_LEN;
+			*op++ = M3_MARKER | 0;
+			while (m_len > 255) {
+				m_len -= 255;
+				*op++ = 0;
+			}
+			assert(m_len > 0);
+			*op++ = m_len;
+		}
+		*op++ = m_off << 2;
+		*op++ = m_off >> 6;
+	} else {
+		unsigned k;
+
+		assert(m_len >= 3);
+		assert(m_off > 0x4000);
+		assert(m_off <= 0xbfff);
+		m_off -= 0x4000;
+		k = (m_off & 0x4000) >> 11;
+		if (m_len <= M4_MAX_LEN)
+			*op++ = M4_MARKER | k | (m_len - 2);
+		else {
+			m_len -= M4_MAX_LEN;
+			*op++ = M4_MARKER | k | 0;
+			while (m_len > 255) {
+				m_len -= 255;
+				*op++ = 0;
+			}
+			assert(m_len > 0);
+			*op++ = m_len;
+		}
+		*op++ = m_off << 2;
+		*op++ = m_off >> 6;
+	}
+
+	return op;
+}
+
+
+static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op,
+		const uint8_t *ii, unsigned t)
+{
+	if (op == c->out && t <= 238) {
+		*op++ = 17 + t;
+	} else if (t <= 3) {
+		op[-2] |= t;
+	} else if (t <= 18) {
+		*op++ = t - 3;
+	} else {
+		unsigned tt = t - 18;
+
+		*op++ = 0;
+		while (tt > 255) {
+			tt -= 255;
+			*op++ = 0;
+		}
+		assert(tt > 0);
+		*op++ = tt;
+	}
+	do *op++ = *ii++; while (--t > 0);
+
+	return op;
+}
+
+
+static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii,
+		unsigned lit)
+{
+	if (lit > 0) {
+		assert(m_len >= 2);
+		op = STORE_RUN(c, op, ii, lit);
+	} else {
+		assert(m_len >= 3);
+	}
+	c->r1_lit = lit;
+
+	return op;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit)
+{
+	int n = 4;
+
+	if (m_len < 2)
+		return -1;
+	if (m_len == 2)
+		return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1;
+	if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
+		return 2;
+	if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4)
+		return 2;
+	if (m_off <= M3_MAX_OFFSET) {
+		if (m_len <= M3_MAX_LEN)
+			return 3;
+		m_len -= M3_MAX_LEN;
+	} else if (m_off <= M4_MAX_OFFSET) {
+		if (m_len <= M4_MAX_LEN)
+			return 3;
+		m_len -= M4_MAX_LEN;
+	} else
+		return -1;
+	while (m_len > 255) {
+		m_len -= 255;
+		n++;
+	}
+	return n;
+}
+
+
+static int min_gain(unsigned ahead, unsigned lit1,
+			unsigned lit2, int l1, int l2, int l3)
+{
+	int lazy_match_min_gain = 0;
+
+	assert (ahead >= 1);
+	lazy_match_min_gain += ahead;
+
+	if (lit1 <= 3)
+		lazy_match_min_gain += (lit2 <= 3) ? 0 : 2;
+	else if (lit1 <= 18)
+		lazy_match_min_gain += (lit2 <= 18) ? 0 : 1;
+
+	lazy_match_min_gain += (l2 - l1) * 2;
+	if (l3 > 0)
+		lazy_match_min_gain -= (ahead - l3) * 2;
+
+	if (lazy_match_min_gain < 0)
+		lazy_match_min_gain = 0;
+
+	return lazy_match_min_gain;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+#if defined(SWD_BEST_OFF)
+
+static void better_match(const lzo_swd_p swd,
+			unsigned *m_len, unsigned *m_off)
+{
+	if (*m_len <= M2_MIN_LEN)
+		return;
+
+	if (*m_off <= M2_MAX_OFFSET)
+		return;
+
+	/* M3/M4 -> M2 */
+	if (*m_off > M2_MAX_OFFSET
+	 && *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1
+	 && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET
+	) {
+		*m_len = *m_len - 1;
+		*m_off = swd->best_off[*m_len];
+		return;
+	}
+
+	/* M4 -> M2 */
+	if (*m_off > M3_MAX_OFFSET
+	 && *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2
+	 && swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET
+	) {
+		*m_len = *m_len - 2;
+		*m_off = swd->best_off[*m_len];
+		return;
+	}
+	/* M4 -> M3 */
+	if (*m_off > M3_MAX_OFFSET
+	 && *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1
+	 && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET
+	) {
+		*m_len = *m_len - 1;
+		*m_off = swd->best_off[*m_len];
+	}
+}
+
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len,
+		uint8_t *out, unsigned *out_len,
+		void *wrkmem,
+		unsigned good_length,
+		unsigned max_lazy,
+		unsigned max_chain,
+		uint32_t use_best_off)
+{
+	uint8_t *op;
+	const uint8_t *ii;
+	unsigned lit;
+	unsigned m_len, m_off;
+	lzo1x_999_t cc;
+	lzo1x_999_t *const c = &cc;
+	const lzo_swd_p swd = (lzo_swd_p) wrkmem;
+	int r;
+
+	c->init = 0;
+	c->ip = c->in = in;
+	c->in_end = in + in_len;
+	c->out = out;
+
+	op = out;
+	ii = c->ip;             /* point to start of literal run */
+	lit = 0;
+	c->r1_lit = 0;
+
+	r = init_match(c, swd, use_best_off);
+	if (r != 0)
+		return r;
+	swd->max_chain = max_chain;
+
+	r = find_match(c, swd, 0, 0);
+	if (r != 0)
+		return r;
+
+	while (c->look > 0) {
+		unsigned ahead;
+		unsigned max_ahead;
+		int l1, l2, l3;
+
+		m_len = c->m_len;
+		m_off = c->m_off;
+
+		assert(c->bp == c->ip - c->look);
+		assert(c->bp >= in);
+		if (lit == 0)
+			ii = c->bp;
+		assert(ii + lit == c->bp);
+		assert(swd->b_char == *(c->bp));
+
+		if (m_len < 2
+		 || (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4))
+		    /* Do not accept this match for compressed-data compatibility
+		     * with LZO v1.01 and before
+		     * [ might be a problem for decompress() and optimize() ]
+		     */
+		 || (m_len == 2 && op == out)
+		 || (op == out && lit == 0)
+		) {
+			/* a literal */
+			m_len = 0;
+		}
+		else if (m_len == M2_MIN_LEN) {
+			/* compression ratio improves if we code a literal in some cases */
+			if (m_off > MX_MAX_OFFSET && lit >= 4)
+				m_len = 0;
+		}
+
+		if (m_len == 0) {
+			/* a literal */
+			lit++;
+			swd->max_chain = max_chain;
+			r = find_match(c, swd, 1, 0);
+			assert(r == 0);
+			continue;
+		}
+
+		/* a match */
+#if defined(SWD_BEST_OFF)
+		if (swd->use_best_off)
+			better_match(swd, &m_len, &m_off);
+#endif
+
+		/* shall we try a lazy match ? */
+		ahead = 0;
+		if (m_len >= max_lazy) {
+			/* no */
+			l1 = 0;
+			max_ahead = 0;
+		} else {
+			/* yes, try a lazy match */
+			l1 = len_of_coded_match(m_len, m_off, lit);
+			assert(l1 > 0);
+			max_ahead = LZO_MIN(2, (unsigned)l1 - 1);
+		}
+
+
+		while (ahead < max_ahead && c->look > m_len) {
+			int lazy_match_min_gain;
+
+			if (m_len >= good_length)
+				swd->max_chain = max_chain >> 2;
+			else
+				swd->max_chain = max_chain;
+			r = find_match(c, swd, 1, 0);
+			ahead++;
+
+			assert(r == 0);
+			assert(c->look > 0);
+			assert(ii + lit + ahead == c->bp);
+
+			if (c->m_len < m_len)
+				continue;
+			if (c->m_len == m_len && c->m_off >= m_off)
+				continue;
+#if defined(SWD_BEST_OFF)
+			if (swd->use_best_off)
+				better_match(swd, &c->m_len, &c->m_off);
+#endif
+			l2 = len_of_coded_match(c->m_len, c->m_off, lit+ahead);
+			if (l2 < 0)
+				continue;
+
+			/* compressed-data compatibility [see above] */
+			l3 = (op == out) ? -1 : len_of_coded_match(ahead, m_off, lit);
+
+			lazy_match_min_gain = min_gain(ahead, lit, lit+ahead, l1, l2, l3);
+			if (c->m_len >= m_len + lazy_match_min_gain) {
+				if (l3 > 0) {
+					/* code previous run */
+					op = code_run(c, op, ii, lit);
+					lit = 0;
+					/* code shortened match */
+					op = code_match(c, op, ahead, m_off);
+				} else {
+					lit += ahead;
+					assert(ii + lit == c->bp);
+				}
+				goto lazy_match_done;
+			}
+		}
+
+		assert(ii + lit + ahead == c->bp);
+
+		/* 1 - code run */
+		op = code_run(c, op, ii, lit);
+		lit = 0;
+
+		/* 2 - code match */
+		op = code_match(c, op, m_len, m_off);
+		swd->max_chain = max_chain;
+		r = find_match(c, swd, m_len, 1+ahead);
+		assert(r == 0);
+
+ lazy_match_done: ;
+	}
+
+	/* store final run */
+	if (lit > 0)
+		op = STORE_RUN(c, op, ii, lit);
+
+#if defined(LZO_EOF_CODE)
+	*op++ = M4_MARKER | 1;
+	*op++ = 0;
+	*op++ = 0;
+#endif
+
+	*out_len = op - out;
+
+	return LZO_E_OK;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len,
+		uint8_t *out, unsigned *out_len,
+		void *wrkmem,
+		int compression_level)
+{
+	static const struct {
+		uint16_t good_length;
+		uint16_t max_lazy;
+		uint16_t max_chain;
+		uint16_t use_best_off;
+	} c[3] = {
+		{     8,    32,  256,   0 },
+		{    32,   128, 2048,   1 },
+		{ SWD_F, SWD_F, 4096,   1 }       /* max. compression */
+	};
+
+	if (compression_level < 7 || compression_level > 9)
+		return LZO_E_ERROR;
+
+	compression_level -= 7;
+	return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem,
+					c[compression_level].good_length,
+					c[compression_level].max_lazy,
+					c[compression_level].max_chain,
+					c[compression_level].use_best_off);
+}
diff --git a/ap/app/busybox/src/archival/libarchive/lzo1x_c.c b/ap/app/busybox/src/archival/libarchive/lzo1x_c.c
new file mode 100644
index 0000000..8c77072
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/lzo1x_c.c
@@ -0,0 +1,296 @@
+/* implementation of the LZO1[XY]-1 compression algorithm
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library 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 of
+   the License, or (at your option) any later version.
+
+   The LZO library 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 the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/***********************************************************************
+// compress a block of data.
+************************************************************************/
+static NOINLINE unsigned
+do_compress(const uint8_t* in, unsigned in_len,
+		uint8_t* out, unsigned* out_len,
+		void* wrkmem)
+{
+	register const uint8_t* ip;
+	uint8_t* op;
+	const uint8_t* const in_end = in + in_len;
+	const uint8_t* const ip_end = in + in_len - M2_MAX_LEN - 5;
+	const uint8_t* ii;
+	const void* *const dict = (const void**) wrkmem;
+
+	op = out;
+	ip = in;
+	ii = ip;
+
+	ip += 4;
+	for (;;) {
+		register const uint8_t* m_pos;
+		unsigned m_off;
+		unsigned m_len;
+		unsigned dindex;
+
+		D_INDEX1(dindex,ip);
+		GINDEX(m_pos,m_off,dict,dindex,in);
+		if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+			goto literal;
+#if 1
+		if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+			goto try_match;
+		D_INDEX2(dindex,ip);
+#endif
+		GINDEX(m_pos,m_off,dict,dindex,in);
+		if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+			goto literal;
+		if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+			goto try_match;
+		goto literal;
+
+ try_match:
+#if 1 && defined(LZO_UNALIGNED_OK_2)
+		if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
+#else
+		if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
+#endif
+		{
+		} else {
+			if (m_pos[2] == ip[2]) {
+#if 0
+				if (m_off <= M2_MAX_OFFSET)
+					goto match;
+				if (lit <= 3)
+					goto match;
+				if (lit == 3) {			  /* better compression, but slower */
+					assert(op - 2 > out); op[-2] |= (uint8_t)(3);
+					*op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
+					goto code_match;
+				}
+				if (m_pos[3] == ip[3])
+#endif
+					goto match;
+			}
+			else {
+				/* still need a better way for finding M1 matches */
+#if 0
+				/* a M1 match */
+#if 0
+				if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3)
+#else
+				if (m_off <= M1_MAX_OFFSET && lit == 3)
+#endif
+				{
+					register unsigned t;
+
+					t = lit;
+					assert(op - 2 > out); op[-2] |= (uint8_t)(t);
+					do *op++ = *ii++; while (--t > 0);
+					assert(ii == ip);
+					m_off -= 1;
+					*op++ = (uint8_t)(M1_MARKER | ((m_off & 3) << 2));
+					*op++ = (uint8_t)(m_off >> 2);
+					ip += 2;
+					goto match_done;
+				}
+#endif
+			}
+		}
+
+		/* a literal */
+ literal:
+		UPDATE_I(dict, 0, dindex, ip, in);
+		++ip;
+		if (ip >= ip_end)
+			break;
+		continue;
+
+		/* a match */
+match:
+		UPDATE_I(dict, 0, dindex, ip, in);
+		/* store current literal run */
+		if (pd(ip, ii) > 0) {
+			register unsigned t = pd(ip, ii);
+
+			if (t <= 3) {
+				assert(op - 2 > out);
+				op[-2] |= (uint8_t)(t);
+			}
+			else if (t <= 18)
+				*op++ = (uint8_t)(t - 3);
+			else {
+				register unsigned tt = t - 18;
+
+				*op++ = 0;
+				while (tt > 255) {
+					tt -= 255;
+					*op++ = 0;
+				}
+				assert(tt > 0);
+				*op++ = (uint8_t)(tt);
+			}
+			do *op++ = *ii++; while (--t > 0);
+		}
+
+		/* code the match */
+		assert(ii == ip);
+		ip += 3;
+		if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++
+		 || m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++
+#ifdef LZO1Y
+		 || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++
+		 || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++
+#endif
+		) {
+			--ip;
+			m_len = pd(ip, ii);
+			assert(m_len >= 3);
+			assert(m_len <= M2_MAX_LEN);
+
+			if (m_off <= M2_MAX_OFFSET) {
+				m_off -= 1;
+#if defined(LZO1X)
+				*op++ = (uint8_t)(((m_len - 1) << 5) | ((m_off & 7) << 2));
+				*op++ = (uint8_t)(m_off >> 3);
+#elif defined(LZO1Y)
+				*op++ = (uint8_t)(((m_len + 1) << 4) | ((m_off & 3) << 2));
+				*op++ = (uint8_t)(m_off >> 2);
+#endif
+			}
+			else if (m_off <= M3_MAX_OFFSET) {
+				m_off -= 1;
+				*op++ = (uint8_t)(M3_MARKER | (m_len - 2));
+				goto m3_m4_offset;
+			} else {
+#if defined(LZO1X)
+				m_off -= 0x4000;
+				assert(m_off > 0);
+				assert(m_off <= 0x7fff);
+				*op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2));
+				goto m3_m4_offset;
+#elif defined(LZO1Y)
+				goto m4_match;
+#endif
+			}
+		}
+		else {
+			{
+				const uint8_t* end = in_end;
+				const uint8_t* m = m_pos + M2_MAX_LEN + 1;
+				while (ip < end && *m == *ip)
+					m++, ip++;
+				m_len = pd(ip, ii);
+			}
+			assert(m_len > M2_MAX_LEN);
+
+			if (m_off <= M3_MAX_OFFSET) {
+				m_off -= 1;
+				if (m_len <= 33)
+					*op++ = (uint8_t)(M3_MARKER | (m_len - 2));
+				else {
+					m_len -= 33;
+					*op++ = M3_MARKER | 0;
+					goto m3_m4_len;
+				}
+			} else {
+#if defined(LZO1Y)
+ m4_match:
+#endif
+				m_off -= 0x4000;
+				assert(m_off > 0);
+				assert(m_off <= 0x7fff);
+				if (m_len <= M4_MAX_LEN)
+					*op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2));
+				else {
+					m_len -= M4_MAX_LEN;
+					*op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11));
+ m3_m4_len:
+					while (m_len > 255) {
+						m_len -= 255;
+						*op++ = 0;
+					}
+					assert(m_len > 0);
+					*op++ = (uint8_t)(m_len);
+				}
+			}
+ m3_m4_offset:
+			*op++ = (uint8_t)((m_off & 63) << 2);
+			*op++ = (uint8_t)(m_off >> 6);
+		}
+#if 0
+ match_done:
+#endif
+		ii = ip;
+		if (ip >= ip_end)
+			break;
+	}
+
+	*out_len = pd(op, out);
+	return pd(in_end, ii);
+}
+
+/***********************************************************************
+// public entry point
+************************************************************************/
+int DO_COMPRESS(const uint8_t* in, unsigned in_len,
+		uint8_t* out, unsigned* out_len,
+		void* wrkmem)
+{
+	uint8_t* op = out;
+	unsigned t;
+
+	if (in_len <= M2_MAX_LEN + 5)
+		t = in_len;
+	else {
+		t = do_compress(in,in_len,op,out_len,wrkmem);
+		op += *out_len;
+	}
+
+	if (t > 0) {
+		const uint8_t* ii = in + in_len - t;
+
+		if (op == out && t <= 238)
+			*op++ = (uint8_t)(17 + t);
+		else if (t <= 3)
+			op[-2] |= (uint8_t)(t);
+		else if (t <= 18)
+			*op++ = (uint8_t)(t - 3);
+		else {
+			unsigned tt = t - 18;
+
+			*op++ = 0;
+			while (tt > 255) {
+				tt -= 255;
+				*op++ = 0;
+			}
+			assert(tt > 0);
+			*op++ = (uint8_t)(tt);
+		}
+		do *op++ = *ii++; while (--t > 0);
+	}
+
+	*op++ = M4_MARKER | 1;
+	*op++ = 0;
+	*op++ = 0;
+
+	*out_len = pd(op, out);
+	return 0; /*LZO_E_OK*/
+}
diff --git a/ap/app/busybox/src/archival/libarchive/lzo1x_d.c b/ap/app/busybox/src/archival/libarchive/lzo1x_d.c
new file mode 100644
index 0000000..9bc1270
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/lzo1x_d.c
@@ -0,0 +1,420 @@
+/* implementation of the LZO1X decompression algorithm
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library 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 of
+   the License, or (at your option) any later version.
+
+   The LZO library 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 the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "libbb.h"
+#include "liblzo.h"
+
+/***********************************************************************
+// decompress a block of data.
+************************************************************************/
+/* safe decompression with overrun testing */
+int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len,
+		uint8_t* out, unsigned* out_len,
+		void* wrkmem UNUSED_PARAM)
+{
+	register uint8_t* op;
+	register const uint8_t* ip;
+	register unsigned t;
+#if defined(COPY_DICT)
+	unsigned m_off;
+	const uint8_t* dict_end;
+#else
+	register const uint8_t* m_pos = NULL; /* possibly not needed */
+#endif
+	const uint8_t* const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+	uint8_t* const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+	unsigned last_m_off = 0;
+#endif
+
+//	LZO_UNUSED(wrkmem);
+
+#if defined(COPY_DICT)
+	if (dict) {
+		if (dict_len > M4_MAX_OFFSET) {
+			dict += dict_len - M4_MAX_OFFSET;
+			dict_len = M4_MAX_OFFSET;
+		}
+		dict_end = dict + dict_len;
+	} else {
+		dict_len = 0;
+		dict_end = NULL;
+	}
+#endif /* COPY_DICT */
+
+	*out_len = 0;
+
+	op = out;
+	ip = in;
+
+	if (*ip > 17) {
+		t = *ip++ - 17;
+		if (t < 4)
+			goto match_next;
+		assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+		do *op++ = *ip++; while (--t > 0);
+		goto first_literal_run;
+	}
+
+	while (TEST_IP && TEST_OP) {
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+		/* a literal run */
+		if (t == 0) {
+			NEED_IP(1);
+			while (*ip == 0) {
+				t += 255;
+				ip++;
+				NEED_IP(1);
+			}
+			t += 15 + *ip++;
+		}
+		/* copy literals */
+		assert(t > 0);
+		NEED_OP(t+3);
+		NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+# if !defined(LZO_UNALIGNED_OK_4)
+		if (PTR_ALIGNED2_4(op, ip))
+# endif
+		{
+			COPY4(op, ip);
+			op += 4;
+			ip += 4;
+			if (--t > 0) {
+				if (t >= 4) {
+					do {
+						COPY4(op, ip);
+						op += 4;
+						ip += 4;
+						t -= 4;
+					} while (t >= 4);
+					if (t > 0)
+						do *op++ = *ip++; while (--t > 0);
+				} else {
+					do *op++ = *ip++; while (--t > 0);
+				}
+			}
+		}
+# if !defined(LZO_UNALIGNED_OK_4)
+		else
+# endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+		{
+			*op++ = *ip++;
+			*op++ = *ip++;
+			*op++ = *ip++;
+			do *op++ = *ip++; while (--t > 0);
+		}
+#endif
+
+ first_literal_run:
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+		m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+		last_m_off = m_off;
+#else
+		m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+		NEED_OP(3);
+		t = 3; COPY_DICT(t,m_off)
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+		t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+		m_pos = op - t;
+		last_m_off = t;
+#else
+		m_pos = op - (1 + M2_MAX_OFFSET);
+		m_pos -= t >> 2;
+		m_pos -= *ip++ << 2;
+#endif
+		TEST_LB(m_pos); NEED_OP(3);
+		*op++ = *m_pos++;
+		*op++ = *m_pos++;
+		*op++ = *m_pos;
+#endif /* COPY_DICT */
+		goto match_done;
+
+		/* handle matches */
+		do {
+ match:
+			if (t >= 64) {		/* a M2 match */
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+				m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+				t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+				m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+				t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+				m_off = t & 0x1f;
+				if (m_off >= 0x1c)
+					m_off = last_m_off;
+				else {
+					m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+					last_m_off = m_off;
+				}
+				t = (t >> 5) - 1;
+#endif
+#else /* !COPY_DICT */
+#if defined(LZO1X)
+				m_pos = op - 1;
+				m_pos -= (t >> 2) & 7;
+				m_pos -= *ip++ << 3;
+				t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+				m_pos = op - 1;
+				m_pos -= (t >> 2) & 3;
+				m_pos -= *ip++ << 2;
+				t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+				{
+					unsigned off = t & 0x1f;
+					m_pos = op;
+					if (off >= 0x1c) {
+						assert(last_m_off > 0);
+						m_pos -= last_m_off;
+					} else {
+						off = 1 + (off << 6) + (*ip++ >> 2);
+						m_pos -= off;
+						last_m_off = off;
+					}
+				}
+				t = (t >> 5) - 1;
+#endif
+				TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+				goto copy_match;
+#endif /* COPY_DICT */
+			}
+			else if (t >= 32) {			/* a M3 match */
+				t &= 31;
+				if (t == 0) {
+					NEED_IP(1);
+					while (*ip == 0) {
+						t += 255;
+						ip++;
+						NEED_IP(1);
+					}
+					t += 31 + *ip++;
+				}
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+				m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+				last_m_off = m_off;
+#else
+				m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+				{
+					unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+					m_pos = op - off;
+					last_m_off = off;
+				}
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+				m_pos = op - 1;
+				m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+				m_pos = op - 1;
+				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif /* COPY_DICT */
+				ip += 2;
+			}
+			else if (t >= 16) {			/* a M4 match */
+#if defined(COPY_DICT)
+				m_off = (t & 8) << 11;
+#else /* !COPY_DICT */
+				m_pos = op;
+				m_pos -= (t & 8) << 11;
+#endif /* COPY_DICT */
+				t &= 7;
+				if (t == 0) {
+					NEED_IP(1);
+					while (*ip == 0) {
+						t += 255;
+						ip++;
+						NEED_IP(1);
+					}
+					t += 7 + *ip++;
+				}
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+				m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+				m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+				ip += 2;
+				if (m_off == 0)
+					goto eof_found;
+				m_off += 0x4000;
+#if defined(LZO1Z)
+				last_m_off = m_off;
+#endif
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+				m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+				m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+				ip += 2;
+				if (m_pos == op)
+					goto eof_found;
+				m_pos -= 0x4000;
+#if defined(LZO1Z)
+				last_m_off = pd((const uint8_t*)op, m_pos);
+#endif
+#endif /* COPY_DICT */
+			}
+			else {				/* a M1 match */
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+				m_off = 1 + (t << 6) + (*ip++ >> 2);
+				last_m_off = m_off;
+#else
+				m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+				NEED_OP(2);
+				t = 2; COPY_DICT(t,m_off)
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+				t = 1 + (t << 6) + (*ip++ >> 2);
+				m_pos = op - t;
+				last_m_off = t;
+#else
+				m_pos = op - 1;
+				m_pos -= t >> 2;
+				m_pos -= *ip++ << 2;
+#endif
+				TEST_LB(m_pos); NEED_OP(2);
+				*op++ = *m_pos++;
+				*op++ = *m_pos;
+#endif /* COPY_DICT */
+				goto match_done;
+			}
+
+			/* copy match */
+#if defined(COPY_DICT)
+
+			NEED_OP(t+3-1);
+			t += 3-1; COPY_DICT(t,m_off)
+
+#else /* !COPY_DICT */
+
+			TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+# if !defined(LZO_UNALIGNED_OK_4)
+			if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) {
+				assert((op - m_pos) >= 4);	/* both pointers are aligned */
+# else
+			if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) {
+# endif
+				COPY4(op,m_pos);
+				op += 4; m_pos += 4; t -= 4 - (3 - 1);
+				do {
+					COPY4(op,m_pos);
+					op += 4; m_pos += 4; t -= 4;
+				} while (t >= 4);
+				if (t > 0)
+					do *op++ = *m_pos++; while (--t > 0);
+			}
+			else
+#endif
+			{
+ copy_match:
+				*op++ = *m_pos++; *op++ = *m_pos++;
+				do *op++ = *m_pos++; while (--t > 0);
+			}
+
+#endif /* COPY_DICT */
+
+ match_done:
+#if defined(LZO1Z)
+			t = ip[-1] & 3;
+#else
+			t = ip[-2] & 3;
+#endif
+			if (t == 0)
+				break;
+
+			/* copy literals */
+ match_next:
+			assert(t > 0);
+			assert(t < 4);
+			NEED_OP(t);
+			NEED_IP(t+1);
+#if 0
+			do *op++ = *ip++; while (--t > 0);
+#else
+			*op++ = *ip++;
+			if (t > 1) {
+				*op++ = *ip++;
+				if (t > 2)
+					*op++ = *ip++;
+			}
+#endif
+			t = *ip++;
+		} while (TEST_IP && TEST_OP);
+	}
+
+//#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+	/* no EOF code was found */
+	*out_len = pd(op, out);
+	return LZO_E_EOF_NOT_FOUND;
+//#endif
+
+ eof_found:
+	assert(t == 1);
+	*out_len = pd(op, out);
+	return (ip == ip_end ? LZO_E_OK :
+		   (ip < ip_end	 ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+//#if defined(HAVE_NEED_IP)
+ input_overrun:
+	*out_len = pd(op, out);
+	return LZO_E_INPUT_OVERRUN;
+//#endif
+
+//#if defined(HAVE_NEED_OP)
+ output_overrun:
+	*out_len = pd(op, out);
+	return LZO_E_OUTPUT_OVERRUN;
+//#endif
+
+//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+ lookbehind_overrun:
+	*out_len = pd(op, out);
+	return LZO_E_LOOKBEHIND_OVERRUN;
+//#endif
+}
diff --git a/ap/app/busybox/src/archival/libarchive/open_transformer.c b/ap/app/busybox/src/archival/libarchive/open_transformer.c
new file mode 100644
index 0000000..dae04aa
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/open_transformer.c
@@ -0,0 +1,221 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+void FAST_FUNC init_transformer_aux_data(transformer_aux_data_t *aux)
+{
+	memset(aux, 0, sizeof(*aux));
+}
+
+int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16)
+{
+	if (aux && aux->check_signature) {
+		uint16_t magic2;
+		if (full_read(src_fd, &magic2, 2) != 2 || magic2 != magic16) {
+			bb_error_msg("invalid magic");
+#if 0 /* possible future extension */
+			if (aux->check_signature > 1)
+				xfunc_die();
+#endif
+			return -1;
+		}
+	}
+	return 0;
+}
+
+void check_errors_in_children(int signo)
+{
+	int status;
+
+	if (!signo) {
+		/* block waiting for any child */
+		if (wait(&status) < 0)
+			return; /* probably there are no children */
+		goto check_status;
+	}
+
+	/* Wait for any child without blocking */
+	for (;;) {
+		if (wait_any_nohang(&status) < 0)
+			/* wait failed?! I'm confused... */
+			return;
+ check_status:
+		if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+			/* this child exited with 0 */
+			continue;
+		/* Cannot happen?
+		if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; */
+		bb_got_signal = 1;
+	}
+}
+
+/* transformer(), more than meets the eye */
+#if BB_MMU
+void FAST_FUNC open_transformer(int fd,
+	int check_signature,
+	IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd)
+)
+#else
+void FAST_FUNC open_transformer(int fd, const char *transform_prog)
+#endif
+{
+	struct fd_pair fd_pipe;
+	int pid;
+
+	xpiped_pair(fd_pipe);
+	pid = BB_MMU ? xfork() : xvfork();
+	if (pid == 0) {
+		/* Child */
+		close(fd_pipe.rd); /* we don't want to read from the parent */
+		// FIXME: error check?
+#if BB_MMU
+		{
+			transformer_aux_data_t aux;
+			init_transformer_aux_data(&aux);
+			aux.check_signature = check_signature;
+			transformer(&aux, fd, fd_pipe.wr);
+			if (ENABLE_FEATURE_CLEAN_UP) {
+				close(fd_pipe.wr); /* send EOF */
+				close(fd);
+			}
+			/* must be _exit! bug was actually seen here */
+			_exit(EXIT_SUCCESS);
+		}
+#else
+		{
+			char *argv[4];
+			xmove_fd(fd, 0);
+			xmove_fd(fd_pipe.wr, 1);
+			argv[0] = (char*)transform_prog;
+			argv[1] = (char*)"-cf";
+			argv[2] = (char*)"-";
+			argv[3] = NULL;
+			BB_EXECVP(transform_prog, argv);
+			bb_perror_msg_and_die("can't execute '%s'", transform_prog);
+		}
+#endif
+		/* notreached */
+	}
+
+	/* parent process */
+	close(fd_pipe.wr); /* don't want to write to the child */
+	xmove_fd(fd_pipe.rd, fd);
+}
+
+
+#if SEAMLESS_COMPRESSION
+
+/* Used by e.g. rpm which gives us a fd without filename,
+ * thus we can't guess the format from filename's extension.
+ */
+int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected)
+{
+	union {
+		uint8_t b[4];
+		uint16_t b16[2];
+		uint32_t b32[1];
+	} magic;
+	int offset = -2;
+	USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);)
+	USE_FOR_NOMMU(const char *xformer_prog;)
+
+	/* .gz and .bz2 both have 2-byte signature, and their
+	 * unpack_XXX_stream wants this header skipped. */
+	xread(fd, magic.b16, sizeof(magic.b16[0]));
+	if (ENABLE_FEATURE_SEAMLESS_GZ
+	 && magic.b16[0] == GZIP_MAGIC
+	) {
+		USE_FOR_MMU(xformer = unpack_gz_stream;)
+		USE_FOR_NOMMU(xformer_prog = "gunzip";)
+		goto found_magic;
+	}
+	if (ENABLE_FEATURE_SEAMLESS_BZ2
+	 && magic.b16[0] == BZIP2_MAGIC
+	) {
+		USE_FOR_MMU(xformer = unpack_bz2_stream;)
+		USE_FOR_NOMMU(xformer_prog = "bunzip2";)
+		goto found_magic;
+	}
+	if (ENABLE_FEATURE_SEAMLESS_XZ
+	 && magic.b16[0] == XZ_MAGIC1
+	) {
+		offset = -6;
+		xread(fd, magic.b32, sizeof(magic.b32[0]));
+		if (magic.b32[0] == XZ_MAGIC2) {
+			USE_FOR_MMU(xformer = unpack_xz_stream;)
+			USE_FOR_NOMMU(xformer_prog = "unxz";)
+			goto found_magic;
+		}
+	}
+
+	/* No known magic seen */
+	if (fail_if_not_detected)
+		bb_error_msg_and_die("no gzip"
+			IF_FEATURE_SEAMLESS_BZ2("/bzip2")
+			IF_FEATURE_SEAMLESS_XZ("/xz")
+			" magic");
+	xlseek(fd, offset, SEEK_CUR);
+	return 1;
+
+ found_magic:
+# if BB_MMU
+	open_transformer_with_no_sig(fd, xformer);
+# else
+	/* NOMMU version of open_transformer execs
+	 * an external unzipper that wants
+	 * file position at the start of the file */
+	xlseek(fd, offset, SEEK_CUR);
+	open_transformer_with_sig(fd, xformer, xformer_prog);
+# endif
+	return 0;
+}
+
+int FAST_FUNC open_zipped(const char *fname)
+{
+	char *sfx;
+	int fd;
+
+	fd = open(fname, O_RDONLY);
+	if (fd < 0)
+		return fd;
+
+	sfx = strrchr(fname, '.');
+	if (sfx) {
+		sfx++;
+		if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0)
+			/* .lzma has no header/signature, just trust it */
+			open_transformer_with_sig(fd, unpack_lzma_stream, "unlzma");
+		else
+		if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0)
+		 || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0)
+		 || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0)
+		) {
+			setup_unzip_on_fd(fd, /*fail_if_not_detected:*/ 1);
+		}
+	}
+
+	return fd;
+}
+
+#endif /* SEAMLESS_COMPRESSION */
+
+void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
+{
+	int fd;
+	char *image;
+
+	fd = open_zipped(fname);
+	if (fd < 0)
+		return NULL;
+
+	image = xmalloc_read(fd, maxsz_p);
+	if (!image)
+		bb_perror_msg("read error from '%s'", fname);
+	close(fd);
+
+	return image;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/seek_by_jump.c b/ap/app/busybox/src/archival/libarchive/seek_by_jump.c
new file mode 100644
index 0000000..4fcd99a
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/seek_by_jump.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+void FAST_FUNC seek_by_jump(int fd, off_t amount)
+{
+	if (amount
+	 && lseek(fd, amount, SEEK_CUR) == (off_t) -1
+	) {
+		if (errno == ESPIPE)
+			seek_by_read(fd, amount);
+		else
+			bb_perror_msg_and_die("seek failure");
+	}
+}
diff --git a/ap/app/busybox/src/archival/libarchive/seek_by_read.c b/ap/app/busybox/src/archival/libarchive/seek_by_read.c
new file mode 100644
index 0000000..c0fde96
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/seek_by_read.c
@@ -0,0 +1,16 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+/*  If we are reading through a pipe, or from stdin then we can't lseek,
+ *  we must read and discard the data to skip over it.
+ */
+void FAST_FUNC seek_by_read(int fd, off_t amount)
+{
+	if (amount)
+		bb_copyfd_exact_size(fd, -1, amount);
+}
diff --git a/ap/app/busybox/src/archival/libarchive/unpack_ar_archive.c b/ap/app/busybox/src/archival/libarchive/unpack_ar_archive.c
new file mode 100644
index 0000000..214d17e
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/unpack_ar_archive.c
@@ -0,0 +1,22 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "bb_archive.h"
+#include "ar.h"
+
+void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive)
+{
+	char magic[7];
+
+	xread(ar_archive->src_fd, magic, AR_MAGIC_LEN);
+	if (strncmp(magic, AR_MAGIC, AR_MAGIC_LEN) != 0) {
+		bb_error_msg_and_die("invalid ar magic");
+	}
+	ar_archive->offset += AR_MAGIC_LEN;
+
+	while (get_header_ar(ar_archive) == EXIT_SUCCESS)
+		continue;
+}
diff --git a/ap/app/busybox/src/archival/libarchive/unxz/README b/ap/app/busybox/src/archival/libarchive/unxz/README
new file mode 100644
index 0000000..c5972f6
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/unxz/README
@@ -0,0 +1,135 @@
+
+XZ Embedded
+===========
+
+    XZ Embedded is a relatively small, limited implementation of the .xz
+    file format. Currently only decoding is implemented.
+
+    XZ Embedded was written for use in the Linux kernel, but the code can
+    be easily used in other environments too, including regular userspace
+    applications.
+
+    This README contains information that is useful only when the copy
+    of XZ Embedded isn't part of the Linux kernel tree. You should also
+    read linux/Documentation/xz.txt even if you aren't using XZ Embedded
+    as part of Linux; information in that file is not repeated in this
+    README.
+
+Compiling the Linux kernel module
+
+    The xz_dec module depends on crc32 module, so make sure that you have
+    it enabled (CONFIG_CRC32).
+
+    Building the xz_dec and xz_dec_test modules without support for BCJ
+    filters:
+
+        cd linux/lib/xz
+        make -C /path/to/kernel/source \
+                KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \
+                CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m
+
+    Building the xz_dec and xz_dec_test modules with support for BCJ
+    filters:
+
+        cd linux/lib/xz
+        make -C /path/to/kernel/source \
+                KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \
+                CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m CONFIG_XZ_DEC_BCJ=y \
+                CONFIG_XZ_DEC_X86=y CONFIG_XZ_DEC_POWERPC=y \
+                CONFIG_XZ_DEC_IA64=y CONFIG_XZ_DEC_ARM=y \
+                CONFIG_XZ_DEC_ARMTHUMB=y CONFIG_XZ_DEC_SPARC=y
+
+    If you want only one or a few of the BCJ filters, omit the appropriate
+    variables. CONFIG_XZ_DEC_BCJ=y is always required to build the support
+    code shared between all BCJ filters.
+
+    Most people don't need the xz_dec_test module. You can skip building
+    it by omitting CONFIG_XZ_DEC_TEST=m from the make command line.
+
+Compiler requirements
+
+    XZ Embedded should compile as either GNU-C89 (used in the Linux
+    kernel) or with any C99 compiler. Getting the code to compile with
+    non-GNU C89 compiler or a C++ compiler should be quite easy as
+    long as there is a data type for unsigned 64-bit integer (or the
+    code is modified not to support large files, which needs some more
+    care than just using 32-bit integer instead of 64-bit).
+
+    If you use GCC, try to use a recent version. For example, on x86,
+    xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when
+    compiled with GCC 4.3.3.
+
+Embedding into userspace applications
+
+    To embed the XZ decoder, copy the following files into a single
+    directory in your source code tree:
+
+        linux/include/linux/xz.h
+        linux/lib/xz/xz_crc32.c
+        linux/lib/xz/xz_dec_lzma2.c
+        linux/lib/xz/xz_dec_stream.c
+        linux/lib/xz/xz_lzma2.h
+        linux/lib/xz/xz_private.h
+        linux/lib/xz/xz_stream.h
+        userspace/xz_config.h
+
+    Alternatively, xz.h may be placed into a different directory but then
+    that directory must be in the compiler include path when compiling
+    the .c files.
+
+    Your code should use only the functions declared in xz.h. The rest of
+    the .h files are meant only for internal use in XZ Embedded.
+
+    You may want to modify xz_config.h to be more suitable for your build
+    environment. Probably you should at least skim through it even if the
+    default file works as is.
+
+BCJ filter support
+
+    If you want support for one or more BCJ filters, you need to copy also
+    linux/lib/xz/xz_dec_bcj.c into your application, and use appropriate
+    #defines in xz_config.h or in compiler flags. You don't need these
+    #defines in the code that just uses XZ Embedded via xz.h, but having
+    them always #defined doesn't hurt either.
+
+        #define             Instruction set     BCJ filter endianness
+        XZ_DEC_X86          x86 or x86-64       Little endian only
+        XZ_DEC_POWERPC      PowerPC             Big endian only
+        XZ_DEC_IA64         Itanium (IA-64)     Big or little endian
+        XZ_DEC_ARM          ARM                 Little endian only
+        XZ_DEC_ARMTHUMB     ARM-Thumb           Little endian only
+        XZ_DEC_SPARC        SPARC               Big or little endian
+
+    While some architectures are (partially) bi-endian, the endianness
+    setting doesn't change the endianness of the instructions on all
+    architectures. That's why Itanium and SPARC filters work for both big
+    and little endian executables (Itanium has little endian instructions
+    and SPARC has big endian instructions).
+
+    There currently is no filter for little endian PowerPC or big endian
+    ARM or ARM-Thumb. Implementing filters for them can be considered if
+    there is a need for such filters in real-world applications.
+
+Notes about shared libraries
+
+    If you are including XZ Embedded into a shared library, you very
+    probably should rename the xz_* functions to prevent symbol
+    conflicts in case your library is linked against some other library
+    or application that also has XZ Embedded in it (which may even be
+    a different version of XZ Embedded). TODO: Provide an easy way
+    to do this.
+
+    Please don't create a shared library of XZ Embedded itself unless
+    it is fine to rebuild everything depending on that shared library
+    everytime you upgrade to a newer version of XZ Embedded. There are
+    no API or ABI stability guarantees between different versions of
+    XZ Embedded.
+
+Specifying the calling convention
+
+    XZ_FUNC macro was included to support declaring functions with __init
+    in Linux. Outside Linux, it can be used to specify the calling
+    convention on systems that support multiple calling conventions.
+    For example, on Windows, you may make all functions use the stdcall
+    calling convention by defining XZ_FUNC=__stdcall when building and
+    using the functions from XZ Embedded.
diff --git a/ap/app/busybox/src/archival/libarchive/unxz/xz.h b/ap/app/busybox/src/archival/libarchive/unxz/xz.h
new file mode 100644
index 0000000..c6c071c
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/unxz/xz.h
@@ -0,0 +1,271 @@
+/*
+ * XZ decompressor
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ *          Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_H
+#define XZ_H
+
+#ifdef __KERNEL__
+#	include <linux/stddef.h>
+#	include <linux/types.h>
+#else
+#	include <stddef.h>
+#	include <stdint.h>
+#endif
+
+/* In Linux, this is used to make extern functions static when needed. */
+#ifndef XZ_EXTERN
+#	define XZ_EXTERN extern
+#endif
+
+/* In Linux, this is used to mark the functions with __init when needed. */
+#ifndef XZ_FUNC
+#	define XZ_FUNC
+#endif
+
+/**
+ * enum xz_mode - Operation mode
+ *
+ * @XZ_SINGLE:              Single-call mode. This uses less RAM than
+ *                          than multi-call modes, because the LZMA2
+ *                          dictionary doesn't need to be allocated as
+ *                          part of the decoder state. All required data
+ *                          structures are allocated at initialization,
+ *                          so xz_dec_run() cannot return XZ_MEM_ERROR.
+ * @XZ_PREALLOC:            Multi-call mode with preallocated LZMA2
+ *                          dictionary buffer. All data structures are
+ *                          allocated at initialization, so xz_dec_run()
+ *                          cannot return XZ_MEM_ERROR.
+ * @XZ_DYNALLOC:            Multi-call mode. The LZMA2 dictionary is
+ *                          allocated once the required size has been
+ *                          parsed from the stream headers. If the
+ *                          allocation fails, xz_dec_run() will return
+ *                          XZ_MEM_ERROR.
+ *
+ * It is possible to enable support only for a subset of the above
+ * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC,
+ * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled
+ * with support for all operation modes, but the preboot code may
+ * be built with fewer features to minimize code size.
+ */
+enum xz_mode {
+	XZ_SINGLE,
+	XZ_PREALLOC,
+	XZ_DYNALLOC
+};
+
+/**
+ * enum xz_ret - Return codes
+ * @XZ_OK:                  Everything is OK so far. More input or more
+ *                          output space is required to continue. This
+ *                          return code is possible only in multi-call mode
+ *                          (XZ_PREALLOC or XZ_DYNALLOC).
+ * @XZ_STREAM_END:          Operation finished successfully.
+ * @XZ_UNSUPPORTED_CHECK:   Integrity check type is not supported. Decoding
+ *                          is still possible in multi-call mode by simply
+ *                          calling xz_dec_run() again.
+ *                          NOTE: This return value is used only if
+ *                          XZ_DEC_ANY_CHECK was defined at build time,
+ *                          which is not used in the kernel. Unsupported
+ *                          check types return XZ_OPTIONS_ERROR if
+ *                          XZ_DEC_ANY_CHECK was not defined at build time.
+ * @XZ_MEM_ERROR:           Allocating memory failed. This return code is
+ *                          possible only if the decoder was initialized
+ *                          with XZ_DYNALLOC. The amount of memory that was
+ *                          tried to be allocated was no more than the
+ *                          dict_max argument given to xz_dec_init().
+ * @XZ_MEMLIMIT_ERROR:      A bigger LZMA2 dictionary would be needed than
+ *                          allowed by the dict_max argument given to
+ *                          xz_dec_init(). This return value is possible
+ *                          only in multi-call mode (XZ_PREALLOC or
+ *                          XZ_DYNALLOC); the single-call mode (XZ_SINGLE)
+ *                          ignores the dict_max argument.
+ * @XZ_FORMAT_ERROR:        File format was not recognized (wrong magic
+ *                          bytes).
+ * @XZ_OPTIONS_ERROR:       This implementation doesn't support the requested
+ *                          compression options. In the decoder this means
+ *                          that the header CRC32 matches, but the header
+ *                          itself specifies something that we don't support.
+ * @XZ_DATA_ERROR:          Compressed data is corrupt.
+ * @XZ_BUF_ERROR:           Cannot make any progress. Details are slightly
+ *                          different between multi-call and single-call
+ *                          mode; more information below.
+ *
+ * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
+ * to XZ code cannot consume any input and cannot produce any new output.
+ * This happens when there is no new input available, or the output buffer
+ * is full while at least one output byte is still pending. Assuming your
+ * code is not buggy, you can get this error only when decoding a compressed
+ * stream that is truncated or otherwise corrupt.
+ *
+ * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
+ * is too small, or the compressed input is corrupt in a way that makes the
+ * decoder produce more output than the caller expected. When it is
+ * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
+ * is used instead of XZ_BUF_ERROR.
+ */
+enum xz_ret {
+	XZ_OK,
+	XZ_STREAM_END,
+	XZ_UNSUPPORTED_CHECK,
+	XZ_MEM_ERROR,
+	XZ_MEMLIMIT_ERROR,
+	XZ_FORMAT_ERROR,
+	XZ_OPTIONS_ERROR,
+	XZ_DATA_ERROR,
+	XZ_BUF_ERROR
+};
+
+/**
+ * struct xz_buf - Passing input and output buffers to XZ code
+ * @in:         Beginning of the input buffer. This may be NULL if and only
+ *              if in_pos is equal to in_size.
+ * @in_pos:     Current position in the input buffer. This must not exceed
+ *              in_size.
+ * @in_size:    Size of the input buffer
+ * @out:        Beginning of the output buffer. This may be NULL if and only
+ *              if out_pos is equal to out_size.
+ * @out_pos:    Current position in the output buffer. This must not exceed
+ *              out_size.
+ * @out_size:   Size of the output buffer
+ *
+ * Only the contents of the output buffer from out[out_pos] onward, and
+ * the variables in_pos and out_pos are modified by the XZ code.
+ */
+struct xz_buf {
+	const uint8_t *in;
+	size_t in_pos;
+	size_t in_size;
+
+	uint8_t *out;
+	size_t out_pos;
+	size_t out_size;
+};
+
+/**
+ * struct xz_dec - Opaque type to hold the XZ decoder state
+ */
+struct xz_dec;
+
+/**
+ * xz_dec_init() - Allocate and initialize a XZ decoder state
+ * @mode:       Operation mode
+ * @dict_max:   Maximum size of the LZMA2 dictionary (history buffer) for
+ *              multi-call decoding. This is ignored in single-call mode
+ *              (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes
+ *              or 2^n + 2^(n-1) bytes (the latter sizes are less common
+ *              in practice), so other values for dict_max don't make sense.
+ *              In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB,
+ *              512 KiB, and 1 MiB are probably the only reasonable values,
+ *              except for kernel and initramfs images where a bigger
+ *              dictionary can be fine and useful.
+ *
+ * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at
+ * once. The caller must provide enough output space or the decoding will
+ * fail. The output space is used as the dictionary buffer, which is why
+ * there is no need to allocate the dictionary as part of the decoder's
+ * internal state.
+ *
+ * Because the output buffer is used as the workspace, streams encoded using
+ * a big dictionary are not a problem in single-call mode. It is enough that
+ * the output buffer is big enough to hold the actual uncompressed data; it
+ * can be smaller than the dictionary size stored in the stream headers.
+ *
+ * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes
+ * of memory is preallocated for the LZMA2 dictionary. This way there is no
+ * risk that xz_dec_run() could run out of memory, since xz_dec_run() will
+ * never allocate any memory. Instead, if the preallocated dictionary is too
+ * small for decoding the given input stream, xz_dec_run() will return
+ * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be
+ * decoded to avoid allocating excessive amount of memory for the dictionary.
+ *
+ * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC):
+ * dict_max specifies the maximum allowed dictionary size that xz_dec_run()
+ * may allocate once it has parsed the dictionary size from the stream
+ * headers. This way excessive allocations can be avoided while still
+ * limiting the maximum memory usage to a sane value to prevent running the
+ * system out of memory when decompressing streams from untrusted sources.
+ *
+ * On success, xz_dec_init() returns a pointer to struct xz_dec, which is
+ * ready to be used with xz_dec_run(). If memory allocation fails,
+ * xz_dec_init() returns NULL.
+ */
+XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(
+		enum xz_mode mode, uint32_t dict_max);
+
+/**
+ * xz_dec_run() - Run the XZ decoder
+ * @s:          Decoder state allocated using xz_dec_init()
+ * @b:          Input and output buffers
+ *
+ * The possible return values depend on build options and operation mode.
+ * See enum xz_ret for details.
+ *
+ * NOTE: If an error occurs in single-call mode (return value is not
+ * XZ_STREAM_END), b->in_pos and b->out_pos are not modified, and the
+ * contents of the output buffer from b->out[b->out_pos] onward are
+ * undefined. This is true even after XZ_BUF_ERROR, because with some filter
+ * chains, there may be a second pass over the output buffer, and this pass
+ * cannot be properly done if the output buffer is truncated. Thus, you
+ * cannot give the single-call decoder a too small buffer and then expect to
+ * get that amount valid data from the beginning of the stream. You must use
+ * the multi-call decoder if you don't want to uncompress the whole stream.
+ */
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b);
+
+/**
+ * xz_dec_reset() - Reset an already allocated decoder state
+ * @s:          Decoder state allocated using xz_dec_init()
+ *
+ * This function can be used to reset the multi-call decoder state without
+ * freeing and reallocating memory with xz_dec_end() and xz_dec_init().
+ *
+ * In single-call mode, xz_dec_reset() is always called in the beginning of
+ * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
+ * multi-call mode.
+ */
+XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s);
+
+/**
+ * xz_dec_end() - Free the memory allocated for the decoder state
+ * @s:          Decoder state allocated using xz_dec_init(). If s is NULL,
+ *              this function does nothing.
+ */
+XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s);
+
+/*
+ * Standalone build (userspace build or in-kernel build for boot time use)
+ * needs a CRC32 implementation. For normal in-kernel use, kernel's own
+ * CRC32 module is used instead, and users of this module don't need to
+ * care about the functions below.
+ */
+#ifndef XZ_INTERNAL_CRC32
+#	ifdef __KERNEL__
+#		define XZ_INTERNAL_CRC32 0
+#	else
+#		define XZ_INTERNAL_CRC32 1
+#	endif
+#endif
+
+#if XZ_INTERNAL_CRC32
+/*
+ * This must be called before any other xz_* function to initialize
+ * the CRC32 lookup table.
+ */
+XZ_EXTERN void XZ_FUNC xz_crc32_init(void);
+
+/*
+ * Update CRC32 value using the polynomial from IEEE-802.3. To start a new
+ * calculation, the third argument must be zero. To continue the calculation,
+ * the previously returned value is passed as the third argument.
+ */
+XZ_EXTERN uint32_t XZ_FUNC xz_crc32(
+		const uint8_t *buf, size_t size, uint32_t crc);
+#endif
+#endif
diff --git a/ap/app/busybox/src/archival/libarchive/unxz/xz_config.h b/ap/app/busybox/src/archival/libarchive/unxz/xz_config.h
new file mode 100644
index 0000000..187e1cb
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/unxz/xz_config.h
@@ -0,0 +1,123 @@
+/*
+ * Private includes and definitions for userspace use of XZ Embedded
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_CONFIG_H
+#define XZ_CONFIG_H
+
+/* Uncomment as needed to enable BCJ filter decoders. */
+/* #define XZ_DEC_X86 */
+/* #define XZ_DEC_POWERPC */
+/* #define XZ_DEC_IA64 */
+/* #define XZ_DEC_ARM */
+/* #define XZ_DEC_ARMTHUMB */
+/* #define XZ_DEC_SPARC */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xz.h"
+
+#define kmalloc(size, flags) malloc(size)
+#define kfree(ptr) free(ptr)
+#define vmalloc(size) malloc(size)
+#define vfree(ptr) free(ptr)
+
+#define memeq(a, b, size) (memcmp(a, b, size) == 0)
+#define memzero(buf, size) memset(buf, 0, size)
+
+#undef min
+#undef min_t
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define min_t(type, x, y) min(x, y)
+
+/*
+ * Some functions have been marked with __always_inline to keep the
+ * performance reasonable even when the compiler is optimizing for
+ * small code size. You may be able to save a few bytes by #defining
+ * __always_inline to plain inline, but don't complain if the code
+ * becomes slow.
+ *
+ * NOTE: System headers on GNU/Linux may #define this macro already,
+ * so if you want to change it, you need to #undef it first.
+ */
+#ifndef __always_inline
+#	ifdef __GNUC__
+#		define __always_inline \
+			inline __attribute__((__always_inline__))
+#	else
+#		define __always_inline inline
+#	endif
+#endif
+
+/*
+ * Some functions are marked to never be inlined to reduce stack usage.
+ * If you don't care about stack usage, you may want to modify this so
+ * that noinline_for_stack is #defined to be empty even when using GCC.
+ * Doing so may save a few bytes in binary size.
+ */
+#ifndef noinline_for_stack
+#	ifdef __GNUC__
+#		define noinline_for_stack __attribute__((__noinline__))
+#	else
+#		define noinline_for_stack
+#	endif
+#endif
+
+/* Inline functions to access unaligned unsigned 32-bit integers */
+#ifndef get_unaligned_le32
+static inline uint32_t XZ_FUNC get_unaligned_le32(const uint8_t *buf)
+{
+	return (uint32_t)buf[0]
+			| ((uint32_t)buf[1] << 8)
+			| ((uint32_t)buf[2] << 16)
+			| ((uint32_t)buf[3] << 24);
+}
+#endif
+
+#ifndef get_unaligned_be32
+static inline uint32_t XZ_FUNC get_unaligned_be32(const uint8_t *buf)
+{
+	return (uint32_t)(buf[0] << 24)
+			| ((uint32_t)buf[1] << 16)
+			| ((uint32_t)buf[2] << 8)
+			| (uint32_t)buf[3];
+}
+#endif
+
+#ifndef put_unaligned_le32
+static inline void XZ_FUNC put_unaligned_le32(uint32_t val, uint8_t *buf)
+{
+	buf[0] = (uint8_t)val;
+	buf[1] = (uint8_t)(val >> 8);
+	buf[2] = (uint8_t)(val >> 16);
+	buf[3] = (uint8_t)(val >> 24);
+}
+#endif
+
+#ifndef put_unaligned_be32
+static inline void XZ_FUNC put_unaligned_be32(uint32_t val, uint8_t *buf)
+{
+	buf[0] = (uint8_t)(val >> 24);
+	buf[1] = (uint8_t)(val >> 16);
+	buf[2] = (uint8_t)(val >> 8);
+	buf[3] = (uint8_t)val;
+}
+#endif
+
+/*
+ * Use get_unaligned_le32() also for aligned access for simplicity. On
+ * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
+ * could save a few bytes in code size.
+ */
+#ifndef get_le32
+#	define get_le32 get_unaligned_le32
+#endif
+
+#endif
diff --git a/ap/app/busybox/src/archival/libarchive/unxz/xz_dec_bcj.c b/ap/app/busybox/src/archival/libarchive/unxz/xz_dec_bcj.c
new file mode 100644
index 0000000..09162b5
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/unxz/xz_dec_bcj.c
@@ -0,0 +1,564 @@
+/*
+ * Branch/Call/Jump (BCJ) filter decoders
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ *          Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+
+/*
+ * The rest of the file is inside this ifdef. It makes things a little more
+ * convenient when building without support for any BCJ filters.
+ */
+#ifdef XZ_DEC_BCJ
+
+struct xz_dec_bcj {
+	/* Type of the BCJ filter being used */
+	enum {
+		BCJ_X86 = 4,        /* x86 or x86-64 */
+		BCJ_POWERPC = 5,    /* Big endian only */
+		BCJ_IA64 = 6,       /* Big or little endian */
+		BCJ_ARM = 7,        /* Little endian only */
+		BCJ_ARMTHUMB = 8,   /* Little endian only */
+		BCJ_SPARC = 9       /* Big or little endian */
+	} type;
+
+	/*
+	 * Return value of the next filter in the chain. We need to preserve
+	 * this information across calls, because we must not call the next
+	 * filter anymore once it has returned XZ_STREAM_END.
+	 */
+	enum xz_ret ret;
+
+	/* True if we are operating in single-call mode. */
+	bool single_call;
+
+	/*
+	 * Absolute position relative to the beginning of the uncompressed
+	 * data (in a single .xz Block). We care only about the lowest 32
+	 * bits so this doesn't need to be uint64_t even with big files.
+	 */
+	uint32_t pos;
+
+	/* x86 filter state */
+	uint32_t x86_prev_mask;
+
+	/* Temporary space to hold the variables from struct xz_buf */
+	uint8_t *out;
+	size_t out_pos;
+	size_t out_size;
+
+	struct {
+		/* Amount of already filtered data in the beginning of buf */
+		size_t filtered;
+
+		/* Total amount of data currently stored in buf  */
+		size_t size;
+
+		/*
+		 * Buffer to hold a mix of filtered and unfiltered data. This
+		 * needs to be big enough to hold Alignment + 2 * Look-ahead:
+		 *
+		 * Type         Alignment   Look-ahead
+		 * x86              1           4
+		 * PowerPC          4           0
+		 * IA-64           16           0
+		 * ARM              4           0
+		 * ARM-Thumb        2           2
+		 * SPARC            4           0
+		 */
+		uint8_t buf[16];
+	} temp;
+};
+
+#ifdef XZ_DEC_X86
+/*
+ * This is macro used to test the most significant byte of a memory address
+ * in an x86 instruction.
+ */
+#define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF)
+
+static noinline_for_stack size_t XZ_FUNC bcj_x86(
+		struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+	static const bool mask_to_allowed_status[8]
+		= { true, true, true, false, true, false, false, false };
+
+	static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
+
+	size_t i;
+	size_t prev_pos = (size_t)-1;
+	uint32_t prev_mask = s->x86_prev_mask;
+	uint32_t src;
+	uint32_t dest;
+	uint32_t j;
+	uint8_t b;
+
+	if (size <= 4)
+		return 0;
+
+	size -= 4;
+	for (i = 0; i < size; ++i) {
+		if ((buf[i] & 0xFE) != 0xE8)
+			continue;
+
+		prev_pos = i - prev_pos;
+		if (prev_pos > 3) {
+			prev_mask = 0;
+		} else {
+			prev_mask = (prev_mask << (prev_pos - 1)) & 7;
+			if (prev_mask != 0) {
+				b = buf[i + 4 - mask_to_bit_num[prev_mask]];
+				if (!mask_to_allowed_status[prev_mask]
+						|| bcj_x86_test_msbyte(b)) {
+					prev_pos = i;
+					prev_mask = (prev_mask << 1) | 1;
+					continue;
+				}
+			}
+		}
+
+		prev_pos = i;
+
+		if (bcj_x86_test_msbyte(buf[i + 4])) {
+			src = get_unaligned_le32(buf + i + 1);
+			while (true) {
+				dest = src - (s->pos + (uint32_t)i + 5);
+				if (prev_mask == 0)
+					break;
+
+				j = mask_to_bit_num[prev_mask] * 8;
+				b = (uint8_t)(dest >> (24 - j));
+				if (!bcj_x86_test_msbyte(b))
+					break;
+
+				src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
+			}
+
+			dest &= 0x01FFFFFF;
+			dest |= (uint32_t)0 - (dest & 0x01000000);
+			put_unaligned_le32(dest, buf + i + 1);
+			i += 4;
+		} else {
+			prev_mask = (prev_mask << 1) | 1;
+		}
+	}
+
+	prev_pos = i - prev_pos;
+	s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
+	return i;
+}
+#endif
+
+#ifdef XZ_DEC_POWERPC
+static noinline_for_stack size_t XZ_FUNC bcj_powerpc(
+		struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+	size_t i;
+	uint32_t instr;
+
+	for (i = 0; i + 4 <= size; i += 4) {
+		instr = get_unaligned_be32(buf + i);
+		if ((instr & 0xFC000003) == 0x48000001) {
+			instr &= 0x03FFFFFC;
+			instr -= s->pos + (uint32_t)i;
+			instr &= 0x03FFFFFC;
+			instr |= 0x48000001;
+			put_unaligned_be32(instr, buf + i);
+		}
+	}
+
+	return i;
+}
+#endif
+
+#ifdef XZ_DEC_IA64
+static noinline_for_stack size_t XZ_FUNC bcj_ia64(
+		struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+	static const uint8_t branch_table[32] = {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		4, 4, 6, 6, 0, 0, 7, 7,
+		4, 4, 0, 0, 4, 4, 0, 0
+	};
+
+	/*
+	 * The local variables take a little bit stack space, but it's less
+	 * than what LZMA2 decoder takes, so it doesn't make sense to reduce
+	 * stack usage here without doing that for the LZMA2 decoder too.
+	 */
+
+	/* Loop counters */
+	size_t i;
+	size_t j;
+
+	/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
+	uint32_t slot;
+
+	/* Bitwise offset of the instruction indicated by slot */
+	uint32_t bit_pos;
+
+	/* bit_pos split into byte and bit parts */
+	uint32_t byte_pos;
+	uint32_t bit_res;
+
+	/* Address part of an instruction */
+	uint32_t addr;
+
+	/* Mask used to detect which instructions to convert */
+	uint32_t mask;
+
+	/* 41-bit instruction stored somewhere in the lowest 48 bits */
+	uint64_t instr;
+
+	/* Instruction normalized with bit_res for easier manipulation */
+	uint64_t norm;
+
+	for (i = 0; i + 16 <= size; i += 16) {
+		mask = branch_table[buf[i] & 0x1F];
+		for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
+			if (((mask >> slot) & 1) == 0)
+				continue;
+
+			byte_pos = bit_pos >> 3;
+			bit_res = bit_pos & 7;
+			instr = 0;
+			for (j = 0; j < 6; ++j)
+				instr |= (uint64_t)(buf[i + j + byte_pos])
+						<< (8 * j);
+
+			norm = instr >> bit_res;
+
+			if (((norm >> 37) & 0x0F) == 0x05
+					&& ((norm >> 9) & 0x07) == 0) {
+				addr = (norm >> 13) & 0x0FFFFF;
+				addr |= ((uint32_t)(norm >> 36) & 1) << 20;
+				addr <<= 4;
+				addr -= s->pos + (uint32_t)i;
+				addr >>= 4;
+
+				norm &= ~((uint64_t)0x8FFFFF << 13);
+				norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
+				norm |= (uint64_t)(addr & 0x100000)
+						<< (36 - 20);
+
+				instr &= (1 << bit_res) - 1;
+				instr |= norm << bit_res;
+
+				for (j = 0; j < 6; j++)
+					buf[i + j + byte_pos]
+						= (uint8_t)(instr >> (8 * j));
+			}
+		}
+	}
+
+	return i;
+}
+#endif
+
+#ifdef XZ_DEC_ARM
+static noinline_for_stack size_t XZ_FUNC bcj_arm(
+		struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+	size_t i;
+	uint32_t addr;
+
+	for (i = 0; i + 4 <= size; i += 4) {
+		if (buf[i + 3] == 0xEB) {
+			addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
+					| ((uint32_t)buf[i + 2] << 16);
+			addr <<= 2;
+			addr -= s->pos + (uint32_t)i + 8;
+			addr >>= 2;
+			buf[i] = (uint8_t)addr;
+			buf[i + 1] = (uint8_t)(addr >> 8);
+			buf[i + 2] = (uint8_t)(addr >> 16);
+		}
+	}
+
+	return i;
+}
+#endif
+
+#ifdef XZ_DEC_ARMTHUMB
+static noinline_for_stack size_t XZ_FUNC bcj_armthumb(
+		struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+	size_t i;
+	uint32_t addr;
+
+	for (i = 0; i + 4 <= size; i += 2) {
+		if ((buf[i + 1] & 0xF8) == 0xF0
+				&& (buf[i + 3] & 0xF8) == 0xF8) {
+			addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
+					| ((uint32_t)buf[i] << 11)
+					| (((uint32_t)buf[i + 3] & 0x07) << 8)
+					| (uint32_t)buf[i + 2];
+			addr <<= 1;
+			addr -= s->pos + (uint32_t)i + 4;
+			addr >>= 1;
+			buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
+			buf[i] = (uint8_t)(addr >> 11);
+			buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
+			buf[i + 2] = (uint8_t)addr;
+			i += 2;
+		}
+	}
+
+	return i;
+}
+#endif
+
+#ifdef XZ_DEC_SPARC
+static noinline_for_stack size_t XZ_FUNC bcj_sparc(
+		struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+	size_t i;
+	uint32_t instr;
+
+	for (i = 0; i + 4 <= size; i += 4) {
+		instr = get_unaligned_be32(buf + i);
+		if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
+			instr <<= 2;
+			instr -= s->pos + (uint32_t)i;
+			instr >>= 2;
+			instr = ((uint32_t)0x40000000 - (instr & 0x400000))
+					| 0x40000000 | (instr & 0x3FFFFF);
+			put_unaligned_be32(instr, buf + i);
+		}
+	}
+
+	return i;
+}
+#endif
+
+/*
+ * Apply the selected BCJ filter. Update *pos and s->pos to match the amount
+ * of data that got filtered.
+ *
+ * NOTE: This is implemented as a switch statement to avoid using function
+ * pointers, which could be problematic in the kernel boot code, which must
+ * avoid pointers to static data (at least on x86).
+ */
+static void XZ_FUNC bcj_apply(struct xz_dec_bcj *s,
+		uint8_t *buf, size_t *pos, size_t size)
+{
+	size_t filtered;
+
+	buf += *pos;
+	size -= *pos;
+
+	switch (s->type) {
+#ifdef XZ_DEC_X86
+	case BCJ_X86:
+		filtered = bcj_x86(s, buf, size);
+		break;
+#endif
+#ifdef XZ_DEC_POWERPC
+	case BCJ_POWERPC:
+		filtered = bcj_powerpc(s, buf, size);
+		break;
+#endif
+#ifdef XZ_DEC_IA64
+	case BCJ_IA64:
+		filtered = bcj_ia64(s, buf, size);
+		break;
+#endif
+#ifdef XZ_DEC_ARM
+	case BCJ_ARM:
+		filtered = bcj_arm(s, buf, size);
+		break;
+#endif
+#ifdef XZ_DEC_ARMTHUMB
+	case BCJ_ARMTHUMB:
+		filtered = bcj_armthumb(s, buf, size);
+		break;
+#endif
+#ifdef XZ_DEC_SPARC
+	case BCJ_SPARC:
+		filtered = bcj_sparc(s, buf, size);
+		break;
+#endif
+	default:
+		/* Never reached but silence compiler warnings. */
+		filtered = 0;
+		break;
+	}
+
+	*pos += filtered;
+	s->pos += filtered;
+}
+
+/*
+ * Flush pending filtered data from temp to the output buffer.
+ * Move the remaining mixture of possibly filtered and unfiltered
+ * data to the beginning of temp.
+ */
+static void XZ_FUNC bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
+{
+	size_t copy_size;
+
+	copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
+	memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
+	b->out_pos += copy_size;
+
+	s->temp.filtered -= copy_size;
+	s->temp.size -= copy_size;
+	memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
+}
+
+/*
+ * The BCJ filter functions are primitive in sense that they process the
+ * data in chunks of 1-16 bytes. To hide this issue, this function does
+ * some buffering.
+ */
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
+		struct xz_dec_lzma2 *lzma2, struct xz_buf *b)
+{
+	size_t out_start;
+
+	/*
+	 * Flush pending already filtered data to the output buffer. Return
+	 * immediatelly if we couldn't flush everything, or if the next
+	 * filter in the chain had already returned XZ_STREAM_END.
+	 */
+	if (s->temp.filtered > 0) {
+		bcj_flush(s, b);
+		if (s->temp.filtered > 0)
+			return XZ_OK;
+
+		if (s->ret == XZ_STREAM_END)
+			return XZ_STREAM_END;
+	}
+
+	/*
+	 * If we have more output space than what is currently pending in
+	 * temp, copy the unfiltered data from temp to the output buffer
+	 * and try to fill the output buffer by decoding more data from the
+	 * next filter in the chain. Apply the BCJ filter on the new data
+	 * in the output buffer. If everything cannot be filtered, copy it
+	 * to temp and rewind the output buffer position accordingly.
+	 */
+	if (s->temp.size < b->out_size - b->out_pos) {
+		out_start = b->out_pos;
+		memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
+		b->out_pos += s->temp.size;
+
+		s->ret = xz_dec_lzma2_run(lzma2, b);
+		if (s->ret != XZ_STREAM_END
+				&& (s->ret != XZ_OK || s->single_call))
+			return s->ret;
+
+		bcj_apply(s, b->out, &out_start, b->out_pos);
+
+		/*
+		 * As an exception, if the next filter returned XZ_STREAM_END,
+		 * we can do that too, since the last few bytes that remain
+		 * unfiltered are meant to remain unfiltered.
+		 */
+		if (s->ret == XZ_STREAM_END)
+			return XZ_STREAM_END;
+
+		s->temp.size = b->out_pos - out_start;
+		b->out_pos -= s->temp.size;
+		memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
+	}
+
+	/*
+	 * If we have unfiltered data in temp, try to fill by decoding more
+	 * data from the next filter. Apply the BCJ filter on temp. Then we
+	 * hopefully can fill the actual output buffer by copying filtered
+	 * data from temp. A mix of filtered and unfiltered data may be left
+	 * in temp; it will be taken care on the next call to this function.
+	 */
+	if (s->temp.size > 0) {
+		/* Make b->out{,_pos,_size} temporarily point to s->temp. */
+		s->out = b->out;
+		s->out_pos = b->out_pos;
+		s->out_size = b->out_size;
+		b->out = s->temp.buf;
+		b->out_pos = s->temp.size;
+		b->out_size = sizeof(s->temp.buf);
+
+		s->ret = xz_dec_lzma2_run(lzma2, b);
+
+		s->temp.size = b->out_pos;
+		b->out = s->out;
+		b->out_pos = s->out_pos;
+		b->out_size = s->out_size;
+
+		if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
+			return s->ret;
+
+		bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
+
+		/*
+		 * If the next filter returned XZ_STREAM_END, we mark that
+		 * everything is filtered, since the last unfiltered bytes
+		 * of the stream are meant to be left as is.
+		 */
+		if (s->ret == XZ_STREAM_END)
+			s->temp.filtered = s->temp.size;
+
+		bcj_flush(s, b);
+		if (s->temp.filtered > 0)
+			return XZ_OK;
+	}
+
+	return s->ret;
+}
+
+XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call)
+{
+	struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (s != NULL)
+		s->single_call = single_call;
+
+	return s;
+}
+
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset(
+		struct xz_dec_bcj *s, uint8_t id)
+{
+	switch (id) {
+#ifdef XZ_DEC_X86
+	case BCJ_X86:
+#endif
+#ifdef XZ_DEC_POWERPC
+	case BCJ_POWERPC:
+#endif
+#ifdef XZ_DEC_IA64
+	case BCJ_IA64:
+#endif
+#ifdef XZ_DEC_ARM
+	case BCJ_ARM:
+#endif
+#ifdef XZ_DEC_ARMTHUMB
+	case BCJ_ARMTHUMB:
+#endif
+#ifdef XZ_DEC_SPARC
+	case BCJ_SPARC:
+#endif
+		break;
+
+	default:
+		/* Unsupported Filter ID */
+		return XZ_OPTIONS_ERROR;
+	}
+
+	s->type = id;
+	s->ret = XZ_OK;
+	s->pos = 0;
+	s->x86_prev_mask = 0;
+	s->temp.filtered = 0;
+	s->temp.size = 0;
+
+	return XZ_OK;
+}
+
+#endif
diff --git a/ap/app/busybox/src/archival/libarchive/unxz/xz_dec_lzma2.c b/ap/app/busybox/src/archival/libarchive/unxz/xz_dec_lzma2.c
new file mode 100644
index 0000000..da71cb4
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/unxz/xz_dec_lzma2.c
@@ -0,0 +1,1175 @@
+/*
+ * LZMA2 decoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ *          Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+#include "xz_lzma2.h"
+
+/*
+ * Range decoder initialization eats the first five bytes of each LZMA chunk.
+ */
+#define RC_INIT_BYTES 5
+
+/*
+ * Minimum number of usable input buffer to safely decode one LZMA symbol.
+ * The worst case is that we decode 22 bits using probabilities and 26
+ * direct bits. This may decode at maximum of 20 bytes of input. However,
+ * lzma_main() does an extra normalization before returning, thus we
+ * need to put 21 here.
+ */
+#define LZMA_IN_REQUIRED 21
+
+/*
+ * Dictionary (history buffer)
+ *
+ * These are always true:
+ *    start <= pos <= full <= end
+ *    pos <= limit <= end
+ *
+ * In multi-call mode, also these are true:
+ *    end == size
+ *    size <= size_max
+ *    allocated <= size
+ *
+ * Most of these variables are size_t to support single-call mode,
+ * in which the dictionary variables address the actual output
+ * buffer directly.
+ */
+struct dictionary {
+	/* Beginning of the history buffer */
+	uint8_t *buf;
+
+	/* Old position in buf (before decoding more data) */
+	size_t start;
+
+	/* Position in buf */
+	size_t pos;
+
+	/*
+	 * How full dictionary is. This is used to detect corrupt input that
+	 * would read beyond the beginning of the uncompressed stream.
+	 */
+	size_t full;
+
+	/* Write limit; we don't write to buf[limit] or later bytes. */
+	size_t limit;
+
+	/*
+	 * End of the dictionary buffer. In multi-call mode, this is
+	 * the same as the dictionary size. In single-call mode, this
+	 * indicates the size of the output buffer.
+	 */
+	size_t end;
+
+	/*
+	 * Size of the dictionary as specified in Block Header. This is used
+	 * together with "full" to detect corrupt input that would make us
+	 * read beyond the beginning of the uncompressed stream.
+	 */
+	uint32_t size;
+
+	/*
+	 * Maximum allowed dictionary size in multi-call mode.
+	 * This is ignored in single-call mode.
+	 */
+	uint32_t size_max;
+
+	/*
+	 * Amount of memory currently allocated for the dictionary.
+	 * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC,
+	 * size_max is always the same as the allocated size.)
+	 */
+	uint32_t allocated;
+
+	/* Operation mode */
+	enum xz_mode mode;
+};
+
+/* Range decoder */
+struct rc_dec {
+	uint32_t range;
+	uint32_t code;
+
+	/*
+	 * Number of initializing bytes remaining to be read
+	 * by rc_read_init().
+	 */
+	uint32_t init_bytes_left;
+
+	/*
+	 * Buffer from which we read our input. It can be either
+	 * temp.buf or the caller-provided input buffer.
+	 */
+	const uint8_t *in;
+	size_t in_pos;
+	size_t in_limit;
+};
+
+/* Probabilities for a length decoder. */
+struct lzma_len_dec {
+	/* Probability of match length being at least 10 */
+	uint16_t choice;
+
+	/* Probability of match length being at least 18 */
+	uint16_t choice2;
+
+	/* Probabilities for match lengths 2-9 */
+	uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
+
+	/* Probabilities for match lengths 10-17 */
+	uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
+
+	/* Probabilities for match lengths 18-273 */
+	uint16_t high[LEN_HIGH_SYMBOLS];
+};
+
+struct lzma_dec {
+	/* Distances of latest four matches */
+	uint32_t rep0;
+	uint32_t rep1;
+	uint32_t rep2;
+	uint32_t rep3;
+
+	/* Types of the most recently seen LZMA symbols */
+	enum lzma_state state;
+
+	/*
+	 * Length of a match. This is updated so that dict_repeat can
+	 * be called again to finish repeating the whole match.
+	 */
+	uint32_t len;
+
+	/*
+	 * LZMA properties or related bit masks (number of literal
+	 * context bits, a mask dervied from the number of literal
+	 * position bits, and a mask dervied from the number
+	 * position bits)
+	 */
+	uint32_t lc;
+	uint32_t literal_pos_mask; /* (1 << lp) - 1 */
+	uint32_t pos_mask;         /* (1 << pb) - 1 */
+
+	/* If 1, it's a match. Otherwise it's a single 8-bit literal. */
+	uint16_t is_match[STATES][POS_STATES_MAX];
+
+	/* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */
+	uint16_t is_rep[STATES];
+
+	/*
+	 * If 0, distance of a repeated match is rep0.
+	 * Otherwise check is_rep1.
+	 */
+	uint16_t is_rep0[STATES];
+
+	/*
+	 * If 0, distance of a repeated match is rep1.
+	 * Otherwise check is_rep2.
+	 */
+	uint16_t is_rep1[STATES];
+
+	/* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */
+	uint16_t is_rep2[STATES];
+
+	/*
+	 * If 1, the repeated match has length of one byte. Otherwise
+	 * the length is decoded from rep_len_decoder.
+	 */
+	uint16_t is_rep0_long[STATES][POS_STATES_MAX];
+
+	/*
+	 * Probability tree for the highest two bits of the match
+	 * distance. There is a separate probability tree for match
+	 * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
+	 */
+	uint16_t dist_slot[DIST_STATES][DIST_SLOTS];
+
+	/*
+	 * Probility trees for additional bits for match distance
+	 * when the distance is in the range [4, 127].
+	 */
+	uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END];
+
+	/*
+	 * Probability tree for the lowest four bits of a match
+	 * distance that is equal to or greater than 128.
+	 */
+	uint16_t dist_align[ALIGN_SIZE];
+
+	/* Length of a normal match */
+	struct lzma_len_dec match_len_dec;
+
+	/* Length of a repeated match */
+	struct lzma_len_dec rep_len_dec;
+
+	/* Probabilities of literals */
+	uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
+};
+
+struct lzma2_dec {
+	/* Position in xz_dec_lzma2_run(). */
+	enum lzma2_seq {
+		SEQ_CONTROL,
+		SEQ_UNCOMPRESSED_1,
+		SEQ_UNCOMPRESSED_2,
+		SEQ_COMPRESSED_0,
+		SEQ_COMPRESSED_1,
+		SEQ_PROPERTIES,
+		SEQ_LZMA_PREPARE,
+		SEQ_LZMA_RUN,
+		SEQ_COPY
+	} sequence;
+
+	/* Next position after decoding the compressed size of the chunk. */
+	enum lzma2_seq next_sequence;
+
+	/* Uncompressed size of LZMA chunk (2 MiB at maximum) */
+	uint32_t uncompressed;
+
+	/*
+	 * Compressed size of LZMA chunk or compressed/uncompressed
+	 * size of uncompressed chunk (64 KiB at maximum)
+	 */
+	uint32_t compressed;
+
+	/*
+	 * True if dictionary reset is needed. This is false before
+	 * the first chunk (LZMA or uncompressed).
+	 */
+	bool need_dict_reset;
+
+	/*
+	 * True if new LZMA properties are needed. This is false
+	 * before the first LZMA chunk.
+	 */
+	bool need_props;
+};
+
+struct xz_dec_lzma2 {
+	/*
+	 * The order below is important on x86 to reduce code size and
+	 * it shouldn't hurt on other platforms. Everything up to and
+	 * including lzma.pos_mask are in the first 128 bytes on x86-32,
+	 * which allows using smaller instructions to access those
+	 * variables. On x86-64, fewer variables fit into the first 128
+	 * bytes, but this is still the best order without sacrificing
+	 * the readability by splitting the structures.
+	 */
+	struct rc_dec rc;
+	struct dictionary dict;
+	struct lzma2_dec lzma2;
+	struct lzma_dec lzma;
+
+	/*
+	 * Temporary buffer which holds small number of input bytes between
+	 * decoder calls. See lzma2_lzma() for details.
+	 */
+	struct {
+		uint32_t size;
+		uint8_t buf[3 * LZMA_IN_REQUIRED];
+	} temp;
+};
+
+/**************
+ * Dictionary *
+ **************/
+
+/*
+ * Reset the dictionary state. When in single-call mode, set up the beginning
+ * of the dictionary to point to the actual output buffer.
+ */
+static void XZ_FUNC dict_reset(struct dictionary *dict, struct xz_buf *b)
+{
+	if (DEC_IS_SINGLE(dict->mode)) {
+		dict->buf = b->out + b->out_pos;
+		dict->end = b->out_size - b->out_pos;
+	}
+
+	dict->start = 0;
+	dict->pos = 0;
+	dict->limit = 0;
+	dict->full = 0;
+}
+
+/* Set dictionary write limit */
+static void XZ_FUNC dict_limit(struct dictionary *dict, size_t out_max)
+{
+	if (dict->end - dict->pos <= out_max)
+		dict->limit = dict->end;
+	else
+		dict->limit = dict->pos + out_max;
+}
+
+/* Return true if at least one byte can be written into the dictionary. */
+static __always_inline bool XZ_FUNC dict_has_space(const struct dictionary *dict)
+{
+	return dict->pos < dict->limit;
+}
+
+/*
+ * Get a byte from the dictionary at the given distance. The distance is
+ * assumed to valid, or as a special case, zero when the dictionary is
+ * still empty. This special case is needed for single-call decoding to
+ * avoid writing a '\0' to the end of the destination buffer.
+ */
+static __always_inline uint32_t XZ_FUNC dict_get(
+		const struct dictionary *dict, uint32_t dist)
+{
+	size_t offset = dict->pos - dist - 1;
+
+	if (dist >= dict->pos)
+		offset += dict->end;
+
+	return dict->full > 0 ? dict->buf[offset] : 0;
+}
+
+/*
+ * Put one byte into the dictionary. It is assumed that there is space for it.
+ */
+static inline void XZ_FUNC dict_put(struct dictionary *dict, uint8_t byte)
+{
+	dict->buf[dict->pos++] = byte;
+
+	if (dict->full < dict->pos)
+		dict->full = dict->pos;
+}
+
+/*
+ * Repeat given number of bytes from the given distance. If the distance is
+ * invalid, false is returned. On success, true is returned and *len is
+ * updated to indicate how many bytes were left to be repeated.
+ */
+static bool XZ_FUNC dict_repeat(
+		struct dictionary *dict, uint32_t *len, uint32_t dist)
+{
+	size_t back;
+	uint32_t left;
+
+	if (dist >= dict->full || dist >= dict->size)
+		return false;
+
+	left = min_t(size_t, dict->limit - dict->pos, *len);
+	*len -= left;
+
+	back = dict->pos - dist - 1;
+	if (dist >= dict->pos)
+		back += dict->end;
+
+	do {
+		dict->buf[dict->pos++] = dict->buf[back++];
+		if (back == dict->end)
+			back = 0;
+	} while (--left > 0);
+
+	if (dict->full < dict->pos)
+		dict->full = dict->pos;
+
+	return true;
+}
+
+/* Copy uncompressed data as is from input to dictionary and output buffers. */
+static void XZ_FUNC dict_uncompressed(
+		struct dictionary *dict, struct xz_buf *b, uint32_t *left)
+{
+	size_t copy_size;
+
+	while (*left > 0 && b->in_pos < b->in_size
+			&& b->out_pos < b->out_size) {
+		copy_size = min(b->in_size - b->in_pos,
+				b->out_size - b->out_pos);
+		if (copy_size > dict->end - dict->pos)
+			copy_size = dict->end - dict->pos;
+		if (copy_size > *left)
+			copy_size = *left;
+
+		*left -= copy_size;
+
+		memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size);
+		dict->pos += copy_size;
+
+		if (dict->full < dict->pos)
+			dict->full = dict->pos;
+
+		if (DEC_IS_MULTI(dict->mode)) {
+			if (dict->pos == dict->end)
+				dict->pos = 0;
+
+			memcpy(b->out + b->out_pos, b->in + b->in_pos,
+					copy_size);
+		}
+
+		dict->start = dict->pos;
+
+		b->out_pos += copy_size;
+		b->in_pos += copy_size;
+
+	}
+}
+
+/*
+ * Flush pending data from dictionary to b->out. It is assumed that there is
+ * enough space in b->out. This is guaranteed because caller uses dict_limit()
+ * before decoding data into the dictionary.
+ */
+static uint32_t XZ_FUNC dict_flush(struct dictionary *dict, struct xz_buf *b)
+{
+	size_t copy_size = dict->pos - dict->start;
+
+	if (DEC_IS_MULTI(dict->mode)) {
+		if (dict->pos == dict->end)
+			dict->pos = 0;
+
+		memcpy(b->out + b->out_pos, dict->buf + dict->start,
+				copy_size);
+	}
+
+	dict->start = dict->pos;
+	b->out_pos += copy_size;
+	return copy_size;
+}
+
+/*****************
+ * Range decoder *
+ *****************/
+
+/* Reset the range decoder. */
+static void XZ_FUNC rc_reset(struct rc_dec *rc)
+{
+	rc->range = (uint32_t)-1;
+	rc->code = 0;
+	rc->init_bytes_left = RC_INIT_BYTES;
+}
+
+/*
+ * Read the first five initial bytes into rc->code if they haven't been
+ * read already. (Yes, the first byte gets completely ignored.)
+ */
+static bool XZ_FUNC rc_read_init(struct rc_dec *rc, struct xz_buf *b)
+{
+	while (rc->init_bytes_left > 0) {
+		if (b->in_pos == b->in_size)
+			return false;
+
+		rc->code = (rc->code << 8) + b->in[b->in_pos++];
+		--rc->init_bytes_left;
+	}
+
+	return true;
+}
+
+/* Return true if there may not be enough input for the next decoding loop. */
+static inline bool XZ_FUNC rc_limit_exceeded(const struct rc_dec *rc)
+{
+	return rc->in_pos > rc->in_limit;
+}
+
+/*
+ * Return true if it is possible (from point of view of range decoder) that
+ * we have reached the end of the LZMA chunk.
+ */
+static inline bool XZ_FUNC rc_is_finished(const struct rc_dec *rc)
+{
+	return rc->code == 0;
+}
+
+/* Read the next input byte if needed. */
+static __always_inline void XZ_FUNC rc_normalize(struct rc_dec *rc)
+{
+	if (rc->range < RC_TOP_VALUE) {
+		rc->range <<= RC_SHIFT_BITS;
+		rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++];
+	}
+}
+
+/*
+ * Decode one bit. In some versions, this function has been splitted in three
+ * functions so that the compiler is supposed to be able to more easily avoid
+ * an extra branch. In this particular version of the LZMA decoder, this
+ * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3
+ * on x86). Using a non-splitted version results in nicer looking code too.
+ *
+ * NOTE: This must return an int. Do not make it return a bool or the speed
+ * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care,
+ * and it generates 10-20 % faster code than GCC 3.x from this file anyway.)
+ */
+static __always_inline int XZ_FUNC rc_bit(struct rc_dec *rc, uint16_t *prob)
+{
+	uint32_t bound;
+	int bit;
+
+	rc_normalize(rc);
+	bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob;
+	if (rc->code < bound) {
+		rc->range = bound;
+		*prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS;
+		bit = 0;
+	} else {
+		rc->range -= bound;
+		rc->code -= bound;
+		*prob -= *prob >> RC_MOVE_BITS;
+		bit = 1;
+	}
+
+	return bit;
+}
+
+/* Decode a bittree starting from the most significant bit. */
+static __always_inline uint32_t XZ_FUNC rc_bittree(
+		struct rc_dec *rc, uint16_t *probs, uint32_t limit)
+{
+	uint32_t symbol = 1;
+
+	do {
+		if (rc_bit(rc, &probs[symbol]))
+			symbol = (symbol << 1) + 1;
+		else
+			symbol <<= 1;
+	} while (symbol < limit);
+
+	return symbol;
+}
+
+/* Decode a bittree starting from the least significant bit. */
+static __always_inline void XZ_FUNC rc_bittree_reverse(struct rc_dec *rc,
+		uint16_t *probs, uint32_t *dest, uint32_t limit)
+{
+	uint32_t symbol = 1;
+	uint32_t i = 0;
+
+	do {
+		if (rc_bit(rc, &probs[symbol])) {
+			symbol = (symbol << 1) + 1;
+			*dest += 1 << i;
+		} else {
+			symbol <<= 1;
+		}
+	} while (++i < limit);
+}
+
+/* Decode direct bits (fixed fifty-fifty probability) */
+static inline void XZ_FUNC rc_direct(
+		struct rc_dec *rc, uint32_t *dest, uint32_t limit)
+{
+	uint32_t mask;
+
+	do {
+		rc_normalize(rc);
+		rc->range >>= 1;
+		rc->code -= rc->range;
+		mask = (uint32_t)0 - (rc->code >> 31);
+		rc->code += rc->range & mask;
+		*dest = (*dest << 1) + (mask + 1);
+	} while (--limit > 0);
+}
+
+/********
+ * LZMA *
+ ********/
+
+/* Get pointer to literal coder probability array. */
+static uint16_t * XZ_FUNC lzma_literal_probs(struct xz_dec_lzma2 *s)
+{
+	uint32_t prev_byte = dict_get(&s->dict, 0);
+	uint32_t low = prev_byte >> (8 - s->lzma.lc);
+	uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc;
+	return s->lzma.literal[low + high];
+}
+
+/* Decode a literal (one 8-bit byte) */
+static void XZ_FUNC lzma_literal(struct xz_dec_lzma2 *s)
+{
+	uint16_t *probs;
+	uint32_t symbol;
+	uint32_t match_byte;
+	uint32_t match_bit;
+	uint32_t offset;
+	uint32_t i;
+
+	probs = lzma_literal_probs(s);
+
+	if (lzma_state_is_literal(s->lzma.state)) {
+		symbol = rc_bittree(&s->rc, probs, 0x100);
+	} else {
+		symbol = 1;
+		match_byte = dict_get(&s->dict, s->lzma.rep0) << 1;
+		offset = 0x100;
+
+		do {
+			match_bit = match_byte & offset;
+			match_byte <<= 1;
+			i = offset + match_bit + symbol;
+
+			if (rc_bit(&s->rc, &probs[i])) {
+				symbol = (symbol << 1) + 1;
+				offset &= match_bit;
+			} else {
+				symbol <<= 1;
+				offset &= ~match_bit;
+			}
+		} while (symbol < 0x100);
+	}
+
+	dict_put(&s->dict, (uint8_t)symbol);
+	lzma_state_literal(&s->lzma.state);
+}
+
+/* Decode the length of the match into s->lzma.len. */
+static void XZ_FUNC lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l,
+		uint32_t pos_state)
+{
+	uint16_t *probs;
+	uint32_t limit;
+
+	if (!rc_bit(&s->rc, &l->choice)) {
+		probs = l->low[pos_state];
+		limit = LEN_LOW_SYMBOLS;
+		s->lzma.len = MATCH_LEN_MIN;
+	} else {
+		if (!rc_bit(&s->rc, &l->choice2)) {
+			probs = l->mid[pos_state];
+			limit = LEN_MID_SYMBOLS;
+			s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS;
+		} else {
+			probs = l->high;
+			limit = LEN_HIGH_SYMBOLS;
+			s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS
+					+ LEN_MID_SYMBOLS;
+		}
+	}
+
+	s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit;
+}
+
+/* Decode a match. The distance will be stored in s->lzma.rep0. */
+static void XZ_FUNC lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
+{
+	uint16_t *probs;
+	uint32_t dist_slot;
+	uint32_t limit;
+
+	lzma_state_match(&s->lzma.state);
+
+	s->lzma.rep3 = s->lzma.rep2;
+	s->lzma.rep2 = s->lzma.rep1;
+	s->lzma.rep1 = s->lzma.rep0;
+
+	lzma_len(s, &s->lzma.match_len_dec, pos_state);
+
+	probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)];
+	dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS;
+
+	if (dist_slot < DIST_MODEL_START) {
+		s->lzma.rep0 = dist_slot;
+	} else {
+		limit = (dist_slot >> 1) - 1;
+		s->lzma.rep0 = 2 + (dist_slot & 1);
+
+		if (dist_slot < DIST_MODEL_END) {
+			s->lzma.rep0 <<= limit;
+			probs = s->lzma.dist_special + s->lzma.rep0
+					- dist_slot - 1;
+			rc_bittree_reverse(&s->rc, probs,
+					&s->lzma.rep0, limit);
+		} else {
+			rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS);
+			s->lzma.rep0 <<= ALIGN_BITS;
+			rc_bittree_reverse(&s->rc, s->lzma.dist_align,
+					&s->lzma.rep0, ALIGN_BITS);
+		}
+	}
+}
+
+/*
+ * Decode a repeated match. The distance is one of the four most recently
+ * seen matches. The distance will be stored in s->lzma.rep0.
+ */
+static void XZ_FUNC lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
+{
+	uint32_t tmp;
+
+	if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) {
+		if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[
+				s->lzma.state][pos_state])) {
+			lzma_state_short_rep(&s->lzma.state);
+			s->lzma.len = 1;
+			return;
+		}
+	} else {
+		if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) {
+			tmp = s->lzma.rep1;
+		} else {
+			if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) {
+				tmp = s->lzma.rep2;
+			} else {
+				tmp = s->lzma.rep3;
+				s->lzma.rep3 = s->lzma.rep2;
+			}
+
+			s->lzma.rep2 = s->lzma.rep1;
+		}
+
+		s->lzma.rep1 = s->lzma.rep0;
+		s->lzma.rep0 = tmp;
+	}
+
+	lzma_state_long_rep(&s->lzma.state);
+	lzma_len(s, &s->lzma.rep_len_dec, pos_state);
+}
+
+/* LZMA decoder core */
+static bool XZ_FUNC lzma_main(struct xz_dec_lzma2 *s)
+{
+	uint32_t pos_state;
+
+	/*
+	 * If the dictionary was reached during the previous call, try to
+	 * finish the possibly pending repeat in the dictionary.
+	 */
+	if (dict_has_space(&s->dict) && s->lzma.len > 0)
+		dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0);
+
+	/*
+	 * Decode more LZMA symbols. One iteration may consume up to
+	 * LZMA_IN_REQUIRED - 1 bytes.
+	 */
+	while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) {
+		pos_state = s->dict.pos & s->lzma.pos_mask;
+
+		if (!rc_bit(&s->rc, &s->lzma.is_match[
+				s->lzma.state][pos_state])) {
+			lzma_literal(s);
+		} else {
+			if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state]))
+				lzma_rep_match(s, pos_state);
+			else
+				lzma_match(s, pos_state);
+
+			if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0))
+				return false;
+		}
+	}
+
+	/*
+	 * Having the range decoder always normalized when we are outside
+	 * this function makes it easier to correctly handle end of the chunk.
+	 */
+	rc_normalize(&s->rc);
+
+	return true;
+}
+
+/*
+ * Reset the LZMA decoder and range decoder state. Dictionary is nore reset
+ * here, because LZMA state may be reset without resetting the dictionary.
+ */
+static void XZ_FUNC lzma_reset(struct xz_dec_lzma2 *s)
+{
+	uint16_t *probs;
+	size_t i;
+
+	s->lzma.state = STATE_LIT_LIT;
+	s->lzma.rep0 = 0;
+	s->lzma.rep1 = 0;
+	s->lzma.rep2 = 0;
+	s->lzma.rep3 = 0;
+
+	/*
+	 * All probabilities are initialized to the same value. This hack
+	 * makes the code smaller by avoiding a separate loop for each
+	 * probability array.
+	 *
+	 * This could be optimized so that only that part of literal
+	 * probabilities that are actually required. In the common case
+	 * we would write 12 KiB less.
+	 */
+	probs = s->lzma.is_match[0];
+	for (i = 0; i < PROBS_TOTAL; ++i)
+		probs[i] = RC_BIT_MODEL_TOTAL / 2;
+
+	rc_reset(&s->rc);
+}
+
+/*
+ * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks
+ * from the decoded lp and pb values. On success, the LZMA decoder state is
+ * reset and true is returned.
+ */
+static bool XZ_FUNC lzma_props(struct xz_dec_lzma2 *s, uint8_t props)
+{
+	if (props > (4 * 5 + 4) * 9 + 8)
+		return false;
+
+	s->lzma.pos_mask = 0;
+	while (props >= 9 * 5) {
+		props -= 9 * 5;
+		++s->lzma.pos_mask;
+	}
+
+	s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1;
+
+	s->lzma.literal_pos_mask = 0;
+	while (props >= 9) {
+		props -= 9;
+		++s->lzma.literal_pos_mask;
+	}
+
+	s->lzma.lc = props;
+
+	if (s->lzma.lc + s->lzma.literal_pos_mask > 4)
+		return false;
+
+	s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1;
+
+	lzma_reset(s);
+
+	return true;
+}
+
+/*********
+ * LZMA2 *
+ *********/
+
+/*
+ * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't
+ * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This
+ * wrapper function takes care of making the LZMA decoder's assumption safe.
+ *
+ * As long as there is plenty of input left to be decoded in the current LZMA
+ * chunk, we decode directly from the caller-supplied input buffer until
+ * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into
+ * s->temp.buf, which (hopefully) gets filled on the next call to this
+ * function. We decode a few bytes from the temporary buffer so that we can
+ * continue decoding from the caller-supplied input buffer again.
+ */
+static bool XZ_FUNC lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b)
+{
+	size_t in_avail;
+	uint32_t tmp;
+
+	in_avail = b->in_size - b->in_pos;
+	if (s->temp.size > 0 || s->lzma2.compressed == 0) {
+		tmp = 2 * LZMA_IN_REQUIRED - s->temp.size;
+		if (tmp > s->lzma2.compressed - s->temp.size)
+			tmp = s->lzma2.compressed - s->temp.size;
+		if (tmp > in_avail)
+			tmp = in_avail;
+
+		memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp);
+
+		if (s->temp.size + tmp == s->lzma2.compressed) {
+			memzero(s->temp.buf + s->temp.size + tmp,
+					sizeof(s->temp.buf)
+						- s->temp.size - tmp);
+			s->rc.in_limit = s->temp.size + tmp;
+		} else if (s->temp.size + tmp < LZMA_IN_REQUIRED) {
+			s->temp.size += tmp;
+			b->in_pos += tmp;
+			return true;
+		} else {
+			s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED;
+		}
+
+		s->rc.in = s->temp.buf;
+		s->rc.in_pos = 0;
+
+		if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp)
+			return false;
+
+		s->lzma2.compressed -= s->rc.in_pos;
+
+		if (s->rc.in_pos < s->temp.size) {
+			s->temp.size -= s->rc.in_pos;
+			memmove(s->temp.buf, s->temp.buf + s->rc.in_pos,
+					s->temp.size);
+			return true;
+		}
+
+		b->in_pos += s->rc.in_pos - s->temp.size;
+		s->temp.size = 0;
+	}
+
+	in_avail = b->in_size - b->in_pos;
+	if (in_avail >= LZMA_IN_REQUIRED) {
+		s->rc.in = b->in;
+		s->rc.in_pos = b->in_pos;
+
+		if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED)
+			s->rc.in_limit = b->in_pos + s->lzma2.compressed;
+		else
+			s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED;
+
+		if (!lzma_main(s))
+			return false;
+
+		in_avail = s->rc.in_pos - b->in_pos;
+		if (in_avail > s->lzma2.compressed)
+			return false;
+
+		s->lzma2.compressed -= in_avail;
+		b->in_pos = s->rc.in_pos;
+	}
+
+	in_avail = b->in_size - b->in_pos;
+	if (in_avail < LZMA_IN_REQUIRED) {
+		if (in_avail > s->lzma2.compressed)
+			in_avail = s->lzma2.compressed;
+
+		memcpy(s->temp.buf, b->in + b->in_pos, in_avail);
+		s->temp.size = in_avail;
+		b->in_pos += in_avail;
+	}
+
+	return true;
+}
+
+/*
+ * Take care of the LZMA2 control layer, and forward the job of actual LZMA
+ * decoding or copying of uncompressed chunks to other functions.
+ */
+XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run(
+		struct xz_dec_lzma2 *s, struct xz_buf *b)
+{
+	uint32_t tmp;
+
+	while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) {
+		switch (s->lzma2.sequence) {
+		case SEQ_CONTROL:
+			/*
+			 * LZMA2 control byte
+			 *
+			 * Exact values:
+			 *   0x00   End marker
+			 *   0x01   Dictionary reset followed by
+			 *          an uncompressed chunk
+			 *   0x02   Uncompressed chunk (no dictionary reset)
+			 *
+			 * Highest three bits (s->control & 0xE0):
+			 *   0xE0   Dictionary reset, new properties and state
+			 *          reset, followed by LZMA compressed chunk
+			 *   0xC0   New properties and state reset, followed
+			 *          by LZMA compressed chunk (no dictionary
+			 *          reset)
+			 *   0xA0   State reset using old properties,
+			 *          followed by LZMA compressed chunk (no
+			 *          dictionary reset)
+			 *   0x80   LZMA chunk (no dictionary or state reset)
+			 *
+			 * For LZMA compressed chunks, the lowest five bits
+			 * (s->control & 1F) are the highest bits of the
+			 * uncompressed size (bits 16-20).
+			 *
+			 * A new LZMA2 stream must begin with a dictionary
+			 * reset. The first LZMA chunk must set new
+			 * properties and reset the LZMA state.
+			 *
+			 * Values that don't match anything described above
+			 * are invalid and we return XZ_DATA_ERROR.
+			 */
+			tmp = b->in[b->in_pos++];
+
+			if (tmp >= 0xE0 || tmp == 0x01) {
+				s->lzma2.need_props = true;
+				s->lzma2.need_dict_reset = false;
+				dict_reset(&s->dict, b);
+			} else if (s->lzma2.need_dict_reset) {
+				return XZ_DATA_ERROR;
+			}
+
+			if (tmp >= 0x80) {
+				s->lzma2.uncompressed = (tmp & 0x1F) << 16;
+				s->lzma2.sequence = SEQ_UNCOMPRESSED_1;
+
+				if (tmp >= 0xC0) {
+					/*
+					 * When there are new properties,
+					 * state reset is done at
+					 * SEQ_PROPERTIES.
+					 */
+					s->lzma2.need_props = false;
+					s->lzma2.next_sequence
+							= SEQ_PROPERTIES;
+
+				} else if (s->lzma2.need_props) {
+					return XZ_DATA_ERROR;
+
+				} else {
+					s->lzma2.next_sequence
+							= SEQ_LZMA_PREPARE;
+					if (tmp >= 0xA0)
+						lzma_reset(s);
+				}
+			} else {
+				if (tmp == 0x00)
+					return XZ_STREAM_END;
+
+				if (tmp > 0x02)
+					return XZ_DATA_ERROR;
+
+				s->lzma2.sequence = SEQ_COMPRESSED_0;
+				s->lzma2.next_sequence = SEQ_COPY;
+			}
+
+			break;
+
+		case SEQ_UNCOMPRESSED_1:
+			s->lzma2.uncompressed
+					+= (uint32_t)b->in[b->in_pos++] << 8;
+			s->lzma2.sequence = SEQ_UNCOMPRESSED_2;
+			break;
+
+		case SEQ_UNCOMPRESSED_2:
+			s->lzma2.uncompressed
+					+= (uint32_t)b->in[b->in_pos++] + 1;
+			s->lzma2.sequence = SEQ_COMPRESSED_0;
+			break;
+
+		case SEQ_COMPRESSED_0:
+			s->lzma2.compressed
+					= (uint32_t)b->in[b->in_pos++] << 8;
+			s->lzma2.sequence = SEQ_COMPRESSED_1;
+			break;
+
+		case SEQ_COMPRESSED_1:
+			s->lzma2.compressed
+					+= (uint32_t)b->in[b->in_pos++] + 1;
+			s->lzma2.sequence = s->lzma2.next_sequence;
+			break;
+
+		case SEQ_PROPERTIES:
+			if (!lzma_props(s, b->in[b->in_pos++]))
+				return XZ_DATA_ERROR;
+
+			s->lzma2.sequence = SEQ_LZMA_PREPARE;
+
+		case SEQ_LZMA_PREPARE:
+			if (s->lzma2.compressed < RC_INIT_BYTES)
+				return XZ_DATA_ERROR;
+
+			if (!rc_read_init(&s->rc, b))
+				return XZ_OK;
+
+			s->lzma2.compressed -= RC_INIT_BYTES;
+			s->lzma2.sequence = SEQ_LZMA_RUN;
+
+		case SEQ_LZMA_RUN:
+			/*
+			 * Set dictionary limit to indicate how much we want
+			 * to be encoded at maximum. Decode new data into the
+			 * dictionary. Flush the new data from dictionary to
+			 * b->out. Check if we finished decoding this chunk.
+			 * In case the dictionary got full but we didn't fill
+			 * the output buffer yet, we may run this loop
+			 * multiple times without changing s->lzma2.sequence.
+			 */
+			dict_limit(&s->dict, min_t(size_t,
+					b->out_size - b->out_pos,
+					s->lzma2.uncompressed));
+			if (!lzma2_lzma(s, b))
+				return XZ_DATA_ERROR;
+
+			s->lzma2.uncompressed -= dict_flush(&s->dict, b);
+
+			if (s->lzma2.uncompressed == 0) {
+				if (s->lzma2.compressed > 0 || s->lzma.len > 0
+						|| !rc_is_finished(&s->rc))
+					return XZ_DATA_ERROR;
+
+				rc_reset(&s->rc);
+				s->lzma2.sequence = SEQ_CONTROL;
+
+			} else if (b->out_pos == b->out_size
+					|| (b->in_pos == b->in_size
+						&& s->temp.size
+						< s->lzma2.compressed)) {
+				return XZ_OK;
+			}
+
+			break;
+
+		case SEQ_COPY:
+			dict_uncompressed(&s->dict, b, &s->lzma2.compressed);
+			if (s->lzma2.compressed > 0)
+				return XZ_OK;
+
+			s->lzma2.sequence = SEQ_CONTROL;
+			break;
+		}
+	}
+
+	return XZ_OK;
+}
+
+XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create(
+		enum xz_mode mode, uint32_t dict_max)
+{
+	struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (s == NULL)
+		return NULL;
+
+	s->dict.mode = mode;
+	s->dict.size_max = dict_max;
+
+	if (DEC_IS_PREALLOC(mode)) {
+		s->dict.buf = vmalloc(dict_max);
+		if (s->dict.buf == NULL) {
+			kfree(s);
+			return NULL;
+		}
+	} else if (DEC_IS_DYNALLOC(mode)) {
+		s->dict.buf = NULL;
+		s->dict.allocated = 0;
+	}
+
+	return s;
+}
+
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset(
+		struct xz_dec_lzma2 *s, uint8_t props)
+{
+	/* This limits dictionary size to 3 GiB to keep parsing simpler. */
+	if (props > 39)
+		return XZ_OPTIONS_ERROR;
+
+	s->dict.size = 2 + (props & 1);
+	s->dict.size <<= (props >> 1) + 11;
+
+	if (DEC_IS_MULTI(s->dict.mode)) {
+		if (s->dict.size > s->dict.size_max)
+			return XZ_MEMLIMIT_ERROR;
+
+		s->dict.end = s->dict.size;
+
+		if (DEC_IS_DYNALLOC(s->dict.mode)) {
+			if (s->dict.allocated < s->dict.size) {
+				vfree(s->dict.buf);
+				s->dict.buf = vmalloc(s->dict.size);
+				if (s->dict.buf == NULL) {
+					s->dict.allocated = 0;
+					return XZ_MEM_ERROR;
+				}
+			}
+		}
+	}
+
+	s->lzma.len = 0;
+
+	s->lzma2.sequence = SEQ_CONTROL;
+	s->lzma2.need_dict_reset = true;
+
+	s->temp.size = 0;
+
+	return XZ_OK;
+}
+
+XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s)
+{
+	if (DEC_IS_MULTI(s->dict.mode))
+		vfree(s->dict.buf);
+
+	kfree(s);
+}
diff --git a/ap/app/busybox/src/archival/libarchive/unxz/xz_dec_stream.c b/ap/app/busybox/src/archival/libarchive/unxz/xz_dec_stream.c
new file mode 100644
index 0000000..bdcbf1b
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/unxz/xz_dec_stream.c
@@ -0,0 +1,822 @@
+/*
+ * .xz Stream decoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+#include "xz_stream.h"
+
+/* Hash used to validate the Index field */
+struct xz_dec_hash {
+	vli_type unpadded;
+	vli_type uncompressed;
+	uint32_t crc32;
+};
+
+struct xz_dec {
+	/* Position in dec_main() */
+	enum {
+		SEQ_STREAM_HEADER,
+		SEQ_BLOCK_START,
+		SEQ_BLOCK_HEADER,
+		SEQ_BLOCK_UNCOMPRESS,
+		SEQ_BLOCK_PADDING,
+		SEQ_BLOCK_CHECK,
+		SEQ_INDEX,
+		SEQ_INDEX_PADDING,
+		SEQ_INDEX_CRC32,
+		SEQ_STREAM_FOOTER
+	} sequence;
+
+	/* Position in variable-length integers and Check fields */
+	uint32_t pos;
+
+	/* Variable-length integer decoded by dec_vli() */
+	vli_type vli;
+
+	/* Saved in_pos and out_pos */
+	size_t in_start;
+	size_t out_start;
+
+	/* CRC32 value in Block or Index */
+	uint32_t crc32;
+
+	/* Type of the integrity check calculated from uncompressed data */
+	enum xz_check check_type;
+
+	/* Operation mode */
+	enum xz_mode mode;
+
+	/*
+	 * True if the next call to xz_dec_run() is allowed to return
+	 * XZ_BUF_ERROR.
+	 */
+	bool allow_buf_error;
+
+	/* Information stored in Block Header */
+	struct {
+		/*
+		 * Value stored in the Compressed Size field, or
+		 * VLI_UNKNOWN if Compressed Size is not present.
+		 */
+		vli_type compressed;
+
+		/*
+		 * Value stored in the Uncompressed Size field, or
+		 * VLI_UNKNOWN if Uncompressed Size is not present.
+		 */
+		vli_type uncompressed;
+
+		/* Size of the Block Header field */
+		uint32_t size;
+	} block_header;
+
+	/* Information collected when decoding Blocks */
+	struct {
+		/* Observed compressed size of the current Block */
+		vli_type compressed;
+
+		/* Observed uncompressed size of the current Block */
+		vli_type uncompressed;
+
+		/* Number of Blocks decoded so far */
+		vli_type count;
+
+		/*
+		 * Hash calculated from the Block sizes. This is used to
+		 * validate the Index field.
+		 */
+		struct xz_dec_hash hash;
+	} block;
+
+	/* Variables needed when verifying the Index field */
+	struct {
+		/* Position in dec_index() */
+		enum {
+			SEQ_INDEX_COUNT,
+			SEQ_INDEX_UNPADDED,
+			SEQ_INDEX_UNCOMPRESSED
+		} sequence;
+
+		/* Size of the Index in bytes */
+		vli_type size;
+
+		/* Number of Records (matches block.count in valid files) */
+		vli_type count;
+
+		/*
+		 * Hash calculated from the Records (matches block.hash in
+		 * valid files).
+		 */
+		struct xz_dec_hash hash;
+	} index;
+
+	/*
+	 * Temporary buffer needed to hold Stream Header, Block Header,
+	 * and Stream Footer. The Block Header is the biggest (1 KiB)
+	 * so we reserve space according to that. buf[] has to be aligned
+	 * to a multiple of four bytes; the size_t variables before it
+	 * should guarantee this.
+	 */
+	struct {
+		size_t pos;
+		size_t size;
+		uint8_t buf[1024];
+	} temp;
+
+	struct xz_dec_lzma2 *lzma2;
+
+#ifdef XZ_DEC_BCJ
+	struct xz_dec_bcj *bcj;
+	bool bcj_active;
+#endif
+};
+
+#ifdef XZ_DEC_ANY_CHECK
+/* Sizes of the Check field with different Check IDs */
+static const uint8_t check_sizes[16] = {
+	0,
+	4, 4, 4,
+	8, 8, 8,
+	16, 16, 16,
+	32, 32, 32,
+	64, 64, 64
+};
+#endif
+
+/*
+ * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
+ * must have set s->temp.pos to indicate how much data we are supposed
+ * to copy into s->temp.buf. Return true once s->temp.pos has reached
+ * s->temp.size.
+ */
+static bool XZ_FUNC fill_temp(struct xz_dec *s, struct xz_buf *b)
+{
+	size_t copy_size = min_t(size_t,
+			b->in_size - b->in_pos, s->temp.size - s->temp.pos);
+
+	memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
+	b->in_pos += copy_size;
+	s->temp.pos += copy_size;
+
+	if (s->temp.pos == s->temp.size) {
+		s->temp.pos = 0;
+		return true;
+	}
+
+	return false;
+}
+
+/* Decode a variable-length integer (little-endian base-128 encoding) */
+static enum xz_ret XZ_FUNC dec_vli(struct xz_dec *s,
+		const uint8_t *in, size_t *in_pos, size_t in_size)
+{
+	uint8_t byte;
+
+	if (s->pos == 0)
+		s->vli = 0;
+
+	while (*in_pos < in_size) {
+		byte = in[*in_pos];
+		++*in_pos;
+
+		s->vli |= (vli_type)(byte & 0x7F) << s->pos;
+
+		if ((byte & 0x80) == 0) {
+			/* Don't allow non-minimal encodings. */
+			if (byte == 0 && s->pos != 0)
+				return XZ_DATA_ERROR;
+
+			s->pos = 0;
+			return XZ_STREAM_END;
+		}
+
+		s->pos += 7;
+		if (s->pos == 7 * VLI_BYTES_MAX)
+			return XZ_DATA_ERROR;
+	}
+
+	return XZ_OK;
+}
+
+/*
+ * Decode the Compressed Data field from a Block. Update and validate
+ * the observed compressed and uncompressed sizes of the Block so that
+ * they don't exceed the values possibly stored in the Block Header
+ * (validation assumes that no integer overflow occurs, since vli_type
+ * is normally uint64_t). Update the CRC32 if presence of the CRC32
+ * field was indicated in Stream Header.
+ *
+ * Once the decoding is finished, validate that the observed sizes match
+ * the sizes possibly stored in the Block Header. Update the hash and
+ * Block count, which are later used to validate the Index field.
+ */
+static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b)
+{
+	enum xz_ret ret;
+
+	s->in_start = b->in_pos;
+	s->out_start = b->out_pos;
+
+#ifdef XZ_DEC_BCJ
+	if (s->bcj_active)
+		ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
+	else
+#endif
+		ret = xz_dec_lzma2_run(s->lzma2, b);
+
+	s->block.compressed += b->in_pos - s->in_start;
+	s->block.uncompressed += b->out_pos - s->out_start;
+
+	/*
+	 * There is no need to separately check for VLI_UNKNOWN, since
+	 * the observed sizes are always smaller than VLI_UNKNOWN.
+	 */
+	if (s->block.compressed > s->block_header.compressed
+			|| s->block.uncompressed
+				> s->block_header.uncompressed)
+		return XZ_DATA_ERROR;
+
+	if (s->check_type == XZ_CHECK_CRC32)
+		s->crc32 = xz_crc32(b->out + s->out_start,
+				b->out_pos - s->out_start, s->crc32);
+
+	if (ret == XZ_STREAM_END) {
+		if (s->block_header.compressed != VLI_UNKNOWN
+				&& s->block_header.compressed
+					!= s->block.compressed)
+			return XZ_DATA_ERROR;
+
+		if (s->block_header.uncompressed != VLI_UNKNOWN
+				&& s->block_header.uncompressed
+					!= s->block.uncompressed)
+			return XZ_DATA_ERROR;
+
+		s->block.hash.unpadded += s->block_header.size
+				+ s->block.compressed;
+
+#ifdef XZ_DEC_ANY_CHECK
+		s->block.hash.unpadded += check_sizes[s->check_type];
+#else
+		if (s->check_type == XZ_CHECK_CRC32)
+			s->block.hash.unpadded += 4;
+#endif
+
+		s->block.hash.uncompressed += s->block.uncompressed;
+		s->block.hash.crc32 = xz_crc32(
+				(const uint8_t *)&s->block.hash,
+				sizeof(s->block.hash), s->block.hash.crc32);
+
+		++s->block.count;
+	}
+
+	return ret;
+}
+
+/* Update the Index size and the CRC32 value. */
+static void XZ_FUNC index_update(struct xz_dec *s, const struct xz_buf *b)
+{
+	size_t in_used = b->in_pos - s->in_start;
+	s->index.size += in_used;
+	s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32);
+}
+
+/*
+ * Decode the Number of Records, Unpadded Size, and Uncompressed Size
+ * fields from the Index field. That is, Index Padding and CRC32 are not
+ * decoded by this function.
+ *
+ * This can return XZ_OK (more input needed), XZ_STREAM_END (everything
+ * successfully decoded), or XZ_DATA_ERROR (input is corrupt).
+ */
+static enum xz_ret XZ_FUNC dec_index(struct xz_dec *s, struct xz_buf *b)
+{
+	enum xz_ret ret;
+
+	do {
+		ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
+		if (ret != XZ_STREAM_END) {
+			index_update(s, b);
+			return ret;
+		}
+
+		switch (s->index.sequence) {
+		case SEQ_INDEX_COUNT:
+			s->index.count = s->vli;
+
+			/*
+			 * Validate that the Number of Records field
+			 * indicates the same number of Records as
+			 * there were Blocks in the Stream.
+			 */
+			if (s->index.count != s->block.count)
+				return XZ_DATA_ERROR;
+
+			s->index.sequence = SEQ_INDEX_UNPADDED;
+			break;
+
+		case SEQ_INDEX_UNPADDED:
+			s->index.hash.unpadded += s->vli;
+			s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
+			break;
+
+		case SEQ_INDEX_UNCOMPRESSED:
+			s->index.hash.uncompressed += s->vli;
+			s->index.hash.crc32 = xz_crc32(
+					(const uint8_t *)&s->index.hash,
+					sizeof(s->index.hash),
+					s->index.hash.crc32);
+			--s->index.count;
+			s->index.sequence = SEQ_INDEX_UNPADDED;
+			break;
+		}
+	} while (s->index.count > 0);
+
+	return XZ_STREAM_END;
+}
+
+/*
+ * Validate that the next four input bytes match the value of s->crc32.
+ * s->pos must be zero when starting to validate the first byte.
+ */
+static enum xz_ret XZ_FUNC crc32_validate(struct xz_dec *s, struct xz_buf *b)
+{
+	do {
+		if (b->in_pos == b->in_size)
+			return XZ_OK;
+
+		if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++])
+			return XZ_DATA_ERROR;
+
+		s->pos += 8;
+
+	} while (s->pos < 32);
+
+	s->crc32 = 0;
+	s->pos = 0;
+
+	return XZ_STREAM_END;
+}
+
+#ifdef XZ_DEC_ANY_CHECK
+/*
+ * Skip over the Check field when the Check ID is not supported.
+ * Returns true once the whole Check field has been skipped over.
+ */
+static bool XZ_FUNC check_skip(struct xz_dec *s, struct xz_buf *b)
+{
+	while (s->pos < check_sizes[s->check_type]) {
+		if (b->in_pos == b->in_size)
+			return false;
+
+		++b->in_pos;
+		++s->pos;
+	}
+
+	s->pos = 0;
+
+	return true;
+}
+#endif
+
+/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
+static enum xz_ret XZ_FUNC dec_stream_header(struct xz_dec *s)
+{
+	if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
+		return XZ_FORMAT_ERROR;
+
+	if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
+			!= get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
+		return XZ_DATA_ERROR;
+
+	if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
+		return XZ_OPTIONS_ERROR;
+
+	/*
+	 * Of integrity checks, we support only none (Check ID = 0) and
+	 * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined,
+	 * we will accept other check types too, but then the check won't
+	 * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given.
+	 */
+	s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
+
+#ifdef XZ_DEC_ANY_CHECK
+	if (s->check_type > XZ_CHECK_MAX)
+		return XZ_OPTIONS_ERROR;
+
+	if (s->check_type > XZ_CHECK_CRC32)
+		return XZ_UNSUPPORTED_CHECK;
+#else
+	if (s->check_type > XZ_CHECK_CRC32)
+		return XZ_OPTIONS_ERROR;
+#endif
+
+	return XZ_OK;
+}
+
+/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
+static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s)
+{
+	if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
+		return XZ_DATA_ERROR;
+
+	if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
+		return XZ_DATA_ERROR;
+
+	/*
+	 * Validate Backward Size. Note that we never added the size of the
+	 * Index CRC32 field to s->index.size, thus we use s->index.size / 4
+	 * instead of s->index.size / 4 - 1.
+	 */
+	if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
+		return XZ_DATA_ERROR;
+
+	if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
+		return XZ_DATA_ERROR;
+
+	/*
+	 * Use XZ_STREAM_END instead of XZ_OK to be more convenient
+	 * for the caller.
+	 */
+	return XZ_STREAM_END;
+}
+
+/* Decode the Block Header and initialize the filter chain. */
+static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s)
+{
+	enum xz_ret ret;
+
+	/*
+	 * Validate the CRC32. We know that the temp buffer is at least
+	 * eight bytes so this is safe.
+	 */
+	s->temp.size -= 4;
+	if (xz_crc32(s->temp.buf, s->temp.size, 0)
+			!= get_le32(s->temp.buf + s->temp.size))
+		return XZ_DATA_ERROR;
+
+	s->temp.pos = 2;
+
+	/*
+	 * Catch unsupported Block Flags. We support only one or two filters
+	 * in the chain, so we catch that with the same test.
+	 */
+#ifdef XZ_DEC_BCJ
+	if (s->temp.buf[1] & 0x3E)
+#else
+	if (s->temp.buf[1] & 0x3F)
+#endif
+		return XZ_OPTIONS_ERROR;
+
+	/* Compressed Size */
+	if (s->temp.buf[1] & 0x40) {
+		if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
+					!= XZ_STREAM_END)
+			return XZ_DATA_ERROR;
+
+		s->block_header.compressed = s->vli;
+	} else {
+		s->block_header.compressed = VLI_UNKNOWN;
+	}
+
+	/* Uncompressed Size */
+	if (s->temp.buf[1] & 0x80) {
+		if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
+				!= XZ_STREAM_END)
+			return XZ_DATA_ERROR;
+
+		s->block_header.uncompressed = s->vli;
+	} else {
+		s->block_header.uncompressed = VLI_UNKNOWN;
+	}
+
+#ifdef XZ_DEC_BCJ
+	/* If there are two filters, the first one must be a BCJ filter. */
+	s->bcj_active = s->temp.buf[1] & 0x01;
+	if (s->bcj_active) {
+		if (s->temp.size - s->temp.pos < 2)
+			return XZ_OPTIONS_ERROR;
+
+		ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
+		if (ret != XZ_OK)
+			return ret;
+
+		/*
+		 * We don't support custom start offset,
+		 * so Size of Properties must be zero.
+		 */
+		if (s->temp.buf[s->temp.pos++] != 0x00)
+			return XZ_OPTIONS_ERROR;
+	}
+#endif
+
+	/* Valid Filter Flags always take at least two bytes. */
+	if (s->temp.size - s->temp.pos < 2)
+		return XZ_DATA_ERROR;
+
+	/* Filter ID = LZMA2 */
+	if (s->temp.buf[s->temp.pos++] != 0x21)
+		return XZ_OPTIONS_ERROR;
+
+	/* Size of Properties = 1-byte Filter Properties */
+	if (s->temp.buf[s->temp.pos++] != 0x01)
+		return XZ_OPTIONS_ERROR;
+
+	/* Filter Properties contains LZMA2 dictionary size. */
+	if (s->temp.size - s->temp.pos < 1)
+		return XZ_DATA_ERROR;
+
+	ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
+	if (ret != XZ_OK)
+		return ret;
+
+	/* The rest must be Header Padding. */
+	while (s->temp.pos < s->temp.size)
+		if (s->temp.buf[s->temp.pos++] != 0x00)
+			return XZ_OPTIONS_ERROR;
+
+	s->temp.pos = 0;
+	s->block.compressed = 0;
+	s->block.uncompressed = 0;
+
+	return XZ_OK;
+}
+
+static enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b)
+{
+	enum xz_ret ret;
+
+	/*
+	 * Store the start position for the case when we are in the middle
+	 * of the Index field.
+	 */
+	s->in_start = b->in_pos;
+
+	while (true) {
+		switch (s->sequence) {
+		case SEQ_STREAM_HEADER:
+			/*
+			 * Stream Header is copied to s->temp, and then
+			 * decoded from there. This way if the caller
+			 * gives us only little input at a time, we can
+			 * still keep the Stream Header decoding code
+			 * simple. Similar approach is used in many places
+			 * in this file.
+			 */
+			if (!fill_temp(s, b))
+				return XZ_OK;
+
+			/*
+			 * If dec_stream_header() returns
+			 * XZ_UNSUPPORTED_CHECK, it is still possible
+			 * to continue decoding if working in multi-call
+			 * mode. Thus, update s->sequence before calling
+			 * dec_stream_header().
+			 */
+			s->sequence = SEQ_BLOCK_START;
+
+			ret = dec_stream_header(s);
+			if (ret != XZ_OK)
+				return ret;
+
+		case SEQ_BLOCK_START:
+			/* We need one byte of input to continue. */
+			if (b->in_pos == b->in_size)
+				return XZ_OK;
+
+			/* See if this is the beginning of the Index field. */
+			if (b->in[b->in_pos] == 0) {
+				s->in_start = b->in_pos++;
+				s->sequence = SEQ_INDEX;
+				break;
+			}
+
+			/*
+			 * Calculate the size of the Block Header and
+			 * prepare to decode it.
+			 */
+			s->block_header.size
+				= ((uint32_t)b->in[b->in_pos] + 1) * 4;
+
+			s->temp.size = s->block_header.size;
+			s->temp.pos = 0;
+			s->sequence = SEQ_BLOCK_HEADER;
+
+		case SEQ_BLOCK_HEADER:
+			if (!fill_temp(s, b))
+				return XZ_OK;
+
+			ret = dec_block_header(s);
+			if (ret != XZ_OK)
+				return ret;
+
+			s->sequence = SEQ_BLOCK_UNCOMPRESS;
+
+		case SEQ_BLOCK_UNCOMPRESS:
+			ret = dec_block(s, b);
+			if (ret != XZ_STREAM_END)
+				return ret;
+
+			s->sequence = SEQ_BLOCK_PADDING;
+
+		case SEQ_BLOCK_PADDING:
+			/*
+			 * Size of Compressed Data + Block Padding
+			 * must be a multiple of four. We don't need
+			 * s->block.compressed for anything else
+			 * anymore, so we use it here to test the size
+			 * of the Block Padding field.
+			 */
+			while (s->block.compressed & 3) {
+				if (b->in_pos == b->in_size)
+					return XZ_OK;
+
+				if (b->in[b->in_pos++] != 0)
+					return XZ_DATA_ERROR;
+
+				++s->block.compressed;
+			}
+
+			s->sequence = SEQ_BLOCK_CHECK;
+
+		case SEQ_BLOCK_CHECK:
+			if (s->check_type == XZ_CHECK_CRC32) {
+				ret = crc32_validate(s, b);
+				if (ret != XZ_STREAM_END)
+					return ret;
+			}
+#ifdef XZ_DEC_ANY_CHECK
+			else if (!check_skip(s, b)) {
+				return XZ_OK;
+			}
+#endif
+
+			s->sequence = SEQ_BLOCK_START;
+			break;
+
+		case SEQ_INDEX:
+			ret = dec_index(s, b);
+			if (ret != XZ_STREAM_END)
+				return ret;
+
+			s->sequence = SEQ_INDEX_PADDING;
+
+		case SEQ_INDEX_PADDING:
+			while ((s->index.size + (b->in_pos - s->in_start))
+					& 3) {
+				if (b->in_pos == b->in_size) {
+					index_update(s, b);
+					return XZ_OK;
+				}
+
+				if (b->in[b->in_pos++] != 0)
+					return XZ_DATA_ERROR;
+			}
+
+			/* Finish the CRC32 value and Index size. */
+			index_update(s, b);
+
+			/* Compare the hashes to validate the Index field. */
+			if (!memeq(&s->block.hash, &s->index.hash,
+					sizeof(s->block.hash)))
+				return XZ_DATA_ERROR;
+
+			s->sequence = SEQ_INDEX_CRC32;
+
+		case SEQ_INDEX_CRC32:
+			ret = crc32_validate(s, b);
+			if (ret != XZ_STREAM_END)
+				return ret;
+
+			s->temp.size = STREAM_HEADER_SIZE;
+			s->sequence = SEQ_STREAM_FOOTER;
+
+		case SEQ_STREAM_FOOTER:
+			if (!fill_temp(s, b))
+				return XZ_OK;
+
+			return dec_stream_footer(s);
+		}
+	}
+
+	/* Never reached */
+}
+
+/*
+ * xz_dec_run() is a wrapper for dec_main() to handle some special cases in
+ * multi-call and single-call decoding.
+ *
+ * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
+ * are not going to make any progress anymore. This is to prevent the caller
+ * from calling us infinitely when the input file is truncated or otherwise
+ * corrupt. Since zlib-style API allows that the caller fills the input buffer
+ * only when the decoder doesn't produce any new output, we have to be careful
+ * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
+ * after the second consecutive call to xz_dec_run() that makes no progress.
+ *
+ * In single-call mode, if we couldn't decode everything and no error
+ * occurred, either the input is truncated or the output buffer is too small.
+ * Since we know that the last input byte never produces any output, we know
+ * that if all the input was consumed and decoding wasn't finished, the file
+ * must be corrupt. Otherwise the output buffer has to be too small or the
+ * file is corrupt in a way that decoding it produces too big output.
+ *
+ * If single-call decoding fails, we reset b->in_pos and b->out_pos back to
+ * their original values. This is because with some filter chains there won't
+ * be any valid uncompressed data in the output buffer unless the decoding
+ * actually succeeds (that's the price to pay of using the output buffer as
+ * the workspace).
+ */
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b)
+{
+	size_t in_start;
+	size_t out_start;
+	enum xz_ret ret;
+
+	if (DEC_IS_SINGLE(s->mode))
+		xz_dec_reset(s);
+
+	in_start = b->in_pos;
+	out_start = b->out_pos;
+	ret = dec_main(s, b);
+
+	if (DEC_IS_SINGLE(s->mode)) {
+		if (ret == XZ_OK)
+			ret = b->in_pos == b->in_size
+					? XZ_DATA_ERROR : XZ_BUF_ERROR;
+
+		if (ret != XZ_STREAM_END) {
+			b->in_pos = in_start;
+			b->out_pos = out_start;
+		}
+
+	} else if (ret == XZ_OK && in_start == b->in_pos
+			&& out_start == b->out_pos) {
+		if (s->allow_buf_error)
+			ret = XZ_BUF_ERROR;
+
+		s->allow_buf_error = true;
+	} else {
+		s->allow_buf_error = false;
+	}
+
+	return ret;
+}
+
+XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(
+		enum xz_mode mode, uint32_t dict_max)
+{
+	struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (s == NULL)
+		return NULL;
+
+	s->mode = mode;
+
+#ifdef XZ_DEC_BCJ
+	s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
+	if (s->bcj == NULL)
+		goto error_bcj;
+#endif
+
+	s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
+	if (s->lzma2 == NULL)
+		goto error_lzma2;
+
+	xz_dec_reset(s);
+	return s;
+
+error_lzma2:
+#ifdef XZ_DEC_BCJ
+	xz_dec_bcj_end(s->bcj);
+error_bcj:
+#endif
+	kfree(s);
+	return NULL;
+}
+
+XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s)
+{
+	s->sequence = SEQ_STREAM_HEADER;
+	s->allow_buf_error = false;
+	s->pos = 0;
+	s->crc32 = 0;
+	memzero(&s->block, sizeof(s->block));
+	memzero(&s->index, sizeof(s->index));
+	s->temp.pos = 0;
+	s->temp.size = STREAM_HEADER_SIZE;
+}
+
+XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s)
+{
+	if (s != NULL) {
+		xz_dec_lzma2_end(s->lzma2);
+#ifdef XZ_DEC_BCJ
+		xz_dec_bcj_end(s->bcj);
+#endif
+		kfree(s);
+	}
+}
diff --git a/ap/app/busybox/src/archival/libarchive/unxz/xz_lzma2.h b/ap/app/busybox/src/archival/libarchive/unxz/xz_lzma2.h
new file mode 100644
index 0000000..47f21af
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/unxz/xz_lzma2.h
@@ -0,0 +1,204 @@
+/*
+ * LZMA2 definitions
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ *          Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_LZMA2_H
+#define XZ_LZMA2_H
+
+/* Range coder constants */
+#define RC_SHIFT_BITS 8
+#define RC_TOP_BITS 24
+#define RC_TOP_VALUE (1 << RC_TOP_BITS)
+#define RC_BIT_MODEL_TOTAL_BITS 11
+#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
+#define RC_MOVE_BITS 5
+
+/*
+ * Maximum number of position states. A position state is the lowest pb
+ * number of bits of the current uncompressed offset. In some places there
+ * are different sets of probabilities for different position states.
+ */
+#define POS_STATES_MAX (1 << 4)
+
+/*
+ * This enum is used to track which LZMA symbols have occurred most recently
+ * and in which order. This information is used to predict the next symbol.
+ *
+ * Symbols:
+ *  - Literal: One 8-bit byte
+ *  - Match: Repeat a chunk of data at some distance
+ *  - Long repeat: Multi-byte match at a recently seen distance
+ *  - Short repeat: One-byte repeat at a recently seen distance
+ *
+ * The symbol names are in from STATE_oldest_older_previous. REP means
+ * either short or long repeated match, and NONLIT means any non-literal.
+ */
+enum lzma_state {
+	STATE_LIT_LIT,
+	STATE_MATCH_LIT_LIT,
+	STATE_REP_LIT_LIT,
+	STATE_SHORTREP_LIT_LIT,
+	STATE_MATCH_LIT,
+	STATE_REP_LIT,
+	STATE_SHORTREP_LIT,
+	STATE_LIT_MATCH,
+	STATE_LIT_LONGREP,
+	STATE_LIT_SHORTREP,
+	STATE_NONLIT_MATCH,
+	STATE_NONLIT_REP
+};
+
+/* Total number of states */
+#define STATES 12
+
+/* The lowest 7 states indicate that the previous state was a literal. */
+#define LIT_STATES 7
+
+/* Indicate that the latest symbol was a literal. */
+static inline void XZ_FUNC lzma_state_literal(enum lzma_state *state)
+{
+	if (*state <= STATE_SHORTREP_LIT_LIT)
+		*state = STATE_LIT_LIT;
+	else if (*state <= STATE_LIT_SHORTREP)
+		*state -= 3;
+	else
+		*state -= 6;
+}
+
+/* Indicate that the latest symbol was a match. */
+static inline void XZ_FUNC lzma_state_match(enum lzma_state *state)
+{
+	*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
+}
+
+/* Indicate that the latest state was a long repeated match. */
+static inline void XZ_FUNC lzma_state_long_rep(enum lzma_state *state)
+{
+	*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
+}
+
+/* Indicate that the latest symbol was a short match. */
+static inline void XZ_FUNC lzma_state_short_rep(enum lzma_state *state)
+{
+	*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
+}
+
+/* Test if the previous symbol was a literal. */
+static inline bool XZ_FUNC lzma_state_is_literal(enum lzma_state state)
+{
+	return state < LIT_STATES;
+}
+
+/* Each literal coder is divided in three sections:
+ *   - 0x001-0x0FF: Without match byte
+ *   - 0x101-0x1FF: With match byte; match bit is 0
+ *   - 0x201-0x2FF: With match byte; match bit is 1
+ *
+ * Match byte is used when the previous LZMA symbol was something else than
+ * a literal (that is, it was some kind of match).
+ */
+#define LITERAL_CODER_SIZE 0x300
+
+/* Maximum number of literal coders */
+#define LITERAL_CODERS_MAX (1 << 4)
+
+/* Minimum length of a match is two bytes. */
+#define MATCH_LEN_MIN 2
+
+/* Match length is encoded with 4, 5, or 10 bits.
+ *
+ * Length   Bits
+ *  2-9      4 = Choice=0 + 3 bits
+ * 10-17     5 = Choice=1 + Choice2=0 + 3 bits
+ * 18-273   10 = Choice=1 + Choice2=1 + 8 bits
+ */
+#define LEN_LOW_BITS 3
+#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
+#define LEN_MID_BITS 3
+#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
+#define LEN_HIGH_BITS 8
+#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
+#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
+
+/*
+ * Maximum length of a match is 273 which is a result of the encoding
+ * described above.
+ */
+#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
+
+/*
+ * Different sets of probabilities are used for match distances that have
+ * very short match length: Lengths of 2, 3, and 4 bytes have a separate
+ * set of probabilities for each length. The matches with longer length
+ * use a shared set of probabilities.
+ */
+#define DIST_STATES 4
+
+/*
+ * Get the index of the appropriate probability array for decoding
+ * the distance slot.
+ */
+static inline uint32_t XZ_FUNC lzma_get_dist_state(uint32_t len)
+{
+	return len < DIST_STATES + MATCH_LEN_MIN
+			? len - MATCH_LEN_MIN : DIST_STATES - 1;
+}
+
+/*
+ * The highest two bits of a 32-bit match distance are encoded using six bits.
+ * This six-bit value is called a distance slot. This way encoding a 32-bit
+ * value takes 6-36 bits, larger values taking more bits.
+ */
+#define DIST_SLOT_BITS 6
+#define DIST_SLOTS (1 << DIST_SLOT_BITS)
+
+/* Match distances up to 127 are fully encoded using probabilities. Since
+ * the highest two bits (distance slot) are always encoded using six bits,
+ * the distances 0-3 don't need any additional bits to encode, since the
+ * distance slot itself is the same as the actual distance. DIST_MODEL_START
+ * indicates the first distance slot where at least one additional bit is
+ * needed.
+ */
+#define DIST_MODEL_START 4
+
+/*
+ * Match distances greater than 127 are encoded in three pieces:
+ *   - distance slot: the highest two bits
+ *   - direct bits: 2-26 bits below the highest two bits
+ *   - alignment bits: four lowest bits
+ *
+ * Direct bits don't use any probabilities.
+ *
+ * The distance slot value of 14 is for distances 128-191.
+ */
+#define DIST_MODEL_END 14
+
+/* Distance slots that indicate a distance <= 127. */
+#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
+#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
+
+/*
+ * For match distances greater than 127, only the highest two bits and the
+ * lowest four bits (alignment) is encoded using probabilities.
+ */
+#define ALIGN_BITS 4
+#define ALIGN_SIZE (1 << ALIGN_BITS)
+#define ALIGN_MASK (ALIGN_SIZE - 1)
+
+/* Total number of all probability variables */
+#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE)
+
+/*
+ * LZMA remembers the four most recent match distances. Reusing these
+ * distances tends to take less space than re-encoding the actual
+ * distance value.
+ */
+#define REPS 4
+
+#endif
diff --git a/ap/app/busybox/src/archival/libarchive/unxz/xz_private.h b/ap/app/busybox/src/archival/libarchive/unxz/xz_private.h
new file mode 100644
index 0000000..145649a
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/unxz/xz_private.h
@@ -0,0 +1,159 @@
+/*
+ * Private includes and definitions
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_PRIVATE_H
+#define XZ_PRIVATE_H
+
+#ifdef __KERNEL__
+	/* XZ_PREBOOT may be defined only via decompress_unxz.c. */
+#	ifndef XZ_PREBOOT
+#		include <linux/slab.h>
+#		include <linux/vmalloc.h>
+#		include <linux/string.h>
+#		define memeq(a, b, size) (memcmp(a, b, size) == 0)
+#		define memzero(buf, size) memset(buf, 0, size)
+#	endif
+#	include <asm/byteorder.h>
+#	include <asm/unaligned.h>
+#	define get_le32(p) le32_to_cpup((const uint32_t *)(p))
+	/* XZ_IGNORE_KCONFIG may be defined only via decompress_unxz.c. */
+#	ifndef XZ_IGNORE_KCONFIG
+#		ifdef CONFIG_XZ_DEC_X86
+#			define XZ_DEC_X86
+#		endif
+#		ifdef CONFIG_XZ_DEC_POWERPC
+#			define XZ_DEC_POWERPC
+#		endif
+#		ifdef CONFIG_XZ_DEC_IA64
+#			define XZ_DEC_IA64
+#		endif
+#		ifdef CONFIG_XZ_DEC_ARM
+#			define XZ_DEC_ARM
+#		endif
+#		ifdef CONFIG_XZ_DEC_ARMTHUMB
+#			define XZ_DEC_ARMTHUMB
+#		endif
+#		ifdef CONFIG_XZ_DEC_SPARC
+#			define XZ_DEC_SPARC
+#		endif
+#	endif
+#	include <linux/xz.h>
+#else
+	/*
+	 * For userspace builds, use a separate header to define the required
+	 * macros and functions. This makes it easier to adapt the code into
+	 * different environments and avoids clutter in the Linux kernel tree.
+	 */
+#	include "xz_config.h"
+#endif
+
+/* If no specific decoding mode is requested, enable support for all modes. */
+#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \
+		&& !defined(XZ_DEC_DYNALLOC)
+#	define XZ_DEC_SINGLE
+#	define XZ_DEC_PREALLOC
+#	define XZ_DEC_DYNALLOC
+#endif
+
+/*
+ * The DEC_IS_foo(mode) macros are used in "if" statements. If only some
+ * of the supported modes are enabled, these macros will evaluate to true or
+ * false at compile time and thus allow the compiler to omit unneeded code.
+ */
+#ifdef XZ_DEC_SINGLE
+#	define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE)
+#else
+#	define DEC_IS_SINGLE(mode) (false)
+#endif
+
+#ifdef XZ_DEC_PREALLOC
+#	define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC)
+#else
+#	define DEC_IS_PREALLOC(mode) (false)
+#endif
+
+#ifdef XZ_DEC_DYNALLOC
+#	define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC)
+#else
+#	define DEC_IS_DYNALLOC(mode) (false)
+#endif
+
+#if !defined(XZ_DEC_SINGLE)
+#	define DEC_IS_MULTI(mode) (true)
+#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC)
+#	define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE)
+#else
+#	define DEC_IS_MULTI(mode) (false)
+#endif
+
+/*
+ * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ.
+ * XZ_DEC_BCJ is used to enable generic support for BCJ decoders.
+ */
+#ifndef XZ_DEC_BCJ
+#	if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
+			|| defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
+			|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
+			|| defined(XZ_DEC_SPARC)
+#		define XZ_DEC_BCJ
+#	endif
+#endif
+
+/*
+ * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used
+ * before calling xz_dec_lzma2_run().
+ */
+XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create(
+		enum xz_mode mode, uint32_t dict_max);
+
+/*
+ * Decode the LZMA2 properties (one byte) and reset the decoder. Return
+ * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not
+ * big enough, and XZ_OPTIONS_ERROR if props indicates something that this
+ * decoder doesn't support.
+ */
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset(
+		struct xz_dec_lzma2 *s, uint8_t props);
+
+/* Decode raw LZMA2 stream from b->in to b->out. */
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_run(
+		struct xz_dec_lzma2 *s, struct xz_buf *b);
+
+/* Free the memory allocated for the LZMA2 decoder. */
+XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
+
+#ifdef XZ_DEC_BCJ
+/*
+ * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before
+ * calling xz_dec_bcj_run().
+ */
+XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call);
+
+/*
+ * Decode the Filter ID of a BCJ filter. This implementation doesn't
+ * support custom start offsets, so no decoding of Filter Properties
+ * is needed. Returns XZ_OK if the given Filter ID is supported.
+ * Otherwise XZ_OPTIONS_ERROR is returned.
+ */
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset(
+		struct xz_dec_bcj *s, uint8_t id);
+
+/*
+ * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is
+ * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run()
+ * must be called directly.
+ */
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
+		struct xz_dec_lzma2 *lzma2, struct xz_buf *b);
+
+/* Free the memory allocated for the BCJ filters. */
+#define xz_dec_bcj_end(s) kfree(s)
+#endif
+
+#endif
diff --git a/ap/app/busybox/src/archival/libarchive/unxz/xz_stream.h b/ap/app/busybox/src/archival/libarchive/unxz/xz_stream.h
new file mode 100644
index 0000000..36f2a7c
--- /dev/null
+++ b/ap/app/busybox/src/archival/libarchive/unxz/xz_stream.h
@@ -0,0 +1,57 @@
+/*
+ * Definitions for handling the .xz file format
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_STREAM_H
+#define XZ_STREAM_H
+
+#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32
+#	include <linux/crc32.h>
+#	undef crc32
+#	define xz_crc32(buf, size, crc) \
+		(~crc32_le(~(uint32_t)(crc), buf, size))
+#endif
+
+/*
+ * See the .xz file format specification at
+ * http://tukaani.org/xz/xz-file-format.txt
+ * to understand the container format.
+ */
+
+#define STREAM_HEADER_SIZE 12
+
+#define HEADER_MAGIC "\3757zXZ\0"
+#define HEADER_MAGIC_SIZE 6
+
+#define FOOTER_MAGIC "YZ"
+#define FOOTER_MAGIC_SIZE 2
+
+/*
+ * Variable-length integer can hold a 63-bit unsigned integer, or a special
+ * value to indicate that the value is unknown.
+ */
+typedef uint64_t vli_type;
+
+#define VLI_MAX ((vli_type)-1 / 2)
+#define VLI_UNKNOWN ((vli_type)-1)
+
+/* Maximum encoded size of a VLI */
+#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
+
+/* Integrity Check types */
+enum xz_check {
+	XZ_CHECK_NONE = 0,
+	XZ_CHECK_CRC32 = 1,
+	XZ_CHECK_CRC64 = 4,
+	XZ_CHECK_SHA256 = 10
+};
+
+/* Maximum possible Check ID */
+#define XZ_CHECK_MAX 15
+
+#endif
diff --git a/ap/app/busybox/src/archival/lzop.c b/ap/app/busybox/src/archival/lzop.c
new file mode 100644
index 0000000..56003d4
--- /dev/null
+++ b/ap/app/busybox/src/archival/lzop.c
@@ -0,0 +1,1101 @@
+/*
+   This file is part of the lzop file compressor.
+
+   Copyright (C) 1996..2003 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzop/
+
+   lzop and the LZO library are free software; you can redistribute them
+   and/or modify them under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, 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; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   "Minimalized" for busybox by Alain Knaff
+*/
+
+//usage:#define lzop_trivial_usage
+//usage:       "[-cfvd123456789CF] [FILE]..."
+//usage:#define lzop_full_usage "\n\n"
+//usage:       "	-1..9	Compression level"
+//usage:     "\n	-d	Decompress"
+//usage:     "\n	-c	Write to stdout"
+//usage:     "\n	-f	Force"
+//usage:     "\n	-v	Verbose"
+//usage:     "\n	-F	Don't store or verify checksum"
+//usage:     "\n	-C	Also write checksum of compressed block"
+//usage:
+//usage:#define lzopcat_trivial_usage
+//usage:       "[-vCF] [FILE]..."
+//usage:#define lzopcat_full_usage "\n\n"
+//usage:       "	-v	Verbose"
+//usage:     "\n	-F	Don't store or verify checksum"
+//usage:
+//usage:#define unlzop_trivial_usage
+//usage:       "[-cfvCF] [FILE]..."
+//usage:#define unlzop_full_usage "\n\n"
+//usage:       "	-c	Write to stdout"
+//usage:     "\n	-f	Force"
+//usage:     "\n	-v	Verbose"
+//usage:     "\n	-F	Don't store or verify checksum"
+
+#include "libbb.h"
+#include "bb_archive.h"
+#include "liblzo_interface.h"
+
+/* lzo-2.03/src/lzo_ptr.h */
+#define pd(a,b)	 ((unsigned)((a)-(b)))
+
+#define lzo_version()			LZO_VERSION
+#define lzo_sizeof_dict_t		(sizeof(uint8_t*))
+
+/* lzo-2.03/include/lzo/lzo1x.h */
+#define LZO1X_1_MEM_COMPRESS	(16384 * lzo_sizeof_dict_t)
+#define LZO1X_1_15_MEM_COMPRESS (32768 * lzo_sizeof_dict_t)
+#define LZO1X_999_MEM_COMPRESS	(14 * 16384 * sizeof(short))
+
+/* lzo-2.03/src/lzo1x_oo.c */
+#define NO_LIT UINT_MAX
+
+/**********************************************************************/
+static void copy2(uint8_t* ip, const uint8_t* m_pos, unsigned off)
+{
+	ip[0] = m_pos[0];
+	if (off == 1)
+		ip[1] = m_pos[0];
+	else
+		ip[1] = m_pos[1];
+}
+
+static void copy3(uint8_t* ip, const uint8_t* m_pos, unsigned off)
+{
+	ip[0] = m_pos[0];
+	if (off == 1) {
+		ip[2] = ip[1] = m_pos[0];
+	}
+	else if (off == 2) {
+		ip[1] = m_pos[1];
+		ip[2] = m_pos[0];
+	}
+	else {
+		ip[1] = m_pos[1];
+		ip[2] = m_pos[2];
+	}
+}
+
+/**********************************************************************/
+// optimize a block of data.
+/**********************************************************************/
+#define TEST_IP		(ip < ip_end)
+#define TEST_OP		(op <= op_end)
+
+static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len,
+		uint8_t *out, unsigned *out_len,
+		void* wrkmem UNUSED_PARAM)
+{
+	uint8_t* op;
+	uint8_t* ip;
+	unsigned t;
+	uint8_t* m_pos;
+	uint8_t* const ip_end = in + in_len;
+	uint8_t* const op_end = out + *out_len;
+	uint8_t* litp = NULL;
+	unsigned lit = 0;
+	unsigned next_lit = NO_LIT;
+	unsigned nl;
+	unsigned long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0;
+
+//	LZO_UNUSED(wrkmem);
+
+	*out_len = 0;
+
+	op = out;
+	ip = in;
+
+	if (*ip > 17) {
+		t = *ip++ - 17;
+		if (t < 4)
+			goto match_next;
+		goto first_literal_run;
+	}
+
+	while (TEST_IP && TEST_OP) {
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+		/* a literal run */
+		litp = ip - 1;
+		if (t == 0) {
+			t = 15;
+			while (*ip == 0)
+				t += 255, ip++;
+			t += *ip++;
+		}
+		lit = t + 3;
+		/* copy literals */
+ copy_literal_run:
+		*op++ = *ip++;
+		*op++ = *ip++;
+		*op++ = *ip++;
+ first_literal_run:
+		do *op++ = *ip++; while (--t > 0);
+
+		t = *ip++;
+
+		if (t >= 16)
+			goto match;
+#if defined(LZO1X)
+		m_pos = op - 1 - 0x800;
+#elif defined(LZO1Y)
+		m_pos = op - 1 - 0x400;
+#endif
+		m_pos -= t >> 2;
+		m_pos -= *ip++ << 2;
+		*op++ = *m_pos++;
+		*op++ = *m_pos++;
+		*op++ = *m_pos++;
+		lit = 0;
+		goto match_done;
+
+
+		/* handle matches */
+		do {
+			if (t < 16) { /* a M1 match */
+				m_pos = op - 1;
+				m_pos -= t >> 2;
+				m_pos -= *ip++ << 2;
+
+				if (litp == NULL)
+					goto copy_m1;
+
+				nl = ip[-2] & 3;
+				/* test if a match follows */
+				if (nl == 0 && lit == 1 && ip[0] >= 16) {
+					next_lit = nl;
+					/* adjust length of previous short run */
+					lit += 2;
+					*litp = (unsigned char)((*litp & ~3) | lit);
+					/* copy over the 2 literals that replace the match */
+					copy2(ip-2, m_pos, pd(op, m_pos));
+					o_m1_a++;
+				}
+				/* test if a literal run follows */
+				else
+				if (nl == 0
+				 && ip[0] < 16
+				 && ip[0] != 0
+				 && (lit + 2 + ip[0] < 16)
+				) {
+					t = *ip++;
+					/* remove short run */
+					*litp &= ~3;
+					/* copy over the 2 literals that replace the match */
+					copy2(ip-3+1, m_pos, pd(op, m_pos));
+					/* move literals 1 byte ahead */
+					litp += 2;
+					if (lit > 0)
+						memmove(litp+1, litp, lit);
+					/* insert new length of long literal run */
+					lit += 2 + t + 3;
+					*litp = (unsigned char)(lit - 3);
+
+					o_m1_b++;
+					*op++ = *m_pos++;
+					*op++ = *m_pos++;
+					goto copy_literal_run;
+				}
+ copy_m1:
+				*op++ = *m_pos++;
+				*op++ = *m_pos++;
+			} else {
+ match:
+				if (t >= 64) {				/* a M2 match */
+					m_pos = op - 1;
+#if defined(LZO1X)
+					m_pos -= (t >> 2) & 7;
+					m_pos -= *ip++ << 3;
+					t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+					m_pos -= (t >> 2) & 3;
+					m_pos -= *ip++ << 2;
+					t = (t >> 4) - 3;
+#endif
+					if (litp == NULL)
+						goto copy_m;
+
+					nl = ip[-2] & 3;
+					/* test if in beetween two long literal runs */
+					if (t == 1 && lit > 3 && nl == 0
+					 && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)
+					) {
+						t = *ip++;
+						/* copy over the 3 literals that replace the match */
+						copy3(ip-1-2, m_pos, pd(op, m_pos));
+						/* set new length of previous literal run */
+						lit += 3 + t + 3;
+						*litp = (unsigned char)(lit - 3);
+						o_m2++;
+						*op++ = *m_pos++;
+						*op++ = *m_pos++;
+						*op++ = *m_pos++;
+						goto copy_literal_run;
+					}
+				} else {
+					if (t >= 32) {			/* a M3 match */
+						t &= 31;
+						if (t == 0) {
+							t = 31;
+							while (*ip == 0)
+								t += 255, ip++;
+							t += *ip++;
+						}
+						m_pos = op - 1;
+						m_pos -= *ip++ >> 2;
+						m_pos -= *ip++ << 6;
+					} else {					/* a M4 match */
+						m_pos = op;
+						m_pos -= (t & 8) << 11;
+						t &= 7;
+						if (t == 0) {
+							t = 7;
+							while (*ip == 0)
+								t += 255, ip++;
+							t += *ip++;
+						}
+						m_pos -= *ip++ >> 2;
+						m_pos -= *ip++ << 6;
+						if (m_pos == op)
+							goto eof_found;
+						m_pos -= 0x4000;
+					}
+					if (litp == NULL)
+						goto copy_m;
+
+					nl = ip[-2] & 3;
+					/* test if in beetween two matches */
+					if (t == 1 && lit == 0 && nl == 0 && ip[0] >= 16) {
+						next_lit = nl;
+						/* make a previous short run */
+						lit += 3;
+						*litp = (unsigned char)((*litp & ~3) | lit);
+						/* copy over the 3 literals that replace the match */
+						copy3(ip-3, m_pos, pd(op, m_pos));
+						o_m3_a++;
+					}
+					/* test if a literal run follows */
+					else if (t == 1 && lit <= 3 && nl == 0
+					 && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)
+					) {
+						t = *ip++;
+						/* remove short run */
+						*litp &= ~3;
+						/* copy over the 3 literals that replace the match */
+						copy3(ip-4+1, m_pos, pd(op, m_pos));
+						/* move literals 1 byte ahead */
+						litp += 2;
+						if (lit > 0)
+							memmove(litp+1,litp,lit);
+						/* insert new length of long literal run */
+						lit += 3 + t + 3;
+						*litp = (unsigned char)(lit - 3);
+
+						o_m3_b++;
+						*op++ = *m_pos++;
+						*op++ = *m_pos++;
+						*op++ = *m_pos++;
+						goto copy_literal_run;
+					}
+				}
+ copy_m:
+				*op++ = *m_pos++;
+				*op++ = *m_pos++;
+				do *op++ = *m_pos++; while (--t > 0);
+			}
+
+ match_done:
+			if (next_lit == NO_LIT) {
+				t = ip[-2] & 3;
+				lit = t;
+				litp = ip - 2;
+			}
+			else
+				t = next_lit;
+			next_lit = NO_LIT;
+			if (t == 0)
+				break;
+			/* copy literals */
+ match_next:
+			do *op++ = *ip++; while (--t > 0);
+			t = *ip++;
+		} while (TEST_IP && TEST_OP);
+	}
+
+	/* no EOF code was found */
+	*out_len = pd(op, out);
+	return LZO_E_EOF_NOT_FOUND;
+
+ eof_found:
+//	LZO_UNUSED(o_m1_a); LZO_UNUSED(o_m1_b); LZO_UNUSED(o_m2);
+//	LZO_UNUSED(o_m3_a); LZO_UNUSED(o_m3_b);
+	*out_len = pd(op, out);
+	return (ip == ip_end ? LZO_E_OK :
+		(ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+}
+
+/**********************************************************************/
+#define F_OS F_OS_UNIX
+#define F_CS F_CS_NATIVE
+
+/**********************************************************************/
+#define ADLER32_INIT_VALUE 1
+#define CRC32_INIT_VALUE   0
+
+/**********************************************************************/
+enum {
+	M_LZO1X_1    = 1,
+	M_LZO1X_1_15 = 2,
+	M_LZO1X_999  = 3,
+};
+
+/**********************************************************************/
+/* header flags */
+#define F_ADLER32_D     0x00000001L
+#define F_ADLER32_C     0x00000002L
+#define F_H_EXTRA_FIELD 0x00000040L
+#define F_H_GMTDIFF     0x00000080L
+#define F_CRC32_D       0x00000100L
+#define F_CRC32_C       0x00000200L
+#define F_H_FILTER      0x00000800L
+#define F_H_CRC32       0x00001000L
+#define F_MASK          0x00003FFFL
+
+/* operating system & file system that created the file [mostly unused] */
+#define F_OS_UNIX       0x03000000L
+#define F_OS_SHIFT      24
+#define F_OS_MASK       0xff000000L
+
+/* character set for file name encoding [mostly unused] */
+#define F_CS_NATIVE     0x00000000L
+#define F_CS_SHIFT      20
+#define F_CS_MASK       0x00f00000L
+
+/* these bits must be zero */
+#define F_RESERVED      ((F_MASK | F_OS_MASK | F_CS_MASK) ^ 0xffffffffL)
+
+typedef struct chksum_t {
+	uint32_t f_adler32;
+	uint32_t f_crc32;
+} chksum_t;
+
+typedef struct header_t {
+	unsigned version;
+	unsigned lib_version;
+	unsigned version_needed_to_extract;
+	uint32_t flags;
+	uint32_t mode;
+	uint32_t mtime;
+	uint32_t gmtdiff;
+	uint32_t header_checksum;
+
+	uint32_t extra_field_len;
+	uint32_t extra_field_checksum;
+
+	unsigned char method;
+	unsigned char level;
+
+	/* info */
+	char name[255+1];
+} header_t;
+
+struct globals {
+	/*const uint32_t *lzo_crc32_table;*/
+	chksum_t chksum_in;
+	chksum_t chksum_out;
+} FIX_ALIASING;
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define INIT_G() do { } while (0)
+//#define G (*ptr_to_globals)
+//#define INIT_G() do {
+//	SET_PTR_TO_GLOBALS(xzalloc(sizeof(G)));
+//} while (0)
+
+
+/**********************************************************************/
+#define LZOP_VERSION            0x1010
+//#define LZOP_VERSION_STRING     "1.01"
+//#define LZOP_VERSION_DATE       "Apr 27th 2003"
+
+#define OPTION_STRING "cfvdt123456789CF"
+
+enum {
+	OPT_STDOUT      = (1 << 0),
+	OPT_FORCE       = (1 << 1),
+	OPT_VERBOSE     = (1 << 2),
+	OPT_DECOMPRESS  = (1 << 3),
+	OPT_TEST        = (1 << 4),
+	OPT_1           = (1 << 5),
+	OPT_2           = (1 << 6),
+	OPT_3           = (1 << 7),
+	OPT_4           = (1 << 8),
+	OPT_5           = (1 << 9),
+	OPT_6           = (1 << 10),
+	OPT_789         = (7 << 11),
+	OPT_7           = (1 << 11),
+	OPT_8           = (1 << 12),
+	OPT_C           = (1 << 14),
+	OPT_F           = (1 << 15),
+};
+
+/**********************************************************************/
+// adler32 checksum
+// adapted from free code by Mark Adler <madler@alumni.caltech.edu>
+// see http://www.zlib.org/
+/**********************************************************************/
+static FAST_FUNC uint32_t
+lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len)
+{
+	enum {
+		LZO_BASE = 65521, /* largest prime smaller than 65536 */
+		/* NMAX is the largest n such that
+		 * 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+		LZO_NMAX = 5552,
+	};
+	uint32_t s1 = adler & 0xffff;
+	uint32_t s2 = (adler >> 16) & 0xffff;
+	unsigned k;
+
+	if (buf == NULL)
+		return 1;
+
+	while (len > 0) {
+		k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX;
+		len -= k;
+		if (k != 0) do {
+			s1 += *buf++;
+			s2 += s1;
+		} while (--k > 0);
+		s1 %= LZO_BASE;
+		s2 %= LZO_BASE;
+	}
+	return (s2 << 16) | s1;
+}
+
+static FAST_FUNC uint32_t
+lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len)
+{
+	//if (buf == NULL) - impossible
+	//	return 0;
+
+	return ~crc32_block_endian0(~c, buf, len, global_crc32_table);
+}
+
+/**********************************************************************/
+static void init_chksum(chksum_t *ct)
+{
+	ct->f_adler32 = ADLER32_INIT_VALUE;
+	ct->f_crc32 = CRC32_INIT_VALUE;
+}
+
+static void add_bytes_to_chksum(chksum_t *ct, const void* buf, int cnt)
+{
+	/* We need to handle the two checksums at once, because at the
+	 * beginning of the header, we don't know yet which one we'll
+	 * eventually need */
+	ct->f_adler32 = lzo_adler32(ct->f_adler32, (const uint8_t*)buf, cnt);
+	ct->f_crc32 = lzo_crc32(ct->f_crc32, (const uint8_t*)buf, cnt);
+}
+
+static uint32_t chksum_getresult(chksum_t *ct, const header_t *h)
+{
+	return (h->flags & F_H_CRC32) ? ct->f_crc32 : ct->f_adler32;
+}
+
+/**********************************************************************/
+static uint32_t read32(void)
+{
+	uint32_t v;
+	xread(0, &v, 4);
+	return ntohl(v);
+}
+
+static void write32(uint32_t v)
+{
+	v = htonl(v);
+	xwrite(1, &v, 4);
+}
+
+static void f_write(const void* buf, int cnt)
+{
+	xwrite(1, buf, cnt);
+	add_bytes_to_chksum(&G.chksum_out, buf, cnt);
+}
+
+static void f_read(void* buf, int cnt)
+{
+	xread(0, buf, cnt);
+	add_bytes_to_chksum(&G.chksum_in, buf, cnt);
+}
+
+static int f_read8(void)
+{
+	uint8_t v;
+	f_read(&v, 1);
+	return v;
+}
+
+static void f_write8(uint8_t v)
+{
+	f_write(&v, 1);
+}
+
+static unsigned f_read16(void)
+{
+	uint16_t v;
+	f_read(&v, 2);
+	return ntohs(v);
+}
+
+static void f_write16(uint16_t v)
+{
+	v = htons(v);
+	f_write(&v, 2);
+}
+
+static uint32_t f_read32(void)
+{
+	uint32_t v;
+	f_read(&v, 4);
+	return ntohl(v);
+}
+
+static void f_write32(uint32_t v)
+{
+	v = htonl(v);
+	f_write(&v, 4);
+}
+
+/**********************************************************************/
+static int lzo_get_method(header_t *h)
+{
+	/* check method */
+	if (h->method == M_LZO1X_1) {
+		if (h->level == 0)
+			h->level = 3;
+	} else if (h->method == M_LZO1X_1_15) {
+		if (h->level == 0)
+			h->level = 1;
+	} else if (h->method == M_LZO1X_999) {
+		if (h->level == 0)
+			h->level = 9;
+	} else
+		return -1;		/* not a LZO method */
+
+	/* check compression level */
+	if (h->level < 1 || h->level > 9)
+		return 15;
+
+	return 0;
+}
+
+/**********************************************************************/
+#define LZO_BLOCK_SIZE	(256 * 1024l)
+#define MAX_BLOCK_SIZE	(64 * 1024l * 1024l)	/* DO NOT CHANGE */
+
+/* LZO may expand uncompressible data by a small amount */
+#define MAX_COMPRESSED_SIZE(x)	((x) + (x) / 16 + 64 + 3)
+
+/**********************************************************************/
+// compress a file
+/**********************************************************************/
+static NOINLINE smallint lzo_compress(const header_t *h)
+{
+	unsigned block_size = LZO_BLOCK_SIZE;
+	int r = 0; /* LZO_E_OK */
+	uint8_t *const b1 = xzalloc(block_size);
+	uint8_t *const b2 = xzalloc(MAX_COMPRESSED_SIZE(block_size));
+	unsigned src_len = 0, dst_len = 0;
+	uint32_t d_adler32 = ADLER32_INIT_VALUE;
+	uint32_t d_crc32 = CRC32_INIT_VALUE;
+	int l;
+	smallint ok = 1;
+	uint8_t *wrk_mem = NULL;
+
+	if (h->method == M_LZO1X_1)
+		wrk_mem = xzalloc(LZO1X_1_MEM_COMPRESS);
+	else if (h->method == M_LZO1X_1_15)
+		wrk_mem = xzalloc(LZO1X_1_15_MEM_COMPRESS);
+	else if (h->method == M_LZO1X_999)
+		wrk_mem = xzalloc(LZO1X_999_MEM_COMPRESS);
+
+	for (;;) {
+		/* read a block */
+		l = full_read(0, b1, block_size);
+		src_len = (l > 0 ? l : 0);
+
+		/* write uncompressed block size */
+		write32(src_len);
+
+		/* exit if last block */
+		if (src_len == 0)
+			break;
+
+		/* compute checksum of uncompressed block */
+		if (h->flags & F_ADLER32_D)
+			d_adler32 = lzo_adler32(ADLER32_INIT_VALUE, b1, src_len);
+		if (h->flags & F_CRC32_D)
+			d_crc32 = lzo_crc32(CRC32_INIT_VALUE, b1, src_len);
+
+		/* compress */
+		if (h->method == M_LZO1X_1)
+			r = lzo1x_1_compress(b1, src_len, b2, &dst_len, wrk_mem);
+		else if (h->method == M_LZO1X_1_15)
+			r = lzo1x_1_15_compress(b1, src_len, b2, &dst_len, wrk_mem);
+#if ENABLE_LZOP_COMPR_HIGH
+		else if (h->method == M_LZO1X_999)
+			r = lzo1x_999_compress_level(b1, src_len, b2, &dst_len,
+						wrk_mem, h->level);
+#endif
+		else
+			bb_error_msg_and_die("internal error");
+
+		if (r != 0) /* not LZO_E_OK */
+			bb_error_msg_and_die("internal error - compression failed");
+
+		/* write compressed block size */
+		if (dst_len < src_len) {
+			/* optimize */
+			if (h->method == M_LZO1X_999) {
+				unsigned new_len = src_len;
+				r = lzo1x_optimize(b2, dst_len, b1, &new_len, NULL);
+				if (r != 0 /*LZO_E_OK*/ || new_len != src_len)
+					bb_error_msg_and_die("internal error - optimization failed");
+			}
+			write32(dst_len);
+		} else {
+			/* data actually expanded => store data uncompressed */
+			write32(src_len);
+		}
+
+		/* write checksum of uncompressed block */
+		if (h->flags & F_ADLER32_D)
+			write32(d_adler32);
+		if (h->flags & F_CRC32_D)
+			write32(d_crc32);
+
+		if (dst_len < src_len) {
+			/* write checksum of compressed block */
+			if (h->flags & F_ADLER32_C)
+				write32(lzo_adler32(ADLER32_INIT_VALUE, b2, dst_len));
+			if (h->flags & F_CRC32_C)
+				write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len));
+			/* write compressed block data */
+			xwrite(1, b2, dst_len);
+		} else {
+			/* write uncompressed block data */
+			xwrite(1, b1, src_len);
+		}
+	}
+
+	free(wrk_mem);
+	free(b1);
+	free(b2);
+	return ok;
+}
+
+static FAST_FUNC void lzo_check(
+		uint32_t init,
+		uint8_t* buf, unsigned len,
+		uint32_t FAST_FUNC (*fn)(uint32_t, const uint8_t*, unsigned),
+		uint32_t ref)
+{
+	/* This function, by having the same order of parameters
+	 * as fn, and by being marked FAST_FUNC (same as fn),
+	 * saves a dozen bytes of code.
+	 */
+	uint32_t c = fn(init, buf, len);
+	if (c != ref)
+		bb_error_msg_and_die("checksum error");
+}
+
+/**********************************************************************/
+// decompress a file
+/**********************************************************************/
+static NOINLINE smallint lzo_decompress(const header_t *h)
+{
+	unsigned block_size = LZO_BLOCK_SIZE;
+	int r;
+	uint32_t src_len, dst_len;
+	uint32_t c_adler32 = ADLER32_INIT_VALUE;
+	uint32_t d_adler32 = ADLER32_INIT_VALUE;
+	uint32_t c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE;
+	smallint ok = 1;
+	uint8_t *b1;
+	uint32_t mcs_block_size = MAX_COMPRESSED_SIZE(block_size);
+	uint8_t *b2 = NULL;
+
+	for (;;) {
+		uint8_t *dst;
+
+		/* read uncompressed block size */
+		dst_len = read32();
+
+		/* exit if last block */
+		if (dst_len == 0)
+			break;
+
+		/* error if split file */
+		if (dst_len == 0xffffffffL)
+			/* should not happen - not yet implemented */
+			bb_error_msg_and_die("this file is a split lzop file");
+
+		if (dst_len > MAX_BLOCK_SIZE)
+			bb_error_msg_and_die("corrupted data");
+
+		/* read compressed block size */
+		src_len = read32();
+		if (src_len <= 0 || src_len > dst_len)
+			bb_error_msg_and_die("corrupted data");
+
+		if (dst_len > block_size) {
+			if (b2) {
+				free(b2);
+				b2 = NULL;
+			}
+			block_size = dst_len;
+			mcs_block_size = MAX_COMPRESSED_SIZE(block_size);
+		}
+
+		/* read checksum of uncompressed block */
+		if (h->flags & F_ADLER32_D)
+			d_adler32 = read32();
+		if (h->flags & F_CRC32_D)
+			d_crc32 = read32();
+
+		/* read checksum of compressed block */
+		if (src_len < dst_len) {
+			if (h->flags & F_ADLER32_C)
+				c_adler32 = read32();
+			if (h->flags & F_CRC32_C)
+				c_crc32 = read32();
+		}
+
+		if (b2 == NULL)
+			b2 = xzalloc(mcs_block_size);
+		/* read the block into the end of our buffer */
+		b1 = b2 + mcs_block_size - src_len;
+		xread(0, b1, src_len);
+
+		if (src_len < dst_len) {
+			unsigned d = dst_len;
+
+			if (!(option_mask32 & OPT_F)) {
+				/* verify checksum of compressed block */
+				if (h->flags & F_ADLER32_C)
+					lzo_check(ADLER32_INIT_VALUE,
+							b1, src_len,
+							lzo_adler32, c_adler32);
+				if (h->flags & F_CRC32_C)
+					lzo_check(CRC32_INIT_VALUE,
+							b1, src_len,
+							lzo_crc32, c_crc32);
+			}
+
+			/* decompress */
+//			if (option_mask32 & OPT_F)
+//				r = lzo1x_decompress(b1, src_len, b2, &d, NULL);
+//			else
+				r = lzo1x_decompress_safe(b1, src_len, b2, &d, NULL);
+
+			if (r != 0 /*LZO_E_OK*/ || dst_len != d) {
+				bb_error_msg_and_die("corrupted data");
+			}
+			dst = b2;
+		} else {
+			/* "stored" block => no decompression */
+			dst = b1;
+		}
+
+		if (!(option_mask32 & OPT_F)) {
+			/* verify checksum of uncompressed block */
+			if (h->flags & F_ADLER32_D)
+				lzo_check(ADLER32_INIT_VALUE,
+					dst, dst_len,
+					lzo_adler32, d_adler32);
+			if (h->flags & F_CRC32_D)
+				lzo_check(CRC32_INIT_VALUE,
+					dst, dst_len,
+					lzo_crc32, d_crc32);
+		}
+
+		/* write uncompressed block data */
+		xwrite(1, dst, dst_len);
+	}
+
+	free(b2);
+	return ok;
+}
+
+/**********************************************************************/
+// lzop file signature (shamelessly borrowed from PNG)
+/**********************************************************************/
+/*
+ * The first nine bytes of a lzop file always contain the following values:
+ *
+ *                                 0   1   2   3   4   5   6   7   8
+ *                               --- --- --- --- --- --- --- --- ---
+ * (hex)                          89  4c  5a  4f  00  0d  0a  1a  0a
+ * (decimal)                     137  76  90  79   0  13  10  26  10
+ * (C notation - ASCII)         \211   L   Z   O  \0  \r  \n \032 \n
+ */
+
+/* (vda) comparison with lzop v1.02rc1 ("lzop -1 <FILE" cmd):
+ * Only slight differences in header:
+ * -00000000  89 4c 5a 4f 00 0d 0a 1a 0a 10 20 20 20 09 40 02
+ * +00000000  89 4c 5a 4f 00 0d 0a 1a 0a 10 10 20 30 09 40 02
+ *                                       ^^^^^ ^^^^^
+ *                                     version lib_version
+ * -00000010  01 03 00 00 0d 00 00 81 a4 49 f7 a6 3f 00 00 00
+ * +00000010  01 03 00 00 01 00 00 00 00 00 00 00 00 00 00 00
+ *               ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^
+ *               flags       mode        mtime
+ * -00000020  00 00 2d 67 04 17 00 04 00 00 00 03 ed ec 9d 6d
+ * +00000020  00 00 10 5f 00 c1 00 04 00 00 00 03 ed ec 9d 6d
+ *                  ^^^^^^^^^^^
+ *                  chksum_out
+ * The rest is identical.
+*/
+static const unsigned char lzop_magic[9] = {
+	0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a
+};
+
+/* This coding is derived from Alexander Lehmann's pngcheck code. */
+static void check_magic(void)
+{
+	unsigned char magic[sizeof(lzop_magic)];
+	xread(0, magic, sizeof(magic));
+	if (memcmp(magic, lzop_magic, sizeof(lzop_magic)) != 0)
+		bb_error_msg_and_die("bad magic number");
+}
+
+/**********************************************************************/
+// lzop file header
+/**********************************************************************/
+static void write_header(const header_t *h)
+{
+	int l;
+
+	xwrite(1, lzop_magic, sizeof(lzop_magic));
+
+	init_chksum(&G.chksum_out);
+
+	f_write16(h->version);
+	f_write16(h->lib_version);
+	f_write16(h->version_needed_to_extract);
+	f_write8(h->method);
+	f_write8(h->level);
+	f_write32(h->flags);
+	f_write32(h->mode);
+	f_write32(h->mtime);
+	f_write32(h->gmtdiff);
+
+	l = (int) strlen(h->name);
+	f_write8(l);
+	if (l)
+		f_write(h->name, l);
+
+	f_write32(chksum_getresult(&G.chksum_out, h));
+}
+
+static int read_header(header_t *h)
+{
+	int r;
+	int l;
+	uint32_t checksum;
+
+	memset(h, 0, sizeof(*h));
+	h->version_needed_to_extract = 0x0900;	/* first lzop version */
+	h->level = 0;
+
+	init_chksum(&G.chksum_in);
+
+	h->version = f_read16();
+	if (h->version < 0x0900)
+		return 3;
+	h->lib_version = f_read16();
+	if (h->version >= 0x0940) {
+		h->version_needed_to_extract = f_read16();
+		if (h->version_needed_to_extract > LZOP_VERSION)
+			return 16;
+		if (h->version_needed_to_extract < 0x0900)
+			return 3;
+	}
+	h->method = f_read8();
+	if (h->version >= 0x0940)
+		h->level = f_read8();
+	h->flags = f_read32();
+	if (h->flags & F_H_FILTER)
+		return 16; /* filter not supported */
+	h->mode = f_read32();
+	h->mtime = f_read32();
+	if (h->version >= 0x0940)
+		h->gmtdiff = f_read32();
+
+	l = f_read8();
+	if (l > 0)
+		f_read(h->name, l);
+	h->name[l] = 0;
+
+	checksum = chksum_getresult(&G.chksum_in, h);
+	h->header_checksum = f_read32();
+	if (h->header_checksum != checksum)
+		return 2;
+
+	if (h->method <= 0)
+		return 14;
+	r = lzo_get_method(h);
+	if (r != 0)
+		return r;
+
+	/* check reserved flags */
+	if (h->flags & F_RESERVED)
+		return -13;
+
+	/* skip extra field [not used yet] */
+	if (h->flags & F_H_EXTRA_FIELD) {
+		uint32_t k;
+
+		/* note: the checksum also covers the length */
+		init_chksum(&G.chksum_in);
+		h->extra_field_len = f_read32();
+		for (k = 0; k < h->extra_field_len; k++)
+			f_read8();
+		checksum = chksum_getresult(&G.chksum_in, h);
+		h->extra_field_checksum = f_read32();
+		if (h->extra_field_checksum != checksum)
+			return 3;
+	}
+
+	return 0;
+}
+
+static void p_header(header_t *h)
+{
+	int r;
+
+	r = read_header(h);
+	if (r == 0)
+		return;
+	bb_error_msg_and_die("header_error %d", r);
+}
+
+/**********************************************************************/
+// compress
+/**********************************************************************/
+static void lzo_set_method(header_t *h)
+{
+	int level = 1;
+
+	if (option_mask32 & OPT_1) {
+		h->method = M_LZO1X_1_15;
+	} else if (option_mask32 & OPT_789) {
+#if ENABLE_LZOP_COMPR_HIGH
+		h->method = M_LZO1X_999;
+		if (option_mask32 & OPT_7)
+			level = 7;
+		else if (option_mask32 & OPT_8)
+			level = 8;
+		else
+			level = 9;
+#else
+		bb_error_msg_and_die("high compression not compiled in");
+#endif
+	} else { /* levels 2..6 or none (defaults to level 3) */
+		h->method = M_LZO1X_1;
+		level = 5; /* levels 2-6 are actually the same */
+	}
+
+	h->level = level;
+}
+
+static smallint do_lzo_compress(void)
+{
+	header_t header;
+
+#define h (&header)
+	memset(h, 0, sizeof(*h));
+
+	lzo_set_method(h);
+
+	h->version = (LZOP_VERSION & 0xffff);
+	h->version_needed_to_extract = 0x0940;
+	h->lib_version = lzo_version() & 0xffff;
+
+	h->flags = (F_OS & F_OS_MASK) | (F_CS & F_CS_MASK);
+
+	if (!(option_mask32 & OPT_F) || h->method == M_LZO1X_999) {
+		h->flags |= F_ADLER32_D;
+		if (option_mask32 & OPT_C)
+			h->flags |= F_ADLER32_C;
+	}
+	write_header(h);
+	return lzo_compress(h);
+#undef h
+}
+
+/**********************************************************************/
+// decompress
+/**********************************************************************/
+static smallint do_lzo_decompress(void)
+{
+	header_t header;
+
+	check_magic();
+	p_header(&header);
+	return lzo_decompress(&header);
+}
+
+static char* FAST_FUNC make_new_name_lzop(char *filename, const char *expected_ext UNUSED_PARAM)
+{
+	if (option_mask32 & OPT_DECOMPRESS) {
+		char *extension = strrchr(filename, '.');
+		if (!extension || strcmp(extension + 1, "lzo") != 0)
+			return xasprintf("%s.out", filename);
+		*extension = '\0';
+		return filename;
+	}
+	return xasprintf("%s.lzo", filename);
+}
+
+static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_aux_data_t *aux UNUSED_PARAM)
+{
+	if (option_mask32 & OPT_DECOMPRESS)
+		return do_lzo_decompress();
+	return do_lzo_compress();
+}
+
+int lzop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int lzop_main(int argc UNUSED_PARAM, char **argv)
+{
+	getopt32(argv, OPTION_STRING);
+	argv += optind;
+	/* lzopcat? */
+	if (applet_name[4] == 'c')
+		option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS);
+	/* unlzop? */
+	if (applet_name[0] == 'u')
+		option_mask32 |= OPT_DECOMPRESS;
+
+	global_crc32_table = crc32_filltable(NULL, 0);
+	return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL);
+}
diff --git a/ap/app/busybox/src/archival/rpm.c b/ap/app/busybox/src/archival/rpm.c
new file mode 100644
index 0000000..6757a6c
--- /dev/null
+++ b/ap/app/busybox/src/archival/rpm.c
@@ -0,0 +1,394 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini rpm applet for busybox
+ *
+ * Copyright (C) 2001,2002 by Laurence Anderson
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//usage:#define rpm_trivial_usage
+//usage:       "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm"
+//usage:#define rpm_full_usage "\n\n"
+//usage:       "Manipulate RPM packages\n"
+//usage:     "\nCommands:"
+//usage:     "\n	-i	Install package"
+//usage:     "\n	-qp	Query package"
+//usage:     "\n	-i	Show information"
+//usage:     "\n	-l	List contents"
+//usage:     "\n	-d	List documents"
+//usage:     "\n	-c	List config files"
+
+#include "libbb.h"
+#include "bb_archive.h"
+#include "rpm.h"
+
+#define RPM_CHAR_TYPE           1
+#define RPM_INT8_TYPE           2
+#define RPM_INT16_TYPE          3
+#define RPM_INT32_TYPE          4
+/* #define RPM_INT64_TYPE       5   ---- These aren't supported (yet) */
+#define RPM_STRING_TYPE         6
+#define RPM_BIN_TYPE            7
+#define RPM_STRING_ARRAY_TYPE   8
+#define RPM_I18NSTRING_TYPE     9
+
+#define TAG_NAME                1000
+#define TAG_VERSION             1001
+#define TAG_RELEASE             1002
+#define TAG_SUMMARY             1004
+#define TAG_DESCRIPTION         1005
+#define TAG_BUILDTIME           1006
+#define TAG_BUILDHOST           1007
+#define TAG_SIZE                1009
+#define TAG_VENDOR              1011
+#define TAG_LICENSE             1014
+#define TAG_PACKAGER            1015
+#define TAG_GROUP               1016
+#define TAG_URL                 1020
+#define TAG_PREIN               1023
+#define TAG_POSTIN              1024
+#define TAG_FILEFLAGS           1037
+#define TAG_FILEUSERNAME        1039
+#define TAG_FILEGROUPNAME       1040
+#define TAG_SOURCERPM           1044
+#define TAG_PREINPROG           1085
+#define TAG_POSTINPROG          1086
+#define TAG_PREFIXS             1098
+#define TAG_DIRINDEXES          1116
+#define TAG_BASENAMES           1117
+#define TAG_DIRNAMES            1118
+
+#define RPMFILE_CONFIG          (1 << 0)
+#define RPMFILE_DOC             (1 << 1)
+
+enum rpm_functions_e {
+	rpm_query = 1,
+	rpm_install = 2,
+	rpm_query_info = 4,
+	rpm_query_package = 8,
+	rpm_query_list = 16,
+	rpm_query_list_doc = 32,
+	rpm_query_list_config = 64
+};
+
+typedef struct {
+	uint32_t tag; /* 4 byte tag */
+	uint32_t type; /* 4 byte type */
+	uint32_t offset; /* 4 byte offset */
+	uint32_t count; /* 4 byte count */
+} rpm_index;
+
+static void *map;
+static rpm_index **mytags;
+static int tagcount;
+
+static void extract_cpio(int fd, const char *source_rpm);
+static rpm_index **rpm_gettags(int fd, int *num_tags);
+static int bsearch_rpmtag(const void *key, const void *item);
+static char *rpm_getstr(int tag, int itemindex);
+static int rpm_getint(int tag, int itemindex);
+static int rpm_getcount(int tag);
+static void fileaction_dobackup(char *filename, int fileref);
+static void fileaction_setowngrp(char *filename, int fileref);
+static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref));
+
+int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rpm_main(int argc, char **argv)
+{
+	int opt = 0, func = 0, rpm_fd, offset;
+	const int pagesize = getpagesize();
+
+	while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
+		switch (opt) {
+		case 'i': /* First arg: Install mode, with q: Information */
+			if (!func) func = rpm_install;
+			else func |= rpm_query_info;
+			break;
+		case 'q': /* First arg: Query mode */
+			if (func) bb_show_usage();
+			func = rpm_query;
+			break;
+		case 'p': /* Query a package */
+			func |= rpm_query_package;
+			break;
+		case 'l': /* List files in a package */
+			func |= rpm_query_list;
+			break;
+		case 'd': /* List doc files in a package (implies list) */
+			func |= rpm_query_list;
+			func |= rpm_query_list_doc;
+			break;
+		case 'c': /* List config files in a package (implies list) */
+			func |= rpm_query_list;
+			func |= rpm_query_list_config;
+			break;
+		default:
+			bb_show_usage();
+		}
+	}
+	argv += optind;
+	//argc -= optind;
+	if (!argv[0]) {
+		bb_show_usage();
+	}
+
+	while (*argv) {
+		const char *source_rpm;
+
+		rpm_fd = xopen(*argv++, O_RDONLY);
+		mytags = rpm_gettags(rpm_fd, &tagcount);
+		if (!mytags)
+			bb_error_msg_and_die("error reading rpm header");
+		offset = xlseek(rpm_fd, 0, SEEK_CUR);
+		/* Mimimum is one page */
+		map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
+
+		source_rpm = rpm_getstr(TAG_SOURCERPM, 0);
+
+		if (func & rpm_install) {
+			/* Backup any config files */
+			loop_through_files(TAG_BASENAMES, fileaction_dobackup);
+			/* Extact the archive */
+			extract_cpio(rpm_fd, source_rpm);
+			/* Set the correct file uid/gid's */
+			loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
+		}
+		else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) {
+			if (!(func & (rpm_query_info|rpm_query_list))) {
+				/* If just a straight query, just give package name */
+				printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0));
+			}
+			if (func & rpm_query_info) {
+				/* Do the nice printout */
+				time_t bdate_time;
+				struct tm *bdate_ptm;
+				char bdatestring[50];
+				const char *p;
+
+				p = rpm_getstr(TAG_PREFIXS, 0);
+				if (!p) p = "(not relocateable)";
+				printf("Name        : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), p);
+				p = rpm_getstr(TAG_VENDOR, 0);
+				if (!p) p = "(none)";
+				printf("Version     : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), p);
+				bdate_time = rpm_getint(TAG_BUILDTIME, 0);
+				bdate_ptm = localtime(&bdate_time);
+				strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm);
+				printf("Release     : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring);
+				printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0));
+				printf("Group       : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), source_rpm);
+				printf("Size        : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0));
+				printf("URL         : %s\n", rpm_getstr(TAG_URL, 0));
+				printf("Summary     : %s\n", rpm_getstr(TAG_SUMMARY, 0));
+				printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0));
+			}
+			if (func & rpm_query_list) {
+				int count, it, flags;
+				count = rpm_getcount(TAG_BASENAMES);
+				for (it = 0; it < count; it++) {
+					flags = rpm_getint(TAG_FILEFLAGS, it);
+					switch (func & (rpm_query_list_doc|rpm_query_list_config)) {
+					case rpm_query_list_doc:
+						if (!(flags & RPMFILE_DOC)) continue;
+						break;
+					case rpm_query_list_config:
+						if (!(flags & RPMFILE_CONFIG)) continue;
+						break;
+					case rpm_query_list_doc|rpm_query_list_config:
+						if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue;
+						break;
+					}
+					printf("%s%s\n",
+						rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)),
+						rpm_getstr(TAG_BASENAMES, it));
+				}
+			}
+		}
+		free(mytags);
+	}
+	return 0;
+}
+
+static void extract_cpio(int fd, const char *source_rpm)
+{
+	archive_handle_t *archive_handle;
+
+	if (source_rpm != NULL) {
+		/* Binary rpm (it was built from some SRPM), install to root */
+		xchdir("/");
+	} /* else: SRPM, install to current dir */
+
+	/* Initialize */
+	archive_handle = init_handle();
+	archive_handle->seek = seek_by_read;
+	archive_handle->action_data = data_extract_all;
+#if 0 /* For testing (rpm -i only lists the files in internal cpio): */
+	archive_handle->action_header = header_list;
+	archive_handle->action_data = data_skip;
+#endif
+	archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS
+		/* compat: overwrite existing files.
+		 * try "rpm -i foo.src.rpm" few times in a row -
+		 * standard rpm will not complain.
+		 * (TODO? real rpm creates "file;1234" and then renames it) */
+		| ARCHIVE_UNLINK_OLD;
+	archive_handle->src_fd = fd;
+	/*archive_handle->offset = 0; - init_handle() did it */
+
+	setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 1);
+	while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
+		continue;
+}
+
+static rpm_index **rpm_gettags(int fd, int *num_tags)
+{
+	/* We should never need more than 200 (shrink via realloc later) */
+	rpm_index **tags = xzalloc(200 * sizeof(tags[0]));
+	int pass, tagindex = 0;
+
+	xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */
+
+	/* 1st pass is the signature headers, 2nd is the main stuff */
+	for (pass = 0; pass < 2; pass++) {
+		struct rpm_header header;
+		rpm_index *tmpindex;
+		int storepos;
+
+		xread(fd, &header, sizeof(header));
+		if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER))
+			return NULL; /* Invalid magic, or not version 1 */
+		header.size = ntohl(header.size);
+		header.entries = ntohl(header.entries);
+		storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16;
+
+		while (header.entries--) {
+			tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex));
+			xread(fd, tmpindex, sizeof(*tmpindex));
+			tmpindex->tag = ntohl(tmpindex->tag);
+			tmpindex->type = ntohl(tmpindex->type);
+			tmpindex->count = ntohl(tmpindex->count);
+			tmpindex->offset = storepos + ntohl(tmpindex->offset);
+			if (pass == 0)
+				tmpindex->tag -= 743;
+		}
+		storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */
+		/* Skip padding to 8 byte boundary after reading signature headers */
+		if (pass == 0)
+			xlseek(fd, (-storepos) & 0x7, SEEK_CUR);
+	}
+	/* realloc tags to save space */
+	tags = xrealloc(tags, tagindex * sizeof(tags[0]));
+	*num_tags = tagindex;
+	/* All done, leave the file at the start of the gzipped cpio archive */
+	return tags;
+}
+
+static int bsearch_rpmtag(const void *key, const void *item)
+{
+	int *tag = (int *)key;
+	rpm_index **tmp = (rpm_index **) item;
+	return (*tag - tmp[0]->tag);
+}
+
+static int rpm_getcount(int tag)
+{
+	rpm_index **found;
+	found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+	if (!found)
+		return 0;
+	return found[0]->count;
+}
+
+static char *rpm_getstr(int tag, int itemindex)
+{
+	rpm_index **found;
+	found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+	if (!found || itemindex >= found[0]->count)
+		return NULL;
+	if (found[0]->type == RPM_STRING_TYPE
+	 || found[0]->type == RPM_I18NSTRING_TYPE
+	 || found[0]->type == RPM_STRING_ARRAY_TYPE
+	) {
+		int n;
+		char *tmpstr = (char *) map + found[0]->offset;
+		for (n = 0; n < itemindex; n++)
+			tmpstr = tmpstr + strlen(tmpstr) + 1;
+		return tmpstr;
+	}
+	return NULL;
+}
+
+static int rpm_getint(int tag, int itemindex)
+{
+	rpm_index **found;
+	int *tmpint; /* NB: using int8_t* would be easier to code */
+
+	/* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
+	 * it's ok to ignore it because tag won't be used as a pointer */
+	found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+	if (!found || itemindex >= found[0]->count)
+		return -1;
+
+	tmpint = (int *) ((char *) map + found[0]->offset);
+
+	if (found[0]->type == RPM_INT32_TYPE) {
+		tmpint = (int *) ((char *) tmpint + itemindex*4);
+		/*return ntohl(*tmpint);*/
+		/* int can be != int32_t */
+		return ntohl(*(int32_t*)tmpint);
+	}
+	if (found[0]->type == RPM_INT16_TYPE) {
+		tmpint = (int *) ((char *) tmpint + itemindex*2);
+		/* ??? read int, and THEN ntohs() it?? */
+		/*return ntohs(*tmpint);*/
+		return ntohs(*(int16_t*)tmpint);
+	}
+	if (found[0]->type == RPM_INT8_TYPE) {
+		tmpint = (int *) ((char *) tmpint + itemindex);
+		/* ??? why we don't read byte here??? */
+		/*return ntohs(*tmpint);*/
+		return *(int8_t*)tmpint;
+	}
+	return -1;
+}
+
+static void fileaction_dobackup(char *filename, int fileref)
+{
+	struct stat oldfile;
+	int stat_res;
+	char *newname;
+	if (rpm_getint(TAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) {
+		/* Only need to backup config files */
+		stat_res = lstat(filename, &oldfile);
+		if (stat_res == 0 && S_ISREG(oldfile.st_mode)) {
+			/* File already exists  - really should check MD5's etc to see if different */
+			newname = xasprintf("%s.rpmorig", filename);
+			copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS);
+			remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE);
+			free(newname);
+		}
+	}
+}
+
+static void fileaction_setowngrp(char *filename, int fileref)
+{
+	/* real rpm warns: "user foo does not exist - using <you>" */
+	struct passwd *pw = getpwnam(rpm_getstr(TAG_FILEUSERNAME, fileref));
+	int uid = pw ? pw->pw_uid : getuid(); /* or euid? */
+	struct group *gr = getgrnam(rpm_getstr(TAG_FILEGROUPNAME, fileref));
+	int gid = gr ? gr->gr_gid : getgid();
+	chown(filename, uid, gid);
+}
+
+static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref))
+{
+	int count = 0;
+	while (rpm_getstr(filetag, count)) {
+		char* filename = xasprintf("%s%s",
+			rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, count)),
+			rpm_getstr(TAG_BASENAMES, count));
+		fileaction(filename, count++);
+		free(filename);
+	}
+}
diff --git a/ap/app/busybox/src/archival/rpm.h b/ap/app/busybox/src/archival/rpm.h
new file mode 100644
index 0000000..afe2b55
--- /dev/null
+++ b/ap/app/busybox/src/archival/rpm.h
@@ -0,0 +1,38 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * RPM structs and consts
+ *
+ * Copyright (C) 2001 by Laurence Anderson
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* RPM file starts with this struct: */
+struct rpm_lead {
+	uint32_t magic;
+	uint8_t  major, minor;
+	uint16_t type;
+	uint16_t archnum;
+	char     name[66];
+	uint16_t osnum;
+	uint16_t signature_type;
+	char     reserved[16];
+};
+struct BUG_rpm_lead {
+	char bug[sizeof(struct rpm_lead) == 96 ? 1 : -1];
+};
+#define RPM_LEAD_MAGIC      0xedabeedb
+#define RPM_LEAD_MAGIC_STR  "\355\253\356\333"
+
+/* Then follows the header: */
+struct rpm_header {
+	uint32_t magic_and_ver; /* 3 byte magic: 0x8e 0xad 0xe8; 1 byte version: 0x01 */
+	uint32_t reserved;      /* 4 bytes reserved */
+	uint32_t entries;       /* Number of entries in header (4 bytes) */
+	uint32_t size;          /* Size of store (4 bytes) */
+};
+struct BUG_rpm_header {
+	char bug[sizeof(struct rpm_header) == 16 ? 1 : -1];
+};
+#define RPM_HEADER_MAGICnVER  0x8eade801
+#define RPM_HEADER_MAGIC_STR  "\216\255\350"
diff --git a/ap/app/busybox/src/archival/rpm2cpio.c b/ap/app/busybox/src/archival/rpm2cpio.c
new file mode 100644
index 0000000..f3dfa51
--- /dev/null
+++ b/ap/app/busybox/src/archival/rpm2cpio.c
@@ -0,0 +1,87 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini rpm2cpio implementation for busybox
+ *
+ * Copyright (C) 2001 by Laurence Anderson
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//usage:#define rpm2cpio_trivial_usage
+//usage:       "package.rpm"
+//usage:#define rpm2cpio_full_usage "\n\n"
+//usage:       "Output a cpio archive of the rpm file"
+
+#include "libbb.h"
+#include "bb_archive.h"
+#include "rpm.h"
+
+enum { rpm_fd = STDIN_FILENO };
+
+static unsigned skip_header(void)
+{
+	struct rpm_header header;
+	unsigned len;
+
+	xread(rpm_fd, &header, sizeof(header));
+//	if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC_STR, 3) != 0) {
+//		bb_error_msg_and_die("invalid RPM header magic");
+//	}
+//	if (header.version != 1) {
+//		bb_error_msg_and_die("unsupported RPM header version");
+//	}
+	if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) {
+		bb_error_msg_and_die("invalid RPM header magic or unsupported version");
+		// ": %x != %x", header.magic_and_ver, htonl(RPM_HEADER_MAGICnVER));
+	}
+
+	/* Seek past index entries, and past store */
+	len = 16 * ntohl(header.entries) + ntohl(header.size);
+	seek_by_jump(rpm_fd, len);
+
+	return sizeof(header) + len;
+}
+
+/* No getopt required */
+int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
+{
+	struct rpm_lead lead;
+	unsigned pos;
+
+	if (argv[1]) {
+		xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd);
+	}
+	xread(rpm_fd, &lead, sizeof(lead));
+
+	/* Just check the magic, the rest is irrelevant */
+	if (lead.magic != htonl(RPM_LEAD_MAGIC)) {
+		bb_error_msg_and_die("invalid RPM magic");
+	}
+
+	/* Skip the signature header, align to 8 bytes */
+	pos = skip_header();
+	seek_by_jump(rpm_fd, (-(int)pos) & 7);
+
+	/* Skip the main header */
+	skip_header();
+
+	//if (SEAMLESS_COMPRESSION)
+	//	/* We need to know whether child (gzip/bzip/etc) exits abnormally */
+	//	signal(SIGCHLD, check_errors_in_children);
+
+	/* This works, but doesn't report uncompress errors (they happen in child) */
+	setup_unzip_on_fd(rpm_fd, /*fail_if_not_detected:*/ 1);
+	if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
+		bb_error_msg_and_die("error unpacking");
+
+	if (ENABLE_FEATURE_CLEAN_UP) {
+		close(rpm_fd);
+	}
+
+	if (SEAMLESS_COMPRESSION) {
+		check_errors_in_children(0);
+		return bb_got_signal;
+	}
+	return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/archival/tar.c b/ap/app/busybox/src/archival/tar.c
new file mode 100644
index 0000000..f46f7bb
--- /dev/null
+++ b/ap/app/busybox/src/archival/tar.c
@@ -0,0 +1,1120 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini tar implementation for busybox
+ *
+ * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg
+ *  by Glenn McGrath
+ *
+ * Note, that as of BusyBox-0.43, tar has been completely rewritten from the
+ * ground up.  It still has remnants of the old code lying about, but it is
+ * very different now (i.e., cleaner, less global variables, etc.)
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Based in part in the tar implementation in sash
+ *  Copyright (c) 1999 by David I. Bell
+ *  Permission is granted to use, distribute, or modify this source,
+ *  provided that this copyright notice remains intact.
+ *  Permission to distribute sash derived code under GPL has been granted.
+ *
+ * Based in part on the tar implementation from busybox-0.28
+ *  Copyright (C) 1995 Bruce Perens
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* TODO: security with -C DESTDIR option can be enhanced.
+ * Consider tar file created via:
+ * $ tar cvf bug.tar anything.txt
+ * $ ln -s /tmp symlink
+ * $ tar --append -f bug.tar symlink
+ * $ rm symlink
+ * $ mkdir symlink
+ * $ tar --append -f bug.tar symlink/evil.py
+ *
+ * This will result in an archive which contains:
+ * $ tar --list -f bug.tar
+ * anything.txt
+ * symlink
+ * symlink/evil.py
+ *
+ * Untarring it puts evil.py in '/tmp' even if the -C DESTDIR is given.
+ * This doesn't feel right, and IIRC GNU tar doesn't do that.
+ */
+
+#include <fnmatch.h>
+#include "libbb.h"
+#include "bb_archive.h"
+/* FIXME: Stop using this non-standard feature */
+#ifndef FNM_LEADING_DIR
+# define FNM_LEADING_DIR 0
+#endif
+
+
+//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
+#define DBG(...) ((void)0)
+
+
+#define block_buf bb_common_bufsiz1
+
+
+#if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
+/* Do not pass gzip flag to writeTarFile() */
+#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \
+	writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude)
+#endif
+
+
+#if ENABLE_FEATURE_TAR_CREATE
+
+/*
+** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
+** the only functions that deal with the HardLinkInfo structure.
+** Even these functions use the xxxHardLinkInfo() functions.
+*/
+typedef struct HardLinkInfo {
+	struct HardLinkInfo *next; /* Next entry in list */
+	dev_t dev;                 /* Device number */
+	ino_t ino;                 /* Inode number */
+//	short linkCount;           /* (Hard) Link Count */
+	char name[1];              /* Start of filename (must be last) */
+} HardLinkInfo;
+
+/* Some info to be carried along when creating a new tarball */
+typedef struct TarBallInfo {
+	int tarFd;                      /* Open-for-write file descriptor
+	                                 * for the tarball */
+	int verboseFlag;                /* Whether to print extra stuff or not */
+	const llist_t *excludeList;     /* List of files to not include */
+	HardLinkInfo *hlInfoHead;       /* Hard Link Tracking Information */
+	HardLinkInfo *hlInfo;           /* Hard Link Info for the current file */
+//TODO: save only st_dev + st_ino
+	struct stat tarFileStatBuf;     /* Stat info for the tarball, letting
+	                                 * us know the inode and device that the
+	                                 * tarball lives, so we can avoid trying
+	                                 * to include the tarball into itself */
+} TarBallInfo;
+
+/* A nice enum with all the possible tar file content types */
+enum {
+	REGTYPE = '0',		/* regular file */
+	REGTYPE0 = '\0',	/* regular file (ancient bug compat) */
+	LNKTYPE = '1',		/* hard link */
+	SYMTYPE = '2',		/* symbolic link */
+	CHRTYPE = '3',		/* character special */
+	BLKTYPE = '4',		/* block special */
+	DIRTYPE = '5',		/* directory */
+	FIFOTYPE = '6',		/* FIFO special */
+	CONTTYPE = '7',		/* reserved */
+	GNULONGLINK = 'K',	/* GNU long (>100 chars) link name */
+	GNULONGNAME = 'L',	/* GNU long (>100 chars) file name */
+};
+
+/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
+static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr,
+					struct stat *statbuf,
+					const char *fileName)
+{
+	/* Note: hlInfoHeadPtr can never be NULL! */
+	HardLinkInfo *hlInfo;
+
+	hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName));
+	hlInfo->next = *hlInfoHeadPtr;
+	*hlInfoHeadPtr = hlInfo;
+	hlInfo->dev = statbuf->st_dev;
+	hlInfo->ino = statbuf->st_ino;
+//	hlInfo->linkCount = statbuf->st_nlink;
+	strcpy(hlInfo->name, fileName);
+}
+
+static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr)
+{
+	HardLinkInfo *hlInfo;
+	HardLinkInfo *hlInfoNext;
+
+	if (hlInfoHeadPtr) {
+		hlInfo = *hlInfoHeadPtr;
+		while (hlInfo) {
+			hlInfoNext = hlInfo->next;
+			free(hlInfo);
+			hlInfo = hlInfoNext;
+		}
+		*hlInfoHeadPtr = NULL;
+	}
+}
+
+/* Might be faster (and bigger) if the dev/ino were stored in numeric order ;) */
+static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf)
+{
+	while (hlInfo) {
+		if (statbuf->st_ino == hlInfo->ino
+		 && statbuf->st_dev == hlInfo->dev
+		) {
+			DBG("found hardlink:'%s'", hlInfo->name);
+			break;
+		}
+		hlInfo = hlInfo->next;
+	}
+	return hlInfo;
+}
+
+/* Put an octal string into the specified buffer.
+ * The number is zero padded and possibly null terminated.
+ * Stores low-order bits only if whole value does not fit. */
+static void putOctal(char *cp, int len, off_t value)
+{
+	char tempBuffer[sizeof(off_t)*3 + 1];
+	char *tempString = tempBuffer;
+	int width;
+
+	width = sprintf(tempBuffer, "%0*"OFF_FMT"o", len, value);
+	tempString += (width - len);
+
+	/* If string has leading zeroes, we can drop one */
+	/* and field will have trailing '\0' */
+	/* (increases chances of compat with other tars) */
+	if (tempString[0] == '0')
+		tempString++;
+
+	/* Copy the string to the field */
+	memcpy(cp, tempString, len);
+}
+#define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
+
+static void chksum_and_xwrite(int fd, struct tar_header_t* hp)
+{
+	/* POSIX says that checksum is done on unsigned bytes
+	 * (Sun and HP-UX gets it wrong... more details in
+	 * GNU tar source) */
+	const unsigned char *cp;
+	int chksum, size;
+
+	strcpy(hp->magic, "ustar  ");
+
+	/* Calculate and store the checksum (i.e., the sum of all of the bytes of
+	 * the header).  The checksum field must be filled with blanks for the
+	 * calculation.  The checksum field is formatted differently from the
+	 * other fields: it has 6 digits, a null, then a space -- rather than
+	 * digits, followed by a null like the other fields... */
+	memset(hp->chksum, ' ', sizeof(hp->chksum));
+	cp = (const unsigned char *) hp;
+	chksum = 0;
+	size = sizeof(*hp);
+	do { chksum += *cp++; } while (--size);
+	putOctal(hp->chksum, sizeof(hp->chksum)-1, chksum);
+
+	/* Now write the header out to disk */
+	xwrite(fd, hp, sizeof(*hp));
+}
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+static void writeLongname(int fd, int type, const char *name, int dir)
+{
+	static const struct {
+		char mode[8];             /* 100-107 */
+		char uid[8];              /* 108-115 */
+		char gid[8];              /* 116-123 */
+		char size[12];            /* 124-135 */
+		char mtime[12];           /* 136-147 */
+	} prefilled = {
+		"0000000",
+		"0000000",
+		"0000000",
+		"00000000000",
+		"00000000000",
+	};
+	struct tar_header_t header;
+	int size;
+
+	dir = !!dir; /* normalize: 0/1 */
+	size = strlen(name) + 1 + dir; /* GNU tar uses strlen+1 */
+	/* + dir: account for possible '/' */
+
+	memset(&header, 0, sizeof(header));
+	strcpy(header.name, "././@LongLink");
+	memcpy(header.mode, prefilled.mode, sizeof(prefilled));
+	PUT_OCTAL(header.size, size);
+	header.typeflag = type;
+	chksum_and_xwrite(fd, &header);
+
+	/* Write filename[/] and pad the block. */
+	/* dir=0: writes 'name<NUL>', pads */
+	/* dir=1: writes 'name', writes '/<NUL>', pads */
+	dir *= 2;
+	xwrite(fd, name, size - dir);
+	xwrite(fd, "/", dir);
+	size = (-size) & (TAR_BLOCK_SIZE-1);
+	memset(&header, 0, size);
+	xwrite(fd, &header, size);
+}
+#endif
+
+/* Write out a tar header for the specified file/directory/whatever */
+static int writeTarHeader(struct TarBallInfo *tbInfo,
+		const char *header_name, const char *fileName, struct stat *statbuf)
+{
+	struct tar_header_t header;
+
+	memset(&header, 0, sizeof(header));
+
+	strncpy(header.name, header_name, sizeof(header.name));
+
+	/* POSIX says to mask mode with 07777. */
+	PUT_OCTAL(header.mode, statbuf->st_mode & 07777);
+	PUT_OCTAL(header.uid, statbuf->st_uid);
+	PUT_OCTAL(header.gid, statbuf->st_gid);
+	memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */
+	/* users report that files with negative st_mtime cause trouble, so: */
+	PUT_OCTAL(header.mtime, statbuf->st_mtime >= 0 ? statbuf->st_mtime : 0);
+
+	/* Enter the user and group names */
+	safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
+	safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname));
+
+	if (tbInfo->hlInfo) {
+		/* This is a hard link */
+		header.typeflag = LNKTYPE;
+		strncpy(header.linkname, tbInfo->hlInfo->name,
+				sizeof(header.linkname));
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+		/* Write out long linkname if needed */
+		if (header.linkname[sizeof(header.linkname)-1])
+			writeLongname(tbInfo->tarFd, GNULONGLINK,
+					tbInfo->hlInfo->name, 0);
+#endif
+	} else if (S_ISLNK(statbuf->st_mode)) {
+		char *lpath = xmalloc_readlink_or_warn(fileName);
+		if (!lpath)
+			return FALSE;
+		header.typeflag = SYMTYPE;
+		strncpy(header.linkname, lpath, sizeof(header.linkname));
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+		/* Write out long linkname if needed */
+		if (header.linkname[sizeof(header.linkname)-1])
+			writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
+#else
+		/* If it is larger than 100 bytes, bail out */
+		if (header.linkname[sizeof(header.linkname)-1]) {
+			free(lpath);
+			bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
+			return FALSE;
+		}
+#endif
+		free(lpath);
+	} else if (S_ISDIR(statbuf->st_mode)) {
+		header.typeflag = DIRTYPE;
+		/* Append '/' only if there is a space for it */
+		if (!header.name[sizeof(header.name)-1])
+			header.name[strlen(header.name)] = '/';
+	} else if (S_ISCHR(statbuf->st_mode)) {
+		header.typeflag = CHRTYPE;
+		PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
+		PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
+	} else if (S_ISBLK(statbuf->st_mode)) {
+		header.typeflag = BLKTYPE;
+		PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
+		PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
+	} else if (S_ISFIFO(statbuf->st_mode)) {
+		header.typeflag = FIFOTYPE;
+	} else if (S_ISREG(statbuf->st_mode)) {
+		/* header.size field is 12 bytes long */
+		/* Does octal-encoded size fit? */
+		uoff_t filesize = statbuf->st_size;
+		if (sizeof(filesize) <= 4
+		 || filesize <= (uoff_t)0777777777777LL
+		) {
+			PUT_OCTAL(header.size, filesize);
+		}
+		/* Does base256-encoded size fit?
+		 * It always does unless off_t is wider than 64 bits.
+		 */
+		else if (ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+#if ULLONG_MAX > 0xffffffffffffffffLL /* 2^64-1 */
+		 && (filesize <= 0x3fffffffffffffffffffffffLL)
+#endif
+		) {
+			/* GNU tar uses "base-256 encoding" for very large numbers.
+			 * Encoding is binary, with highest bit always set as a marker
+			 * and sign in next-highest bit:
+			 * 80 00 .. 00 - zero
+			 * bf ff .. ff - largest positive number
+			 * ff ff .. ff - minus 1
+			 * c0 00 .. 00 - smallest negative number
+			 */
+			char *p8 = header.size + sizeof(header.size);
+			do {
+				*--p8 = (uint8_t)filesize;
+				filesize >>= 8;
+			} while (p8 != header.size);
+			*p8 |= 0x80;
+		} else {
+			bb_error_msg_and_die("can't store file '%s' "
+				"of size %"OFF_FMT"u, aborting",
+				fileName, statbuf->st_size);
+		}
+		header.typeflag = REGTYPE;
+	} else {
+		bb_error_msg("%s: unknown file type", fileName);
+		return FALSE;
+	}
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+	/* Write out long name if needed */
+	/* (we, like GNU tar, output long linkname *before* long name) */
+	if (header.name[sizeof(header.name)-1])
+		writeLongname(tbInfo->tarFd, GNULONGNAME,
+				header_name, S_ISDIR(statbuf->st_mode));
+#endif
+
+	/* Now write the header out to disk */
+	chksum_and_xwrite(tbInfo->tarFd, &header);
+
+	/* Now do the verbose thing (or not) */
+	if (tbInfo->verboseFlag) {
+		FILE *vbFd = stdout;
+
+		/* If archive goes to stdout, verbose goes to stderr */
+		if (tbInfo->tarFd == STDOUT_FILENO)
+			vbFd = stderr;
+		/* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
+		/* We don't have such excesses here: for us "v" == "vv" */
+		/* '/' is probably a GNUism */
+		fprintf(vbFd, "%s%s\n", header_name,
+				S_ISDIR(statbuf->st_mode) ? "/" : "");
+	}
+
+	return TRUE;
+}
+
+#if ENABLE_FEATURE_TAR_FROM
+static int exclude_file(const llist_t *excluded_files, const char *file)
+{
+	while (excluded_files) {
+		if (excluded_files->data[0] == '/') {
+			if (fnmatch(excluded_files->data, file,
+					FNM_PATHNAME | FNM_LEADING_DIR) == 0)
+				return 1;
+		} else {
+			const char *p;
+
+			for (p = file; p[0] != '\0'; p++) {
+				if ((p == file || p[-1] == '/')
+				 && p[0] != '/'
+				 && fnmatch(excluded_files->data, p,
+						FNM_PATHNAME | FNM_LEADING_DIR) == 0
+				) {
+					return 1;
+				}
+			}
+		}
+		excluded_files = excluded_files->link;
+	}
+
+	return 0;
+}
+#else
+# define exclude_file(excluded_files, file) 0
+#endif
+
+static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
+			void *userData, int depth UNUSED_PARAM)
+{
+	struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
+	const char *header_name;
+	int inputFileFd = -1;
+
+	DBG("writeFileToTarball('%s')", fileName);
+
+	/* Strip leading '/' and such (must be before memorizing hardlink's name) */
+	header_name = strip_unsafe_prefix(fileName);
+
+	if (header_name[0] == '\0')
+		return TRUE;
+
+	/* It is against the rules to archive a socket */
+	if (S_ISSOCK(statbuf->st_mode)) {
+		bb_error_msg("%s: socket ignored", fileName);
+		return TRUE;
+	}
+
+	/*
+	 * Check to see if we are dealing with a hard link.
+	 * If so -
+	 * Treat the first occurance of a given dev/inode as a file while
+	 * treating any additional occurances as hard links.  This is done
+	 * by adding the file information to the HardLinkInfo linked list.
+	 */
+	tbInfo->hlInfo = NULL;
+	if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) {
+		DBG("'%s': st_nlink > 1", header_name);
+		tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
+		if (tbInfo->hlInfo == NULL) {
+			DBG("'%s': addHardLinkInfo", header_name);
+			addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
+		}
+	}
+
+	/* It is a bad idea to store the archive we are in the process of creating,
+	 * so check the device and inode to be sure that this particular file isn't
+	 * the new tarball */
+	if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
+	 && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
+	) {
+		bb_error_msg("%s: file is the archive; skipping", fileName);
+		return TRUE;
+	}
+
+	if (exclude_file(tbInfo->excludeList, header_name))
+		return SKIP;
+
+#if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+	if (strlen(header_name) >= NAME_SIZE) {
+		bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
+		return TRUE;
+	}
+#endif
+
+	/* Is this a regular file? */
+	if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
+		/* open the file we want to archive, and make sure all is well */
+		inputFileFd = open_or_warn(fileName, O_RDONLY);
+		if (inputFileFd < 0) {
+			return FALSE;
+		}
+	}
+
+	/* Add an entry to the tarball */
+	if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
+		return FALSE;
+	}
+
+	/* If it was a regular file, write out the body */
+	if (inputFileFd >= 0) {
+		size_t readSize;
+		/* Write the file to the archive. */
+		/* We record size into header first, */
+		/* and then write out file. If file shrinks in between, */
+		/* tar will be corrupted. So we don't allow for that. */
+		/* NB: GNU tar 1.16 warns and pads with zeroes */
+		/* or even seeks back and updates header */
+		bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
+		////off_t readSize;
+		////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
+		////if (readSize != statbuf->st_size && readSize >= 0) {
+		////	bb_error_msg_and_die("short read from %s, aborting", fileName);
+		////}
+
+		/* Check that file did not grow in between? */
+		/* if (safe_read(inputFileFd, 1) == 1) warn but continue? */
+
+		close(inputFileFd);
+
+		/* Pad the file up to the tar block size */
+		/* (a few tricks here in the name of code size) */
+		readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
+		memset(block_buf, 0, readSize);
+		xwrite(tbInfo->tarFd, block_buf, readSize);
+	}
+
+	return TRUE;
+}
+
+#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
+# if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
+#  define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
+# endif
+/* Don't inline: vfork scares gcc and pessimizes code */
+static void NOINLINE vfork_compressor(int tar_fd, int gzip)
+{
+	pid_t gzipPid;
+# if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
+	const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
+# elif ENABLE_FEATURE_SEAMLESS_GZ
+	const char *zip_exec = "gzip";
+# else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
+	const char *zip_exec = "bzip2";
+# endif
+	// On Linux, vfork never unpauses parent early, although standard
+	// allows for that. Do we want to waste bytes checking for it?
+# define WAIT_FOR_CHILD 0
+	volatile int vfork_exec_errno = 0;
+	struct fd_pair gzipDataPipe;
+# if WAIT_FOR_CHILD
+	struct fd_pair gzipStatusPipe;
+	xpiped_pair(gzipStatusPipe);
+# endif
+	xpiped_pair(gzipDataPipe);
+
+	signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
+
+# if defined(__GNUC__) && __GNUC__
+	/* Avoid vfork clobbering */
+	(void) &zip_exec;
+# endif
+
+	gzipPid = xvfork();
+
+	if (gzipPid == 0) {
+		/* child */
+		/* NB: close _first_, then move fds! */
+		close(gzipDataPipe.wr);
+# if WAIT_FOR_CHILD
+		close(gzipStatusPipe.rd);
+		/* gzipStatusPipe.wr will close only on exec -
+		 * parent waits for this close to happen */
+		fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
+# endif
+		xmove_fd(gzipDataPipe.rd, 0);
+		xmove_fd(tar_fd, 1);
+		/* exec gzip/bzip2 program/applet */
+		BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
+		vfork_exec_errno = errno;
+		_exit(EXIT_FAILURE);
+	}
+
+	/* parent */
+	xmove_fd(gzipDataPipe.wr, tar_fd);
+	close(gzipDataPipe.rd);
+# if WAIT_FOR_CHILD
+	close(gzipStatusPipe.wr);
+	while (1) {
+		char buf;
+		int n;
+
+		/* Wait until child execs (or fails to) */
+		n = full_read(gzipStatusPipe.rd, &buf, 1);
+		if (n < 0 /* && errno == EAGAIN */)
+			continue;	/* try it again */
+	}
+	close(gzipStatusPipe.rd);
+# endif
+	if (vfork_exec_errno) {
+		errno = vfork_exec_errno;
+		bb_perror_msg_and_die("can't execute '%s'", zip_exec);
+	}
+}
+#endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
+
+
+/* gcc 4.2.1 inlines it, making code bigger */
+static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
+	int recurseFlags, const llist_t *include,
+	const llist_t *exclude, int gzip)
+{
+	int errorFlag = FALSE;
+	struct TarBallInfo tbInfo;
+
+	tbInfo.hlInfoHead = NULL;
+	tbInfo.tarFd = tar_fd;
+	tbInfo.verboseFlag = verboseFlag;
+
+	/* Store the stat info for the tarball's file, so
+	 * can avoid including the tarball into itself....  */
+	xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file");
+
+#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
+	if (gzip)
+		vfork_compressor(tbInfo.tarFd, gzip);
+#endif
+
+	tbInfo.excludeList = exclude;
+
+	/* Read the directory/files and iterate over them one at a time */
+	while (include) {
+		if (!recursive_action(include->data, recurseFlags,
+				writeFileToTarball, writeFileToTarball, &tbInfo, 0)
+		) {
+			errorFlag = TRUE;
+		}
+		include = include->link;
+	}
+	/* Write two empty blocks to the end of the archive */
+	memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
+	xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
+
+	/* To be pedantically correct, we would check if the tarball
+	 * is smaller than 20 tar blocks, and pad it if it was smaller,
+	 * but that isn't necessary for GNU tar interoperability, and
+	 * so is considered a waste of space */
+
+	/* Close so the child process (if any) will exit */
+	close(tbInfo.tarFd);
+
+	/* Hang up the tools, close up shop, head home */
+	if (ENABLE_FEATURE_CLEAN_UP)
+		freeHardLinkInfo(&tbInfo.hlInfoHead);
+
+	if (errorFlag)
+		bb_error_msg("error exit delayed from previous errors");
+
+#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
+	if (gzip) {
+		int status;
+		if (safe_waitpid(-1, &status, 0) == -1)
+			bb_perror_msg("waitpid");
+		else if (!WIFEXITED(status) || WEXITSTATUS(status))
+			/* gzip was killed or has exited with nonzero! */
+			errorFlag = TRUE;
+	}
+#endif
+	return errorFlag;
+}
+#else
+int writeTarFile(int tar_fd, int verboseFlag,
+	int recurseFlags, const llist_t *include,
+	const llist_t *exclude, int gzip);
+#endif /* FEATURE_TAR_CREATE */
+
+#if ENABLE_FEATURE_TAR_FROM
+static llist_t *append_file_list_to_list(llist_t *list)
+{
+	FILE *src_stream;
+	char *line;
+	llist_t *newlist = NULL;
+
+	while (list) {
+		src_stream = xfopen_stdin(llist_pop(&list));
+		while ((line = xmalloc_fgetline(src_stream)) != NULL) {
+			/* kill trailing '/' unless the string is just "/" */
+			char *cp = last_char_is(line, '/');
+			if (cp > line)
+				*cp = '\0';
+			llist_add_to(&newlist, line);
+		}
+		fclose(src_stream);
+	}
+	return newlist;
+}
+#else
+# define append_file_list_to_list(x) 0
+#endif
+
+//usage:#define tar_trivial_usage
+//usage:	"-[" IF_FEATURE_TAR_CREATE("c") "xt"
+//usage:	IF_FEATURE_SEAMLESS_Z("Z")
+//usage:	IF_FEATURE_SEAMLESS_GZ("z")
+//usage:	IF_FEATURE_SEAMLESS_XZ("J")
+//usage:	IF_FEATURE_SEAMLESS_BZ2("j")
+//usage:	IF_FEATURE_SEAMLESS_LZMA("a")
+//usage:	IF_FEATURE_TAR_CREATE("h")
+//usage:	IF_FEATURE_TAR_NOPRESERVE_TIME("m")
+//usage:	"vO] "
+//usage:	IF_FEATURE_TAR_FROM("[-X FILE] [-T FILE] ")
+//usage:	"[-f TARFILE] [-C DIR] [FILE]..."
+//usage:#define tar_full_usage "\n\n"
+//usage:	IF_FEATURE_TAR_CREATE("Create, extract, ")
+//usage:	IF_NOT_FEATURE_TAR_CREATE("Extract ")
+//usage:	"or list files from a tar file\n"
+//usage:     "\nOperation:"
+//usage:	IF_FEATURE_TAR_CREATE(
+//usage:     "\n	c	Create"
+//usage:	)
+//usage:     "\n	x	Extract"
+//usage:     "\n	t	List"
+//usage:     "\n	f	Name of TARFILE ('-' for stdin/out)"
+//usage:     "\n	C	Change to DIR before operation"
+//usage:     "\n	v	Verbose"
+//usage:	IF_FEATURE_SEAMLESS_Z(
+//usage:     "\n	Z	(De)compress using compress"
+//usage:	)
+//usage:	IF_FEATURE_SEAMLESS_GZ(
+//usage:     "\n	z	(De)compress using gzip"
+//usage:	)
+//usage:	IF_FEATURE_SEAMLESS_XZ(
+//usage:     "\n	J	(De)compress using xz"
+//usage:	)
+//usage:	IF_FEATURE_SEAMLESS_BZ2(
+//usage:     "\n	j	(De)compress using bzip2"
+//usage:	)
+//usage:	IF_FEATURE_SEAMLESS_LZMA(
+//usage:     "\n	a	(De)compress using lzma"
+//usage:	)
+//usage:     "\n	O	Extract to stdout"
+//usage:	IF_FEATURE_TAR_CREATE(
+//usage:     "\n	h	Follow symlinks"
+//usage:	)
+//usage:	IF_FEATURE_TAR_NOPRESERVE_TIME(
+//usage:     "\n	m	Don't restore mtime"
+//usage:	)
+//usage:	IF_FEATURE_TAR_FROM(
+//usage:	IF_FEATURE_TAR_LONG_OPTIONS(
+//usage:     "\n	exclude	File to exclude"
+//usage:	)
+//usage:     "\n	X	File with names to exclude"
+//usage:     "\n	T	File with names to include"
+//usage:	)
+//usage:
+//usage:#define tar_example_usage
+//usage:       "$ zcat /tmp/tarball.tar.gz | tar -xf -\n"
+//usage:       "$ tar -cf /tmp/tarball.tar /usr/local\n"
+
+// Supported but aren't in --help:
+//	o	no-same-owner
+//	p	same-permissions
+//	k	keep-old
+//	no-recursion
+//	numeric-owner
+//	no-same-permissions
+//	overwrite
+//IF_FEATURE_TAR_TO_COMMAND(
+//	to-command
+//)
+
+enum {
+	OPTBIT_KEEP_OLD = 8,
+	IF_FEATURE_TAR_CREATE(   OPTBIT_CREATE      ,)
+	IF_FEATURE_TAR_CREATE(   OPTBIT_DEREFERENCE ,)
+	IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2       ,)
+	IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA        ,)
+	IF_FEATURE_TAR_FROM(     OPTBIT_INCLUDE_FROM,)
+	IF_FEATURE_TAR_FROM(     OPTBIT_EXCLUDE_FROM,)
+	IF_FEATURE_SEAMLESS_GZ(  OPTBIT_GZIP        ,)
+	IF_FEATURE_SEAMLESS_XZ(  OPTBIT_XZ          ,) // 16th bit
+	IF_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,)
+	IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS
+	OPTBIT_NORECURSION,
+	IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND   ,)
+	OPTBIT_NUMERIC_OWNER,
+	OPTBIT_NOPRESERVE_PERM,
+	OPTBIT_OVERWRITE,
+#endif
+	OPT_TEST         = 1 << 0, // t
+	OPT_EXTRACT      = 1 << 1, // x
+	OPT_BASEDIR      = 1 << 2, // C
+	OPT_TARNAME      = 1 << 3, // f
+	OPT_2STDOUT      = 1 << 4, // O
+	OPT_NOPRESERVE_OWNER = 1 << 5, // o == no-same-owner
+	OPT_P            = 1 << 6, // p
+	OPT_VERBOSE      = 1 << 7, // v
+	OPT_KEEP_OLD     = 1 << 8, // k
+	OPT_CREATE       = IF_FEATURE_TAR_CREATE(   (1 << OPTBIT_CREATE      )) + 0, // c
+	OPT_DEREFERENCE  = IF_FEATURE_TAR_CREATE(   (1 << OPTBIT_DEREFERENCE )) + 0, // h
+	OPT_BZIP2        = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2       )) + 0, // j
+	OPT_LZMA         = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA        )) + 0, // a
+	OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM(     (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
+	OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM(     (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
+	OPT_GZIP         = IF_FEATURE_SEAMLESS_GZ(  (1 << OPTBIT_GZIP        )) + 0, // z
+	OPT_XZ           = IF_FEATURE_SEAMLESS_XZ(  (1 << OPTBIT_XZ          )) + 0, // J
+	OPT_COMPRESS     = IF_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
+	OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m
+	OPT_NORECURSION     = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION    )) + 0, // no-recursion
+	OPT_2COMMAND        = IF_FEATURE_TAR_TO_COMMAND(  (1 << OPTBIT_2COMMAND       )) + 0, // to-command
+	OPT_NUMERIC_OWNER   = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER  )) + 0, // numeric-owner
+	OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
+	OPT_OVERWRITE       = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE      )) + 0, // overwrite
+
+	OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_XZ | OPT_COMPRESS),
+};
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS
+static const char tar_longopts[] ALIGN1 =
+	"list\0"                No_argument       "t"
+	"extract\0"             No_argument       "x"
+	"directory\0"           Required_argument "C"
+	"file\0"                Required_argument "f"
+	"to-stdout\0"           No_argument       "O"
+	/* do not restore owner */
+	/* Note: GNU tar handles 'o' as no-same-owner only on extract,
+	 * on create, 'o' is --old-archive. We do not support --old-archive. */
+	"no-same-owner\0"       No_argument       "o"
+	"same-permissions\0"    No_argument       "p"
+	"verbose\0"             No_argument       "v"
+	"keep-old\0"            No_argument       "k"
+# if ENABLE_FEATURE_TAR_CREATE
+	"create\0"              No_argument       "c"
+	"dereference\0"         No_argument       "h"
+# endif
+# if ENABLE_FEATURE_SEAMLESS_BZ2
+	"bzip2\0"               No_argument       "j"
+# endif
+# if ENABLE_FEATURE_SEAMLESS_LZMA
+	"lzma\0"                No_argument       "a"
+# endif
+# if ENABLE_FEATURE_TAR_FROM
+	"files-from\0"          Required_argument "T"
+	"exclude-from\0"        Required_argument "X"
+# endif
+# if ENABLE_FEATURE_SEAMLESS_GZ
+	"gzip\0"                No_argument       "z"
+# endif
+# if ENABLE_FEATURE_SEAMLESS_XZ
+	"xz\0"                  No_argument       "J"
+# endif
+# if ENABLE_FEATURE_SEAMLESS_Z
+	"compress\0"            No_argument       "Z"
+# endif
+# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
+	"touch\0"               No_argument       "m"
+# endif
+	"no-recursion\0"	No_argument       "\xfa"
+# if ENABLE_FEATURE_TAR_TO_COMMAND
+	"to-command\0"		Required_argument "\xfb"
+# endif
+	/* use numeric uid/gid from tar header, not textual */
+	"numeric-owner\0"       No_argument       "\xfc"
+	/* do not restore mode */
+	"no-same-permissions\0" No_argument       "\xfd"
+	/* on unpack, open with O_TRUNC and !O_EXCL */
+	"overwrite\0"           No_argument       "\xfe"
+	/* --exclude takes next bit position in option mask, */
+	/* therefore we have to put it _after_ --no-same-permissions */
+# if ENABLE_FEATURE_TAR_FROM
+	"exclude\0"             Required_argument "\xff"
+# endif
+	;
+#endif
+
+int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tar_main(int argc UNUSED_PARAM, char **argv)
+{
+	archive_handle_t *tar_handle;
+	char *base_dir = NULL;
+	const char *tar_filename = "-";
+	unsigned opt;
+	int verboseFlag = 0;
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
+	llist_t *excludes = NULL;
+#endif
+
+	/* Initialise default values */
+	tar_handle = init_handle();
+	tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
+	                     | ARCHIVE_RESTORE_DATE
+	                     | ARCHIVE_UNLINK_OLD;
+
+	/* Apparently only root's tar preserves perms (see bug 3844) */
+	if (getuid() != 0)
+		tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
+
+	/* Prepend '-' to the first argument if required */
+	opt_complementary = "--:" // first arg is options
+		"tt:vv:" // count -t,-v
+		IF_FEATURE_TAR_FROM("X::T::") // cumulative lists
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
+		"\xff::" // cumulative lists for --exclude
+#endif
+		IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
+		IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
+		IF_NOT_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS
+	applet_long_options = tar_longopts;
+#endif
+#if ENABLE_DESKTOP
+	if (argv[1] && argv[1][0] != '-') {
+		/* Compat:
+		 * 1st argument without dash handles options with parameters
+		 * differently from dashed one: it takes *next argv[i]*
+		 * as paramenter even if there are more chars in 1st argument:
+		 *  "tar fx TARFILE" - "x" is not taken as f's param
+		 *  but is interpreted as -x option
+		 *  "tar -xf TARFILE" - dashed equivalent of the above
+		 *  "tar -fx ..." - "x" is taken as f's param
+		 * getopt32 wouldn't handle 1st command correctly.
+		 * Unfortunately, people do use such commands.
+		 * We massage argv[1] to work around it by moving 'f'
+		 * to the end of the string.
+		 * More contrived "tar fCx TARFILE DIR" still fails,
+		 * but such commands are much less likely to be used.
+		 */
+		char *f = strchr(argv[1], 'f');
+		if (f) {
+			while (f[1] != '\0') {
+				*f = f[1];
+				f++;
+			}
+			*f = 'f';
+		}
+	}
+#endif
+	opt = getopt32(argv,
+		"txC:f:Oopvk"
+		IF_FEATURE_TAR_CREATE(   "ch"  )
+		IF_FEATURE_SEAMLESS_BZ2( "j"   )
+		IF_FEATURE_SEAMLESS_LZMA("a"   )
+		IF_FEATURE_TAR_FROM(     "T:X:")
+		IF_FEATURE_SEAMLESS_GZ(  "z"   )
+		IF_FEATURE_SEAMLESS_XZ(  "J"   )
+		IF_FEATURE_SEAMLESS_Z(   "Z"   )
+		IF_FEATURE_TAR_NOPRESERVE_TIME("m")
+		, &base_dir // -C dir
+		, &tar_filename // -f filename
+		IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
+		IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
+		IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
+		, &excludes // --exclude
+#endif
+		, &verboseFlag // combined count for -t and -v
+		, &verboseFlag // combined count for -t and -v
+		);
+	//bb_error_msg("opt:%08x", opt);
+	argv += optind;
+
+	if (verboseFlag) tar_handle->action_header = header_verbose_list;
+	if (verboseFlag == 1) tar_handle->action_header = header_list;
+
+	if (opt & OPT_EXTRACT)
+		tar_handle->action_data = data_extract_all;
+
+	if (opt & OPT_2STDOUT)
+		tar_handle->action_data = data_extract_to_stdout;
+
+	if (opt & OPT_2COMMAND) {
+		putenv((char*)"TAR_FILETYPE=f");
+		signal(SIGPIPE, SIG_IGN);
+		tar_handle->action_data = data_extract_to_command;
+		IF_FEATURE_TAR_TO_COMMAND(tar_handle->tar__to_command_shell = xstrdup(get_shell_name());)
+	}
+
+	if (opt & OPT_KEEP_OLD)
+		tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
+
+	if (opt & OPT_NUMERIC_OWNER)
+		tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER;
+
+	if (opt & OPT_NOPRESERVE_OWNER)
+		tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER;
+
+	if (opt & OPT_NOPRESERVE_PERM)
+		tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
+
+	if (opt & OPT_OVERWRITE) {
+		tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
+		tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
+	}
+
+	if (opt & OPT_NOPRESERVE_TIME)
+		tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
+
+#if ENABLE_FEATURE_TAR_FROM
+	tar_handle->reject = append_file_list_to_list(tar_handle->reject);
+# if ENABLE_FEATURE_TAR_LONG_OPTIONS
+	/* Append excludes to reject */
+	while (excludes) {
+		llist_t *next = excludes->link;
+		excludes->link = tar_handle->reject;
+		tar_handle->reject = excludes;
+		excludes = next;
+	}
+# endif
+	tar_handle->accept = append_file_list_to_list(tar_handle->accept);
+#endif
+
+	/* Setup an array of filenames to work with */
+	/* TODO: This is the same as in ar, make a separate function? */
+	while (*argv) {
+		/* kill trailing '/' unless the string is just "/" */
+		char *cp = last_char_is(*argv, '/');
+		if (cp > *argv)
+			*cp = '\0';
+		llist_add_to_end(&tar_handle->accept, *argv);
+		argv++;
+	}
+
+	if (tar_handle->accept || tar_handle->reject)
+		tar_handle->filter = filter_accept_reject_list;
+
+	/* Open the tar file */
+	{
+		int tar_fd = STDIN_FILENO;
+		int flags = O_RDONLY;
+
+		if (opt & OPT_CREATE) {
+			/* Make sure there is at least one file to tar up */
+			if (tar_handle->accept == NULL)
+				bb_error_msg_and_die("empty archive");
+
+			tar_fd = STDOUT_FILENO;
+			/* Mimicking GNU tar 1.15.1: */
+			flags = O_WRONLY | O_CREAT | O_TRUNC;
+		}
+
+		if (LONE_DASH(tar_filename)) {
+			tar_handle->src_fd = tar_fd;
+			tar_handle->seek = seek_by_read;
+		} else {
+			if (ENABLE_FEATURE_TAR_AUTODETECT
+			 && flags == O_RDONLY
+			 && !(opt & OPT_ANY_COMPRESS)
+			) {
+				tar_handle->src_fd = open_zipped(tar_filename);
+				if (tar_handle->src_fd < 0)
+					bb_perror_msg_and_die("can't open '%s'", tar_filename);
+			} else {
+				tar_handle->src_fd = xopen(tar_filename, flags);
+			}
+		}
+	}
+
+	if (base_dir)
+		xchdir(base_dir);
+
+	//if (SEAMLESS_COMPRESSION || OPT_COMPRESS)
+	//	/* We need to know whether child (gzip/bzip/etc) exits abnormally */
+	//	signal(SIGCHLD, check_errors_in_children);
+
+	/* Create an archive */
+	if (opt & OPT_CREATE) {
+#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
+		int zipMode = 0;
+		if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP))
+			zipMode = 1;
+		if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2))
+			zipMode = 2;
+#endif
+		/* NB: writeTarFile() closes tar_handle->src_fd */
+		return writeTarFile(tar_handle->src_fd, verboseFlag,
+				(opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0)
+				| (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE),
+				tar_handle->accept,
+				tar_handle->reject, zipMode);
+	}
+
+	if (opt & OPT_ANY_COMPRESS) {
+		USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);)
+		USE_FOR_NOMMU(const char *xformer_prog;)
+
+		if (opt & OPT_COMPRESS)
+			USE_FOR_MMU(xformer = unpack_Z_stream;)
+			USE_FOR_NOMMU(xformer_prog = "uncompress";)
+		if (opt & OPT_GZIP)
+			USE_FOR_MMU(xformer = unpack_gz_stream;)
+			USE_FOR_NOMMU(xformer_prog = "gunzip";)
+		if (opt & OPT_BZIP2)
+			USE_FOR_MMU(xformer = unpack_bz2_stream;)
+			USE_FOR_NOMMU(xformer_prog = "bunzip2";)
+		if (opt & OPT_LZMA)
+			USE_FOR_MMU(xformer = unpack_lzma_stream;)
+			USE_FOR_NOMMU(xformer_prog = "unlzma";)
+		if (opt & OPT_XZ)
+			USE_FOR_MMU(xformer = unpack_xz_stream;)
+			USE_FOR_NOMMU(xformer_prog = "unxz";)
+
+		open_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
+		/* Can't lseek over pipes */
+		tar_handle->seek = seek_by_read;
+		/*tar_handle->offset = 0; - already is */
+	}
+
+	while (get_header_tar(tar_handle) == EXIT_SUCCESS)
+		continue;
+
+	/* Check that every file that should have been extracted was */
+	while (tar_handle->accept) {
+		if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
+		 && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
+		) {
+			bb_error_msg_and_die("%s: not found in archive",
+				tar_handle->accept->data);
+		}
+		tar_handle->accept = tar_handle->accept->link;
+	}
+	if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
+		close(tar_handle->src_fd);
+
+	if (SEAMLESS_COMPRESSION || OPT_COMPRESS) {
+		check_errors_in_children(0);
+		return bb_got_signal;
+	}
+	return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/archival/unzip.c b/ap/app/busybox/src/archival/unzip.c
new file mode 100644
index 0000000..046027c
--- /dev/null
+++ b/ap/app/busybox/src/archival/unzip.c
@@ -0,0 +1,709 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini unzip implementation for busybox
+ *
+ * Copyright (C) 2004 by Ed Clark
+ *
+ * Loosely based on original busybox unzip applet by Laurence Anderson.
+ * All options and features should work in this version.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* For reference see
+ * http://www.pkware.com/company/standards/appnote/
+ * http://www.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+ */
+
+/* TODO
+ * Zip64 + other methods
+ */
+
+//usage:#define unzip_trivial_usage
+//usage:       "[-lnopq] FILE[.zip] [FILE]... [-x FILE...] [-d DIR]"
+//usage:#define unzip_full_usage "\n\n"
+//usage:       "Extract FILEs from ZIP archive\n"
+//usage:     "\n	-l	List contents (with -q for short form)"
+//usage:     "\n	-n	Never overwrite files (default: ask)"
+//usage:     "\n	-o	Overwrite"
+//usage:     "\n	-p	Print to stdout"
+//usage:     "\n	-q	Quiet"
+//usage:     "\n	-x FILE	Exclude FILEs"
+//usage:     "\n	-d DIR	Extract into DIR"
+
+#include "libbb.h"
+#include "bb_archive.h"
+
+enum {
+#if BB_BIG_ENDIAN
+	ZIP_FILEHEADER_MAGIC = 0x504b0304,
+	ZIP_CDF_MAGIC        = 0x504b0102, /* central directory's file header */
+	ZIP_CDE_MAGIC        = 0x504b0506, /* "end of central directory" record */
+	ZIP_DD_MAGIC         = 0x504b0708,
+#else
+	ZIP_FILEHEADER_MAGIC = 0x04034b50,
+	ZIP_CDF_MAGIC        = 0x02014b50,
+	ZIP_CDE_MAGIC        = 0x06054b50,
+	ZIP_DD_MAGIC         = 0x08074b50,
+#endif
+};
+
+#define ZIP_HEADER_LEN 26
+
+typedef union {
+	uint8_t raw[ZIP_HEADER_LEN];
+	struct {
+		uint16_t version;               /* 0-1 */
+		uint16_t zip_flags;             /* 2-3 */
+		uint16_t method;                /* 4-5 */
+		uint16_t modtime;               /* 6-7 */
+		uint16_t moddate;               /* 8-9 */
+		uint32_t crc32 PACKED;          /* 10-13 */
+		uint32_t cmpsize PACKED;        /* 14-17 */
+		uint32_t ucmpsize PACKED;       /* 18-21 */
+		uint16_t filename_len;          /* 22-23 */
+		uint16_t extra_len;             /* 24-25 */
+	} formatted PACKED;
+} zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */
+
+/* Check the offset of the last element, not the length.  This leniency
+ * allows for poor packing, whereby the overall struct may be too long,
+ * even though the elements are all in the right place.
+ */
+struct BUG_zip_header_must_be_26_bytes {
+	char BUG_zip_header_must_be_26_bytes[
+		offsetof(zip_header_t, formatted.extra_len) + 2
+			== ZIP_HEADER_LEN ? 1 : -1];
+};
+
+#define FIX_ENDIANNESS_ZIP(zip_header) do { \
+	(zip_header).formatted.version      = SWAP_LE16((zip_header).formatted.version     ); \
+	(zip_header).formatted.method       = SWAP_LE16((zip_header).formatted.method      ); \
+	(zip_header).formatted.modtime      = SWAP_LE16((zip_header).formatted.modtime     ); \
+	(zip_header).formatted.moddate      = SWAP_LE16((zip_header).formatted.moddate     ); \
+	(zip_header).formatted.crc32        = SWAP_LE32((zip_header).formatted.crc32       ); \
+	(zip_header).formatted.cmpsize      = SWAP_LE32((zip_header).formatted.cmpsize     ); \
+	(zip_header).formatted.ucmpsize     = SWAP_LE32((zip_header).formatted.ucmpsize    ); \
+	(zip_header).formatted.filename_len = SWAP_LE16((zip_header).formatted.filename_len); \
+	(zip_header).formatted.extra_len    = SWAP_LE16((zip_header).formatted.extra_len   ); \
+} while (0)
+
+#define CDF_HEADER_LEN 42
+
+typedef union {
+	uint8_t raw[CDF_HEADER_LEN];
+	struct {
+		/* uint32_t signature; 50 4b 01 02 */
+		uint16_t version_made_by;       /* 0-1 */
+		uint16_t version_needed;        /* 2-3 */
+		uint16_t cdf_flags;             /* 4-5 */
+		uint16_t method;                /* 6-7 */
+		uint16_t mtime;                 /* 8-9 */
+		uint16_t mdate;                 /* 10-11 */
+		uint32_t crc32;                 /* 12-15 */
+		uint32_t cmpsize;               /* 16-19 */
+		uint32_t ucmpsize;              /* 20-23 */
+		uint16_t file_name_length;      /* 24-25 */
+		uint16_t extra_field_length;    /* 26-27 */
+		uint16_t file_comment_length;   /* 28-29 */
+		uint16_t disk_number_start;     /* 30-31 */
+		uint16_t internal_file_attributes; /* 32-33 */
+		uint32_t external_file_attributes PACKED; /* 34-37 */
+		uint32_t relative_offset_of_local_header PACKED; /* 38-41 */
+	} formatted PACKED;
+} cdf_header_t;
+
+struct BUG_cdf_header_must_be_42_bytes {
+	char BUG_cdf_header_must_be_42_bytes[
+		offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4
+			== CDF_HEADER_LEN ? 1 : -1];
+};
+
+#define FIX_ENDIANNESS_CDF(cdf_header) do { \
+	(cdf_header).formatted.crc32        = SWAP_LE32((cdf_header).formatted.crc32       ); \
+	(cdf_header).formatted.cmpsize      = SWAP_LE32((cdf_header).formatted.cmpsize     ); \
+	(cdf_header).formatted.ucmpsize     = SWAP_LE32((cdf_header).formatted.ucmpsize    ); \
+	(cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \
+	(cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \
+	(cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \
+	IF_DESKTOP( \
+	(cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \
+	(cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \
+	) \
+} while (0)
+
+#define CDE_HEADER_LEN 16
+
+typedef union {
+	uint8_t raw[CDE_HEADER_LEN];
+	struct {
+		/* uint32_t signature; 50 4b 05 06 */
+		uint16_t this_disk_no;
+		uint16_t disk_with_cdf_no;
+		uint16_t cdf_entries_on_this_disk;
+		uint16_t cdf_entries_total;
+		uint32_t cdf_size;
+		uint32_t cdf_offset;
+		/* uint16_t file_comment_length; */
+		/* .ZIP file comment (variable size) */
+	} formatted PACKED;
+} cde_header_t;
+
+struct BUG_cde_header_must_be_16_bytes {
+	char BUG_cde_header_must_be_16_bytes[
+		sizeof(cde_header_t) == CDE_HEADER_LEN ? 1 : -1];
+};
+
+#define FIX_ENDIANNESS_CDE(cde_header) do { \
+	(cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \
+} while (0)
+
+enum { zip_fd = 3 };
+
+
+#if ENABLE_DESKTOP
+
+#define PEEK_FROM_END 16384
+
+/* NB: does not preserve file position! */
+static uint32_t find_cdf_offset(void)
+{
+	cde_header_t cde_header;
+	unsigned char *p;
+	off_t end;
+	unsigned char *buf = xzalloc(PEEK_FROM_END);
+
+	end = xlseek(zip_fd, 0, SEEK_END);
+	end -= PEEK_FROM_END;
+	if (end < 0)
+		end = 0;
+	xlseek(zip_fd, end, SEEK_SET);
+	full_read(zip_fd, buf, PEEK_FROM_END);
+
+	p = buf;
+	while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) {
+		if (*p != 'P') {
+			p++;
+			continue;
+		}
+		if (*++p != 'K')
+			continue;
+		if (*++p != 5)
+			continue;
+		if (*++p != 6)
+			continue;
+		/* we found CDE! */
+		memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN);
+		FIX_ENDIANNESS_CDE(cde_header);
+		free(buf);
+		return cde_header.formatted.cdf_offset;
+	}
+	//free(buf);
+	bb_error_msg_and_die("can't find file table");
+};
+
+static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
+{
+	off_t org;
+
+	org = xlseek(zip_fd, 0, SEEK_CUR);
+
+	if (!cdf_offset)
+		cdf_offset = find_cdf_offset();
+
+	xlseek(zip_fd, cdf_offset + 4, SEEK_SET);
+	xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN);
+	FIX_ENDIANNESS_CDF(*cdf_ptr);
+	cdf_offset += 4 + CDF_HEADER_LEN
+		+ cdf_ptr->formatted.file_name_length
+		+ cdf_ptr->formatted.extra_field_length
+		+ cdf_ptr->formatted.file_comment_length;
+
+	xlseek(zip_fd, org, SEEK_SET);
+	return cdf_offset;
+};
+#endif
+
+static void unzip_skip(off_t skip)
+{
+	if (lseek(zip_fd, skip, SEEK_CUR) == (off_t)-1)
+		bb_copyfd_exact_size(zip_fd, -1, skip);
+}
+
+static void unzip_create_leading_dirs(const char *fn)
+{
+	/* Create all leading directories */
+	char *name = xstrdup(fn);
+	if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) {
+		xfunc_die(); /* bb_make_directory is noisy */
+	}
+	free(name);
+}
+
+static void unzip_extract(zip_header_t *zip_header, int dst_fd)
+{
+	if (zip_header->formatted.method == 0) {
+		/* Method 0 - stored (not compressed) */
+		off_t size = zip_header->formatted.ucmpsize;
+		if (size)
+			bb_copyfd_exact_size(zip_fd, dst_fd, size);
+	} else {
+		/* Method 8 - inflate */
+		transformer_aux_data_t aux;
+		init_transformer_aux_data(&aux);
+		aux.bytes_in = zip_header->formatted.cmpsize;
+		if (inflate_unzip(&aux, zip_fd, dst_fd) < 0)
+			bb_error_msg_and_die("inflate error");
+		/* Validate decompression - crc */
+		if (zip_header->formatted.crc32 != (aux.crc32 ^ 0xffffffffL)) {
+			bb_error_msg_and_die("crc error");
+		}
+		/* Validate decompression - size */
+		if (zip_header->formatted.ucmpsize != aux.bytes_out) {
+			/* Don't die. Who knows, maybe len calculation
+			 * was botched somewhere. After all, crc matched! */
+			bb_error_msg("bad length");
+		}
+	}
+}
+
+int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int unzip_main(int argc, char **argv)
+{
+	enum { O_PROMPT, O_NEVER, O_ALWAYS };
+
+	zip_header_t zip_header;
+	smallint quiet = 0;
+	IF_NOT_DESKTOP(const) smallint verbose = 0;
+	smallint listing = 0;
+	smallint overwrite = O_PROMPT;
+	smallint x_opt_seen;
+#if ENABLE_DESKTOP
+	uint32_t cdf_offset;
+#endif
+	unsigned long total_usize;
+	unsigned long total_size;
+	unsigned total_entries;
+	int dst_fd = -1;
+	char *src_fn = NULL;
+	char *dst_fn = NULL;
+	llist_t *zaccept = NULL;
+	llist_t *zreject = NULL;
+	char *base_dir = NULL;
+	int i, opt;
+	char key_buf[80];
+	struct stat stat_buf;
+
+/* -q, -l and -v: UnZip 5.52 of 28 February 2005, by Info-ZIP:
+ *
+ * # /usr/bin/unzip -qq -v decompress_unlzma.i.zip
+ *   204372  Defl:N    35278  83%  09-06-09 14:23  0d056252  decompress_unlzma.i
+ * # /usr/bin/unzip -q -v decompress_unlzma.i.zip
+ *  Length   Method    Size  Ratio   Date   Time   CRC-32    Name
+ * --------  ------  ------- -----   ----   ----   ------    ----
+ *   204372  Defl:N    35278  83%  09-06-09 14:23  0d056252  decompress_unlzma.i
+ * --------          -------  ---                            -------
+ *   204372            35278  83%                            1 file
+ * # /usr/bin/unzip -v decompress_unlzma.i.zip
+ * Archive:  decompress_unlzma.i.zip
+ *  Length   Method    Size  Ratio   Date   Time   CRC-32    Name
+ * --------  ------  ------- -----   ----   ----   ------    ----
+ *   204372  Defl:N    35278  83%  09-06-09 14:23  0d056252  decompress_unlzma.i
+ * --------          -------  ---                            -------
+ *   204372            35278  83%                            1 file
+ * # unzip -v decompress_unlzma.i.zip
+ * Archive:  decompress_unlzma.i.zip
+ *   Length     Date   Time    Name
+ *  --------    ----   ----    ----
+ *    204372  09-06-09 14:23   decompress_unlzma.i
+ *  --------                   -------
+ *    204372                   1 files
+ * # /usr/bin/unzip -l -qq decompress_unlzma.i.zip
+ *    204372  09-06-09 14:23   decompress_unlzma.i
+ * # /usr/bin/unzip -l -q decompress_unlzma.i.zip
+ *   Length     Date   Time    Name
+ *  --------    ----   ----    ----
+ *    204372  09-06-09 14:23   decompress_unlzma.i
+ *  --------                   -------
+ *    204372                   1 file
+ * # /usr/bin/unzip -l decompress_unlzma.i.zip
+ * Archive:  decompress_unlzma.i.zip
+ *   Length     Date   Time    Name
+ *  --------    ----   ----    ----
+ *    204372  09-06-09 14:23   decompress_unlzma.i
+ *  --------                   -------
+ *    204372                   1 file
+ */
+
+	x_opt_seen = 0;
+	/* '-' makes getopt return 1 for non-options */
+	while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) {
+		switch (opt) {
+		case 'd':  /* Extract to base directory */
+			base_dir = optarg;
+			break;
+
+		case 'l': /* List */
+			listing = 1;
+			break;
+
+		case 'n': /* Never overwrite existing files */
+			overwrite = O_NEVER;
+			break;
+
+		case 'o': /* Always overwrite existing files */
+			overwrite = O_ALWAYS;
+			break;
+
+		case 'p': /* Extract files to stdout and fall through to set verbosity */
+			dst_fd = STDOUT_FILENO;
+
+		case 'q': /* Be quiet */
+			quiet++;
+			break;
+
+		case 'v': /* Verbose list */
+			IF_DESKTOP(verbose++;)
+			listing = 1;
+			break;
+
+		case 'x':
+			x_opt_seen = 1;
+			break;
+
+		case 1:
+			if (!src_fn) {
+				/* The zip file */
+				/* +5: space for ".zip" and NUL */
+				src_fn = xmalloc(strlen(optarg) + 5);
+				strcpy(src_fn, optarg);
+			} else if (!x_opt_seen) {
+				/* Include files */
+				llist_add_to(&zaccept, optarg);
+			} else {
+				/* Exclude files */
+				llist_add_to(&zreject, optarg);
+			}
+			break;
+
+		default:
+			bb_show_usage();
+		}
+	}
+
+#ifndef __GLIBC__
+	/*
+	 * This code is needed for non-GNU getopt
+	 * which doesn't understand "-" in option string.
+	 * The -x option won't work properly in this case:
+	 * "unzip a.zip q -x w e" will be interpreted as
+	 * "unzip a.zip q w e -x" = "unzip a.zip q w e"
+	 */
+	argv += optind;
+	if (argv[0]) {
+		/* +5: space for ".zip" and NUL */
+		src_fn = xmalloc(strlen(argv[0]) + 5);
+		strcpy(src_fn, argv[0]);
+		while (*++argv)
+			llist_add_to(&zaccept, *argv);
+	}
+#endif
+
+	if (!src_fn) {
+		bb_show_usage();
+	}
+
+	/* Open input file */
+	if (LONE_DASH(src_fn)) {
+		xdup2(STDIN_FILENO, zip_fd);
+		/* Cannot use prompt mode since zip data is arriving on STDIN */
+		if (overwrite == O_PROMPT)
+			overwrite = O_NEVER;
+	} else {
+		static const char extn[][5] = { ".zip", ".ZIP" };
+		char *ext = src_fn + strlen(src_fn);
+		int src_fd;
+
+		i = 0;
+		for (;;) {
+			src_fd = open(src_fn, O_RDONLY);
+			if (src_fd >= 0)
+				break;
+			if (++i > 2) {
+				*ext = '\0';
+				bb_error_msg_and_die("can't open %s[.zip]", src_fn);
+			}
+			strcpy(ext, extn[i - 1]);
+		}
+		xmove_fd(src_fd, zip_fd);
+	}
+
+	/* Change dir if necessary */
+	if (base_dir)
+		xchdir(base_dir);
+
+	if (quiet <= 1) { /* not -qq */
+		if (quiet == 0)
+			printf("Archive:  %s\n", src_fn);
+		if (listing) {
+			puts(verbose ?
+				" Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n"
+				"--------  ------  ------- -----   ----   ----   ------    ----"
+				:
+				"  Length     Date   Time    Name\n"
+				" --------    ----   ----    ----"
+				);
+		}
+	}
+
+/* Example of an archive with one 0-byte long file named 'z'
+ * created by Zip 2.31 on Unix:
+ * 0000 [50 4b]03 04 0a 00 00 00 00 00 42 1a b8 3c 00 00 |PK........B..<..|
+ *       sig........ vneed flags compr mtime mdate crc32>
+ * 0010  00 00 00 00 00 00 00 00 00 00 01 00 15 00 7a 55 |..............zU|
+ *      >..... csize...... usize...... fnlen exlen fn ex>
+ * 0020  54 09 00 03 cc d3 f9 4b cc d3 f9 4b 55 78 04 00 |T......K...KUx..|
+ *      >tra_field......................................
+ * 0030  00 00 00 00[50 4b]01 02 17 03 0a 00 00 00 00 00 |....PK..........|
+ *       ........... sig........ vmade vneed flags compr
+ * 0040  42 1a b8 3c 00 00 00 00 00 00 00 00 00 00 00 00 |B..<............|
+ *       mtime mdate crc32...... csize...... usize......
+ * 0050  01 00 0d 00 00 00 00 00 00 00 00 00 a4 81 00 00 |................|
+ *       fnlen exlen clen. dnum. iattr eattr...... relofs> (eattr = rw-r--r--)
+ * 0060  00 00 7a 55 54 05 00 03 cc d3 f9 4b 55 78 00 00 |..zUT......KUx..|
+ *      >..... fn extra_field...........................
+ * 0070 [50 4b]05 06 00 00 00 00 01 00 01 00 3c 00 00 00 |PK..........<...|
+ * 0080  34 00 00 00 00 00                               |4.....|
+ */
+	total_usize = 0;
+	total_size = 0;
+	total_entries = 0;
+#if ENABLE_DESKTOP
+	cdf_offset = 0;
+#endif
+	while (1) {
+		uint32_t magic;
+		mode_t dir_mode = 0777;
+#if ENABLE_DESKTOP
+		mode_t file_mode = 0666;
+#endif
+
+		/* Check magic number */
+		xread(zip_fd, &magic, 4);
+		/* Central directory? It's at the end, so exit */
+		if (magic == ZIP_CDF_MAGIC)
+			break;
+#if ENABLE_DESKTOP
+		/* Data descriptor? It was a streaming file, go on */
+		if (magic == ZIP_DD_MAGIC) {
+			/* skip over duplicate crc32, cmpsize and ucmpsize */
+			unzip_skip(3 * 4);
+			continue;
+		}
+#endif
+		if (magic != ZIP_FILEHEADER_MAGIC)
+			bb_error_msg_and_die("invalid zip magic %08X", (int)magic);
+
+		/* Read the file header */
+		xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN);
+		FIX_ENDIANNESS_ZIP(zip_header);
+		if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) {
+			bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);
+		}
+#if !ENABLE_DESKTOP
+		if (zip_header.formatted.zip_flags & SWAP_LE16(0x0009)) {
+			bb_error_msg_and_die("zip flags 1 and 8 are not supported");
+		}
+#else
+		if (zip_header.formatted.zip_flags & SWAP_LE16(0x0001)) {
+			/* 0x0001 - encrypted */
+			bb_error_msg_and_die("zip flag 1 (encryption) is not supported");
+		}
+
+		{
+			cdf_header_t cdf_header;
+			cdf_offset = read_next_cdf(cdf_offset, &cdf_header);
+			if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) {
+				/* 0x0008 - streaming. [u]cmpsize can be reliably gotten
+				 * only from Central Directory. See unzip_doc.txt */
+				zip_header.formatted.crc32    = cdf_header.formatted.crc32;
+				zip_header.formatted.cmpsize  = cdf_header.formatted.cmpsize;
+				zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize;
+			}
+			if ((cdf_header.formatted.version_made_by >> 8) == 3) {
+				/* this archive is created on Unix */
+				dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16);
+			}
+		}
+#endif
+
+		/* Read filename */
+		free(dst_fn);
+		dst_fn = xzalloc(zip_header.formatted.filename_len + 1);
+		xread(zip_fd, dst_fn, zip_header.formatted.filename_len);
+
+		/* Skip extra header bytes */
+		unzip_skip(zip_header.formatted.extra_len);
+
+		/* Filter zip entries */
+		if (find_list_entry(zreject, dst_fn)
+		 || (zaccept && !find_list_entry(zaccept, dst_fn))
+		) { /* Skip entry */
+			i = 'n';
+
+		} else { /* Extract entry */
+			if (listing) { /* List entry */
+				unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);
+				if (!verbose) {
+					//      "  Length     Date   Time    Name\n"
+					//      " --------    ----   ----    ----"
+					printf(       "%9u  %02u-%02u-%02u %02u:%02u   %s\n",
+						(unsigned)zip_header.formatted.ucmpsize,
+						(dostime & 0x01e00000) >> 21,
+						(dostime & 0x001f0000) >> 16,
+						(((dostime & 0xfe000000) >> 25) + 1980) % 100,
+						(dostime & 0x0000f800) >> 11,
+						(dostime & 0x000007e0) >> 5,
+						dst_fn);
+					total_usize += zip_header.formatted.ucmpsize;
+				} else {
+					unsigned long percents = zip_header.formatted.ucmpsize - zip_header.formatted.cmpsize;
+					percents = percents * 100;
+					if (zip_header.formatted.ucmpsize)
+						percents /= zip_header.formatted.ucmpsize;
+					//      " Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n"
+					//      "--------  ------  ------- -----   ----   ----   ------    ----"
+					printf(      "%8u  Defl:N"    "%9u%4u%%  %02u-%02u-%02u %02u:%02u  %08x  %s\n",
+						(unsigned)zip_header.formatted.ucmpsize,
+						(unsigned)zip_header.formatted.cmpsize,
+						(unsigned)percents,
+						(dostime & 0x01e00000) >> 21,
+						(dostime & 0x001f0000) >> 16,
+						(((dostime & 0xfe000000) >> 25) + 1980) % 100,
+						(dostime & 0x0000f800) >> 11,
+						(dostime & 0x000007e0) >> 5,
+						zip_header.formatted.crc32,
+						dst_fn);
+					total_usize += zip_header.formatted.ucmpsize;
+					total_size += zip_header.formatted.cmpsize;
+				}
+				i = 'n';
+			} else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */
+				i = -1;
+			} else if (last_char_is(dst_fn, '/')) { /* Extract directory */
+				if (stat(dst_fn, &stat_buf) == -1) {
+					if (errno != ENOENT) {
+						bb_perror_msg_and_die("can't stat '%s'", dst_fn);
+					}
+					if (!quiet) {
+						printf("   creating: %s\n", dst_fn);
+					}
+					unzip_create_leading_dirs(dst_fn);
+					if (bb_make_directory(dst_fn, dir_mode, FILEUTILS_IGNORE_CHMOD_ERR)) {
+						xfunc_die();
+					}
+				} else {
+					if (!S_ISDIR(stat_buf.st_mode)) {
+						bb_error_msg_and_die("'%s' exists but is not directory", dst_fn);
+					}
+				}
+				i = 'n';
+
+			} else {  /* Extract file */
+ check_file:
+				if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */
+					if (errno != ENOENT) {
+						bb_perror_msg_and_die("can't stat '%s'", dst_fn);
+					}
+					i = 'y';
+				} else { /* File already exists */
+					if (overwrite == O_NEVER) {
+						i = 'n';
+					} else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */
+						if (overwrite == O_ALWAYS) {
+							i = 'y';
+						} else {
+							printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
+							fflush_all();
+							if (!fgets(key_buf, sizeof(key_buf), stdin)) {
+								bb_perror_msg_and_die("can't read input");
+							}
+							i = key_buf[0];
+						}
+					} else { /* File is not regular file */
+						bb_error_msg_and_die("'%s' exists but is not regular file", dst_fn);
+					}
+				}
+			}
+		}
+
+		switch (i) {
+		case 'A':
+			overwrite = O_ALWAYS;
+		case 'y': /* Open file and fall into unzip */
+			unzip_create_leading_dirs(dst_fn);
+#if ENABLE_DESKTOP
+			dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode);
+#else
+			dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
+#endif
+		case -1: /* Unzip */
+			if (!quiet) {
+				printf("  inflating: %s\n", dst_fn);
+			}
+			unzip_extract(&zip_header, dst_fd);
+			if (dst_fd != STDOUT_FILENO) {
+				/* closing STDOUT is potentially bad for future business */
+				close(dst_fd);
+			}
+			break;
+
+		case 'N':
+			overwrite = O_NEVER;
+		case 'n':
+			/* Skip entry data */
+			unzip_skip(zip_header.formatted.cmpsize);
+			break;
+
+		case 'r':
+			/* Prompt for new name */
+			printf("new name: ");
+			if (!fgets(key_buf, sizeof(key_buf), stdin)) {
+				bb_perror_msg_and_die("can't read input");
+			}
+			free(dst_fn);
+			dst_fn = xstrdup(key_buf);
+			chomp(dst_fn);
+			goto check_file;
+
+		default:
+			printf("error: invalid response [%c]\n", (char)i);
+			goto check_file;
+		}
+
+		total_entries++;
+	}
+
+	if (listing && quiet <= 1) {
+		if (!verbose) {
+			//      "  Length     Date   Time    Name\n"
+			//      " --------    ----   ----    ----"
+			printf( " --------                   -------\n"
+				"%9lu"   "                   %u files\n",
+				total_usize, total_entries);
+		} else {
+			unsigned long percents = total_usize - total_size;
+			percents = percents * 100;
+			if (total_usize)
+				percents /= total_usize;
+			//      " Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n"
+			//      "--------  ------  ------- -----   ----   ----   ------    ----"
+			printf( "--------          -------  ---                            -------\n"
+				"%8lu"              "%17lu%4u%%                            %u files\n",
+				total_usize, total_size, (unsigned)percents,
+				total_entries);
+		}
+	}
+
+	return 0;
+}