125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Decompression support for libdwfl: zlib (gzip) and/or bzlib (bzip2).
225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Copyright (C) 2009 Red Hat, Inc.
325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   This file is part of Red Hat elfutils.
425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is free software; you can redistribute it and/or modify
625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   it under the terms of the GNU General Public License as published by the
725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Free Software Foundation; version 2 of the License.
825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is distributed in the hope that it will be useful, but
1025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
1125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   General Public License for more details.
1325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
1425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   You should have received a copy of the GNU General Public License along
1525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   with Red Hat elfutils; if not, write to the Free Software Foundation,
1625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
1725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
1825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   In addition, as a special exception, Red Hat, Inc. gives You the
1925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   additional right to link the code of Red Hat elfutils with code licensed
2025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   under any Open Source Initiative certified open source license
2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   (http://www.opensource.org/licenses/index.php) which requires the
2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   distribution of source code with any binary distribution and to
2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   distribute linked combinations of the two.  Non-GPL Code permitted under
2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   this exception must only link to the code of Red Hat elfutils through
2525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   those well defined interfaces identified in the file named EXCEPTION
2625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   found in the source code files (the "Approved Interfaces").  The files
2725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   of Non-GPL Code may instantiate templates or use macros or inline
2825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   functions from the Approved Interfaces without causing the resulting
2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   work to be covered by the GNU General Public License.  Only Red Hat,
3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Inc. may make changes or additions to the list of Approved Interfaces.
3125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat's grant of this exception is conditioned upon your not adding
3225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   any new exceptions.  If you wish to add a new Approved Interface or
3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   exception, please contact Red Hat.  You must obey the GNU General Public
3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   License in all respects for all of the Red Hat elfutils code and other
3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   code used in conjunction with Red Hat elfutils except the Non-GPL Code
3625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   covered by this exception.  If you modify this file, you may extend this
3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   exception to your version of the file, but you are not obligated to do
3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   so.  If you do not wish to provide this exception without modification,
3925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   you must delete this exception statement from your version and license
4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   this file solely under the GPL without exception.
4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is an included package of the Open Invention Network.
4325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   An included package of the Open Invention Network is a package for which
4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Open Invention Network licensees cross-license their patents.  No patent
4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   license is granted, either expressly or impliedly, by designation as an
4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   included package.  Should you wish to participate in the Open Invention
4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Network licensing program, please visit www.openinventionnetwork.com
4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   <http://www.openinventionnetwork.com>.  */
4925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "libdwflP.h"
5125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "system.h"
5225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <unistd.h>
5425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifdef LZMA
5625b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define USE_INFLATE	1
5725b3c049e70834cf33790a28643ab058b507b35cBen Cheng# include <lzma.h>
5825b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define unzip		__libdw_unlzma
5925b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define DWFL_E_ZLIB	DWFL_E_LZMA
6025b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define MAGIC		"\xFD" "7zXZ\0" /* XZ file format.  */
6125b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define MAGIC2		"\x5d\0"	/* Raw LZMA format.  */
6225b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define Z(what)	LZMA_##what
6325b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define LZMA_ERRNO	LZMA_PROG_ERROR
6425b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define z_stream	lzma_stream
6525b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define inflateInit(z)	lzma_auto_decoder (z, 1 << 30, 0)
6625b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define do_inflate(z)	lzma_code (z, LZMA_RUN)
6725b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define inflateEnd(z)	lzma_end (z)
6825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#elif defined BZLIB
6925b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define USE_INFLATE	1
7025b3c049e70834cf33790a28643ab058b507b35cBen Cheng# include <bzlib.h>
7125b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define unzip		__libdw_bunzip2
7225b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define DWFL_E_ZLIB	DWFL_E_BZLIB
7325b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define MAGIC		"BZh"
7425b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define Z(what)	BZ_##what
7525b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define BZ_ERRNO	BZ_IO_ERROR
7625b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define z_stream	bz_stream
7725b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define inflateInit(z)	BZ2_bzDecompressInit (z, 0, 0)
7825b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define do_inflate(z)	BZ2_bzDecompress (z)
7925b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define inflateEnd(z)	BZ2_bzDecompressEnd (z)
8025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#else
8125b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define USE_INFLATE	0
8225b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define crc32		loser_crc32
8325b3c049e70834cf33790a28643ab058b507b35cBen Cheng# include <zlib.h>
8425b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define unzip		__libdw_gunzip
8525b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define MAGIC		"\037\213"
8625b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define Z(what)	Z_##what
8725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
8825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define READ_SIZE		(1 << 20)
9025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* If this is not a compressed image, return DWFL_E_BADELF.
9225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   If we uncompressed it into *WHOLE, *WHOLE_SIZE, return DWFL_E_NOERROR.
9325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Otherwise return an error for bad compressed data or I/O failure.
9425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   If we return an error after reading the first part of the file,
9525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   leave that portion malloc'd in *WHOLE, *WHOLE_SIZE.  If *WHOLE
9625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   is not null on entry, we'll use it in lieu of repeating a read.  */
9725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9825b3c049e70834cf33790a28643ab058b507b35cBen ChengDwfl_Error internal_function
9925b3c049e70834cf33790a28643ab058b507b35cBen Chengunzip (int fd, off64_t start_offset,
10025b3c049e70834cf33790a28643ab058b507b35cBen Cheng       void *mapped, size_t mapped_size,
10125b3c049e70834cf33790a28643ab058b507b35cBen Cheng       void **whole, size_t *whole_size)
10225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
10325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *buffer = NULL;
10425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t size = 0;
10525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline bool bigger_buffer (size_t start)
10625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
10725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    size_t more = size ? size * 2 : start;
10825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    char *b = realloc (buffer, more);
10925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    while (unlikely (b == NULL) && more >= size + 1024)
11025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      b = realloc (buffer, more -= 1024);
11125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (unlikely (b == NULL))
11225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return false;
11325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    buffer = b;
11425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    size = more;
11525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return true;
11625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
11725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline void smaller_buffer (size_t end)
11825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
11925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    buffer = realloc (buffer, end) ?: end == 0 ? NULL : buffer;
12025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    size = end;
12125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
12225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *input_buffer = NULL;
12425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  off_t input_pos = 0;
12525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline Dwfl_Error fail (Dwfl_Error failure)
12725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
12825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (input_pos == (off_t) mapped_size)
12925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      *whole = input_buffer;
13025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    else
13125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
13225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	free (input_buffer);
13325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	*whole = NULL;
13425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
13525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    free (buffer);
13625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return failure;
13725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
13825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
13925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline Dwfl_Error zlib_fail (int result)
14025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
14125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    switch (result)
14225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
14325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      case Z (MEM_ERROR):
14425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return fail (DWFL_E_NOMEM);
14525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      case Z (ERRNO):
14625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return fail (DWFL_E_ERRNO);
14725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      default:
14825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return fail (DWFL_E_ZLIB);
14925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
15025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
15125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (mapped == NULL)
15325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
15425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (*whole == NULL)
15525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
15625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  input_buffer = malloc (READ_SIZE);
15725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (unlikely (input_buffer == NULL))
15825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    return DWFL_E_NOMEM;
15925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
16025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ssize_t n = pread_retry (fd, input_buffer, READ_SIZE, start_offset);
16125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (unlikely (n < 0))
16225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    return zlib_fail (Z (ERRNO));
16325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
16425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  input_pos = n;
16525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  mapped = input_buffer;
16625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  mapped_size = n;
16725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
16825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
16925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
17025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  input_buffer = *whole;
17125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  input_pos = mapped_size = *whole_size;
17225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
17325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
17425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define NOMAGIC(magic) \
17625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  (mapped_size <= sizeof magic || memcmp (mapped, magic, sizeof magic - 1))
17725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* First, look at the header.  */
17925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (NOMAGIC (MAGIC)
18025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifdef MAGIC2
18125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && NOMAGIC (MAGIC2)
18225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
18325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      )
18425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* Not a compressed file.  */
18525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return DWFL_E_BADELF;
18625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
18725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#if USE_INFLATE
18825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
18925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* This style actually only works with bzlib and liblzma.
19025b3c049e70834cf33790a28643ab058b507b35cBen Cheng     The stupid zlib interface has nothing to grok the
19125b3c049e70834cf33790a28643ab058b507b35cBen Cheng     gzip file headers except the slow gzFile interface.  */
19225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
19325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  z_stream z = { .next_in = mapped, .avail_in = mapped_size };
19425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int result = inflateInit (&z);
19525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (result != Z (OK))
19625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
19725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      inflateEnd (&z);
19825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return zlib_fail (result);
19925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
20025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  do
20225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
20325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (z.avail_in == 0 && input_buffer != NULL)
20425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
20525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ssize_t n = pread_retry (fd, input_buffer, READ_SIZE,
20625b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   start_offset + input_pos);
20725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (unlikely (n < 0))
20825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
20925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      inflateEnd (&z);
21025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      return zlib_fail (Z (ERRNO));
21125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
21225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  z.next_in = input_buffer;
21325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  z.avail_in = n;
21425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  input_pos += n;
21525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
21625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (z.avail_out == 0)
21725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
21825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ptrdiff_t pos = (void *) z.next_out - buffer;
21925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (!bigger_buffer (z.avail_in))
22025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
22125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      result = Z (MEM_ERROR);
22225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
22325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
22425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  z.next_out = buffer + pos;
22525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  z.avail_out = size - pos;
22625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
22725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
22825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while ((result = do_inflate (&z)) == Z (OK));
22925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifdef BZLIB
23125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32)
23225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			| z.total_out_lo32);
23325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  smaller_buffer (total_out);
23425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#else
23525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  smaller_buffer (z.total_out);
23625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
23725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inflateEnd (&z);
23925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (result != Z (STREAM_END))
24125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return zlib_fail (result);
24225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#else  /* gzip only.  */
24425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Let the decompression library read the file directly.  */
24625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  gzFile zf;
24825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwfl_Error open_stream (void)
24925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
25025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    int d = dup (fd);
25125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (unlikely (d < 0))
25225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return DWFL_E_BADELF;
25325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (start_offset != 0)
25425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
25525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	off64_t off = lseek (d, start_offset, SEEK_SET);
25625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (off != start_offset)
25725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
25825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    close (d);
25925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    return DWFL_E_BADELF;
26025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
26125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
26225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    zf = gzdopen (d, "r");
26325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (unlikely (zf == NULL))
26425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
26525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	close (d);
26625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return zlib_fail (Z (MEM_ERROR));
26725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
26825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* From here on, zlib will close D.  */
27025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return DWFL_E_NOERROR;
27225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
27325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwfl_Error result = open_stream ();
27525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (result == DWFL_E_NOERROR && gzdirect (zf))
27725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
27825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      gzclose (zf);
27925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return fail (DWFL_E_BADELF);
28025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
28125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
28225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (result != DWFL_E_NOERROR)
28325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return fail (result);
28425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
28525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  ptrdiff_t pos = 0;
28625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (1)
28725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
28825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (!bigger_buffer (1024))
28925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
29025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  gzclose (zf);
29125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return zlib_fail (Z (MEM_ERROR));
29225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
29325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      int n = gzread (zf, buffer + pos, size - pos);
29425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (n < 0)
29525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
29625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  int code;
29725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  gzerror (zf, &code);
29825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  gzclose (zf);
29925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return zlib_fail (code);
30025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
30125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (n == 0)
30225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
30325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      pos += n;
30425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
30525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  gzclose (zf);
30725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  smaller_buffer (pos);
30825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
30925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (input_buffer);
31125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  *whole = buffer;
31325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  *whole_size = size;
31425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return DWFL_E_NOERROR;
31625b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
317