LCOV - differential code coverage report
Current view: top level - src/bin/pg_dump - compress_gzip.c (source / functions) Coverage Total Hit UNC GNC
Current: Differential Code Coverage HEAD vs 15 Lines: 81.4 % 172 140 32 140
Current Date: 2023-04-08 15:15:32 Functions: 88.2 % 17 15 2 15
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * compress_gzip.c
       4                 :  *   Routines for archivers to read or write a gzip compressed data stream.
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7                 :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :  *
       9                 :  * IDENTIFICATION
      10                 :  *     src/bin/pg_dump/compress_gzip.c
      11                 :  *
      12                 :  *-------------------------------------------------------------------------
      13                 :  */
      14                 : #include "postgres_fe.h"
      15                 : #include <unistd.h>
      16                 : 
      17                 : #include "compress_gzip.h"
      18                 : #include "pg_backup_utils.h"
      19                 : 
      20                 : #ifdef HAVE_LIBZ
      21                 : #include "zlib.h"
      22                 : 
      23                 : /*----------------------
      24                 :  * Compressor API
      25                 :  *----------------------
      26                 :  */
      27                 : typedef struct GzipCompressorState
      28                 : {
      29                 :     z_streamp   zp;
      30                 : 
      31                 :     void       *outbuf;
      32                 :     size_t      outsize;
      33                 : } GzipCompressorState;
      34                 : 
      35                 : /* Private routines that support gzip compressed data I/O */
      36                 : static void DeflateCompressorInit(CompressorState *cs);
      37                 : static void DeflateCompressorEnd(ArchiveHandle *AH, CompressorState *cs);
      38                 : static void DeflateCompressorCommon(ArchiveHandle *AH, CompressorState *cs,
      39                 :                                     bool flush);
      40                 : static void EndCompressorGzip(ArchiveHandle *AH, CompressorState *cs);
      41                 : static void WriteDataToArchiveGzip(ArchiveHandle *AH, CompressorState *cs,
      42                 :                                    const void *data, size_t dLen);
      43                 : static void ReadDataFromArchiveGzip(ArchiveHandle *AH, CompressorState *cs);
      44                 : 
      45                 : static void
      46 GNC          55 : DeflateCompressorInit(CompressorState *cs)
      47                 : {
      48                 :     GzipCompressorState *gzipcs;
      49                 :     z_streamp   zp;
      50                 : 
      51              55 :     gzipcs = (GzipCompressorState *) pg_malloc0(sizeof(GzipCompressorState));
      52              55 :     zp = gzipcs->zp = (z_streamp) pg_malloc(sizeof(z_stream));
      53              55 :     zp->zalloc = Z_NULL;
      54              55 :     zp->zfree = Z_NULL;
      55              55 :     zp->opaque = Z_NULL;
      56                 : 
      57                 :     /*
      58                 :      * outsize is the buffer size we tell zlib it can output to.  We actually
      59                 :      * allocate one extra byte because some routines want to append a trailing
      60                 :      * zero byte to the zlib output.
      61                 :      */
      62              55 :     gzipcs->outsize = DEFAULT_IO_BUFFER_SIZE;
      63              55 :     gzipcs->outbuf = pg_malloc(gzipcs->outsize + 1);
      64                 : 
      65                 :     /* -Z 0 uses the "None" compressor -- not zlib with no compression */
      66              55 :     Assert(cs->compression_spec.level != 0);
      67                 : 
      68              55 :     if (deflateInit(zp, cs->compression_spec.level) != Z_OK)
      69 UNC           0 :         pg_fatal("could not initialize compression library: %s", zp->msg);
      70                 : 
      71                 :     /* Just be paranoid - maybe End is called after Start, with no Write */
      72 GNC          55 :     zp->next_out = gzipcs->outbuf;
      73              55 :     zp->avail_out = gzipcs->outsize;
      74                 : 
      75                 :     /* Keep track of gzipcs */
      76              55 :     cs->private_data = gzipcs;
      77              55 : }
      78                 : 
      79                 : static void
      80              55 : DeflateCompressorEnd(ArchiveHandle *AH, CompressorState *cs)
      81                 : {
      82              55 :     GzipCompressorState *gzipcs = (GzipCompressorState *) cs->private_data;
      83                 :     z_streamp   zp;
      84                 : 
      85              55 :     zp = gzipcs->zp;
      86              55 :     zp->next_in = NULL;
      87              55 :     zp->avail_in = 0;
      88                 : 
      89                 :     /* Flush any remaining data from zlib buffer */
      90              55 :     DeflateCompressorCommon(AH, cs, true);
      91                 : 
      92              55 :     if (deflateEnd(zp) != Z_OK)
      93 UNC           0 :         pg_fatal("could not close compression stream: %s", zp->msg);
      94                 : 
      95 GNC          55 :     pg_free(gzipcs->outbuf);
      96              55 :     pg_free(gzipcs->zp);
      97              55 :     pg_free(gzipcs);
      98              55 :     cs->private_data = NULL;
      99              55 : }
     100                 : 
     101                 : static void
     102             166 : DeflateCompressorCommon(ArchiveHandle *AH, CompressorState *cs, bool flush)
     103                 : {
     104             166 :     GzipCompressorState *gzipcs = (GzipCompressorState *) cs->private_data;
     105             166 :     z_streamp   zp = gzipcs->zp;
     106             166 :     void       *out = gzipcs->outbuf;
     107             166 :     int         res = Z_OK;
     108                 : 
     109             277 :     while (gzipcs->zp->avail_in != 0 || flush)
     110                 :     {
     111             166 :         res = deflate(zp, flush ? Z_FINISH : Z_NO_FLUSH);
     112             166 :         if (res == Z_STREAM_ERROR)
     113 UNC           0 :             pg_fatal("could not compress data: %s", zp->msg);
     114 GNC         166 :         if ((flush && (zp->avail_out < gzipcs->outsize))
     115             111 :             || (zp->avail_out == 0)
     116             111 :             || (zp->avail_in != 0)
     117                 :             )
     118                 :         {
     119                 :             /*
     120                 :              * Extra paranoia: avoid zero-length chunks, since a zero length
     121                 :              * chunk is the EOF marker in the custom format. This should never
     122                 :              * happen but ...
     123                 :              */
     124              55 :             if (zp->avail_out < gzipcs->outsize)
     125                 :             {
     126                 :                 /*
     127                 :                  * Any write function should do its own error checking but to
     128                 :                  * make sure we do a check here as well ...
     129                 :                  */
     130              55 :                 size_t      len = gzipcs->outsize - zp->avail_out;
     131                 : 
     132              55 :                 cs->writeF(AH, (char *) out, len);
     133                 :             }
     134              55 :             zp->next_out = out;
     135              55 :             zp->avail_out = gzipcs->outsize;
     136                 :         }
     137                 : 
     138             166 :         if (res == Z_STREAM_END)
     139              55 :             break;
     140                 :     }
     141             166 : }
     142                 : 
     143                 : static void
     144             110 : EndCompressorGzip(ArchiveHandle *AH, CompressorState *cs)
     145                 : {
     146                 :     /* If deflation was initialized, finalize it */
     147             110 :     if (cs->private_data)
     148              55 :         DeflateCompressorEnd(AH, cs);
     149             110 : }
     150                 : 
     151                 : static void
     152             111 : WriteDataToArchiveGzip(ArchiveHandle *AH, CompressorState *cs,
     153                 :                        const void *data, size_t dLen)
     154                 : {
     155             111 :     GzipCompressorState *gzipcs = (GzipCompressorState *) cs->private_data;
     156                 : 
     157             111 :     gzipcs->zp->next_in = (void *) unconstify(void *, data);
     158             111 :     gzipcs->zp->avail_in = dLen;
     159             111 :     DeflateCompressorCommon(AH, cs, false);
     160             111 : }
     161                 : 
     162                 : static void
     163              55 : ReadDataFromArchiveGzip(ArchiveHandle *AH, CompressorState *cs)
     164                 : {
     165                 :     z_streamp   zp;
     166                 :     char       *out;
     167              55 :     int         res = Z_OK;
     168                 :     size_t      cnt;
     169                 :     char       *buf;
     170                 :     size_t      buflen;
     171                 : 
     172              55 :     zp = (z_streamp) pg_malloc(sizeof(z_stream));
     173              55 :     zp->zalloc = Z_NULL;
     174              55 :     zp->zfree = Z_NULL;
     175              55 :     zp->opaque = Z_NULL;
     176                 : 
     177              55 :     buflen = DEFAULT_IO_BUFFER_SIZE;
     178              55 :     buf = pg_malloc(buflen);
     179                 : 
     180              55 :     out = pg_malloc(DEFAULT_IO_BUFFER_SIZE + 1);
     181                 : 
     182              55 :     if (inflateInit(zp) != Z_OK)
     183 UNC           0 :         pg_fatal("could not initialize compression library: %s",
     184                 :                  zp->msg);
     185                 : 
     186                 :     /* no minimal chunk size for zlib */
     187 GNC         110 :     while ((cnt = cs->readF(AH, &buf, &buflen)))
     188                 :     {
     189              55 :         zp->next_in = (void *) buf;
     190              55 :         zp->avail_in = cnt;
     191                 : 
     192             110 :         while (zp->avail_in > 0)
     193                 :         {
     194              55 :             zp->next_out = (void *) out;
     195              55 :             zp->avail_out = DEFAULT_IO_BUFFER_SIZE;
     196                 : 
     197              55 :             res = inflate(zp, 0);
     198              55 :             if (res != Z_OK && res != Z_STREAM_END)
     199 UNC           0 :                 pg_fatal("could not uncompress data: %s", zp->msg);
     200                 : 
     201 GNC          55 :             out[DEFAULT_IO_BUFFER_SIZE - zp->avail_out] = '\0';
     202              55 :             ahwrite(out, 1, DEFAULT_IO_BUFFER_SIZE - zp->avail_out, AH);
     203                 :         }
     204                 :     }
     205                 : 
     206              55 :     zp->next_in = NULL;
     207              55 :     zp->avail_in = 0;
     208              55 :     while (res != Z_STREAM_END)
     209                 :     {
     210 UNC           0 :         zp->next_out = (void *) out;
     211               0 :         zp->avail_out = DEFAULT_IO_BUFFER_SIZE;
     212               0 :         res = inflate(zp, 0);
     213               0 :         if (res != Z_OK && res != Z_STREAM_END)
     214               0 :             pg_fatal("could not uncompress data: %s", zp->msg);
     215                 : 
     216               0 :         out[DEFAULT_IO_BUFFER_SIZE - zp->avail_out] = '\0';
     217               0 :         ahwrite(out, 1, DEFAULT_IO_BUFFER_SIZE - zp->avail_out, AH);
     218                 :     }
     219                 : 
     220 GNC          55 :     if (inflateEnd(zp) != Z_OK)
     221 UNC           0 :         pg_fatal("could not close compression library: %s", zp->msg);
     222                 : 
     223 GNC          55 :     free(buf);
     224              55 :     free(out);
     225              55 :     free(zp);
     226              55 : }
     227                 : 
     228                 : /* Public routines that support gzip compressed data I/O */
     229                 : void
     230             110 : InitCompressorGzip(CompressorState *cs,
     231                 :                    const pg_compress_specification compression_spec)
     232                 : {
     233             110 :     cs->readData = ReadDataFromArchiveGzip;
     234             110 :     cs->writeData = WriteDataToArchiveGzip;
     235             110 :     cs->end = EndCompressorGzip;
     236                 : 
     237             110 :     cs->compression_spec = compression_spec;
     238                 : 
     239                 :     /*
     240                 :      * If the caller has defined a write function, prepare the necessary
     241                 :      * state.  Note that if the data is empty, End may be called immediately
     242                 :      * after Init, without ever calling Write.
     243                 :      */
     244             110 :     if (cs->writeF)
     245              55 :         DeflateCompressorInit(cs);
     246             110 : }
     247                 : 
     248                 : 
     249                 : /*----------------------
     250                 :  * Compress File API
     251                 :  *----------------------
     252                 :  */
     253                 : 
     254                 : static bool
     255             236 : Gzip_read(void *ptr, size_t size, size_t *rsize, CompressFileHandle *CFH)
     256                 : {
     257             236 :     gzFile      gzfp = (gzFile) CFH->private_data;
     258                 :     int         gzret;
     259                 : 
     260             236 :     gzret = gzread(gzfp, ptr, size);
     261             236 :     if (gzret <= 0 && !gzeof(gzfp))
     262                 :     {
     263                 :         int         errnum;
     264 UNC           0 :         const char *errmsg = gzerror(gzfp, &errnum);
     265                 : 
     266               0 :         pg_fatal("could not read from input file: %s",
     267                 :                  errnum == Z_ERRNO ? strerror(errno) : errmsg);
     268                 :     }
     269                 : 
     270 GNC         236 :     if (rsize)
     271             236 :         *rsize = (size_t) gzret;
     272                 : 
     273             236 :     return true;
     274                 : }
     275                 : 
     276                 : static bool
     277           25632 : Gzip_write(const void *ptr, size_t size, CompressFileHandle *CFH)
     278                 : {
     279           25632 :     gzFile      gzfp = (gzFile) CFH->private_data;
     280                 : 
     281           25632 :     return gzwrite(gzfp, ptr, size) > 0;
     282                 : }
     283                 : 
     284                 : static int
     285 UNC           0 : Gzip_getc(CompressFileHandle *CFH)
     286                 : {
     287               0 :     gzFile      gzfp = (gzFile) CFH->private_data;
     288                 :     int         ret;
     289                 : 
     290               0 :     errno = 0;
     291               0 :     ret = gzgetc(gzfp);
     292               0 :     if (ret == EOF)
     293                 :     {
     294               0 :         if (!gzeof(gzfp))
     295               0 :             pg_fatal("could not read from input file: %s", strerror(errno));
     296                 :         else
     297               0 :             pg_fatal("could not read from input file: end of file");
     298                 :     }
     299                 : 
     300               0 :     return ret;
     301                 : }
     302                 : 
     303                 : static char *
     304 GNC           3 : Gzip_gets(char *ptr, int size, CompressFileHandle *CFH)
     305                 : {
     306               3 :     gzFile      gzfp = (gzFile) CFH->private_data;
     307                 : 
     308               3 :     return gzgets(gzfp, ptr, size);
     309                 : }
     310                 : 
     311                 : static bool
     312             209 : Gzip_close(CompressFileHandle *CFH)
     313                 : {
     314             209 :     gzFile      gzfp = (gzFile) CFH->private_data;
     315                 : 
     316             209 :     CFH->private_data = NULL;
     317                 : 
     318             209 :     return gzclose(gzfp) == Z_OK;
     319                 : }
     320                 : 
     321                 : static bool
     322               1 : Gzip_eof(CompressFileHandle *CFH)
     323                 : {
     324               1 :     gzFile      gzfp = (gzFile) CFH->private_data;
     325                 : 
     326               1 :     return gzeof(gzfp) == 1;
     327                 : }
     328                 : 
     329                 : static const char *
     330 UNC           0 : Gzip_get_error(CompressFileHandle *CFH)
     331                 : {
     332               0 :     gzFile      gzfp = (gzFile) CFH->private_data;
     333                 :     const char *errmsg;
     334                 :     int         errnum;
     335                 : 
     336               0 :     errmsg = gzerror(gzfp, &errnum);
     337               0 :     if (errnum == Z_ERRNO)
     338               0 :         errmsg = strerror(errno);
     339                 : 
     340               0 :     return errmsg;
     341                 : }
     342                 : 
     343                 : static bool
     344 GNC         209 : Gzip_open(const char *path, int fd, const char *mode, CompressFileHandle *CFH)
     345                 : {
     346                 :     gzFile      gzfp;
     347                 :     char        mode_compression[32];
     348                 : 
     349             209 :     if (CFH->compression_spec.level != Z_DEFAULT_COMPRESSION)
     350                 :     {
     351                 :         /*
     352                 :          * user has specified a compression level, so tell zlib to use it
     353                 :          */
     354             132 :         snprintf(mode_compression, sizeof(mode_compression), "%s%d",
     355                 :                  mode, CFH->compression_spec.level);
     356                 :     }
     357                 :     else
     358              77 :         strcpy(mode_compression, mode);
     359                 : 
     360             209 :     if (fd >= 0)
     361 UNC           0 :         gzfp = gzdopen(dup(fd), mode_compression);
     362                 :     else
     363 GNC         209 :         gzfp = gzopen(path, mode_compression);
     364                 : 
     365             209 :     if (gzfp == NULL)
     366 UNC           0 :         return false;
     367                 : 
     368 GNC         209 :     CFH->private_data = gzfp;
     369                 : 
     370             209 :     return true;
     371                 : }
     372                 : 
     373                 : static bool
     374             103 : Gzip_open_write(const char *path, const char *mode, CompressFileHandle *CFH)
     375                 : {
     376                 :     char       *fname;
     377                 :     bool        ret;
     378                 :     int         save_errno;
     379                 : 
     380             103 :     fname = psprintf("%s.gz", path);
     381             103 :     ret = CFH->open_func(fname, -1, mode, CFH);
     382                 : 
     383             103 :     save_errno = errno;
     384             103 :     pg_free(fname);
     385             103 :     errno = save_errno;
     386                 : 
     387             103 :     return ret;
     388                 : }
     389                 : 
     390                 : void
     391             209 : InitCompressFileHandleGzip(CompressFileHandle *CFH,
     392                 :                            const pg_compress_specification compression_spec)
     393                 : {
     394             209 :     CFH->open_func = Gzip_open;
     395             209 :     CFH->open_write_func = Gzip_open_write;
     396             209 :     CFH->read_func = Gzip_read;
     397             209 :     CFH->write_func = Gzip_write;
     398             209 :     CFH->gets_func = Gzip_gets;
     399             209 :     CFH->getc_func = Gzip_getc;
     400             209 :     CFH->close_func = Gzip_close;
     401             209 :     CFH->eof_func = Gzip_eof;
     402             209 :     CFH->get_error_func = Gzip_get_error;
     403                 : 
     404             209 :     CFH->compression_spec = compression_spec;
     405                 : 
     406             209 :     CFH->private_data = NULL;
     407             209 : }
     408                 : #else                           /* HAVE_LIBZ */
     409                 : void
     410                 : InitCompressorGzip(CompressorState *cs,
     411                 :                    const pg_compress_specification compression_spec)
     412                 : {
     413                 :     pg_fatal("this build does not support compression with %s", "gzip");
     414                 : }
     415                 : 
     416                 : void
     417                 : InitCompressFileHandleGzip(CompressFileHandle *CFH,
     418                 :                            const pg_compress_specification compression_spec)
     419                 : {
     420                 :     pg_fatal("this build does not support compression with %s", "gzip");
     421                 : }
     422                 : #endif                          /* HAVE_LIBZ */
        

Generated by: LCOV version v1.16-55-g56c0a2a