mirror of https://github.com/postgres/postgres
Calling fseek() or ftello() on a handle to a non-seeking device such as
a pipe or a communications device is not supported. Unfortunately,
MSVC's flavor of these routines, _fseeki64() and _ftelli64(), do not
return an error when given a pipe as handle. Some of the logic of
pg_dump and restore relies on these routines to check if a handle is
seekable, causing failures when passing the contents of pg_dump to
pg_restore through a pipe, for example.
This commit introduces wrappers for fseeko() and ftello() on MSVC so as
any callers are able to properly detect the cases of non-seekable
handles. This relies mainly on GetFileType(), sharing a bit of code
with the MSVC port for fstat(). The code in charge of getting a file
type is refactored into a new file called win32common.c, shared by
win32stat.c and the new win32fseek.c. It includes the MSVC ports for
fseeko() and ftello().
Like 765f5df
, this is backpatched down to 14, where the fstat()
implementation for MSVC is able to understand about files larger than
4GB in size. Using a TAP test for that is proving to be tricky as
IPC::Run handles the pipes by itself, still I have been able to check
the fix manually.
Reported-by: Daniel Watzinger
Author: Juan José Santamaría Flecha, Michael Paquier
Discussion: https://postgr.es/m/CAC+AXB26a4EmxM2suXxPpJaGrqAdxracd7hskLg-zxtPB50h7A@mail.gmail.com
Backpatch-through: 14
pull/137/head
parent
c03c2eae0a
commit
a923e21631
@ -0,0 +1,68 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* win32common.c |
||||||
|
* Common routines shared among the win32*.c ports. |
||||||
|
* |
||||||
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group |
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California |
||||||
|
* |
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* src/port/win32common.c |
||||||
|
* |
||||||
|
*------------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifdef FRONTEND |
||||||
|
#include "postgres_fe.h" |
||||||
|
#else |
||||||
|
#include "postgres.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef WIN32 |
||||||
|
|
||||||
|
/*
|
||||||
|
* pgwin32_get_file_type |
||||||
|
* |
||||||
|
* Convenience wrapper for GetFileType() with specific error handling for all the |
||||||
|
* port implementations. Returns the file type associated with a HANDLE. |
||||||
|
* |
||||||
|
* On error, sets errno with FILE_TYPE_UNKNOWN as file type. |
||||||
|
*/ |
||||||
|
DWORD |
||||||
|
pgwin32_get_file_type(HANDLE hFile) |
||||||
|
{ |
||||||
|
DWORD fileType = FILE_TYPE_UNKNOWN; |
||||||
|
DWORD lastError; |
||||||
|
|
||||||
|
errno = 0; |
||||||
|
|
||||||
|
/*
|
||||||
|
* When stdin, stdout, and stderr aren't associated with a stream the |
||||||
|
* special value -2 is returned: |
||||||
|
* https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle
|
||||||
|
*/ |
||||||
|
if (hFile == INVALID_HANDLE_VALUE || hFile == (HANDLE) -2) |
||||||
|
{ |
||||||
|
errno = EINVAL; |
||||||
|
return FILE_TYPE_UNKNOWN; |
||||||
|
} |
||||||
|
|
||||||
|
fileType = GetFileType(hFile); |
||||||
|
lastError = GetLastError(); |
||||||
|
|
||||||
|
/*
|
||||||
|
* Invoke GetLastError in order to distinguish between a "valid" return of |
||||||
|
* FILE_TYPE_UNKNOWN and its return due to a calling error. In case of |
||||||
|
* success, GetLastError() returns NO_ERROR. |
||||||
|
*/ |
||||||
|
if (fileType == FILE_TYPE_UNKNOWN && lastError != NO_ERROR) |
||||||
|
{ |
||||||
|
_dosmaperr(lastError); |
||||||
|
return FILE_TYPE_UNKNOWN; |
||||||
|
} |
||||||
|
|
||||||
|
return fileType; |
||||||
|
} |
||||||
|
|
||||||
|
#endif /* WIN32 */ |
@ -0,0 +1,75 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* 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, and fseek() may not return |
||||||
|
* an error. This wrapper relies on the file type to check which cases |
||||||
|
* are supported. |
||||||
|
*/ |
||||||
|
int |
||||||
|
_pgfseeko64(FILE *stream, pgoff_t offset, int origin) |
||||||
|
{ |
||||||
|
DWORD fileType; |
||||||
|
HANDLE hFile = (HANDLE) _get_osfhandle(_fileno(stream)); |
||||||
|
|
||||||
|
fileType = pgwin32_get_file_type(hFile); |
||||||
|
if (errno != 0) |
||||||
|
return -1; |
||||||
|
|
||||||
|
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; |
||||||
|
HANDLE hFile = (HANDLE) _get_osfhandle(_fileno(stream)); |
||||||
|
|
||||||
|
fileType = pgwin32_get_file_type(hFile); |
||||||
|
if (errno != 0) |
||||||
|
return -1; |
||||||
|
|
||||||
|
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) */ |
Loading…
Reference in new issue