Add num_done counter to the pg_stat_checkpointer view.
[pgsql.git] / src / port / open.c
blob13e49af8d4fba76424e854cb12a29ab64284e9df
1 /*-------------------------------------------------------------------------
3 * open.c
4 * Win32 open() replacement
7 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
9 * src/port/open.c
11 *-------------------------------------------------------------------------
14 #ifdef WIN32
16 #ifndef FRONTEND
17 #include "postgres.h"
18 #else
19 #include "postgres_fe.h"
20 #endif
22 #include "port/win32ntdll.h"
24 #include <fcntl.h>
25 #include <assert.h>
26 #include <sys/stat.h>
28 static int
29 openFlagsToCreateFileFlags(int openFlags)
31 switch (openFlags & (O_CREAT | O_TRUNC | O_EXCL))
33 /* O_EXCL is meaningless without O_CREAT */
34 case 0:
35 case O_EXCL:
36 return OPEN_EXISTING;
38 case O_CREAT:
39 return OPEN_ALWAYS;
41 /* O_EXCL is meaningless without O_CREAT */
42 case O_TRUNC:
43 case O_TRUNC | O_EXCL:
44 return TRUNCATE_EXISTING;
46 case O_CREAT | O_TRUNC:
47 return CREATE_ALWAYS;
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;
55 /* will never get here */
56 return 0;
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.
64 HANDLE
65 pgwin32_open_handle(const char *fileName, int fileFlags, bool backup_semantics)
67 HANDLE h;
68 SECURITY_ATTRIBUTES sa;
69 int loops = 0;
71 if (initialize_ntdll() < 0)
72 return INVALID_HANDLE_VALUE;
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);
80 sa.nLength = sizeof(sa);
81 sa.bInheritHandle = TRUE;
82 sa.lpSecurityDescriptor = NULL;
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)
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.
107 DWORD err = GetLastError();
109 if (err == ERROR_SHARING_VIOLATION ||
110 err == ERROR_LOCK_VIOLATION)
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
121 if (loops < 300)
123 pg_usleep(100000);
124 loops++;
125 continue;
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.
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).
141 if (err == ERROR_ACCESS_DENIED &&
142 pg_RtlGetLastNtStatus() == STATUS_DELETE_PENDING)
144 if (fileFlags & O_CREAT)
145 err = ERROR_FILE_EXISTS;
146 else
147 err = ERROR_FILE_NOT_FOUND;
150 _dosmaperr(err);
151 return INVALID_HANDLE_VALUE;
154 return h;
158 pgwin32_open(const char *fileName, int fileFlags,...)
160 HANDLE h;
161 int fd;
163 h = pgwin32_open_handle(fileName, fileFlags, false);
164 if (h == INVALID_HANDLE_VALUE)
165 return -1;
167 #ifdef FRONTEND
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.
177 if ((fileFlags & O_BINARY) == 0)
178 fileFlags |= O_TEXT;
179 #endif
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)
187 _close(fd);
188 return -1;
191 return fd;
194 FILE *
195 pgwin32_fopen(const char *fileName, const char *mode)
197 int openmode = 0;
198 int fd;
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;
211 if (strchr(mode, 'b'))
212 openmode |= O_BINARY;
213 if (strchr(mode, 't'))
214 openmode |= O_TEXT;
216 fd = pgwin32_open(fileName, openmode);
217 if (fd == -1)
218 return NULL;
219 return _fdopen(fd, mode);
222 #endif