From 13b30c16f3164ee70599adee251256bd069fa0e4 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Tue, 24 Nov 2015 17:18:28 -0500
Subject: [PATCH] pg_upgrade:  fix CopyFile() on Windows to fail on file
 existence

Also fix getErrorText() to return the right error string on failure.
This behavior now matches that of other operating systems.

Report by Noah Misch

Backpatch through 9.1
---
 src/bin/pg_upgrade/check.c       | 16 ++++++++--------
 src/bin/pg_upgrade/controldata.c |  2 +-
 src/bin/pg_upgrade/exec.c        |  8 ++++----
 src/bin/pg_upgrade/file.c        |  8 ++++----
 src/bin/pg_upgrade/function.c    |  2 +-
 src/bin/pg_upgrade/option.c      |  2 +-
 src/bin/pg_upgrade/pg_upgrade.c  |  2 +-
 src/bin/pg_upgrade/pg_upgrade.h  |  2 +-
 src/bin/pg_upgrade/relfilenode.c |  2 +-
 src/bin/pg_upgrade/tablespace.c  |  2 +-
 src/bin/pg_upgrade/util.c        |  9 +++------
 src/bin/pg_upgrade/version.c     |  4 ++--
 12 files changed, 28 insertions(+), 31 deletions(-)

diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 41d4606dd59..539f1978039 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -421,7 +421,7 @@ create_script_for_cluster_analyze(char **analyze_script_file_name)
 
 	if ((script = fopen_priv(*analyze_script_file_name, "w")) == NULL)
 		pg_fatal("Could not open file \"%s\": %s\n",
-				 *analyze_script_file_name, getErrorText(errno));
+				 *analyze_script_file_name, getErrorText());
 
 #ifndef WIN32
 	/* add shebang header */
@@ -476,7 +476,7 @@ create_script_for_cluster_analyze(char **analyze_script_file_name)
 #ifndef WIN32
 	if (chmod(*analyze_script_file_name, S_IRWXU) != 0)
 		pg_fatal("Could not add execute permission to file \"%s\": %s\n",
-				 *analyze_script_file_name, getErrorText(errno));
+				 *analyze_script_file_name, getErrorText());
 #endif
 
 	if (os_info.user_specified)
@@ -532,7 +532,7 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name)
 
 	if ((script = fopen_priv(*deletion_script_file_name, "w")) == NULL)
 		pg_fatal("Could not open file \"%s\": %s\n",
-				 *deletion_script_file_name, getErrorText(errno));
+				 *deletion_script_file_name, getErrorText());
 
 #ifndef WIN32
 	/* add shebang header */
@@ -588,7 +588,7 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name)
 #ifndef WIN32
 	if (chmod(*deletion_script_file_name, S_IRWXU) != 0)
 		pg_fatal("Could not add execute permission to file \"%s\": %s\n",
-				 *deletion_script_file_name, getErrorText(errno));
+				 *deletion_script_file_name, getErrorText());
 #endif
 
 	check_ok();
@@ -790,7 +790,7 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 			found = true;
 			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
 				pg_fatal("Could not open file \"%s\": %s\n",
-						 output_path, getErrorText(errno));
+						 output_path, getErrorText());
 			if (!db_used)
 			{
 				fprintf(script, "Database: %s\n", active_db->db_name);
@@ -893,7 +893,7 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
 			found = true;
 			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
 				pg_fatal("Could not open file \"%s\": %s\n",
-						 output_path, getErrorText(errno));
+						 output_path, getErrorText());
 			if (!db_used)
 			{
 				fprintf(script, "Database: %s\n", active_db->db_name);
@@ -984,7 +984,7 @@ check_for_jsonb_9_4_usage(ClusterInfo *cluster)
 			found = true;
 			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
 				pg_fatal("Could not open file \"%s\": %s\n",
-						 output_path, getErrorText(errno));
+						 output_path, getErrorText());
 			if (!db_used)
 			{
 				fprintf(script, "Database: %s\n", active_db->db_name);
@@ -1032,7 +1032,7 @@ get_bin_version(ClusterInfo *cluster)
 	if ((output = popen(cmd, "r")) == NULL ||
 		fgets(cmd_output, sizeof(cmd_output), output) == NULL)
 		pg_fatal("Could not get pg_ctl version data using %s: %s\n",
-				 cmd, getErrorText(errno));
+				 cmd, getErrorText());
 
 	pclose(output);
 
diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c
index 8a86e45979f..8da4ce3ccc1 100644
--- a/src/bin/pg_upgrade/controldata.c
+++ b/src/bin/pg_upgrade/controldata.c
@@ -120,7 +120,7 @@ get_control_data(ClusterInfo *cluster, bool live_check)
 
 	if ((output = popen(cmd, "r")) == NULL)
 		pg_fatal("Could not get control data using %s: %s\n",
-				 cmd, getErrorText(errno));
+				 cmd, getErrorText());
 
 	/* Only in <= 9.2 */
 	if (GET_MAJOR_VERSION(cluster->major_version) <= 902)
diff --git a/src/bin/pg_upgrade/exec.c b/src/bin/pg_upgrade/exec.c
index 7d319126ed9..92c3766d16a 100644
--- a/src/bin/pg_upgrade/exec.c
+++ b/src/bin/pg_upgrade/exec.c
@@ -191,7 +191,7 @@ pid_lock_file_exists(const char *datadir)
 		/* ENOTDIR means we will throw a more useful error later */
 		if (errno != ENOENT && errno != ENOTDIR)
 			pg_fatal("could not open file \"%s\" for reading: %s\n",
-					 path, getErrorText(errno));
+					 path, getErrorText());
 
 		return false;
 	}
@@ -285,7 +285,7 @@ check_data_dir(const char *pg_data)
 
 		if (stat(subDirName, &statBuf) != 0)
 			report_status(PG_FATAL, "check for \"%s\" failed: %s\n",
-						  subDirName, getErrorText(errno));
+						  subDirName, getErrorText());
 		else if (!S_ISDIR(statBuf.st_mode))
 			report_status(PG_FATAL, "%s is not a directory\n",
 						  subDirName);
@@ -309,7 +309,7 @@ check_bin_dir(ClusterInfo *cluster)
 	/* check bindir */
 	if (stat(cluster->bindir, &statBuf) != 0)
 		report_status(PG_FATAL, "check for \"%s\" failed: %s\n",
-					  cluster->bindir, getErrorText(errno));
+					  cluster->bindir, getErrorText());
 	else if (!S_ISDIR(statBuf.st_mode))
 		report_status(PG_FATAL, "%s is not a directory\n",
 					  cluster->bindir);
@@ -352,7 +352,7 @@ validate_exec(const char *dir, const char *cmdName)
 	 */
 	if (stat(path, &buf) < 0)
 		pg_fatal("check for \"%s\" failed: %s\n",
-				 path, getErrorText(errno));
+				 path, getErrorText());
 	else if (!S_ISREG(buf.st_mode))
 		pg_fatal("check for \"%s\" failed: not an executable file\n",
 				 path);
diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c
index 37eb832c93a..c84783c9de6 100644
--- a/src/bin/pg_upgrade/file.c
+++ b/src/bin/pg_upgrade/file.c
@@ -37,9 +37,9 @@ copyAndUpdateFile(pageCnvCtx *pageConverter,
 #ifndef WIN32
 		if (copy_file(src, dst, force) == -1)
 #else
-		if (CopyFile(src, dst, force) == 0)
+		if (CopyFile(src, dst, !force) == 0)
 #endif
-			return getErrorText(errno);
+			return getErrorText();
 		else
 			return NULL;
 	}
@@ -121,7 +121,7 @@ linkAndUpdateFile(pageCnvCtx *pageConverter,
 		return "Cannot in-place update this cluster, page-by-page conversion is required";
 
 	if (pg_link_file(src, dst) == -1)
-		return getErrorText(errno);
+		return getErrorText();
 	else
 		return NULL;
 }
@@ -219,7 +219,7 @@ check_hard_link(void)
 	{
 		pg_fatal("Could not create hard link between old and new data directories: %s\n"
 				 "In link mode the old and new data directories must be on the same file system volume.\n",
-				 getErrorText(errno));
+				 getErrorText());
 	}
 	unlink(new_link_file);
 }
diff --git a/src/bin/pg_upgrade/function.c b/src/bin/pg_upgrade/function.c
index 04492a5cee4..0fb8c31104b 100644
--- a/src/bin/pg_upgrade/function.c
+++ b/src/bin/pg_upgrade/function.c
@@ -214,7 +214,7 @@ check_loadable_libraries(void)
 
 			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
 				pg_fatal("Could not open file \"%s\": %s\n",
-						 output_path, getErrorText(errno));
+						 output_path, getErrorText());
 			fprintf(script, "Could not load library \"%s\"\n%s\n",
 					lib,
 					PQerrorMessage(conn));
diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c
index 90f1401549b..a8571f08450 100644
--- a/src/bin/pg_upgrade/option.c
+++ b/src/bin/pg_upgrade/option.c
@@ -423,7 +423,7 @@ adjust_data_dir(ClusterInfo *cluster)
 	if ((output = popen(cmd, "r")) == NULL ||
 		fgets(cmd_output, sizeof(cmd_output), output) == NULL)
 		pg_fatal("Could not get data directory using %s: %s\n",
-				 cmd, getErrorText(errno));
+				 cmd, getErrorText());
 
 	pclose(output);
 
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
index 00cc938b654..4a7281b3698 100644
--- a/src/bin/pg_upgrade/pg_upgrade.c
+++ b/src/bin/pg_upgrade/pg_upgrade.c
@@ -224,7 +224,7 @@ setup(char *argv0, bool *live_check)
 
 	/* get path to pg_upgrade executable */
 	if (find_my_exec(argv0, exec_path) < 0)
-		pg_fatal("Could not get path name to pg_upgrade: %s\n", getErrorText(errno));
+		pg_fatal("Could not get path name to pg_upgrade: %s\n", getErrorText());
 
 	/* Trim off program name and keep just path */
 	*last_dir_separator(exec_path) = '\0';
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index fa4661b7d6a..a43dff5f53b 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -460,7 +460,7 @@ void		pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2) pg_attribute_noret
 void		end_progress_output(void);
 void		prep_status(const char *fmt,...) pg_attribute_printf(1, 2);
 void		check_ok(void);
-const char *getErrorText(int errNum);
+const char *getErrorText(void);
 unsigned int str2uint(const char *str);
 void		pg_putenv(const char *var, const char *val);
 
diff --git a/src/bin/pg_upgrade/relfilenode.c b/src/bin/pg_upgrade/relfilenode.c
index c22df429492..bfde1b1da4e 100644
--- a/src/bin/pg_upgrade/relfilenode.c
+++ b/src/bin/pg_upgrade/relfilenode.c
@@ -258,7 +258,7 @@ transfer_relfile(pageCnvCtx *pageConverter, FileNameMap *map,
 				else
 					pg_fatal("error while checking for file existence \"%s.%s\" (\"%s\" to \"%s\"): %s\n",
 							 map->nspname, map->relname, old_file, new_file,
-							 getErrorText(errno));
+							 getErrorText());
 			}
 			close(fd);
 		}
diff --git a/src/bin/pg_upgrade/tablespace.c b/src/bin/pg_upgrade/tablespace.c
index ce7097e71bf..a20cbc60a4a 100644
--- a/src/bin/pg_upgrade/tablespace.c
+++ b/src/bin/pg_upgrade/tablespace.c
@@ -91,7 +91,7 @@ get_tablespace_paths(void)
 			else
 				report_status(PG_FATAL,
 						   "cannot stat() tablespace directory \"%s\": %s\n",
-					   os_info.old_tablespaces[tblnum], getErrorText(errno));
+					   os_info.old_tablespaces[tblnum], getErrorText());
 		}
 		if (!S_ISDIR(statBuf.st_mode))
 			report_status(PG_FATAL,
diff --git a/src/bin/pg_upgrade/util.c b/src/bin/pg_upgrade/util.c
index 7f328f06444..8cd3f5d1a1f 100644
--- a/src/bin/pg_upgrade/util.c
+++ b/src/bin/pg_upgrade/util.c
@@ -235,18 +235,15 @@ get_user_info(char **user_name_p)
 /*
  * getErrorText()
  *
- *	Returns the text of the error message for the given error number
- *
- *	This feature is factored into a separate function because it is
- *	system-dependent.
+ *	Returns the text of the most recent error
  */
 const char *
-getErrorText(int errNum)
+getErrorText(void)
 {
 #ifdef WIN32
 	_dosmaperr(GetLastError());
 #endif
-	return pg_strdup(strerror(errNum));
+	return pg_strdup(strerror(errno));
 }
 
 
diff --git a/src/bin/pg_upgrade/version.c b/src/bin/pg_upgrade/version.c
index 9954daea17e..b93c414d7a3 100644
--- a/src/bin/pg_upgrade/version.c
+++ b/src/bin/pg_upgrade/version.c
@@ -49,7 +49,7 @@ new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster, bool check_mode)
 			if (!check_mode)
 			{
 				if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
-					pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
+					pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText());
 				fprintf(script, "\\connect %s\n",
 						quote_identifier(active_db->db_name));
 				fprintf(script,
@@ -143,7 +143,7 @@ old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster)
 		{
 			found = true;
 			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
-				pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
+				pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText());
 			if (!db_used)
 			{
 				fprintf(script, "Database: %s\n", active_db->db_name);
-- 
GitLab