LCOV - code coverage report
Current view: top level - elfutils/libdwfl - gzip.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 37 105 35.2 %
Date: 2013-03-08 Functions: 5 16 31.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 15 69 21.7 %

           Branch data     Line data    Source code
       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.
       4                 :            : 
       5                 :            :    This file is free software; you can redistribute it and/or modify
       6                 :            :    it under the terms of either
       7                 :            : 
       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
      11                 :            : 
      12                 :            :    or
      13                 :            : 
      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
      17                 :            : 
      18                 :            :    or both in parallel, as here.
      19                 :            : 
      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.
      24                 :            : 
      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/>.  */
      28                 :            : 
      29                 :            : #include "libdwflP.h"
      30                 :            : #include "system.h"
      31                 :            : 
      32                 :            : #include <unistd.h>
      33                 :            : 
      34                 :            : #ifdef LZMA
      35                 :            : # define USE_INFLATE    1
      36                 :            : # include <lzma.h>
      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)
      47                 :            : #elif defined BZLIB
      48                 :            : # define USE_INFLATE    1
      49                 :            : # include <bzlib.h>
      50                 :            : # define unzip          __libdw_bunzip2
      51                 :            : # define DWFL_E_ZLIB    DWFL_E_BZLIB
      52                 :            : # define MAGIC          "BZh"
      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)
      59                 :            : #else
      60                 :            : # define USE_INFLATE    0
      61                 :            : # define crc32          loser_crc32
      62                 :            : # include <zlib.h>
      63                 :            : # define unzip          __libdw_gunzip
      64                 :            : # define MAGIC          "\037\213"
      65                 :            : # define Z(what)        Z_##what
      66                 :            : #endif
      67                 :            : 
      68                 :            : #define READ_SIZE               (1 << 20)
      69                 :            : 
      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.  */
      76                 :            : 
      77                 :            : Dwfl_Error internal_function
      78                 :         11 : unzip (int fd, off64_t start_offset,
      79                 :            :        void *mapped, size_t mapped_size,
      80                 :            :        void **whole, size_t *whole_size)
      81                 :            : {
      82                 :         11 :   void *buffer = NULL;
      83                 :         11 :   size_t size = 0;
      84                 :         18 :   inline bool bigger_buffer (size_t start)
      85                 :            :   {
      86         [ +  + ]:         18 :     size_t more = size ? size * 2 : start;
      87                 :         18 :     char *b = realloc (buffer, more);
      88 [ -  + ][ #  # ]:         18 :     while (unlikely (b == NULL) && more >= size + 1024)
      89                 :          0 :       b = realloc (buffer, more -= 1024);
      90         [ +  - ]:         18 :     if (unlikely (b == NULL))
      91                 :            :       return false;
      92                 :         18 :     buffer = b;
      93                 :         18 :     size = more;
      94                 :         18 :     return true;
      95                 :            :   }
      96                 :          5 :   inline void smaller_buffer (size_t end)
      97                 :            :   {
      98 [ -  + ][ #  # ]:          5 :     buffer = realloc (buffer, end) ?: end == 0 ? NULL : buffer;
      99                 :          5 :     size = end;
     100                 :          5 :   }
     101                 :            : 
     102                 :         11 :   void *input_buffer = NULL;
     103                 :         11 :   off_t input_pos = 0;
     104                 :            : 
     105                 :          0 :   inline Dwfl_Error fail (Dwfl_Error failure)
     106                 :            :   {
     107         [ #  # ]:          0 :     if (input_pos == (off_t) mapped_size)
     108                 :          0 :       *whole = input_buffer;
     109                 :            :     else
     110                 :            :       {
     111                 :          0 :         free (input_buffer);
     112                 :          0 :         *whole = NULL;
     113                 :            :       }
     114                 :          0 :     free (buffer);
     115                 :          0 :     return failure;
     116                 :            :   }
     117                 :            : 
     118                 :          0 :   inline Dwfl_Error zlib_fail (int result)
     119                 :            :   {
     120      [ #  #  # ]:          0 :     switch (result)
     121                 :            :       {
     122                 :            :       case Z (MEM_ERROR):
     123                 :          0 :         return fail (DWFL_E_NOMEM);
     124                 :            :       case Z (ERRNO):
     125                 :          0 :         return fail (DWFL_E_ERRNO);
     126                 :            :       default:
     127                 :          0 :         return fail (DWFL_E_ZLIB);
     128                 :            :       }
     129                 :            :   }
     130                 :            : 
     131         [ -  + ]:         11 :   if (mapped == NULL)
     132                 :            :     {
     133         [ #  # ]:          0 :       if (*whole == NULL)
     134                 :            :         {
     135                 :          0 :           input_buffer = malloc (READ_SIZE);
     136         [ #  # ]:          0 :           if (unlikely (input_buffer == NULL))
     137                 :            :             return DWFL_E_NOMEM;
     138                 :            : 
     139                 :          0 :           ssize_t n = pread_retry (fd, input_buffer, READ_SIZE, start_offset);
     140         [ #  # ]:          0 :           if (unlikely (n < 0))
     141                 :          0 :             return zlib_fail (Z (ERRNO));
     142                 :            : 
     143                 :          0 :           input_pos = n;
     144                 :          0 :           mapped = input_buffer;
     145                 :          0 :           mapped_size = n;
     146                 :            :         }
     147                 :            :       else
     148                 :            :         {
     149                 :          0 :           input_buffer = *whole;
     150                 :          0 :           input_pos = mapped_size = *whole_size;
     151                 :            :         }
     152                 :            :     }
     153                 :            : 
     154                 :            : #define NOMAGIC(magic) \
     155                 :            :   (mapped_size <= sizeof magic || memcmp (mapped, magic, sizeof magic - 1))
     156                 :            : 
     157                 :            :   /* First, look at the header.  */
     158 [ +  - ][ -  + ]:         11 :   if (NOMAGIC (MAGIC)
     159                 :            : #ifdef MAGIC2
     160 [ #  # ][ #  # ]:          0 :       && NOMAGIC (MAGIC2)
     161                 :            : #endif
     162                 :            :       )
     163                 :            :     /* Not a compressed file.  */
     164                 :            :     return DWFL_E_BADELF;
     165                 :            : 
     166                 :            : #if USE_INFLATE
     167                 :            : 
     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.  */
     171                 :            : 
     172                 :          5 :   z_stream z = { .next_in = mapped, .avail_in = mapped_size };
     173                 :          5 :   int result = inflateInit (&z);
     174         [ -  + ]:          5 :   if (result != Z (OK))
     175                 :            :     {
     176                 :          0 :       inflateEnd (&z);
     177                 :          5 :       return zlib_fail (result);
     178                 :            :     }
     179                 :            : 
     180                 :            :   do
     181                 :            :     {
     182 [ -  + ][ #  # ]:         18 :       if (z.avail_in == 0 && input_buffer != NULL)
     183                 :            :         {
     184                 :          0 :           ssize_t n = pread_retry (fd, input_buffer, READ_SIZE,
     185                 :            :                                    start_offset + input_pos);
     186         [ #  # ]:          0 :           if (unlikely (n < 0))
     187                 :            :             {
     188                 :          0 :               inflateEnd (&z);
     189                 :          0 :               return zlib_fail (Z (ERRNO));
     190                 :            :             }
     191                 :          0 :           z.next_in = input_buffer;
     192                 :          0 :           z.avail_in = n;
     193                 :          0 :           input_pos += n;
     194                 :            :         }
     195         [ +  - ]:         18 :       if (z.avail_out == 0)
     196                 :            :         {
     197                 :         18 :           ptrdiff_t pos = (void *) z.next_out - buffer;
     198         [ +  - ]:         18 :           if (!bigger_buffer (z.avail_in))
     199                 :            :             {
     200                 :            :               result = Z (MEM_ERROR);
     201                 :            :               break;
     202                 :            :             }
     203                 :         18 :           z.next_out = buffer + pos;
     204                 :         18 :           z.avail_out = size - pos;
     205                 :            :         }
     206                 :            :     }
     207         [ +  + ]:         18 :   while ((result = do_inflate (&z)) == Z (OK));
     208                 :            : 
     209                 :            : #ifdef BZLIB
     210                 :          0 :   uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32)
     211                 :          0 :                         | z.total_out_lo32);
     212                 :          0 :   smaller_buffer (total_out);
     213                 :            : #else
     214                 :          5 :   smaller_buffer (z.total_out);
     215                 :            : #endif
     216                 :            : 
     217                 :          5 :   inflateEnd (&z);
     218                 :            : 
     219         [ -  + ]:          5 :   if (result != Z (STREAM_END))
     220                 :          0 :     return zlib_fail (result);
     221                 :            : 
     222                 :            : #else  /* gzip only.  */
     223                 :            : 
     224                 :            :   /* Let the decompression library read the file directly.  */
     225                 :            : 
     226                 :            :   gzFile zf;
     227                 :          0 :   Dwfl_Error open_stream (void)
     228                 :            :   {
     229                 :          0 :     int d = dup (fd);
     230         [ #  # ]:          0 :     if (unlikely (d < 0))
     231                 :            :       return DWFL_E_BADELF;
     232         [ #  # ]:          0 :     if (start_offset != 0)
     233                 :            :       {
     234                 :          0 :         off64_t off = lseek (d, start_offset, SEEK_SET);
     235         [ #  # ]:          0 :         if (off != start_offset)
     236                 :            :           {
     237                 :          0 :             close (d);
     238                 :          0 :             return DWFL_E_BADELF;
     239                 :            :           }
     240                 :            :       }
     241                 :          0 :     zf = gzdopen (d, "r");
     242         [ #  # ]:          0 :     if (unlikely (zf == NULL))
     243                 :            :       {
     244                 :          0 :         close (d);
     245                 :          0 :         return zlib_fail (Z (MEM_ERROR));
     246                 :            :       }
     247                 :            : 
     248                 :            :     /* From here on, zlib will close D.  */
     249                 :            : 
     250                 :            :     return DWFL_E_NOERROR;
     251                 :            :   }
     252                 :            : 
     253                 :          0 :   Dwfl_Error result = open_stream ();
     254                 :            : 
     255 [ #  # ][ #  # ]:          0 :   if (result == DWFL_E_NOERROR && gzdirect (zf))
     256                 :            :     {
     257                 :          0 :       gzclose (zf);
     258                 :          0 :       return fail (DWFL_E_BADELF);
     259                 :            :     }
     260                 :            : 
     261         [ #  # ]:          0 :   if (result != DWFL_E_NOERROR)
     262                 :          0 :     return fail (result);
     263                 :            : 
     264                 :            :   ptrdiff_t pos = 0;
     265                 :            :   while (1)
     266                 :            :     {
     267         [ #  # ]:          0 :       if (!bigger_buffer (1024))
     268                 :            :         {
     269                 :          0 :           gzclose (zf);
     270                 :          0 :           return zlib_fail (Z (MEM_ERROR));
     271                 :            :         }
     272                 :          0 :       int n = gzread (zf, buffer + pos, size - pos);
     273         [ #  # ]:          0 :       if (n < 0)
     274                 :            :         {
     275                 :            :           int code;
     276                 :          0 :           gzerror (zf, &code);
     277                 :          0 :           gzclose (zf);
     278                 :          0 :           return zlib_fail (code);
     279                 :            :         }
     280         [ #  # ]:          0 :       if (n == 0)
     281                 :            :         break;
     282                 :          0 :       pos += n;
     283                 :          0 :     }
     284                 :            : 
     285                 :          0 :   gzclose (zf);
     286                 :          0 :   smaller_buffer (pos);
     287                 :            : #endif
     288                 :            : 
     289                 :          5 :   free (input_buffer);
     290                 :            : 
     291                 :          5 :   *whole = buffer;
     292                 :          8 :   *whole_size = size;
     293                 :            : 
     294                 :          3 :   return DWFL_E_NOERROR;
     295                 :            : }

Generated by: LCOV version 1.9