summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2009-08-26 01:27:59 -0700
committerRoland McGrath <roland@redhat.com>2009-08-26 01:27:59 -0700
commitae1d7dc16530898192929ea2a8faea803282a3b3 (patch)
tree64f30a68288f583b9c46a71964880613cde84ec6
parentd6ccdc1a05f27bf0bb5d802ec14f879aa9fe3e98 (diff)
downloadelfutils-ae1d7dc16530898192929ea2a8faea803282a3b3.tar.gz
Fix bzip2 support for non-mmap case.
-rw-r--r--libdwfl/ChangeLog2
-rw-r--r--libdwfl/gzip.c242
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;