X Tutup
#include #include //****************************************************************************** //** Junction Utilities //****************************************************************************** /** * Functions used to create and analyze Windows Junction Points. * Contains code by Inv Softworks LLC, www.flexhex.com. * http://www.flexhex.com/docs/articles/hard-links.phtml * ******************************************************************************/ #define REPARSE_MOUNTPOINT_HEADER_SIZE 8 typedef struct { DWORD ReparseTag; DWORD ReparseDataLength; WORD Reserved; WORD ReparseTargetLength; WORD ReparseTargetMaximumLength; WORD Reserved1; WCHAR ReparseTarget[1]; } REPARSE_MOUNTPOINT_DATA_BUFFER, *PREPARSE_MOUNTPOINT_DATA_BUFFER; #define FSCTL_GET_REPARSE_POINT 0x000900a8 #define FSCTL_SET_REPARSE_POINT 0x000900a4 //************************************************************************** //** OpenDirectory //************************************************************************** /** Used get a handle for a given path. */ HANDLE OpenDirectory(const wchar_t* path, BOOL bReadWrite) { //Obtain restore privilege in case we don't have it HANDLE hToken; TOKEN_PRIVILEGES tp; ::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken); ::LookupPrivilegeValue(NULL, (bReadWrite ? SE_RESTORE_NAME : SE_BACKUP_NAME), &tp.Privileges[0].Luid); tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; ::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL); ::CloseHandle(hToken); //Open the directory DWORD dwAccess = bReadWrite ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ; HANDLE hDir = ::CreateFileW(path, dwAccess, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); return hDir; } #define DIR_ATTR (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT) //************************************************************************** //** IsDirectoryJunction //************************************************************************** /** Used to determine whether a given path represents a Junction point. */ BOOL IsDirectoryJunction(const wchar_t* path) { DWORD dwAttr = ::GetFileAttributesW(path); if (dwAttr == -1) return FALSE; // Not exists if ((dwAttr & DIR_ATTR) != DIR_ATTR) return FALSE; // Not dir or no reparse point HANDLE hDir = OpenDirectory(path, FALSE); if (hDir == INVALID_HANDLE_VALUE) return FALSE; // Failed to open directory BYTE buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_MOUNTPOINT_DATA_BUFFER& ReparseBuffer = (REPARSE_MOUNTPOINT_DATA_BUFFER&)buf; DWORD dwRet; BOOL br = ::DeviceIoControl(hDir, FSCTL_GET_REPARSE_POINT, NULL, 0, &ReparseBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRet, NULL); ::CloseHandle(hDir); return br ? (ReparseBuffer.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) : FALSE; } //************************************************************************** //** GetTarget //************************************************************************** /** Used to return the path for a given junction. */ LPCWSTR GetTarget(const wchar_t* path) { if (!IsDirectoryJunction(path)) { return NULL; // Throw Error: no junction here } // Open for reading only (see OpenDirectory definition above) HANDLE hDir = OpenDirectory(path, FALSE); BYTE buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; // We need a large buffer REPARSE_MOUNTPOINT_DATA_BUFFER& ReparseBuffer = (REPARSE_MOUNTPOINT_DATA_BUFFER&)buf; DWORD dwRet; if (::DeviceIoControl(hDir, FSCTL_GET_REPARSE_POINT, NULL, 0, &ReparseBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRet, NULL)) { // Success ::CloseHandle(hDir); LPCWSTR pPath = ReparseBuffer.ReparseTarget; if (wcsncmp(pPath, L"\\??\\", 4) == 0) pPath += 4; // Skip 'non-parsed' prefix return pPath; } else { // Error DWORD dr = ::GetLastError(); ::CloseHandle(hDir); // Some error action (throw or MessageBox) } return NULL; } //************************************************************************** //** CreateJunction //************************************************************************** /** Used to create a junction point. * static void CreateJunction(LPCSTR szJunction, LPCSTR szPath) { BYTE buf[sizeof(REPARSE_MOUNTPOINT_DATA_BUFFER) + MAX_PATH * sizeof(WCHAR)]; REPARSE_MOUNTPOINT_DATA_BUFFER& ReparseBuffer = (REPARSE_MOUNTPOINT_DATA_BUFFER&)buf; char szTarget[MAX_PATH] = "\\??\\"; strcat(szTarget, szPath); strcat(szTarget, "\\"); if (!::CreateDirectory(szJunction, NULL)) throw ::GetLastError(); // Obtain SE_RESTORE_NAME privilege (required for opening a directory) HANDLE hToken = NULL; TOKEN_PRIVILEGES tp; try { if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) throw ::GetLastError(); if (!::LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.Privileges[0].Luid)) throw ::GetLastError(); tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) throw ::GetLastError(); } catch (DWORD) { } // Ignore errors if (hToken) ::CloseHandle(hToken); HANDLE hDir = ::CreateFile(szJunction, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hDir == INVALID_HANDLE_VALUE) throw ::GetLastError(); memset(buf, 0, sizeof(buf)); ReparseBuffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; int len = ::MultiByteToWideChar(CP_ACP, 0, szTarget, -1, ReparseBuffer.ReparseTarget, MAX_PATH); ReparseBuffer.ReparseTargetMaximumLength = (len--) * sizeof(WCHAR); ReparseBuffer.ReparseTargetLength = len * sizeof(WCHAR); ReparseBuffer.ReparseDataLength = ReparseBuffer.ReparseTargetLength + 12; DWORD dwRet; if (!::DeviceIoControl(hDir, FSCTL_SET_REPARSE_POINT, &ReparseBuffer, ReparseBuffer.ReparseDataLength+REPARSE_MOUNTPOINT_HEADER_SIZE, NULL, 0, &dwRet, NULL)) { DWORD dr = ::GetLastError(); ::CloseHandle(hDir); ::RemoveDirectory(szJunction); throw dr; } ::CloseHandle(hDir); } // CreateJunction */
X Tutup