|
@@ -35,10 +35,12 @@
|
|
|
#include <fstream>
|
|
#include <fstream>
|
|
|
#include <sstream>
|
|
#include <sstream>
|
|
|
#include <set>
|
|
#include <set>
|
|
|
|
|
+#include <vector>
|
|
|
|
|
|
|
|
// Work-around CMake dependency scanning limitation. This must
|
|
// Work-around CMake dependency scanning limitation. This must
|
|
|
// duplicate the above list of headers.
|
|
// duplicate the above list of headers.
|
|
|
#if 0
|
|
#if 0
|
|
|
|
|
+# include "RegularExpression.hxx.in"
|
|
|
# include "SystemTools.hxx.in"
|
|
# include "SystemTools.hxx.in"
|
|
|
# include "Directory.hxx.in"
|
|
# include "Directory.hxx.in"
|
|
|
# include "FStream.hxx.in"
|
|
# include "FStream.hxx.in"
|
|
@@ -87,6 +89,7 @@
|
|
|
// Windows API.
|
|
// Windows API.
|
|
|
#if defined(_WIN32)
|
|
#if defined(_WIN32)
|
|
|
# include <windows.h>
|
|
# include <windows.h>
|
|
|
|
|
+# include <winioctl.h>
|
|
|
# ifndef INVALID_FILE_ATTRIBUTES
|
|
# ifndef INVALID_FILE_ATTRIBUTES
|
|
|
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
|
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
|
|
# endif
|
|
# endif
|
|
@@ -2754,6 +2757,106 @@ std::string SystemTools::GetLastSystemError()
|
|
|
return strerror(e);
|
|
return strerror(e);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+#ifdef _WIN32
|
|
|
|
|
+
|
|
|
|
|
+static bool IsJunction(const std::wstring& source)
|
|
|
|
|
+{
|
|
|
|
|
+#ifdef FSCTL_GET_REPARSE_POINT
|
|
|
|
|
+ const DWORD JUNCTION_ATTRS = FILE_ATTRIBUTE_DIRECTORY |
|
|
|
|
|
+ FILE_ATTRIBUTE_REPARSE_POINT;
|
|
|
|
|
+ DWORD attrs = GetFileAttributesW(source.c_str());
|
|
|
|
|
+ if (attrs == INVALID_FILE_ATTRIBUTES)
|
|
|
|
|
+ {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ if ((attrs & JUNCTION_ATTRS) != JUNCTION_ATTRS)
|
|
|
|
|
+ {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Adjust privileges so that we can succefully open junction points.
|
|
|
|
|
+ HANDLE token;
|
|
|
|
|
+ TOKEN_PRIVILEGES privs;
|
|
|
|
|
+ OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token);
|
|
|
|
|
+ LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &privs.Privileges[0].Luid);
|
|
|
|
|
+ privs.PrivilegeCount = 1;
|
|
|
|
|
+ privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
|
+ AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
|
|
|
|
|
+ CloseHandle(token);
|
|
|
|
|
+
|
|
|
|
|
+ HANDLE dir = CreateFileW(source.c_str(), GENERIC_READ,
|
|
|
|
|
+ 0, NULL, OPEN_EXISTING,
|
|
|
|
|
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
|
|
|
+ if (dir == INVALID_HANDLE_VALUE)
|
|
|
|
|
+ {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Query whether this is a reparse point or not.
|
|
|
|
|
+ BYTE buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
|
|
|
|
+ REPARSE_GUID_DATA_BUFFER *reparse_buffer =
|
|
|
|
|
+ (REPARSE_GUID_DATA_BUFFER*) buffer;
|
|
|
|
|
+ DWORD sentinel;
|
|
|
|
|
+
|
|
|
|
|
+ BOOL success = DeviceIoControl(
|
|
|
|
|
+ dir, FSCTL_GET_REPARSE_POINT,
|
|
|
|
|
+ NULL, 0,
|
|
|
|
|
+ reparse_buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
|
|
|
|
|
+ &sentinel, NULL);
|
|
|
|
|
+
|
|
|
|
|
+ CloseHandle(dir);
|
|
|
|
|
+
|
|
|
|
|
+ return (success && (reparse_buffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT));
|
|
|
|
|
+#else
|
|
|
|
|
+ return false;
|
|
|
|
|
+#endif
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static bool DeleteJunction(const std::wstring& source)
|
|
|
|
|
+{
|
|
|
|
|
+#ifdef FSCTL_DELETE_REPARSE_POINT
|
|
|
|
|
+ // Adjust privileges so that we can succefully open junction points as
|
|
|
|
|
+ // read/write.
|
|
|
|
|
+ HANDLE token;
|
|
|
|
|
+ TOKEN_PRIVILEGES privs;
|
|
|
|
|
+ OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token);
|
|
|
|
|
+ LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &privs.Privileges[0].Luid);
|
|
|
|
|
+ privs.PrivilegeCount = 1;
|
|
|
|
|
+ privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
|
+ AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
|
|
|
|
|
+ CloseHandle(token);
|
|
|
|
|
+
|
|
|
|
|
+ HANDLE dir = CreateFileW(source.c_str(), GENERIC_READ | GENERIC_WRITE,
|
|
|
|
|
+ 0, NULL, OPEN_EXISTING,
|
|
|
|
|
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
|
|
|
+ if (dir == INVALID_HANDLE_VALUE)
|
|
|
|
|
+ {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Set up the structure so that we can delete the junction.
|
|
|
|
|
+ std::vector<BYTE> buffer(REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, 0);
|
|
|
|
|
+ REPARSE_GUID_DATA_BUFFER *reparse_buffer =
|
|
|
|
|
+ (REPARSE_GUID_DATA_BUFFER*) &buffer[0];
|
|
|
|
|
+ DWORD sentinel;
|
|
|
|
|
+
|
|
|
|
|
+ reparse_buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
|
|
|
|
+
|
|
|
|
|
+ BOOL success = DeviceIoControl(
|
|
|
|
|
+ dir, FSCTL_DELETE_REPARSE_POINT,
|
|
|
|
|
+ reparse_buffer, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
|
|
|
|
|
+ NULL, 0,
|
|
|
|
|
+ &sentinel, NULL);
|
|
|
|
|
+
|
|
|
|
|
+ CloseHandle(dir);
|
|
|
|
|
+
|
|
|
|
|
+ return !!success;
|
|
|
|
|
+#else
|
|
|
|
|
+ return false;
|
|
|
|
|
+#endif
|
|
|
|
|
+}
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
bool SystemTools::RemoveFile(const std::string& source)
|
|
bool SystemTools::RemoveFile(const std::string& source)
|
|
|
{
|
|
{
|
|
|
#ifdef _WIN32
|
|
#ifdef _WIN32
|
|
@@ -2781,6 +2884,10 @@ bool SystemTools::RemoveFile(const std::string& source)
|
|
|
SetLastError(err);
|
|
SetLastError(err);
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
+ if (IsJunction(ws) && !DeleteJunction(ws))
|
|
|
|
|
+ {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
if (DeleteFileW(ws.c_str()) ||
|
|
if (DeleteFileW(ws.c_str()) ||
|
|
|
GetLastError() == ERROR_FILE_NOT_FOUND ||
|
|
GetLastError() == ERROR_FILE_NOT_FOUND ||
|
|
|
GetLastError() == ERROR_PATH_NOT_FOUND)
|
|
GetLastError() == ERROR_PATH_NOT_FOUND)
|