1 /*-------------------------------------------------------------------------
4 * directory handling functions
6 * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * This includes replacement versions of functions that work on
10 * Win32 (NT4 and newer).
15 *-------------------------------------------------------------------------
21 #include "postgres_fe.h"
24 /* Don't modify declarations in system headers */
25 #if defined(WIN32) || defined(__CYGWIN__)
33 #if defined(WIN32) || defined(__CYGWIN__)
38 #include <w32api/winioctl.h>
42 #if defined(WIN32) || defined(__CYGWIN__)
48 pgrename(const char *from, const char *to)
53 * We need to loop because even though PostgreSQL uses flags that allow
54 * rename while the file is open, other applications might have the file
55 * open without those flags. However, we won't wait indefinitely for
56 * someone else to close the file, as the caller might be holding locks
57 * and blocking other backends.
59 #if defined(WIN32) && !defined(__CYGWIN__)
60 while (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
62 while (rename(from, to) < 0)
65 #if defined(WIN32) && !defined(__CYGWIN__)
66 DWORD err = GetLastError();
71 * Modern NT-based Windows versions return ERROR_SHARING_VIOLATION if
72 * another process has the file open without FILE_SHARE_DELETE.
73 * ERROR_LOCK_VIOLATION has also been seen with some anti-virus
74 * software. This used to check for just ERROR_ACCESS_DENIED, so
75 * presumably you can get that too with some OS versions. We don't
76 * expect real permission errors where we currently use rename().
78 if (err != ERROR_ACCESS_DENIED &&
79 err != ERROR_SHARING_VIOLATION &&
80 err != ERROR_LOCK_VIOLATION)
87 if (++loops > 100) /* time out after 10 sec */
89 pg_usleep(100000); /* us */
99 pgunlink(const char *path)
104 * We need to loop because even though PostgreSQL uses flags that allow
105 * unlink while the file is open, other applications might have the file
106 * open without those flags. However, we won't wait indefinitely for
107 * someone else to close the file, as the caller might be holding locks
108 * and blocking other backends.
114 if (++loops > 100) /* time out after 10 sec */
116 pg_usleep(100000); /* us */
121 /* We undefined these above; now redefine for possible use below */
122 #define rename(from, to) pgrename(from, to)
123 #define unlink(path) pgunlink(path)
124 #endif /* defined(WIN32) || defined(__CYGWIN__) */
127 #if defined(WIN32) && !defined(__CYGWIN__) /* Cygwin has its own symlinks */
132 * This struct is a replacement for REPARSE_DATA_BUFFER which is defined in VC6 winnt.h
133 * but omitted in later SDK functions.
134 * We only need the SymbolicLinkReparseBuffer part of the original struct's union.
139 WORD ReparseDataLength;
141 /* SymbolicLinkReparseBuffer */
142 WORD SubstituteNameOffset;
143 WORD SubstituteNameLength;
144 WORD PrintNameOffset;
145 WORD PrintNameLength;
146 WCHAR PathBuffer[FLEXIBLE_ARRAY_MEMBER];
147 } REPARSE_JUNCTION_DATA_BUFFER;
149 #define REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE \
150 FIELD_OFFSET(REPARSE_JUNCTION_DATA_BUFFER, SubstituteNameOffset)
154 * pgsymlink - uses Win32 junction points
156 * For reference: http://www.codeproject.com/KB/winsdk/junctionpoints.aspx
159 pgsymlink(const char *oldpath, const char *newpath)
163 char buffer[MAX_PATH * sizeof(WCHAR) + offsetof(REPARSE_JUNCTION_DATA_BUFFER, PathBuffer)];
164 char nativeTarget[MAX_PATH];
165 char *p = nativeTarget;
166 REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
168 CreateDirectory(newpath, 0);
169 dirhandle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE,
171 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0);
173 if (dirhandle == INVALID_HANDLE_VALUE)
176 /* make sure we have an unparsed native win32 path */
177 if (memcmp("\\??\\", oldpath, 4) != 0)
178 snprintf(nativeTarget, sizeof(nativeTarget), "\\??\\%s", oldpath);
180 strlcpy(nativeTarget, oldpath, sizeof(nativeTarget));
182 while ((p = strchr(p, '/')) != NULL)
185 len = strlen(nativeTarget) * sizeof(WCHAR);
186 reparseBuf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
187 reparseBuf->ReparseDataLength = len + 12;
188 reparseBuf->Reserved = 0;
189 reparseBuf->SubstituteNameOffset = 0;
190 reparseBuf->SubstituteNameLength = len;
191 reparseBuf->PrintNameOffset = len + sizeof(WCHAR);
192 reparseBuf->PrintNameLength = 0;
193 MultiByteToWideChar(CP_ACP, 0, nativeTarget, -1,
194 reparseBuf->PathBuffer, MAX_PATH);
197 * FSCTL_SET_REPARSE_POINT is coded differently depending on SDK version;
198 * we use our own definition
200 if (!DeviceIoControl(dirhandle,
201 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS),
203 reparseBuf->ReparseDataLength + REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE,
209 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
210 NULL, GetLastError(),
211 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
212 (LPSTR) &msg, 0, NULL);
215 (errcode_for_file_access(),
216 errmsg("could not set junction for \"%s\": %s",
217 nativeTarget, msg)));
219 fprintf(stderr, _("could not set junction for \"%s\": %s\n"),
224 CloseHandle(dirhandle);
225 RemoveDirectory(newpath);
229 CloseHandle(dirhandle);
235 * pgreadlink - uses Win32 junction points
238 pgreadlink(const char *path, char *buf, size_t size)
242 char buffer[MAX_PATH * sizeof(WCHAR) + offsetof(REPARSE_JUNCTION_DATA_BUFFER, PathBuffer)];
243 REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
247 attr = GetFileAttributes(path);
248 if (attr == INVALID_FILE_ATTRIBUTES)
250 _dosmaperr(GetLastError());
253 if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
261 FILE_SHARE_READ | FILE_SHARE_WRITE,
264 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
266 if (h == INVALID_HANDLE_VALUE)
268 _dosmaperr(GetLastError());
272 if (!DeviceIoControl(h,
273 FSCTL_GET_REPARSE_POINT,
284 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
285 NULL, GetLastError(),
286 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
287 (LPSTR) &msg, 0, NULL);
290 (errcode_for_file_access(),
291 errmsg("could not get junction for \"%s\": %s",
294 fprintf(stderr, _("could not get junction for \"%s\": %s\n"),
304 /* Got it, let's get some results from this */
305 if (reparseBuf->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
311 r = WideCharToMultiByte(CP_ACP, 0,
312 reparseBuf->PathBuffer, -1,
324 * If the path starts with "\??\", which it will do in most (all?) cases,
327 if (r > 4 && strncmp(buf, "\\??\\", 4) == 0)
329 memmove(buf, buf + 4, strlen(buf + 4) + 1);
336 * Assumes the file exists, so will return false if it doesn't
337 * (since a nonexistant file is not a junction)
340 pgwin32_is_junction(char *path)
342 DWORD attr = GetFileAttributes(path);
344 if (attr == INVALID_FILE_ATTRIBUTES)
346 _dosmaperr(GetLastError());
349 return ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT);
351 #endif /* defined(WIN32) && !defined(__CYGWIN__) */
354 #if defined(WIN32) && !defined(__CYGWIN__)
359 * The stat() function in win32 is not guaranteed to update the st_size
360 * field when run. So we define our own version that uses the Win32 API
361 * to update this field.
364 pgwin32_safestat(const char *path, struct stat * buf)
367 WIN32_FILE_ATTRIBUTE_DATA attr;
373 if (!GetFileAttributesEx(path, GetFileExInfoStandard, &attr))
375 _dosmaperr(GetLastError());
380 * XXX no support for large files here, but we don't do that in general on
383 buf->st_size = attr.nFileSizeLow;