1*7304104dSAndroid Build Coastguard Worker /* Decompression support for libdwfl: zlib (gzip) and/or bzlib (bzip2).
2*7304104dSAndroid Build Coastguard Worker Copyright (C) 2009 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker
5*7304104dSAndroid Build Coastguard Worker This file is free software; you can redistribute it and/or modify
6*7304104dSAndroid Build Coastguard Worker it under the terms of either
7*7304104dSAndroid Build Coastguard Worker
8*7304104dSAndroid Build Coastguard Worker * the GNU Lesser General Public License as published by the Free
9*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 3 of the License, or (at
10*7304104dSAndroid Build Coastguard Worker your option) any later version
11*7304104dSAndroid Build Coastguard Worker
12*7304104dSAndroid Build Coastguard Worker or
13*7304104dSAndroid Build Coastguard Worker
14*7304104dSAndroid Build Coastguard Worker * the GNU General Public License as published by the Free
15*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 2 of the License, or (at
16*7304104dSAndroid Build Coastguard Worker your option) any later version
17*7304104dSAndroid Build Coastguard Worker
18*7304104dSAndroid Build Coastguard Worker or both in parallel, as here.
19*7304104dSAndroid Build Coastguard Worker
20*7304104dSAndroid Build Coastguard Worker elfutils is distributed in the hope that it will be useful, but
21*7304104dSAndroid Build Coastguard Worker WITHOUT ANY WARRANTY; without even the implied warranty of
22*7304104dSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23*7304104dSAndroid Build Coastguard Worker General Public License for more details.
24*7304104dSAndroid Build Coastguard Worker
25*7304104dSAndroid Build Coastguard Worker You should have received copies of the GNU General Public License and
26*7304104dSAndroid Build Coastguard Worker the GNU Lesser General Public License along with this program. If
27*7304104dSAndroid Build Coastguard Worker not, see <http://www.gnu.org/licenses/>. */
28*7304104dSAndroid Build Coastguard Worker
29*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
30*7304104dSAndroid Build Coastguard Worker # include <config.h>
31*7304104dSAndroid Build Coastguard Worker #endif
32*7304104dSAndroid Build Coastguard Worker
33*7304104dSAndroid Build Coastguard Worker #include "libdwflP.h"
34*7304104dSAndroid Build Coastguard Worker #include "system.h"
35*7304104dSAndroid Build Coastguard Worker
36*7304104dSAndroid Build Coastguard Worker #ifdef LZMA
37*7304104dSAndroid Build Coastguard Worker # define USE_INFLATE 1
38*7304104dSAndroid Build Coastguard Worker # include <lzma.h>
39*7304104dSAndroid Build Coastguard Worker # define unzip __libdw_unlzma
40*7304104dSAndroid Build Coastguard Worker # define DWFL_E_ZLIB DWFL_E_LZMA
41*7304104dSAndroid Build Coastguard Worker # define MAGIC "\xFD" "7zXZ\0" /* XZ file format. */
42*7304104dSAndroid Build Coastguard Worker # define MAGIC2 "\x5d\0" /* Raw LZMA format. */
43*7304104dSAndroid Build Coastguard Worker # define Z(what) LZMA_##what
44*7304104dSAndroid Build Coastguard Worker # define LZMA_ERRNO LZMA_PROG_ERROR
45*7304104dSAndroid Build Coastguard Worker # define z_stream lzma_stream
46*7304104dSAndroid Build Coastguard Worker # define inflateInit(z) lzma_auto_decoder (z, 1 << 30, 0)
47*7304104dSAndroid Build Coastguard Worker # define do_inflate(z) lzma_code (z, LZMA_RUN)
48*7304104dSAndroid Build Coastguard Worker # define inflateEnd(z) lzma_end (z)
49*7304104dSAndroid Build Coastguard Worker #elif defined ZSTD
50*7304104dSAndroid Build Coastguard Worker # define USE_INFLATE 1
51*7304104dSAndroid Build Coastguard Worker # include <zstd.h>
52*7304104dSAndroid Build Coastguard Worker # define unzip __libdw_unzstd
53*7304104dSAndroid Build Coastguard Worker # define DWFL_E_ZLIB DWFL_E_ZSTD
54*7304104dSAndroid Build Coastguard Worker # define MAGIC "\x28\xb5\x2f\xfd"
55*7304104dSAndroid Build Coastguard Worker #elif defined BZLIB
56*7304104dSAndroid Build Coastguard Worker # define USE_INFLATE 1
57*7304104dSAndroid Build Coastguard Worker # include <bzlib.h>
58*7304104dSAndroid Build Coastguard Worker # define unzip __libdw_bunzip2
59*7304104dSAndroid Build Coastguard Worker # define DWFL_E_ZLIB DWFL_E_BZLIB
60*7304104dSAndroid Build Coastguard Worker # define MAGIC "BZh"
61*7304104dSAndroid Build Coastguard Worker # define Z(what) BZ_##what
62*7304104dSAndroid Build Coastguard Worker # define BZ_ERRNO BZ_IO_ERROR
63*7304104dSAndroid Build Coastguard Worker # define z_stream bz_stream
64*7304104dSAndroid Build Coastguard Worker # define inflateInit(z) BZ2_bzDecompressInit (z, 0, 0)
65*7304104dSAndroid Build Coastguard Worker # define do_inflate(z) BZ2_bzDecompress (z)
66*7304104dSAndroid Build Coastguard Worker # define inflateEnd(z) BZ2_bzDecompressEnd (z)
67*7304104dSAndroid Build Coastguard Worker #else
68*7304104dSAndroid Build Coastguard Worker # define USE_INFLATE 0
69*7304104dSAndroid Build Coastguard Worker # define crc32 loser_crc32
70*7304104dSAndroid Build Coastguard Worker # include <zlib.h>
71*7304104dSAndroid Build Coastguard Worker # define unzip __libdw_gunzip
72*7304104dSAndroid Build Coastguard Worker # define MAGIC "\037\213"
73*7304104dSAndroid Build Coastguard Worker # define Z(what) Z_##what
74*7304104dSAndroid Build Coastguard Worker #endif
75*7304104dSAndroid Build Coastguard Worker
76*7304104dSAndroid Build Coastguard Worker #define READ_SIZE (1 << 20)
77*7304104dSAndroid Build Coastguard Worker
78*7304104dSAndroid Build Coastguard Worker struct unzip_state {
79*7304104dSAndroid Build Coastguard Worker #if !USE_INFLATE
80*7304104dSAndroid Build Coastguard Worker gzFile zf;
81*7304104dSAndroid Build Coastguard Worker #endif
82*7304104dSAndroid Build Coastguard Worker size_t mapped_size;
83*7304104dSAndroid Build Coastguard Worker void **whole;
84*7304104dSAndroid Build Coastguard Worker void *buffer;
85*7304104dSAndroid Build Coastguard Worker size_t size;
86*7304104dSAndroid Build Coastguard Worker void *input_buffer;
87*7304104dSAndroid Build Coastguard Worker off_t input_pos;
88*7304104dSAndroid Build Coastguard Worker };
89*7304104dSAndroid Build Coastguard Worker
90*7304104dSAndroid Build Coastguard Worker static inline bool
bigger_buffer(struct unzip_state * state,size_t start)91*7304104dSAndroid Build Coastguard Worker bigger_buffer (struct unzip_state *state, size_t start)
92*7304104dSAndroid Build Coastguard Worker {
93*7304104dSAndroid Build Coastguard Worker size_t more = state->size ? state->size * 2 : start;
94*7304104dSAndroid Build Coastguard Worker char *b = realloc (state->buffer, more);
95*7304104dSAndroid Build Coastguard Worker while (unlikely (b == NULL) && more >= state->size + 1024)
96*7304104dSAndroid Build Coastguard Worker b = realloc (state->buffer, more -= 1024);
97*7304104dSAndroid Build Coastguard Worker if (unlikely (b == NULL))
98*7304104dSAndroid Build Coastguard Worker return false;
99*7304104dSAndroid Build Coastguard Worker state->buffer = b;
100*7304104dSAndroid Build Coastguard Worker state->size = more;
101*7304104dSAndroid Build Coastguard Worker return true;
102*7304104dSAndroid Build Coastguard Worker }
103*7304104dSAndroid Build Coastguard Worker
104*7304104dSAndroid Build Coastguard Worker static inline void
smaller_buffer(struct unzip_state * state,size_t end)105*7304104dSAndroid Build Coastguard Worker smaller_buffer (struct unzip_state *state, size_t end)
106*7304104dSAndroid Build Coastguard Worker {
107*7304104dSAndroid Build Coastguard Worker state->buffer =
108*7304104dSAndroid Build Coastguard Worker realloc (state->buffer, end) ?: end == 0 ? NULL : state->buffer;
109*7304104dSAndroid Build Coastguard Worker state->size = end;
110*7304104dSAndroid Build Coastguard Worker }
111*7304104dSAndroid Build Coastguard Worker
112*7304104dSAndroid Build Coastguard Worker static inline Dwfl_Error
fail(struct unzip_state * state,Dwfl_Error failure)113*7304104dSAndroid Build Coastguard Worker fail (struct unzip_state *state, Dwfl_Error failure)
114*7304104dSAndroid Build Coastguard Worker {
115*7304104dSAndroid Build Coastguard Worker if (state->input_pos == (off_t) state->mapped_size)
116*7304104dSAndroid Build Coastguard Worker *state->whole = state->input_buffer;
117*7304104dSAndroid Build Coastguard Worker else
118*7304104dSAndroid Build Coastguard Worker {
119*7304104dSAndroid Build Coastguard Worker free (state->input_buffer);
120*7304104dSAndroid Build Coastguard Worker *state->whole = NULL;
121*7304104dSAndroid Build Coastguard Worker }
122*7304104dSAndroid Build Coastguard Worker free (state->buffer);
123*7304104dSAndroid Build Coastguard Worker return failure;
124*7304104dSAndroid Build Coastguard Worker }
125*7304104dSAndroid Build Coastguard Worker
126*7304104dSAndroid Build Coastguard Worker #ifndef ZSTD
127*7304104dSAndroid Build Coastguard Worker static inline Dwfl_Error
zlib_fail(struct unzip_state * state,int result)128*7304104dSAndroid Build Coastguard Worker zlib_fail (struct unzip_state *state, int result)
129*7304104dSAndroid Build Coastguard Worker {
130*7304104dSAndroid Build Coastguard Worker switch (result)
131*7304104dSAndroid Build Coastguard Worker {
132*7304104dSAndroid Build Coastguard Worker case Z (MEM_ERROR):
133*7304104dSAndroid Build Coastguard Worker return fail (state, DWFL_E_NOMEM);
134*7304104dSAndroid Build Coastguard Worker case Z (ERRNO):
135*7304104dSAndroid Build Coastguard Worker return fail (state, DWFL_E_ERRNO);
136*7304104dSAndroid Build Coastguard Worker default:
137*7304104dSAndroid Build Coastguard Worker return fail (state, DWFL_E_ZLIB);
138*7304104dSAndroid Build Coastguard Worker }
139*7304104dSAndroid Build Coastguard Worker }
140*7304104dSAndroid Build Coastguard Worker #endif
141*7304104dSAndroid Build Coastguard Worker
142*7304104dSAndroid Build Coastguard Worker #if !USE_INFLATE
143*7304104dSAndroid Build Coastguard Worker static Dwfl_Error
open_stream(int fd,off_t start_offset,struct unzip_state * state)144*7304104dSAndroid Build Coastguard Worker open_stream (int fd, off_t start_offset, struct unzip_state *state)
145*7304104dSAndroid Build Coastguard Worker {
146*7304104dSAndroid Build Coastguard Worker int d = dup (fd);
147*7304104dSAndroid Build Coastguard Worker if (unlikely (d < 0))
148*7304104dSAndroid Build Coastguard Worker return DWFL_E_ERRNO;
149*7304104dSAndroid Build Coastguard Worker if (start_offset != 0)
150*7304104dSAndroid Build Coastguard Worker {
151*7304104dSAndroid Build Coastguard Worker off_t off = lseek (d, start_offset, SEEK_SET);
152*7304104dSAndroid Build Coastguard Worker if (off != start_offset)
153*7304104dSAndroid Build Coastguard Worker {
154*7304104dSAndroid Build Coastguard Worker close (d);
155*7304104dSAndroid Build Coastguard Worker return DWFL_E_ERRNO;
156*7304104dSAndroid Build Coastguard Worker }
157*7304104dSAndroid Build Coastguard Worker }
158*7304104dSAndroid Build Coastguard Worker state->zf = gzdopen (d, "r");
159*7304104dSAndroid Build Coastguard Worker if (unlikely (state->zf == NULL))
160*7304104dSAndroid Build Coastguard Worker {
161*7304104dSAndroid Build Coastguard Worker close (d);
162*7304104dSAndroid Build Coastguard Worker return DWFL_E_NOMEM;
163*7304104dSAndroid Build Coastguard Worker }
164*7304104dSAndroid Build Coastguard Worker
165*7304104dSAndroid Build Coastguard Worker /* From here on, zlib will close D. */
166*7304104dSAndroid Build Coastguard Worker
167*7304104dSAndroid Build Coastguard Worker return DWFL_E_NOERROR;
168*7304104dSAndroid Build Coastguard Worker }
169*7304104dSAndroid Build Coastguard Worker #endif
170*7304104dSAndroid Build Coastguard Worker
171*7304104dSAndroid Build Coastguard Worker /* If this is not a compressed image, return DWFL_E_BADELF.
172*7304104dSAndroid Build Coastguard Worker If we uncompressed it into *WHOLE, *WHOLE_SIZE, return DWFL_E_NOERROR.
173*7304104dSAndroid Build Coastguard Worker Otherwise return an error for bad compressed data or I/O failure.
174*7304104dSAndroid Build Coastguard Worker If we return an error after reading the first part of the file,
175*7304104dSAndroid Build Coastguard Worker leave that portion malloc'd in *WHOLE, *WHOLE_SIZE. If *WHOLE
176*7304104dSAndroid Build Coastguard Worker is not null on entry, we'll use it in lieu of repeating a read. */
177*7304104dSAndroid Build Coastguard Worker
178*7304104dSAndroid Build Coastguard Worker Dwfl_Error internal_function
unzip(int fd,off_t start_offset,void * mapped,size_t _mapped_size,void ** _whole,size_t * whole_size)179*7304104dSAndroid Build Coastguard Worker unzip (int fd, off_t start_offset,
180*7304104dSAndroid Build Coastguard Worker void *mapped, size_t _mapped_size,
181*7304104dSAndroid Build Coastguard Worker void **_whole, size_t *whole_size)
182*7304104dSAndroid Build Coastguard Worker {
183*7304104dSAndroid Build Coastguard Worker struct unzip_state state =
184*7304104dSAndroid Build Coastguard Worker {
185*7304104dSAndroid Build Coastguard Worker #if !USE_INFLATE
186*7304104dSAndroid Build Coastguard Worker .zf = NULL,
187*7304104dSAndroid Build Coastguard Worker #endif
188*7304104dSAndroid Build Coastguard Worker .mapped_size = _mapped_size,
189*7304104dSAndroid Build Coastguard Worker .whole = _whole,
190*7304104dSAndroid Build Coastguard Worker .buffer = NULL,
191*7304104dSAndroid Build Coastguard Worker .size = 0,
192*7304104dSAndroid Build Coastguard Worker .input_buffer = NULL,
193*7304104dSAndroid Build Coastguard Worker .input_pos = 0
194*7304104dSAndroid Build Coastguard Worker };
195*7304104dSAndroid Build Coastguard Worker
196*7304104dSAndroid Build Coastguard Worker if (mapped == NULL)
197*7304104dSAndroid Build Coastguard Worker {
198*7304104dSAndroid Build Coastguard Worker if (*state.whole == NULL)
199*7304104dSAndroid Build Coastguard Worker {
200*7304104dSAndroid Build Coastguard Worker state.input_buffer = malloc (READ_SIZE);
201*7304104dSAndroid Build Coastguard Worker if (unlikely (state.input_buffer == NULL))
202*7304104dSAndroid Build Coastguard Worker return DWFL_E_NOMEM;
203*7304104dSAndroid Build Coastguard Worker
204*7304104dSAndroid Build Coastguard Worker ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE, start_offset);
205*7304104dSAndroid Build Coastguard Worker if (unlikely (n < 0))
206*7304104dSAndroid Build Coastguard Worker return fail (&state, DWFL_E_ERRNO);
207*7304104dSAndroid Build Coastguard Worker
208*7304104dSAndroid Build Coastguard Worker state.input_pos = n;
209*7304104dSAndroid Build Coastguard Worker mapped = state.input_buffer;
210*7304104dSAndroid Build Coastguard Worker state.mapped_size = n;
211*7304104dSAndroid Build Coastguard Worker }
212*7304104dSAndroid Build Coastguard Worker else
213*7304104dSAndroid Build Coastguard Worker {
214*7304104dSAndroid Build Coastguard Worker state.input_buffer = *state.whole;
215*7304104dSAndroid Build Coastguard Worker state.input_pos = state.mapped_size = *whole_size;
216*7304104dSAndroid Build Coastguard Worker }
217*7304104dSAndroid Build Coastguard Worker }
218*7304104dSAndroid Build Coastguard Worker
219*7304104dSAndroid Build Coastguard Worker #define NOMAGIC(magic) \
220*7304104dSAndroid Build Coastguard Worker (state.mapped_size <= sizeof magic || \
221*7304104dSAndroid Build Coastguard Worker memcmp (mapped, magic, sizeof magic - 1))
222*7304104dSAndroid Build Coastguard Worker
223*7304104dSAndroid Build Coastguard Worker /* First, look at the header. */
224*7304104dSAndroid Build Coastguard Worker if (NOMAGIC (MAGIC)
225*7304104dSAndroid Build Coastguard Worker #ifdef MAGIC2
226*7304104dSAndroid Build Coastguard Worker && NOMAGIC (MAGIC2)
227*7304104dSAndroid Build Coastguard Worker #endif
228*7304104dSAndroid Build Coastguard Worker )
229*7304104dSAndroid Build Coastguard Worker /* Not a compressed file. */
230*7304104dSAndroid Build Coastguard Worker return fail (&state, DWFL_E_BADELF);
231*7304104dSAndroid Build Coastguard Worker
232*7304104dSAndroid Build Coastguard Worker #ifdef ZSTD
233*7304104dSAndroid Build Coastguard Worker /* special case for libzstd since it is slightly different from the
234*7304104dSAndroid Build Coastguard Worker API provided by bzlib and liblzma. */
235*7304104dSAndroid Build Coastguard Worker
236*7304104dSAndroid Build Coastguard Worker void *next_in = mapped;
237*7304104dSAndroid Build Coastguard Worker size_t avail_in = state.mapped_size;
238*7304104dSAndroid Build Coastguard Worker void *next_out = NULL;
239*7304104dSAndroid Build Coastguard Worker size_t avail_out = 0;
240*7304104dSAndroid Build Coastguard Worker size_t total_out = 0;
241*7304104dSAndroid Build Coastguard Worker
242*7304104dSAndroid Build Coastguard Worker size_t result;
243*7304104dSAndroid Build Coastguard Worker ZSTD_DCtx *dctx = ZSTD_createDCtx();
244*7304104dSAndroid Build Coastguard Worker if (dctx == NULL)
245*7304104dSAndroid Build Coastguard Worker return fail (&state, DWFL_E_NOMEM);
246*7304104dSAndroid Build Coastguard Worker
247*7304104dSAndroid Build Coastguard Worker do
248*7304104dSAndroid Build Coastguard Worker {
249*7304104dSAndroid Build Coastguard Worker if (avail_in == 0 && state.input_buffer != NULL)
250*7304104dSAndroid Build Coastguard Worker {
251*7304104dSAndroid Build Coastguard Worker ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE,
252*7304104dSAndroid Build Coastguard Worker start_offset + state.input_pos);
253*7304104dSAndroid Build Coastguard Worker if (unlikely (n < 0))
254*7304104dSAndroid Build Coastguard Worker {
255*7304104dSAndroid Build Coastguard Worker ZSTD_freeDCtx (dctx);
256*7304104dSAndroid Build Coastguard Worker return fail (&state, DWFL_E_ERRNO);
257*7304104dSAndroid Build Coastguard Worker }
258*7304104dSAndroid Build Coastguard Worker next_in = state.input_buffer;
259*7304104dSAndroid Build Coastguard Worker avail_in = n;
260*7304104dSAndroid Build Coastguard Worker state.input_pos += n;
261*7304104dSAndroid Build Coastguard Worker }
262*7304104dSAndroid Build Coastguard Worker if (avail_out == 0)
263*7304104dSAndroid Build Coastguard Worker {
264*7304104dSAndroid Build Coastguard Worker ptrdiff_t pos = (void *) next_out - state.buffer;
265*7304104dSAndroid Build Coastguard Worker if (!bigger_buffer (&state, avail_in))
266*7304104dSAndroid Build Coastguard Worker {
267*7304104dSAndroid Build Coastguard Worker ZSTD_freeDCtx (dctx);
268*7304104dSAndroid Build Coastguard Worker return fail (&state, DWFL_E_NOMEM);
269*7304104dSAndroid Build Coastguard Worker }
270*7304104dSAndroid Build Coastguard Worker next_out = state.buffer + pos;
271*7304104dSAndroid Build Coastguard Worker avail_out = state.size - pos;
272*7304104dSAndroid Build Coastguard Worker }
273*7304104dSAndroid Build Coastguard Worker
274*7304104dSAndroid Build Coastguard Worker ZSTD_inBuffer input = { next_in, avail_in, 0 };
275*7304104dSAndroid Build Coastguard Worker ZSTD_outBuffer output = { next_out, avail_out, 0 };
276*7304104dSAndroid Build Coastguard Worker result = ZSTD_decompressStream (dctx, &output, &input);
277*7304104dSAndroid Build Coastguard Worker
278*7304104dSAndroid Build Coastguard Worker if (! ZSTD_isError (result))
279*7304104dSAndroid Build Coastguard Worker {
280*7304104dSAndroid Build Coastguard Worker total_out += output.pos;
281*7304104dSAndroid Build Coastguard Worker next_out += output.pos;
282*7304104dSAndroid Build Coastguard Worker avail_out -= output.pos;
283*7304104dSAndroid Build Coastguard Worker next_in += input.pos;
284*7304104dSAndroid Build Coastguard Worker avail_in -= input.pos;
285*7304104dSAndroid Build Coastguard Worker }
286*7304104dSAndroid Build Coastguard Worker
287*7304104dSAndroid Build Coastguard Worker if (result == 0)
288*7304104dSAndroid Build Coastguard Worker break;
289*7304104dSAndroid Build Coastguard Worker }
290*7304104dSAndroid Build Coastguard Worker while (avail_in > 0 && ! ZSTD_isError (result));
291*7304104dSAndroid Build Coastguard Worker
292*7304104dSAndroid Build Coastguard Worker ZSTD_freeDCtx (dctx);
293*7304104dSAndroid Build Coastguard Worker
294*7304104dSAndroid Build Coastguard Worker if (ZSTD_isError (result))
295*7304104dSAndroid Build Coastguard Worker return fail (&state, DWFL_E_ZSTD);
296*7304104dSAndroid Build Coastguard Worker
297*7304104dSAndroid Build Coastguard Worker smaller_buffer (&state, total_out);
298*7304104dSAndroid Build Coastguard Worker
299*7304104dSAndroid Build Coastguard Worker #elif USE_INFLATE
300*7304104dSAndroid Build Coastguard Worker
301*7304104dSAndroid Build Coastguard Worker /* This style actually only works with bzlib and liblzma.
302*7304104dSAndroid Build Coastguard Worker The stupid zlib interface has nothing to grok the
303*7304104dSAndroid Build Coastguard Worker gzip file headers except the slow gzFile interface. */
304*7304104dSAndroid Build Coastguard Worker
305*7304104dSAndroid Build Coastguard Worker z_stream z = { .next_in = mapped, .avail_in = state.mapped_size };
306*7304104dSAndroid Build Coastguard Worker int result = inflateInit (&z);
307*7304104dSAndroid Build Coastguard Worker if (result != Z (OK))
308*7304104dSAndroid Build Coastguard Worker {
309*7304104dSAndroid Build Coastguard Worker inflateEnd (&z);
310*7304104dSAndroid Build Coastguard Worker return zlib_fail (&state, result);
311*7304104dSAndroid Build Coastguard Worker }
312*7304104dSAndroid Build Coastguard Worker
313*7304104dSAndroid Build Coastguard Worker do
314*7304104dSAndroid Build Coastguard Worker {
315*7304104dSAndroid Build Coastguard Worker if (z.avail_in == 0 && state.input_buffer != NULL)
316*7304104dSAndroid Build Coastguard Worker {
317*7304104dSAndroid Build Coastguard Worker ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE,
318*7304104dSAndroid Build Coastguard Worker start_offset + state.input_pos);
319*7304104dSAndroid Build Coastguard Worker if (unlikely (n < 0))
320*7304104dSAndroid Build Coastguard Worker {
321*7304104dSAndroid Build Coastguard Worker inflateEnd (&z);
322*7304104dSAndroid Build Coastguard Worker return zlib_fail (&state, Z (ERRNO));
323*7304104dSAndroid Build Coastguard Worker }
324*7304104dSAndroid Build Coastguard Worker z.next_in = state.input_buffer;
325*7304104dSAndroid Build Coastguard Worker z.avail_in = n;
326*7304104dSAndroid Build Coastguard Worker state.input_pos += n;
327*7304104dSAndroid Build Coastguard Worker }
328*7304104dSAndroid Build Coastguard Worker if (z.avail_out == 0)
329*7304104dSAndroid Build Coastguard Worker {
330*7304104dSAndroid Build Coastguard Worker ptrdiff_t pos = (void *) z.next_out - state.buffer;
331*7304104dSAndroid Build Coastguard Worker if (!bigger_buffer (&state, z.avail_in))
332*7304104dSAndroid Build Coastguard Worker {
333*7304104dSAndroid Build Coastguard Worker result = Z (MEM_ERROR);
334*7304104dSAndroid Build Coastguard Worker break;
335*7304104dSAndroid Build Coastguard Worker }
336*7304104dSAndroid Build Coastguard Worker z.next_out = state.buffer + pos;
337*7304104dSAndroid Build Coastguard Worker z.avail_out = state.size - pos;
338*7304104dSAndroid Build Coastguard Worker }
339*7304104dSAndroid Build Coastguard Worker }
340*7304104dSAndroid Build Coastguard Worker while ((result = do_inflate (&z)) == Z (OK));
341*7304104dSAndroid Build Coastguard Worker
342*7304104dSAndroid Build Coastguard Worker #ifdef BZLIB
343*7304104dSAndroid Build Coastguard Worker uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32)
344*7304104dSAndroid Build Coastguard Worker | z.total_out_lo32);
345*7304104dSAndroid Build Coastguard Worker smaller_buffer (&state, total_out);
346*7304104dSAndroid Build Coastguard Worker #else
347*7304104dSAndroid Build Coastguard Worker smaller_buffer (&state, z.total_out);
348*7304104dSAndroid Build Coastguard Worker #endif
349*7304104dSAndroid Build Coastguard Worker
350*7304104dSAndroid Build Coastguard Worker inflateEnd (&z);
351*7304104dSAndroid Build Coastguard Worker
352*7304104dSAndroid Build Coastguard Worker if (result != Z (STREAM_END))
353*7304104dSAndroid Build Coastguard Worker return zlib_fail (&state, result);
354*7304104dSAndroid Build Coastguard Worker
355*7304104dSAndroid Build Coastguard Worker #else /* gzip only. */
356*7304104dSAndroid Build Coastguard Worker
357*7304104dSAndroid Build Coastguard Worker /* Let the decompression library read the file directly. */
358*7304104dSAndroid Build Coastguard Worker
359*7304104dSAndroid Build Coastguard Worker Dwfl_Error result = open_stream (fd, start_offset, &state);
360*7304104dSAndroid Build Coastguard Worker
361*7304104dSAndroid Build Coastguard Worker if (result == DWFL_E_NOERROR && gzdirect (state.zf))
362*7304104dSAndroid Build Coastguard Worker {
363*7304104dSAndroid Build Coastguard Worker gzclose (state.zf);
364*7304104dSAndroid Build Coastguard Worker /* Not a compressed stream after all. */
365*7304104dSAndroid Build Coastguard Worker return fail (&state, DWFL_E_BADELF);
366*7304104dSAndroid Build Coastguard Worker }
367*7304104dSAndroid Build Coastguard Worker
368*7304104dSAndroid Build Coastguard Worker if (result != DWFL_E_NOERROR)
369*7304104dSAndroid Build Coastguard Worker return fail (&state, result);
370*7304104dSAndroid Build Coastguard Worker
371*7304104dSAndroid Build Coastguard Worker ptrdiff_t pos = 0;
372*7304104dSAndroid Build Coastguard Worker while (1)
373*7304104dSAndroid Build Coastguard Worker {
374*7304104dSAndroid Build Coastguard Worker if (!bigger_buffer (&state, 1024))
375*7304104dSAndroid Build Coastguard Worker {
376*7304104dSAndroid Build Coastguard Worker gzclose (state.zf);
377*7304104dSAndroid Build Coastguard Worker return zlib_fail (&state, Z (MEM_ERROR));
378*7304104dSAndroid Build Coastguard Worker }
379*7304104dSAndroid Build Coastguard Worker int n = gzread (state.zf, state.buffer + pos, state.size - pos);
380*7304104dSAndroid Build Coastguard Worker if (n < 0)
381*7304104dSAndroid Build Coastguard Worker {
382*7304104dSAndroid Build Coastguard Worker int code;
383*7304104dSAndroid Build Coastguard Worker gzerror (state.zf, &code);
384*7304104dSAndroid Build Coastguard Worker gzclose (state.zf);
385*7304104dSAndroid Build Coastguard Worker return zlib_fail (&state, code);
386*7304104dSAndroid Build Coastguard Worker }
387*7304104dSAndroid Build Coastguard Worker if (n == 0)
388*7304104dSAndroid Build Coastguard Worker break;
389*7304104dSAndroid Build Coastguard Worker pos += n;
390*7304104dSAndroid Build Coastguard Worker }
391*7304104dSAndroid Build Coastguard Worker
392*7304104dSAndroid Build Coastguard Worker gzclose (state.zf);
393*7304104dSAndroid Build Coastguard Worker smaller_buffer (&state, pos);
394*7304104dSAndroid Build Coastguard Worker #endif
395*7304104dSAndroid Build Coastguard Worker
396*7304104dSAndroid Build Coastguard Worker free (state.input_buffer);
397*7304104dSAndroid Build Coastguard Worker
398*7304104dSAndroid Build Coastguard Worker *state.whole = state.buffer;
399*7304104dSAndroid Build Coastguard Worker *whole_size = state.size;
400*7304104dSAndroid Build Coastguard Worker
401*7304104dSAndroid Build Coastguard Worker return DWFL_E_NOERROR;
402*7304104dSAndroid Build Coastguard Worker }
403