|
|
|
|
@ -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 $ |
|
|
|
|
* |
|
|
|
|
*------------------------------------------------------------------------- |
|
|
|
|
*/ |
|
|
|
|
@ -33,10 +33,14 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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; |
|
|
|
|
|