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)
70 /* If this is not a compressed image, return DWFL_E_BADELF.
71 If we uncompressed it into *WHOLE, *WHOLE_SIZE, return DWFL_E_NOERROR.
72 Otherwise return an error for bad compressed data or I/O failure.
73 If we return an error after reading the first part of the file,
74 leave that portion malloc'd in *WHOLE, *WHOLE_SIZE. If *WHOLE
75 is not null on entry, we'll use it in lieu of repeating a read. */
77 Dwfl_Error internal_function
78 unzip (int fd, off64_t start_offset,
79 void *mapped, size_t mapped_size,
80 void **whole, size_t *whole_size)
84 inline bool bigger_buffer (size_t start)
86 size_t more = size ? size * 2 : start;
87 char *b = realloc (buffer, more);
88 while (unlikely (b == NULL) && more >= size + 1024)
89 b = realloc (buffer, more -= 1024);
90 if (unlikely (b == NULL))
96 inline void smaller_buffer (size_t end)
98 buffer = realloc (buffer, end) ?: end == 0 ? NULL : buffer;
102 void *input_buffer = NULL;
105 inline Dwfl_Error fail (Dwfl_Error failure)
107 if (input_pos == (off_t) mapped_size)
108 *whole = input_buffer;
118 inline Dwfl_Error zlib_fail (int result)
123 return fail (DWFL_E_NOMEM);
125 return fail (DWFL_E_ERRNO);
127 return fail (DWFL_E_ZLIB);
135 input_buffer = malloc (READ_SIZE);
136 if (unlikely (input_buffer == NULL))
139 ssize_t n = pread_retry (fd, input_buffer, READ_SIZE, start_offset);
140 if (unlikely (n < 0))
141 return zlib_fail (Z (ERRNO));
144 mapped = input_buffer;
149 input_buffer = *whole;
150 input_pos = mapped_size = *whole_size;
154 #define NOMAGIC(magic) \
155 (mapped_size <= sizeof magic || memcmp (mapped, magic, sizeof magic - 1))
157 /* First, look at the header. */
163 /* Not a compressed file. */
164 return DWFL_E_BADELF;
168 /* This style actually only works with bzlib and liblzma.
169 The stupid zlib interface has nothing to grok the
170 gzip file headers except the slow gzFile interface. */
172 z_stream z = { .next_in = mapped, .avail_in = mapped_size };
173 int result = inflateInit (&z);
174 if (result != Z (OK))
177 return zlib_fail (result);
182 if (z.avail_in == 0 && input_buffer != NULL)
184 ssize_t n = pread_retry (fd, input_buffer, READ_SIZE,
185 start_offset + input_pos);
186 if (unlikely (n < 0))
189 return zlib_fail (Z (ERRNO));
191 z.next_in = input_buffer;
195 if (z.avail_out == 0)
197 ptrdiff_t pos = (void *) z.next_out - buffer;
198 if (!bigger_buffer (z.avail_in))
200 result = Z (MEM_ERROR);
203 z.next_out = buffer + pos;
204 z.avail_out = size - pos;
207 while ((result = do_inflate (&z)) == Z (OK));
210 uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32)
212 smaller_buffer (total_out);
214 smaller_buffer (z.total_out);
219 if (result != Z (STREAM_END))
220 return zlib_fail (result);
222 #else /* gzip only. */
224 /* Let the decompression library read the file directly. */
227 Dwfl_Error open_stream (void)
230 if (unlikely (d < 0))
231 return DWFL_E_BADELF;
232 if (start_offset != 0)
234 off64_t off = lseek (d, start_offset, SEEK_SET);
235 if (off != start_offset)
238 return DWFL_E_BADELF;
241 zf = gzdopen (d, "r");
242 if (unlikely (zf == NULL))
245 return zlib_fail (Z (MEM_ERROR));
248 /* From here on, zlib will close D. */
250 return DWFL_E_NOERROR;
253 Dwfl_Error result = open_stream ();
255 if (result == DWFL_E_NOERROR && gzdirect (zf))
258 return fail (DWFL_E_BADELF);
261 if (result != DWFL_E_NOERROR)
262 return fail (result);
267 if (!bigger_buffer (1024))
270 return zlib_fail (Z (MEM_ERROR));
272 int n = gzread (zf, buffer + pos, size - pos);
278 return zlib_fail (code);
286 smaller_buffer (pos);
294 return DWFL_E_NOERROR;