From 8432019bb6212c53c78f9de512d34357adae97f7 Mon Sep 17 00:00:00 2001
From: Paul Guo <pguo@pivotal.io>
Date: Wed, 24 Apr 2019 11:32:35 +0800
Subject: [PATCH] Make sure the file is a regular file if it exists before
 calling AllocateFile() for file writing.

---
 src/backend/commands/copy.c     |  8 ++++++++
 src/backend/postmaster/pgstat.c | 15 +++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index c39218f8db..abca8f2cfd 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -1916,6 +1916,14 @@ BeginCopyTo(ParseState *pstate,
 			oumask = umask(S_IWGRP | S_IWOTH);
 			PG_TRY();
 			{
+				struct stat	fst;
+
+				if (stat(cstate->filename, &fst) == 0 && !S_ISREG(fst.st_mode))
+					ereport(ERROR,
+							(ERRCODE_DUPLICATE_FILE,
+							errmsg("file \"%s\" exists but is not a regular file",
+							cstate->filename)));
+
 				cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_W);
 			}
 			PG_CATCH();
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index cdf87bae32..a5c9a586d3 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -23,6 +23,7 @@
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -4780,9 +4781,16 @@ pgstat_write_statsfiles(bool permanent, bool allDbs)
 	const char *tmpfile = permanent ? PGSTAT_STAT_PERMANENT_TMPFILE : pgstat_stat_tmpname;
 	const char *statfile = permanent ? PGSTAT_STAT_PERMANENT_FILENAME : pgstat_stat_filename;
 	int			rc;
+	struct stat	fst;
 
 	elog(DEBUG2, "writing stats file \"%s\"", statfile);
 
+	if (stat(tmpfile, &fst) == 0 && !S_ISREG(fst.st_mode))
+		ereport(ERROR,
+				(ERRCODE_DUPLICATE_FILE,
+				errmsg("file \"%s\" exists but is not a regular file",
+				tmpfile)));
+
 	/*
 	 * Open the statistics temp file to write out the current values.
 	 */
@@ -4934,12 +4942,19 @@ pgstat_write_db_statsfile(PgStat_StatDBEntry *dbentry, bool permanent)
 	int			rc;
 	char		tmpfile[MAXPGPATH];
 	char		statfile[MAXPGPATH];
+	struct stat	fst;
 
 	get_dbstat_filename(permanent, true, dbid, tmpfile, MAXPGPATH);
 	get_dbstat_filename(permanent, false, dbid, statfile, MAXPGPATH);
 
 	elog(DEBUG2, "writing stats file \"%s\"", statfile);
 
+	if (stat(tmpfile, &fst) == 0 && !S_ISREG(fst.st_mode))
+		ereport(ERROR,
+				(ERRCODE_DUPLICATE_FILE,
+				errmsg("file \"%s\" exists but is not a regular file",
+				tmpfile)));
+
 	/*
 	 * Open the statistics temp file to write out the current values.
 	 */
-- 
2.17.2

