OK, applied. I moved the funciton into port/dirmod.c and cleaned up the
interface for Win32.
Would someone test this on Win32 in case I broke something? Patch
attached.
---------------------------------------------------------------------------
Andreas Pflug wrote:
> The attached patch implements a symlink for win32 using junctions, and
> uses that for win32 tablespaces.
>
> Regards,
> Andreas
>
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
> subscribe-nomail command to [EMAIL PROTECTED] so that your
> message can get through to the mailing list cleanly
--
Bruce Momjian | http://candle.pha.pa.us
[EMAIL PROTECTED] | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Index: src/include/port.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/port.h,v
retrieving revision 1.47
diff -c -c -r1.47 port.h
*** src/include/port.h 1 Aug 2004 06:56:39 -0000 1.47
--- src/include/port.h 7 Aug 2004 21:36:14 -0000
***************
*** 80,86 ****
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)
#define EXE ".exe"
#define DEVNULL "nul"
#else
--- 80,86 ----
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(WIN32) || defined(__CYGWIN__)
#define EXE ".exe"
#define DEVNULL "nul"
#else
***************
*** 140,153 ****
extern int pclose_check(FILE *stream);
! #if defined(__MINGW32__) || defined(__CYGWIN__)
/*
! * Win32 doesn't have reliable rename/unlink during concurrent access
*/
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)
#endif
extern bool rmtree(char *path, bool rmtopdir);
--- 140,156 ----
extern int pclose_check(FILE *stream);
! #if defined(WIN32) || defined(__CYGWIN__)
/*
! * 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);
! 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);
Index: src/port/dirmod.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/port/dirmod.c,v
retrieving revision 1.13
diff -c -c -r1.13 dirmod.c
*** src/port/dirmod.c 1 Aug 2004 06:19:26 -0000 1.13
--- src/port/dirmod.c 7 Aug 2004 21:36:19 -0000
***************
*** 33,42 ****
--- 33,46 ----
#include "miscadmin.h"
+ #include <winioctl.h>
#undef rename
#undef unlink
+ /*
+ * pgrename
+ */
int
pgrename(const char *from, const char *to)
{
***************
*** 79,84 ****
--- 83,91 ----
}
+ /*
+ * pgunlink
+ */
int
pgunlink(const char *path)
{
***************
*** 110,121 ****
return 0;
}
#endif
#if defined(WIN32) || defined(__CYGWIN__)
! #define rmt_unlink(path) pgunlink(path)
! #else
! #define rmt_unlink(path) unlink(path)
#endif
#ifdef FRONTEND
--- 117,235 ----
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 unlink(path) pgunlink(path)
#endif
#ifdef FRONTEND
***************
*** 175,190 ****
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
*
*/
-
bool
rmtree(char *path, bool rmtopdir)
{
--- 289,303 ----
xfree(filenames);
}
/*
! * 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,255 ****
}
else
{
! if (rmt_unlink(filepath) != 0)
{
rmt_cleanup(filenames);
return false;
--- 362,368 ----
}
else
{
! if (unlink(filepath) != 0)
{
rmt_cleanup(filenames);
return false;
---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings