LCOV - code coverage report
Current view: top level - src/bin/pg_dump - compress_io.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 176 228 77.2 %
Date: 2019-11-15 23:07:02 Functions: 21 24 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * compress_io.c
       4             :  *   Routines for archivers to write an uncompressed or compressed data
       5             :  *   stream.
       6             :  *
       7             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  * This file includes two APIs for dealing with compressed data. The first
      11             :  * provides more flexibility, using callbacks to read/write data from the
      12             :  * underlying stream. The second API is a wrapper around fopen/gzopen and
      13             :  * friends, providing an interface similar to those, but abstracts away
      14             :  * the possible compression. Both APIs use libz for the compression, but
      15             :  * the second API uses gzip headers, so the resulting files can be easily
      16             :  * manipulated with the gzip utility.
      17             :  *
      18             :  * Compressor API
      19             :  * --------------
      20             :  *
      21             :  *  The interface for writing to an archive consists of three functions:
      22             :  *  AllocateCompressor, WriteDataToArchive and EndCompressor. First you call
      23             :  *  AllocateCompressor, then write all the data by calling WriteDataToArchive
      24             :  *  as many times as needed, and finally EndCompressor. WriteDataToArchive
      25             :  *  and EndCompressor will call the WriteFunc that was provided to
      26             :  *  AllocateCompressor for each chunk of compressed data.
      27             :  *
      28             :  *  The interface for reading an archive consists of just one function:
      29             :  *  ReadDataFromArchive. ReadDataFromArchive reads the whole compressed input
      30             :  *  stream, by repeatedly calling the given ReadFunc. ReadFunc returns the
      31             :  *  compressed data chunk at a time, and ReadDataFromArchive decompresses it
      32             :  *  and passes the decompressed data to ahwrite(), until ReadFunc returns 0
      33             :  *  to signal EOF.
      34             :  *
      35             :  *  The interface is the same for compressed and uncompressed streams.
      36             :  *
      37             :  * Compressed stream API
      38             :  * ----------------------
      39             :  *
      40             :  *  The compressed stream API is a wrapper around the C standard fopen() and
      41             :  *  libz's gzopen() APIs. It allows you to use the same functions for
      42             :  *  compressed and uncompressed streams. cfopen_read() first tries to open
      43             :  *  the file with given name, and if it fails, it tries to open the same
      44             :  *  file with the .gz suffix. cfopen_write() opens a file for writing, an
      45             :  *  extra argument specifies if the file should be compressed, and adds the
      46             :  *  .gz suffix to the filename if so. This allows you to easily handle both
      47             :  *  compressed and uncompressed files.
      48             :  *
      49             :  * IDENTIFICATION
      50             :  *     src/bin/pg_dump/compress_io.c
      51             :  *
      52             :  *-------------------------------------------------------------------------
      53             :  */
      54             : #include "postgres_fe.h"
      55             : 
      56             : #include "compress_io.h"
      57             : #include "pg_backup_utils.h"
      58             : 
      59             : /*----------------------
      60             :  * Compressor API
      61             :  *----------------------
      62             :  */
      63             : 
      64             : /* typedef appears in compress_io.h */
      65             : struct CompressorState
      66             : {
      67             :     CompressionAlgorithm comprAlg;
      68             :     WriteFunc   writeF;
      69             : 
      70             : #ifdef HAVE_LIBZ
      71             :     z_streamp   zp;
      72             :     char       *zlibOut;
      73             :     size_t      zlibOutSize;
      74             : #endif
      75             : };
      76             : 
      77             : static void ParseCompressionOption(int compression, CompressionAlgorithm *alg,
      78             :                                    int *level);
      79             : 
      80             : /* Routines that support zlib compressed data I/O */
      81             : #ifdef HAVE_LIBZ
      82             : static void InitCompressorZlib(CompressorState *cs, int level);
      83             : static void DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs,
      84             :                                   bool flush);
      85             : static void ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF);
      86             : static void WriteDataToArchiveZlib(ArchiveHandle *AH, CompressorState *cs,
      87             :                                    const char *data, size_t dLen);
      88             : static void EndCompressorZlib(ArchiveHandle *AH, CompressorState *cs);
      89             : #endif
      90             : 
      91             : /* Routines that support uncompressed data I/O */
      92             : static void ReadDataFromArchiveNone(ArchiveHandle *AH, ReadFunc readF);
      93             : static void WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs,
      94             :                                    const char *data, size_t dLen);
      95             : 
      96             : /*
      97             :  * Interprets a numeric 'compression' value. The algorithm implied by the
      98             :  * value (zlib or none at the moment), is returned in *alg, and the
      99             :  * zlib compression level in *level.
     100             :  */
     101             : static void
     102          68 : ParseCompressionOption(int compression, CompressionAlgorithm *alg, int *level)
     103             : {
     104          68 :     if (compression == Z_DEFAULT_COMPRESSION ||
     105          68 :         (compression > 0 && compression <= 9))
     106          68 :         *alg = COMPR_ALG_LIBZ;
     107           0 :     else if (compression == 0)
     108           0 :         *alg = COMPR_ALG_NONE;
     109             :     else
     110             :     {
     111           0 :         fatal("invalid compression code: %d", compression);
     112             :         *alg = COMPR_ALG_NONE;  /* keep compiler quiet */
     113             :     }
     114             : 
     115             :     /* The level is just the passed-in value. */
     116          68 :     if (level)
     117          34 :         *level = compression;
     118          68 : }
     119             : 
     120             : /* Public interface routines */
     121             : 
     122             : /* Allocate a new compressor */
     123             : CompressorState *
     124          34 : AllocateCompressor(int compression, WriteFunc writeF)
     125             : {
     126             :     CompressorState *cs;
     127             :     CompressionAlgorithm alg;
     128             :     int         level;
     129             : 
     130          34 :     ParseCompressionOption(compression, &alg, &level);
     131             : 
     132             : #ifndef HAVE_LIBZ
     133             :     if (alg == COMPR_ALG_LIBZ)
     134             :         fatal("not built with zlib support");
     135             : #endif
     136             : 
     137          34 :     cs = (CompressorState *) pg_malloc0(sizeof(CompressorState));
     138          34 :     cs->writeF = writeF;
     139          34 :     cs->comprAlg = alg;
     140             : 
     141             :     /*
     142             :      * Perform compression algorithm specific initialization.
     143             :      */
     144             : #ifdef HAVE_LIBZ
     145          34 :     if (alg == COMPR_ALG_LIBZ)
     146          34 :         InitCompressorZlib(cs, level);
     147             : #endif
     148             : 
     149          34 :     return cs;
     150             : }
     151             : 
     152             : /*
     153             :  * Read all compressed data from the input stream (via readF) and print it
     154             :  * out with ahwrite().
     155             :  */
     156             : void
     157          34 : ReadDataFromArchive(ArchiveHandle *AH, int compression, ReadFunc readF)
     158             : {
     159             :     CompressionAlgorithm alg;
     160             : 
     161          34 :     ParseCompressionOption(compression, &alg, NULL);
     162             : 
     163          34 :     if (alg == COMPR_ALG_NONE)
     164           0 :         ReadDataFromArchiveNone(AH, readF);
     165          34 :     if (alg == COMPR_ALG_LIBZ)
     166             :     {
     167             : #ifdef HAVE_LIBZ
     168          34 :         ReadDataFromArchiveZlib(AH, readF);
     169             : #else
     170             :         fatal("not built with zlib support");
     171             : #endif
     172             :     }
     173          34 : }
     174             : 
     175             : /*
     176             :  * Compress and write data to the output stream (via writeF).
     177             :  */
     178             : void
     179          88 : WriteDataToArchive(ArchiveHandle *AH, CompressorState *cs,
     180             :                    const void *data, size_t dLen)
     181             : {
     182          88 :     switch (cs->comprAlg)
     183             :     {
     184             :         case COMPR_ALG_LIBZ:
     185             : #ifdef HAVE_LIBZ
     186          88 :             WriteDataToArchiveZlib(AH, cs, data, dLen);
     187             : #else
     188             :             fatal("not built with zlib support");
     189             : #endif
     190          88 :             break;
     191             :         case COMPR_ALG_NONE:
     192           0 :             WriteDataToArchiveNone(AH, cs, data, dLen);
     193           0 :             break;
     194             :     }
     195          88 :     return;
     196             : }
     197             : 
     198             : /*
     199             :  * Terminate compression library context and flush its buffers.
     200             :  */
     201             : void
     202          34 : EndCompressor(ArchiveHandle *AH, CompressorState *cs)
     203             : {
     204             : #ifdef HAVE_LIBZ
     205          34 :     if (cs->comprAlg == COMPR_ALG_LIBZ)
     206          34 :         EndCompressorZlib(AH, cs);
     207             : #endif
     208          34 :     free(cs);
     209          34 : }
     210             : 
     211             : /* Private routines, specific to each compression method. */
     212             : 
     213             : #ifdef HAVE_LIBZ
     214             : /*
     215             :  * Functions for zlib compressed output.
     216             :  */
     217             : 
     218             : static void
     219          34 : InitCompressorZlib(CompressorState *cs, int level)
     220             : {
     221             :     z_streamp   zp;
     222             : 
     223          34 :     zp = cs->zp = (z_streamp) pg_malloc(sizeof(z_stream));
     224          34 :     zp->zalloc = Z_NULL;
     225          34 :     zp->zfree = Z_NULL;
     226          34 :     zp->opaque = Z_NULL;
     227             : 
     228             :     /*
     229             :      * zlibOutSize is the buffer size we tell zlib it can output to.  We
     230             :      * actually allocate one extra byte because some routines want to append a
     231             :      * trailing zero byte to the zlib output.
     232             :      */
     233          34 :     cs->zlibOut = (char *) pg_malloc(ZLIB_OUT_SIZE + 1);
     234          34 :     cs->zlibOutSize = ZLIB_OUT_SIZE;
     235             : 
     236          34 :     if (deflateInit(zp, level) != Z_OK)
     237           0 :         fatal("could not initialize compression library: %s",
     238             :               zp->msg);
     239             : 
     240             :     /* Just be paranoid - maybe End is called after Start, with no Write */
     241          34 :     zp->next_out = (void *) cs->zlibOut;
     242          34 :     zp->avail_out = cs->zlibOutSize;
     243          34 : }
     244             : 
     245             : static void
     246          34 : EndCompressorZlib(ArchiveHandle *AH, CompressorState *cs)
     247             : {
     248          34 :     z_streamp   zp = cs->zp;
     249             : 
     250          34 :     zp->next_in = NULL;
     251          34 :     zp->avail_in = 0;
     252             : 
     253             :     /* Flush any remaining data from zlib buffer */
     254          34 :     DeflateCompressorZlib(AH, cs, true);
     255             : 
     256          34 :     if (deflateEnd(zp) != Z_OK)
     257           0 :         fatal("could not close compression stream: %s", zp->msg);
     258             : 
     259          34 :     free(cs->zlibOut);
     260          34 :     free(cs->zp);
     261          34 : }
     262             : 
     263             : static void
     264         122 : DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs, bool flush)
     265             : {
     266         122 :     z_streamp   zp = cs->zp;
     267         122 :     char       *out = cs->zlibOut;
     268         122 :     int         res = Z_OK;
     269             : 
     270         332 :     while (cs->zp->avail_in != 0 || flush)
     271             :     {
     272         122 :         res = deflate(zp, flush ? Z_FINISH : Z_NO_FLUSH);
     273         122 :         if (res == Z_STREAM_ERROR)
     274           0 :             fatal("could not compress data: %s", zp->msg);
     275         122 :         if ((flush && (zp->avail_out < cs->zlibOutSize))
     276          88 :             || (zp->avail_out == 0)
     277          88 :             || (zp->avail_in != 0)
     278             :             )
     279             :         {
     280             :             /*
     281             :              * Extra paranoia: avoid zero-length chunks, since a zero length
     282             :              * chunk is the EOF marker in the custom format. This should never
     283             :              * happen but...
     284             :              */
     285          34 :             if (zp->avail_out < cs->zlibOutSize)
     286             :             {
     287             :                 /*
     288             :                  * Any write function should do its own error checking but to
     289             :                  * make sure we do a check here as well...
     290             :                  */
     291          34 :                 size_t      len = cs->zlibOutSize - zp->avail_out;
     292             : 
     293          34 :                 cs->writeF(AH, out, len);
     294             :             }
     295          34 :             zp->next_out = (void *) out;
     296          34 :             zp->avail_out = cs->zlibOutSize;
     297             :         }
     298             : 
     299         122 :         if (res == Z_STREAM_END)
     300          34 :             break;
     301             :     }
     302         122 : }
     303             : 
     304             : static void
     305          88 : WriteDataToArchiveZlib(ArchiveHandle *AH, CompressorState *cs,
     306             :                        const char *data, size_t dLen)
     307             : {
     308          88 :     cs->zp->next_in = (void *) unconstify(char *, data);
     309          88 :     cs->zp->avail_in = dLen;
     310          88 :     DeflateCompressorZlib(AH, cs, false);
     311             : 
     312          88 :     return;
     313             : }
     314             : 
     315             : static void
     316          34 : ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF)
     317             : {
     318             :     z_streamp   zp;
     319             :     char       *out;
     320          34 :     int         res = Z_OK;
     321             :     size_t      cnt;
     322             :     char       *buf;
     323             :     size_t      buflen;
     324             : 
     325          34 :     zp = (z_streamp) pg_malloc(sizeof(z_stream));
     326          34 :     zp->zalloc = Z_NULL;
     327          34 :     zp->zfree = Z_NULL;
     328          34 :     zp->opaque = Z_NULL;
     329             : 
     330          34 :     buf = pg_malloc(ZLIB_IN_SIZE);
     331          34 :     buflen = ZLIB_IN_SIZE;
     332             : 
     333          34 :     out = pg_malloc(ZLIB_OUT_SIZE + 1);
     334             : 
     335          34 :     if (inflateInit(zp) != Z_OK)
     336           0 :         fatal("could not initialize compression library: %s",
     337             :               zp->msg);
     338             : 
     339             :     /* no minimal chunk size for zlib */
     340         102 :     while ((cnt = readF(AH, &buf, &buflen)))
     341             :     {
     342          34 :         zp->next_in = (void *) buf;
     343          34 :         zp->avail_in = cnt;
     344             : 
     345         102 :         while (zp->avail_in > 0)
     346             :         {
     347          34 :             zp->next_out = (void *) out;
     348          34 :             zp->avail_out = ZLIB_OUT_SIZE;
     349             : 
     350          34 :             res = inflate(zp, 0);
     351          34 :             if (res != Z_OK && res != Z_STREAM_END)
     352           0 :                 fatal("could not uncompress data: %s", zp->msg);
     353             : 
     354          34 :             out[ZLIB_OUT_SIZE - zp->avail_out] = '\0';
     355          34 :             ahwrite(out, 1, ZLIB_OUT_SIZE - zp->avail_out, AH);
     356             :         }
     357             :     }
     358             : 
     359          34 :     zp->next_in = NULL;
     360          34 :     zp->avail_in = 0;
     361          68 :     while (res != Z_STREAM_END)
     362             :     {
     363           0 :         zp->next_out = (void *) out;
     364           0 :         zp->avail_out = ZLIB_OUT_SIZE;
     365           0 :         res = inflate(zp, 0);
     366           0 :         if (res != Z_OK && res != Z_STREAM_END)
     367           0 :             fatal("could not uncompress data: %s", zp->msg);
     368             : 
     369           0 :         out[ZLIB_OUT_SIZE - zp->avail_out] = '\0';
     370           0 :         ahwrite(out, 1, ZLIB_OUT_SIZE - zp->avail_out, AH);
     371             :     }
     372             : 
     373          34 :     if (inflateEnd(zp) != Z_OK)
     374           0 :         fatal("could not close compression library: %s", zp->msg);
     375             : 
     376          34 :     free(buf);
     377          34 :     free(out);
     378          34 :     free(zp);
     379          34 : }
     380             : #endif                          /* HAVE_LIBZ */
     381             : 
     382             : 
     383             : /*
     384             :  * Functions for uncompressed output.
     385             :  */
     386             : 
     387             : static void
     388           0 : ReadDataFromArchiveNone(ArchiveHandle *AH, ReadFunc readF)
     389             : {
     390             :     size_t      cnt;
     391             :     char       *buf;
     392             :     size_t      buflen;
     393             : 
     394           0 :     buf = pg_malloc(ZLIB_OUT_SIZE);
     395           0 :     buflen = ZLIB_OUT_SIZE;
     396             : 
     397           0 :     while ((cnt = readF(AH, &buf, &buflen)))
     398             :     {
     399           0 :         ahwrite(buf, 1, cnt, AH);
     400             :     }
     401             : 
     402           0 :     free(buf);
     403           0 : }
     404             : 
     405             : static void
     406           0 : WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs,
     407             :                        const char *data, size_t dLen)
     408             : {
     409           0 :     cs->writeF(AH, data, dLen);
     410           0 :     return;
     411             : }
     412             : 
     413             : 
     414             : /*----------------------
     415             :  * Compressed stream API
     416             :  *----------------------
     417             :  */
     418             : 
     419             : /*
     420             :  * cfp represents an open stream, wrapping the underlying FILE or gzFile
     421             :  * pointer. This is opaque to the callers.
     422             :  */
     423             : struct cfp
     424             : {
     425             :     FILE       *uncompressedfp;
     426             : #ifdef HAVE_LIBZ
     427             :     gzFile      compressedfp;
     428             : #endif
     429             : };
     430             : 
     431             : #ifdef HAVE_LIBZ
     432             : static int  hasSuffix(const char *filename, const char *suffix);
     433             : #endif
     434             : 
     435             : /* free() without changing errno; useful in several places below */
     436             : static void
     437         400 : free_keep_errno(void *p)
     438             : {
     439         400 :     int         save_errno = errno;
     440             : 
     441         400 :     free(p);
     442         400 :     errno = save_errno;
     443         400 : }
     444             : 
     445             : /*
     446             :  * Open a file for reading. 'path' is the file to open, and 'mode' should
     447             :  * be either "r" or "rb".
     448             :  *
     449             :  * If the file at 'path' does not exist, we append the ".gz" suffix (if 'path'
     450             :  * doesn't already have it) and try again. So if you pass "foo" as 'path',
     451             :  * this will open either "foo" or "foo.gz".
     452             :  *
     453             :  * On failure, return NULL with an error code in errno.
     454             :  */
     455             : cfp *
     456          92 : cfopen_read(const char *path, const char *mode)
     457             : {
     458             :     cfp        *fp;
     459             : 
     460             : #ifdef HAVE_LIBZ
     461          92 :     if (hasSuffix(path, ".gz"))
     462           0 :         fp = cfopen(path, mode, 1);
     463             :     else
     464             : #endif
     465             :     {
     466          92 :         fp = cfopen(path, mode, 0);
     467             : #ifdef HAVE_LIBZ
     468          92 :         if (fp == NULL)
     469             :         {
     470             :             char       *fname;
     471             : 
     472          74 :             fname = psprintf("%s.gz", path);
     473          74 :             fp = cfopen(fname, mode, 1);
     474          74 :             free_keep_errno(fname);
     475             :         }
     476             : #endif
     477             :     }
     478          92 :     return fp;
     479             : }
     480             : 
     481             : /*
     482             :  * Open a file for writing. 'path' indicates the path name, and 'mode' must
     483             :  * be a filemode as accepted by fopen() and gzopen() that indicates writing
     484             :  * ("w", "wb", "a", or "ab").
     485             :  *
     486             :  * If 'compression' is non-zero, a gzip compressed stream is opened, and
     487             :  * 'compression' indicates the compression level used. The ".gz" suffix
     488             :  * is automatically added to 'path' in that case.
     489             :  *
     490             :  * On failure, return NULL with an error code in errno.
     491             :  */
     492             : cfp *
     493          88 : cfopen_write(const char *path, const char *mode, int compression)
     494             : {
     495             :     cfp        *fp;
     496             : 
     497          88 :     if (compression == 0)
     498          16 :         fp = cfopen(path, mode, 0);
     499             :     else
     500             :     {
     501             : #ifdef HAVE_LIBZ
     502             :         char       *fname;
     503             : 
     504          72 :         fname = psprintf("%s.gz", path);
     505          72 :         fp = cfopen(fname, mode, compression);
     506          72 :         free_keep_errno(fname);
     507             : #else
     508             :         fatal("not built with zlib support");
     509             :         fp = NULL;              /* keep compiler quiet */
     510             : #endif
     511             :     }
     512          88 :     return fp;
     513             : }
     514             : 
     515             : /*
     516             :  * Opens file 'path' in 'mode'. If 'compression' is non-zero, the file
     517             :  * is opened with libz gzopen(), otherwise with plain fopen().
     518             :  *
     519             :  * On failure, return NULL with an error code in errno.
     520             :  */
     521             : cfp *
     522         254 : cfopen(const char *path, const char *mode, int compression)
     523             : {
     524         254 :     cfp        *fp = pg_malloc(sizeof(cfp));
     525             : 
     526         254 :     if (compression != 0)
     527             :     {
     528             : #ifdef HAVE_LIBZ
     529         146 :         if (compression != Z_DEFAULT_COMPRESSION)
     530             :         {
     531             :             /* user has specified a compression level, so tell zlib to use it */
     532             :             char        mode_compression[32];
     533             : 
     534          74 :             snprintf(mode_compression, sizeof(mode_compression), "%s%d",
     535             :                      mode, compression);
     536          74 :             fp->compressedfp = gzopen(path, mode_compression);
     537             :         }
     538             :         else
     539             :         {
     540             :             /* don't specify a level, just use the zlib default */
     541          72 :             fp->compressedfp = gzopen(path, mode);
     542             :         }
     543             : 
     544         146 :         fp->uncompressedfp = NULL;
     545         146 :         if (fp->compressedfp == NULL)
     546             :         {
     547           0 :             free_keep_errno(fp);
     548           0 :             fp = NULL;
     549             :         }
     550             : #else
     551             :         fatal("not built with zlib support");
     552             : #endif
     553             :     }
     554             :     else
     555             :     {
     556             : #ifdef HAVE_LIBZ
     557         108 :         fp->compressedfp = NULL;
     558             : #endif
     559         108 :         fp->uncompressedfp = fopen(path, mode);
     560         108 :         if (fp->uncompressedfp == NULL)
     561             :         {
     562          74 :             free_keep_errno(fp);
     563          74 :             fp = NULL;
     564             :         }
     565             :     }
     566             : 
     567         254 :     return fp;
     568             : }
     569             : 
     570             : 
     571             : int
     572        9748 : cfread(void *ptr, int size, cfp *fp)
     573             : {
     574             :     int         ret;
     575             : 
     576        9748 :     if (size == 0)
     577         994 :         return 0;
     578             : 
     579             : #ifdef HAVE_LIBZ
     580        8754 :     if (fp->compressedfp)
     581             :     {
     582         148 :         ret = gzread(fp->compressedfp, ptr, size);
     583         148 :         if (ret != size && !gzeof(fp->compressedfp))
     584             :         {
     585             :             int         errnum;
     586           0 :             const char *errmsg = gzerror(fp->compressedfp, &errnum);
     587             : 
     588           0 :             fatal("could not read from input file: %s",
     589             :                   errnum == Z_ERRNO ? strerror(errno) : errmsg);
     590             :         }
     591             :     }
     592             :     else
     593             : #endif
     594             :     {
     595        8606 :         ret = fread(ptr, 1, size, fp->uncompressedfp);
     596        8606 :         if (ret != size && !feof(fp->uncompressedfp))
     597           0 :             READ_ERROR_EXIT(fp->uncompressedfp);
     598             :     }
     599        8754 :     return ret;
     600             : }
     601             : 
     602             : int
     603       91374 : cfwrite(const void *ptr, int size, cfp *fp)
     604             : {
     605             : #ifdef HAVE_LIBZ
     606       91374 :     if (fp->compressedfp)
     607         180 :         return gzwrite(fp->compressedfp, ptr, size);
     608             :     else
     609             : #endif
     610       91194 :         return fwrite(ptr, 1, size, fp->uncompressedfp);
     611             : }
     612             : 
     613             : int
     614       82864 : cfgetc(cfp *fp)
     615             : {
     616             :     int         ret;
     617             : 
     618             : #ifdef HAVE_LIBZ
     619       82864 :     if (fp->compressedfp)
     620             :     {
     621           0 :         ret = gzgetc(fp->compressedfp);
     622           0 :         if (ret == EOF)
     623             :         {
     624           0 :             if (!gzeof(fp->compressedfp))
     625           0 :                 fatal("could not read from input file: %s", strerror(errno));
     626             :             else
     627           0 :                 fatal("could not read from input file: end of file");
     628             :         }
     629             :     }
     630             :     else
     631             : #endif
     632             :     {
     633       82864 :         ret = fgetc(fp->uncompressedfp);
     634       82864 :         if (ret == EOF)
     635           0 :             READ_ERROR_EXIT(fp->uncompressedfp);
     636             :     }
     637             : 
     638       82864 :     return ret;
     639             : }
     640             : 
     641             : char *
     642           8 : cfgets(cfp *fp, char *buf, int len)
     643             : {
     644             : #ifdef HAVE_LIBZ
     645           8 :     if (fp->compressedfp)
     646           0 :         return gzgets(fp->compressedfp, buf, len);
     647             :     else
     648             : #endif
     649           8 :         return fgets(buf, len, fp->uncompressedfp);
     650             : }
     651             : 
     652             : int
     653         180 : cfclose(cfp *fp)
     654             : {
     655             :     int         result;
     656             : 
     657         180 :     if (fp == NULL)
     658             :     {
     659           0 :         errno = EBADF;
     660           0 :         return EOF;
     661             :     }
     662             : #ifdef HAVE_LIBZ
     663         180 :     if (fp->compressedfp)
     664             :     {
     665         146 :         result = gzclose(fp->compressedfp);
     666         146 :         fp->compressedfp = NULL;
     667             :     }
     668             :     else
     669             : #endif
     670             :     {
     671          34 :         result = fclose(fp->uncompressedfp);
     672          34 :         fp->uncompressedfp = NULL;
     673             :     }
     674         180 :     free_keep_errno(fp);
     675             : 
     676         180 :     return result;
     677             : }
     678             : 
     679             : int
     680           4 : cfeof(cfp *fp)
     681             : {
     682             : #ifdef HAVE_LIBZ
     683           4 :     if (fp->compressedfp)
     684           0 :         return gzeof(fp->compressedfp);
     685             :     else
     686             : #endif
     687           4 :         return feof(fp->uncompressedfp);
     688             : }
     689             : 
     690             : const char *
     691           0 : get_cfp_error(cfp *fp)
     692             : {
     693             : #ifdef HAVE_LIBZ
     694           0 :     if (fp->compressedfp)
     695             :     {
     696             :         int         errnum;
     697           0 :         const char *errmsg = gzerror(fp->compressedfp, &errnum);
     698             : 
     699           0 :         if (errnum != Z_ERRNO)
     700           0 :             return errmsg;
     701             :     }
     702             : #endif
     703           0 :     return strerror(errno);
     704             : }
     705             : 
     706             : #ifdef HAVE_LIBZ
     707             : static int
     708          92 : hasSuffix(const char *filename, const char *suffix)
     709             : {
     710          92 :     int         filenamelen = strlen(filename);
     711          92 :     int         suffixlen = strlen(suffix);
     712             : 
     713          92 :     if (filenamelen < suffixlen)
     714           0 :         return 0;
     715             : 
     716          92 :     return memcmp(&filename[filenamelen - suffixlen],
     717             :                   suffix,
     718          92 :                   suffixlen) == 0;
     719             : }
     720             : 
     721             : #endif

Generated by: LCOV version 1.13