mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-03-01 19:45:33 +08:00
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.
This commit is contained in:
parent
262fbcb9dd
commit
ba7bee837e
@ -291,8 +291,11 @@ extern int pgunlink(const char *path);
|
||||
*/
|
||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||
extern int pgsymlink(const char *oldpath, const char *newpath);
|
||||
extern int pgreadlink(const char *path, char *buf, size_t size);
|
||||
extern bool pgwin32_is_junction(char *path);
|
||||
|
||||
#define symlink(oldpath, newpath) pgsymlink(oldpath, newpath)
|
||||
#define readlink(path, buf, size) pgreadlink(path, buf, size)
|
||||
#endif
|
||||
|
||||
extern void copydir(char *fromdir, char *todir, bool recurse);
|
||||
|
@ -297,6 +297,124 @@ pgsymlink(const char *oldpath, const char *newpath)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* pgreadlink - uses Win32 junction points
|
||||
*/
|
||||
int
|
||||
pgreadlink(const char *path, char *buf, size_t size)
|
||||
{
|
||||
DWORD attr;
|
||||
HANDLE h;
|
||||
char buffer[MAX_PATH * sizeof(WCHAR) + sizeof(REPARSE_JUNCTION_DATA_BUFFER)];
|
||||
REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
|
||||
DWORD len;
|
||||
int r;
|
||||
|
||||
attr = GetFileAttributes(path);
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
_dosmaperr(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
h = CreateFile(path,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
0);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
_dosmaperr(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!DeviceIoControl(h,
|
||||
FSCTL_GET_REPARSE_POINT,
|
||||
NULL,
|
||||
0,
|
||||
(LPVOID) reparseBuf,
|
||||
sizeof(buffer),
|
||||
&len,
|
||||
NULL))
|
||||
{
|
||||
LPSTR msg;
|
||||
|
||||
errno = 0;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, GetLastError(),
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
|
||||
(LPSTR) &msg, 0, NULL);
|
||||
#ifndef FRONTEND
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not get junction for \"%s\": %s",
|
||||
path, msg)));
|
||||
#else
|
||||
fprintf(stderr, _("could not get junction for \"%s\": %s\n"),
|
||||
path, msg);
|
||||
#endif
|
||||
LocalFree(msg);
|
||||
CloseHandle(h);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
CloseHandle(h);
|
||||
|
||||
/* Got it, let's get some results from this */
|
||||
if (reparseBuf->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = WideCharToMultiByte(CP_ACP, 0,
|
||||
reparseBuf->PathBuffer, -1,
|
||||
buf,
|
||||
size,
|
||||
NULL, NULL);
|
||||
|
||||
if (r <= 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the path starts with "\??\", which it will do in most (all?) cases,
|
||||
* strip those out.
|
||||
*/
|
||||
if (r > 4 && strncmp(buf, "\\??\\", 4) == 0)
|
||||
{
|
||||
memmove(buf, buf + 4, strlen(buf + 4) + 1);
|
||||
r -= 4;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assumes the file exists, so will return false if it doesn't
|
||||
* (since a nonexistant file is not a junction)
|
||||
*/
|
||||
bool
|
||||
pgwin32_is_junction(char *path)
|
||||
{
|
||||
DWORD attr = GetFileAttributes(path);
|
||||
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
_dosmaperr(GetLastError());
|
||||
return false;
|
||||
}
|
||||
return ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT);
|
||||
}
|
||||
#endif /* defined(WIN32) && !defined(__CYGWIN__) */
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user