summaryrefslogtreecommitdiffstats
path: root/package/busybox/busybox-1.21.0/busybox-1.21.0-xz.patch
blob: 56ba1a2731e6e194a60c9adbb4d9422ebd736d25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
--- busybox-1.21.0/archival/libarchive/decompress_unxz.c
+++ busybox-1.21.0-xz/archival/libarchive/decompress_unxz.c
@@ -40,6 +40,7 @@ static uint32_t xz_crc32(const uint8_t *
 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
 	/* 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
 				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);