From 45ea3338e10c6b296ddc1cedb80ce8e5f103e51d Mon Sep 17 00:00:00 2001
From: Juan Jose Santamaria Flecha <juanjo.santamaria@gmail.com>
Date: Wed, 15 Mar 2023 07:04:44 -0400
Subject: [PATCH] fix fseek detection of unseekable files for WIN32

Calling fseek() on a handle to a non-seeking device such as a pipe or
a communications device is not supported, even though the fseek() may
not return an error, so harden that funcion with our version.
---
 src/include/port/win32_port.h |  9 ++++--
 src/port/meson.build          |  1 +
 src/port/win32fseek.c         | 68 +++++++++++++++++++++++++++++++++++++++++++
 src/tools/msvc/Mkvcbuild.pm   |  1 +
 4 files changed, 76 insertions(+), 3 deletions(-)
 create mode 100644 src/port/win32fseek.c

diff --git a/src/include/port/win32_port.h b/src/include/port/win32_port.h
index 9488195..66553fe 100644
--- a/src/include/port/win32_port.h
+++ b/src/include/port/win32_port.h
@@ -206,13 +206,16 @@ int			setitimer(int which, const struct itimerval *value, struct itimerval *oval
 
 /*
  * WIN32 does not provide 64-bit off_t, but does provide the functions operating
- * with 64-bit offsets.
+ * with 64-bit offsets. Also, fseek() might not give an error for unseekable
+ * streams, so harden that function with our version.
  */
 #define pgoff_t __int64
 
 #ifdef _MSC_VER
-#define fseeko(stream, offset, origin) _fseeki64(stream, offset, origin)
-#define ftello(stream) _ftelli64(stream)
+extern int  	_pgfseeko64(FILE *stream, pgoff_t offset, int origin);
+extern pgoff_t	_pgftello64(FILE *stream);
+#define fseeko(stream, offset, origin) _pgfseeko64(stream, offset, origin)
+#define ftello(stream) _pgftello64(stream)
 #else
 #ifndef fseeko
 #define fseeko(stream, offset, origin) fseeko64(stream, offset, origin)
diff --git a/src/port/meson.build b/src/port/meson.build
index b174b25..3d8eeb4 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -33,6 +33,7 @@ if host_system == 'windows'
     'win32env.c',
     'win32error.c',
     'win32fdatasync.c',
+    'win32fseek.c',
     'win32getrusage.c',
     'win32link.c',
     'win32ntdll.c',
diff --git a/src/port/win32fseek.c b/src/port/win32fseek.c
new file mode 100644
index 0000000..6cf62db
--- /dev/null
+++ b/src/port/win32fseek.c
@@ -0,0 +1,68 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32fseek.c
+ *	  Replacements for fseeko() and ftello().
+ *
+ * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *	  src/port/win32fseek.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifdef FRONTEND
+#include "postgres_fe.h"
+#else
+#include "postgres.h"
+#endif
+
+#if defined(WIN32) && defined(_MSC_VER)
+
+/*
+ * _pgfseeko64
+ *
+ * Calling fseek() on a handle to a non-seeking device such as a pipe or
+ * a communications device is not supported, even though the fseek() may
+ * not return an error.
+ */
+int
+_pgfseeko64(FILE *stream, pgoff_t offset, int origin)
+{
+	DWORD			fileType;
+
+	fileType = GetFileType((HANDLE) _get_osfhandle(_fileno(stream)));
+
+	if (fileType == FILE_TYPE_DISK)
+		return _fseeki64(stream, offset, origin);
+	else if (fileType == FILE_TYPE_CHAR || fileType == FILE_TYPE_PIPE)
+		errno = ESPIPE;
+	else
+		errno = EINVAL;
+
+	return -1;
+}
+
+/*
+ * _pgftello64
+ *
+ * Same as _pgfseeko64().
+ */
+pgoff_t
+_pgftello64(FILE *stream)
+{
+	DWORD			fileType;
+
+	fileType = GetFileType((HANDLE) _get_osfhandle(_fileno(stream)));
+
+	if (fileType == FILE_TYPE_DISK)
+		return _ftelli64(stream);
+	else if (fileType == FILE_TYPE_CHAR || fileType == FILE_TYPE_PIPE)
+		errno = ESPIPE;
+	else
+		errno = EINVAL;
+
+	return -1;
+}
+
+#endif							/* defined(WIN32) && defined(_MSC_VER) */
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index f1c9ddf..61ace57 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -111,6 +111,7 @@ sub mkvcbuild
 	  win32dlopen.c
 	  win32env.c win32error.c
 	  win32fdatasync.c
+	  win32fseek.c
 	  win32getrusage.c
 	  win32gettimeofday.c
 	  win32link.c
-- 
2.11.0

