From 87d05718d69cf26d0f2017dc30e30f0f62dcbbff Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Thu, 14 Jul 2022 16:43:03 +0200
Subject: [PATCH v25 2/4] split is_path_tslink as a new routine

---
 src/backend/access/transam/xlogrecovery.c | 68 +++++++++++++----------
 1 file changed, 40 insertions(+), 28 deletions(-)

diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index ae81244e06..e04d30cf3e 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -2008,54 +2008,66 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
 	}
 }
 
+/*
+ * Is the given directory entry a symlink/junction point?  Subroutine for
+ * CheckTablespaceDirectory.
+ */
+static bool
+is_path_tslink(const char *path)
+{
+#ifndef WIN32
+		struct stat st;
+
+		if (lstat(path, &st) < 0)
+			ereport(ERROR, errcode_for_file_access(),
+					errmsg("could not stat file \"%s\": %m", path));
+		return S_ISLNK(st.st_mode);
+#else
+		return pgwin32_is_junction(path);
+#endif
+}
+
 /*
  * Makes sure that ./pg_tblspc directory doesn't contain a real directory.
  *
- * This is intended to be called after reaching consistency.
- * ignore_invalid_pages=on turns into the PANIC error into WARNING so that
- * recovery can continue.
+ * Replay of database creation XLOG records for databases that were later
+ * dropped can create fake directories in pg_tblspc.  By the time consistency
+ * is reached these directories should have been removed; here we verify
+ * that this did indeed happen.  This must be called after reached consistent
+ * state.
  *
- * This can't be checked in allow_in_place_tablespaces mode, so skip it in
- * that case.
+ * ignore_invalid_pages=on turns into the PANIC error into WARNING so that
+ * recovery can continue.  XXX piggybacking on this particular GUC sounds like
+ * a bad idea.  Why not just advise to use allow_in_place_tablespaces?
  */
 static void
 CheckTablespaceDirectory(void)
 {
-	char *tblspc_path = "./pg_tblspc";
 	DIR		   *dir;
 	struct dirent *de;
 
-	/* Do not check for this when test tablespaces are in use */
+	/*
+	 * In allow_in_place_tablespaces mode, it is valid to have non-symlink
+	 * directories in pg_tblspc, so we cannot run this check.  Give up.
+	 */
 	if (allow_in_place_tablespaces)
 		return;
 
-	dir = AllocateDir(tblspc_path);
-	while ((de = ReadDir(dir, tblspc_path)) != NULL)
+	dir = AllocateDir("pg_tblspc");
+	while ((de = ReadDir(dir, "pg_tblspc")) != NULL)
 	{
-		char	path[MAXPGPATH];
-		char   *p;
-#ifndef WIN32
-		struct stat st;
-#endif
+		char	path[MAXPGPATH + 10];
 
 		/* Skip entries of non-oid names */
-		for (p = de->d_name; *p && isdigit(*p); p++);
-		if (*p)
+		if (strspn(de->d_name, "0123456789") != strlen(de->d_name))
 			continue;
 
-		snprintf(path, MAXPGPATH, "%s/%s", tblspc_path, de->d_name);
+		snprintf(path, sizeof(path), "pg_tblspc/%s", de->d_name);
 
-#ifndef WIN32
-		if (lstat(path, &st) < 0)
-			ereport(ERROR, errcode_for_file_access(),
-					errmsg("could not stat file \"%s\": %m", path));
-
-		if (!S_ISLNK(st.st_mode))
-#else
-		if (!pgwin32_is_junction(path))
-#endif
-			elog(ignore_invalid_pages ? WARNING : PANIC,
-				 "real directory found in pg_tblspc directory: %s", de->d_name);
+		if (!is_path_tslink(path))
+			ereport(ignore_invalid_pages ? WARNING : PANIC,
+					(errcode(ERRCODE_DATA_CORRUPTED),
+					 errmsg("real directory found in pg_tblspc directory: %s", de->d_name)));
 	}
 }
 
-- 
2.30.2

