From 38704c29b593e32404ad13f93d0bce6330ee41d1 Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryzbyj@telsasoft.com>
Date: Sun, 8 Mar 2020 17:15:02 -0500
Subject: [PATCH v12 06/11] Show links to dirs with isdir=false..

..this is needed to avoid infinite recursion in pg_ls_dir_recurse.

Change pg_stat_file for consistency.
---
 doc/src/sgml/func.sgml          |  2 +-
 src/backend/utils/adt/genfile.c | 21 +++++++++++++++++++--
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4b966ed847..68c7327e1d 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -21545,7 +21545,7 @@ SELECT convert_from(pg_read_binary_file('file_in_utf8.txt'), 'UTF8');
     size, last accessed time stamp, last modified time stamp,
     last file status change time stamp (Unix platforms only),
     file creation time stamp (Windows only), and a <type>boolean</type>
-    indicating if it is a directory (or a symbolic link to a directory).
+    indicating if it is a directory (and not a symbolic link to a directory).
     Typical usages include:
 <programlisting>
 SELECT * FROM pg_stat_file('filename');
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 98ab9a2b92..70b541388e 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -365,6 +365,22 @@ pg_read_binary_file_all(PG_FUNCTION_ARGS)
 	return pg_read_binary_file(fcinfo);
 }
 
+/* Return true iff path is a symbolic link (unix) or junction (win32) */
+static bool
+islink(const char *path)
+{
+#ifndef WIN32
+	struct stat attrib;
+	if (lstat(path, &attrib) < 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m", path)));
+	return S_ISLNK(attrib.st_mode);
+#else
+	return pgwin32_is_junction(path);
+#endif
+}
+
 /*
  * stat a file
  */
@@ -428,7 +444,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 	isnull[3] = true;
 	values[4] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime));
 #endif
-	values[5] = BoolGetDatum(S_ISDIR(fst.st_mode));
+	values[5] = BoolGetDatum(S_ISDIR(fst.st_mode) && !islink(filename));
 
 	tuple = heap_form_tuple(tupdesc, values, isnull);
 
@@ -614,7 +630,8 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, int flags)
 			values[1] = Int64GetDatum((int64) attrib.st_size);
 			values[2] = TimestampTzGetDatum(time_t_to_timestamptz(attrib.st_mtime));
 			if (flags & LS_DIR_ISDIR)
-				values[3] = BoolGetDatum(S_ISDIR(attrib.st_mode));
+				values[3] = BoolGetDatum(S_ISDIR(attrib.st_mode) &&
+					!islink(path));
 		}
 
 		memset(nulls, 0, sizeof(nulls));
-- 
2.17.0

