From 178dfd69039a99f5ed9e7f0bfc042211f7b95f4e Mon Sep 17 00:00:00 2001
From: Jakub Wartak <jakub.wartak@enterprisedb.com>
Date: Fri, 22 Nov 2024 10:45:25 +0100
Subject: [PATCH] Bugfix Windows pg_basebackup ability to create >2GB
 pg_wal.tar tarballs.

Previously on WIN32 pg_basebackup was reporting "could not close file:
Invalid argument" when creating pg_wal.tar with sizes above ~2^31 bytes
due to off_t being 32-bit on Win32. Fix via introducing pgoff_t and
_lseeki64(), Also fixed the ftruncate to support pgoff_t.
---
 src/bin/pg_basebackup/walmethods.c | 10 +++++-----
 src/bin/pg_basebackup/walmethods.h |  2 +-
 src/include/port/win32_port.h      | 29 +++++++++++++++++++++++++++--
 3 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index 602727f4d43..6204ba8aba7 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -63,7 +63,7 @@ static DirectoryMethodData *dir_data = NULL;
 typedef struct DirectoryMethodFile
 {
 	int			fd;
-	off_t		currpos;
+	pgoff_t		currpos;
 	char	   *pathname;
 	char	   *fullpath;
 	char	   *temp_suffix;
@@ -370,7 +370,7 @@ dir_write(Walfile f, const void *buf, size_t count)
 	return r;
 }
 
-static off_t
+static pgoff_t
 dir_get_current_pos(Walfile f)
 {
 	Assert(f != NULL);
@@ -666,8 +666,8 @@ FreeWalDirectoryMethod(void)
 
 typedef struct TarMethodFile
 {
-	off_t		ofs_start;		/* Where does the *header* for this file start */
-	off_t		currpos;
+	pgoff_t		ofs_start;		/* Where does the *header* for this file start */
+	pgoff_t		currpos;
 	char		header[TAR_BLOCK_SIZE];
 	char	   *pathname;
 	size_t		pad_to_size;
@@ -1005,7 +1005,7 @@ tar_compression_algorithm(void)
 	return tar_data->compression_algorithm;
 }
 
-static off_t
+static pgoff_t
 tar_get_current_pos(Walfile f)
 {
 	Assert(f != NULL);
diff --git a/src/bin/pg_basebackup/walmethods.h b/src/bin/pg_basebackup/walmethods.h
index 76530dc9419..240e3f22fc8 100644
--- a/src/bin/pg_basebackup/walmethods.h
+++ b/src/bin/pg_basebackup/walmethods.h
@@ -69,7 +69,7 @@ struct WalWriteMethod
 	ssize_t		(*write) (Walfile f, const void *buf, size_t count);
 
 	/* Return the current position in a file or -1 on error */
-	off_t		(*get_current_pos) (Walfile f);
+	pgoff_t		(*get_current_pos) (Walfile f);
 
 	/*
 	 * fsync the contents of the specified file. Returns 0 on success.
diff --git a/src/include/port/win32_port.h b/src/include/port/win32_port.h
index c6398662174..6bbf4f852c6 100644
--- a/src/include/port/win32_port.h
+++ b/src/include/port/win32_port.h
@@ -67,11 +67,14 @@
 #undef fstat
 #undef stat
 
+#define lseek microsoft_native_lseek
+#include <io.h>
+#undef lseek
+#define lseek(fd, offset, origin) _lseeki64((fd), (offset), (origin))
+
 /* Must be here to avoid conflicting with prototype in windows.h */
 #define mkdir(a,b)	mkdir(a)
 
-#define ftruncate(a,b)	chsize(a,b)
-
 /* Windows doesn't have fsync() as such, use _commit() */
 #define fsync(fd) _commit(fd)
 
@@ -225,6 +228,28 @@ extern pgoff_t _pgftello64(FILE *stream);
 #endif
 #endif
 
+#define ftruncate mingw_native_ftruncate
+#include <unistd.h>
+#undef ftruncate
+static inline int
+ftruncate(int fd, pgoff_t length)
+{
+#if defined(_UCRT) || defined(_MSC_VER)
+	/* MinGW + UCRT and all supported MSVC versions have this. */
+	errno = _chsize_s(fd, length);
+	return errno == 0 ? 0 : -1;
+#else
+	/* MinGW + ancient msvcrt.dll has only _chsize, limited by off_t (long). */
+	if (length > LONG_MAX)
+	{
+		/* A clear error is better than silent corruption. */
+		errno = EFBIG;
+		return - 1;
+	}
+	return _chsize(fd, length);
+#endif
+}
+
 /*
  *	Win32 also doesn't have symlinks, but we can emulate them with
  *	junction points on newer Win32 versions.
-- 
2.39.5 (Apple Git-154)

