From 33005aaad52a550ba028277dfb634d3d6fbfdd7f Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Thu, 28 Jul 2022 11:45:31 +1200
Subject: [PATCH] Fix get_dirent_type() for simlinks on MinGW/MSYS.

On Windows with MSVC, get_dirent_type() was recently made to return
DT_LNK for junction points by commit 9d3444dc, which fixed some
defective dirent.c code.

On Windows with Cygwin, get_dirent_type() already worked for symlinks,
as it does on POSIX systems, because Cygwin has its own fake symlinks
that behave like POSIX (on closer inspection, Cygwin's dirent has the
BSD d_type extension but it's probably always DT_UNKNOWN, so we fall
back to lstat(), which understands Cygwin symlinks with S_ISLNK()).

On Windows with MinGW/MSYS, we need extra code, because the MinGW
runtime has its own readdir() without d_type, and the lstat()-based
fallback has no knowledge of our convention for treating junctions as
symlinks.

Reported-by: Andrew Dunstan <andrew@dunslane.net>
Discussion: https://postgr.es/m/b9ddf605-6b36-f90d-7c30-7b3e95c46276%40dunslane.net
---
 src/common/file_utils.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/src/common/file_utils.c b/src/common/file_utils.c
index 19d308ad1f..210b2c4dfd 100644
--- a/src/common/file_utils.c
+++ b/src/common/file_utils.c
@@ -465,5 +465,19 @@ get_dirent_type(const char *path,
 #endif
 	}
 
+#if defined(WIN32) && !defined(_MSC_VER)
+	/*
+	 * If we're on native Windows (not Cygwin, which has its own POSIX
+	 * symlinks), but not using the MSVC compiler, then we're using a readdir()
+	 * emulation provided by the compiler's runtime that has no concept of
+	 * symlinks.  It sees junction points as directories, so we need an extra
+	 * system call to recognize them as symlinks, following our convention.
+	 */
+	if (result == PGFILETYPE_DIR &&
+		!look_through_symlinks &&
+		pgwin32_is_junction(path))
+		result = PGFILETYPE_LNK;
+#endif
+
 	return result;
 }
-- 
2.36.1

