LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-compress.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 86.4 % 125 108
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 11 11
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 73.2 % 56 41

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * pgp-compress.c
       3                 :             :  *    ZIP and ZLIB compression via zlib.
       4                 :             :  *
       5                 :             :  * Copyright (c) 2005 Marko Kreen
       6                 :             :  * All rights reserved.
       7                 :             :  *
       8                 :             :  * Redistribution and use in source and binary forms, with or without
       9                 :             :  * modification, are permitted provided that the following conditions
      10                 :             :  * are met:
      11                 :             :  * 1. Redistributions of source code must retain the above copyright
      12                 :             :  *    notice, this list of conditions and the following disclaimer.
      13                 :             :  * 2. Redistributions in binary form must reproduce the above copyright
      14                 :             :  *    notice, this list of conditions and the following disclaimer in the
      15                 :             :  *    documentation and/or other materials provided with the distribution.
      16                 :             :  *
      17                 :             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
      18                 :             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      19                 :             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      20                 :             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      21                 :             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      22                 :             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      23                 :             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      24                 :             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      25                 :             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      26                 :             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      27                 :             :  * SUCH DAMAGE.
      28                 :             :  *
      29                 :             :  * contrib/pgcrypto/pgp-compress.c
      30                 :             :  */
      31                 :             : 
      32                 :             : #include "postgres.h"
      33                 :             : 
      34                 :             : #include "pgp.h"
      35                 :             : #include "px.h"
      36                 :             : 
      37                 :             : /*
      38                 :             :  * Compressed pkt writer
      39                 :             :  */
      40                 :             : 
      41                 :             : #ifdef HAVE_LIBZ
      42                 :             : 
      43                 :             : #include <zlib.h>
      44                 :             : 
      45                 :             : #define ZIP_OUT_BUF 8192
      46                 :             : #define ZIP_IN_BLOCK 8192
      47                 :             : 
      48                 :             : struct ZipStat
      49                 :             : {
      50                 :             :     uint8       type;
      51                 :             :     int         buf_len;
      52                 :             :     int         hdr_done;
      53                 :             :     z_stream    stream;
      54                 :             :     uint8       buf[ZIP_OUT_BUF];
      55                 :             : };
      56                 :             : 
      57                 :             : static void *
      58                 :          22 : z_alloc(void *priv, unsigned n_items, unsigned item_len)
      59                 :             : {
      60                 :          22 :     return palloc(n_items * item_len);
      61                 :             : }
      62                 :             : 
      63                 :             : static void
      64                 :          22 : z_free(void *priv, void *addr)
      65                 :             : {
      66                 :          22 :     pfree(addr);
      67                 :          22 : }
      68                 :             : 
      69                 :             : static int
      70                 :           3 : compress_init(PushFilter *next, void *init_arg, void **priv_p)
      71                 :             : {
      72                 :             :     int         res;
      73                 :             :     struct ZipStat *st;
      74                 :           3 :     PGP_Context *ctx = init_arg;
      75                 :           3 :     uint8       type = ctx->compress_algo;
      76                 :             : 
      77   [ +  +  -  + ]:           3 :     if (type != PGP_COMPR_ZLIB && type != PGP_COMPR_ZIP)
      78                 :           0 :         return PXE_PGP_UNSUPPORTED_COMPR;
      79                 :             : 
      80                 :             :     /*
      81                 :             :      * init
      82                 :             :      */
      83                 :           3 :     st = palloc0_object(struct ZipStat);
      84                 :           3 :     st->buf_len = ZIP_OUT_BUF;
      85                 :           3 :     st->stream.zalloc = z_alloc;
      86                 :           3 :     st->stream.zfree = z_free;
      87                 :             : 
      88         [ +  + ]:           3 :     if (type == PGP_COMPR_ZIP)
      89                 :           2 :         res = deflateInit2(&st->stream, ctx->compress_level,
      90                 :             :                            Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
      91                 :             :     else
      92                 :           1 :         res = deflateInit(&st->stream, ctx->compress_level);
      93         [ -  + ]:           3 :     if (res != Z_OK)
      94                 :             :     {
      95                 :           0 :         pfree(st);
      96                 :           0 :         return PXE_PGP_COMPRESSION_ERROR;
      97                 :             :     }
      98                 :           3 :     *priv_p = st;
      99                 :             : 
     100                 :           3 :     return ZIP_IN_BLOCK;
     101                 :             : }
     102                 :             : 
     103                 :             : /* writes compressed data packet */
     104                 :             : 
     105                 :             : /* can handle zero-len incoming data, but shouldn't */
     106                 :             : static int
     107                 :           4 : compress_process(PushFilter *next, void *priv, const uint8 *data, int len)
     108                 :             : {
     109                 :             :     int         res,
     110                 :             :                 n_out;
     111                 :           4 :     struct ZipStat *st = priv;
     112                 :             : 
     113                 :             :     /*
     114                 :             :      * process data
     115                 :             :      */
     116                 :           4 :     st->stream.next_in = data;
     117                 :           4 :     st->stream.avail_in = len;
     118         [ +  + ]:          12 :     while (st->stream.avail_in > 0)
     119                 :             :     {
     120                 :           4 :         st->stream.next_out = st->buf;
     121                 :           4 :         st->stream.avail_out = st->buf_len;
     122                 :           4 :         res = deflate(&st->stream, Z_NO_FLUSH);
     123         [ -  + ]:           4 :         if (res != Z_OK)
     124                 :           0 :             return PXE_PGP_COMPRESSION_ERROR;
     125                 :             : 
     126                 :           4 :         n_out = st->buf_len - st->stream.avail_out;
     127         [ +  + ]:           4 :         if (n_out > 0)
     128                 :             :         {
     129                 :           1 :             res = pushf_write(next, st->buf, n_out);
     130         [ -  + ]:           1 :             if (res < 0)
     131                 :           0 :                 return res;
     132                 :             :         }
     133                 :             :     }
     134                 :             : 
     135                 :           4 :     return 0;
     136                 :             : }
     137                 :             : 
     138                 :             : static int
     139                 :           3 : compress_flush(PushFilter *next, void *priv)
     140                 :             : {
     141                 :             :     int         res,
     142                 :             :                 zres,
     143                 :             :                 n_out;
     144                 :           3 :     struct ZipStat *st = priv;
     145                 :             : 
     146                 :           3 :     st->stream.next_in = NULL;
     147                 :           3 :     st->stream.avail_in = 0;
     148                 :             :     while (1)
     149                 :             :     {
     150                 :           4 :         st->stream.next_out = st->buf;
     151                 :           4 :         st->stream.avail_out = st->buf_len;
     152                 :           4 :         zres = deflate(&st->stream, Z_FINISH);
     153   [ +  +  -  + ]:           4 :         if (zres != Z_STREAM_END && zres != Z_OK)
     154                 :           0 :             return PXE_PGP_COMPRESSION_ERROR;
     155                 :             : 
     156                 :           4 :         n_out = st->buf_len - st->stream.avail_out;
     157         [ +  - ]:           4 :         if (n_out > 0)
     158                 :             :         {
     159                 :           4 :             res = pushf_write(next, st->buf, n_out);
     160         [ -  + ]:           4 :             if (res < 0)
     161                 :           0 :                 return res;
     162                 :             :         }
     163         [ +  + ]:           4 :         if (zres == Z_STREAM_END)
     164                 :           3 :             break;
     165                 :             :     }
     166                 :           3 :     return 0;
     167                 :             : }
     168                 :             : 
     169                 :             : static void
     170                 :           3 : compress_free(void *priv)
     171                 :             : {
     172                 :           3 :     struct ZipStat *st = priv;
     173                 :             : 
     174                 :           3 :     deflateEnd(&st->stream);
     175                 :           3 :     px_memset(st, 0, sizeof(*st));
     176                 :           3 :     pfree(st);
     177                 :           3 : }
     178                 :             : 
     179                 :             : static const PushFilterOps
     180                 :             :             compress_filter = {
     181                 :             :     compress_init, compress_process, compress_flush, compress_free
     182                 :             : };
     183                 :             : 
     184                 :             : int
     185                 :           3 : pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst)
     186                 :             : {
     187                 :           3 :     return pushf_create(res, &compress_filter, ctx, dst);
     188                 :             : }
     189                 :             : 
     190                 :             : /*
     191                 :             :  * Decompress
     192                 :             :  */
     193                 :             : struct DecomprData
     194                 :             : {
     195                 :             :     int         buf_len;        /* = ZIP_OUT_BUF */
     196                 :             :     int         buf_data;       /* available data */
     197                 :             :     uint8      *pos;
     198                 :             :     z_stream    stream;
     199                 :             :     int         eof;
     200                 :             :     uint8       buf[ZIP_OUT_BUF];
     201                 :             : };
     202                 :             : 
     203                 :             : static int
     204                 :           4 : decompress_init(void **priv_p, void *arg, PullFilter *src)
     205                 :             : {
     206                 :           4 :     PGP_Context *ctx = arg;
     207                 :             :     struct DecomprData *dec;
     208                 :             :     int         res;
     209                 :             : 
     210         [ +  + ]:           4 :     if (ctx->compress_algo != PGP_COMPR_ZLIB
     211         [ -  + ]:           3 :         && ctx->compress_algo != PGP_COMPR_ZIP)
     212                 :           0 :         return PXE_PGP_UNSUPPORTED_COMPR;
     213                 :             : 
     214                 :           4 :     dec = palloc0_object(struct DecomprData);
     215                 :           4 :     dec->buf_len = ZIP_OUT_BUF;
     216                 :           4 :     *priv_p = dec;
     217                 :             : 
     218                 :           4 :     dec->stream.zalloc = z_alloc;
     219                 :           4 :     dec->stream.zfree = z_free;
     220                 :             : 
     221         [ +  + ]:           4 :     if (ctx->compress_algo == PGP_COMPR_ZIP)
     222                 :           3 :         res = inflateInit2(&dec->stream, -15);
     223                 :             :     else
     224                 :           1 :         res = inflateInit(&dec->stream);
     225         [ -  + ]:           4 :     if (res != Z_OK)
     226                 :             :     {
     227                 :           0 :         pfree(dec);
     228                 :           0 :         px_debug("decompress_init: inflateInit error");
     229                 :           0 :         return PXE_PGP_COMPRESSION_ERROR;
     230                 :             :     }
     231                 :             : 
     232                 :           4 :     return 0;
     233                 :             : }
     234                 :             : 
     235                 :             : static int
     236                 :          36 : decompress_read(void *priv, PullFilter *src, int len,
     237                 :             :                 uint8 **data_p, uint8 *buf, int buflen)
     238                 :             : {
     239                 :             :     int         res;
     240                 :             :     int         flush;
     241                 :          36 :     struct DecomprData *dec = priv;
     242                 :             : 
     243                 :          44 : restart:
     244         [ +  + ]:          44 :     if (dec->buf_data > 0)
     245                 :             :     {
     246         [ +  + ]:          32 :         if (len > dec->buf_data)
     247                 :           4 :             len = dec->buf_data;
     248                 :          32 :         *data_p = dec->pos;
     249                 :          32 :         dec->pos += len;
     250                 :          32 :         dec->buf_data -= len;
     251                 :          32 :         return len;
     252                 :             :     }
     253                 :             : 
     254         [ +  + ]:          12 :     if (dec->eof)
     255                 :           4 :         return 0;
     256                 :             : 
     257         [ +  - ]:           8 :     if (dec->stream.avail_in == 0)
     258                 :             :     {
     259                 :             :         uint8      *tmp;
     260                 :             : 
     261                 :           8 :         res = pullf_read(src, 8192, &tmp);
     262         [ -  + ]:           8 :         if (res < 0)
     263                 :           0 :             return res;
     264                 :           8 :         dec->stream.next_in = tmp;
     265                 :           8 :         dec->stream.avail_in = res;
     266                 :             :     }
     267                 :             : 
     268                 :           8 :     dec->stream.next_out = dec->buf;
     269                 :           8 :     dec->stream.avail_out = dec->buf_len;
     270                 :           8 :     dec->pos = dec->buf;
     271                 :             : 
     272                 :             :     /*
     273                 :             :      * Z_SYNC_FLUSH is tell zlib to output as much as possible. It should do
     274                 :             :      * it anyway (Z_NO_FLUSH), but seems to reserve the right not to.  So lets
     275                 :             :      * follow the API.
     276                 :             :      */
     277         [ +  - ]:           8 :     flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH;
     278                 :           8 :     res = inflate(&dec->stream, flush);
     279   [ +  +  -  + ]:           8 :     if (res != Z_OK && res != Z_STREAM_END)
     280                 :             :     {
     281                 :           0 :         px_debug("decompress_read: inflate error: %d", res);
     282                 :           0 :         return PXE_PGP_CORRUPT_DATA;
     283                 :             :     }
     284                 :             : 
     285                 :           8 :     dec->buf_data = dec->buf_len - dec->stream.avail_out;
     286         [ +  + ]:           8 :     if (res == Z_STREAM_END)
     287                 :             :     {
     288                 :             :         uint8      *tmp;
     289                 :             : 
     290                 :             :         /*
     291                 :             :          * A stream must be terminated by a normal packet.  If the last stream
     292                 :             :          * packet in the source stream is a full packet, a normal empty packet
     293                 :             :          * must follow.  Since the underlying packet reader doesn't know that
     294                 :             :          * the compressed stream has been ended, we need to consume the
     295                 :             :          * terminating packet here.  This read does not harm even if the
     296                 :             :          * stream has already ended.
     297                 :             :          */
     298                 :           4 :         res = pullf_read(src, 1, &tmp);
     299                 :             : 
     300         [ -  + ]:           4 :         if (res < 0)
     301                 :           0 :             return res;
     302         [ -  + ]:           4 :         else if (res > 0)
     303                 :             :         {
     304                 :           0 :             px_debug("decompress_read: extra bytes after end of stream");
     305                 :           0 :             return PXE_PGP_CORRUPT_DATA;
     306                 :             :         }
     307                 :           4 :         dec->eof = 1;
     308                 :             :     }
     309                 :           8 :     goto restart;
     310                 :             : }
     311                 :             : 
     312                 :             : static void
     313                 :           4 : decompress_free(void *priv)
     314                 :             : {
     315                 :           4 :     struct DecomprData *dec = priv;
     316                 :             : 
     317                 :           4 :     inflateEnd(&dec->stream);
     318                 :           4 :     px_memset(dec, 0, sizeof(*dec));
     319                 :           4 :     pfree(dec);
     320                 :           4 : }
     321                 :             : 
     322                 :             : static const PullFilterOps
     323                 :             :             decompress_filter = {
     324                 :             :     decompress_init, decompress_read, decompress_free
     325                 :             : };
     326                 :             : 
     327                 :             : int
     328                 :           4 : pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
     329                 :             : {
     330                 :           4 :     return pullf_create(res, &decompress_filter, ctx, src);
     331                 :             : }
     332                 :             : #else                           /* !HAVE_LIBZ */
     333                 :             : 
     334                 :             : int
     335                 :             : pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst)
     336                 :             : {
     337                 :             :     return PXE_PGP_UNSUPPORTED_COMPR;
     338                 :             : }
     339                 :             : 
     340                 :             : int
     341                 :             : pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
     342                 :             : {
     343                 :             :     return PXE_PGP_UNSUPPORTED_COMPR;
     344                 :             : }
     345                 :             : 
     346                 :             : #endif
        

Generated by: LCOV version 2.0-1