15c4b64e6SXin LI /* $NetBSD: unxz.c,v 1.8 2018/10/06 16:36:45 martin Exp $ */
2140c037aSXin LI
3140c037aSXin LI /*-
4*b61a5730SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
51de7b4b8SPedro F. Giffuni *
6140c037aSXin LI * Copyright (c) 2011 The NetBSD Foundation, Inc.
7140c037aSXin LI * All rights reserved.
8140c037aSXin LI *
9140c037aSXin LI * This code is derived from software contributed to The NetBSD Foundation
10140c037aSXin LI * by Christos Zoulas.
11140c037aSXin LI *
12140c037aSXin LI * Redistribution and use in source and binary forms, with or without
13140c037aSXin LI * modification, are permitted provided that the following conditions
14140c037aSXin LI * are met:
15140c037aSXin LI * 1. Redistributions of source code must retain the above copyright
16140c037aSXin LI * notice, this list of conditions and the following disclaimer.
17140c037aSXin LI * 2. Redistributions in binary form must reproduce the above copyright
18140c037aSXin LI * notice, this list of conditions and the following disclaimer in the
19140c037aSXin LI * documentation and/or other materials provided with the distribution.
20140c037aSXin LI *
21140c037aSXin LI * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22140c037aSXin LI * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23140c037aSXin LI * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24140c037aSXin LI * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25140c037aSXin LI * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26140c037aSXin LI * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27140c037aSXin LI * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28140c037aSXin LI * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29140c037aSXin LI * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30140c037aSXin LI * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31140c037aSXin LI * POSSIBILITY OF SUCH DAMAGE.
32140c037aSXin LI */
33140c037aSXin LI #include <sys/cdefs.h>
34140c037aSXin LI #include <stdarg.h>
35140c037aSXin LI #include <errno.h>
36140c037aSXin LI #include <stdio.h>
37140c037aSXin LI #include <unistd.h>
38140c037aSXin LI #include <lzma.h>
39140c037aSXin LI
40140c037aSXin LI static off_t
unxz(int i,int o,char * pre,size_t prelen,off_t * bytes_in)41140c037aSXin LI unxz(int i, int o, char *pre, size_t prelen, off_t *bytes_in)
42140c037aSXin LI {
43140c037aSXin LI lzma_stream strm = LZMA_STREAM_INIT;
44140c037aSXin LI static const int flags = LZMA_TELL_UNSUPPORTED_CHECK|LZMA_CONCATENATED;
45140c037aSXin LI lzma_ret ret;
46140c037aSXin LI lzma_action action = LZMA_RUN;
47140c037aSXin LI off_t bytes_out, bp;
48140c037aSXin LI uint8_t ibuf[BUFSIZ];
49140c037aSXin LI uint8_t obuf[BUFSIZ];
50140c037aSXin LI
51140c037aSXin LI if (bytes_in == NULL)
52140c037aSXin LI bytes_in = &bp;
53140c037aSXin LI
54140c037aSXin LI strm.next_in = ibuf;
55140c037aSXin LI memcpy(ibuf, pre, prelen);
56140c037aSXin LI strm.avail_in = read(i, ibuf + prelen, sizeof(ibuf) - prelen);
57140c037aSXin LI if (strm.avail_in == (size_t)-1)
58140c037aSXin LI maybe_err("read failed");
5990f528e8SXin LI infile_newdata(strm.avail_in);
60140c037aSXin LI strm.avail_in += prelen;
61140c037aSXin LI *bytes_in = strm.avail_in;
62140c037aSXin LI
63140c037aSXin LI if ((ret = lzma_stream_decoder(&strm, UINT64_MAX, flags)) != LZMA_OK)
64140c037aSXin LI maybe_errx("Can't initialize decoder (%d)", ret);
65140c037aSXin LI
66140c037aSXin LI strm.next_out = NULL;
67140c037aSXin LI strm.avail_out = 0;
68140c037aSXin LI if ((ret = lzma_code(&strm, LZMA_RUN)) != LZMA_OK)
69140c037aSXin LI maybe_errx("Can't read headers (%d)", ret);
70140c037aSXin LI
71140c037aSXin LI bytes_out = 0;
72140c037aSXin LI strm.next_out = obuf;
73140c037aSXin LI strm.avail_out = sizeof(obuf);
74140c037aSXin LI
75140c037aSXin LI for (;;) {
7690f528e8SXin LI check_siginfo();
77140c037aSXin LI if (strm.avail_in == 0) {
78140c037aSXin LI strm.next_in = ibuf;
79140c037aSXin LI strm.avail_in = read(i, ibuf, sizeof(ibuf));
80140c037aSXin LI switch (strm.avail_in) {
81140c037aSXin LI case (size_t)-1:
82140c037aSXin LI maybe_err("read failed");
83140c037aSXin LI /*NOTREACHED*/
84140c037aSXin LI case 0:
85140c037aSXin LI action = LZMA_FINISH;
86140c037aSXin LI break;
87140c037aSXin LI default:
8890f528e8SXin LI infile_newdata(strm.avail_in);
89140c037aSXin LI *bytes_in += strm.avail_in;
90140c037aSXin LI break;
91140c037aSXin LI }
92140c037aSXin LI }
93140c037aSXin LI
94140c037aSXin LI ret = lzma_code(&strm, action);
95140c037aSXin LI
96140c037aSXin LI // Write and check write error before checking decoder error.
97140c037aSXin LI // This way as much data as possible gets written to output
98140c037aSXin LI // even if decoder detected an error.
99140c037aSXin LI if (strm.avail_out == 0 || ret != LZMA_OK) {
100140c037aSXin LI const size_t write_size = sizeof(obuf) - strm.avail_out;
101140c037aSXin LI
102140c037aSXin LI if (write(o, obuf, write_size) != (ssize_t)write_size)
103140c037aSXin LI maybe_err("write failed");
104140c037aSXin LI
105140c037aSXin LI strm.next_out = obuf;
106140c037aSXin LI strm.avail_out = sizeof(obuf);
107140c037aSXin LI bytes_out += write_size;
108140c037aSXin LI }
109140c037aSXin LI
110140c037aSXin LI if (ret != LZMA_OK) {
111140c037aSXin LI if (ret == LZMA_STREAM_END) {
112140c037aSXin LI // Check that there's no trailing garbage.
113140c037aSXin LI if (strm.avail_in != 0 || read(i, ibuf, 1))
114140c037aSXin LI ret = LZMA_DATA_ERROR;
115140c037aSXin LI else {
116140c037aSXin LI lzma_end(&strm);
117140c037aSXin LI return bytes_out;
118140c037aSXin LI }
119140c037aSXin LI }
120140c037aSXin LI
121140c037aSXin LI const char *msg;
122140c037aSXin LI switch (ret) {
123140c037aSXin LI case LZMA_MEM_ERROR:
124140c037aSXin LI msg = strerror(ENOMEM);
125140c037aSXin LI break;
126140c037aSXin LI
127140c037aSXin LI case LZMA_FORMAT_ERROR:
128140c037aSXin LI msg = "File format not recognized";
129140c037aSXin LI break;
130140c037aSXin LI
131140c037aSXin LI case LZMA_OPTIONS_ERROR:
132140c037aSXin LI // FIXME: Better message?
133140c037aSXin LI msg = "Unsupported compression options";
134140c037aSXin LI break;
135140c037aSXin LI
136140c037aSXin LI case LZMA_DATA_ERROR:
137140c037aSXin LI msg = "File is corrupt";
138140c037aSXin LI break;
139140c037aSXin LI
140140c037aSXin LI case LZMA_BUF_ERROR:
141140c037aSXin LI msg = "Unexpected end of input";
142140c037aSXin LI break;
143140c037aSXin LI
144140c037aSXin LI case LZMA_MEMLIMIT_ERROR:
145140c037aSXin LI msg = "Reached memory limit";
146140c037aSXin LI break;
147140c037aSXin LI
148140c037aSXin LI default:
149140c037aSXin LI maybe_errx("Unknown error (%d)", ret);
150140c037aSXin LI break;
151140c037aSXin LI }
152140c037aSXin LI maybe_errx("%s", msg);
153140c037aSXin LI
154140c037aSXin LI }
155140c037aSXin LI }
156140c037aSXin LI }
1575c4b64e6SXin LI
1585c4b64e6SXin LI #include <stdbool.h>
1595c4b64e6SXin LI
1605c4b64e6SXin LI /*
1615c4b64e6SXin LI * Copied various bits and pieces from xz support code or brute force
1625c4b64e6SXin LI * replacements.
1635c4b64e6SXin LI */
1645c4b64e6SXin LI
1655c4b64e6SXin LI #define my_min(A,B) ((A)<(B)?(A):(B))
1665c4b64e6SXin LI
1675c4b64e6SXin LI // Some systems have suboptimal BUFSIZ. Use a bit bigger value on them.
1685c4b64e6SXin LI // We also need that IO_BUFFER_SIZE is a multiple of 8 (sizeof(uint64_t))
1695c4b64e6SXin LI #if BUFSIZ <= 1024
1705c4b64e6SXin LI # define IO_BUFFER_SIZE 8192
1715c4b64e6SXin LI #else
1725c4b64e6SXin LI # define IO_BUFFER_SIZE (BUFSIZ & ~7U)
1735c4b64e6SXin LI #endif
1745c4b64e6SXin LI
1755c4b64e6SXin LI /// is_sparse() accesses the buffer as uint64_t for maximum speed.
1765c4b64e6SXin LI /// Use an union to make sure that the buffer is properly aligned.
1775c4b64e6SXin LI typedef union {
1785c4b64e6SXin LI uint8_t u8[IO_BUFFER_SIZE];
1795c4b64e6SXin LI uint32_t u32[IO_BUFFER_SIZE / sizeof(uint32_t)];
1805c4b64e6SXin LI uint64_t u64[IO_BUFFER_SIZE / sizeof(uint64_t)];
1815c4b64e6SXin LI } io_buf;
1825c4b64e6SXin LI
1835c4b64e6SXin LI
1845c4b64e6SXin LI static bool
io_pread(int fd,io_buf * buf,size_t size,off_t pos)1855c4b64e6SXin LI io_pread(int fd, io_buf *buf, size_t size, off_t pos)
1865c4b64e6SXin LI {
1875c4b64e6SXin LI // Using lseek() and read() is more portable than pread() and
1885c4b64e6SXin LI // for us it is as good as real pread().
1895c4b64e6SXin LI if (lseek(fd, pos, SEEK_SET) != pos) {
1905c4b64e6SXin LI return true;
1915c4b64e6SXin LI }
1925c4b64e6SXin LI
1935c4b64e6SXin LI const size_t amount = read(fd, buf, size);
1945c4b64e6SXin LI if (amount == SIZE_MAX)
1955c4b64e6SXin LI return true;
1965c4b64e6SXin LI
1975c4b64e6SXin LI if (amount != size) {
1985c4b64e6SXin LI return true;
1995c4b64e6SXin LI }
2005c4b64e6SXin LI
2015c4b64e6SXin LI return false;
2025c4b64e6SXin LI }
2035c4b64e6SXin LI
2045c4b64e6SXin LI /*
2055c4b64e6SXin LI * Most of the following is copied (mostly verbatim) from the xz
2065c4b64e6SXin LI * distribution, from file src/xz/list.c
2075c4b64e6SXin LI */
2085c4b64e6SXin LI
2095c4b64e6SXin LI ///////////////////////////////////////////////////////////////////////////////
2105c4b64e6SXin LI //
2115c4b64e6SXin LI /// \file list.c
2125c4b64e6SXin LI /// \brief Listing information about .xz files
2135c4b64e6SXin LI //
2145c4b64e6SXin LI // Author: Lasse Collin
2155c4b64e6SXin LI //
2165c4b64e6SXin LI // This file has been put into the public domain.
2175c4b64e6SXin LI // You can do whatever you want with this file.
2185c4b64e6SXin LI //
2195c4b64e6SXin LI ///////////////////////////////////////////////////////////////////////////////
2205c4b64e6SXin LI
2215c4b64e6SXin LI
2225c4b64e6SXin LI /// Information about a .xz file
2235c4b64e6SXin LI typedef struct {
2245c4b64e6SXin LI /// Combined Index of all Streams in the file
2255c4b64e6SXin LI lzma_index *idx;
2265c4b64e6SXin LI
2275c4b64e6SXin LI /// Total amount of Stream Padding
2285c4b64e6SXin LI uint64_t stream_padding;
2295c4b64e6SXin LI
2305c4b64e6SXin LI /// Highest memory usage so far
2315c4b64e6SXin LI uint64_t memusage_max;
2325c4b64e6SXin LI
2335c4b64e6SXin LI /// True if all Blocks so far have Compressed Size and
2345c4b64e6SXin LI /// Uncompressed Size fields
2355c4b64e6SXin LI bool all_have_sizes;
2365c4b64e6SXin LI
2375c4b64e6SXin LI /// Oldest XZ Utils version that will decompress the file
2385c4b64e6SXin LI uint32_t min_version;
2395c4b64e6SXin LI
2405c4b64e6SXin LI } xz_file_info;
2415c4b64e6SXin LI
2425c4b64e6SXin LI #define XZ_FILE_INFO_INIT { NULL, 0, 0, true, 50000002 }
2435c4b64e6SXin LI
2445c4b64e6SXin LI
2455c4b64e6SXin LI /// \brief Parse the Index(es) from the given .xz file
2465c4b64e6SXin LI ///
2475c4b64e6SXin LI /// \param xfi Pointer to structure where the decoded information
2485c4b64e6SXin LI /// is stored.
2495c4b64e6SXin LI /// \param pair Input file
2505c4b64e6SXin LI ///
2515c4b64e6SXin LI /// \return On success, false is returned. On error, true is returned.
2525c4b64e6SXin LI ///
2535c4b64e6SXin LI // TODO: This function is pretty big. liblzma should have a function that
2545c4b64e6SXin LI // takes a callback function to parse the Index(es) from a .xz file to make
2555c4b64e6SXin LI // it easy for applications.
2565c4b64e6SXin LI static bool
parse_indexes(xz_file_info * xfi,int src_fd)2575c4b64e6SXin LI parse_indexes(xz_file_info *xfi, int src_fd)
2585c4b64e6SXin LI {
2595c4b64e6SXin LI struct stat st;
2605c4b64e6SXin LI
26158135fbdSEric van Gyzen if (fstat(src_fd, &st) != 0) {
2625c4b64e6SXin LI return true;
2635c4b64e6SXin LI }
2645c4b64e6SXin LI
2655c4b64e6SXin LI if (st.st_size < 2 * LZMA_STREAM_HEADER_SIZE) {
2665c4b64e6SXin LI return true;
2675c4b64e6SXin LI }
2685c4b64e6SXin LI
2695c4b64e6SXin LI io_buf buf;
2705c4b64e6SXin LI lzma_stream_flags header_flags;
2715c4b64e6SXin LI lzma_stream_flags footer_flags;
2725c4b64e6SXin LI lzma_ret ret;
2735c4b64e6SXin LI
2745c4b64e6SXin LI // lzma_stream for the Index decoder
2755c4b64e6SXin LI lzma_stream strm = LZMA_STREAM_INIT;
2765c4b64e6SXin LI
2775c4b64e6SXin LI // All Indexes decoded so far
2785c4b64e6SXin LI lzma_index *combined_index = NULL;
2795c4b64e6SXin LI
2805c4b64e6SXin LI // The Index currently being decoded
2815c4b64e6SXin LI lzma_index *this_index = NULL;
2825c4b64e6SXin LI
2835c4b64e6SXin LI // Current position in the file. We parse the file backwards so
2845c4b64e6SXin LI // initialize it to point to the end of the file.
2855c4b64e6SXin LI off_t pos = st.st_size;
2865c4b64e6SXin LI
2875c4b64e6SXin LI // Each loop iteration decodes one Index.
2885c4b64e6SXin LI do {
2895c4b64e6SXin LI // Check that there is enough data left to contain at least
2905c4b64e6SXin LI // the Stream Header and Stream Footer. This check cannot
2915c4b64e6SXin LI // fail in the first pass of this loop.
2925c4b64e6SXin LI if (pos < 2 * LZMA_STREAM_HEADER_SIZE) {
2935c4b64e6SXin LI goto error;
2945c4b64e6SXin LI }
2955c4b64e6SXin LI
2965c4b64e6SXin LI pos -= LZMA_STREAM_HEADER_SIZE;
2975c4b64e6SXin LI lzma_vli stream_padding = 0;
2985c4b64e6SXin LI
2995c4b64e6SXin LI // Locate the Stream Footer. There may be Stream Padding which
3005c4b64e6SXin LI // we must skip when reading backwards.
3015c4b64e6SXin LI while (true) {
3025c4b64e6SXin LI if (pos < LZMA_STREAM_HEADER_SIZE) {
3035c4b64e6SXin LI goto error;
3045c4b64e6SXin LI }
3055c4b64e6SXin LI
3065c4b64e6SXin LI if (io_pread(src_fd, &buf,
3075c4b64e6SXin LI LZMA_STREAM_HEADER_SIZE, pos))
3085c4b64e6SXin LI goto error;
3095c4b64e6SXin LI
3105c4b64e6SXin LI // Stream Padding is always a multiple of four bytes.
3115c4b64e6SXin LI int i = 2;
3125c4b64e6SXin LI if (buf.u32[i] != 0)
3135c4b64e6SXin LI break;
3145c4b64e6SXin LI
3155c4b64e6SXin LI // To avoid calling io_pread() for every four bytes
3165c4b64e6SXin LI // of Stream Padding, take advantage that we read
3175c4b64e6SXin LI // 12 bytes (LZMA_STREAM_HEADER_SIZE) already and
3185c4b64e6SXin LI // check them too before calling io_pread() again.
3195c4b64e6SXin LI do {
3205c4b64e6SXin LI stream_padding += 4;
3215c4b64e6SXin LI pos -= 4;
3225c4b64e6SXin LI --i;
3235c4b64e6SXin LI } while (i >= 0 && buf.u32[i] == 0);
3245c4b64e6SXin LI }
3255c4b64e6SXin LI
3265c4b64e6SXin LI // Decode the Stream Footer.
3275c4b64e6SXin LI ret = lzma_stream_footer_decode(&footer_flags, buf.u8);
3285c4b64e6SXin LI if (ret != LZMA_OK) {
3295c4b64e6SXin LI goto error;
3305c4b64e6SXin LI }
3315c4b64e6SXin LI
3325c4b64e6SXin LI // Check that the Stream Footer doesn't specify something
3335c4b64e6SXin LI // that we don't support. This can only happen if the xz
3345c4b64e6SXin LI // version is older than liblzma and liblzma supports
3355c4b64e6SXin LI // something new.
3365c4b64e6SXin LI //
3375c4b64e6SXin LI // It is enough to check Stream Footer. Stream Header must
3385c4b64e6SXin LI // match when it is compared against Stream Footer with
3395c4b64e6SXin LI // lzma_stream_flags_compare().
3405c4b64e6SXin LI if (footer_flags.version != 0) {
3415c4b64e6SXin LI goto error;
3425c4b64e6SXin LI }
3435c4b64e6SXin LI
3445c4b64e6SXin LI // Check that the size of the Index field looks sane.
3455c4b64e6SXin LI lzma_vli index_size = footer_flags.backward_size;
3465c4b64e6SXin LI if ((lzma_vli)(pos) < index_size + LZMA_STREAM_HEADER_SIZE) {
3475c4b64e6SXin LI goto error;
3485c4b64e6SXin LI }
3495c4b64e6SXin LI
3505c4b64e6SXin LI // Set pos to the beginning of the Index.
3515c4b64e6SXin LI pos -= index_size;
3525c4b64e6SXin LI
3535c4b64e6SXin LI // Decode the Index.
3545c4b64e6SXin LI ret = lzma_index_decoder(&strm, &this_index, UINT64_MAX);
3555c4b64e6SXin LI if (ret != LZMA_OK) {
3565c4b64e6SXin LI goto error;
3575c4b64e6SXin LI }
3585c4b64e6SXin LI
3595c4b64e6SXin LI do {
3605c4b64e6SXin LI // Don't give the decoder more input than the
3615c4b64e6SXin LI // Index size.
3625c4b64e6SXin LI strm.avail_in = my_min(IO_BUFFER_SIZE, index_size);
3635c4b64e6SXin LI if (io_pread(src_fd, &buf, strm.avail_in, pos))
3645c4b64e6SXin LI goto error;
3655c4b64e6SXin LI
3665c4b64e6SXin LI pos += strm.avail_in;
3675c4b64e6SXin LI index_size -= strm.avail_in;
3685c4b64e6SXin LI
3695c4b64e6SXin LI strm.next_in = buf.u8;
3705c4b64e6SXin LI ret = lzma_code(&strm, LZMA_RUN);
3715c4b64e6SXin LI
3725c4b64e6SXin LI } while (ret == LZMA_OK);
3735c4b64e6SXin LI
3745c4b64e6SXin LI // If the decoding seems to be successful, check also that
3755c4b64e6SXin LI // the Index decoder consumed as much input as indicated
3765c4b64e6SXin LI // by the Backward Size field.
3775c4b64e6SXin LI if (ret == LZMA_STREAM_END)
3785c4b64e6SXin LI if (index_size != 0 || strm.avail_in != 0)
3795c4b64e6SXin LI ret = LZMA_DATA_ERROR;
3805c4b64e6SXin LI
3815c4b64e6SXin LI if (ret != LZMA_STREAM_END) {
3825c4b64e6SXin LI // LZMA_BUFFER_ERROR means that the Index decoder
3835c4b64e6SXin LI // would have liked more input than what the Index
3845c4b64e6SXin LI // size should be according to Stream Footer.
3855c4b64e6SXin LI // The message for LZMA_DATA_ERROR makes more
3865c4b64e6SXin LI // sense in that case.
3875c4b64e6SXin LI if (ret == LZMA_BUF_ERROR)
3885c4b64e6SXin LI ret = LZMA_DATA_ERROR;
3895c4b64e6SXin LI
3905c4b64e6SXin LI goto error;
3915c4b64e6SXin LI }
3925c4b64e6SXin LI
3935c4b64e6SXin LI // Decode the Stream Header and check that its Stream Flags
3945c4b64e6SXin LI // match the Stream Footer.
3955c4b64e6SXin LI pos -= footer_flags.backward_size + LZMA_STREAM_HEADER_SIZE;
3965c4b64e6SXin LI if ((lzma_vli)(pos) < lzma_index_total_size(this_index)) {
3975c4b64e6SXin LI goto error;
3985c4b64e6SXin LI }
3995c4b64e6SXin LI
4005c4b64e6SXin LI pos -= lzma_index_total_size(this_index);
4015c4b64e6SXin LI if (io_pread(src_fd, &buf, LZMA_STREAM_HEADER_SIZE, pos))
4025c4b64e6SXin LI goto error;
4035c4b64e6SXin LI
4045c4b64e6SXin LI ret = lzma_stream_header_decode(&header_flags, buf.u8);
4055c4b64e6SXin LI if (ret != LZMA_OK) {
4065c4b64e6SXin LI goto error;
4075c4b64e6SXin LI }
4085c4b64e6SXin LI
4095c4b64e6SXin LI ret = lzma_stream_flags_compare(&header_flags, &footer_flags);
4105c4b64e6SXin LI if (ret != LZMA_OK) {
4115c4b64e6SXin LI goto error;
4125c4b64e6SXin LI }
4135c4b64e6SXin LI
4145c4b64e6SXin LI // Store the decoded Stream Flags into this_index. This is
4155c4b64e6SXin LI // needed so that we can print which Check is used in each
4165c4b64e6SXin LI // Stream.
4175c4b64e6SXin LI ret = lzma_index_stream_flags(this_index, &footer_flags);
4185c4b64e6SXin LI if (ret != LZMA_OK)
4195c4b64e6SXin LI goto error;
4205c4b64e6SXin LI
4215c4b64e6SXin LI // Store also the size of the Stream Padding field. It is
4225c4b64e6SXin LI // needed to show the offsets of the Streams correctly.
4235c4b64e6SXin LI ret = lzma_index_stream_padding(this_index, stream_padding);
4245c4b64e6SXin LI if (ret != LZMA_OK)
4255c4b64e6SXin LI goto error;
4265c4b64e6SXin LI
4275c4b64e6SXin LI if (combined_index != NULL) {
4285c4b64e6SXin LI // Append the earlier decoded Indexes
4295c4b64e6SXin LI // after this_index.
4305c4b64e6SXin LI ret = lzma_index_cat(
4315c4b64e6SXin LI this_index, combined_index, NULL);
4325c4b64e6SXin LI if (ret != LZMA_OK) {
4335c4b64e6SXin LI goto error;
4345c4b64e6SXin LI }
4355c4b64e6SXin LI }
4365c4b64e6SXin LI
4375c4b64e6SXin LI combined_index = this_index;
4385c4b64e6SXin LI this_index = NULL;
4395c4b64e6SXin LI
4405c4b64e6SXin LI xfi->stream_padding += stream_padding;
4415c4b64e6SXin LI
4425c4b64e6SXin LI } while (pos > 0);
4435c4b64e6SXin LI
4445c4b64e6SXin LI lzma_end(&strm);
4455c4b64e6SXin LI
4465c4b64e6SXin LI // All OK. Make combined_index available to the caller.
4475c4b64e6SXin LI xfi->idx = combined_index;
4485c4b64e6SXin LI return false;
4495c4b64e6SXin LI
4505c4b64e6SXin LI error:
4515c4b64e6SXin LI // Something went wrong, free the allocated memory.
4525c4b64e6SXin LI lzma_end(&strm);
4535c4b64e6SXin LI lzma_index_end(combined_index, NULL);
4545c4b64e6SXin LI lzma_index_end(this_index, NULL);
4555c4b64e6SXin LI return true;
4565c4b64e6SXin LI }
4575c4b64e6SXin LI
4585c4b64e6SXin LI /***************** end of copy form list.c *************************/
4595c4b64e6SXin LI
4605c4b64e6SXin LI /*
4615c4b64e6SXin LI * Small wrapper to extract total length of a file
4625c4b64e6SXin LI */
4635c4b64e6SXin LI off_t
unxz_len(int fd)4645c4b64e6SXin LI unxz_len(int fd)
4655c4b64e6SXin LI {
4665c4b64e6SXin LI xz_file_info xfi = XZ_FILE_INFO_INIT;
4675c4b64e6SXin LI if (!parse_indexes(&xfi, fd)) {
4685c4b64e6SXin LI off_t res = lzma_index_uncompressed_size(xfi.idx);
4695c4b64e6SXin LI lzma_index_end(xfi.idx, NULL);
4705c4b64e6SXin LI return res;
4715c4b64e6SXin LI }
4725c4b64e6SXin LI return 0;
4735c4b64e6SXin LI }
4745c4b64e6SXin LI
475