From 178dfd69039a99f5ed9e7f0bfc042211f7b95f4e Mon Sep 17 00:00:00 2001 From: Jakub Wartak 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 +#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 +#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)