From 81f203af67bb0dfed1a55656496fd55211d98972 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Thu, 11 Aug 2022 12:30:48 +1200
Subject: [PATCH v2 2/2] Follow junction point chains in our stat() emulation.

Commit c5cb8f3b supposed that we'd only ever have to follow junction
points for one hop, because we don't construct longer chains of them
ourselves.  But when stat()ing a parent directory supplied by the user,
we should really be able to cope with longer chains.  Choose an
arbitrary cap of 8, to match the minimum acceptable value of SYMLOOP_MAX
from POSIX.
---
 src/port/win32stat.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/port/win32stat.c b/src/port/win32stat.c
index 26443293d7..2ff42b9a90 100644
--- a/src/port/win32stat.c
+++ b/src/port/win32stat.c
@@ -184,16 +184,27 @@ _pglstat64(const char *name, struct stat *buf)
 int
 _pgstat64(const char *name, struct stat *buf)
 {
+	int			loops = 0;
 	int			ret;
 
 	ret = _pglstat64(name, buf);
 
 	/* Do we need to follow a symlink (junction point)? */
-	if (ret == 0 && S_ISLNK(buf->st_mode))
+	while (ret == 0 && S_ISLNK(buf->st_mode))
 	{
 		char		next[MAXPGPATH];
 		ssize_t		size;
 
+		if (++loops > 8)
+		{
+			/*
+			 * Give up. The error for too many symlinks is supposed to be
+			 * ELOOP, but Windows hasn't got it.
+			 */
+			errno = EIO;
+			return -1;
+		}
+
 		/*
 		 * _pglstat64() already called readlink() once to be able to fill in
 		 * st_size, and now we need to do it again to get the path to follow.
@@ -219,17 +230,6 @@ _pgstat64(const char *name, struct stat *buf)
 		next[size] = 0;
 
 		ret = _pglstat64(next, buf);
-		if (ret == 0 && S_ISLNK(buf->st_mode))
-		{
-			/*
-			 * We're only prepared to go one hop, because we only expect to
-			 * deal with the simple cases that we create.  The error for too
-			 * many symlinks is supposed to be ELOOP, but Windows hasn't got
-			 * it.
-			 */
-			errno = EIO;
-			return -1;
-		}
 	}
 
 	return ret;
-- 
2.35.1

