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 17:13:01 Functions: 88.2 % 17 15 2 15
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 81.4 % 172 140 32 140
Legend: Lines: hit not hit Function coverage date bins:
[..60] days: 88.2 % 17 15 2 15

 Age         Owner                  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
   11 tomas.vondra               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)
   11 tomas.vondra               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 */
   11 tomas.vondra               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)
   11 tomas.vondra               93 UNC           0 :         pg_fatal("could not close compression stream: %s", zp->msg);
                                 94                 : 
   11 tomas.vondra               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                 : {
   45                           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)
   45 tomas.vondra              113 UNC           0 :             pg_fatal("could not compress data: %s", zp->msg);
   45 tomas.vondra              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 */
   11                           147             110 :     if (cs->private_data)
                                148              55 :         DeflateCompressorEnd(AH, cs);
   45                           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;
   11                           159             111 :     DeflateCompressorCommon(AH, cs, false);
   45                           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                 : 
   17                           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                 : 
   45                           182              55 :     if (inflateInit(zp) != Z_OK)
   45 tomas.vondra              183 UNC           0 :         pg_fatal("could not initialize compression library: %s",
                                184                 :                  zp->msg);
                                185                 : 
                                186                 :     /* no minimal chunk size for zlib */
   45 tomas.vondra              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;
   17                           195              55 :             zp->avail_out = DEFAULT_IO_BUFFER_SIZE;
                                196                 : 
   45                           197              55 :             res = inflate(zp, 0);
                                198              55 :             if (res != Z_OK && res != Z_STREAM_END)
   45 tomas.vondra              199 UNC           0 :                 pg_fatal("could not uncompress data: %s", zp->msg);
                                200                 : 
   17 tomas.vondra              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                 : 
   45                           206              55 :     zp->next_in = NULL;
                                207              55 :     zp->avail_in = 0;
                                208              55 :     while (res != Z_STREAM_END)
                                209                 :     {
   45 tomas.vondra              210 UNC           0 :         zp->next_out = (void *) out;
   17                           211               0 :         zp->avail_out = DEFAULT_IO_BUFFER_SIZE;
   45                           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                 : 
   17                           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                 : 
   45 tomas.vondra              220 GNC          55 :     if (inflateEnd(zp) != Z_OK)
   45 tomas.vondra              221 UNC           0 :         pg_fatal("could not close compression library: %s", zp->msg);
                                222                 : 
   45 tomas.vondra              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                 :      */
   11                           244             110 :     if (cs->writeF)
                                245              55 :         DeflateCompressorInit(cs);
   45                           246             110 : }
                                247                 : 
                                248                 : 
                                249                 : /*----------------------
                                250                 :  * Compress File API
                                251                 :  *----------------------
                                252                 :  */
                                253                 : 
                                254                 : static bool
   17                           255             236 : Gzip_read(void *ptr, size_t size, size_t *rsize, CompressFileHandle *CFH)
                                256                 : {
   45                           257             236 :     gzFile      gzfp = (gzFile) CFH->private_data;
                                258                 :     int         gzret;
                                259                 : 
   17                           260             236 :     gzret = gzread(gzfp, ptr, size);
                                261             236 :     if (gzret <= 0 && !gzeof(gzfp))
                                262                 :     {
                                263                 :         int         errnum;
   45 tomas.vondra              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                 : 
   17 tomas.vondra              270 GNC         236 :     if (rsize)
                                271             236 :         *rsize = (size_t) gzret;
                                272                 : 
                                273             236 :     return true;
                                274                 : }
                                275                 : 
                                276                 : static bool
   45                           277           25632 : Gzip_write(const void *ptr, size_t size, CompressFileHandle *CFH)
                                278                 : {
                                279           25632 :     gzFile      gzfp = (gzFile) CFH->private_data;
                                280                 : 
   17                           281           25632 :     return gzwrite(gzfp, ptr, size) > 0;
                                282                 : }
                                283                 : 
                                284                 : static int
   45 tomas.vondra              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 *
   45 tomas.vondra              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                 : 
   17                           318             209 :     return gzclose(gzfp) == Z_OK;
                                319                 : }
                                320                 : 
                                321                 : static bool
   45                           322               1 : Gzip_eof(CompressFileHandle *CFH)
                                323                 : {
                                324               1 :     gzFile      gzfp = (gzFile) CFH->private_data;
                                325                 : 
   17                           326               1 :     return gzeof(gzfp) == 1;
                                327                 : }
                                328                 : 
                                329                 : static const char *
   45 tomas.vondra              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
   45 tomas.vondra              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)
   45 tomas.vondra              361 UNC           0 :         gzfp = gzdopen(dup(fd), mode_compression);
                                362                 :     else
   45 tomas.vondra              363 GNC         209 :         gzfp = gzopen(path, mode_compression);
                                364                 : 
                                365             209 :     if (gzfp == NULL)
   17 tomas.vondra              366 UNC           0 :         return false;
                                367                 : 
   45 tomas.vondra              368 GNC         209 :     CFH->private_data = gzfp;
                                369                 : 
   17                           370             209 :     return true;
                                371                 : }
                                372                 : 
                                373                 : static bool
   45                           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