LCOV - code coverage report
Current view: top level - libdwfl - gzip.c (source / functions) Hit Total Coverage
Test: elfutils-0.183 Lines: 57 153 37.3 %
Date: 2021-02-07 19:08:58 Functions: 4 9 44.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 26 101 25.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                 :            : #ifdef HAVE_CONFIG_H
      30                 :            : # include <config.h>
      31                 :            : #endif
      32                 :            : 
      33                 :            : #include "libdwflP.h"
      34                 :            : #include "system.h"
      35                 :            : 
      36                 :            : #include <unistd.h>
      37                 :            : 
      38                 :            : #ifdef LZMA
      39                 :            : # define USE_INFLATE    1
      40                 :            : # include <lzma.h>
      41                 :            : # define unzip          __libdw_unlzma
      42                 :            : # define DWFL_E_ZLIB    DWFL_E_LZMA
      43                 :            : # define MAGIC          "\xFD" "7zXZ\0" /* XZ file format.  */
      44                 :            : # define MAGIC2         "\x5d\0"      /* Raw LZMA format.  */
      45                 :            : # define Z(what)        LZMA_##what
      46                 :            : # define LZMA_ERRNO     LZMA_PROG_ERROR
      47                 :            : # define z_stream       lzma_stream
      48                 :            : # define inflateInit(z) lzma_auto_decoder (z, 1 << 30, 0)
      49                 :            : # define do_inflate(z)  lzma_code (z, LZMA_RUN)
      50                 :            : # define inflateEnd(z)  lzma_end (z)
      51                 :            : #elif defined ZSTD
      52                 :            : # define USE_INFLATE    1
      53                 :            : # include <zstd.h>
      54                 :            : # define unzip          __libdw_unzstd
      55                 :            : # define DWFL_E_ZLIB    DWFL_E_ZSTD
      56                 :            : # define MAGIC          "\x28\xb5\x2f\xfd"
      57                 :            : #elif defined BZLIB
      58                 :            : # define USE_INFLATE    1
      59                 :            : # include <bzlib.h>
      60                 :            : # define unzip          __libdw_bunzip2
      61                 :            : # define DWFL_E_ZLIB    DWFL_E_BZLIB
      62                 :            : # define MAGIC          "BZh"
      63                 :            : # define Z(what)        BZ_##what
      64                 :            : # define BZ_ERRNO       BZ_IO_ERROR
      65                 :            : # define z_stream       bz_stream
      66                 :            : # define inflateInit(z) BZ2_bzDecompressInit (z, 0, 0)
      67                 :            : # define do_inflate(z)  BZ2_bzDecompress (z)
      68                 :            : # define inflateEnd(z)  BZ2_bzDecompressEnd (z)
      69                 :            : #else
      70                 :            : # define USE_INFLATE    0
      71                 :            : # define crc32          loser_crc32
      72                 :            : # include <zlib.h>
      73                 :            : # define unzip          __libdw_gunzip
      74                 :            : # define MAGIC          "\037\213"
      75                 :            : # define Z(what)        Z_##what
      76                 :            : #endif
      77                 :            : 
      78                 :            : #define READ_SIZE               (1 << 20)
      79                 :            : 
      80                 :            : struct unzip_state {
      81                 :            : #if !USE_INFLATE
      82                 :            :   gzFile zf;
      83                 :            : #endif
      84                 :            :   size_t mapped_size;
      85                 :            :   void **whole;
      86                 :            :   void *buffer;
      87                 :            :   size_t size;
      88                 :            :   void *input_buffer;
      89                 :            :   off_t input_pos;
      90                 :            : };
      91                 :            : 
      92                 :            : static inline bool
      93                 :          0 : bigger_buffer (struct unzip_state *state, size_t start)
      94                 :            : {
      95         [ #  # ]:          0 :   size_t more = state->size ? state->size * 2 : start;
      96                 :          0 :   char *b = realloc (state->buffer, more);
      97   [ #  #  #  # ]:          0 :   while (unlikely (b == NULL) && more >= state->size + 1024)
      98                 :          0 :     b = realloc (state->buffer, more -= 1024);
      99         [ #  # ]:          0 :   if (unlikely (b == NULL))
     100                 :          0 :     return false;
     101                 :          0 :   state->buffer = b;
     102                 :          0 :   state->size = more;
     103                 :          0 :   return true;
     104                 :            : }
     105                 :            : 
     106                 :            : static inline void
     107                 :          0 : smaller_buffer (struct unzip_state *state, size_t end)
     108                 :            : {
     109                 :         56 :   state->buffer =
     110   [ #  #  #  #  :          0 :       realloc (state->buffer, end) ?: end == 0 ? NULL : state->buffer;
                   #  # ]
     111                 :         28 :   state->size = end;
     112                 :          0 : }
     113                 :            : 
     114                 :            : static inline Dwfl_Error
     115                 :          0 : fail (struct unzip_state *state, Dwfl_Error failure)
     116                 :            : {
     117         [ #  # ]:          0 :   if (state->input_pos == (off_t) state->mapped_size)
     118                 :          0 :     *state->whole = state->input_buffer;
     119                 :            :   else
     120                 :            :     {
     121                 :          0 :       free (state->input_buffer);
     122                 :          0 :       *state->whole = NULL;
     123                 :            :     }
     124                 :          0 :   free (state->buffer);
     125                 :          0 :   return failure;
     126                 :            : }
     127                 :            : 
     128                 :            : #ifndef ZSTD
     129                 :            : static inline Dwfl_Error
     130                 :          0 : zlib_fail (struct unzip_state *state, int result)
     131                 :            : {
     132      [ #  #  # ]:          0 :   switch (result)
     133                 :            :     {
     134                 :          0 :     case Z (MEM_ERROR):
     135                 :          0 :       return fail (state, DWFL_E_NOMEM);
     136                 :          0 :     case Z (ERRNO):
     137                 :          0 :       return fail (state, DWFL_E_ERRNO);
     138                 :          0 :     default:
     139                 :          0 :       return fail (state, DWFL_E_ZLIB);
     140                 :            :     }
     141                 :            : }
     142                 :            : #endif
     143                 :            : 
     144                 :            : #if !USE_INFLATE
     145                 :            : static Dwfl_Error
     146                 :          0 : open_stream (int fd, off_t start_offset, struct unzip_state *state)
     147                 :            : {
     148                 :          0 :     int d = dup (fd);
     149         [ #  # ]:          0 :     if (unlikely (d < 0))
     150                 :          0 :       return DWFL_E_ERRNO;
     151         [ #  # ]:          0 :     if (start_offset != 0)
     152                 :            :       {
     153                 :          0 :         off_t off = lseek (d, start_offset, SEEK_SET);
     154         [ #  # ]:          0 :         if (off != start_offset)
     155                 :            :           {
     156                 :          0 :             close (d);
     157                 :          0 :             return DWFL_E_ERRNO;
     158                 :            :           }
     159                 :            :       }
     160                 :          0 :     state->zf = gzdopen (d, "r");
     161         [ #  # ]:          0 :     if (unlikely (state->zf == NULL))
     162                 :            :       {
     163                 :          0 :         close (d);
     164                 :          0 :         return DWFL_E_NOMEM;
     165                 :            :       }
     166                 :            : 
     167                 :            :     /* From here on, zlib will close D.  */
     168                 :            : 
     169                 :            :     return DWFL_E_NOERROR;
     170                 :            : }
     171                 :            : #endif
     172                 :            : 
     173                 :            : /* If this is not a compressed image, return DWFL_E_BADELF.
     174                 :            :    If we uncompressed it into *WHOLE, *WHOLE_SIZE, return DWFL_E_NOERROR.
     175                 :            :    Otherwise return an error for bad compressed data or I/O failure.
     176                 :            :    If we return an error after reading the first part of the file,
     177                 :            :    leave that portion malloc'd in *WHOLE, *WHOLE_SIZE.  If *WHOLE
     178                 :            :    is not null on entry, we'll use it in lieu of repeating a read.  */
     179                 :            : 
     180                 :            : Dwfl_Error internal_function
     181                 :         44 : unzip (int fd, off_t start_offset,
     182                 :            :        void *mapped, size_t _mapped_size,
     183                 :            :        void **_whole, size_t *whole_size)
     184                 :            : {
     185                 :         44 :   struct unzip_state state =
     186                 :            :     {
     187                 :            : #if !USE_INFLATE
     188                 :            :       .zf = NULL,
     189                 :            : #endif
     190                 :            :       .mapped_size = _mapped_size,
     191                 :            :       .whole = _whole,
     192                 :            :       .buffer = NULL,
     193                 :            :       .size = 0,
     194                 :            :       .input_buffer = NULL,
     195                 :            :       .input_pos = 0
     196                 :            :     };
     197                 :            : 
     198         [ -  + ]:         44 :   if (mapped == NULL)
     199                 :            :     {
     200         [ #  # ]:          0 :       if (*state.whole == NULL)
     201                 :            :         {
     202                 :          0 :           state.input_buffer = malloc (READ_SIZE);
     203         [ #  # ]:          0 :           if (unlikely (state.input_buffer == NULL))
     204                 :            :             return DWFL_E_NOMEM;
     205                 :            : 
     206                 :          0 :           ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE, start_offset);
     207         [ #  # ]:          0 :           if (unlikely (n < 0))
     208                 :          0 :             return fail (&state, DWFL_E_ERRNO);
     209                 :            : 
     210                 :          0 :           state.input_pos = n;
     211                 :          0 :           mapped = state.input_buffer;
     212                 :          0 :           state.mapped_size = n;
     213                 :            :         }
     214                 :            :       else
     215                 :            :         {
     216                 :          0 :           state.input_buffer = *state.whole;
     217                 :          0 :           state.input_pos = state.mapped_size = *whole_size;
     218                 :            :         }
     219                 :            :     }
     220                 :            : 
     221                 :            : #define NOMAGIC(magic) \
     222                 :            :   (state.mapped_size <= sizeof magic || \
     223                 :            :    memcmp (mapped, magic, sizeof magic - 1))
     224                 :            : 
     225                 :            :   /* First, look at the header.  */
     226 [ +  - ][ +  + ]:         44 :   if (NOMAGIC (MAGIC)
     227                 :            : #ifdef MAGIC2
     228 [ +  - ][ -  + ]:          2 :       && NOMAGIC (MAGIC2)
     229                 :            : #endif
     230                 :            :       )
     231                 :            :     /* Not a compressed file.  */
     232                 :            :     return DWFL_E_BADELF;
     233                 :            : 
     234                 :            : #ifdef ZSTD
     235                 :            :   /* special case for libzstd since it is slightly different from the
     236                 :            :      API provided by bzlib and liblzma.  */
     237                 :            : 
     238                 :          2 :   void *next_in = mapped;
     239                 :          2 :   size_t avail_in = state.mapped_size;
     240                 :          2 :   void *next_out = NULL;
     241                 :          2 :   size_t avail_out = 0;
     242                 :          2 :   size_t total_out = 0;
     243                 :            : 
     244                 :          2 :   size_t result;
     245                 :          2 :   ZSTD_DCtx *dctx = ZSTD_createDCtx();
     246         [ -  + ]:          2 :   if (dctx == NULL)
     247                 :          0 :     return fail (&state, DWFL_E_NOMEM);
     248                 :            : 
     249                 :          6 :   do
     250                 :            :     {
     251   [ -  +  #  # ]:          6 :       if (avail_in == 0 && state.input_buffer != NULL)
     252                 :            :         {
     253                 :          0 :           ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE,
     254                 :          0 :                                    start_offset + state.input_pos);
     255         [ #  # ]:          0 :           if (unlikely (n < 0))
     256                 :            :             {
     257                 :          0 :               ZSTD_freeDCtx (dctx);
     258                 :          0 :               return fail (&state, DWFL_E_ERRNO);
     259                 :            :             }
     260                 :          0 :           next_in = state.input_buffer;
     261                 :          0 :           avail_in = n;
     262                 :          0 :           state.input_pos += n;
     263                 :            :         }
     264         [ +  - ]:          6 :       if (avail_out == 0)
     265                 :            :         {
     266                 :          6 :           ptrdiff_t pos = (void *) next_out - state.buffer;
     267         [ -  + ]:          6 :           if (!bigger_buffer (&state, avail_in))
     268                 :            :             {
     269                 :          0 :               ZSTD_freeDCtx (dctx);
     270                 :          0 :               return fail (&state, DWFL_E_NOMEM);
     271                 :            :             }
     272                 :          6 :           next_out = state.buffer + pos;
     273                 :          6 :           avail_out = state.size - pos;
     274                 :            :         }
     275                 :            : 
     276                 :          6 :       ZSTD_inBuffer input = { next_in, avail_in, 0 };
     277                 :          6 :       ZSTD_outBuffer output = { next_out, avail_out, 0 };
     278                 :          6 :       result = ZSTD_decompressStream (dctx, &output, &input);
     279                 :            : 
     280         [ +  - ]:          6 :       if (! ZSTD_isError (result))
     281                 :            :         {
     282                 :          6 :           total_out += output.pos;
     283                 :          6 :           next_out += output.pos;
     284                 :          6 :           avail_out -= output.pos;
     285                 :          6 :           next_in += input.pos;
     286                 :          6 :           avail_in -= input.pos;
     287                 :            :         }
     288                 :            : 
     289         [ +  + ]:          6 :       if (result == 0)
     290                 :            :         break;
     291                 :            :     }
     292 [ +  - ][ +  - ]:          4 :   while (avail_in > 0 && ! ZSTD_isError (result));
     293                 :            : 
     294                 :          2 :   ZSTD_freeDCtx (dctx);
     295                 :            : 
     296         [ -  + ]:          2 :   if (ZSTD_isError (result))
     297                 :          0 :     return fail (&state, DWFL_E_ZSTD);
     298                 :            : 
     299         [ -  + ]:          2 :   smaller_buffer (&state, total_out);
     300                 :            : 
     301                 :            : #elif USE_INFLATE
     302                 :            : 
     303                 :            :   /* This style actually only works with bzlib and liblzma.
     304                 :            :      The stupid zlib interface has nothing to grok the
     305                 :            :      gzip file headers except the slow gzFile interface.  */
     306                 :            : 
     307                 :         26 :   z_stream z = { .next_in = mapped, .avail_in = state.mapped_size };
     308                 :         26 :   int result = inflateInit (&z);
     309         [ -  + ]:         26 :   if (result != Z (OK))
     310                 :            :     {
     311                 :          0 :       inflateEnd (&z);
     312                 :          0 :       return zlib_fail (&state, result);
     313                 :            :     }
     314                 :            : 
     315                 :        100 :   do
     316                 :            :     {
     317   [ -  +  #  # ]:        100 :       if (z.avail_in == 0 && state.input_buffer != NULL)
     318                 :            :         {
     319                 :          0 :           ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE,
     320                 :          0 :                                    start_offset + state.input_pos);
     321         [ #  # ]:          0 :           if (unlikely (n < 0))
     322                 :            :             {
     323                 :          0 :               inflateEnd (&z);
     324                 :          0 :               return zlib_fail (&state, Z (ERRNO));
     325                 :            :             }
     326                 :          0 :           z.next_in = state.input_buffer;
     327                 :          0 :           z.avail_in = n;
     328                 :          0 :           state.input_pos += n;
     329                 :            :         }
     330         [ +  - ]:        100 :       if (z.avail_out == 0)
     331                 :            :         {
     332                 :        100 :           ptrdiff_t pos = (void *) z.next_out - state.buffer;
     333         [ +  - ]:        100 :           if (!bigger_buffer (&state, z.avail_in))
     334                 :            :             {
     335                 :            :               result = Z (MEM_ERROR);
     336                 :            :               break;
     337                 :            :             }
     338                 :        100 :           z.next_out = state.buffer + pos;
     339                 :        100 :           z.avail_out = state.size - pos;
     340                 :            :         }
     341                 :            :     }
     342         [ +  + ]:        100 :   while ((result = do_inflate (&z)) == Z (OK));
     343                 :            : 
     344                 :            : #ifdef BZLIB
     345                 :          4 :   uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32)
     346                 :          2 :                         | z.total_out_lo32);
     347         [ -  + ]:          2 :   smaller_buffer (&state, total_out);
     348                 :            : #else
     349         [ -  + ]:         24 :   smaller_buffer (&state, z.total_out);
     350                 :            : #endif
     351                 :            : 
     352                 :         26 :   inflateEnd (&z);
     353                 :            : 
     354         [ -  + ]:         26 :   if (result != Z (STREAM_END))
     355                 :          0 :     return zlib_fail (&state, result);
     356                 :            : 
     357                 :            : #else  /* gzip only.  */
     358                 :            : 
     359                 :            :   /* Let the decompression library read the file directly.  */
     360                 :            : 
     361                 :          0 :   Dwfl_Error result = open_stream (fd, start_offset, &state);
     362                 :            : 
     363   [ #  #  #  # ]:          0 :   if (result == DWFL_E_NOERROR && gzdirect (state.zf))
     364                 :            :     {
     365                 :          0 :       gzclose (state.zf);
     366                 :            :       /* Not a compressed stream after all.  */
     367                 :          0 :       return fail (&state, DWFL_E_BADELF);
     368                 :            :     }
     369                 :            : 
     370         [ #  # ]:          0 :   if (result != DWFL_E_NOERROR)
     371                 :          0 :     return fail (&state, result);
     372                 :            : 
     373                 :            :   ptrdiff_t pos = 0;
     374                 :          0 :   while (1)
     375                 :          0 :     {
     376         [ #  # ]:          0 :       if (!bigger_buffer (&state, 1024))
     377                 :            :         {
     378                 :          0 :           gzclose (state.zf);
     379                 :          0 :           return zlib_fail (&state, Z (MEM_ERROR));
     380                 :            :         }
     381                 :          0 :       int n = gzread (state.zf, state.buffer + pos, state.size - pos);
     382         [ #  # ]:          0 :       if (n < 0)
     383                 :            :         {
     384                 :          0 :           int code;
     385                 :          0 :           gzerror (state.zf, &code);
     386                 :          0 :           gzclose (state.zf);
     387                 :          0 :           return zlib_fail (&state, code);
     388                 :            :         }
     389         [ #  # ]:          0 :       if (n == 0)
     390                 :            :         break;
     391                 :          0 :       pos += n;
     392                 :            :     }
     393                 :            : 
     394                 :          0 :   gzclose (state.zf);
     395         [ #  # ]:          0 :   smaller_buffer (&state, pos);
     396                 :            : #endif
     397                 :            : 
     398                 :         28 :   free (state.input_buffer);
     399                 :            : 
     400                 :         28 :   *state.whole = state.buffer;
     401                 :         28 :   *whole_size = state.size;
     402                 :            : 
     403                 :         28 :   return DWFL_E_NOERROR;
     404                 :            : }

Generated by: LCOV version 1.13