diff --git a/src/include/port.h b/src/include/port.h index 731ec4120a41d2191feb5794814b67865086f784..10387b6201636e188f5901c5dd9ccdd91bedf876 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/port.h,v 1.47 2004/08/01 06:56:39 momjian Exp $ + * $PostgreSQL: pgsql/src/include/port.h,v 1.48 2004/08/07 21:48:09 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -80,7 +80,7 @@ extern void set_pglocale_pgservice(const char *argv0, const char *app); extern int find_my_exec(const char *argv0, char *retpath); extern int find_other_exec(const char *argv0, const char *target, const char *versionstr, char *retpath); -#if defined(__CYGWIN__) || defined(WIN32) +#if defined(WIN32) || defined(__CYGWIN__) #define EXE ".exe" #define DEVNULL "nul" #else @@ -140,14 +140,17 @@ extern int pgkill(int pid, int sig); extern int pclose_check(FILE *stream); -#if defined(__MINGW32__) || defined(__CYGWIN__) +#if defined(WIN32) || defined(__CYGWIN__) /* - * Win32 doesn't have reliable rename/unlink during concurrent access + * Win32 doesn't have reliable rename/unlink during concurrent access, + * and we need special code to do symlinks. */ extern int pgrename(const char *from, const char *to); extern int pgunlink(const char *path); -#define rename(from, to) pgrename(from, to) -#define unlink(path) pgunlink(path) +extern int pgsymlink(const char *oldpath, const char *newpath); +#define rename(from, to) pgrename(from, to) +#define unlink(path) pgunlink(path) +#define symlink(oldpath, newpath) pgsymlink(oldpath, newpath) #endif extern bool rmtree(char *path, bool rmtopdir); diff --git a/src/port/dirmod.c b/src/port/dirmod.c index 912a0c1ca8e13b6c0a20effde3ba9165a88322d6..3010127c4c2215dfc2e4cdbd621550f2ca948f47 100644 --- a/src/port/dirmod.c +++ b/src/port/dirmod.c @@ -10,7 +10,7 @@ * Win32 (NT, Win2k, XP). replace() doesn't work on Win95/98/Me. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/port/dirmod.c,v 1.13 2004/08/01 06:19:26 momjian Exp $ + * $PostgreSQL: pgsql/src/port/dirmod.c,v 1.14 2004/08/07 21:48:09 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -33,10 +33,14 @@ #include "miscadmin.h" +#include <winioctl.h> #undef rename #undef unlink +/* + * pgrename + */ int pgrename(const char *from, const char *to) { @@ -79,6 +83,9 @@ pgrename(const char *from, const char *to) } +/* + * pgunlink + */ int pgunlink(const char *path) { @@ -110,12 +117,119 @@ pgunlink(const char *path) return 0; } + +/* + * pgsymlink support: + * + * This struct is a replacement for REPARSE_DATA_BUFFER which is defined in VC6 winnt.h + * but omitted in later SDK functions. + * We only need the SymbolicLinkReparseBuffer part of the original struct's union. + */ +typedef struct +{ + DWORD ReparseTag; + WORD ReparseDataLength; + WORD Reserved; + /* SymbolicLinkReparseBuffer */ + WORD SubstituteNameOffset; + WORD SubstituteNameLength; + WORD PrintNameOffset; + WORD PrintNameLength; + WCHAR PathBuffer[1]; +} +REPARSE_JUNCTION_DATA_BUFFER; + +#define REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE \ + FIELD_OFFSET(REPARSE_JUNCTION_DATA_BUFFER, SubstituteNameOffset) + + +/* + * pgsymlink - uses Win32 junction points + * + * For reference: http://www.codeproject.com/w2k/junctionpoints.asp + */ +int +pgsymlink(const char *oldpath, const char *newpath) +{ + HANDLE dirhandle; + DWORD len; + char *p = nativeTarget; + char buffer[MAX_PATH*sizeof(WCHAR) + sizeof(REPARSE_JUNCTION_DATA_BUFFER)]; + char nativeTarget[MAX_PATH]; + REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER*)buffer; + + CreateDirectory(newpath, 0); + dirhandle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, + 0, 0, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0); + + if (dirhandle == INVALID_HANDLE_VALUE) + return -1; + + /* make sure we have an unparsed native win32 path */ + if (memcmp("\\??\\", oldpath, 4)) + sprintf(nativeTarget, "\\??\\%s", oldpath); + else + strcpy(nativeTarget, oldpath); + + while ((p = strchr(p, '/')) != 0) + *p++ = '\\'; + + len = strlen(nativeTarget) * sizeof(WCHAR); + reparseBuf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + reparseBuf->ReparseDataLength = len + 12; + reparseBuf->Reserved = 0; + reparseBuf->SubstituteNameOffset = 0; + reparseBuf->SubstituteNameLength = len; + reparseBuf->PrintNameOffset = len+sizeof(WCHAR); + reparseBuf->PrintNameLength = 0; + MultiByteToWideChar(CP_ACP, 0, nativeTarget, -1, + reparseBuf->PathBuffer, MAX_PATH); + + /* + * FSCTL_SET_REPARSE_POINT is coded differently depending on SDK version; + * we use our own definition + */ + if (!DeviceIoControl(dirhandle, + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS), + reparseBuf, + reparseBuf->ReparseDataLength + REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE, + 0, 0, &len, 0)) + { + LPSTR msg; + + errno=0; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&msg, 0, NULL ); + ereport(ERROR, (errcode_for_file_access(), + errmsg("Error setting junction for %s: %s", nativeTarget, msg))); + + LocalFree(msg); + + CloseHandle(dirhandle); + RemoveDirectory(newpath); + return -1; + } + + CloseHandle(dirhandle); + + return 0; +} + #endif + +/* ---------------- + * rmtree routines + * ---------------- + */ + + +/* We undefined these above, so we redefine them */ #if defined(WIN32) || defined(__CYGWIN__) -#define rmt_unlink(path) pgunlink(path) -#else -#define rmt_unlink(path) unlink(path) +#define unlink(path) pgunlink(path) #endif #ifdef FRONTEND @@ -175,16 +289,15 @@ rmt_cleanup(char ** filenames) xfree(filenames); } - - /* - * delete a directory tree recursively - * assumes path points to a valid directory - * deletes everything under path - * if rmtopdir is true deletes the directory too + * rmtree + * + * Delete a directory tree recursively. + * Assumes path points to a valid directory. + * Deletes everything under path. + * If rmtopdir is true deletes the directory too. * */ - bool rmtree(char *path, bool rmtopdir) { @@ -249,7 +362,7 @@ rmtree(char *path, bool rmtopdir) } else { - if (rmt_unlink(filepath) != 0) + if (unlink(filepath) != 0) { rmt_cleanup(filenames); return false;