From b26d3fa15723ab38057276471942e79cf4c7789b Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryzbyj@telsasoft.com>
Date: Thu, 24 Dec 2020 22:08:43 -0600
Subject: [PATCH 04/20] struct compressLibs

---
 src/bin/pg_dump/compress_io.c         | 55 +++++++++++++++++++--------
 src/bin/pg_dump/compress_io.h         |  7 ++++
 src/bin/pg_dump/pg_backup_directory.c | 20 ++++++----
 src/bin/pg_dump/pg_dump.c             | 25 +++++++-----
 4 files changed, 75 insertions(+), 32 deletions(-)

diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c
index db16fd33f2..21957d68f3 100644
--- a/src/bin/pg_dump/compress_io.c
+++ b/src/bin/pg_dump/compress_io.c
@@ -56,6 +56,18 @@
 #include "compress_io.h"
 #include "pg_backup_utils.h"
 
+const struct compressLibs
+compresslibs[] = {
+	{ COMPR_ALG_NONE, "no", "", 0, },
+	{ COMPR_ALG_NONE, "none", "", 0, }, /* Alternate name */
+
+// #ifdef HAVE_LIBZ?
+	{ COMPR_ALG_LIBZ, "libz", ".gz", Z_DEFAULT_COMPRESSION },
+	{ COMPR_ALG_LIBZ, "zlib", ".gz", Z_DEFAULT_COMPRESSION }, /* Alternate name */
+
+	{ 0, NULL, } /* sentinel */
+};
+
 /*----------------------
  * Compressor API
  *----------------------
@@ -401,7 +413,7 @@ struct cfp
 #endif
 };
 
-static int	hasSuffix(const char *filename, const char *suffix);
+static int	hasSuffix(const char *filename);
 
 /* free() without changing errno; useful in several places below */
 static void
@@ -428,7 +440,7 @@ cfopen_read(const char *path, const char *mode, Compress *compression)
 {
 	cfp		   *fp;
 
-	if (hasSuffix(path, ".gz"))
+	if (hasSuffix(path))
 		fp = cfopen(path, mode, compression);
 	else
 	{
@@ -656,18 +668,29 @@ get_cfp_error(cfp *fp)
 	return strerror(errno);
 }
 
+/* Return true iff the filename has a known compression suffix */
 static int
-hasSuffix(const char *filename, const char *suffix)
+hasSuffix(const char *filename)
 {
-	int			filenamelen = strlen(filename);
-	int			suffixlen = strlen(suffix);
+	for (int i = 0; compresslibs[i].name != NULL; ++i)
+	{
+		const char	*suffix = compresslibs[i].suffix;
+		int			filenamelen = strlen(filename);
+		int			suffixlen = strlen(suffix);
 
-	if (filenamelen < suffixlen)
-		return 0;
+		/* COMPR_ALG_NONE has an empty "suffix", which doesn't count */
+		if (suffixlen == 0)
+			continue;
+
+		if (filenamelen < suffixlen)
+			continue;
 
-	return memcmp(&filename[filenamelen - suffixlen],
-				  suffix,
-				  suffixlen) == 0;
+		if (memcmp(&filename[filenamelen - suffixlen],
+					  suffix, suffixlen) == 0)
+			return true;
+	}
+
+	return false;
 }
 
 /*
@@ -677,11 +700,13 @@ hasSuffix(const char *filename, const char *suffix)
 const char *
 compress_suffix(Compress *compression)
 {
-	switch (compression->alg)
+	for (int i = 0; compresslibs[i].name != NULL; ++i)
 	{
-		case COMPR_ALG_LIBZ:
-			return ".gz";
-		default:
-			return "";
+		if (compression->alg != compresslibs[i].alg)
+			continue;
+
+		return compresslibs[i].suffix;
 	}
+
+	return "";
 }
diff --git a/src/bin/pg_dump/compress_io.h b/src/bin/pg_dump/compress_io.h
index 2c073676eb..fb9d659acc 100644
--- a/src/bin/pg_dump/compress_io.h
+++ b/src/bin/pg_dump/compress_io.h
@@ -47,6 +47,13 @@ extern void WriteDataToArchive(ArchiveHandle *AH, CompressorState *cs,
 							   const void *data, size_t dLen);
 extern void EndCompressor(ArchiveHandle *AH, CompressorState *cs);
 
+struct compressLibs {
+	const CompressionAlgorithm alg;
+	const char	*name;			/* Name in -Z alg= */
+	const char	*suffix;		/* file extension */
+	const int	defaultlevel;	/* Default compression level */
+};
+extern const struct compressLibs compresslibs[];
 
 typedef struct cfp cfp;
 
diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c
index 8bf869c6ca..75c1bf22e4 100644
--- a/src/bin/pg_dump/pg_backup_directory.c
+++ b/src/bin/pg_dump/pg_backup_directory.c
@@ -768,14 +768,20 @@ _PrepParallelRestore(ArchiveHandle *AH)
 		 */
 		setFilePath(AH, fname, tctx->filename);
 
-		if (stat(fname, &st) == 0)
-			te->dataLength = st.st_size;
-		else
+		for (int i = 0; compresslibs[i].name != NULL; ++i)
 		{
-			/* It might be compressed */
-			strlcat(fname, ".gz", sizeof(fname));
-			if (stat(fname, &st) == 0)
-				te->dataLength = st.st_size;
+			char	filename[MAXPGPATH];
+			int	ret;
+
+			snprintf(filename, sizeof(filename), "%s%s", fname,
+					compresslibs[i].suffix);
+
+			ret = stat(fname, &st);
+			if (ret < 0) // && errno == ENOENT)
+				continue;
+
+			te->dataLength = st.st_size;
+			break;
 		}
 
 		/*
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 4cbc79aedc..75985fd4d3 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -318,7 +318,7 @@ parse_compression(const char *optarg, Compress *compress)
 	}
 	else
 	{
-		/* Parse a more flexible string like level=3 alg=zlib opts=long */
+		/* Parse a more flexible string like -Z level=3 -Z alg=zlib -Z checksum=1 */
 		for (;;)
 		{
 			char *eq = strchr(optarg, '=');
@@ -333,14 +333,19 @@ parse_compression(const char *optarg, Compress *compress)
 			len = eq - optarg;
 			if (strncmp(optarg, "alg", len) == 0)
 			{
-				if (strchr(eq, ' '))
-					len = strchr(eq, ' ') - eq - 1;
-				else
-					len = strlen(eq) - len;
-				if (strncmp(1+eq, "zlib", len) == 0 ||
-						strncmp(1+eq, "libz", len) == 0)
-					compress->alg = COMPR_ALG_LIBZ;
-				else
+				len = strlen(eq) - len;
+
+				for (int i = 0; compresslibs[i].name != NULL; ++i)
+				{
+					if (strlen(1+eq) != strlen(compresslibs[i].name))
+						continue;
+					if (strncmp(1+eq, compresslibs[i].name, len) != 0)
+						continue;
+					compress->alg = compresslibs[i].alg;
+					break;
+				}
+
+				if (compress->alg == COMPR_ALG_DEFAULT)
 				{
 					pg_log_error("unknown compression algorithm: %s", 1+eq);
 					exit_nicely(1);
@@ -363,7 +368,7 @@ parse_compression(const char *optarg, Compress *compress)
 		}
 
 		if (!compress->level_set)
-		{
+		{ // XXX
 			const int default_compress_level[] = {
 				0,			/* COMPR_ALG_NONE */
 				Z_DEFAULT_COMPRESSION,	/* COMPR_ALG_ZLIB */
-- 
2.17.0

