Skip to content

Commit 53e8bec

Browse files
committed
The attached patch implements a symlink for win32 using junctions, and
uses that for win32 tablespaces. Andreas Pflug
1 parent 27fedc8 commit 53e8bec

File tree

2 files changed

+134
-18
lines changed

2 files changed

+134
-18
lines changed

src/include/port.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/port.h,v 1.47 2004/08/01 06:56:39 momjian Exp $
9+
* $PostgreSQL: pgsql/src/include/port.h,v 1.48 2004/08/07 21:48:09 momjian Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -80,7 +80,7 @@ extern void set_pglocale_pgservice(const char *argv0, const char *app);
8080
extern int find_my_exec(const char *argv0, char *retpath);
8181
extern int find_other_exec(const char *argv0, const char *target,
8282
const char *versionstr, char *retpath);
83-
#if defined(__CYGWIN__) || defined(WIN32)
83+
#if defined(WIN32) || defined(__CYGWIN__)
8484
#define EXE ".exe"
8585
#define DEVNULL "nul"
8686
#else
@@ -140,14 +140,17 @@ extern int pgkill(int pid, int sig);
140140

141141
extern int pclose_check(FILE *stream);
142142

143-
#if defined(__MINGW32__) || defined(__CYGWIN__)
143+
#if defined(WIN32) || defined(__CYGWIN__)
144144
/*
145-
* Win32 doesn't have reliable rename/unlink during concurrent access
145+
* Win32 doesn't have reliable rename/unlink during concurrent access,
146+
* and we need special code to do symlinks.
146147
*/
147148
extern int pgrename(const char *from, const char *to);
148149
extern int pgunlink(const char *path);
149-
#define rename(from, to) pgrename(from, to)
150-
#define unlink(path) pgunlink(path)
150+
extern int pgsymlink(const char *oldpath, const char *newpath);
151+
#define rename(from, to) pgrename(from, to)
152+
#define unlink(path) pgunlink(path)
153+
#define symlink(oldpath, newpath) pgsymlink(oldpath, newpath)
151154
#endif
152155

153156
extern bool rmtree(char *path, bool rmtopdir);

src/port/dirmod.c

Lines changed: 125 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Win32 (NT, Win2k, XP). replace() doesn't work on Win95/98/Me.
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/port/dirmod.c,v 1.13 2004/08/01 06:19:26 momjian Exp $
13+
* $PostgreSQL: pgsql/src/port/dirmod.c,v 1.14 2004/08/07 21:48:09 momjian Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -33,10 +33,14 @@
3333

3434

3535
#include "miscadmin.h"
36+
#include <winioctl.h>
3637

3738
#undef rename
3839
#undef unlink
3940

41+
/*
42+
* pgrename
43+
*/
4044
int
4145
pgrename(const char *from, const char *to)
4246
{
@@ -79,6 +83,9 @@ pgrename(const char *from, const char *to)
7983
}
8084

8185

86+
/*
87+
* pgunlink
88+
*/
8289
int
8390
pgunlink(const char *path)
8491
{
@@ -110,12 +117,119 @@ pgunlink(const char *path)
110117
return 0;
111118
}
112119

120+
121+
/*
122+
* pgsymlink support:
123+
*
124+
* This struct is a replacement for REPARSE_DATA_BUFFER which is defined in VC6 winnt.h
125+
* but omitted in later SDK functions.
126+
* We only need the SymbolicLinkReparseBuffer part of the original struct's union.
127+
*/
128+
typedef struct
129+
{
130+
DWORD ReparseTag;
131+
WORD ReparseDataLength;
132+
WORD Reserved;
133+
/* SymbolicLinkReparseBuffer */
134+
WORD SubstituteNameOffset;
135+
WORD SubstituteNameLength;
136+
WORD PrintNameOffset;
137+
WORD PrintNameLength;
138+
WCHAR PathBuffer[1];
139+
}
140+
REPARSE_JUNCTION_DATA_BUFFER;
141+
142+
#define REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE \
143+
FIELD_OFFSET(REPARSE_JUNCTION_DATA_BUFFER, SubstituteNameOffset)
144+
145+
146+
/*
147+
* pgsymlink - uses Win32 junction points
148+
*
149+
* For reference: http://www.codeproject.com/w2k/junctionpoints.asp
150+
*/
151+
int
152+
pgsymlink(const char *oldpath, const char *newpath)
153+
{
154+
HANDLE dirhandle;
155+
DWORD len;
156+
char *p = nativeTarget;
157+
char buffer[MAX_PATH*sizeof(WCHAR) + sizeof(REPARSE_JUNCTION_DATA_BUFFER)];
158+
char nativeTarget[MAX_PATH];
159+
REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER*)buffer;
160+
161+
CreateDirectory(newpath, 0);
162+
dirhandle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE,
163+
0, 0, OPEN_EXISTING,
164+
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0);
165+
166+
if (dirhandle == INVALID_HANDLE_VALUE)
167+
return -1;
168+
169+
/* make sure we have an unparsed native win32 path */
170+
if (memcmp("\\??\\", oldpath, 4))
171+
sprintf(nativeTarget, "\\??\\%s", oldpath);
172+
else
173+
strcpy(nativeTarget, oldpath);
174+
175+
while ((p = strchr(p, '/')) != 0)
176+
*p++ = '\\';
177+
178+
len = strlen(nativeTarget) * sizeof(WCHAR);
179+
reparseBuf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
180+
reparseBuf->ReparseDataLength = len + 12;
181+
reparseBuf->Reserved = 0;
182+
reparseBuf->SubstituteNameOffset = 0;
183+
reparseBuf->SubstituteNameLength = len;
184+
reparseBuf->PrintNameOffset = len+sizeof(WCHAR);
185+
reparseBuf->PrintNameLength = 0;
186+
MultiByteToWideChar(CP_ACP, 0, nativeTarget, -1,
187+
reparseBuf->PathBuffer, MAX_PATH);
188+
189+
/*
190+
* FSCTL_SET_REPARSE_POINT is coded differently depending on SDK version;
191+
* we use our own definition
192+
*/
193+
if (!DeviceIoControl(dirhandle,
194+
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS),
195+
reparseBuf,
196+
reparseBuf->ReparseDataLength + REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE,
197+
0, 0, &len, 0))
198+
{
199+
LPSTR msg;
200+
201+
errno=0;
202+
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
203+
NULL, GetLastError(),
204+
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
205+
(LPSTR)&msg, 0, NULL );
206+
ereport(ERROR, (errcode_for_file_access(),
207+
errmsg("Error setting junction for %s: %s", nativeTarget, msg)));
208+
209+
LocalFree(msg);
210+
211+
CloseHandle(dirhandle);
212+
RemoveDirectory(newpath);
213+
return -1;
214+
}
215+
216+
CloseHandle(dirhandle);
217+
218+
return 0;
219+
}
220+
113221
#endif
114222

223+
224+
/* ----------------
225+
* rmtree routines
226+
* ----------------
227+
*/
228+
229+
230+
/* We undefined these above, so we redefine them */
115231
#if defined(WIN32) || defined(__CYGWIN__)
116-
#define rmt_unlink(path) pgunlink(path)
117-
#else
118-
#define rmt_unlink(path) unlink(path)
232+
#define unlink(path) pgunlink(path)
119233
#endif
120234

121235
#ifdef FRONTEND
@@ -175,16 +289,15 @@ rmt_cleanup(char ** filenames)
175289
xfree(filenames);
176290
}
177291

178-
179-
180292
/*
181-
* delete a directory tree recursively
182-
* assumes path points to a valid directory
183-
* deletes everything under path
184-
* if rmtopdir is true deletes the directory too
293+
* rmtree
294+
*
295+
* Delete a directory tree recursively.
296+
* Assumes path points to a valid directory.
297+
* Deletes everything under path.
298+
* If rmtopdir is true deletes the directory too.
185299
*
186300
*/
187-
188301
bool
189302
rmtree(char *path, bool rmtopdir)
190303
{
@@ -249,7 +362,7 @@ rmtree(char *path, bool rmtopdir)
249362
}
250363
else
251364
{
252-
if (rmt_unlink(filepath) != 0)
365+
if (unlink(filepath) != 0)
253366
{
254367
rmt_cleanup(filenames);
255368
return false;

0 commit comments

Comments
 (0)