Repository navigation
Expand file tree
/
Copy pathClipboardOperations.cpp
More file actions
142 lines (113 loc) · 3.81 KB
/
Copy pathClipboardOperations.cpp
File metadata and controls
142 lines (113 loc) · 3.81 KB
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright (C) Explorer++ Project
// SPDX-License-Identifier: GPL-3.0-only
// See LICENSE in the top level directory
#include "stdafx.h"
#include "ClipboardOperations.h"
#include "CommandLine.h"
#include "DirectoryOperationsHelper.h"
#include "PasteSymLinksServer.h"
#include "../Helper/Clipboard.h"
#include "../Helper/ClipboardStore.h"
#include "../Helper/ShellHelper.h"
using namespace std::chrono_literals;
namespace
{
enum class LinkType
{
HardLink,
SymLink
};
void CreateSymLink(const std::filesystem::path &sourceFilePath,
const std::filesystem::path &destinationFilePath, std::error_code &error)
{
bool isDirectory = std::filesystem::is_directory(sourceFilePath, error);
if (error)
{
return;
}
if (isDirectory)
{
std::filesystem::create_directory_symlink(sourceFilePath, destinationFilePath, error);
}
else
{
std::filesystem::create_symlink(sourceFilePath, destinationFilePath, error);
}
}
ClipboardOperations::PastedItems PasteLinksOfType(ClipboardStore *clipboardStore,
const std::wstring &destination, LinkType linkType)
{
Clipboard clipboard(clipboardStore);
auto paths = clipboard.ReadHDropData();
if (!paths)
{
return {};
}
ClipboardOperations::PastedItems pastedItems;
for (const auto &path : *paths)
{
std::filesystem::path sourceFilePath(path);
std::filesystem::path destinationFilePath(destination);
destinationFilePath /= sourceFilePath.filename();
std::error_code error;
switch (linkType)
{
case LinkType::HardLink:
std::filesystem::create_hard_link(sourceFilePath, destinationFilePath, error);
break;
case LinkType::SymLink:
CreateSymLink(sourceFilePath, destinationFilePath, error);
break;
default:
CHECK(false);
}
pastedItems.emplace_back(destinationFilePath, error);
}
return pastedItems;
}
ClipboardOperations::PastedItems PasteSymLinksViaElevatedProcess(const std::wstring &destination)
{
auto clientLauncher = [&destination]
{
std::wstring parameters =
std::format(L"{} \"{}\"", CommandLine::PASTE_SYMLINKS_ARGUMENT, destination);
return LaunchCurrentProcess(nullptr, parameters, LaunchProcessFlags::Elevated);
};
PasteSymLinksServer server;
return server.LaunchClientAndWaitForResponse(clientLauncher, 10s);
}
}
namespace ClipboardOperations
{
bool CanPasteLinkInDirectory(const ClipboardStore *clipboardStore, PCIDLIST_ABSOLUTE pidl)
{
return clipboardStore->IsDataAvailable(CF_HDROP) && IsFilesystemFolder(pidl);
}
PastedItems PasteHardLinks(ClipboardStore *clipboardStore, const std::wstring &destination)
{
return PasteLinksOfType(clipboardStore, destination, LinkType::HardLink);
}
PastedItems PasteSymLinks(ClipboardStore *clipboardStore, const std::wstring &destination)
{
auto pastedItems = PasteLinksOfType(clipboardStore, destination, LinkType::SymLink);
auto itr = std::find_if(pastedItems.begin(), pastedItems.end(),
[](const auto &pastedItem)
{
return pastedItem.error
== std::error_code(ERROR_PRIVILEGE_NOT_HELD, std::system_category());
});
if (itr == pastedItems.end())
{
// If none of the symlink operations failed because of insufficient privileges, it indicates
// that either this process is elevated, or developer mode is enabled. In either case,
// there's no need to retry the operations in an elevated process.
// Note that this doesn't necessarily indicate that any of the symlink operations actually
// succeeded, only that they didn't fail because symlink creation is blocked.
return pastedItems;
}
// If at least one symlink operation failed due to insufficient privileges, it's assumed they
// all failed for that reason. In which case, the operation needs to be retried in an elevated
// process.
return PasteSymLinksViaElevatedProcess(destination);
}
}