PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 |
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
151 return INVALID_HANDLE_VALUE;
152 }
153
154 return h;
155}
156
157int
158pgwin32_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
194FILE *
195pgwin32_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:1204
int errhint(const char *fmt,...)
Definition: elog.c:1318
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define _(x)
Definition: elog.c:91
#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:55
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:342
int initialize_ntdll(void)
Definition: win32ntdll.c:39
PGDLLIMPORT RtlGetLastNtStatus_t pg_RtlGetLastNtStatus
Definition: win32ntdll.c:20