-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathexport.cpp
More file actions
273 lines (241 loc) · 12.2 KB
/
export.cpp
File metadata and controls
273 lines (241 loc) · 12.2 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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
#include "FSWrapper.h"
#include "FSWrapperMergeDirsWithParent.h"
#include "FileUtils.h"
#include "IFSWrapper.h"
#include "malloc.h"
#include "utils/DevoptabTrampoline.h"
#include "utils/StringTools.h"
#include "utils/logger.h"
#include "utils/utils.h"
#include <FSWrapperReplaceSingleFile.h>
#include <content_redirection/redirection.h>
#include <coreinit/dynload.h>
#include <cstring>
#include <mutex>
#include <nn/act.h>
#include <wums/exports.h>
struct AOCTitle {
WUT_UNKNOWN_BYTES(0x68);
};
WUT_CHECK_SIZE(AOCTitle, 0x68);
bool getAOCPath(std::string &outStr) {
int32_t (*AOC_Initialize)() = nullptr;
int32_t (*AOC_Finalize)() = nullptr;
int32_t (*AOC_ListTitle)(uint32_t * titleCountOut, AOCTitle * titleList, uint32_t maxCount, void *workBuffer, uint32_t workBufferSize) = nullptr;
int32_t (*AOC_OpenTitle)(char *pathOut, AOCTitle *aocTitleInfo, void *workBuffer, uint32_t workBufferSize) = nullptr;
int32_t (*AOC_CalculateWorkBufferSize)(uint32_t count) = nullptr;
int32_t (*AOC_CloseTitle)(AOCTitle * aocTitleInfo) = nullptr;
AOCTitle title{};
char aocPath[256];
aocPath[0] = '\0';
uint32_t outCount = 0;
uint32_t workBufferSize = 0;
void *workBuffer = nullptr;
bool result = false;
OSDynLoad_Module aoc_handle;
if (OSDynLoad_Acquire("nn_aoc.rpl", &aoc_handle) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_WARN("OSDynLoad_Acquire failed");
return false;
}
if (OSDynLoad_FindExport(aoc_handle, OS_DYNLOAD_EXPORT_FUNC, "AOC_Initialize", reinterpret_cast<void **>(&AOC_Initialize)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed");
goto end;
}
if (OSDynLoad_FindExport(aoc_handle, OS_DYNLOAD_EXPORT_FUNC, "AOC_Finalize", reinterpret_cast<void **>(&AOC_Finalize)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed");
goto end;
}
if (OSDynLoad_FindExport(aoc_handle, OS_DYNLOAD_EXPORT_FUNC, "AOC_OpenTitle", reinterpret_cast<void **>(&AOC_OpenTitle)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed");
goto end;
}
if (OSDynLoad_FindExport(aoc_handle, OS_DYNLOAD_EXPORT_FUNC, "AOC_ListTitle", reinterpret_cast<void **>(&AOC_ListTitle)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed");
goto end;
}
if (OSDynLoad_FindExport(aoc_handle, OS_DYNLOAD_EXPORT_FUNC, "AOC_CalculateWorkBufferSize", reinterpret_cast<void **>(&AOC_CalculateWorkBufferSize)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed");
goto end;
}
if (OSDynLoad_FindExport(aoc_handle, OS_DYNLOAD_EXPORT_FUNC, "AOC_CloseTitle", reinterpret_cast<void **>(&AOC_CloseTitle)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed");
goto end;
}
AOC_Initialize();
workBufferSize = AOC_CalculateWorkBufferSize(1);
workBuffer = memalign(0x40, workBufferSize);
if (!workBuffer) {
DEBUG_FUNCTION_LINE_WARN("Failed to alloc workBuffer");
goto end;
}
if (AOC_ListTitle(&outCount, &title, 1, workBuffer, workBufferSize) < 0) {
DEBUG_FUNCTION_LINE_WARN("AOC_ListTitle failed");
goto end;
}
if (AOC_OpenTitle(aocPath, &title, workBuffer, workBufferSize) < 0) {
DEBUG_FUNCTION_LINE_WARN("AOC_OpenTitle failed");
goto end;
}
result = true;
outStr = aocPath;
AOC_CloseTitle(&title);
end:
free(workBuffer);
AOC_Finalize();
OSDynLoad_Release(aoc_handle);
return result;
}
ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *layerName, const char *replacementDir, const FSLayerType layerType) {
if (!handle || layerName == nullptr || replacementDir == nullptr) {
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
}
std::unique_ptr<IFSWrapper> ptr;
if (layerType == FS_LAYER_TYPE_CONTENT_REPLACE) {
DEBUG_FUNCTION_LINE_INFO("Redirecting \"/vol/content\" to \"%s\", mode: \"replace\"", replacementDir);
ptr = make_unique_nothrow<FSWrapper>(layerName, "/vol/content", replacementDir, false, false);
} else if (layerType == FS_LAYER_TYPE_CONTENT_MERGE) {
DEBUG_FUNCTION_LINE_INFO("Redirecting \"/vol/content\" to \"%s\", mode: \"merge\"", replacementDir);
ptr = make_unique_nothrow<FSWrapperMergeDirsWithParent>(layerName, "/vol/content", replacementDir, true);
} else if (layerType == FS_LAYER_TYPE_AOC_MERGE || layerType == FS_LAYER_TYPE_AOC_REPLACE) {
std::string targetPath;
if (!getAOCPath(targetPath)) {
DEBUG_FUNCTION_LINE_ERR("(%s) Failed to get the AOC path. Not redirecting /vol/aoc", layerName);
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
}
DEBUG_FUNCTION_LINE_INFO("Redirecting \"%s\" to \"%s\", mode: \"%s\"", targetPath.c_str(), replacementDir, layerType == FS_LAYER_TYPE_AOC_MERGE ? "merge" : "replace");
if (layerType == FS_LAYER_TYPE_AOC_MERGE) {
ptr = make_unique_nothrow<FSWrapperMergeDirsWithParent>(layerName, targetPath.c_str(), replacementDir, true);
} else {
ptr = make_unique_nothrow<FSWrapper>(layerName, targetPath.c_str(), replacementDir, false, false);
}
} else if (layerType == FS_LAYER_TYPE_SAVE_REPLACE) {
DEBUG_FUNCTION_LINE_INFO("Redirecting \"/vol/save\" to \"%s\", mode: \"replace\"", replacementDir);
ptr = make_unique_nothrow<FSWrapper>(layerName, "/vol/save", replacementDir, false, true);
} else if (layerType == FS_LAYER_TYPE_SAVE_REPLACE_FOR_CURRENT_USER) {
nn::act::Initialize();
nn::act::PersistentId persistentId = nn::act::GetPersistentId();
nn::act::Finalize();
std::string user = string_format("/vol/save/%08X", 0x80000000 | persistentId);
DEBUG_FUNCTION_LINE_INFO("Redirecting \"%s\" to \"%s\", mode: \"replace\"", user.c_str(), replacementDir);
ptr = make_unique_nothrow<FSWrapper>(layerName, user, replacementDir, false, true);
} else {
DEBUG_FUNCTION_LINE_ERR("CONTENT_REDIRECTION_API_ERROR_UNKNOWN_LAYER_DIR_TYPE: %s %s %d", layerName, replacementDir, layerType);
return CONTENT_REDIRECTION_API_ERROR_UNKNOWN_FS_LAYER_TYPE;
}
if (ptr) {
DEBUG_FUNCTION_LINE_VERBOSE("Added new layer (%s). Replacement dir: %s Type:%d", layerName, replacementDir, layerType);
std::lock_guard lock(gFSLayerMutex);
*handle = (CRLayerHandle) ptr->getHandle();
gFSLayers.push_back(std::move(ptr));
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory");
return CONTENT_REDIRECTION_API_ERROR_NO_MEMORY;
}
ContentRedirectionApiErrorType CRAddFSLayerEx(CRLayerHandle *handle, const char *layerName, const char *targetPath, const char *replacementPath, const FSLayerTypeEx layerType) {
if (!handle || layerName == nullptr || replacementPath == nullptr || targetPath == nullptr) {
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
}
std::unique_ptr<IFSWrapper> ptr;
switch (layerType) {
case FS_LAYER_TYPE_EX_REPLACE_DIRECTORY: {
DEBUG_FUNCTION_LINE_INFO("[AddFSLayerEx] Redirecting \"%s\" to \"%s\", mode: \"replace\"", targetPath, replacementPath);
ptr = make_unique_nothrow<FSWrapper>(layerName, targetPath, replacementPath, false, false);
break;
}
case FS_LAYER_TYPE_EX_MERGE_DIRECTORY: {
DEBUG_FUNCTION_LINE_INFO("[AddFSLayerEx] Redirecting \"%s\" to \"%s\", mode: \"merge\"", targetPath, replacementPath);
ptr = make_unique_nothrow<FSWrapperMergeDirsWithParent>(layerName, targetPath, replacementPath, true);
break;
}
case FS_LAYER_TYPE_EX_REPLACE_FILE: {
DEBUG_FUNCTION_LINE_INFO("[AddFSLayerEx] Redirecting file \"%s\" to \"%s\"", targetPath, replacementPath);
ptr = make_unique_nothrow<FSWrapperReplaceSingleFile>(layerName, targetPath, replacementPath, true);
break;
}
default: {
DEBUG_FUNCTION_LINE_ERR("[AddFSLayerEx] CONTENT_REDIRECTION_API_ERROR_UNKNOWN_LAYER_DIR_TYPE: %s %s %d", layerName, replacementPath, layerType);
return CONTENT_REDIRECTION_API_ERROR_UNKNOWN_FS_LAYER_TYPE;
}
}
if (ptr) {
DEBUG_FUNCTION_LINE_VERBOSE("[AddFSLayerEx] Added new layer (%s). Target path: %s Replacement dir: %s Type:%d", layerName, targetPath, replacementPath, layerType);
std::lock_guard lock(gFSLayerMutex);
*handle = ptr->getHandle();
gFSLayers.emplace_back(std::move(ptr));
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
DEBUG_FUNCTION_LINE_ERR("[AddFSLayerEx] Failed to allocate memory");
return CONTENT_REDIRECTION_API_ERROR_NO_MEMORY;
}
ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) {
if (!remove_locked_first_if(gFSLayerMutex, gFSLayers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == handle; })) {
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
}
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
ContentRedirectionApiErrorType CRSetActive(CRLayerHandle handle, bool active) {
std::lock_guard lock(gFSLayerMutex);
for (auto &cur : gFSLayers) {
if ((CRLayerHandle) cur->getHandle() == handle) {
cur->setActive(active);
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
}
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
}
ContentRedirectionApiErrorType CRGetVersion(ContentRedirectionVersion *outVersion) {
if (outVersion == nullptr) {
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
}
*outVersion = 3;
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
int CRAddDevice(const devoptab_t *device) {
DEBUG_FUNCTION_LINE_WARN("Usage of deprecated \"CRAddDevice\" API detected. Please use latest libcontentredirection.");
return AddDevice(device);
}
int CRRemoveDevice(const char *name) {
DEBUG_FUNCTION_LINE_WARN("Usage deprecated \"CRRemoveDevice\" API. Please use latest libcontentredirection.");
return RemoveDevice(name);
}
ContentRedirectionApiErrorType CRAddDeviceABI(const ContentRedirectionDeviceABI *device, int *resultOut) {
if (!device || device->magic != CONTENT_REDIRECTION_DEVICE_MAGIC || device->version < CONTENT_REDIRECTION_DEVICE_VERSION || !resultOut) {
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
}
const auto *host_dev = DevoptabTrampoline::CreateDevoptab(device);
if (!host_dev) {
return CONTENT_REDIRECTION_API_ERROR_NO_MEMORY;
}
*resultOut = AddDevice(host_dev);
if (*resultOut < 0) {
DevoptabTrampoline::ClearDevoptab(host_dev);
}
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
ContentRedirectionApiErrorType CRRemoveDeviceABI(const char *device_name, int *resultOut) {
if (!device_name || !resultOut) {
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
}
if (!DevoptabTrampoline::RemoveDevoptab(device_name, resultOut)) {
*resultOut = -1;
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
}
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
// API Version 1
WUMS_EXPORT_FUNCTION(CRGetVersion);
WUMS_EXPORT_FUNCTION(CRAddFSLayer);
WUMS_EXPORT_FUNCTION(CRRemoveFSLayer);
WUMS_EXPORT_FUNCTION(CRSetActive);
WUMS_EXPORT_FUNCTION(CRAddDevice);
WUMS_EXPORT_FUNCTION(CRRemoveDevice);
// API Version 2
WUMS_EXPORT_FUNCTION(CRAddFSLayerEx);
// API Version 3
WUMS_EXPORT_FUNCTION(CRAddDeviceABI);
WUMS_EXPORT_FUNCTION(CRRemoveDeviceABI);