2014-12-29 20:34:41 +00:00
|
|
|
/*
|
2015-06-20 17:40:55 +00:00
|
|
|
* unxz implementation for Bled/busybox
|
2014-12-29 20:34:41 +00:00
|
|
|
*
|
2020-02-04 12:09:47 +00:00
|
|
|
* Copyright © 2014-2020 Pete Batard <pete@akeo.ie>
|
2015-01-01 23:39:28 +00:00
|
|
|
* Based on xz-embedded © Lasse Collin <lasse.collin@tukaani.org> - Public Domain
|
2014-12-29 20:34:41 +00:00
|
|
|
*
|
|
|
|
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "libbb.h"
|
|
|
|
#include "bb_archive.h"
|
|
|
|
|
|
|
|
#define XZ_EXTERN static
|
|
|
|
// We get XZ_OPTIONS_ERROR in xz_dec_stream if this is not defined
|
|
|
|
#define XZ_DEC_ANY_CHECK
|
|
|
|
|
2020-02-04 12:09:47 +00:00
|
|
|
#define XZ_BUFSIZE BB_BUFSIZE
|
|
|
|
|
2014-12-29 20:34:41 +00:00
|
|
|
#include "xz_dec_bcj.c"
|
|
|
|
#include "xz_dec_lzma2.c"
|
|
|
|
#include "xz_dec_stream.c"
|
|
|
|
|
|
|
|
static void XZ_FUNC xz_crc32_init(void)
|
|
|
|
{
|
|
|
|
if (!global_crc32_table)
|
|
|
|
global_crc32_table = crc32_filltable(NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t XZ_FUNC xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
|
|
|
|
{
|
|
|
|
// The XZ CRC32 is INVERTED!
|
|
|
|
return ~crc32_block_endian0(~crc, buf, size, global_crc32_table);
|
|
|
|
}
|
|
|
|
|
|
|
|
IF_DESKTOP(long long) int FAST_FUNC unpack_xz_stream(transformer_state_t *xstate)
|
|
|
|
{
|
|
|
|
IF_DESKTOP(long long) int n = 0;
|
|
|
|
struct xz_buf b;
|
|
|
|
struct xz_dec *s;
|
|
|
|
enum xz_ret ret = XZ_STREAM_END;
|
|
|
|
uint8_t *in = NULL, *out = NULL;
|
|
|
|
ssize_t nwrote;
|
|
|
|
|
|
|
|
xz_crc32_init();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Support up to 64 MiB dictionary. The actually needed memory
|
|
|
|
* is allocated once the headers have been parsed.
|
|
|
|
*/
|
|
|
|
s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
|
|
|
|
if (!s)
|
2015-01-01 23:39:28 +00:00
|
|
|
bb_error_msg_and_err("memory allocation error");
|
2014-12-29 20:34:41 +00:00
|
|
|
|
2020-02-04 12:09:47 +00:00
|
|
|
in = xmalloc(XZ_BUFSIZE);
|
|
|
|
out = xmalloc(XZ_BUFSIZE);
|
2014-12-29 20:34:41 +00:00
|
|
|
|
|
|
|
b.in = in;
|
|
|
|
b.in_pos = 0;
|
|
|
|
b.in_size = 0;
|
|
|
|
b.out = out;
|
|
|
|
b.out_pos = 0;
|
2020-02-04 12:09:47 +00:00
|
|
|
b.out_size = XZ_BUFSIZE;
|
2014-12-29 20:34:41 +00:00
|
|
|
|
|
|
|
while (true) {
|
|
|
|
if (b.in_pos == b.in_size) {
|
2020-02-04 12:09:47 +00:00
|
|
|
b.in_size = safe_read(xstate->src_fd, in, XZ_BUFSIZE);
|
2014-12-29 20:34:41 +00:00
|
|
|
if ((int)b.in_size < 0)
|
2015-01-01 23:39:28 +00:00
|
|
|
bb_error_msg_and_err("read error (errno: %d)", errno);
|
2014-12-29 20:34:41 +00:00
|
|
|
b.in_pos = 0;
|
|
|
|
}
|
|
|
|
ret = xz_dec_run(s, &b);
|
|
|
|
|
2020-02-04 12:09:47 +00:00
|
|
|
if (b.out_pos == XZ_BUFSIZE) {
|
2014-12-29 20:34:41 +00:00
|
|
|
nwrote = transformer_write(xstate, b.out, b.out_pos);
|
2015-02-11 23:22:18 +00:00
|
|
|
if (nwrote == -ENOSPC) {
|
|
|
|
ret = XZ_BUF_FULL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (nwrote < 0) {
|
2014-12-29 20:34:41 +00:00
|
|
|
ret = XZ_DATA_ERROR;
|
2015-01-01 23:39:28 +00:00
|
|
|
bb_error_msg_and_err("write error (errno: %d)", errno);
|
2014-12-29 20:34:41 +00:00
|
|
|
}
|
|
|
|
IF_DESKTOP(n += nwrote;)
|
|
|
|
b.out_pos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == XZ_OK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
#ifdef XZ_DEC_ANY_CHECK
|
|
|
|
if (ret == XZ_UNSUPPORTED_CHECK) {
|
|
|
|
bb_error_msg("unsupported check; not verifying file integrity");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
nwrote = transformer_write(xstate, b.out, b.out_pos);
|
2015-02-11 23:22:18 +00:00
|
|
|
if (nwrote == -ENOSPC) {
|
|
|
|
ret = XZ_BUF_FULL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (nwrote < 0) {
|
2014-12-29 20:34:41 +00:00
|
|
|
ret = XZ_DATA_ERROR;
|
2015-01-01 23:39:28 +00:00
|
|
|
bb_error_msg_and_err("write error (errno: %d)", errno);
|
2014-12-29 20:34:41 +00:00
|
|
|
}
|
|
|
|
IF_DESKTOP(n += nwrote;)
|
|
|
|
|
|
|
|
switch (ret) {
|
|
|
|
case XZ_STREAM_END:
|
|
|
|
ret = XZ_OK;
|
|
|
|
goto out;
|
|
|
|
case XZ_MEM_ERROR:
|
2015-01-01 23:39:28 +00:00
|
|
|
bb_error_msg_and_err("memory allocation error");
|
2014-12-29 20:34:41 +00:00
|
|
|
case XZ_MEMLIMIT_ERROR:
|
2015-01-01 23:39:28 +00:00
|
|
|
bb_error_msg_and_err("memory usage limit error");
|
2014-12-29 20:34:41 +00:00
|
|
|
case XZ_FORMAT_ERROR:
|
|
|
|
bb_error_msg_and_err("not a .xz file");
|
|
|
|
case XZ_OPTIONS_ERROR:
|
2015-01-01 23:39:28 +00:00
|
|
|
bb_error_msg_and_err("unsupported XZ header option");
|
2014-12-29 20:34:41 +00:00
|
|
|
case XZ_DATA_ERROR:
|
2015-01-01 23:39:28 +00:00
|
|
|
bb_error_msg_and_err("corrupted archive");
|
2014-12-29 20:34:41 +00:00
|
|
|
case XZ_BUF_ERROR:
|
2015-01-01 23:39:28 +00:00
|
|
|
bb_error_msg_and_err("corrupted buffer");
|
2015-02-11 23:22:18 +00:00
|
|
|
case XZ_BUF_FULL:
|
|
|
|
break;
|
2014-12-29 20:34:41 +00:00
|
|
|
default:
|
2015-01-01 23:39:28 +00:00
|
|
|
bb_error_msg_and_err("XZ decompression bug!");
|
2014-12-29 20:34:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
err:
|
|
|
|
xz_dec_end(s);
|
|
|
|
free(in);
|
|
|
|
free(out);
|
2015-02-11 23:22:18 +00:00
|
|
|
if (ret == XZ_OK)
|
|
|
|
return n;
|
|
|
|
else if (ret == XZ_BUF_FULL)
|
|
|
|
return xstate->mem_output_size_max;
|
|
|
|
else
|
|
|
|
return -ret;
|
2014-12-29 20:34:41 +00:00
|
|
|
}
|