837 lines · c
1// SPDX-License-Identifier: 0BSD2 3/*4 * .xz Stream decoder5 *6 * Author: Lasse Collin <lasse.collin@tukaani.org>7 */8 9#include "xz_private.h"10#include "xz_stream.h"11 12/* Hash used to validate the Index field */13struct xz_dec_hash {14 vli_type unpadded;15 vli_type uncompressed;16 uint32_t crc32;17};18 19struct xz_dec {20 /* Position in dec_main() */21 enum {22 SEQ_STREAM_HEADER,23 SEQ_BLOCK_START,24 SEQ_BLOCK_HEADER,25 SEQ_BLOCK_UNCOMPRESS,26 SEQ_BLOCK_PADDING,27 SEQ_BLOCK_CHECK,28 SEQ_INDEX,29 SEQ_INDEX_PADDING,30 SEQ_INDEX_CRC32,31 SEQ_STREAM_FOOTER32 } sequence;33 34 /* Position in variable-length integers and Check fields */35 uint32_t pos;36 37 /* Variable-length integer decoded by dec_vli() */38 vli_type vli;39 40 /* Saved in_pos and out_pos */41 size_t in_start;42 size_t out_start;43 44 /* CRC32 value in Block or Index */45 uint32_t crc32;46 47 /* Type of the integrity check calculated from uncompressed data */48 enum xz_check check_type;49 50 /* Operation mode */51 enum xz_mode mode;52 53 /*54 * True if the next call to xz_dec_run() is allowed to return55 * XZ_BUF_ERROR.56 */57 bool allow_buf_error;58 59 /* Information stored in Block Header */60 struct {61 /*62 * Value stored in the Compressed Size field, or63 * VLI_UNKNOWN if Compressed Size is not present.64 */65 vli_type compressed;66 67 /*68 * Value stored in the Uncompressed Size field, or69 * VLI_UNKNOWN if Uncompressed Size is not present.70 */71 vli_type uncompressed;72 73 /* Size of the Block Header field */74 uint32_t size;75 } block_header;76 77 /* Information collected when decoding Blocks */78 struct {79 /* Observed compressed size of the current Block */80 vli_type compressed;81 82 /* Observed uncompressed size of the current Block */83 vli_type uncompressed;84 85 /* Number of Blocks decoded so far */86 vli_type count;87 88 /*89 * Hash calculated from the Block sizes. This is used to90 * validate the Index field.91 */92 struct xz_dec_hash hash;93 } block;94 95 /* Variables needed when verifying the Index field */96 struct {97 /* Position in dec_index() */98 enum {99 SEQ_INDEX_COUNT,100 SEQ_INDEX_UNPADDED,101 SEQ_INDEX_UNCOMPRESSED102 } sequence;103 104 /* Size of the Index in bytes */105 vli_type size;106 107 /* Number of Records (matches block.count in valid files) */108 vli_type count;109 110 /*111 * Hash calculated from the Records (matches block.hash in112 * valid files).113 */114 struct xz_dec_hash hash;115 } index;116 117 /*118 * Temporary buffer needed to hold Stream Header, Block Header,119 * and Stream Footer. The Block Header is the biggest (1 KiB)120 * so we reserve space according to that. buf[] has to be aligned121 * to a multiple of four bytes; the size_t variables before it122 * should guarantee this.123 */124 struct {125 size_t pos;126 size_t size;127 uint8_t buf[1024];128 } temp;129 130 struct xz_dec_lzma2 *lzma2;131 132#ifdef XZ_DEC_BCJ133 struct xz_dec_bcj *bcj;134 bool bcj_active;135#endif136};137 138#ifdef XZ_DEC_ANY_CHECK139/* Sizes of the Check field with different Check IDs */140static const uint8_t check_sizes[16] = {141 0,142 4, 4, 4,143 8, 8, 8,144 16, 16, 16,145 32, 32, 32,146 64, 64, 64147};148#endif149 150/*151 * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller152 * must have set s->temp.pos to indicate how much data we are supposed153 * to copy into s->temp.buf. Return true once s->temp.pos has reached154 * s->temp.size.155 */156static bool fill_temp(struct xz_dec *s, struct xz_buf *b)157{158 size_t copy_size = min_t(size_t,159 b->in_size - b->in_pos, s->temp.size - s->temp.pos);160 161 memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);162 b->in_pos += copy_size;163 s->temp.pos += copy_size;164 165 if (s->temp.pos == s->temp.size) {166 s->temp.pos = 0;167 return true;168 }169 170 return false;171}172 173/* Decode a variable-length integer (little-endian base-128 encoding) */174static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,175 size_t *in_pos, size_t in_size)176{177 uint8_t byte;178 179 if (s->pos == 0)180 s->vli = 0;181 182 while (*in_pos < in_size) {183 byte = in[*in_pos];184 ++*in_pos;185 186 s->vli |= (vli_type)(byte & 0x7F) << s->pos;187 188 if ((byte & 0x80) == 0) {189 /* Don't allow non-minimal encodings. */190 if (byte == 0 && s->pos != 0)191 return XZ_DATA_ERROR;192 193 s->pos = 0;194 return XZ_STREAM_END;195 }196 197 s->pos += 7;198 if (s->pos == 7 * VLI_BYTES_MAX)199 return XZ_DATA_ERROR;200 }201 202 return XZ_OK;203}204 205/*206 * Decode the Compressed Data field from a Block. Update and validate207 * the observed compressed and uncompressed sizes of the Block so that208 * they don't exceed the values possibly stored in the Block Header209 * (validation assumes that no integer overflow occurs, since vli_type210 * is normally uint64_t). Update the CRC32 if presence of the CRC32211 * field was indicated in Stream Header.212 *213 * Once the decoding is finished, validate that the observed sizes match214 * the sizes possibly stored in the Block Header. Update the hash and215 * Block count, which are later used to validate the Index field.216 */217static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)218{219 enum xz_ret ret;220 221 s->in_start = b->in_pos;222 s->out_start = b->out_pos;223 224#ifdef XZ_DEC_BCJ225 if (s->bcj_active)226 ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);227 else228#endif229 ret = xz_dec_lzma2_run(s->lzma2, b);230 231 s->block.compressed += b->in_pos - s->in_start;232 s->block.uncompressed += b->out_pos - s->out_start;233 234 /*235 * There is no need to separately check for VLI_UNKNOWN, since236 * the observed sizes are always smaller than VLI_UNKNOWN.237 */238 if (s->block.compressed > s->block_header.compressed239 || s->block.uncompressed240 > s->block_header.uncompressed)241 return XZ_DATA_ERROR;242 243 if (s->check_type == XZ_CHECK_CRC32)244 s->crc32 = xz_crc32(b->out + s->out_start,245 b->out_pos - s->out_start, s->crc32);246 247 if (ret == XZ_STREAM_END) {248 if (s->block_header.compressed != VLI_UNKNOWN249 && s->block_header.compressed250 != s->block.compressed)251 return XZ_DATA_ERROR;252 253 if (s->block_header.uncompressed != VLI_UNKNOWN254 && s->block_header.uncompressed255 != s->block.uncompressed)256 return XZ_DATA_ERROR;257 258 s->block.hash.unpadded += s->block_header.size259 + s->block.compressed;260 261#ifdef XZ_DEC_ANY_CHECK262 s->block.hash.unpadded += check_sizes[s->check_type];263#else264 if (s->check_type == XZ_CHECK_CRC32)265 s->block.hash.unpadded += 4;266#endif267 268 s->block.hash.uncompressed += s->block.uncompressed;269 s->block.hash.crc32 = xz_crc32(270 (const uint8_t *)&s->block.hash,271 sizeof(s->block.hash), s->block.hash.crc32);272 273 ++s->block.count;274 }275 276 return ret;277}278 279/* Update the Index size and the CRC32 value. */280static void index_update(struct xz_dec *s, const struct xz_buf *b)281{282 size_t in_used = b->in_pos - s->in_start;283 s->index.size += in_used;284 s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32);285}286 287/*288 * Decode the Number of Records, Unpadded Size, and Uncompressed Size289 * fields from the Index field. That is, Index Padding and CRC32 are not290 * decoded by this function.291 *292 * This can return XZ_OK (more input needed), XZ_STREAM_END (everything293 * successfully decoded), or XZ_DATA_ERROR (input is corrupt).294 */295static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)296{297 enum xz_ret ret;298 299 do {300 ret = dec_vli(s, b->in, &b->in_pos, b->in_size);301 if (ret != XZ_STREAM_END) {302 index_update(s, b);303 return ret;304 }305 306 switch (s->index.sequence) {307 case SEQ_INDEX_COUNT:308 s->index.count = s->vli;309 310 /*311 * Validate that the Number of Records field312 * indicates the same number of Records as313 * there were Blocks in the Stream.314 */315 if (s->index.count != s->block.count)316 return XZ_DATA_ERROR;317 318 s->index.sequence = SEQ_INDEX_UNPADDED;319 break;320 321 case SEQ_INDEX_UNPADDED:322 s->index.hash.unpadded += s->vli;323 s->index.sequence = SEQ_INDEX_UNCOMPRESSED;324 break;325 326 case SEQ_INDEX_UNCOMPRESSED:327 s->index.hash.uncompressed += s->vli;328 s->index.hash.crc32 = xz_crc32(329 (const uint8_t *)&s->index.hash,330 sizeof(s->index.hash),331 s->index.hash.crc32);332 --s->index.count;333 s->index.sequence = SEQ_INDEX_UNPADDED;334 break;335 }336 } while (s->index.count > 0);337 338 return XZ_STREAM_END;339}340 341/*342 * Validate that the next four input bytes match the value of s->crc32.343 * s->pos must be zero when starting to validate the first byte.344 */345static enum xz_ret crc32_validate(struct xz_dec *s, struct xz_buf *b)346{347 do {348 if (b->in_pos == b->in_size)349 return XZ_OK;350 351 if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++])352 return XZ_DATA_ERROR;353 354 s->pos += 8;355 356 } while (s->pos < 32);357 358 s->crc32 = 0;359 s->pos = 0;360 361 return XZ_STREAM_END;362}363 364#ifdef XZ_DEC_ANY_CHECK365/*366 * Skip over the Check field when the Check ID is not supported.367 * Returns true once the whole Check field has been skipped over.368 */369static bool check_skip(struct xz_dec *s, struct xz_buf *b)370{371 while (s->pos < check_sizes[s->check_type]) {372 if (b->in_pos == b->in_size)373 return false;374 375 ++b->in_pos;376 ++s->pos;377 }378 379 s->pos = 0;380 381 return true;382}383#endif384 385/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */386static enum xz_ret dec_stream_header(struct xz_dec *s)387{388 if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))389 return XZ_FORMAT_ERROR;390 391 if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)392 != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))393 return XZ_DATA_ERROR;394 395 if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)396 return XZ_OPTIONS_ERROR;397 398 /*399 * Of integrity checks, we support only none (Check ID = 0) and400 * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined,401 * we will accept other check types too, but then the check won't402 * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given.403 */404 if (s->temp.buf[HEADER_MAGIC_SIZE + 1] > XZ_CHECK_MAX)405 return XZ_OPTIONS_ERROR;406 407 s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];408 409#ifdef XZ_DEC_ANY_CHECK410 if (s->check_type > XZ_CHECK_CRC32)411 return XZ_UNSUPPORTED_CHECK;412#else413 if (s->check_type > XZ_CHECK_CRC32)414 return XZ_OPTIONS_ERROR;415#endif416 417 return XZ_OK;418}419 420/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */421static enum xz_ret dec_stream_footer(struct xz_dec *s)422{423 if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))424 return XZ_DATA_ERROR;425 426 if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))427 return XZ_DATA_ERROR;428 429 /*430 * Validate Backward Size. Note that we never added the size of the431 * Index CRC32 field to s->index.size, thus we use s->index.size / 4432 * instead of s->index.size / 4 - 1.433 */434 if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))435 return XZ_DATA_ERROR;436 437 if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)438 return XZ_DATA_ERROR;439 440 /*441 * Use XZ_STREAM_END instead of XZ_OK to be more convenient442 * for the caller.443 */444 return XZ_STREAM_END;445}446 447/* Decode the Block Header and initialize the filter chain. */448static enum xz_ret dec_block_header(struct xz_dec *s)449{450 enum xz_ret ret;451 452 /*453 * Validate the CRC32. We know that the temp buffer is at least454 * eight bytes so this is safe.455 */456 s->temp.size -= 4;457 if (xz_crc32(s->temp.buf, s->temp.size, 0)458 != get_le32(s->temp.buf + s->temp.size))459 return XZ_DATA_ERROR;460 461 s->temp.pos = 2;462 463 /*464 * Catch unsupported Block Flags. We support only one or two filters465 * in the chain, so we catch that with the same test.466 */467#ifdef XZ_DEC_BCJ468 if (s->temp.buf[1] & 0x3E)469#else470 if (s->temp.buf[1] & 0x3F)471#endif472 return XZ_OPTIONS_ERROR;473 474 /* Compressed Size */475 if (s->temp.buf[1] & 0x40) {476 if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)477 != XZ_STREAM_END)478 return XZ_DATA_ERROR;479 480 s->block_header.compressed = s->vli;481 } else {482 s->block_header.compressed = VLI_UNKNOWN;483 }484 485 /* Uncompressed Size */486 if (s->temp.buf[1] & 0x80) {487 if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)488 != XZ_STREAM_END)489 return XZ_DATA_ERROR;490 491 s->block_header.uncompressed = s->vli;492 } else {493 s->block_header.uncompressed = VLI_UNKNOWN;494 }495 496#ifdef XZ_DEC_BCJ497 /* If there are two filters, the first one must be a BCJ filter. */498 s->bcj_active = s->temp.buf[1] & 0x01;499 if (s->bcj_active) {500 if (s->temp.size - s->temp.pos < 2)501 return XZ_OPTIONS_ERROR;502 503 ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);504 if (ret != XZ_OK)505 return ret;506 507 /*508 * We don't support custom start offset,509 * so Size of Properties must be zero.510 */511 if (s->temp.buf[s->temp.pos++] != 0x00)512 return XZ_OPTIONS_ERROR;513 }514#endif515 516 /* Valid Filter Flags always take at least two bytes. */517 if (s->temp.size - s->temp.pos < 2)518 return XZ_DATA_ERROR;519 520 /* Filter ID = LZMA2 */521 if (s->temp.buf[s->temp.pos++] != 0x21)522 return XZ_OPTIONS_ERROR;523 524 /* Size of Properties = 1-byte Filter Properties */525 if (s->temp.buf[s->temp.pos++] != 0x01)526 return XZ_OPTIONS_ERROR;527 528 /* Filter Properties contains LZMA2 dictionary size. */529 if (s->temp.size - s->temp.pos < 1)530 return XZ_DATA_ERROR;531 532 ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);533 if (ret != XZ_OK)534 return ret;535 536 /* The rest must be Header Padding. */537 while (s->temp.pos < s->temp.size)538 if (s->temp.buf[s->temp.pos++] != 0x00)539 return XZ_OPTIONS_ERROR;540 541 s->temp.pos = 0;542 s->block.compressed = 0;543 s->block.uncompressed = 0;544 545 return XZ_OK;546}547 548static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)549{550 enum xz_ret ret;551 552 /*553 * Store the start position for the case when we are in the middle554 * of the Index field.555 */556 s->in_start = b->in_pos;557 558 while (true) {559 switch (s->sequence) {560 case SEQ_STREAM_HEADER:561 /*562 * Stream Header is copied to s->temp, and then563 * decoded from there. This way if the caller564 * gives us only little input at a time, we can565 * still keep the Stream Header decoding code566 * simple. Similar approach is used in many places567 * in this file.568 */569 if (!fill_temp(s, b))570 return XZ_OK;571 572 /*573 * If dec_stream_header() returns574 * XZ_UNSUPPORTED_CHECK, it is still possible575 * to continue decoding if working in multi-call576 * mode. Thus, update s->sequence before calling577 * dec_stream_header().578 */579 s->sequence = SEQ_BLOCK_START;580 581 ret = dec_stream_header(s);582 if (ret != XZ_OK)583 return ret;584 585 fallthrough;586 587 case SEQ_BLOCK_START:588 /* We need one byte of input to continue. */589 if (b->in_pos == b->in_size)590 return XZ_OK;591 592 /* See if this is the beginning of the Index field. */593 if (b->in[b->in_pos] == 0) {594 s->in_start = b->in_pos++;595 s->sequence = SEQ_INDEX;596 break;597 }598 599 /*600 * Calculate the size of the Block Header and601 * prepare to decode it.602 */603 s->block_header.size604 = ((uint32_t)b->in[b->in_pos] + 1) * 4;605 606 s->temp.size = s->block_header.size;607 s->temp.pos = 0;608 s->sequence = SEQ_BLOCK_HEADER;609 610 fallthrough;611 612 case SEQ_BLOCK_HEADER:613 if (!fill_temp(s, b))614 return XZ_OK;615 616 ret = dec_block_header(s);617 if (ret != XZ_OK)618 return ret;619 620 s->sequence = SEQ_BLOCK_UNCOMPRESS;621 622 fallthrough;623 624 case SEQ_BLOCK_UNCOMPRESS:625 ret = dec_block(s, b);626 if (ret != XZ_STREAM_END)627 return ret;628 629 s->sequence = SEQ_BLOCK_PADDING;630 631 fallthrough;632 633 case SEQ_BLOCK_PADDING:634 /*635 * Size of Compressed Data + Block Padding636 * must be a multiple of four. We don't need637 * s->block.compressed for anything else638 * anymore, so we use it here to test the size639 * of the Block Padding field.640 */641 while (s->block.compressed & 3) {642 if (b->in_pos == b->in_size)643 return XZ_OK;644 645 if (b->in[b->in_pos++] != 0)646 return XZ_DATA_ERROR;647 648 ++s->block.compressed;649 }650 651 s->sequence = SEQ_BLOCK_CHECK;652 653 fallthrough;654 655 case SEQ_BLOCK_CHECK:656 if (s->check_type == XZ_CHECK_CRC32) {657 ret = crc32_validate(s, b);658 if (ret != XZ_STREAM_END)659 return ret;660 }661#ifdef XZ_DEC_ANY_CHECK662 else if (!check_skip(s, b)) {663 return XZ_OK;664 }665#endif666 667 s->sequence = SEQ_BLOCK_START;668 break;669 670 case SEQ_INDEX:671 ret = dec_index(s, b);672 if (ret != XZ_STREAM_END)673 return ret;674 675 s->sequence = SEQ_INDEX_PADDING;676 677 fallthrough;678 679 case SEQ_INDEX_PADDING:680 while ((s->index.size + (b->in_pos - s->in_start))681 & 3) {682 if (b->in_pos == b->in_size) {683 index_update(s, b);684 return XZ_OK;685 }686 687 if (b->in[b->in_pos++] != 0)688 return XZ_DATA_ERROR;689 }690 691 /* Finish the CRC32 value and Index size. */692 index_update(s, b);693 694 /* Compare the hashes to validate the Index field. */695 if (!memeq(&s->block.hash, &s->index.hash,696 sizeof(s->block.hash)))697 return XZ_DATA_ERROR;698 699 s->sequence = SEQ_INDEX_CRC32;700 701 fallthrough;702 703 case SEQ_INDEX_CRC32:704 ret = crc32_validate(s, b);705 if (ret != XZ_STREAM_END)706 return ret;707 708 s->temp.size = STREAM_HEADER_SIZE;709 s->sequence = SEQ_STREAM_FOOTER;710 711 fallthrough;712 713 case SEQ_STREAM_FOOTER:714 if (!fill_temp(s, b))715 return XZ_OK;716 717 return dec_stream_footer(s);718 }719 }720 721 /* Never reached */722}723 724/*725 * xz_dec_run() is a wrapper for dec_main() to handle some special cases in726 * multi-call and single-call decoding.727 *728 * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we729 * are not going to make any progress anymore. This is to prevent the caller730 * from calling us infinitely when the input file is truncated or otherwise731 * corrupt. Since zlib-style API allows that the caller fills the input buffer732 * only when the decoder doesn't produce any new output, we have to be careful733 * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only734 * after the second consecutive call to xz_dec_run() that makes no progress.735 *736 * In single-call mode, if we couldn't decode everything and no error737 * occurred, either the input is truncated or the output buffer is too small.738 * Since we know that the last input byte never produces any output, we know739 * that if all the input was consumed and decoding wasn't finished, the file740 * must be corrupt. Otherwise the output buffer has to be too small or the741 * file is corrupt in a way that decoding it produces too big output.742 *743 * If single-call decoding fails, we reset b->in_pos and b->out_pos back to744 * their original values. This is because with some filter chains there won't745 * be any valid uncompressed data in the output buffer unless the decoding746 * actually succeeds (that's the price to pay of using the output buffer as747 * the workspace).748 */749enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)750{751 size_t in_start;752 size_t out_start;753 enum xz_ret ret;754 755 if (DEC_IS_SINGLE(s->mode))756 xz_dec_reset(s);757 758 in_start = b->in_pos;759 out_start = b->out_pos;760 ret = dec_main(s, b);761 762 if (DEC_IS_SINGLE(s->mode)) {763 if (ret == XZ_OK)764 ret = b->in_pos == b->in_size765 ? XZ_DATA_ERROR : XZ_BUF_ERROR;766 767 if (ret != XZ_STREAM_END) {768 b->in_pos = in_start;769 b->out_pos = out_start;770 }771 772 } else if (ret == XZ_OK && in_start == b->in_pos773 && out_start == b->out_pos) {774 if (s->allow_buf_error)775 ret = XZ_BUF_ERROR;776 777 s->allow_buf_error = true;778 } else {779 s->allow_buf_error = false;780 }781 782 return ret;783}784 785struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)786{787 struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);788 if (s == NULL)789 return NULL;790 791 s->mode = mode;792 793#ifdef XZ_DEC_BCJ794 s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));795 if (s->bcj == NULL)796 goto error_bcj;797#endif798 799 s->lzma2 = xz_dec_lzma2_create(mode, dict_max);800 if (s->lzma2 == NULL)801 goto error_lzma2;802 803 xz_dec_reset(s);804 return s;805 806error_lzma2:807#ifdef XZ_DEC_BCJ808 xz_dec_bcj_end(s->bcj);809error_bcj:810#endif811 kfree(s);812 return NULL;813}814 815void xz_dec_reset(struct xz_dec *s)816{817 s->sequence = SEQ_STREAM_HEADER;818 s->allow_buf_error = false;819 s->pos = 0;820 s->crc32 = 0;821 memzero(&s->block, sizeof(s->block));822 memzero(&s->index, sizeof(s->index));823 s->temp.pos = 0;824 s->temp.size = STREAM_HEADER_SIZE;825}826 827void xz_dec_end(struct xz_dec *s)828{829 if (s != NULL) {830 xz_dec_lzma2_end(s->lzma2);831#ifdef XZ_DEC_BCJ832 xz_dec_bcj_end(s->bcj);833#endif834 kfree(s);835 }836}837