-
Notifications
You must be signed in to change notification settings - Fork 1
/
JunctionPointUtil.cc
79 lines (73 loc) · 4.69 KB
/
JunctionPointUtil.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include "JunctionPoint.h"
#include "Win32Exception.h"
#include "Win32Handle.h"
#include <Windows.h>
#include <cstring>
#include <cstdlib>
#include <memory>
#include <new>
std::pair<std::unique_ptr<JunctionPoint::ReparseDataBuffer, std::function<void(void*)>>, size_t> JunctionPoint::ReparseDataBuffer::CreateMountPoint(std::wstring_view substituteName, std::wstring_view printName) {
size_t substituteNameSize = (substituteName.size() + 1) * sizeof(wchar_t);
size_t printNameSize = (printName.size() + 1) * sizeof(wchar_t);
size_t reparseDataBufferSize = FIELD_OFFSET(ReparseDataBuffer, MountPointReparseBuffer.PathBuffer) + substituteNameSize + printNameSize;
ReparseDataBuffer* reparseDataBuffer = reinterpret_cast<ReparseDataBuffer*>(std::malloc(reparseDataBufferSize));
if (reparseDataBuffer == nullptr) {
throw std::bad_alloc();
}
reparseDataBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
reparseDataBuffer->ReparseDataLength = static_cast<uint16_t>(reparseDataBufferSize - FIELD_OFFSET(ReparseDataBuffer, MountPointReparseBuffer));
reparseDataBuffer->Reserved = 0;
reparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset = 0;
reparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength = static_cast<uint16_t>(substituteNameSize - sizeof(wchar_t));
reparseDataBuffer->MountPointReparseBuffer.PrintNameOffset = static_cast<uint16_t>(substituteNameSize);
reparseDataBuffer->MountPointReparseBuffer.PrintNameLength = static_cast<uint16_t>(printNameSize - sizeof(wchar_t));
std::memcpy(reparseDataBuffer->MountPointReparseBuffer.PathBuffer, substituteName.data(), substituteNameSize);
std::memcpy(reinterpret_cast<uint8_t*>(reparseDataBuffer->MountPointReparseBuffer.PathBuffer) + substituteNameSize, printName.data(), printNameSize);
return std::make_pair(std::unique_ptr<ReparseDataBuffer, std::function<void(void*)>>(reparseDataBuffer, &std::free), reparseDataBufferSize);
}
void JunctionPoint::Mount(std::wstring_view junctionPoint, std::wstring_view targetDir) {
DWORD targetDirFullPathSize = ::GetFullPathNameW(targetDir.data(), 0, nullptr, nullptr);
Win32Exception::ThrowLastErrorIf(targetDirFullPathSize == 0);
std::wstring targetDirNtPath(targetDirFullPathSize + 4, 0);
std::wmemcpy(targetDirNtPath.data(), L"\\??\\", 4);
targetDirFullPathSize = ::GetFullPathNameW(targetDir.data(), targetDirFullPathSize, targetDirNtPath.data() + 4, nullptr);
Win32Exception::ThrowLastErrorIf(targetDirFullPathSize == 0);
targetDirNtPath.resize(targetDirNtPath.size() - 1);
Win32Handle reparsePoint = ::CreateFileW(junctionPoint.data(), GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
Win32Exception::ThrowLastErrorIf(reparsePoint == INVALID_HANDLE_VALUE);
std::pair<std::unique_ptr<ReparseDataBuffer, std::function<void(void*)>>, size_t> reparseData = ReparseDataBuffer::CreateMountPoint(targetDirNtPath, L"");
DWORD bytesReturned;
BOOL ret = ::DeviceIoControl(reparsePoint, FSCTL_SET_REPARSE_POINT, reparseData.first.get(), static_cast<DWORD>(reparseData.second), nullptr, 0, &bytesReturned, nullptr);
Win32Exception::ThrowLastErrorIf(!ret);
}
void JunctionPoint::Create(std::wstring_view junctionPoint, std::wstring_view targetDir) {
Win32Exception::ThrowLastErrorIf(!::CreateDirectoryW(junctionPoint.data(), nullptr));
try {
Mount(junctionPoint, targetDir);
} catch (const Win32Exception& e) {
::RemoveDirectoryW(junctionPoint.data());
throw e;
}
}
void JunctionPoint::Unmount(std::wstring_view junctionPoint) {
ReparseDataBuffer reparseDataBuffer = {
.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT
};
Win32Handle reparsePoint = ::CreateFileW(junctionPoint.data(), GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
Win32Exception::ThrowLastErrorIf(reparsePoint == INVALID_HANDLE_VALUE);
DWORD bytesReturned;
BOOL ret = ::DeviceIoControl(reparsePoint, FSCTL_DELETE_REPARSE_POINT, &reparseDataBuffer, FIELD_OFFSET(ReparseDataBuffer, MountPointReparseBuffer), nullptr, 0, &bytesReturned, nullptr);
Win32Exception::ThrowLastErrorIf(!ret);
}
void JunctionPoint::Delete(std::wstring_view junctionPoint) {
Unmount(junctionPoint);
::RemoveDirectoryW(junctionPoint.data());
}
bool JunctionPoint::IsJunctionPoint(std::wstring_view path) {
DWORD attributes = ::GetFileAttributesW(path.data());
Win32Exception::ThrowLastErrorIf(attributes == INVALID_FILE_ATTRIBUTES);
if ((attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) != (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) {
return false;
}
return true;
}