The attached patch implements a symlink for win32 using junctions, and uses that for win32 tablespaces.

Regards,
Andreas

Index: tablespace.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/tablespace.c,v
retrieving revision 1.7
diff -u -r1.7 tablespace.c
--- tablespace.c	1 Aug 2004 20:30:48 -0000	1.7
+++ tablespace.c	5 Aug 2004 13:36:48 -0000
@@ -77,6 +77,113 @@
 static bool directory_is_empty(const char *path);
 
 
+
+#ifdef WIN32
+
+#define symlink pgsymlink
+#define HAVE_SYMLINK
+
+#include "winioctl.h"
+
+int pgsymlink(const char *oldpath, const char *newpath);
+
+
+/*
+ * 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)
+
+    
+int
+pgsymlink(const char *oldpath, const char *newpath)
+{
+    HANDLE dirhandle;
+    DWORD len;
+    
+    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);
+    
+    char *p=nativeTarget;
+    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
+
+
 /*
  * Each database using a table space is isolated into its own name space
  * by a subdirectory named for the database OID.  On first creation of an
@@ -482,11 +589,19 @@
 				 errmsg("could not unlink file \"%s\": %m",
 						subfile)));
 
+#ifdef WIN32
+        if (rmdir(location) < 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not remove junction dir \"%s\": %m",
+						location)));
+#else
 	if (unlink(location) < 0)
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not unlink symbolic link \"%s\": %m",
 						location)));
+#endif
 
 	pfree(subfile);
 	pfree(location);
---------------------------(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

Reply via email to