]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
The attached patch implements a symlink for win32 using junctions, and
authorBruce Momjian <bruce@momjian.us>
Sat, 7 Aug 2004 21:48:09 +0000 (21:48 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 7 Aug 2004 21:48:09 +0000 (21:48 +0000)
uses that for win32 tablespaces.

Andreas Pflug

src/include/port.h
src/port/dirmod.c

index 731ec4120a41d2191feb5794814b67865086f784..10387b6201636e188f5901c5dd9ccdd91bedf876 100644 (file)
@@ -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);
index 912a0c1ca8e13b6c0a20effde3ba9165a88322d6..3010127c4c2215dfc2e4cdbd621550f2ca948f47 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 
 #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;