diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_gzip.c index 5ac21f091f0..3c9ac55c266 100644 --- a/src/bin/pg_dump/compress_io.c +++ b/src/bin/pg_dump/compress_gzip.c @@ -1,285 +1,118 @@ /*------------------------------------------------------------------------- * - * compress_io.c - * Routines for archivers to write an uncompressed or compressed data - * stream. + * compress_gzip.c + * Routines for archivers to read or write a gzip compressed data stream. * * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * This file includes two APIs for dealing with compressed data. The first - * provides more flexibility, using callbacks to read/write data from the - * underlying stream. The second API is a wrapper around fopen/gzopen and - * friends, providing an interface similar to those, but abstracts away - * the possible compression. Both APIs use libz for the compression, but - * the second API uses gzip headers, so the resulting files can be easily - * manipulated with the gzip utility. - * - * Compressor API - * -------------- - * - * The interface for writing to an archive consists of three functions: - * AllocateCompressor, WriteDataToArchive and EndCompressor. First you call - * AllocateCompressor, then write all the data by calling WriteDataToArchive - * as many times as needed, and finally EndCompressor. WriteDataToArchive - * and EndCompressor will call the WriteFunc that was provided to - * AllocateCompressor for each chunk of compressed data. - * - * The interface for reading an archive consists of just one function: - * ReadDataFromArchive. ReadDataFromArchive reads the whole compressed input - * stream, by repeatedly calling the given ReadFunc. ReadFunc returns the - * compressed data chunk at a time, and ReadDataFromArchive decompresses it - * and passes the decompressed data to ahwrite(), until ReadFunc returns 0 - * to signal EOF. - * - * The interface is the same for compressed and uncompressed streams. - * - * Compressed stream API - * ---------------------- - * - * The compressed stream API is a wrapper around the C standard fopen() and - * libz's gzopen() APIs. It allows you to use the same functions for - * compressed and uncompressed streams. cfopen_read() first tries to open - * the file with given name, and if it fails, it tries to open the same - * file with the .gz suffix. cfopen_write() opens a file for writing, an - * extra argument specifies if the file should be compressed, and adds the - * .gz suffix to the filename if so. This allows you to easily handle both - * compressed and uncompressed files. - * * IDENTIFICATION - * src/bin/pg_dump/compress_io.c + * src/bin/pg_dump/compress_gzip.c * *------------------------------------------------------------------------- */ #include "postgres_fe.h" +#include -#include "compress_io.h" +#include "compress_gzip.h" #include "pg_backup_utils.h" #ifdef HAVE_LIBZ -#include -#endif - -/*---------------------- - * Generic functions - *---------------------- - */ - -/* - * Checks whether a compression algorithm is supported. - * - * On success returns NULL, otherwise returns a malloc'ed string which can be - * used by the caller in an error message. - */ -char * -supports_compression(const pg_compress_specification compression_spec) -{ - const pg_compress_algorithm algorithm = compression_spec.algorithm; - bool supported = false; - - if (algorithm == PG_COMPRESSION_NONE) - supported = true; -#ifdef HAVE_LIBZ - if (algorithm == PG_COMPRESSION_GZIP) - supported = true; -#endif - - if (!supported) - return psprintf("this build does not support compression with %s", - get_compress_algorithm_name(algorithm)); - - return NULL; -} +#include "zlib.h" /*---------------------- * Compressor API *---------------------- */ - -/* typedef appears in compress_io.h */ -struct CompressorState +typedef struct GzipCompressorState { - pg_compress_specification compression_spec; - WriteFunc writeF; - -#ifdef HAVE_LIBZ z_streamp zp; - char *zlibOut; - size_t zlibOutSize; -#endif -}; -/* Routines that support zlib compressed data I/O */ -#ifdef HAVE_LIBZ -static void InitCompressorZlib(CompressorState *cs, int level); -static void DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs, - bool flush); -static void ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF); -static void WriteDataToArchiveZlib(ArchiveHandle *AH, CompressorState *cs, - const char *data, size_t dLen); -static void EndCompressorZlib(ArchiveHandle *AH, CompressorState *cs); -#endif - -/* Routines that support uncompressed data I/O */ -static void ReadDataFromArchiveNone(ArchiveHandle *AH, ReadFunc readF); -static void WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs, - const char *data, size_t dLen); - -/* Public interface routines */ - -/* Allocate a new compressor */ -CompressorState * -AllocateCompressor(const pg_compress_specification compression_spec, - WriteFunc writeF) -{ - CompressorState *cs; - -#ifndef HAVE_LIBZ - if (compression_spec.algorithm == PG_COMPRESSION_GZIP) - pg_fatal("this build does not support compression with %s", "gzip"); -#endif - - cs = (CompressorState *) pg_malloc0(sizeof(CompressorState)); - cs->writeF = writeF; - cs->compression_spec = compression_spec; - - /* - * Perform compression algorithm specific initialization. - */ -#ifdef HAVE_LIBZ - if (cs->compression_spec.algorithm == PG_COMPRESSION_GZIP) - InitCompressorZlib(cs, cs->compression_spec.level); -#endif - - return cs; -} - -/* - * Read all compressed data from the input stream (via readF) and print it - * out with ahwrite(). - */ -void -ReadDataFromArchive(ArchiveHandle *AH, - const pg_compress_specification compression_spec, - ReadFunc readF) -{ - if (compression_spec.algorithm == PG_COMPRESSION_NONE) - ReadDataFromArchiveNone(AH, readF); - if (compression_spec.algorithm == PG_COMPRESSION_GZIP) - { -#ifdef HAVE_LIBZ - ReadDataFromArchiveZlib(AH, readF); -#else - pg_fatal("this build does not support compression with %s", "gzip"); -#endif - } -} - -/* - * Compress and write data to the output stream (via writeF). - */ -void -WriteDataToArchive(ArchiveHandle *AH, CompressorState *cs, - const void *data, size_t dLen) -{ - switch (cs->compression_spec.algorithm) - { - case PG_COMPRESSION_GZIP: -#ifdef HAVE_LIBZ - WriteDataToArchiveZlib(AH, cs, data, dLen); -#else - pg_fatal("this build does not support compression with %s", "gzip"); -#endif - break; - case PG_COMPRESSION_NONE: - WriteDataToArchiveNone(AH, cs, data, dLen); - break; - case PG_COMPRESSION_LZ4: - /* fallthrough */ - case PG_COMPRESSION_ZSTD: - pg_fatal("invalid compression method"); - break; - } -} - -/* - * Terminate compression library context and flush its buffers. - */ -void -EndCompressor(ArchiveHandle *AH, CompressorState *cs) -{ -#ifdef HAVE_LIBZ - if (cs->compression_spec.algorithm == PG_COMPRESSION_GZIP) - EndCompressorZlib(AH, cs); -#endif - free(cs); -} + void *outbuf; + size_t outsize; +} GzipCompressorState; -/* Private routines, specific to each compression method. */ -#ifdef HAVE_LIBZ -/* - * Functions for zlib compressed output. - */ +/* Private routines that support gzip compressed data I/O */ +static void DeflateCompressorInit(CompressorState *cs); +static void DeflateCompressorEnd(ArchiveHandle *AH, CompressorState *cs); +static void DeflateCompressorCommon(ArchiveHandle *AH, CompressorState *cs, + bool flush); +static void EndCompressorGzip(ArchiveHandle *AH, CompressorState *cs); +static void WriteDataToArchiveGzip(ArchiveHandle *AH, CompressorState *cs, + const void *data, size_t dLen); +static void ReadDataFromArchiveGzip(ArchiveHandle *AH, CompressorState *cs); static void -InitCompressorZlib(CompressorState *cs, int level) +DeflateCompressorInit(CompressorState *cs) { + GzipCompressorState *gzipcs; z_streamp zp; - zp = cs->zp = (z_streamp) pg_malloc(sizeof(z_stream)); + gzipcs = (GzipCompressorState *) pg_malloc0(sizeof(GzipCompressorState)); + zp = gzipcs->zp = (z_streamp) pg_malloc(sizeof(z_stream)); zp->zalloc = Z_NULL; zp->zfree = Z_NULL; zp->opaque = Z_NULL; /* - * zlibOutSize is the buffer size we tell zlib it can output to. We - * actually allocate one extra byte because some routines want to append a - * trailing zero byte to the zlib output. + * outsize is the buffer size we tell zlib it can output to. We actually + * allocate one extra byte because some routines want to append a trailing + * zero byte to the zlib output. */ - cs->zlibOut = (char *) pg_malloc(ZLIB_OUT_SIZE + 1); - cs->zlibOutSize = ZLIB_OUT_SIZE; + gzipcs->outbuf = pg_malloc(ZLIB_OUT_SIZE + 1); + gzipcs->outsize = ZLIB_OUT_SIZE; - if (deflateInit(zp, level) != Z_OK) - pg_fatal("could not initialize compression library: %s", - zp->msg); + /* -Z 0 uses the "None" compressor -- not zlib with no compression */ + Assert(cs->compression_spec.level != 0); + + if (deflateInit(zp, cs->compression_spec.level) != Z_OK) + pg_fatal("could not initialize compression library: %s", zp->msg); /* Just be paranoid - maybe End is called after Start, with no Write */ - zp->next_out = (void *) cs->zlibOut; - zp->avail_out = cs->zlibOutSize; + zp->next_out = gzipcs->outbuf; + zp->avail_out = gzipcs->outsize; + + /* Keep track of gzipcs */ + cs->private_data = gzipcs; } static void -EndCompressorZlib(ArchiveHandle *AH, CompressorState *cs) +DeflateCompressorEnd(ArchiveHandle *AH, CompressorState *cs) { - z_streamp zp = cs->zp; + GzipCompressorState *gzipcs = (GzipCompressorState *) cs->private_data; + z_streamp zp; + zp = gzipcs->zp; zp->next_in = NULL; zp->avail_in = 0; /* Flush any remaining data from zlib buffer */ - DeflateCompressorZlib(AH, cs, true); + DeflateCompressorCommon(AH, cs, true); if (deflateEnd(zp) != Z_OK) pg_fatal("could not close compression stream: %s", zp->msg); - free(cs->zlibOut); - free(cs->zp); + pg_free(gzipcs->outbuf); + pg_free(gzipcs->zp); + pg_free(gzipcs); + cs->private_data = NULL; } static void -DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs, bool flush) +DeflateCompressorCommon(ArchiveHandle *AH, CompressorState *cs, bool flush) { - z_streamp zp = cs->zp; - char *out = cs->zlibOut; + GzipCompressorState *gzipcs = (GzipCompressorState *) cs->private_data; + z_streamp zp = gzipcs->zp; + void *out = gzipcs->outbuf; int res = Z_OK; - while (cs->zp->avail_in != 0 || flush) + while (gzipcs->zp->avail_in != 0 || flush) { res = deflate(zp, flush ? Z_FINISH : Z_NO_FLUSH); if (res == Z_STREAM_ERROR) pg_fatal("could not compress data: %s", zp->msg); - if ((flush && (zp->avail_out < cs->zlibOutSize)) + if ((flush && (zp->avail_out < gzipcs->outsize)) || (zp->avail_out == 0) || (zp->avail_in != 0) ) @@ -289,18 +122,18 @@ DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs, bool flush) * chunk is the EOF marker in the custom format. This should never * happen but ... */ - if (zp->avail_out < cs->zlibOutSize) + if (zp->avail_out < gzipcs->outsize) { /* * Any write function should do its own error checking but to * make sure we do a check here as well ... */ - size_t len = cs->zlibOutSize - zp->avail_out; + size_t len = gzipcs->outsize - zp->avail_out; - cs->writeF(AH, out, len); + cs->writeF(AH, (char *) out, len); } - zp->next_out = (void *) out; - zp->avail_out = cs->zlibOutSize; + zp->next_out = out; + zp->avail_out = gzipcs->outsize; } if (res == Z_STREAM_END) @@ -309,16 +142,26 @@ DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs, bool flush) } static void -WriteDataToArchiveZlib(ArchiveHandle *AH, CompressorState *cs, - const char *data, size_t dLen) +EndCompressorGzip(ArchiveHandle *AH, CompressorState *cs) { - cs->zp->next_in = (void *) unconstify(char *, data); - cs->zp->avail_in = dLen; - DeflateCompressorZlib(AH, cs, false); + /* If deflation was initialized, finalize it */ + if (cs->private_data) + DeflateCompressorEnd(AH, cs); } static void -ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF) +WriteDataToArchiveGzip(ArchiveHandle *AH, CompressorState *cs, + const void *data, size_t dLen) +{ + GzipCompressorState *gzipcs = (GzipCompressorState *) cs->private_data; + + gzipcs->zp->next_in = (void *) unconstify(void *, data); + gzipcs->zp->avail_in = dLen; + DeflateCompressorCommon(AH, cs, false); +} + +static void +ReadDataFromArchiveGzip(ArchiveHandle *AH, CompressorState *cs) { z_streamp zp; char *out; @@ -342,7 +185,7 @@ ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF) zp->msg); /* no minimal chunk size for zlib */ - while ((cnt = readF(AH, &buf, &buflen))) + while ((cnt = cs->readF(AH, &buf, &buflen))) { zp->next_in = (void *) buf; zp->avail_in = cnt; @@ -382,389 +225,196 @@ ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF) free(out); free(zp); } -#endif /* HAVE_LIBZ */ - -/* - * Functions for uncompressed output. - */ - -static void -ReadDataFromArchiveNone(ArchiveHandle *AH, ReadFunc readF) -{ - size_t cnt; - char *buf; - size_t buflen; - - buf = pg_malloc(ZLIB_OUT_SIZE); - buflen = ZLIB_OUT_SIZE; - - while ((cnt = readF(AH, &buf, &buflen))) +/* Public routines that support gzip compressed data I/O */ +void +InitCompressorGzip(CompressorState *cs, + const pg_compress_specification compression_spec) { - ahwrite(buf, 1, cnt, AH); - } + cs->readData = ReadDataFromArchiveGzip; + cs->writeData = WriteDataToArchiveGzip; + cs->end = EndCompressorGzip; - free(buf); -} + cs->compression_spec = compression_spec; -static void -WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs, - const char *data, size_t dLen) -{ - cs->writeF(AH, data, dLen); + /* + * If the caller has defined a write function, prepare the necessary + * state. Note that if the data is empty, End may be called immediately + * after Init, without ever calling Write. + */ + if (cs->writeF) + DeflateCompressorInit(cs); } /*---------------------- - * Compressed stream API + * Compress File API *---------------------- */ -/* - * cfp represents an open stream, wrapping the underlying FILE or gzFile - * pointer. This is opaque to the callers. - */ -struct cfp +static size_t +Gzip_read(void *ptr, size_t size, CompressFileHandle *CFH) { - FILE *uncompressedfp; -#ifdef HAVE_LIBZ - gzFile compressedfp; -#endif -}; - -#ifdef HAVE_LIBZ -static int hasSuffix(const char *filename, const char *suffix); -#endif + gzFile gzfp = (gzFile) CFH->private_data; + size_t ret; -/* free() without changing errno; useful in several places below */ -static void -free_keep_errno(void *p) -{ - int save_errno = errno; - - free(p); - errno = save_errno; -} - -/* - * Open a file for reading. 'path' is the file to open, and 'mode' should - * be either "r" or "rb". - * - * If the file at 'path' does not exist, we append the ".gz" suffix (if 'path' - * doesn't already have it) and try again. So if you pass "foo" as 'path', - * this will open either "foo" or "foo.gz". - * - * On failure, return NULL with an error code in errno. - */ -cfp * -cfopen_read(const char *path, const char *mode) + ret = gzread(gzfp, ptr, size); + if (ret != size && !gzeof(gzfp)) { - cfp *fp; - - pg_compress_specification compression_spec = {0}; + int errnum; + const char *errmsg = gzerror(gzfp, &errnum); -#ifdef HAVE_LIBZ - if (hasSuffix(path, ".gz")) - { - compression_spec.algorithm = PG_COMPRESSION_GZIP; - fp = cfopen(path, mode, compression_spec); + pg_fatal("could not read from input file: %s", + errnum == Z_ERRNO ? strerror(errno) : errmsg); } - else -#endif - { - compression_spec.algorithm = PG_COMPRESSION_NONE; - fp = cfopen(path, mode, compression_spec); -#ifdef HAVE_LIBZ - if (fp == NULL) - { - char *fname; - fname = psprintf("%s.gz", path); - compression_spec.algorithm = PG_COMPRESSION_GZIP; - fp = cfopen(fname, mode, compression_spec); - free_keep_errno(fname); - } -#endif - } - return fp; + return ret; } -/* - * Open a file for writing. 'path' indicates the path name, and 'mode' must - * be a filemode as accepted by fopen() and gzopen() that indicates writing - * ("w", "wb", "a", or "ab"). - * - * If 'compression_spec.algorithm' is GZIP, a gzip compressed stream is opened, - * and 'compression_spec.level' used. The ".gz" suffix is automatically added to - * 'path' in that case. - * - * On failure, return NULL with an error code in errno. - */ -cfp * -cfopen_write(const char *path, const char *mode, - const pg_compress_specification compression_spec) +static size_t +Gzip_write(const void *ptr, size_t size, CompressFileHandle *CFH) { - cfp *fp; - - if (compression_spec.algorithm == PG_COMPRESSION_NONE) - fp = cfopen(path, mode, compression_spec); - else - { -#ifdef HAVE_LIBZ - char *fname; + gzFile gzfp = (gzFile) CFH->private_data; - fname = psprintf("%s.gz", path); - fp = cfopen(fname, mode, compression_spec); - free_keep_errno(fname); -#else - pg_fatal("this build does not support compression with %s", "gzip"); - fp = NULL; /* keep compiler quiet */ -#endif + return gzwrite(gzfp, ptr, size); } - return fp; -} - -/* - * This is the workhorse for cfopen() or cfdopen(). It opens file 'path' or - * associates a stream 'fd', if 'fd' is a valid descriptor, in 'mode'. The - * descriptor is not dup'ed and it is the caller's responsibility to do so. - * The caller must verify that the 'compress_algorithm' is supported by the - * current build. - * - * On failure, return NULL with an error code in errno. - */ -static cfp * -cfopen_internal(const char *path, int fd, const char *mode, - pg_compress_specification compression_spec) -{ - cfp *fp = pg_malloc0(sizeof(cfp)); - if (compression_spec.algorithm == PG_COMPRESSION_GZIP) - { -#ifdef HAVE_LIBZ - if (compression_spec.level != Z_DEFAULT_COMPRESSION) +static int +Gzip_getc(CompressFileHandle *CFH) { - /* user has specified a compression level, so tell zlib to use it */ - char mode_compression[32]; + gzFile gzfp = (gzFile) CFH->private_data; + int ret; - snprintf(mode_compression, sizeof(mode_compression), "%s%d", - mode, compression_spec.level); - if (fd >= 0) - fp->compressedfp = gzdopen(fd, mode_compression); - else - fp->compressedfp = gzopen(path, mode_compression); - } - else + errno = 0; + ret = gzgetc(gzfp); + if (ret == EOF) { - /* don't specify a level, just use the zlib default */ - if (fd >= 0) - fp->compressedfp = gzdopen(fd, mode); + if (!gzeof(gzfp)) + pg_fatal("could not read from input file: %s", strerror(errno)); else - fp->compressedfp = gzopen(path, mode); + pg_fatal("could not read from input file: end of file"); } - if (fp->compressedfp == NULL) - { - free_keep_errno(fp); - fp = NULL; - } -#else - pg_fatal("this build does not support compression with %s", "gzip"); -#endif + return ret; } - else - { - if (fd >= 0) - fp->uncompressedfp = fdopen(fd, mode); - else - fp->uncompressedfp = fopen(path, mode); - if (fp->uncompressedfp == NULL) +static char * +Gzip_gets(char *ptr, int size, CompressFileHandle *CFH) { - free_keep_errno(fp); - fp = NULL; - } - } + gzFile gzfp = (gzFile) CFH->private_data; - return fp; + return gzgets(gzfp, ptr, size); } -/* - * Opens file 'path' in 'mode' and compression as defined in - * compression_spec. The caller must verify that the compression - * is supported by the current build. - * - * On failure, return NULL with an error code in errno. - */ -cfp * -cfopen(const char *path, const char *mode, - const pg_compress_specification compression_spec) +static int +Gzip_close(CompressFileHandle *CFH) { - return cfopen_internal(path, -1, mode, compression_spec); -} + gzFile gzfp = (gzFile) CFH->private_data; -/* - * Associates a stream 'fd', if 'fd' is a valid descriptor, in 'mode' - * and compression as defined in compression_spec. The caller must - * verify that the compression is supported by the current build. - * - * On failure, return NULL with an error code in errno. - */ -cfp * -cfdopen(int fd, const char *mode, - const pg_compress_specification compression_spec) -{ - return cfopen_internal(NULL, fd, mode, compression_spec); + CFH->private_data = NULL; + + return gzclose(gzfp); } -int -cfread(void *ptr, int size, cfp *fp) +static int +Gzip_eof(CompressFileHandle *CFH) { - int ret; + gzFile gzfp = (gzFile) CFH->private_data; - if (size == 0) - return 0; + return gzeof(gzfp); +} -#ifdef HAVE_LIBZ - if (fp->compressedfp) - { - ret = gzread(fp->compressedfp, ptr, size); - if (ret != size && !gzeof(fp->compressedfp)) +static const char * +Gzip_get_error(CompressFileHandle *CFH) { + gzFile gzfp = (gzFile) CFH->private_data; + const char *errmsg; int errnum; - const char *errmsg = gzerror(fp->compressedfp, &errnum); - pg_fatal("could not read from input file: %s", - errnum == Z_ERRNO ? strerror(errno) : errmsg); - } - } - else -#endif - { - ret = fread(ptr, 1, size, fp->uncompressedfp); - if (ret != size && !feof(fp->uncompressedfp)) - READ_ERROR_EXIT(fp->uncompressedfp); - } - return ret; -} + errmsg = gzerror(gzfp, &errnum); + if (errnum == Z_ERRNO) + errmsg = strerror(errno); -int -cfwrite(const void *ptr, int size, cfp *fp) -{ -#ifdef HAVE_LIBZ - if (fp->compressedfp) - return gzwrite(fp->compressedfp, ptr, size); - else -#endif - return fwrite(ptr, 1, size, fp->uncompressedfp); + return errmsg; } -int -cfgetc(cfp *fp) +static int +Gzip_open(const char *path, int fd, const char *mode, CompressFileHandle *CFH) { - int ret; + gzFile gzfp; + char mode_compression[32]; -#ifdef HAVE_LIBZ - if (fp->compressedfp) - { - ret = gzgetc(fp->compressedfp); - if (ret == EOF) + if (CFH->compression_spec.level != Z_DEFAULT_COMPRESSION) { - if (!gzeof(fp->compressedfp)) - pg_fatal("could not read from input file: %s", strerror(errno)); - else - pg_fatal("could not read from input file: end of file"); - } + /* + * user has specified a compression level, so tell zlib to use it + */ + snprintf(mode_compression, sizeof(mode_compression), "%s%d", + mode, CFH->compression_spec.level); } else -#endif - { - ret = fgetc(fp->uncompressedfp); - if (ret == EOF) - READ_ERROR_EXIT(fp->uncompressedfp); - } - - return ret; -} + strcpy(mode_compression, mode); -char * -cfgets(cfp *fp, char *buf, int len) -{ -#ifdef HAVE_LIBZ - if (fp->compressedfp) - return gzgets(fp->compressedfp, buf, len); + if (fd >= 0) + gzfp = gzdopen(dup(fd), mode_compression); else -#endif - return fgets(buf, len, fp->uncompressedfp); -} + gzfp = gzopen(path, mode_compression); -int -cfclose(cfp *fp) -{ - int result; + if (gzfp == NULL) + return 1; - if (fp == NULL) - { - errno = EBADF; - return EOF; - } -#ifdef HAVE_LIBZ - if (fp->compressedfp) - { - result = gzclose(fp->compressedfp); - fp->compressedfp = NULL; - } - else -#endif - { - result = fclose(fp->uncompressedfp); - fp->uncompressedfp = NULL; - } - free_keep_errno(fp); + CFH->private_data = gzfp; - return result; + return 0; } -int -cfeof(cfp *fp) +static int +Gzip_open_write(const char *path, const char *mode, CompressFileHandle *CFH) { -#ifdef HAVE_LIBZ - if (fp->compressedfp) - return gzeof(fp->compressedfp); - else -#endif - return feof(fp->uncompressedfp); -} + char *fname; + int ret; + int save_errno; -const char * -get_cfp_error(cfp *fp) -{ -#ifdef HAVE_LIBZ - if (fp->compressedfp) - { - int errnum; - const char *errmsg = gzerror(fp->compressedfp, &errnum); + fname = psprintf("%s.gz", path); + ret = CFH->open_func(fname, -1, mode, CFH); - if (errnum != Z_ERRNO) - return errmsg; - } -#endif - return strerror(errno); + save_errno = errno; + pg_free(fname); + errno = save_errno; + + return ret; } -#ifdef HAVE_LIBZ -static int -hasSuffix(const char *filename, const char *suffix) +void +InitCompressFileHandleGzip(CompressFileHandle *CFH, + const pg_compress_specification compression_spec) { - int filenamelen = strlen(filename); - int suffixlen = strlen(suffix); + CFH->open_func = Gzip_open; + CFH->open_write_func = Gzip_open_write; + CFH->read_func = Gzip_read; + CFH->write_func = Gzip_write; + CFH->gets_func = Gzip_gets; + CFH->getc_func = Gzip_getc; + CFH->close_func = Gzip_close; + CFH->eof_func = Gzip_eof; + CFH->get_error_func = Gzip_get_error; - if (filenamelen < suffixlen) - return 0; + CFH->compression_spec = compression_spec; - return memcmp(&filename[filenamelen - suffixlen], - suffix, - suffixlen) == 0; + CFH->private_data = NULL; +} +#else /* HAVE_LIBZ */ +void +InitCompressorGzip(CompressorState *cs, + const pg_compress_specification compression_spec) +{ + pg_fatal("this build does not support compression with %s", "gzip"); } -#endif +void +InitCompressFileHandleGzip(CompressFileHandle *CFH, + const pg_compress_specification compression_spec) +{ + pg_fatal("this build does not support compression with %s", "gzip"); +} +#endif /* HAVE_LIBZ */