]> granicus.if.org Git - postgresql/blobdiff - src/port/open.c
Centralize single quote escaping in src/port/quotes.c
[postgresql] / src / port / open.c
index cd17f4164f470c436a094d39ff5652180ebd1747..e91641d2a7c3c08edb34786baa4fb7e2c5e54ff0 100644 (file)
@@ -4,28 +4,32 @@
  *        Win32 open() replacement
  *
  *
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/port/open.c,v 1.8 2005/02/27 00:53:29 momjian Exp $
+ * src/port/open.c
  *
  *-------------------------------------------------------------------------
  */
 
 #ifdef WIN32
 
-#include <postgres.h>
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
 #include <windows.h>
 #include <fcntl.h>
-#include <errno.h>
 #include <assert.h>
 
-int win32_open(const char *fileName, int fileFlags, ...);
 
 static int
 openFlagsToCreateFileFlags(int openFlags)
 {
        switch (openFlags & (O_CREAT | O_TRUNC | O_EXCL))
        {
+                       /* O_EXCL is meaningless without O_CREAT */
                case 0:
                case O_EXCL:
                        return OPEN_EXISTING;
@@ -33,6 +37,7 @@ openFlagsToCreateFileFlags(int openFlags)
                case O_CREAT:
                        return OPEN_ALWAYS;
 
+                       /* O_EXCL is meaningless without O_CREAT */
                case O_TRUNC:
                case O_TRUNC | O_EXCL:
                        return TRUNCATE_EXISTING;
@@ -40,6 +45,7 @@ openFlagsToCreateFileFlags(int openFlags)
                case O_CREAT | O_TRUNC:
                        return CREATE_ALWAYS;
 
+                       /* O_TRUNC is meaningless with O_CREAT */
                case O_CREAT | O_EXCL:
                case O_CREAT | O_TRUNC | O_EXCL:
                        return CREATE_NEW;
@@ -51,65 +57,111 @@ openFlagsToCreateFileFlags(int openFlags)
 
 /*
  *      - file attribute setting, based on fileMode?
- *      - handle other flags? (eg FILE_FLAG_NO_BUFFERING/FILE_FLAG_WRITE_THROUGH)
  */
 int
-win32_open(const char *fileName, int fileFlags,...)
+pgwin32_open(const char *fileName, int fileFlags,...)
 {
        int                     fd;
-       HANDLE          h;
+       HANDLE          h = INVALID_HANDLE_VALUE;
        SECURITY_ATTRIBUTES sa;
+       int                     loops = 0;
 
        /* Check that we can handle the request */
        assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND |
                                                 (O_RANDOM | O_SEQUENTIAL | O_TEMPORARY) |
-                                                _O_SHORT_LIVED | O_SYNC |
-         (O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags);
+                                                _O_SHORT_LIVED | O_DSYNC | O_DIRECT |
+                 (O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags);
 
        sa.nLength = sizeof(sa);
        sa.bInheritHandle = TRUE;
        sa.lpSecurityDescriptor = NULL;
 
-       if ((h = CreateFile(fileName,
+       while ((h = CreateFile(fileName,
        /* cannot use O_RDONLY, as it == 0 */
-                                 (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :
-                                ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ),
-                               /* These flags allow concurrent rename/unlink */
-                               (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
-                                               &sa,
-                                               openFlagsToCreateFileFlags(fileFlags),
-                                               FILE_ATTRIBUTE_NORMAL |
-                                ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) |
-                  ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) |
-                 ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) |
-                        ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0)|
-                                       ((fileFlags & O_SYNC) ? FILE_FLAG_WRITE_THROUGH : 0),
-                                               NULL)) == INVALID_HANDLE_VALUE)
+                                         (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :
+                                        ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ),
+       /* These flags allow concurrent rename/unlink */
+                                       (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
+                                                  &sa,
+                                                  openFlagsToCreateFileFlags(fileFlags),
+                                                  FILE_ATTRIBUTE_NORMAL |
+                                        ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) |
+                          ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) |
+                         ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) |
+                               ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) |
+                                         ((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) |
+                                          ((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0),
+                                                  NULL)) == INVALID_HANDLE_VALUE)
        {
-               switch (GetLastError())
+               /*
+                * Sharing violation or locking error can indicate antivirus, backup
+                * or similar software that's locking the file. Try again for 30
+                * seconds before giving up.
+                */
+               DWORD           err = GetLastError();
+
+               if (err == ERROR_SHARING_VIOLATION ||
+                       err == ERROR_LOCK_VIOLATION)
                {
-                               /* EMFILE, ENFILE should not occur from CreateFile. */
-                       case ERROR_PATH_NOT_FOUND:
-                       case ERROR_FILE_NOT_FOUND:
-                               errno = ENOENT;
-                               break;
-                       case ERROR_FILE_EXISTS:
-                               errno = EEXIST;
-                               break;
-                       case ERROR_ACCESS_DENIED:
-                               errno = EACCES;
-                               break;
-                       default:
-                               errno = EINVAL;
+                       pg_usleep(100000);
+                       loops++;
+
+#ifndef FRONTEND
+                       if (loops == 50)
+                               ereport(LOG,
+                                               (errmsg("could not open file \"%s\": %s", fileName,
+                                                               (err == ERROR_SHARING_VIOLATION) ? _("sharing violation") : _("lock violation")),
+                                                errdetail("Continuing to retry for 30 seconds."),
+                                                errhint("You might have antivirus, backup, or similar software interfering with the database system.")));
+#endif
+
+                       if (loops < 300)
+                               continue;
                }
+
+               _dosmaperr(err);
                return -1;
        }
 
        /* _open_osfhandle will, on error, set errno accordingly */
-       if ((fd = _open_osfhandle((long) h, fileFlags & O_APPEND)) < 0 ||
-               (fileFlags & (O_TEXT | O_BINARY) && (_setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0)))
+       if ((fd = _open_osfhandle((intptr_t) h, fileFlags & O_APPEND)) < 0)
                CloseHandle(h);                 /* will not affect errno */
+       else if (fileFlags & (O_TEXT | O_BINARY) &&
+                        _setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0)
+       {
+               _close(fd);
+               return -1;
+       }
+
        return fd;
 }
 
+FILE *
+pgwin32_fopen(const char *fileName, const char *mode)
+{
+       int                     openmode = 0;
+       int                     fd;
+
+       if (strstr(mode, "r+"))
+               openmode |= O_RDWR;
+       else if (strchr(mode, 'r'))
+               openmode |= O_RDONLY;
+       if (strstr(mode, "w+"))
+               openmode |= O_RDWR | O_CREAT | O_TRUNC;
+       else if (strchr(mode, 'w'))
+               openmode |= O_WRONLY | O_CREAT | O_TRUNC;
+       if (strchr(mode, 'a'))
+               openmode |= O_WRONLY | O_CREAT | O_APPEND;
+
+       if (strchr(mode, 'b'))
+               openmode |= O_BINARY;
+       if (strchr(mode, 't'))
+               openmode |= O_TEXT;
+
+       fd = pgwin32_open(fileName, openmode);
+       if (fd == -1)
+               return NULL;
+       return _fdopen(fd, mode);
+}
+
 #endif