[git commit] xz: support concatenated .xz streams

Denys Vlasenko vda.linux at googlemail.com
Wed Feb 27 16:26:40 UTC 2013


commit: http://git.busybox.net/busybox/commit/?id=380c8a0763462692eef8d00df4872a561ff7aa7b
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
xz_dec_reset                                           -      77     +77
unpack_xz_stream                                    2402    2397      -5

Signed-off-by: Lasse Collin <lasse.collin at tukaani.org>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 archival/libarchive/decompress_unxz.c |   43 +++++++++++++++++++++++++++-----
 1 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
index 79b48a1..e9ddd37 100644
--- a/archival/libarchive/decompress_unxz.c
+++ b/archival/libarchive/decompress_unxz.c
@@ -40,6 +40,7 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
 IF_DESKTOP(long long) int FAST_FUNC
 unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
 {
+	enum xz_ret xz_result;
 	struct xz_buf iobuf;
 	struct xz_dec *state;
 	unsigned char *membuf;
@@ -63,9 +64,8 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
 	/* Limit memory usage to about 64 MiB. */
 	state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024);
 
+	xz_result = X_OK;
 	while (1) {
-		enum xz_ret r;
-
 		if (iobuf.in_pos == iobuf.in_size) {
 			int rd = safe_read(src_fd, membuf, BUFSIZ);
 			if (rd < 0) {
@@ -73,28 +73,57 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
 				total = -1;
 				break;
 			}
+			if (rd == 0 && xz_result == XZ_STREAM_END)
+				break;
 			iobuf.in_size = rd;
 			iobuf.in_pos = 0;
 		}
+		if (xz_result == XZ_STREAM_END) {
+			/*
+			 * Try to start decoding next concatenated stream.
+			 * Stream padding must always be a multiple of four
+			 * bytes to preserve four-byte alignment. To keep the
+			 * code slightly smaller, we aren't as strict here as
+			 * the .xz spec requires. We just skip all zero-bytes
+			 * without checking the alignment and thus can accept
+			 * files that aren't valid, e.g. the XZ utils test
+			 * files bad-0pad-empty.xz and bad-0catpad-empty.xz.
+			 */
+			do {
+				if (membuf[iobuf.in_pos] != 0) {
+					xz_dec_reset(state);
+					goto do_run;
+				}
+				iobuf.in_pos++;
+			} while (iobuf.in_pos < iobuf.in_size);
+		}
+ do_run:
 //		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);
+		xz_result = 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);
+//				iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, xz_result);
 		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 (xz_result == XZ_STREAM_END) {
+			/*
+			 * Can just "break;" here, if not for concatenated
+			 * .xz streams.
+			 * Checking for padding may require buffer
+			 * replenishment. Can't do it here.
+			 */
+			continue;
 		}
-		if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) {
+		if (xz_result != XZ_OK && xz_result != XZ_UNSUPPORTED_CHECK) {
 			bb_error_msg("corrupted data");
 			total = -1;
 			break;
 		}
 	}
+
 	xz_dec_end(state);
 	free(membuf);
 


More information about the busybox-cvs mailing list