On 3/6/17 8:50 AM, Stephen Frost wrote:

> * Simon Riggs (si...@2ndquadrant.com) wrote:
>>> to allow the default mode of files and directories
>>> in the $PGDATA directory to be modified.
>>
>> Are you saying if this is changed all files/directories will be
>> changed to the new mode?
> 
> No, new files will be created with the new mode and existing files will
> be allowed to have the mode set.  Changing all of the existing files
> didn't seem like something we should be trying to do at server start.
> 
>> It seems like it would be annoying to have some files in one mode,
>> some in another.
> 
> It's not intended for that to happen, but it is possible for it to.  The
> alternative is to try and forcibly change all files at server start time
> to match what is configured but that didn't seem like a great idea.

Agreed.  It would definitely affect server start time, perhaps
significantly.

I have added a note to the docs that a change in file_mode_mask does not
automatically change the mode of existing files on disk.

This patch applies cleanly on 6f3a13f.

-- 
-David
da...@pgmasters.net
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c 
b/contrib/pg_stat_statements/pg_stat_statements.c
index 62dec87..98f8170 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1858,8 +1858,7 @@ qtext_store(const char *query, int query_len,
        *query_offset = off;
 
        /* Now write the data into the successfully-reserved part of the file */
-       fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY);
        if (fd < 0)
                goto error;
 
@@ -1923,7 +1922,7 @@ qtext_load_file(Size *buffer_size)
        int                     fd;
        struct stat stat;
 
-       fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY);
        if (fd < 0)
        {
                if (errno != ENOENT)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index cd82c04..6c84082 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -812,6 +812,44 @@ include_dir 'conf.d'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-file-mode-mask" xreflabel="file_mode_mask">
+      <term><varname>file_mode_mask</varname> (<type>integer</type>)
+      <indexterm>
+       <primary><varname>file_mode_mask</> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Sets the file mode mask (umask) for the data directory. The parameter
+        value is expected to be a numeric mode specified in the format
+        accepted by the <function>chmod</function> and
+        <function>umask</function> system calls. (To use the customary octal
+        format the number must start with a <literal>0</literal> (zero).)
+       </para>
+
+       <para>
+        The default <literal>file_mode_mask</literal> is 
<literal>0077</literal>,
+        meaning that the only the database owner can read and write files in
+        the data directory.  For example, setting the
+        <literal>file_mode_mask</literal> to <literal>0027</literal> would 
allow
+        any user in the same group as the database owner to read all database
+        files, which would be useful for producing a backup using a relatively
+        unprivileged user.
+       </para>
+
+       <para>
+         Note that changing this parameter does not automatically change the
+         mode of existing files in the cluster.  This must be done manually by
+         an administator.
+       </para>
+
+       <para>
+        This parameter can only be set at server start.
+       </para>
+
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-bonjour" xreflabel="bonjour">
       <term><varname>bonjour</varname> (<type>boolean</type>)
       <indexterm>
diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml
index 1aaa490..bd1f849 100644
--- a/doc/src/sgml/ref/initdb.sgml
+++ b/doc/src/sgml/ref/initdb.sgml
@@ -296,6 +296,25 @@ PostgreSQL documentation
      </varlistentry>
 
      <varlistentry>
+      <term><option>-u <replaceable 
class="parameter">mask</replaceable></option></term>
+      <term><option>--file-mode-mask=<replaceable 
class="parameter">mask</replaceable></option></term>
+      <listitem>
+       <para>
+        Sets the file mode mask (umask) for the data directory. The parameter
+        value is expected to be a numeric mode specified in the format
+        accepted by the <function>chmod</function> and
+        <function>umask</function> system calls. (To use the customary octal
+        format the number must start with a <literal>0</literal> (zero).)
+       </para>
+
+       <para>
+        Specifying this parameter will automatically set
+        <xref linkend="guc-file-mode-mask"> in <filename>postgresql.conf</>.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><option>-W</option></term>
       <term><option>--pwprompt</option></term>
       <listitem>
diff --git a/src/backend/access/heap/rewriteheap.c 
b/src/backend/access/heap/rewriteheap.c
index c7b283c..53a2acc 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -1010,8 +1010,7 @@ logical_rewrite_log_mapping(RewriteState state, 
TransactionId xid,
                src->off = 0;
                memcpy(src->path, path, sizeof(path));
                src->vfd = PathNameOpenFile(path,
-                                                                       O_CREAT 
| O_EXCL | O_WRONLY | PG_BINARY,
-                                                                       S_IRUSR 
| S_IWUSR);
+                                                                       O_CREAT 
| O_EXCL | O_WRONLY | PG_BINARY);
                if (src->vfd < 0)
                        ereport(ERROR,
                                        (errcode_for_file_access(),
@@ -1130,8 +1129,7 @@ heap_xlog_logical_rewrite(XLogReaderState *r)
                         xlrec->mapped_xid, XLogRecGetXid(r));
 
        fd = OpenTransientFile(path,
-                                                  O_CREAT | O_WRONLY | 
PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+                                                  O_CREAT | O_WRONLY | 
PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -1249,7 +1247,7 @@ CheckPointLogicalRewriteHeap(void)
                }
                else
                {
-                       int                     fd = OpenTransientFile(path, 
O_RDONLY | PG_BINARY, 0);
+                       int                     fd = OpenTransientFile(path, 
O_RDONLY | PG_BINARY);
 
                        /*
                         * The file cannot vanish due to concurrency since this 
function
diff --git a/src/backend/access/transam/slru.c 
b/src/backend/access/transam/slru.c
index a66ef5c..f385b79 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -594,7 +594,7 @@ SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno)
 
        SlruFileName(ctl, path, segno);
 
-       fd = OpenTransientFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
        if (fd < 0)
        {
                /* expected: file doesn't exist */
@@ -649,7 +649,7 @@ SlruPhysicalReadPage(SlruCtl ctl, int pageno, int slotno)
         * SlruPhysicalWritePage).  Hence, if we are InRecovery, allow the case
         * where the file doesn't exist, and return zeroes instead.
         */
-       fd = OpenTransientFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
        if (fd < 0)
        {
                if (errno != ENOENT || !InRecovery)
@@ -796,8 +796,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, 
SlruFlush fdata)
                 * don't use O_EXCL or O_TRUNC or anything like that.
                 */
                SlruFileName(ctl, path, segno);
-               fd = OpenTransientFile(path, O_RDWR | O_CREAT | PG_BINARY,
-                                                          S_IRUSR | S_IWUSR);
+               fd = OpenTransientFile(path, O_RDWR | O_CREAT | PG_BINARY);
                if (fd < 0)
                {
                        slru_errcause = SLRU_OPEN_FAILED;
diff --git a/src/backend/access/transam/timeline.c 
b/src/backend/access/transam/timeline.c
index 1fdc591..baa766a 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -306,8 +306,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID 
parentTLI,
        unlink(tmppath);
 
        /* do not use get_sync_bit() here --- want to fsync only at end of fill 
*/
-       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -324,7 +323,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID 
parentTLI,
        else
                TLHistoryFilePath(path, parentTLI);
 
-       srcfd = OpenTransientFile(path, O_RDONLY, 0);
+       srcfd = OpenTransientFile(path, O_RDONLY);
        if (srcfd < 0)
        {
                if (errno != ENOENT)
@@ -452,8 +451,7 @@ writeTimeLineHistoryFile(TimeLineID tli, char *content, int 
size)
        unlink(tmppath);
 
        /* do not use get_sync_bit() here --- want to fsync only at end of fill 
*/
-       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
diff --git a/src/backend/access/transam/twophase.c 
b/src/backend/access/transam/twophase.c
index 0a8edb9..1f02dd1 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1151,7 +1151,7 @@ ReadTwoPhaseFile(TransactionId xid, bool give_warnings)
 
        TwoPhaseFilePath(path, xid);
 
-       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
        if (fd < 0)
        {
                if (give_warnings)
@@ -1533,8 +1533,7 @@ RecreateTwoPhaseFile(TransactionId xid, void *content, 
int len)
        TwoPhaseFilePath(path, xid);
 
        fd = OpenTransientFile(path,
-                                                  O_CREAT | O_TRUNC | O_WRONLY 
| PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+                                                  O_CREAT | O_TRUNC | O_WRONLY 
| PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
diff --git a/src/backend/access/transam/xlog.c 
b/src/backend/access/transam/xlog.c
index 8973583..eed7dda 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -3156,8 +3156,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool 
use_lock)
         */
        if (*use_existent)
        {
-               fd = BasicOpenFile(path, O_RDWR | PG_BINARY | 
get_sync_bit(sync_method),
-                                                  S_IRUSR | S_IWUSR);
+               fd = BasicOpenFile(path, O_RDWR | PG_BINARY | 
get_sync_bit(sync_method));
                if (fd < 0)
                {
                        if (errno != ENOENT)
@@ -3182,8 +3181,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool 
use_lock)
        unlink(tmppath);
 
        /* do not use get_sync_bit() here --- want to fsync only at end of fill 
*/
-       fd = BasicOpenFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
-                                          S_IRUSR | S_IWUSR);
+       fd = BasicOpenFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -3275,8 +3273,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool 
use_lock)
        *use_existent = false;
 
        /* Now open original target segment (might not be file I just made) */
-       fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
-                                          S_IRUSR | S_IWUSR);
+       fd = BasicOpenFile(path, O_RDWR | PG_BINARY | 
get_sync_bit(sync_method));
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -3317,7 +3314,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, 
XLogSegNo srcsegno,
         * Open the source file
         */
        XLogFilePath(path, srcTLI, srcsegno);
-       srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+       srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
        if (srcfd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -3331,8 +3328,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, 
XLogSegNo srcsegno,
        unlink(tmppath);
 
        /* do not use get_sync_bit() here --- want to fsync only at end of fill 
*/
-       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -3504,8 +3500,7 @@ XLogFileOpen(XLogSegNo segno)
 
        XLogFilePath(path, ThisTimeLineID, segno);
 
-       fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
-                                          S_IRUSR | S_IWUSR);
+       fd = BasicOpenFile(path, O_RDWR | PG_BINARY | 
get_sync_bit(sync_method));
        if (fd < 0)
                ereport(PANIC,
                                (errcode_for_file_access(),
@@ -3571,7 +3566,7 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
                snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
        }
 
-       fd = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
+       fd = BasicOpenFile(path, O_RDONLY | PG_BINARY);
        if (fd >= 0)
        {
                /* Success! */
@@ -4065,7 +4060,7 @@ ValidateXLOGDirectoryStructure(void)
        {
                ereport(LOG,
                                (errmsg("creating missing WAL directory 
\"%s\"", path)));
-               if (mkdir(path, S_IRWXU) < 0)
+               if (mkdir(path, PG_DEFAULT_DIR_MODE) < 0)
                        ereport(FATAL,
                                        (errmsg("could not create missing 
directory \"%s\": %m",
                                                        path)));
@@ -4404,8 +4399,7 @@ WriteControlFile(void)
        memcpy(buffer, ControlFile, sizeof(ControlFileData));
 
        fd = BasicOpenFile(XLOG_CONTROL_FILE,
-                                          O_RDWR | O_CREAT | O_EXCL | 
PG_BINARY,
-                                          S_IRUSR | S_IWUSR);
+                                          O_RDWR | O_CREAT | O_EXCL | 
PG_BINARY);
        if (fd < 0)
                ereport(PANIC,
                                (errcode_for_file_access(),
@@ -4444,8 +4438,7 @@ ReadControlFile(void)
         * Read data...
         */
        fd = BasicOpenFile(XLOG_CONTROL_FILE,
-                                          O_RDWR | PG_BINARY,
-                                          S_IRUSR | S_IWUSR);
+                                          O_RDWR | PG_BINARY);
        if (fd < 0)
                ereport(PANIC,
                                (errcode_for_file_access(),
@@ -4624,8 +4617,7 @@ UpdateControlFile(void)
        FIN_CRC32C(ControlFile->crc);
 
        fd = BasicOpenFile(XLOG_CONTROL_FILE,
-                                          O_RDWR | PG_BINARY,
-                                          S_IRUSR | S_IWUSR);
+                                          O_RDWR | PG_BINARY);
        if (fd < 0)
                ereport(PANIC,
                                (errcode_for_file_access(),
diff --git a/src/backend/access/transam/xlogutils.c 
b/src/backend/access/transam/xlogutils.c
index 8b99b78..96ac73f 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -687,7 +687,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, 
Size count)
 
                        XLogFilePath(path, tli, sendSegNo);
 
-                       sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
+                       sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY);
 
                        if (sendFile < 0)
                        {
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index 11ee536..578b46b 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -428,7 +428,7 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, 
char relpersistence)
 
                /* Check for existing file of same name */
                rpath = relpath(rnode, MAIN_FORKNUM);
-               fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0);
+               fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY);
 
                if (fd >= 0)
                {
diff --git a/src/backend/commands/tablespace.c 
b/src/backend/commands/tablespace.c
index f9c2620..312ac07 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -151,7 +151,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool 
isRedo)
                        else
                        {
                                /* Directory creation failed? */
-                               if (mkdir(dir, S_IRWXU) < 0)
+                               if (mkdir(dir, PG_DEFAULT_DIR_MODE) < 0)
                                {
                                        char       *parentdir;
 
@@ -173,7 +173,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool 
isRedo)
                                        get_parent_directory(parentdir);
                                        get_parent_directory(parentdir);
                                        /* Can't create parent and it doesn't 
already exist? */
-                                       if (mkdir(parentdir, S_IRWXU) < 0 && 
errno != EEXIST)
+                                       if (mkdir(parentdir, 
PG_DEFAULT_DIR_MODE) < 0 && errno != EEXIST)
                                                ereport(ERROR,
                                                                
(errcode_for_file_access(),
                                                          errmsg("could not 
create directory \"%s\": %m",
@@ -184,7 +184,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool 
isRedo)
                                        parentdir = pstrdup(dir);
                                        get_parent_directory(parentdir);
                                        /* Can't create parent and it doesn't 
already exist? */
-                                       if (mkdir(parentdir, S_IRWXU) < 0 && 
errno != EEXIST)
+                                       if (mkdir(parentdir, 
PG_DEFAULT_DIR_MODE) < 0 && errno != EEXIST)
                                                ereport(ERROR,
                                                                
(errcode_for_file_access(),
                                                          errmsg("could not 
create directory \"%s\": %m",
@@ -192,7 +192,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool 
isRedo)
                                        pfree(parentdir);
 
                                        /* Create database directory */
-                                       if (mkdir(dir, S_IRWXU) < 0)
+                                       if (mkdir(dir, PG_DEFAULT_DIR_MODE) < 0)
                                                ereport(ERROR,
                                                                
(errcode_for_file_access(),
                                                          errmsg("could not 
create directory \"%s\": %m",
@@ -610,7 +610,7 @@ create_tablespace_directories(const char *location, const 
Oid tablespaceoid)
         * The creation of the version directory prevents more than one 
tablespace
         * in a single location.
         */
-       if (mkdir(location_with_version_dir, S_IRWXU) < 0)
+       if (mkdir(location_with_version_dir, PG_DEFAULT_DIR_MODE) < 0)
        {
                if (errno == EEXIST)
                        ereport(ERROR,
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
index f537aff..c0c8d94 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -462,7 +462,7 @@ lo_import_internal(text *filename, Oid lobjOid)
         * open the file to be read in
         */
        text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
-       fd = OpenTransientFile(fnamebuf, O_RDONLY | PG_BINARY, S_IRWXU);
+       fd = OpenTransientFile(fnamebuf, O_RDONLY | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -538,8 +538,8 @@ be_lo_export(PG_FUNCTION_ARGS)
         */
        text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
        oumask = umask(S_IWGRP | S_IWOTH);
-       fd = OpenTransientFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | 
PG_BINARY,
-                                                  S_IRUSR | S_IWUSR | S_IRGRP 
| S_IROTH);
+       fd = OpenTransientFilePerm(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | 
PG_BINARY,
+                                                          S_IRUSR | S_IWUSR | 
S_IRGRP | S_IROTH);
        umask(oumask);
        if (fd < 0)
                ereport(ERROR,
diff --git a/src/backend/postmaster/postmaster.c 
b/src/backend/postmaster/postmaster.c
index 6831342..9fbd2a9 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -579,9 +579,10 @@ PostmasterMain(int argc, char *argv[])
        IsPostmasterEnvironment = true;
 
        /*
-        * for security, no dir or file created can be group or other accessible
+        * Initially set most restrictive umask in case any files are
+        * accidentally created before file_mode_mask is loaded from GUC.
         */
-       umask(S_IRWXG | S_IRWXO);
+       umask(file_mode_mask);
 
        /*
         * Initialize random(3) so we don't get the same values in every run.
@@ -854,6 +855,9 @@ PostmasterMain(int argc, char *argv[])
                ExitPostmaster(0);
        }
 
+       /* Reset the file mode creation mask now that GUC has been loaded. */
+       umask(file_mode_mask);
+
        /* Verify that DataDir looks reasonable */
        checkDataDir();
 
@@ -1496,25 +1500,20 @@ checkDataDir(void)
 #endif
 
        /*
-        * Check if the directory has group or world access.  If so, reject.
-        *
-        * It would be possible to allow weaker constraints (for example, allow
-        * group access) but we cannot make a general assumption that that is
-        * okay; for example there are platforms where nearly all users
-        * customarily belong to the same group.  Perhaps this test should be
-        * configurable.
+        * Check if the directory has the correct permissions.  If not, then 
reject.
         *
         * XXX temporarily suppress check when on Windows, because there may not
         * be proper support for Unix-y file permissions.  Need to think of a
         * reasonable check to apply on Windows.
         */
 #if !defined(WIN32) && !defined(__CYGWIN__)
-       if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
+       if (stat_buf.st_mode & file_mode_mask)
                ereport(FATAL,
                                
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("data directory \"%s\" has group or 
world access",
+                                errmsg("data directory \"%s\" has incorrect 
permissions",
                                                DataDir),
-                                errdetail("Permissions should be u=rwx 
(0700).")));
+                                errdetail("Permissions should be (%04o).",
+                                               (PG_DEFAULT_DIR_MODE & 
~file_mode_mask))));
 #endif
 
        /* Look for PG_VERSION before looking for pg_control */
@@ -4400,7 +4399,7 @@ internal_forkexec(int argc, char *argv[], Port *port)
                 * As in OpenTemporaryFileInTablespace, try to make the 
temp-file
                 * directory
                 */
-               mkdir(PG_TEMP_FILES_DIR, S_IRWXU);
+               mkdir(PG_TEMP_FILES_DIR, PG_DEFAULT_DIR_MODE);
 
                fp = AllocateFile(tmpfilename, PG_BINARY_W);
                if (!fp)
diff --git a/src/backend/postmaster/syslogger.c 
b/src/backend/postmaster/syslogger.c
index aaefdae..f7b1cb5 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -41,6 +41,7 @@
 #include "postmaster/postmaster.h"
 #include "postmaster/syslogger.h"
 #include "storage/dsm.h"
+#include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
 #include "storage/pg_shmem.h"
@@ -322,7 +323,7 @@ SysLoggerMain(int argc, char *argv[])
                                /*
                                 * Also, create new directory if not present; 
ignore errors
                                 */
-                               mkdir(Log_directory, S_IRWXU);
+                               mkdir(Log_directory, PG_DEFAULT_DIR_MODE);
                        }
                        if (strcmp(Log_filename, currentLogFilename) != 0)
                        {
@@ -564,7 +565,7 @@ SysLogger_Start(void)
        /*
         * Create log directory if not present; ignore errors
         */
-       mkdir(Log_directory, S_IRWXU);
+       mkdir(Log_directory, PG_DEFAULT_DIR_MODE);
 
        /*
         * The initial logfile is created right in the postmaster, to verify 
that
diff --git a/src/backend/replication/logical/origin.c 
b/src/backend/replication/logical/origin.c
index bf84c68..51d54ab 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -527,8 +527,7 @@ CheckPointReplicationOrigin(void)
         * CheckpointLock.
         */
        tmpfd = OpenTransientFile((char *) tmppath,
-                                                         O_CREAT | O_EXCL | 
O_WRONLY | PG_BINARY,
-                                                         S_IRUSR | S_IWUSR);
+                                                         O_CREAT | O_EXCL | 
O_WRONLY | PG_BINARY);
        if (tmpfd < 0)
                ereport(PANIC,
                                (errcode_for_file_access(),
@@ -637,7 +636,7 @@ StartupReplicationOrigin(void)
 
        elog(DEBUG2, "starting up replication origin progress state");
 
-       fd = OpenTransientFile((char *) path, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile((char *) path, O_RDONLY | PG_BINARY);
 
        /*
         * might have had max_replication_slots == 0 last run, or we just 
brought
diff --git a/src/backend/replication/logical/reorderbuffer.c 
b/src/backend/replication/logical/reorderbuffer.c
index 8aac670..af7edea 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -2103,8 +2103,7 @@ ReorderBufferSerializeTXN(ReorderBuffer *rb, 
ReorderBufferTXN *txn)
 
                        /* open segment, create it if necessary */
                        fd = OpenTransientFile(path,
-                                                                  O_CREAT | 
O_WRONLY | O_APPEND | PG_BINARY,
-                                                                  S_IRUSR | 
S_IWUSR);
+                                                                  O_CREAT | 
O_WRONLY | O_APPEND | PG_BINARY);
 
                        if (fd < 0)
                                ereport(ERROR,
@@ -2345,7 +2344,7 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, 
ReorderBufferTXN *txn,
                                        NameStr(MyReplicationSlot->data.name), 
txn->xid,
                                        (uint32) (recptr >> 32), (uint32) 
recptr);
 
-                       *fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+                       *fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
                        if (*fd < 0 && errno == ENOENT)
                        {
                                *fd = -1;
@@ -3030,7 +3029,7 @@ ApplyLogicalMappingFile(HTAB *tuplecid_data, Oid relid, 
const char *fname)
        LogicalRewriteMappingData map;
 
        sprintf(path, "pg_logical/mappings/%s", fname);
-       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
diff --git a/src/backend/replication/logical/snapbuild.c 
b/src/backend/replication/logical/snapbuild.c
index 6f19cdc..961b0f9 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -1574,8 +1574,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 
        /* we have valid data now, open tempfile and write it there */
        fd = OpenTransientFile(tmppath,
-                                                  O_CREAT | O_EXCL | O_WRONLY 
| PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+                                                  O_CREAT | O_EXCL | O_WRONLY 
| PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errmsg("could not open file \"%s\": %m", 
path)));
@@ -1655,7 +1654,7 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
        sprintf(path, "pg_logical/snapshots/%X-%X.snap",
                        (uint32) (lsn >> 32), (uint32) lsn);
 
-       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
 
        if (fd < 0 && errno == ENOENT)
                return false;
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 10d69d0..7e8b50e 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1011,7 +1011,7 @@ CreateSlotOnDisk(ReplicationSlot *slot)
                rmtree(tmppath, true);
 
        /* Create and fsync the temporary slot directory. */
-       if (mkdir(tmppath, S_IRWXU) < 0)
+       if (mkdir(tmppath, PG_DEFAULT_DIR_MODE) < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
                                 errmsg("could not create directory \"%s\": %m",
@@ -1072,9 +1072,7 @@ SaveSlotToPath(ReplicationSlot *slot, const char *dir, 
int elevel)
        sprintf(tmppath, "%s/state.tmp", dir);
        sprintf(path, "%s/state", dir);
 
-       fd = OpenTransientFile(tmppath,
-                                                  O_CREAT | O_EXCL | O_WRONLY 
| PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(tmppath, O_CREAT | O_EXCL | O_WRONLY | 
PG_BINARY);
        if (fd < 0)
        {
                ereport(elevel,
@@ -1187,7 +1185,7 @@ RestoreSlotFromDisk(const char *name)
 
        elog(DEBUG1, "restoring replication slot from \"%s\"", path);
 
-       fd = OpenTransientFile(path, O_RDWR | PG_BINARY, 0);
+       fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
 
        /*
         * We do not need to handle this as we are rename()ing the directory 
into
diff --git a/src/backend/replication/walsender.c 
b/src/backend/replication/walsender.c
index 9cf9eb0..e1af7a3 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -437,7 +437,7 @@ SendTimeLineHistory(TimeLineHistoryCmd *cmd)
        pq_sendint(&buf, len, 4);       /* col1 len */
        pq_sendbytes(&buf, histfname, len);
 
-       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0666);
+       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -2031,7 +2031,7 @@ retry:
 
                        XLogFilePath(path, curFileTimeLine, sendSegNo);
 
-                       sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
+                       sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY);
                        if (sendFile < 0)
                        {
                                /*
diff --git a/src/backend/storage/file/copydir.c 
b/src/backend/storage/file/copydir.c
index 101da47..0e078f5 100644
--- a/src/backend/storage/file/copydir.c
+++ b/src/backend/storage/file/copydir.c
@@ -41,7 +41,7 @@ copydir(char *fromdir, char *todir, bool recurse)
        char            fromfile[MAXPGPATH];
        char            tofile[MAXPGPATH];
 
-       if (mkdir(todir, S_IRWXU) != 0)
+       if (mkdir(todir, PG_DEFAULT_DIR_MODE) != 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
                                 errmsg("could not create directory \"%s\": 
%m", todir)));
@@ -148,14 +148,13 @@ copy_file(char *fromfile, char *tofile)
        /*
         * Open the files
         */
-       srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY, 0);
+       srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);
        if (srcfd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
                                 errmsg("could not open file \"%s\": %m", 
fromfile)));
 
-       dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
-                                                         S_IRUSR | S_IWUSR);
+       dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | 
PG_BINARY);
        if (dstfd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index fd02fc0..46caf90 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -138,6 +138,8 @@ int                 max_files_per_process = 1000;
  */
 int                    max_safe_fds = 32;      /* default if not changed */
 
+/* The file mode creation mask for creating new files and directories. */
+int                    file_mode_mask = PG_DEFAULT_MODE_MASK;
 
 /* Debugging.... */
 
@@ -604,7 +606,7 @@ durable_rename(const char *oldfile, const char *newfile, 
int elevel)
        if (fsync_fname_ext(oldfile, false, false, elevel) != 0)
                return -1;
 
-       fd = OpenTransientFile((char *) newfile, PG_BINARY | O_RDWR, 0);
+       fd = OpenTransientFile((char *) newfile, PG_BINARY | O_RDWR);
        if (fd < 0)
        {
                if (errno != ENOENT)
@@ -896,7 +898,7 @@ set_max_safe_fds(void)
  * this module wouldn't have any open files to close at that point anyway.
  */
 int
-BasicOpenFile(FileName fileName, int fileFlags, int fileMode)
+BasicOpenFilePerm(FileName fileName, int fileFlags, int fileMode)
 {
        int                     fd;
 
@@ -922,6 +924,12 @@ tryAgain:
        return -1;                                      /* failure */
 }
 
+int
+BasicOpenFile(FileName fileName, int fileFlags)
+{
+       return BasicOpenFilePerm(fileName, fileFlags, PG_DEFAULT_FILE_MODE);
+}
+
 #if defined(FDDEBUG)
 
 static void
@@ -1047,8 +1055,8 @@ LruInsert(File file)
                 * overall system file table being full.  So, be prepared to 
release
                 * another FD if necessary...
                 */
-               vfdP->fd = BasicOpenFile(vfdP->fileName, vfdP->fileFlags,
-                                                                
vfdP->fileMode);
+               vfdP->fd = BasicOpenFilePerm(vfdP->fileName, vfdP->fileFlags,
+                                                                        
vfdP->fileMode);
                if (vfdP->fd < 0)
                {
                        DO_DB(elog(LOG, "re-open failed: %m"));
@@ -1263,13 +1271,19 @@ FileInvalidate(File file)
  * (which should always be $PGDATA when this code is running).
  */
 File
-PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
+PathNameOpenFile(FileName fileName, int fileFlags)
+{
+       return PathNameOpenFilePerm(fileName, fileFlags, PG_DEFAULT_FILE_MODE);
+}
+
+File
+PathNameOpenFilePerm(FileName fileName, int fileFlags, int fileMode)
 {
        char       *fnamecopy;
        File            file;
        Vfd                *vfdP;
 
-       DO_DB(elog(LOG, "PathNameOpenFile: %s %x %o",
+       DO_DB(elog(LOG, "PathNameOpenFilePerm: %s %x %o",
                           fileName, fileFlags, fileMode));
 
        /*
@@ -1287,7 +1301,7 @@ PathNameOpenFile(FileName fileName, int fileFlags, int 
fileMode)
        /* Close excess kernel FDs. */
        ReleaseLruFiles();
 
-       vfdP->fd = BasicOpenFile(fileName, fileFlags, fileMode);
+       vfdP->fd = BasicOpenFilePerm(fileName, fileFlags, fileMode);
 
        if (vfdP->fd < 0)
        {
@@ -1424,8 +1438,7 @@ OpenTemporaryFileInTablespace(Oid tblspcOid, bool 
rejectError)
         * temp file that can be reused.
         */
        file = PathNameOpenFile(tempfilepath,
-                                                       O_RDWR | O_CREAT | 
O_TRUNC | PG_BINARY,
-                                                       0600);
+                                                       O_RDWR | O_CREAT | 
O_TRUNC | PG_BINARY);
        if (file <= 0)
        {
                /*
@@ -1436,11 +1449,10 @@ OpenTemporaryFileInTablespace(Oid tblspcOid, bool 
rejectError)
                 * just did the same thing.  If it doesn't work then we'll bomb 
out on
                 * the second create attempt, instead.
                 */
-               mkdir(tempdirpath, S_IRWXU);
+               mkdir(tempdirpath, PG_DEFAULT_DIR_MODE);
 
                file = PathNameOpenFile(tempfilepath,
-                                                               O_RDWR | 
O_CREAT | O_TRUNC | PG_BINARY,
-                                                               0600);
+                                                               O_RDWR | 
O_CREAT | O_TRUNC | PG_BINARY);
                if (file <= 0 && rejectError)
                        elog(ERROR, "could not create temporary file \"%s\": 
%m",
                                 tempfilepath);
@@ -2090,7 +2102,7 @@ TryAgain:
  * Like AllocateFile, but returns an unbuffered fd like open(2)
  */
 int
-OpenTransientFile(FileName fileName, int fileFlags, int fileMode)
+OpenTransientFilePerm(FileName fileName, int fileFlags, int fileMode)
 {
        int                     fd;
 
@@ -2107,7 +2119,7 @@ OpenTransientFile(FileName fileName, int fileFlags, int 
fileMode)
        /* Close excess kernel FDs. */
        ReleaseLruFiles();
 
-       fd = BasicOpenFile(fileName, fileFlags, fileMode);
+       fd = BasicOpenFilePerm(fileName, fileFlags, fileMode);
 
        if (fd >= 0)
        {
@@ -2124,6 +2136,12 @@ OpenTransientFile(FileName fileName, int fileFlags, int 
fileMode)
        return -1;                                      /* failure */
 }
 
+int
+OpenTransientFile(FileName fileName, int fileFlags)
+{
+       return OpenTransientFilePerm(fileName, fileFlags, PG_DEFAULT_FILE_MODE);
+}
+
 /*
  * Routines that want to initiate a pipe stream should use OpenPipeStream
  * rather than plain popen().  This lets fd.c deal with freeing FDs if
@@ -3030,7 +3048,7 @@ pre_sync_fname(const char *fname, bool isdir, int elevel)
        if (isdir)
                return;
 
-       fd = OpenTransientFile((char *) fname, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile((char *) fname, O_RDONLY | PG_BINARY);
 
        if (fd < 0)
        {
@@ -3090,7 +3108,7 @@ fsync_fname_ext(const char *fname, bool isdir, bool 
ignore_perm, int elevel)
        else
                flags |= O_RDONLY;
 
-       fd = OpenTransientFile((char *) fname, flags, 0);
+       fd = OpenTransientFile((char *) fname, flags);
 
        /*
         * Some OSs don't allow us to open directories at all (Windows returns
diff --git a/src/backend/storage/ipc/dsm_impl.c 
b/src/backend/storage/ipc/dsm_impl.c
index b2c9cdc..80ee4fa 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -283,7 +283,7 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size 
request_size,
         * returning.
         */
        flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0);
-       if ((fd = shm_open(name, flags, 0600)) == -1)
+       if ((fd = shm_open(name, flags, PG_DEFAULT_FILE_MODE)) == -1)
        {
                if (errno != EEXIST)
                        ereport(elevel,
@@ -834,7 +834,7 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size 
request_size,
 
        /* Create new segment or open an existing one for attach or resize. */
        flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0);
-       if ((fd = OpenTransientFile(name, flags, 0600)) == -1)
+       if ((fd = OpenTransientFile(name, flags)) == -1)
        {
                if (errno != EEXIST)
                        ereport(elevel,
diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c
index ffd91f5..dfc5b75 100644
--- a/src/backend/storage/ipc/ipc.c
+++ b/src/backend/storage/ipc/ipc.c
@@ -28,6 +28,7 @@
 #include "postmaster/autovacuum.h"
 #endif
 #include "storage/dsm.h"
+#include "storage/fd.h"
 #include "storage/ipc.h"
 #include "tcop/tcopprot.h"
 
@@ -132,8 +133,8 @@ proc_exit(int code)
                else
                        snprintf(gprofDirName, 32, "gprof/%d", (int) getpid());
 
-               mkdir("gprof", S_IRWXU | S_IRWXG | S_IRWXO);
-               mkdir(gprofDirName, S_IRWXU | S_IRWXG | S_IRWXO);
+               mkdir("gprof", PG_DEFAULT_DIR_MODE);
+               mkdir(gprofDirName, PG_DEFAULT_DIR_MODE);
                chdir(gprofDirName);
        }
 #endif
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 6c17b54..cf951a2 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -303,7 +303,7 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
 
        path = relpath(reln->smgr_rnode, forkNum);
 
-       fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 
0600);
+       fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
 
        if (fd < 0)
        {
@@ -316,7 +316,7 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
                 * already, even if isRedo is not set.  (See also mdopen)
                 */
                if (isRedo || IsBootstrapProcessingMode())
-                       fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600);
+                       fd = PathNameOpenFile(path, O_RDWR | PG_BINARY);
                if (fd < 0)
                {
                        /* be sure to report the error reported by create, not 
open */
@@ -429,7 +429,7 @@ mdunlinkfork(RelFileNodeBackend rnode, ForkNumber forkNum, 
bool isRedo)
                /* truncate(2) would be easier here, but Windows hasn't got it 
*/
                int                     fd;
 
-               fd = OpenTransientFile(path, O_RDWR | PG_BINARY, 0);
+               fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
                if (fd >= 0)
                {
                        int                     save_errno;
@@ -582,7 +582,7 @@ mdopen(SMgrRelation reln, ForkNumber forknum, int behavior)
 
        path = relpath(reln->smgr_rnode, forknum);
 
-       fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600);
+       fd = PathNameOpenFile(path, O_RDWR | PG_BINARY);
 
        if (fd < 0)
        {
@@ -593,7 +593,7 @@ mdopen(SMgrRelation reln, ForkNumber forknum, int behavior)
                 * substitute for mdcreate() in bootstrap mode only. (See 
mdcreate)
                 */
                if (IsBootstrapProcessingMode())
-                       fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | 
PG_BINARY, 0600);
+                       fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | 
PG_BINARY);
                if (fd < 0)
                {
                        if ((behavior & EXTENSION_RETURN_NULL) &&
@@ -1779,7 +1779,7 @@ _mdfd_openseg(SMgrRelation reln, ForkNumber forknum, 
BlockNumber segno,
        fullpath = _mdfd_segpath(reln, forknum, segno);
 
        /* open the file */
-       fd = PathNameOpenFile(fullpath, O_RDWR | PG_BINARY | oflags, 0600);
+       fd = PathNameOpenFile(fullpath, O_RDWR | PG_BINARY | oflags);
 
        pfree(fullpath);
 
diff --git a/src/backend/utils/cache/relmapper.c 
b/src/backend/utils/cache/relmapper.c
index c9d6e44..fe68b5b 100644
--- a/src/backend/utils/cache/relmapper.c
+++ b/src/backend/utils/cache/relmapper.c
@@ -643,8 +643,7 @@ load_relmap_file(bool shared)
        }
 
        /* Read data ... */
-       fd = OpenTransientFile(mapfilename,
-                                                  O_RDONLY | PG_BINARY, 
S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(mapfilename, O_RDONLY | PG_BINARY);
        if (fd < 0)
                ereport(FATAL,
                                (errcode_for_file_access(),
@@ -742,9 +741,7 @@ write_relmap_file(bool shared, RelMapFile *newmap,
                realmap = &local_map;
        }
 
-       fd = OpenTransientFile(mapfilename,
-                                                  O_WRONLY | O_CREAT | 
PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(mapfilename, O_WRONLY | O_CREAT | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0707f66..bb3e471 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -190,6 +190,7 @@ static void assign_application_name(const char *newval, 
void *extra);
 static bool check_cluster_name(char **newval, void **extra, GucSource source);
 static const char *show_unix_socket_permissions(void);
 static const char *show_log_file_mode(void);
+static const char *show_file_mode_mask(void);
 
 /* Private functions in guc-file.l that need to be called from guc.c */
 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
@@ -2841,6 +2842,18 @@ static struct config_int ConfigureNamesInt[] =
                4096, 64, MAX_KILOBYTES,
                NULL, NULL, NULL
        },
+       {
+               {"file_mode_mask", PGC_POSTMASTER, UNGROUPED,
+                       gettext_noop("Sets the file mode creation mask for the 
backend process."),
+                       gettext_noop("The parameter value is expected to be a 
numeric mode"
+                                                "specification in the form 
accepted by the chmod and "
+                                                "umask system calls.  (To use 
the customary octal "
+                                                "format the number must start 
with a 0 (zero).)")
+               },
+               &file_mode_mask,
+               PG_DEFAULT_MODE_MASK, 0000, 0777,
+               NULL, NULL, show_file_mode_mask
+       },
 
        /* End-of-list marker */
        {
@@ -7186,8 +7199,7 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
         * truncate and reuse it.
         */
        Tmpfd = BasicOpenFile(AutoConfTmpFileName,
-                                                 O_CREAT | O_RDWR | O_TRUNC,
-                                                 S_IRUSR | S_IWUSR);
+                                                 O_CREAT | O_RDWR | O_TRUNC);
        if (Tmpfd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -10444,6 +10456,15 @@ show_unix_socket_permissions(void)
 }
 
 static const char *
+show_file_mode_mask(void)
+{
+       static char buf[8];
+
+       snprintf(buf, sizeof(buf), "%04o", file_mode_mask);
+       return buf;
+}
+
+static const char *
 show_log_file_mode(void)
 {
        static char buf[8];
diff --git a/src/backend/utils/misc/postgresql.conf.sample 
b/src/backend/utils/misc/postgresql.conf.sample
index 157d775..81fd9da 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -49,6 +49,7 @@
 #external_pid_file = ''                        # write an extra PID file
                                        # (change requires restart)
 
+#file_mode_mask = 0077
 
 #------------------------------------------------------------------------------
 # CONNECTIONS AND AUTHENTICATION
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 1ed0d20..283ec09 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -110,6 +110,15 @@ static const char *const auth_methods_local[] = {
        NULL
 };
 
+/* File mode to use with chmod on files. */
+#define PG_DEFAULT_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH 
| S_IWOTH)
+
+/* File mode to use with chmod on directories. */
+#define PG_DEFAULT_DIR_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
+
+/* Default file mode creation mask. */
+#define PG_DEFAULT_MODE_MASK (S_IRWXG | S_IRWXO)
+
 /*
  * these values are passed in by makefile defines
  */
@@ -139,6 +148,7 @@ static bool sync_only = false;
 static bool show_setting = false;
 static bool data_checksums = false;
 static char *xlog_dir = "";
+static mode_t file_mode_mask = PG_DEFAULT_MODE_MASK;
 
 
 /* internal vars */
@@ -1095,6 +1105,11 @@ setup_config(void)
        conflines = replace_token(conflines, "#dynamic_shared_memory_type = 
posix",
                                                          repltok);
 
+       snprintf(repltok, sizeof(repltok), "file_mode_mask = %04o",
+                        file_mode_mask);
+       conflines = replace_token(conflines, "#file_mode_mask = 0077",
+                                                         repltok);
+
 #if DEFAULT_BACKEND_FLUSH_AFTER > 0
        snprintf(repltok, sizeof(repltok), "#backend_flush_after = %dkB",
                         DEFAULT_BACKEND_FLUSH_AFTER * (BLCKSZ / 1024));
@@ -1131,7 +1146,7 @@ setup_config(void)
        snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
 
        writefile(path, conflines);
-       if (chmod(path, S_IRUSR | S_IWUSR) != 0)
+       if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0)
        {
                fprintf(stderr, _("%s: could not change permissions of \"%s\": 
%s\n"),
                                progname, path, strerror(errno));
@@ -1151,7 +1166,7 @@ setup_config(void)
        sprintf(path, "%s/postgresql.auto.conf", pg_data);
 
        writefile(path, autoconflines);
-       if (chmod(path, S_IRUSR | S_IWUSR) != 0)
+       if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0)
        {
                fprintf(stderr, _("%s: could not change permissions of \"%s\": 
%s\n"),
                                progname, path, strerror(errno));
@@ -1235,7 +1250,7 @@ setup_config(void)
        snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data);
 
        writefile(path, conflines);
-       if (chmod(path, S_IRUSR | S_IWUSR) != 0)
+       if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0)
        {
                fprintf(stderr, _("%s: could not change permissions of \"%s\": 
%s\n"),
                                progname, path, strerror(errno));
@@ -1251,7 +1266,7 @@ setup_config(void)
        snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data);
 
        writefile(path, conflines);
-       if (chmod(path, S_IRUSR | S_IWUSR) != 0)
+       if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0)
        {
                fprintf(stderr, _("%s: could not change permissions of \"%s\": 
%s\n"),
                                progname, path, strerror(errno));
@@ -2243,6 +2258,7 @@ usage(const char *progname)
        printf(_("      --auth-local=METHOD   default authentication method for 
local-socket connections\n"));
        printf(_(" [-D, --pgdata=]DATADIR     location for this database 
cluster\n"));
        printf(_("  -E, --encoding=ENCODING   set default encoding for new 
databases\n"));
+       printf(_("  -u, --file-mode-mask=MASK set default file mode creation 
mask (umask)\n"));
        printf(_("      --locale=LOCALE       set default locale for new 
databases\n"));
        printf(_("      --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n"
                         "      --lc-monetary=, --lc-numeric=, 
--lc-time=LOCALE\n"
@@ -2624,7 +2640,7 @@ create_data_directory(void)
                                   pg_data);
                        fflush(stdout);
 
-                       if (pg_mkdir_p(pg_data, S_IRWXU) != 0)
+                       if (pg_mkdir_p(pg_data, PG_DEFAULT_DIR_MODE) != 0)
                        {
                                fprintf(stderr, _("%s: could not create 
directory \"%s\": %s\n"),
                                                progname, pg_data, 
strerror(errno));
@@ -2642,7 +2658,7 @@ create_data_directory(void)
                                   pg_data);
                        fflush(stdout);
 
-                       if (chmod(pg_data, S_IRWXU) != 0)
+                       if (chmod(pg_data, (PG_DEFAULT_DIR_MODE & 
~file_mode_mask)) != 0)
                        {
                                fprintf(stderr, _("%s: could not change 
permissions of directory \"%s\": %s\n"),
                                                progname, pg_data, 
strerror(errno));
@@ -2710,7 +2726,8 @@ create_xlog_or_symlink(void)
                                           xlog_dir);
                                fflush(stdout);
 
-                               if (pg_mkdir_p(xlog_dir, S_IRWXU) != 0)
+                               printf("MASK: %04o\n", file_mode_mask);
+                               if (pg_mkdir_p(xlog_dir, PG_DEFAULT_DIR_MODE) 
!= 0)
                                {
                                        fprintf(stderr, _("%s: could not create 
directory \"%s\": %s\n"),
                                                        progname, xlog_dir, 
strerror(errno));
@@ -2728,7 +2745,8 @@ create_xlog_or_symlink(void)
                                           xlog_dir);
                                fflush(stdout);
 
-                               if (chmod(xlog_dir, S_IRWXU) != 0)
+                               printf("MASK: %04o\n", file_mode_mask);
+                               if (chmod(xlog_dir, (PG_DEFAULT_DIR_MODE & 
~file_mode_mask)) != 0)
                                {
                                        fprintf(stderr, _("%s: could not change 
permissions of directory \"%s\": %s\n"),
                                                        progname, xlog_dir, 
strerror(errno));
@@ -2778,7 +2796,7 @@ create_xlog_or_symlink(void)
        else
        {
                /* Without -X option, just make the subdirectory normally */
-               if (mkdir(subdirloc, S_IRWXU) < 0)
+               if (mkdir(subdirloc, PG_DEFAULT_DIR_MODE) < 0)
                {
                        fprintf(stderr, _("%s: could not create directory 
\"%s\": %s\n"),
                                        progname, subdirloc, strerror(errno));
@@ -2814,7 +2832,9 @@ initialize_data_directory(void)
 
        setup_signals();
 
-       umask(S_IRWXG | S_IRWXO);
+       /* Set the file mode creation mask. */
+       umask(file_mode_mask);
+       printf(_("Initializing with file mode creation mask: %04o\n"), 
file_mode_mask);
 
        create_data_directory();
 
@@ -2834,7 +2854,7 @@ initialize_data_directory(void)
                 * The parent directory already exists, so we only need mkdir() 
not
                 * pg_mkdir_p() here, which avoids some failure modes; cf bug 
#13853.
                 */
-               if (mkdir(path, S_IRWXU) < 0)
+               if (mkdir(path, PG_DEFAULT_DIR_MODE) < 0)
                {
                        fprintf(stderr, _("%s: could not create directory 
\"%s\": %s\n"),
                                        progname, path, strerror(errno));
@@ -2942,6 +2962,7 @@ main(int argc, char *argv[])
                {"sync-only", no_argument, NULL, 'S'},
                {"waldir", required_argument, NULL, 'X'},
                {"data-checksums", no_argument, NULL, 'k'},
+               {"file-mode-mask", required_argument, NULL, 'u'},
                {NULL, 0, NULL, 0}
        };
 
@@ -2983,7 +3004,7 @@ main(int argc, char *argv[])
 
        /* process command-line options */
 
-       while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", 
long_options, &option_index)) != -1)
+       while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:u:", 
long_options, &option_index)) != -1)
        {
                switch (c)
                {
@@ -3074,6 +3095,9 @@ main(int argc, char *argv[])
                        case 'X':
                                xlog_dir = pg_strdup(optarg);
                                break;
+                       case 'u':
+                               file_mode_mask = strtoul(optarg, NULL, 8);
+                               break;
                        default:
                                /* getopt_long already emitted a complaint */
                                fprintf(stderr, _("Try \"%s --help\" for more 
information.\n"),
diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h
index 1a43a2c..6660b7b 100644
--- a/src/include/storage/fd.h
+++ b/src/include/storage/fd.h
@@ -22,7 +22,7 @@
  * Use them for all file activity...
  *
  *     File fd;
- *     fd = PathNameOpenFile("foo", O_RDONLY, 0600);
+ *     fd = PathNameOpenFile("foo", O_RDONLY);
  *
  *     AllocateFile();
  *     FreeFile();
@@ -59,13 +59,21 @@ extern int  max_files_per_process;
  */
 extern int     max_safe_fds;
 
+/* The file mode creation mask for creating new files and directories. */
+extern int     file_mode_mask;
+
+/* Define default modes and masks. */
+#define PG_DEFAULT_FILE_MODE   (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | 
S_IROTH | S_IWOTH)
+#define PG_DEFAULT_DIR_MODE            (S_IRWXU | S_IRWXG | S_IRWXO)
+#define PG_DEFAULT_MODE_MASK   (S_IRWXG | S_IRWXO)
 
 /*
  * prototypes for functions in fd.c
  */
 
 /* Operations on virtual Files --- equivalent to Unix kernel file ops */
-extern File PathNameOpenFile(FileName fileName, int fileFlags, int fileMode);
+extern File PathNameOpenFilePerm(FileName fileName, int fileFlags, int 
fileMode);
+extern File PathNameOpenFile(FileName fileName, int fileFlags);
 extern File OpenTemporaryFile(bool interXact);
 extern void FileClose(File file);
 extern int     FilePrefetch(File file, off_t offset, int amount);
@@ -94,11 +102,13 @@ extern struct dirent *ReadDir(DIR *dir, const char 
*dirname);
 extern int     FreeDir(DIR *dir);
 
 /* Operations to allow use of a plain kernel FD, with automatic cleanup */
-extern int     OpenTransientFile(FileName fileName, int fileFlags, int 
fileMode);
+extern int     OpenTransientFilePerm(FileName fileName, int fileFlags, int 
fileMode);
+extern int OpenTransientFile(FileName fileName, int fileFlags);
 extern int     CloseTransientFile(int fd);
 
 /* If you've really really gotta have a plain kernel FD, use this */
-extern int     BasicOpenFile(FileName fileName, int fileFlags, int fileMode);
+extern int     BasicOpenFilePerm(FileName fileName, int fileFlags, int 
fileMode);
+extern int     BasicOpenFile(FileName fileName, int fileFlags);
 
 /* Miscellaneous support routines */
 extern void InitFileAccess(void);

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to