PostgreSQL Source Code  git master
open.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * open.c
4  * Win32 open() replacement
5  *
6  *
7  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8  *
9  * src/port/open.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 
14 #ifdef WIN32
15 
16 #ifndef FRONTEND
17 #include "postgres.h"
18 #else
19 #include "postgres_fe.h"
20 #endif
21 
22 #include "port/win32ntdll.h"
23 
24 #include <fcntl.h>
25 #include <assert.h>
26 #include <sys/stat.h>
27 
28 static int
29 openFlagsToCreateFileFlags(int openFlags)
30 {
31  switch (openFlags & (O_CREAT | O_TRUNC | O_EXCL))
32  {
33  /* O_EXCL is meaningless without O_CREAT */
34  case 0:
35  case O_EXCL:
36  return OPEN_EXISTING;
37 
38  case O_CREAT:
39  return OPEN_ALWAYS;
40 
41  /* O_EXCL is meaningless without O_CREAT */
42  case O_TRUNC:
43  case O_TRUNC | O_EXCL:
44  return TRUNCATE_EXISTING;
45 
46  case O_CREAT | O_TRUNC:
47  return CREATE_ALWAYS;
48 
49  /* O_TRUNC is meaningless with O_CREAT */
50  case O_CREAT | O_EXCL:
51  case O_CREAT | O_TRUNC | O_EXCL:
52  return CREATE_NEW;
53  }
54 
55  /* will never get here */
56  return 0;
57 }
58 
59 /*
60  * Internal function used by pgwin32_open() and _pgstat64(). When
61  * backup_semantics is true, directories may be opened (for limited uses). On
62  * failure, INVALID_HANDLE_VALUE is returned and errno is set.
63  */
64 HANDLE
65 pgwin32_open_handle(const char *fileName, int fileFlags, bool backup_semantics)
66 {
67  HANDLE h;
68  SECURITY_ATTRIBUTES sa;
69  int loops = 0;
70 
71  if (initialize_ntdll() < 0)
72  return INVALID_HANDLE_VALUE;
73 
74  /* Check that we can handle the request */
75  assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND |
76  (O_RANDOM | O_SEQUENTIAL | O_TEMPORARY) |
77  _O_SHORT_LIVED | O_DSYNC | O_DIRECT |
78  (O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags);
79 
80  sa.nLength = sizeof(sa);
81  sa.bInheritHandle = TRUE;
82  sa.lpSecurityDescriptor = NULL;
83 
84  while ((h = CreateFile(fileName,
85  /* cannot use O_RDONLY, as it == 0 */
86  (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :
87  ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ),
88  /* These flags allow concurrent rename/unlink */
89  (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
90  &sa,
91  openFlagsToCreateFileFlags(fileFlags),
92  FILE_ATTRIBUTE_NORMAL |
93  (backup_semantics ? FILE_FLAG_BACKUP_SEMANTICS : 0) |
94  ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) |
95  ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) |
96  ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) |
97  ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) |
98  ((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) |
99  ((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0),
100  NULL)) == INVALID_HANDLE_VALUE)
101  {
102  /*
103  * Sharing violation or locking error can indicate antivirus, backup
104  * or similar software that's locking the file. Wait a bit and try
105  * again, giving up after 30 seconds.
106  */
107  DWORD err = GetLastError();
108 
109  if (err == ERROR_SHARING_VIOLATION ||
110  err == ERROR_LOCK_VIOLATION)
111  {
112 #ifndef FRONTEND
113  if (loops == 50)
114  ereport(LOG,
115  (errmsg("could not open file \"%s\": %s", fileName,
116  (err == ERROR_SHARING_VIOLATION) ? _("sharing violation") : _("lock violation")),
117  errdetail("Continuing to retry for 30 seconds."),
118  errhint("You might have antivirus, backup, or similar software interfering with the database system.")));
119 #endif
120 
121  if (loops < 300)
122  {
123  pg_usleep(100000);
124  loops++;
125  continue;
126  }
127  }
128 
129  /*
130  * ERROR_ACCESS_DENIED is returned if the file is deleted but not yet
131  * gone (Windows NT status code is STATUS_DELETE_PENDING). In that
132  * case, we'd better ask for the NT status too so we can translate it
133  * to a more Unix-like error. We hope that nothing clobbers the NT
134  * status in between the internal NtCreateFile() call and CreateFile()
135  * returning.
136  *
137  * If there's no O_CREAT flag, then we'll pretend the file is
138  * invisible. With O_CREAT, we have no choice but to report that
139  * there's a file in the way (which wouldn't happen on Unix).
140  */
141  if (err == ERROR_ACCESS_DENIED &&
142  pg_RtlGetLastNtStatus() == STATUS_DELETE_PENDING)
143  {
144  if (fileFlags & O_CREAT)
145  err = ERROR_FILE_EXISTS;
146  else
147  err = ERROR_FILE_NOT_FOUND;
148  }
149 
150  _dosmaperr(err);
151  return INVALID_HANDLE_VALUE;
152  }
153 
154  return h;
155 }
156 
157 int
158 pgwin32_open(const char *fileName, int fileFlags,...)
159 {
160  HANDLE h;
161  int fd;
162 
163  h = pgwin32_open_handle(fileName, fileFlags, false);
164  if (h == INVALID_HANDLE_VALUE)
165  return -1;
166 
167 #ifdef FRONTEND
168 
169  /*
170  * Since PostgreSQL 12, those concurrent-safe versions of open() and
171  * fopen() can be used by frontends, having as side-effect to switch the
172  * file-translation mode from O_TEXT to O_BINARY if none is specified.
173  * Caller may want to enforce the binary or text mode, but if nothing is
174  * defined make sure that the default mode maps with what versions older
175  * than 12 have been doing.
176  */
177  if ((fileFlags & O_BINARY) == 0)
178  fileFlags |= O_TEXT;
179 #endif
180 
181  /* _open_osfhandle will, on error, set errno accordingly */
182  if ((fd = _open_osfhandle((intptr_t) h, fileFlags & O_APPEND)) < 0)
183  CloseHandle(h); /* will not affect errno */
184  else if (fileFlags & (O_TEXT | O_BINARY) &&
185  _setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0)
186  {
187  _close(fd);
188  return -1;
189  }
190 
191  return fd;
192 }
193 
194 FILE *
195 pgwin32_fopen(const char *fileName, const char *mode)
196 {
197  int openmode = 0;
198  int fd;
199 
200  if (strstr(mode, "r+"))
201  openmode |= O_RDWR;
202  else if (strchr(mode, 'r'))
203  openmode |= O_RDONLY;
204  if (strstr(mode, "w+"))
205  openmode |= O_RDWR | O_CREAT | O_TRUNC;
206  else if (strchr(mode, 'w'))
207  openmode |= O_WRONLY | O_CREAT | O_TRUNC;
208  if (strchr(mode, 'a'))
209  openmode |= O_WRONLY | O_CREAT | O_APPEND;
210 
211  if (strchr(mode, 'b'))
212  openmode |= O_BINARY;
213  if (strchr(mode, 't'))
214  openmode |= O_TEXT;
215 
216  fd = pgwin32_open(fileName, openmode);
217  if (fd == -1)
218  return NULL;
219  return _fdopen(fd, mode);
220 }
221 
222 #endif
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define _(x)
Definition: elog.c:90
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
void err(int eval, const char *fmt,...)
Definition: err.c:43
static PgChecksumMode mode
Definition: pg_checksums.c:56
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define assert(x)
Definition: regcustom.h:56
void pg_usleep(long microsec)
Definition: signal.c:53
void _dosmaperr(unsigned long)
Definition: win32error.c:177
#define O_DSYNC
Definition: win32_port.h:352
int initialize_ntdll(void)
Definition: win32ntdll.c:39
PGDLLIMPORT RtlGetLastNtStatus_t pg_RtlGetLastNtStatus
Definition: win32ntdll.c:20