From b2de45f9200d9adcac50015521574696dc464ccd Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 11 Mar 2022 12:22:02 -0500 Subject: [PATCH] pg_basebackup: Avoid unclean failure with server-compression and -D -. Fail with a suitable error message instead. We can't inject the backup manifest into the output tarfile without decompressing it, and if we did that, we'd have to recompress the tarfile afterwards to produce the result the user is expecting. While we have enough infrastructure in pg_basebackup now to accomplish that whole series of steps without much additional code, it seems like excessively surprising behavior. The user probably did not select server-side compression with the idea that the client was going to end up decompressing it and then recompressing. Report from Justin Pryzby. Fix by me. Discussion: http://postgr.es/m/CA+Tgmob6Rnjz-Qv32h3yJn8nnUkLhrtQDAS4y5AtsgtorAFHRA@mail.gmail.com --- src/bin/pg_basebackup/pg_basebackup.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index 9f3ecc60fbe..43c4036eeed 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -1208,7 +1208,8 @@ CreateBackupStreamer(char *archive_name, char *spclocation, bool is_tar, is_tar_gz, is_tar_lz4, - is_tar_zstd; + is_tar_zstd, + is_compressed_tar; bool must_parse_archive; int archive_name_len = strlen(archive_name); @@ -1235,6 +1236,24 @@ CreateBackupStreamer(char *archive_name, char *spclocation, is_tar_zstd = (archive_name_len > 8 && strcmp(archive_name + archive_name_len - 4, ".zst") == 0); + /* Is this any kind of compressed tar? */ + is_compressed_tar = is_tar_gz || is_tar_lz4 || is_tar_zstd; + + /* + * Injecting the manifest into a compressed tar file would be possible if + * we decompressed it, parsed the tarfile, generated a new tarfile, and + * recompressed it, but compressing and decompressing multiple times just + * to inject the manifest seems inefficient enough that it's probably not + * what the user wants. So, instead, reject the request and tell the user + * to specify something more reasonable. + */ + if (inject_manifest && is_compressed_tar) + { + pg_log_error("cannot inject manifest into a compressed tarfile"); + pg_log_info("use client-side compression, send the output to a directory rather than standard output, or use --no-manifest"); + exit(1); + } + /* * We have to parse the archive if (1) we're suppose to extract it, or if * (2) we need to inject backup_manifest or recovery configuration into it. @@ -1244,8 +1263,7 @@ CreateBackupStreamer(char *archive_name, char *spclocation, (spclocation == NULL && writerecoveryconf)); /* At present, we only know how to parse tar archives. */ - if (must_parse_archive && !is_tar && !is_tar_gz && !is_tar_lz4 - && !is_tar_zstd) + if (must_parse_archive && !is_tar && !is_compressed_tar) { pg_log_error("unable to parse archive: %s", archive_name); pg_log_info("only tar archives can be parsed");