aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pg_dump/compress_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/pg_dump/compress_io.c')
-rw-r--r--src/bin/pg_dump/compress_io.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c
index 8c41a690438..fb280ab672f 100644
--- a/src/bin/pg_dump/compress_io.c
+++ b/src/bin/pg_dump/compress_io.c
@@ -7,6 +7,17 @@
* Portions Copyright (c) 1996-2011, 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
@@ -23,6 +34,17 @@
*
* 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
@@ -32,6 +54,10 @@
#include "compress_io.h"
+/*----------------------
+ * Compressor API
+ *----------------------
+ */
/* typedef appears in compress_io.h */
struct CompressorState
@@ -418,3 +444,234 @@ WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs,
}
+/*----------------------
+ * Compressed stream API
+ *----------------------
+ */
+
+/*
+ * cfp represents an open stream, wrapping the underlying FILE or gzFile
+ * pointer. This is opaque to the callers.
+ */
+struct cfp
+{
+ FILE *uncompressedfp;
+#ifdef HAVE_LIBZ
+ gzFile compressedfp;
+#endif
+};
+
+#ifdef HAVE_LIBZ
+static int hasSuffix(const char *filename, const char *suffix);
+#endif
+
+/*
+ * 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".
+ */
+cfp *
+cfopen_read(const char *path, const char *mode)
+{
+ cfp *fp;
+
+#ifdef HAVE_LIBZ
+ if (hasSuffix(path, ".gz"))
+ fp = cfopen(path, mode, 1);
+ else
+#endif
+ {
+ fp = cfopen(path, mode, 0);
+#ifdef HAVE_LIBZ
+ if (fp == NULL)
+ {
+ int fnamelen = strlen(path) + 4;
+ char *fname = malloc(fnamelen);
+ if (fname == NULL)
+ die_horribly(NULL, modulename, "Out of memory\n");
+
+ snprintf(fname, fnamelen, "%s%s", path, ".gz");
+ fp = cfopen(fname, mode, 1);
+ free(fname);
+ }
+#endif
+ }
+ return fp;
+}
+
+/*
+ * 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' is non-zero, a gzip compressed stream is opened, and
+ * and 'compression' indicates the compression level used. The ".gz" suffix
+ * is automatically added to 'path' in that case.
+ */
+cfp *
+cfopen_write(const char *path, const char *mode, int compression)
+{
+ cfp *fp;
+
+ if (compression == 0)
+ fp = cfopen(path, mode, 0);
+ else
+ {
+#ifdef HAVE_LIBZ
+ int fnamelen = strlen(path) + 4;
+ char *fname = malloc(fnamelen);
+ if (fname == NULL)
+ die_horribly(NULL, modulename, "Out of memory\n");
+
+ snprintf(fname, fnamelen, "%s%s", path, ".gz");
+ fp = cfopen(fname, mode, 1);
+ free(fname);
+#else
+ die_horribly(NULL, modulename, "not built with zlib support\n");
+#endif
+ }
+ return fp;
+}
+
+/*
+ * Opens file 'path' in 'mode'. If 'compression' is non-zero, the file
+ * is opened with libz gzopen(), otherwise with plain fopen()
+ */
+cfp *
+cfopen(const char *path, const char *mode, int compression)
+{
+ cfp *fp = malloc(sizeof(cfp));
+ if (fp == NULL)
+ die_horribly(NULL, modulename, "Out of memory\n");
+
+ if (compression != 0)
+ {
+#ifdef HAVE_LIBZ
+ fp->compressedfp = gzopen(path, mode);
+ fp->uncompressedfp = NULL;
+ if (fp->compressedfp == NULL)
+ {
+ free(fp);
+ fp = NULL;
+ }
+#else
+ die_horribly(NULL, modulename, "not built with zlib support\n");
+#endif
+ }
+ else
+ {
+#ifdef HAVE_LIBZ
+ fp->compressedfp = NULL;
+#endif
+ fp->uncompressedfp = fopen(path, mode);
+ if (fp->uncompressedfp == NULL)
+ {
+ free(fp);
+ fp = NULL;
+ }
+ }
+
+ return fp;
+}
+
+
+int
+cfread(void *ptr, int size, cfp *fp)
+{
+#ifdef HAVE_LIBZ
+ if (fp->compressedfp)
+ return gzread(fp->compressedfp, ptr, size);
+ else
+#endif
+ return fread(ptr, 1, size, fp->uncompressedfp);
+}
+
+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);
+}
+
+int
+cfgetc(cfp *fp)
+{
+#ifdef HAVE_LIBZ
+ if (fp->compressedfp)
+ return gzgetc(fp->compressedfp);
+ else
+#endif
+ return fgetc(fp->uncompressedfp);
+}
+
+char *
+cfgets(cfp *fp, char *buf, int len)
+{
+#ifdef HAVE_LIBZ
+ if (fp->compressedfp)
+ return gzgets(fp->compressedfp, buf, len);
+ else
+#endif
+ return fgets(buf, len, fp->uncompressedfp);
+}
+
+int
+cfclose(cfp *fp)
+{
+ int result;
+
+ 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(fp);
+
+ return result;
+}
+
+int
+cfeof(cfp *fp)
+{
+#ifdef HAVE_LIBZ
+ if (fp->compressedfp)
+ return gzeof(fp->compressedfp);
+ else
+#endif
+ return feof(fp->uncompressedfp);
+}
+
+#ifdef HAVE_LIBZ
+static int
+hasSuffix(const char *filename, const char *suffix)
+{
+ int filenamelen = strlen(filename);
+ int suffixlen = strlen(suffix);
+
+ if (filenamelen < suffixlen)
+ return 0;
+
+ return memcmp(&filename[filenamelen - suffixlen],
+ suffix,
+ suffixlen) == 0;
+}
+#endif