Re: Win32 tablespace - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: Win32 tablespace
Date
Msg-id 200408072149.i77LnlW08410@candle.pha.pa.us
Whole thread Raw
In response to Win32 tablespace  (Andreas Pflug <pgadmin@pse-consulting.de>)
Responses Re: Win32 tablespace
List pgsql-patches
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 majordomo@postgresql.org so that your
>       message can get through to the mailing list cleanly

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (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;

pgsql-patches by date:

Previous
From: Oliver Elphick
Date:
Subject: Re: [HACKERS] UNICODE characters above 0x10000
Next
From: Bruce Momjian
Date:
Subject: Re: Patch for Array min() / max()