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-2025, 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
28static int
29openFlagsToCreateFileFlags(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 */
64HANDLE
65pgwin32_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 | O_CLOEXEC |
78 (O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags);
79
80 sa.nLength = sizeof(sa);
81 sa.lpSecurityDescriptor = NULL;
82
83 /*
84 * If O_CLOEXEC is specified, create a non-inheritable handle. Otherwise,
85 * create an inheritable handle (the default Windows behavior).
86 *
87 * Note: We could instead use SetHandleInformation() after CreateFile() to
88 * clear HANDLE_FLAG_INHERIT, but this way avoids rare leaks in
89 * multi-threaded programs that create processes, just like POSIX
90 * O_CLOEXEC.
91 */
92 sa.bInheritHandle = !(fileFlags & O_CLOEXEC);
93
94 while ((h = CreateFile(fileName,
95 /* cannot use O_RDONLY, as it == 0 */
96 (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :
97 ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ),
98 /* These flags allow concurrent rename/unlink */
99 (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
100 &sa,
101 openFlagsToCreateFileFlags(fileFlags),
102 FILE_ATTRIBUTE_NORMAL |
103 (backup_semantics ? FILE_FLAG_BACKUP_SEMANTICS : 0) |
104 ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) |
105 ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) |
106 ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) |
107 ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) |
108 ((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) |
109 ((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0),
110 NULL)) == INVALID_HANDLE_VALUE)
111 {
112 /*
113 * Sharing violation or locking error can indicate antivirus, backup
114 * or similar software that's locking the file. Wait a bit and try
115 * again, giving up after 30 seconds.
116 */
117 DWORD err = GetLastError();
118
119 if (err == ERROR_SHARING_VIOLATION ||
120 err == ERROR_LOCK_VIOLATION)
121 {
122#ifndef FRONTEND
123 if (loops == 50)
124 ereport(LOG,
125 (errmsg("could not open file \"%s\": %s", fileName,
126 (err == ERROR_SHARING_VIOLATION) ? _("sharing violation") : _("lock violation")),
127 errdetail("Continuing to retry for 30 seconds."),
128 errhint("You might have antivirus, backup, or similar software interfering with the database system.")));
129#endif
130
131 if (loops < 300)
132 {
133 pg_usleep(100000);
134 loops++;
135 continue;
136 }
137 }
138
139 /*
140 * ERROR_ACCESS_DENIED is returned if the file is deleted but not yet
141 * gone (Windows NT status code is STATUS_DELETE_PENDING). In that
142 * case, we'd better ask for the NT status too so we can translate it
143 * to a more Unix-like error. We hope that nothing clobbers the NT
144 * status in between the internal NtCreateFile() call and CreateFile()
145 * returning.
146 *
147 * If there's no O_CREAT flag, then we'll pretend the file is
148 * invisible. With O_CREAT, we have no choice but to report that
149 * there's a file in the way (which wouldn't happen on Unix).
150 */
151 if (err == ERROR_ACCESS_DENIED &&
152 pg_RtlGetLastNtStatus() == STATUS_DELETE_PENDING)
153 {
154 if (fileFlags & O_CREAT)
155 err = ERROR_FILE_EXISTS;
156 else
157 err = ERROR_FILE_NOT_FOUND;
158 }
159
161 return INVALID_HANDLE_VALUE;
162 }
163
164 return h;
165}
166
167int
168pgwin32_open(const char *fileName, int fileFlags,...)
169{
170 HANDLE h;
171 int fd;
172
173 h = pgwin32_open_handle(fileName, fileFlags, false);
174 if (h == INVALID_HANDLE_VALUE)
175 return -1;
176
177#ifdef FRONTEND
178
179 /*
180 * Since PostgreSQL 12, those concurrent-safe versions of open() and
181 * fopen() can be used by frontends, having as side-effect to switch the
182 * file-translation mode from O_TEXT to O_BINARY if none is specified.
183 * Caller may want to enforce the binary or text mode, but if nothing is
184 * defined make sure that the default mode maps with what versions older
185 * than 12 have been doing.
186 */
187 if ((fileFlags & O_BINARY) == 0)
188 fileFlags |= O_TEXT;
189#endif
190
191 /* _open_osfhandle will, on error, set errno accordingly */
192 if ((fd = _open_osfhandle((intptr_t) h, fileFlags & O_APPEND)) < 0)
193 CloseHandle(h); /* will not affect errno */
194 else if (fileFlags & (O_TEXT | O_BINARY) &&
195 _setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0)
196 {
197 _close(fd);
198 return -1;
199 }
200
201 return fd;
202}
203
204FILE *
205pgwin32_fopen(const char *fileName, const char *mode)
206{
207 int openmode = 0;
208 int fd;
209
210 if (strstr(mode, "r+"))
211 openmode |= O_RDWR;
212 else if (strchr(mode, 'r'))
213 openmode |= O_RDONLY;
214 if (strstr(mode, "w+"))
215 openmode |= O_RDWR | O_CREAT | O_TRUNC;
216 else if (strchr(mode, 'w'))
217 openmode |= O_WRONLY | O_CREAT | O_TRUNC;
218 if (strchr(mode, 'a'))
219 openmode |= O_WRONLY | O_CREAT | O_APPEND;
220
221 if (strchr(mode, 'b'))
222 openmode |= O_BINARY;
223 if (strchr(mode, 't'))
224 openmode |= O_TEXT;
225
226 fd = pgwin32_open(fileName, openmode);
227 if (fd == -1)
228 return NULL;
229 return _fdopen(fd, mode);
230}
231
232#endif
int errdetail(const char *fmt,...)
Definition: elog.c:1216
int errhint(const char *fmt,...)
Definition: elog.c:1330
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define _(x)
Definition: elog.c:91
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:150
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:57
void pg_usleep(long microsec)
Definition: signal.c:53
void _dosmaperr(unsigned long)
Definition: win32error.c:177
#define O_DIRECT
Definition: win32_port.h:345
#define O_CLOEXEC
Definition: win32_port.h:344
#define O_DSYNC
Definition: win32_port.h:346
int initialize_ntdll(void)
Definition: win32ntdll.c:39
PGDLLIMPORT RtlGetLastNtStatus_t pg_RtlGetLastNtStatus
Definition: win32ntdll.c:20