diff options
author | Roland McGrath <roland@redhat.com> | 2009-08-26 01:27:59 -0700 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2009-08-26 01:27:59 -0700 |
commit | ae1d7dc16530898192929ea2a8faea803282a3b3 (patch) | |
tree | 64f30a68288f583b9c46a71964880613cde84ec6 | |
parent | d6ccdc1a05f27bf0bb5d802ec14f879aa9fe3e98 (diff) | |
download | elfutils-ae1d7dc16530898192929ea2a8faea803282a3b3.tar.gz |
Fix bzip2 support for non-mmap case.
-rw-r--r-- | libdwfl/ChangeLog | 2 | ||||
-rw-r--r-- | libdwfl/gzip.c | 242 |
2 files changed, 138 insertions, 106 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index c5b8edf3..ddfd3259 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -2,6 +2,8 @@ * gzip.c (mapped_zImage): Limit scan to 32kb. Make this unconditional, support bzip2 kernel images too. + (unzip): Use direct inflate method for non-mmap case too. + Only zlib uses the stream method. 2009-08-09 Roland McGrath <roland@redhat.com> diff --git a/libdwfl/gzip.c b/libdwfl/gzip.c index 42352db7..9b871920 100644 --- a/libdwfl/gzip.c +++ b/libdwfl/gzip.c @@ -48,16 +48,18 @@ <http://www.openinventionnetwork.com>. */ #include "libdwflP.h" +#include "system.h" #include <unistd.h> #ifdef BZLIB -# define inflate_groks_header true +# define USE_INFLATE 1 # include <bzlib.h> # define unzip __libdw_bunzip2 # define DWFL_E_ZLIB DWFL_E_BZLIB # define MAGIC "BZh" # define Z(what) BZ_##what +# define BZ_ERRNO BZ_IO_ERROR # define z_stream bz_stream # define inflateInit(z) BZ2_bzDecompressInit (z, 0, 0) # define inflate(z, f) BZ2_bzDecompress (z) @@ -68,7 +70,8 @@ # define gzclose BZ2_bzclose # define gzerror BZ2_bzerror #else -# define inflate_groks_header false +# define USE_INFLATE 0 +# define crc32 loser_crc32 # include <zlib.h> # define unzip __libdw_gunzip # define MAGIC "\037\213" @@ -106,6 +109,8 @@ mapped_zImage (off64_t *start_offset, void **mapped, size_t *mapped_size) return false; } +#define READ_SIZE (1 << 20) + /* If this is not a compressed image, return DWFL_E_BADELF. If we uncompressed it into *WHOLE, *WHOLE_SIZE, return DWFL_E_NOERROR. Otherwise return an error for bad compressed data or I/O failure. */ @@ -135,6 +140,9 @@ unzip (int fd, off64_t start_offset, size = end; } + void *input_buffer = NULL; + off_t input_pos; + inline Dwfl_Error zlib_fail (int result) { Dwfl_Error failure = DWFL_E_ZLIB; @@ -143,32 +151,61 @@ unzip (int fd, off64_t start_offset, case Z (MEM_ERROR): failure = DWFL_E_NOMEM; break; + case Z (ERRNO): + failure = DWFL_E_ERRNO; + break; } free (buffer); + free (input_buffer); *whole = NULL; return failure; } - /* If the file is already mapped in, look at the header. */ - if (mapped != NULL - && (mapped_size <= sizeof MAGIC - || memcmp (mapped, MAGIC, sizeof MAGIC - 1)) + if (mapped == NULL) + { + input_buffer = malloc (READ_SIZE); + if (unlikely (input_buffer == NULL)) + return DWFL_E_NOMEM; + + ssize_t n = pread_retry (fd, input_buffer, READ_SIZE, 0); + if (unlikely (n < 0)) + return zlib_fail (Z (ERRNO)); + + input_pos = n; + mapped = input_buffer; + mapped_size = n; + } + + /* First, look at the header. */ + if ((mapped_size <= sizeof MAGIC + || memcmp (mapped, MAGIC, sizeof MAGIC - 1)) && !mapped_zImage (&start_offset, &mapped, &mapped_size)) /* Not a compressed file. */ return DWFL_E_BADELF; - if (mapped != NULL && inflate_groks_header) - { - /* This style actually only works with bzlib. - The stupid zlib interface has nothing to grok the - gzip file headers except the slow gzFile interface. */ +#if USE_INFLATE - z_stream z = { .next_in = mapped, .avail_in = mapped_size }; - int result = inflateInit (&z); - if (result != Z (OK)) - return zlib_fail (result); + /* This style actually only works with bzlib and liblzma. + The stupid zlib interface has nothing to grok the + gzip file headers except the slow gzFile interface. */ - do + z_stream z = { .next_in = mapped, .avail_in = mapped_size }; + int result = inflateInit (&z); + if (result != Z (OK)) + return zlib_fail (result); + + do + { + if (z.avail_in == 0 && input_buffer != NULL) + { + ssize_t n = pread_retry (fd, input_buffer, READ_SIZE, input_pos); + if (unlikely (n < 0)) + return zlib_fail (Z (IO_ERROR)); + z.next_in = input_buffer; + z.avail_in = n; + input_pos += n; + } + if (z.avail_out == 0) { ptrdiff_t pos = (void *) z.next_out - buffer; if (!bigger_buffer (z.avail_in)) @@ -179,121 +216,114 @@ unzip (int fd, off64_t start_offset, z.next_out = buffer + pos; z.avail_out = size - pos; } - while ((result = inflate (&z, Z_SYNC_FLUSH)) == Z (OK)); + } + while ((result = inflate (&z, Z_SYNC_FLUSH)) == Z (OK)); #ifdef BZLIB - uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32) - | z.total_out_lo32); - smaller_buffer (total_out); + uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32) + | z.total_out_lo32); + smaller_buffer (total_out); #else - smaller_buffer (z.total_out); + smaller_buffer (z.total_out); #endif - inflateEnd (&z); + inflateEnd (&z); - if (result != Z (STREAM_END)) - return zlib_fail (result); - } - else - { - /* Let the decompression library read the file directly. */ + if (result != Z (STREAM_END)) + return zlib_fail (result); + +#else /* gzip only. */ + + /* Let the decompression library read the file directly. */ - gzFile zf; - Dwfl_Error open_stream (void) + gzFile zf; + Dwfl_Error open_stream (void) + { + int d = dup (fd); + if (unlikely (d < 0)) + return DWFL_E_BADELF; + if (start_offset != 0) { - int d = dup (fd); - if (unlikely (d < 0)) - return DWFL_E_BADELF; - if (start_offset != 0) - { - off64_t off = lseek (d, start_offset, SEEK_SET); - if (off != start_offset) - { - close (d); - return DWFL_E_BADELF; - } - } - zf = gzdopen (d, "r"); - if (unlikely (zf == NULL)) + off64_t off = lseek (d, start_offset, SEEK_SET); + if (off != start_offset) { close (d); - return zlib_fail (Z (MEM_ERROR)); + return DWFL_E_BADELF; } - - /* From here on, zlib will close D. */ - - return DWFL_E_NOERROR; + } + zf = gzdopen (d, "r"); + if (unlikely (zf == NULL)) + { + close (d); + return zlib_fail (Z (MEM_ERROR)); } - Dwfl_Error result = open_stream (); + /* From here on, zlib will close D. */ -#ifndef BZLIB - if (result == DWFL_E_NOERROR && gzdirect (zf)) - { - bool found = false; - char buf[sizeof LINUX_MAGIC - 1]; - gzseek (zf, start_offset + LINUX_MAGIC_OFFSET, SEEK_SET); - int n = gzread (zf, buf, sizeof buf); - if (n == sizeof buf - && !memcmp (buf, LINUX_MAGIC, sizeof LINUX_MAGIC - 1)) - while (gzread (zf, buf, sizeof MAGIC - 1) == sizeof MAGIC - 1) - if (!memcmp (buf, MAGIC, sizeof MAGIC - 1)) - { - start_offset = gztell (zf) - 2; - found = true; - break; - } - gzclose (zf); - if (found) - { - result = open_stream (); - if (result == DWFL_E_NOERROR && unlikely (gzdirect (zf))) - { - gzclose (zf); - result = DWFL_E_BADELF; - } - } - else - result = DWFL_E_BADELF; - } -#endif + return DWFL_E_NOERROR; + } - if (result != DWFL_E_NOERROR) - return result; + Dwfl_Error result = open_stream (); - ptrdiff_t pos = 0; - while (1) - { - if (!bigger_buffer (1024)) + if (result == DWFL_E_NOERROR && gzdirect (zf)) + { + bool found = false; + char buf[sizeof LINUX_MAGIC - 1]; + gzseek (zf, start_offset + LINUX_MAGIC_OFFSET, SEEK_SET); + int n = gzread (zf, buf, sizeof buf); + if (n == sizeof buf + && !memcmp (buf, LINUX_MAGIC, sizeof LINUX_MAGIC - 1)) + while (gzread (zf, buf, sizeof MAGIC - 1) == sizeof MAGIC - 1) + if (!memcmp (buf, MAGIC, sizeof MAGIC - 1)) { - gzclose (zf); - return zlib_fail (Z (MEM_ERROR)); + start_offset = gztell (zf) - (sizeof MAGIC - 1); + found = true; + break; } - int n = gzread (zf, buffer + pos, size - pos); - if (n < 0) + else if (gztell (zf) > LINUX_MAX_SCAN) + break; + gzclose (zf); + if (found) + { + result = open_stream (); + if (result == DWFL_E_NOERROR && unlikely (gzdirect (zf))) { - int code; - gzerror (zf, &code); -#ifdef BZLIB - if (code == BZ_DATA_ERROR_MAGIC) - { - gzclose (zf); - free (buffer); - return DWFL_E_BADELF; - } -#endif gzclose (zf); - return zlib_fail (code); + result = DWFL_E_BADELF; } - if (n == 0) - break; - pos += n; } + else + result = DWFL_E_BADELF; + } - gzclose (zf); - smaller_buffer (pos); + if (result != DWFL_E_NOERROR) + return result; + + ptrdiff_t pos = 0; + while (1) + { + if (!bigger_buffer (1024)) + { + gzclose (zf); + return zlib_fail (Z (MEM_ERROR)); + } + int n = gzread (zf, buffer + pos, size - pos); + if (n < 0) + { + int code; + gzerror (zf, &code); + gzclose (zf); + return zlib_fail (code); + } + if (n == 0) + break; + pos += n; } + gzclose (zf); + smaller_buffer (pos); +#endif + *whole = buffer; *whole_size = size; |