Skip to content

Commit ba7bee8

Browse files
committed
Backport "Add pgreadlink() on Windows to read junction points".
The patch to recurseively fsync pgdata needs this, but it was only introduced in 9.1.
1 parent 262fbcb commit ba7bee8

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

src/include/port.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,11 @@ extern int pgunlink(const char *path);
291291
*/
292292
#if defined(WIN32) && !defined(__CYGWIN__)
293293
extern int pgsymlink(const char *oldpath, const char *newpath);
294+
extern int pgreadlink(const char *path, char *buf, size_t size);
295+
extern bool pgwin32_is_junction(char *path);
294296

295297
#define symlink(oldpath, newpath) pgsymlink(oldpath, newpath)
298+
#define readlink(path, buf, size) pgreadlink(path, buf, size)
296299
#endif
297300

298301
extern void copydir(char *fromdir, char *todir, bool recurse);

src/port/dirmod.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,124 @@ pgsymlink(const char *oldpath, const char *newpath)
297297

298298
return 0;
299299
}
300+
301+
/*
302+
* pgreadlink - uses Win32 junction points
303+
*/
304+
int
305+
pgreadlink(const char *path, char *buf, size_t size)
306+
{
307+
DWORD attr;
308+
HANDLE h;
309+
char buffer[MAX_PATH * sizeof(WCHAR) + sizeof(REPARSE_JUNCTION_DATA_BUFFER)];
310+
REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
311+
DWORD len;
312+
int r;
313+
314+
attr = GetFileAttributes(path);
315+
if (attr == INVALID_FILE_ATTRIBUTES)
316+
{
317+
_dosmaperr(GetLastError());
318+
return -1;
319+
}
320+
if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
321+
{
322+
errno = EINVAL;
323+
return -1;
324+
}
325+
326+
h = CreateFile(path,
327+
GENERIC_READ,
328+
FILE_SHARE_READ | FILE_SHARE_WRITE,
329+
NULL,
330+
OPEN_EXISTING,
331+
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
332+
0);
333+
if (h == INVALID_HANDLE_VALUE)
334+
{
335+
_dosmaperr(GetLastError());
336+
return -1;
337+
}
338+
339+
if (!DeviceIoControl(h,
340+
FSCTL_GET_REPARSE_POINT,
341+
NULL,
342+
0,
343+
(LPVOID) reparseBuf,
344+
sizeof(buffer),
345+
&len,
346+
NULL))
347+
{
348+
LPSTR msg;
349+
350+
errno = 0;
351+
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
352+
NULL, GetLastError(),
353+
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
354+
(LPSTR) &msg, 0, NULL);
355+
#ifndef FRONTEND
356+
ereport(ERROR,
357+
(errcode_for_file_access(),
358+
errmsg("could not get junction for \"%s\": %s",
359+
path, msg)));
360+
#else
361+
fprintf(stderr, _("could not get junction for \"%s\": %s\n"),
362+
path, msg);
363+
#endif
364+
LocalFree(msg);
365+
CloseHandle(h);
366+
errno = EINVAL;
367+
return -1;
368+
}
369+
CloseHandle(h);
370+
371+
/* Got it, let's get some results from this */
372+
if (reparseBuf->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
373+
{
374+
errno = EINVAL;
375+
return -1;
376+
}
377+
378+
r = WideCharToMultiByte(CP_ACP, 0,
379+
reparseBuf->PathBuffer, -1,
380+
buf,
381+
size,
382+
NULL, NULL);
383+
384+
if (r <= 0)
385+
{
386+
errno = EINVAL;
387+
return -1;
388+
}
389+
390+
/*
391+
* If the path starts with "\??\", which it will do in most (all?) cases,
392+
* strip those out.
393+
*/
394+
if (r > 4 && strncmp(buf, "\\??\\", 4) == 0)
395+
{
396+
memmove(buf, buf + 4, strlen(buf + 4) + 1);
397+
r -= 4;
398+
}
399+
return r;
400+
}
401+
402+
/*
403+
* Assumes the file exists, so will return false if it doesn't
404+
* (since a nonexistant file is not a junction)
405+
*/
406+
bool
407+
pgwin32_is_junction(char *path)
408+
{
409+
DWORD attr = GetFileAttributes(path);
410+
411+
if (attr == INVALID_FILE_ATTRIBUTES)
412+
{
413+
_dosmaperr(GetLastError());
414+
return false;
415+
}
416+
return ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT);
417+
}
300418
#endif /* defined(WIN32) && !defined(__CYGWIN__) */
301419

302420

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy