From 86fb08d25c74e8f4c3bcdeb8b0ac75e5de8ccd95 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Wed, 22 Jul 2026 11:57:46 -0400
Subject: [PATCH v1] Undo inadvertent loosening of archive filename checking.

Commit c8a350a439826267186c187dbfbf1f839f7521aa attempted to consolidate
code for identify possibly-compressed tar archives by suffix into a new
function parse_tar_compress_algorithm(). Unfortunately, the refactoring
wasn't perfect, and slightly changed the behavior at both existing call
sites.

In CreateBackupStreamer(), the previous code required the filename to
consist of more than just a suffix, so the aforementioned commit had the
effect of allowing pg_basebackup to accept a file from the server whose
entire name was something like .tar.gz -- which should never happen, but
let's reject it as previous releases did.

In precheck_tar_backup_file(), the previous code required the suffix to
be immediately adjacent to the prefix already checked, so the commit
in question allowed pg_verifybackup to accept not only filenames like
base.tar.gz but also filenames like baseFOOBARBAZ.tar.gz. While such
filenames are perhaps unlikely, rejecting them is correct, so let's go
back to that behavior.
---
 src/bin/pg_basebackup/pg_basebackup.c     |  4 ++--
 src/bin/pg_verifybackup/pg_verifybackup.c |  2 +-
 src/bin/pg_waldump/pg_waldump.c           |  5 ++--
 src/common/compression.c                  | 28 +++++++++++++++++------
 src/include/common/compression.h          |  2 +-
 5 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 8a599fc9869..12fc752bff5 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -1083,8 +1083,8 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
 	inject_manifest = (format == 't' && strcmp(basedir, "-") == 0 && manifest);
 
 	/* Check whether it is a tar archive and its compression type */
-	is_tar = parse_tar_compress_algorithm(archive_name,
-										  &compressed_tar_algorithm);
+	is_tar = (parse_tar_compress_algorithm(archive_name,
+										   &compressed_tar_algorithm) > 0);
 
 	/* Is this any kind of compressed tar? */
 	is_compressed_tar = (is_tar &&
diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c
index 05385a91e88..90a3625130d 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.c
+++ b/src/bin/pg_verifybackup/pg_verifybackup.c
@@ -972,7 +972,7 @@ precheck_tar_backup_file(verifier_context *context, char *relpath,
 	}
 
 	/* Now, check the compression type of the tar */
-	if (!parse_tar_compress_algorithm(suffix, &compress_algorithm))
+	if (parse_tar_compress_algorithm(suffix, &compress_algorithm) != 0)
 	{
 		report_backup_error(context,
 							"file \"%s\" is not expected in a tar format backup",
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index cf760d8b236..ffe6e8a6bca 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -1242,7 +1242,7 @@ main(int argc, char **argv)
 	if (waldir != NULL)
 	{
 		/* Check whether the path looks like a tar archive by its extension */
-		if (parse_tar_compress_algorithm(waldir, &compression))
+		if (parse_tar_compress_algorithm(waldir, &compression) >= 0)
 		{
 			split_path(waldir, &private.archive_dir, &private.archive_name);
 		}
@@ -1286,7 +1286,8 @@ main(int argc, char **argv)
 				pg_fatal("could not open directory \"%s\": %m", waldir);
 		}
 
-		if (fname != NULL && parse_tar_compress_algorithm(fname, &compression))
+		if (fname != NULL &&
+			parse_tar_compress_algorithm(fname, &compression) >= 0)
 		{
 			private.archive_dir = waldir;
 			private.archive_name = fname;
diff --git a/src/common/compression.c b/src/common/compression.c
index ae2089d9406..e78913ad9dc 100644
--- a/src/common/compression.c
+++ b/src/common/compression.c
@@ -42,33 +42,47 @@ static bool expect_boolean_value(char *keyword, char *value,
 								 pg_compress_specification *result);
 
 /*
- * Look up a compression algorithm by archive file extension. Returns true and
- * sets *algorithm if the extension is recognized. Otherwise returns false.
+ * Look up a compression algorithm by archive file extension. Sets *algorithm
+ * and returns the length of the non-extension portion of the filename, or -1
+ * if the filename does not end with a recognized tar extension.
  */
-bool
+int
 parse_tar_compress_algorithm(const char *fname, pg_compress_algorithm *algorithm)
 {
-	size_t		fname_len = strlen(fname);
+	int			fname_len = strlen(fname);
 
 	if (fname_len >= 4 &&
 		strcmp(fname + fname_len - 4, ".tar") == 0)
+	{
 		*algorithm = PG_COMPRESSION_NONE;
+		return fname_len - 4;
+	}
 	else if (fname_len >= 4 &&
 			 strcmp(fname + fname_len - 4, ".tgz") == 0)
+	{
 		*algorithm = PG_COMPRESSION_GZIP;
+		return fname_len - 4;
+	}
 	else if (fname_len >= 7 &&
 			 strcmp(fname + fname_len - 7, ".tar.gz") == 0)
+	{
 		*algorithm = PG_COMPRESSION_GZIP;
+		return fname_len - 7;
+	}
 	else if (fname_len >= 8 &&
 			 strcmp(fname + fname_len - 8, ".tar.lz4") == 0)
+	{
 		*algorithm = PG_COMPRESSION_LZ4;
+		return fname_len - 8;
+	}
 	else if (fname_len >= 8 &&
 			 strcmp(fname + fname_len - 8, ".tar.zst") == 0)
+	{
 		*algorithm = PG_COMPRESSION_ZSTD;
-	else
-		return false;
+		return fname_len - 8;
+	}
 
-	return true;
+	return -1;
 }
 
 /*
diff --git a/src/include/common/compression.h b/src/include/common/compression.h
index f99c747cdd3..adbe668a105 100644
--- a/src/include/common/compression.h
+++ b/src/include/common/compression.h
@@ -41,7 +41,7 @@ typedef struct pg_compress_specification
 
 extern void parse_compress_options(const char *option, char **algorithm,
 								   char **detail);
-extern bool parse_tar_compress_algorithm(const char *fname,
+extern int	parse_tar_compress_algorithm(const char *fname,
 										 pg_compress_algorithm *algorithm);
 extern bool parse_compress_algorithm(char *name, pg_compress_algorithm *algorithm);
 extern const char *get_compress_algorithm_name(pg_compress_algorithm algorithm);
-- 
2.50.1 (Apple Git-155)

