]> 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 627922b600e4739d90a2ab5d1d4cecdea2c0ea61..e91641d2a7c3c08edb34786baa4fb7e2c5e54ff0 100644 (file)
@@ -4,37 +4,51 @@
  *        Win32 open() replacement
  *
  *
- * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/port/open.c,v 1.2 2004/04/19 17:42:59 momjian Exp $
+ * src/port/open.c
  *
  *-------------------------------------------------------------------------
  */
 
 #ifdef WIN32
 
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
 #include <windows.h>
 #include <fcntl.h>
-#include <errno.h>
 #include <assert.h>
 
+
 static int
 openFlagsToCreateFileFlags(int openFlags)
 {
-       switch (openFlags & (O_CREAT|O_TRUNC|O_EXCL))
+       switch (openFlags & (O_CREAT | O_TRUNC | O_EXCL))
        {
+                       /* O_EXCL is meaningless without O_CREAT */
                case 0:
-               case O_EXCL:    return OPEN_EXISTING;
+               case O_EXCL:
+                       return OPEN_EXISTING;
 
-               case O_CREAT:   return OPEN_ALWAYS;
+               case O_CREAT:
+                       return OPEN_ALWAYS;
 
+                       /* O_EXCL is meaningless without O_CREAT */
                case O_TRUNC:
-               case O_TRUNC|O_EXCL:    return TRUNCATE_EXISTING;
+               case O_TRUNC | O_EXCL:
+                       return TRUNCATE_EXISTING;
 
-               case O_CREAT|O_TRUNC:   return CREATE_ALWAYS;
+               case O_CREAT | O_TRUNC:
+                       return CREATE_ALWAYS;
 
-               case O_CREAT|O_EXCL:
-               case O_CREAT|O_TRUNC|O_EXCL:    return CREATE_NEW;
+                       /* O_TRUNC is meaningless with O_CREAT */
+               case O_CREAT | O_EXCL:
+               case O_CREAT | O_TRUNC | O_EXCL:
+                       return CREATE_NEW;
        }
 
        /* will never get here */
@@ -42,57 +56,112 @@ openFlagsToCreateFileFlags(int openFlags)
 }
 
 /*
- *   - file attribute setting, based on fileMode?
- *   - handle other flags? (eg FILE_FLAG_NO_BUFFERING/FILE_FLAG_WRITE_THROUGH)
+ *      - file attribute setting, based on fileMode?
  */
-int win32_open(const char* fileName, int fileFlags, ...)
+int
+pgwin32_open(const char *fileName, int fileFlags,...)
 {
-       int fd;
-       HANDLE h;
+       int                     fd;
+       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_CREAT|O_TRUNC|O_EXCL) | (O_TEXT|O_BINARY))) == fileFlags);
-
-       sa.nLength=sizeof(sa);
-       sa.bInheritHandle=TRUE;
-       sa.lpSecurityDescriptor=NULL;
-
-       if ((h = CreateFile(fileName,
-                                               /* cannot use O_RDONLY, as it == 0 */
-                                               (fileFlags & O_RDWR)     ? (GENERIC_WRITE | GENERIC_READ) :
-                                               ((fileFlags &  O_WRONLY) ?  GENERIC_WRITE : GENERIC_READ),
-                                               (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),
-                                               NULL)) == INVALID_HANDLE_VALUE)
+       assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND |
+                                                (O_RANDOM | O_SEQUENTIAL | O_TEMPORARY) |
+                                                _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;
+
+       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_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)))
-               CloseHandle(h); /* will not affect errno */
+       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