1 /* Decompression support for libdwfl: zlib (gzip) and/or bzlib (bzip2).
2 Copyright (C) 2009 Red Hat, Inc.
3 This file is part of elfutils.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
8 * the GNU Lesser General Public License as published by the Free
9 Software Foundation; either version 3 of the License, or (at
10 your option) any later version
14 * the GNU General Public License as published by the Free
15 Software Foundation; either version 2 of the License, or (at
16 your option) any later version
18 or both in parallel, as here.
20 elfutils is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received copies of the GNU General Public License and
26 the GNU Lesser General Public License along with this program. If
27 not, see <http://www.gnu.org/licenses/>. */
35 # define USE_INFLATE 1
37 # define unzip __libdw_unlzma
38 # define DWFL_E_ZLIB DWFL_E_LZMA
39 # define MAGIC "\xFD" "7zXZ\0" /* XZ file format. */
40 # define MAGIC2 "\x5d\0" /* Raw LZMA format. */
41 # define Z(what) LZMA_##what
42 # define LZMA_ERRNO LZMA_PROG_ERROR
43 # define z_stream lzma_stream
44 # define inflateInit(z) lzma_auto_decoder (z, 1 << 30, 0)
45 # define do_inflate(z) lzma_code (z, LZMA_RUN)
46 # define inflateEnd(z) lzma_end (z)
48 # define USE_INFLATE 1
50 # define unzip __libdw_bunzip2
51 # define DWFL_E_ZLIB DWFL_E_BZLIB
53 # define Z(what) BZ_##what
54 # define BZ_ERRNO BZ_IO_ERROR
55 # define z_stream bz_stream
56 # define inflateInit(z) BZ2_bzDecompressInit (z, 0, 0)
57 # define do_inflate(z) BZ2_bzDecompress (z)
58 # define inflateEnd(z) BZ2_bzDecompressEnd (z)
60 # define USE_INFLATE 0
61 # define crc32 loser_crc32
63 # define unzip __libdw_gunzip
64 # define MAGIC "\037\213"
65 # define Z(what) Z_##what
68 #define READ_SIZE (1 << 20)
83 bigger_buffer (struct unzip_state *state, size_t start)
85 size_t more = state->size ? state->size * 2 : start;
86 char *b = realloc (state->buffer, more);
87 while (unlikely (b == NULL) && more >= state->size + 1024)
88 b = realloc (state->buffer, more -= 1024);
89 if (unlikely (b == NULL))
97 smaller_buffer (struct unzip_state *state, size_t end)
100 realloc (state->buffer, end) ?: end == 0 ? NULL : state->buffer;
104 static inline Dwfl_Error
105 fail (struct unzip_state *state, Dwfl_Error failure)
107 if (state->input_pos == (off_t) state->mapped_size)
108 *state->whole = state->input_buffer;
111 free (state->input_buffer);
112 *state->whole = NULL;
114 free (state->buffer);
118 static inline Dwfl_Error
119 zlib_fail (struct unzip_state *state, int result)
124 return fail (state, DWFL_E_NOMEM);
126 return fail (state, DWFL_E_ERRNO);
128 return fail (state, DWFL_E_ZLIB);
134 open_stream (int fd, off_t start_offset, struct unzip_state *state)
137 if (unlikely (d < 0))
138 return DWFL_E_BADELF;
139 if (start_offset != 0)
141 off_t off = lseek (d, start_offset, SEEK_SET);
142 if (off != start_offset)
145 return DWFL_E_BADELF;
148 state->zf = gzdopen (d, "r");
149 if (unlikely (state->zf == NULL))
152 return zlib_fail (state, Z (MEM_ERROR));
155 /* From here on, zlib will close D. */
157 return DWFL_E_NOERROR;
161 /* If this is not a compressed image, return DWFL_E_BADELF.
162 If we uncompressed it into *WHOLE, *WHOLE_SIZE, return DWFL_E_NOERROR.
163 Otherwise return an error for bad compressed data or I/O failure.
164 If we return an error after reading the first part of the file,
165 leave that portion malloc'd in *WHOLE, *WHOLE_SIZE. If *WHOLE
166 is not null on entry, we'll use it in lieu of repeating a read. */
168 Dwfl_Error internal_function
169 unzip (int fd, off_t start_offset,
170 void *mapped, size_t _mapped_size,
171 void **_whole, size_t *whole_size)
173 struct unzip_state state =
178 .mapped_size = _mapped_size,
182 .input_buffer = NULL,
188 if (*state.whole == NULL)
190 state.input_buffer = malloc (READ_SIZE);
191 if (unlikely (state.input_buffer == NULL))
194 ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE, start_offset);
195 if (unlikely (n < 0))
196 return zlib_fail (&state, Z (ERRNO));
199 mapped = state.input_buffer;
200 state.mapped_size = n;
204 state.input_buffer = *state.whole;
205 state.input_pos = state.mapped_size = *whole_size;
209 #define NOMAGIC(magic) \
210 (state.mapped_size <= sizeof magic || \
211 memcmp (mapped, magic, sizeof magic - 1))
213 /* First, look at the header. */
219 /* Not a compressed file. */
220 return DWFL_E_BADELF;
224 /* This style actually only works with bzlib and liblzma.
225 The stupid zlib interface has nothing to grok the
226 gzip file headers except the slow gzFile interface. */
228 z_stream z = { .next_in = mapped, .avail_in = state.mapped_size };
229 int result = inflateInit (&z);
230 if (result != Z (OK))
233 return zlib_fail (&state, result);
238 if (z.avail_in == 0 && state.input_buffer != NULL)
240 ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE,
241 start_offset + state.input_pos);
242 if (unlikely (n < 0))
245 return zlib_fail (&state, Z (ERRNO));
247 z.next_in = state.input_buffer;
249 state.input_pos += n;
251 if (z.avail_out == 0)
253 ptrdiff_t pos = (void *) z.next_out - state.buffer;
254 if (!bigger_buffer (&state, z.avail_in))
256 result = Z (MEM_ERROR);
259 z.next_out = state.buffer + pos;
260 z.avail_out = state.size - pos;
263 while ((result = do_inflate (&z)) == Z (OK));
266 uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32)
268 smaller_buffer (&state, total_out);
270 smaller_buffer (&state, z.total_out);
275 if (result != Z (STREAM_END))
276 return zlib_fail (&state, result);
278 #else /* gzip only. */
280 /* Let the decompression library read the file directly. */
282 Dwfl_Error result = open_stream (fd, start_offset, &state);
284 if (result == DWFL_E_NOERROR && gzdirect (state.zf))
287 return fail (&state, DWFL_E_BADELF);
290 if (result != DWFL_E_NOERROR)
291 return fail (&state, result);
296 if (!bigger_buffer (&state, 1024))
299 return zlib_fail (&state, Z (MEM_ERROR));
301 int n = gzread (state.zf, state.buffer + pos, state.size - pos);
305 gzerror (state.zf, &code);
307 return zlib_fail (&state, code);
315 smaller_buffer (&state, pos);
318 free (state.input_buffer);
320 *state.whole = state.buffer;
321 *whole_size = state.size;
323 return DWFL_E_NOERROR;