From d10e2eab346c34bf50b6be5865f8422159154371 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Tue, 12 Feb 2019 17:55:53 +1100
Subject: [PATCH] New pg_basebackup -g option to control the group access
 permissions

By default, pg_basebackup follows the backup file permissions
same as source instance, but with this option, user can control the
behavior.

--group-mode = inherit (default) (same permissions are source instance)
--group-mode = none (no group access permissions)
--group-mode = group (group access permissions)

The same applies to the database directory that is already present.

To support group access permissions for the tar mode, the
BASE BACKUP protocol is enhanced to support new option "GROUP_MODE"
with options "none" and "group". These options will be sent to the
server whenever user wants control the group access mode permissions
other than default.
---
 doc/src/sgml/protocol.sgml                   | 13 +++-
 doc/src/sgml/ref/pg_basebackup.sgml          | 48 ++++++++++++
 src/backend/replication/basebackup.c         | 46 +++++++++++
 src/backend/replication/repl_gram.y          |  8 +-
 src/backend/replication/repl_scanner.l       |  1 +
 src/bin/pg_basebackup/pg_basebackup.c        | 66 +++++++++++-----
 src/bin/pg_basebackup/streamutil.c           | 57 ++++++++------
 src/bin/pg_basebackup/streamutil.h           | 11 +++
 src/bin/pg_basebackup/t/010_pg_basebackup.pl | 82 +++++++++++++++++++-
 9 files changed, 288 insertions(+), 44 deletions(-)

diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index d66b860cbd..9437c42256 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -2397,7 +2397,7 @@ The commands accepted in replication mode are:
   </varlistentry>
 
   <varlistentry>
-    <term><literal>BASE_BACKUP</literal> [ <literal>LABEL</literal> <replaceable>'label'</replaceable> ] [ <literal>PROGRESS</literal> ] [ <literal>FAST</literal> ] [ <literal>WAL</literal> ] [ <literal>NOWAIT</literal> ] [ <literal>MAX_RATE</literal> <replaceable>rate</replaceable> ] [ <literal>TABLESPACE_MAP</literal> ] [ <literal>NOVERIFY_CHECKSUMS</literal> ]
+    <term><literal>BASE_BACKUP</literal> [ <literal>LABEL</literal> <replaceable>'label'</replaceable> ] [ <literal>PROGRESS</literal> ] [ <literal>FAST</literal> ] [ <literal>WAL</literal> ] [ <literal>NOWAIT</literal> ] [ <literal>MAX_RATE</literal> <replaceable>rate</replaceable> ] [ <literal>TABLESPACE_MAP</literal> ] [ <literal>NOVERIFY_CHECKSUMS</literal> ] [ <literal>GROUP_MODE</literal> <replaceable>'mode'</replaceable> ]
      <indexterm><primary>BASE_BACKUP</primary></indexterm>
     </term>
     <listitem>
@@ -2507,6 +2507,17 @@ The commands accepted in replication mode are:
          </para>
         </listitem>
        </varlistentry>
+       
+       <varlistentry>
+        <term><literal>GROUP_MODE</literal> <replaceable>'mode'</replaceable></term>
+        <listitem>
+         <para>
+          By default, the group access permissions will be same as source instance. If <literal>none</literal> is specified,
+          the backup files doesn't contains group access permissions. If <literal>group</literal> is specified, the backup
+          files should contains group access permissions.
+         </para>
+        </listitem>
+       </varlistentry>
       </variablelist>
      </para>
      <para>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index c4f3950e5b..6b7a81c900 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -535,6 +535,53 @@ PostgreSQL documentation
        </para>
       </listitem>
      </varlistentry>
+     
+     <varlistentry>
+      <term><option>-g <replaceable class="parameter">mode</replaceable></option></term>
+      <term><option>--group-mode=<replaceable class="parameter">mode</replaceable></option></term>
+      <listitem>
+       <para>
+        Controls the group permissions of the file in the backup. This option is ignored
+        on <productname>Windows</productname> as it does not support <acronym>POSIX</acronym>-style
+        group permissions. The following methods are available to control the group permissions:
+
+        <variablelist>
+         <varlistentry>
+          <term><literal>n</literal></term>
+          <term><literal>none</literal></term>
+          <listitem>
+           <para>
+            Don't include group access permissions in the backup.
+           </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+          <term><literal>i</literal></term>
+          <term><literal>inherit</literal></term>
+          <listitem>
+           <para>
+            Follow the same access permissions of the source instance.
+           </para>
+           <para>
+            This value is the default.
+           </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+          <term><literal>g</literal></term>
+          <term><literal>group</literal></term>
+          <listitem>
+           <para>
+            Include group access permissions for all the backup files.
+           </para>
+          </listitem>
+         </varlistentry>
+        </variablelist>
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
 
@@ -735,6 +782,7 @@ PostgreSQL documentation
    or an older major version, down to 9.1. However, WAL streaming mode (<literal>-X
    stream</literal>) only works with server version 9.3 and later, and tar format mode
    (<literal>--format=tar</literal>) of the current version only works with server version 9.5
+   or later. (<literal>-g</literal>) of the current version only works with server version 12
    or later.
   </para>
 
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 537f09e342..23b7a05489 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -54,6 +54,8 @@ typedef struct
 	bool		sendtblspcmapfile;
 } basebackup_options;
 
+static int	backup_dir_create_mode = 0;
+static int	backup_file_create_mode = 0;
 
 static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
 		List *tablespaces, bool sendtblspclinks);
@@ -650,6 +652,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_group_mode = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -738,6 +741,30 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "group_mode") == 0)
+		{
+			if (o_group_mode)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			if (strcmp(strVal(defel->arg), "none") == 0)
+			{
+				backup_dir_create_mode = PG_DIR_MODE_OWNER;
+				backup_file_create_mode = PG_FILE_MODE_OWNER;
+			}
+			else if (strcmp(strVal(defel->arg), "group") == 0)
+			{
+				backup_dir_create_mode = PG_DIR_MODE_GROUP;
+				backup_file_create_mode = PG_FILE_MODE_GROUP;
+			}
+			else
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("Invalid option for group_mode \"%s\"", defel->defname)));
+
+			o_group_mode = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -1602,6 +1629,25 @@ _tarWriteHeader(const char *filename, const char *linktarget,
 
 	if (!sizeonly)
 	{
+		/*
+		 * Adjust the mode of the file according to the backup request, ignore
+		 * it for tablespace links.
+		 */
+		if (!linktarget && backup_file_create_mode)
+		{
+			if (S_ISDIR(statbuf->st_mode))
+			{
+				statbuf->st_mode &= ~(pg_dir_create_mode);
+				statbuf->st_mode |= backup_dir_create_mode;
+			}
+			else
+			{
+				statbuf->st_mode &= ~(pg_file_create_mode);
+				statbuf->st_mode |= backup_file_create_mode;
+			}
+
+		}
+
 		rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
 							 statbuf->st_mode, statbuf->st_uid, statbuf->st_gid,
 							 statbuf->st_mtime);
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index c4e11cc4e8..44059e299b 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -78,6 +78,7 @@ static SQLCmd *make_sqlcmd(void);
 %token K_WAL
 %token K_TABLESPACE_MAP
 %token K_NOVERIFY_CHECKSUMS
+%token K_GROUP_MODE
 %token K_TIMELINE
 %token K_PHYSICAL
 %token K_LOGICAL
@@ -155,7 +156,7 @@ var_name:	IDENT	{ $$ = $1; }
 
 /*
  * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT]
- * [MAX_RATE %d] [TABLESPACE_MAP] [NOVERIFY_CHECKSUMS]
+ * [MAX_RATE %d] [TABLESPACE_MAP] [NOVERIFY_CHECKSUMS] [GROUP_MODE '<mode>']
  */
 base_backup:
 			K_BASE_BACKUP base_backup_opt_list
@@ -214,6 +215,11 @@ base_backup_opt:
 				  $$ = makeDefElem("noverify_checksums",
 								   (Node *)makeInteger(true), -1);
 				}
+			| K_GROUP_MODE SCONST
+				{
+				  $$ = makeDefElem("group_mode",
+								   (Node *)makeString($2), -1);
+				}
 			;
 
 create_replication_slot:
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 380faeb5f6..7d1fde67bd 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -93,6 +93,7 @@ MAX_RATE		{ return K_MAX_RATE; }
 WAL			{ return K_WAL; }
 TABLESPACE_MAP			{ return K_TABLESPACE_MAP; }
 NOVERIFY_CHECKSUMS	{ return K_NOVERIFY_CHECKSUMS; }
+GROUP_MODE	{ return K_GROUP_MODE; }
 TIMELINE			{ return K_TIMELINE; }
 START_REPLICATION	{ return K_START_REPLICATION; }
 CREATE_REPLICATION_SLOT		{ return K_CREATE_REPLICATION_SLOT; }
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 916371232b..746ea7ece4 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -367,6 +367,8 @@ usage(void)
 	printf(_("  -N, --no-sync          do not wait for changes to be written safely to disk\n"));
 	printf(_("  -P, --progress         show progress information\n"));
 	printf(_("  -S, --slot=SLOTNAME    replication slot to use\n"));
+	printf(_("  -g, --group-mode=inherit|group|none\n"
+			 "							specify required group access mode for basebackup directory\n"));
 	printf(_("  -v, --verbose          output verbose messages\n"));
 	printf(_("  -V, --version          output version information, then exit\n"));
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
@@ -706,6 +708,12 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 			/*
 			 * Exists, empty
 			 */
+			if (chmod(dirname, pg_dir_create_mode) != 0)
+			{
+				fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
+						progname, dirname, strerror(errno));
+				exit(1);
+			}
 			if (found)
 				*found = true;
 			return;
@@ -1498,7 +1506,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 
 		if (file == NULL)
 		{
-			int			filemode;
+			mode_t		oumask;
 
 			/*
 			 * No current file, so this must be the header for a new file
@@ -1513,9 +1521,6 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 
 			current_len_left = read_tar_number(&copybuf[124], 12);
 
-			/* Set permissions on the file */
-			filemode = read_tar_number(&copybuf[100], 8);
-
 			/*
 			 * All files are padded up to 512 bytes
 			 */
@@ -1560,12 +1565,6 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 							exit(1);
 						}
 					}
-#ifndef WIN32
-					if (chmod(filename, (mode_t) filemode))
-						fprintf(stderr,
-								_("%s: could not set permissions on directory \"%s\": %s\n"),
-								progname, filename, strerror(errno));
-#endif
 				}
 				else if (copybuf[156] == '2')
 				{
@@ -1606,7 +1605,9 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 			/*
 			 * regular file
 			 */
+			oumask = umask(pg_mode_mask);
 			file = fopen(filename, "wb");
+			umask(oumask);
 			if (!file)
 			{
 				fprintf(stderr, _("%s: could not create file \"%s\": %s\n"),
@@ -1614,12 +1615,6 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				exit(1);
 			}
 
-#ifndef WIN32
-			if (chmod(filename, (mode_t) filemode))
-				fprintf(stderr, _("%s: could not set permissions on file \"%s\": %s\n"),
-						progname, filename, strerror(errno));
-#endif
-
 			if (current_len_left == 0)
 			{
 				/*
@@ -1861,6 +1856,7 @@ BaseBackup(void)
 	char	   *basebkp;
 	char		escaped_label[MAXPGPATH];
 	char	   *maxrate_clause = NULL;
+	char	   *group_access_mode_clause = NULL;
 	int			i;
 	char		xlogstart[64];
 	char		xlogend[64];
@@ -1936,8 +1932,14 @@ BaseBackup(void)
 			fprintf(stderr, "\n");
 	}
 
+	/* Request server to send the file permissions according to the request */
+	if (group_access_mode == GROUP_ACCESS_NONE)
+		group_access_mode_clause = psprintf("GROUP_MODE '%s'", "none");
+	else if (group_access_mode == GROUP_ACCESS_PROVIDE)
+		group_access_mode_clause = psprintf("GROUP_MODE '%s'", "group");
+
 	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s %s",
 				 escaped_label,
 				 showprogress ? "PROGRESS" : "",
 				 includewal == FETCH_WAL ? "WAL" : "",
@@ -1945,7 +1947,8 @@ BaseBackup(void)
 				 includewal == NO_WAL ? "" : "NOWAIT",
 				 maxrate_clause ? maxrate_clause : "",
 				 format == 't' ? "TABLESPACE_MAP" : "",
-				 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+				 verify_checksums ? "" : "NOVERIFY_CHECKSUMS",
+				 group_access_mode_clause ? group_access_mode_clause : "");
 
 	if (PQsendQuery(conn, basebkp) == 0)
 	{
@@ -2278,6 +2281,7 @@ main(int argc, char **argv)
 		{"status-interval", required_argument, NULL, 's'},
 		{"verbose", no_argument, NULL, 'v'},
 		{"progress", no_argument, NULL, 'P'},
+		{"group-mode", required_argument, NULL, 'g'},
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
@@ -2307,7 +2311,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:g:h:p:U:s:wWkvP",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2449,6 +2453,30 @@ main(int argc, char **argv)
 			case 'P':
 				showprogress = true;
 				break;
+			case 'g':
+				if (strcmp(optarg, "i") == 0 ||
+					strcmp(optarg, "inherit") == 0)
+				{
+					group_access_mode = GROUP_ACCESS_INHERIT;
+				}
+				else if (strcmp(optarg, "g") == 0 ||
+						 strcmp(optarg, "group") == 0)
+				{
+					group_access_mode = GROUP_ACCESS_PROVIDE;
+				}
+				else if (strcmp(optarg, "n") == 0 ||
+						 strcmp(optarg, "none") == 0)
+				{
+					group_access_mode = GROUP_ACCESS_NONE;
+				}
+				else
+				{
+					fprintf(stderr,
+							_("%s: invalid group-mode option \"%s\", must be \"inherit\", \"group\", or \"none\"\n"),
+							progname, optarg);
+					exit(1);
+				}
+				break;
 			case 3:
 				verify_checksums = false;
 				break;
diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c
index 7e86830ad8..6b0bbff625 100644
--- a/src/bin/pg_basebackup/streamutil.c
+++ b/src/bin/pg_basebackup/streamutil.c
@@ -32,6 +32,7 @@
 #define ERRCODE_DUPLICATE_OBJECT  "42710"
 
 uint32		WalSegSz;
+GroupAccessMode group_access_mode = GROUP_ACCESS_INHERIT;
 
 static bool RetrieveDataDirCreatePerm(PGconn *conn);
 
@@ -371,37 +372,49 @@ RetrieveDataDirCreatePerm(PGconn *conn)
 	if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_GROUP_ACCESS)
 		return true;
 
-	res = PQexec(conn, "SHOW data_directory_mode");
-	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	if (group_access_mode == GROUP_ACCESS_INHERIT)
 	{
-		fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
-				progname, "SHOW data_directory_mode", PQerrorMessage(conn));
+		res = PQexec(conn, "SHOW data_directory_mode");
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
+					progname, "SHOW data_directory_mode", PQerrorMessage(conn));
+
+			PQclear(res);
+			return false;
+		}
+		if (PQntuples(res) != 1 || PQnfields(res) < 1)
+		{
+			fprintf(stderr,
+					_("%s: could not fetch group access flag: got %d rows and %d fields, expected %d rows and %d or more fields\n"),
+					progname, PQntuples(res), PQnfields(res), 1, 1);
+
+			PQclear(res);
+			return false;
+		}
+
+		if (sscanf(PQgetvalue(res, 0, 0), "%o", &data_directory_mode) != 1)
+		{
+			fprintf(stderr, _("%s: group access flag could not be parsed: %s\n"),
+					progname, PQgetvalue(res, 0, 0));
+
+			PQclear(res);
+			return false;
+		}
+
+		SetDataDirectoryCreatePerm(data_directory_mode);
 
 		PQclear(res);
-		return false;
 	}
-	if (PQntuples(res) != 1 || PQnfields(res) < 1)
+	else if (group_access_mode == GROUP_ACCESS_NONE)
 	{
-		fprintf(stderr,
-				_("%s: could not fetch group access flag: got %d rows and %d fields, expected %d rows and %d or more fields\n"),
-				progname, PQntuples(res), PQnfields(res), 1, 1);
-
-		PQclear(res);
-		return false;
+		SetDataDirectoryCreatePerm(PG_DIR_MODE_OWNER);
 	}
-
-	if (sscanf(PQgetvalue(res, 0, 0), "%o", &data_directory_mode) != 1)
+	else
 	{
-		fprintf(stderr, _("%s: group access flag could not be parsed: %s\n"),
-				progname, PQgetvalue(res, 0, 0));
-
-		PQclear(res);
-		return false;
+		SetDataDirectoryCreatePerm(PG_DIR_MODE_GROUP);
 	}
 
-	SetDataDirectoryCreatePerm(data_directory_mode);
-
-	PQclear(res);
 	return true;
 }
 
diff --git a/src/bin/pg_basebackup/streamutil.h b/src/bin/pg_basebackup/streamutil.h
index 2fa74e71bd..30b7408a9a 100644
--- a/src/bin/pg_basebackup/streamutil.h
+++ b/src/bin/pg_basebackup/streamutil.h
@@ -17,6 +17,16 @@
 #include "access/xlogdefs.h"
 #include "datatype/timestamp.h"
 
+/*
+ * Different ways to specify group access mode
+ */
+typedef enum
+{
+	GROUP_ACCESS_INHERIT = 0,
+	GROUP_ACCESS_PROVIDE,
+	GROUP_ACCESS_NONE
+}			GroupAccessMode;
+
 extern const char *progname;
 extern char *connection_string;
 extern char *dbhost;
@@ -25,6 +35,7 @@ extern char *dbport;
 extern char *dbname;
 extern int	dbgetpassword;
 extern uint32 WalSegSz;
+extern GroupAccessMode group_access_mode;
 
 /* Connection kept global so we can disconnect easily */
 extern PGconn *conn;
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 33869fecc9..868e461075 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -6,7 +6,7 @@ use File::Basename qw(basename dirname);
 use File::Path qw(rmtree);
 use PostgresNode;
 use TestLib;
-use Test::More tests => 106;
+use Test::More tests => 118;
 
 program_help_ok('pg_basebackup');
 program_version_ok('pg_basebackup');
@@ -402,6 +402,86 @@ $node->command_ok(
 	'pg_basebackup -X stream runs with --no-slot');
 rmtree("$tempdir/backupnoslot");
 
+# The following tests test backup unix file permissions. Windows doesn't support
+# unix file permissions, so skip on Windows.
+SKIP:
+{
+	skip "unix style file permissions are not supported on Windows", 18 if ($windows_os);
+
+	$node->stop;
+
+	# Set umask so test directories and files are created with default permissions
+	umask(0077);
+
+	# Enable no group permissions on PGDATA
+	chmod_recursive("$pgdata", 0700, 0600);
+
+	$node->start;
+	
+	$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupP", '-g', 'group' ],
+		'pg_basebackup -g group runs');
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backupP", 0750, 0640),
+		"check backup dir permissions");
+	rmtree("$tempdir/backupP");
+	
+	$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupP", '-g', 'inherit' ],
+		'pg_basebackup -g inherit runs');
+
+	# Group access should be not enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backupP", 0700, 0600),
+		"check backup dir permissions");
+	rmtree("$tempdir/backupP");
+
+	$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupP", '-g', 'group', '-Ft' ],
+		'pg_basebackup -g group in tar mode runs');
+
+	system_or_bail 'tar', '-xvf', "$tempdir/backupP/base.tar";
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backupP", 0750, 0640),
+		"check backup dir permissions");
+	rmtree("$tempdir/backupP");
+
+	
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable no group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	$node->start;
+	
+	$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupP", ],
+		'pg_basebackup default runs');
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backupP", 0750, 0640),
+		"check backup dir permissions");
+	rmtree("$tempdir/backupP");
+	
+	$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupP", '-g', 'none'],
+	'pg_basebackup -g none runs');
+
+	# Group access should be not enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backupP", 0700, 0600),
+		"check backup dir permissions");
+	rmtree("$tempdir/backupP");
+
+	$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupP", '-g', 'none', '-Ft' ],
+		'pg_basebackup -g none in tar mode runs');
+
+	system_or_bail 'tar', '-xvf', "$tempdir/backupP/base.tar";
+
+	# Group access should be not enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backupP", 0700, 0600),
+		"check backup dir permissions");
+	rmtree("$tempdir/backupP");
+}
+
 $node->command_fails(
 	[
 		'pg_basebackup',             '-D',
-- 
2.20.1.windows.1

