Skip to content

Commit bed9075

Browse files
committed
Fix our Windows stat() emulation to handle file sizes > 4GB.
Hack things so that our idea of "struct stat" is equivalent to Windows' struct __stat64, allowing it to have a wide enough st_size field. Instead of relying on native stat(), use GetFileInformationByHandle(). This avoids a number of issues with Microsoft's multiple and rather slipshod emulations of stat(). We still need to jump through hoops to deal with ERROR_DELETE_PENDING, though :-( Pull the relevant support code out of dirmod.c and put it into its own file, win32stat.c. Still TODO: do we need to do something different with lstat(), rather than treating it identically to stat()? Juan José Santamaría Flecha, reviewed by Emil Iggland; based on prior work by Michael Paquier, Sergey Zubkovsky, and others Discussion: https://postgr.es/m/1803D792815FC24D871C00D17AE95905CF5099@g01jpexmbkw24 Discussion: https://postgr.es/m/[email protected]
1 parent f13f2e4 commit bed9075

File tree

6 files changed

+339
-65
lines changed

6 files changed

+339
-65
lines changed

configure

+6
Original file line numberDiff line numberDiff line change
@@ -16137,6 +16137,12 @@ esac
1613716137
;;
1613816138
esac
1613916139

16140+
case " $LIBOBJS " in
16141+
*" win32stat.$ac_objext "* ) ;;
16142+
*) LIBOBJS="$LIBOBJS win32stat.$ac_objext"
16143+
;;
16144+
esac
16145+
1614016146

1614116147
$as_echo "#define HAVE_SYMLINK 1" >>confdefs.h
1614216148

configure.ac

+1
Original file line numberDiff line numberDiff line change
@@ -1807,6 +1807,7 @@ if test "$PORTNAME" = "win32"; then
18071807
AC_LIBOBJ(win32error)
18081808
AC_LIBOBJ(win32security)
18091809
AC_LIBOBJ(win32setlocale)
1810+
AC_LIBOBJ(win32stat)
18101811
AC_DEFINE([HAVE_SYMLINK], 1,
18111812
[Define to 1 if you have the `symlink' function.])
18121813
AC_CHECK_TYPES(MINIDUMP_TYPE, [pgac_minidump_type=yes], [pgac_minidump_type=no], [

src/include/port/win32_port.h

+32-12
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@
5151
#include <signal.h>
5252
#include <direct.h>
5353
#undef near
54-
#include <sys/stat.h> /* needed before sys/stat hacking below */
54+
55+
/* needed before sys/stat hacking below: */
56+
#define fstat microsoft_native_fstat
57+
#define stat microsoft_native_stat
58+
#include <sys/stat.h>
59+
#undef fstat
60+
#undef stat
5561

5662
/* Must be here to avoid conflicting with prototype in windows.h */
5763
#define mkdir(a,b) mkdir(a)
@@ -240,20 +246,34 @@ typedef int pid_t;
240246
* Supplement to <sys/stat.h>.
241247
*
242248
* We must pull in sys/stat.h before this part, else our overrides lose.
243-
*/
244-
#define lstat(path, sb) stat(path, sb)
245-
246-
/*
249+
*
247250
* stat() is not guaranteed to set the st_size field on win32, so we
248-
* redefine it to our own implementation that is.
251+
* redefine it to our own implementation. See src/port/win32stat.c.
249252
*
250-
* Some frontends don't need the size from stat, so if UNSAFE_STAT_OK
251-
* is defined we don't bother with this.
253+
* The struct stat is 32 bit in MSVC, so we redefine it as a copy of
254+
* struct __stat64. This also fixes the struct size for MINGW builds.
252255
*/
253-
#ifndef UNSAFE_STAT_OK
254-
extern int pgwin32_safestat(const char *path, struct stat *buf);
255-
#define stat(a,b) pgwin32_safestat(a,b)
256-
#endif
256+
struct stat /* This should match struct __stat64 */
257+
{
258+
_dev_t st_dev;
259+
_ino_t st_ino;
260+
unsigned short st_mode;
261+
short st_nlink;
262+
short st_uid;
263+
short st_gid;
264+
_dev_t st_rdev;
265+
__int64 st_size;
266+
__time64_t st_atime;
267+
__time64_t st_mtime;
268+
__time64_t st_ctime;
269+
};
270+
271+
extern int _pgfstat64(int fileno, struct stat *buf);
272+
extern int _pgstat64(const char *name, struct stat *buf);
273+
274+
#define fstat(fileno, sb) _pgfstat64(fileno, sb)
275+
#define stat(path, sb) _pgstat64(path, sb)
276+
#define lstat(path, sb) _pgstat64(path, sb)
257277

258278
/* These macros are not provided by older MinGW, nor by MSVC */
259279
#ifndef S_IRUSR

src/port/dirmod.c

-52
Original file line numberDiff line numberDiff line change
@@ -353,55 +353,3 @@ pgwin32_is_junction(const char *path)
353353
return ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT);
354354
}
355355
#endif /* defined(WIN32) && !defined(__CYGWIN__) */
356-
357-
358-
#if defined(WIN32) && !defined(__CYGWIN__)
359-
360-
#undef stat
361-
362-
/*
363-
* The stat() function in win32 is not guaranteed to update the st_size
364-
* field when run. So we define our own version that uses the Win32 API
365-
* to update this field.
366-
*/
367-
int
368-
pgwin32_safestat(const char *path, struct stat *buf)
369-
{
370-
int r;
371-
WIN32_FILE_ATTRIBUTE_DATA attr;
372-
373-
r = stat(path, buf);
374-
if (r < 0)
375-
{
376-
if (GetLastError() == ERROR_DELETE_PENDING)
377-
{
378-
/*
379-
* File has been deleted, but is not gone from the filesystem yet.
380-
* This can happen when some process with FILE_SHARE_DELETE has it
381-
* open and it will be fully removed once that handle is closed.
382-
* Meanwhile, we can't open it, so indicate that the file just
383-
* doesn't exist.
384-
*/
385-
errno = ENOENT;
386-
return -1;
387-
}
388-
389-
return r;
390-
}
391-
392-
if (!GetFileAttributesEx(path, GetFileExInfoStandard, &attr))
393-
{
394-
_dosmaperr(GetLastError());
395-
return -1;
396-
}
397-
398-
/*
399-
* XXX no support for large files here, but we don't do that in general on
400-
* Win32 yet.
401-
*/
402-
buf->st_size = attr.nFileSizeLow;
403-
404-
return 0;
405-
}
406-
407-
#endif

0 commit comments

Comments
 (0)