From f455fcfdb8ca3b67373223a4e15648c35e2592a9 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 26 Oct 2014 20:59:21 -0400
Subject: [PATCH] Avoid unportable strftime() behavior in pg_dump/pg_dumpall.

Commit ad5d46a4494b0b480a3af246bb4227d9bdadca37 thought that we could
get around the known portability issues of strftime's %Z specifier by
using %z instead.  However, that idea seems to have been innocent of
any actual research, as it certainly missed the facts that
(1) %z is not portable to pre-C99 systems, and
(2) %z doesn't actually act differently from %Z on Windows anyway.

Per failures on buildfarm member hamerkop.

While at it, centralize the code defining what strftime format we
want to use in pg_dump; three copies of that string seems a bit much.
---
 src/bin/pg_dump/dumputils.h          | 17 +++++++++++++++++
 src/bin/pg_dump/pg_backup_archiver.c |  8 +++++---
 src/bin/pg_dump/pg_dumpall.c         |  6 +++---
 3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index 688e9ca6b8..aaf4074852 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -49,6 +49,23 @@ typedef struct SimpleStringList
 
 #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
 
+/*
+ * Preferred strftime(3) format specifier for printing timestamps in pg_dump
+ * and friends.
+ *
+ * We don't print the timezone on Windows, because the names are long and
+ * localized, which means they may contain characters in various random
+ * encodings; this has been seen to cause encoding errors when reading the
+ * dump script.  Think not to get around that by using %z, because
+ * (1) %z is not portable to pre-C99 systems, and
+ * (2) %z doesn't actually act differently from %Z on Windows anyway.
+ */
+#ifndef WIN32
+#define PGDUMP_STRFTIME_FMT  "%Y-%m-%d %H:%M:%S %Z"
+#else
+#define PGDUMP_STRFTIME_FMT  "%Y-%m-%d %H:%M:%S"
+#endif
+
 extern int	quote_all_identifiers;
 extern PQExpBuffer (*getLocalPQExpBuffer) (void);
 
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index ed28d36e13..1a2ebcb1f4 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -1047,14 +1047,16 @@ PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
 	teSection	curSection;
 	OutputContext sav;
 	const char *fmtName;
-	struct tm  *tm = localtime(&AH->createDate);
 	char		stamp_str[64];
 
 	sav = SaveOutput(AH);
 	if (ropt->filename)
 		SetOutput(AH, ropt->filename, 0 /* no compression */ );
 
-	strftime(stamp_str, sizeof(stamp_str), "%Y-%m-%d %H:%M:%S %z", tm);
+	if (strftime(stamp_str, sizeof(stamp_str), PGDUMP_STRFTIME_FMT,
+				 localtime(&AH->createDate)) == 0)
+		strcpy(stamp_str, "[unknown]");
+
 	ahprintf(AH, ";\n; Archive created at %s\n", stamp_str);
 	ahprintf(AH, ";     dbname: %s\n;     TOC Entries: %d\n;     Compression: %d\n",
 			 AH->archdbname, AH->tocCount, AH->compression);
@@ -3544,7 +3546,7 @@ dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim)
 {
 	char		buf[64];
 
-	if (strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %z", localtime(&tim)) != 0)
+	if (strftime(buf, sizeof(buf), PGDUMP_STRFTIME_FMT, localtime(&tim)) != 0)
 		ahprintf(AH, "-- %s %s\n\n", msg, buf);
 }
 
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index dc8de69db1..23cb0b4da7 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -48,7 +48,7 @@ static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
 					   const char *type, const char *name, const char *type2,
 					   const char *name2);
 static void dumpDatabases(PGconn *conn);
-static void dumpTimestamp(char *msg);
+static void dumpTimestamp(const char *msg);
 static void doShellQuoting(PQExpBuffer buf, const char *str);
 static void doConnStrQuoting(PQExpBuffer buf, const char *str);
 
@@ -2058,12 +2058,12 @@ executeCommand(PGconn *conn, const char *query)
  * dumpTimestamp
  */
 static void
-dumpTimestamp(char *msg)
+dumpTimestamp(const char *msg)
 {
 	char		buf[64];
 	time_t		now = time(NULL);
 
-	if (strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %z", localtime(&now)) != 0)
+	if (strftime(buf, sizeof(buf), PGDUMP_STRFTIME_FMT, localtime(&now)) != 0)
 		fprintf(OPF, "-- %s %s\n\n", msg, buf);
 }
 
-- 
2.49.0