mirror of
https://github.com/wiiu-env/ContentRedirectionModule.git
synced 2025-05-17 09:47:00 +02:00
Implement FSWrapperReplaceSingleFile
This commit is contained in:
parent
bee512fba6
commit
7416bc340b
@ -1,7 +1,7 @@
|
|||||||
FROM ghcr.io/wiiu-env/devkitppc:20240505
|
FROM ghcr.io/wiiu-env/devkitppc:20241128
|
||||||
|
|
||||||
COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO
|
COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO
|
||||||
COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20240424 /artifacts $DEVKITPRO
|
COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20240424 /artifacts $DEVKITPRO
|
||||||
COPY --from=ghcr.io/wiiu-env/libcontentredirection:20240428 /artifacts $DEVKITPRO
|
COPY --from=ghcr.io/wiiu-env/libcontentredirection:1.2-dev-20250207-b11c3c8 /artifacts $DEVKITPRO
|
||||||
|
|
||||||
WORKDIR project
|
WORKDIR project
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
#include <coreinit/filesystem_fsa.h>
|
#include <coreinit/filesystem_fsa.h>
|
||||||
|
|
||||||
typedef struct FSDirectoryEntryEx {
|
typedef struct FSDirectoryEntryEx {
|
||||||
FSADirectoryEntry realEntry{};
|
FSADirectoryEntry realEntry = {};
|
||||||
bool isMarkedAsDeleted = false;
|
bool isMarkedAsDeleted = false;
|
||||||
} FSDirectoryEntryEx;
|
} FSDirectoryEntryEx;
|
||||||
|
|
||||||
struct DirInfoEx final : DirInfo {
|
struct DirInfoEx final : DirInfo {
|
||||||
@ -13,3 +13,10 @@ struct DirInfoEx final : DirInfo {
|
|||||||
int readResultNumberOfEntries = 0;
|
int readResultNumberOfEntries = 0;
|
||||||
FSDirectoryHandle realDirHandle = 0;
|
FSDirectoryHandle realDirHandle = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DirInfoExSingleFile final : DirInfoBase {
|
||||||
|
FSADirectoryEntry directoryEntry = {};
|
||||||
|
bool entryRead = false;
|
||||||
|
bool entryReadSuccess = false;
|
||||||
|
FSDirectoryHandle realDirHandle = 0;
|
||||||
|
};
|
||||||
|
@ -42,11 +42,7 @@ FSError FSWrapper::FSOpenDirWrapper(const char *path, FSDirectoryHandle *handle)
|
|||||||
|
|
||||||
dirHandle->path[0] = '\0';
|
dirHandle->path[0] = '\0';
|
||||||
strncat(dirHandle->path, newPath.c_str(), sizeof(dirHandle->path) - 1);
|
strncat(dirHandle->path, newPath.c_str(), sizeof(dirHandle->path) - 1);
|
||||||
{
|
addDirHandle(dirHandle);
|
||||||
std::lock_guard<std::mutex> lock(openDirsMutex);
|
|
||||||
openDirs.push_back(dirHandle);
|
|
||||||
OSMemoryBarrier();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
auto err = errno;
|
auto err = errno;
|
||||||
if (err == ENOENT) {
|
if (err == ENOENT) {
|
||||||
@ -743,6 +739,12 @@ std::shared_ptr<DirInfoBase> FSWrapper::getDirFromHandle(const FSDirectoryHandle
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FSWrapper::addDirHandle(const std::shared_ptr<DirInfoBase> &dirHandle) {
|
||||||
|
std::lock_guard lock(openDirsMutex);
|
||||||
|
openDirs.push_back(dirHandle);
|
||||||
|
OSMemoryBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
void FSWrapper::deleteDirHandle(FSDirectoryHandle handle) {
|
void FSWrapper::deleteDirHandle(FSDirectoryHandle handle) {
|
||||||
if (!remove_locked_first_if(openDirsMutex, openDirs, [handle](auto &cur) { return static_cast<FSDirectoryHandle>(cur->handle) == handle; })) {
|
if (!remove_locked_first_if(openDirsMutex, openDirs, [handle](auto &cur) { return static_cast<FSDirectoryHandle>(cur->handle) == handle; })) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("[%s] Delete failed because the handle %08X was not found", getName().c_str(), handle);
|
DEBUG_FUNCTION_LINE_ERR("[%s] Delete failed because the handle %08X was not found", getName().c_str(), handle);
|
||||||
|
@ -114,6 +114,7 @@ protected:
|
|||||||
bool isValidDirHandle(FSDirectoryHandle handle) override;
|
bool isValidDirHandle(FSDirectoryHandle handle) override;
|
||||||
bool isValidFileHandle(FSFileHandle handle) override;
|
bool isValidFileHandle(FSFileHandle handle) override;
|
||||||
|
|
||||||
|
void addDirHandle(const std::shared_ptr<DirInfoBase> &dirHandle);
|
||||||
void deleteDirHandle(FSDirectoryHandle handle) override;
|
void deleteDirHandle(FSDirectoryHandle handle) override;
|
||||||
void deleteFileHandle(FSFileHandle handle) override;
|
void deleteFileHandle(FSFileHandle handle) override;
|
||||||
|
|
||||||
|
247
src/FSWrapperReplaceSingleFile.cpp
Normal file
247
src/FSWrapperReplaceSingleFile.cpp
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
#include "FSWrapperReplaceSingleFile.h"
|
||||||
|
#include "utils/StringTools.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "utils/utils.h"
|
||||||
|
|
||||||
|
#include <coreinit/cache.h>
|
||||||
|
#include <coreinit/debug.h>
|
||||||
|
#include <coreinit/filesystem.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
FSWrapperReplaceSingleFile::FSWrapperReplaceSingleFile(const std::string &name,
|
||||||
|
const std::string &fileToReplace,
|
||||||
|
const std::string &replaceWithPath,
|
||||||
|
const bool fallbackOnError) : FSWrapper(name,
|
||||||
|
fileToReplace,
|
||||||
|
replaceWithPath,
|
||||||
|
fallbackOnError,
|
||||||
|
false) {
|
||||||
|
auto strCpy = fileToReplace;
|
||||||
|
std::ranges::replace(strCpy, '\\', '/');
|
||||||
|
auto asPath = std::filesystem::path(strCpy);
|
||||||
|
mPathToReplace = asPath.parent_path();
|
||||||
|
mFileNameToReplace = asPath.filename();
|
||||||
|
mFullPathToReplace = fileToReplace;
|
||||||
|
|
||||||
|
strCpy = replaceWithPath;
|
||||||
|
std::ranges::replace(strCpy, '\\', '/');
|
||||||
|
asPath = std::filesystem::path(strCpy);
|
||||||
|
mReplacedWithPath = asPath.parent_path();
|
||||||
|
mReplacedWithFileName = asPath.filename();
|
||||||
|
|
||||||
|
FSAInit();
|
||||||
|
this->mClientHandle = FSAAddClient(nullptr);
|
||||||
|
if (mClientHandle < 0) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] FSAClientHandle failed: %s (%d)", name.c_str(), FSAGetStatusStr(static_cast<FSError>(mClientHandle)), mClientHandle);
|
||||||
|
mClientHandle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FSWrapperReplaceSingleFile::~FSWrapperReplaceSingleFile() {
|
||||||
|
if (mClientHandle) {
|
||||||
|
if (const FSError res = FSADelClient(mClientHandle); res != FS_ERROR_OK) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] FSADelClient failed: %s (%d)", FSAGetStatusStr(res), res);
|
||||||
|
}
|
||||||
|
mClientHandle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FSError FSWrapperReplaceSingleFile::FSOpenDirWrapper(const char *path,
|
||||||
|
FSADirectoryHandle *handle) {
|
||||||
|
if (!IsDirPathToReplace(path)) {
|
||||||
|
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||||
|
}
|
||||||
|
if (handle == nullptr) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] handle was NULL", getName().c_str());
|
||||||
|
return FS_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
if (const auto dirInfo = make_shared_nothrow<DirInfoExSingleFile>()) {
|
||||||
|
dirInfo->handle = (reinterpret_cast<uint32_t>(dirInfo.get()) & 0x0FFFFFFF) | 0x30000000;
|
||||||
|
*handle = dirInfo->handle;
|
||||||
|
addDirHandle(dirInfo);
|
||||||
|
if (!isValidDirHandle(*handle)) {
|
||||||
|
FSWrapper::FSCloseDirWrapper(*handle);
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] No valid dir handle %08X", getName().c_str(), *handle);
|
||||||
|
return FS_ERROR_INVALID_DIRHANDLE;
|
||||||
|
}
|
||||||
|
if (const auto dirHandle = getDirExFromHandle(*handle); dirHandle != nullptr) {
|
||||||
|
dirHandle->entryRead = false;
|
||||||
|
dirHandle->entryReadSuccess = false;
|
||||||
|
dirHandle->directoryEntry = {};
|
||||||
|
dirHandle->realDirHandle = 0;
|
||||||
|
|
||||||
|
if (mClientHandle) {
|
||||||
|
FSADirectoryHandle realHandle = 0;
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSAOpenDir with %s for parent layer", getName().c_str(), path);
|
||||||
|
if (const FSError err = FSAOpenDir(mClientHandle, path, &realHandle); err == FS_ERROR_OK) {
|
||||||
|
dirHandle->realDirHandle = realHandle;
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to open real dir %s. %s (%d)", getName().c_str(), path, FSAGetStatusStr(err), err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
|
||||||
|
}
|
||||||
|
OSMemoryBarrier();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to alloc dir handle", getName().c_str());
|
||||||
|
return FS_ERROR_MAX_DIRS;
|
||||||
|
}
|
||||||
|
return FS_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSError FSWrapperReplaceSingleFile::FSReadDirWrapper(const FSADirectoryHandle handle, FSADirectoryEntry *entry) {
|
||||||
|
if (!isValidDirHandle(handle)) {
|
||||||
|
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||||
|
}
|
||||||
|
const auto dirHandle = getDirExFromHandle(handle);
|
||||||
|
if (!dirHandle) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] No valid dir handle %08X", getName().c_str(), handle);
|
||||||
|
return FS_ERROR_INVALID_DIRHANDLE;
|
||||||
|
}
|
||||||
|
FSError res = FS_ERROR_OK;
|
||||||
|
do {
|
||||||
|
if (!dirHandle->entryRead) {
|
||||||
|
dirHandle->entryRead = true;
|
||||||
|
const auto newPath = GetNewPath(mFullPathToReplace);
|
||||||
|
|
||||||
|
struct stat path_stat {};
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] dir read of %s (%s)", getName().c_str(), mFullPathToReplace.c_str(), newPath.c_str());
|
||||||
|
if (stat(newPath.c_str(), &path_stat) < 0) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("[%s] Path %s (%s) for dir read not found ", getName().c_str(), mFullPathToReplace.c_str(), newPath.c_str());
|
||||||
|
dirHandle->entryReadSuccess = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
translate_stat(&path_stat, &dirHandle->directoryEntry.info);
|
||||||
|
strncpy(dirHandle->directoryEntry.name, mFileNameToReplace.c_str(), sizeof(dirHandle->directoryEntry.name));
|
||||||
|
memcpy(entry, &dirHandle->directoryEntry, sizeof(FSADirectoryEntry));
|
||||||
|
|
||||||
|
dirHandle->entryReadSuccess = true;
|
||||||
|
OSMemoryBarrier();
|
||||||
|
} else {
|
||||||
|
// Read the real directory.
|
||||||
|
if (dirHandle->realDirHandle != 0) {
|
||||||
|
if (mClientHandle) {
|
||||||
|
FSADirectoryEntry realDirEntry;
|
||||||
|
while (true) {
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSReadDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle);
|
||||||
|
if (const FSError readDirResult = FSAReadDir(mClientHandle, dirHandle->realDirHandle, &realDirEntry); readDirResult == FS_ERROR_OK) {
|
||||||
|
// Skip already read new files
|
||||||
|
if (dirHandle->entryRead && dirHandle->entryReadSuccess && strcmp(dirHandle->directoryEntry.name, realDirEntry.name) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// But use new entries!
|
||||||
|
memcpy(entry, &realDirEntry, sizeof(FSADirectoryEntry));
|
||||||
|
res = FS_ERROR_OK;
|
||||||
|
break;
|
||||||
|
} else if (readDirResult == FS_ERROR_END_OF_DIR) {
|
||||||
|
res = FS_ERROR_END_OF_DIR;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] real_FSReadDir returned an unexpected error: %s (%d)", getName().c_str(), FSAGetStatusStr(readDirResult), readDirResult);
|
||||||
|
res = FS_ERROR_END_OF_DIR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
FSError FSWrapperReplaceSingleFile::FSCloseDirWrapper(const FSADirectoryHandle handle) {
|
||||||
|
if (!isValidDirHandle(handle)) {
|
||||||
|
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||||
|
}
|
||||||
|
const auto dirHandle = getDirExFromHandle(handle);
|
||||||
|
if (dirHandle->realDirHandle != 0) {
|
||||||
|
if (mClientHandle) {
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSCloseDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle);
|
||||||
|
auto realResult = FSACloseDir(mClientHandle, dirHandle->realDirHandle);
|
||||||
|
if (realResult == FS_ERROR_OK) {
|
||||||
|
dirHandle->realDirHandle = 0;
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to close realDirHandle %d: res %s (%d)", getName().c_str(), dirHandle->realDirHandle, FSAGetStatusStr(realResult), realResult);
|
||||||
|
return realResult == FS_ERROR_CANCELLED ? FS_ERROR_CANCELLED : FS_ERROR_MEDIA_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] dirHandle->realDirHandle was 0", getName().c_str());
|
||||||
|
}
|
||||||
|
dirHandle->entryRead = false;
|
||||||
|
dirHandle->entryReadSuccess = false;
|
||||||
|
|
||||||
|
OSMemoryBarrier();
|
||||||
|
return FS_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSError FSWrapperReplaceSingleFile::FSRewindDirWrapper(const FSADirectoryHandle handle) {
|
||||||
|
if (!isValidDirHandle(handle)) {
|
||||||
|
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||||
|
}
|
||||||
|
const auto dirHandle = getDirExFromHandle(handle);
|
||||||
|
dirHandle->entryRead = false;
|
||||||
|
dirHandle->entryReadSuccess = false;
|
||||||
|
if (dirHandle->realDirHandle != 0) {
|
||||||
|
if (mClientHandle) {
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSARewindDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle);
|
||||||
|
if (const FSError err = FSARewindDir(mClientHandle, dirHandle->realDirHandle); err != FS_ERROR_OK) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to rewind dir for realDirHandle %08X. %s (%d)", getName().c_str(), dirHandle->realDirHandle, FSAGetStatusStr(err), err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] dirHandle->realDirHandle was 0", getName().c_str());
|
||||||
|
}
|
||||||
|
OSMemoryBarrier();
|
||||||
|
|
||||||
|
return FS_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FSWrapperReplaceSingleFile::SkipDeletedFilesInReadDir() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FSWrapperReplaceSingleFile::IsDirPathToReplace(const std::string_view &path) const {
|
||||||
|
return starts_with_case_insensitive(path, mPathToReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FSWrapperReplaceSingleFile::GetNewPath(const std::string_view &path) const {
|
||||||
|
auto pathCpy = std::string(path);
|
||||||
|
SafeReplaceInString(pathCpy, this->mPathToReplace, this->mReplacedWithPath);
|
||||||
|
SafeReplaceInString(pathCpy, this->mFileNameToReplace, this->mReplacedWithFileName);
|
||||||
|
std::ranges::replace(pathCpy, '\\', '/');
|
||||||
|
|
||||||
|
uint32_t length = pathCpy.size();
|
||||||
|
|
||||||
|
//! clear path of double slashes
|
||||||
|
for (uint32_t i = 1; i < length; ++i) {
|
||||||
|
if (pathCpy[i - 1] == '/' && pathCpy[i] == '/') {
|
||||||
|
pathCpy.erase(i, 1);
|
||||||
|
i--;
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Redirect %.*s -> %s", getName().c_str(), int(path.length()), path.data(), pathCpy.c_str());
|
||||||
|
return pathCpy;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<DirInfoExSingleFile> FSWrapperReplaceSingleFile::getDirExFromHandle(FSADirectoryHandle handle) {
|
||||||
|
auto dir = std::dynamic_pointer_cast<DirInfoExSingleFile>(getDirFromHandle(handle));
|
||||||
|
|
||||||
|
if (!dir) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("[%s] dynamic_pointer_cast<DirInfoExSingleFile *>(%08X) failed", getName().c_str(), handle);
|
||||||
|
OSFatal("ContentRedirectionModule: dynamic_pointer_cast<DirInfoExSingleFile *> failed");
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
52
src/FSWrapperReplaceSingleFile.h
Normal file
52
src/FSWrapperReplaceSingleFile.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "DirInfoEx.h"
|
||||||
|
#include "FSWrapper.h"
|
||||||
|
|
||||||
|
#include <coreinit/filesystem.h>
|
||||||
|
|
||||||
|
class FSWrapperReplaceSingleFile final : public FSWrapper {
|
||||||
|
public:
|
||||||
|
FSWrapperReplaceSingleFile(const std::string &name,
|
||||||
|
const std::string &fileToReplace,
|
||||||
|
const std::string &replaceWithPath,
|
||||||
|
bool fallbackOnError);
|
||||||
|
|
||||||
|
~FSWrapperReplaceSingleFile() override;
|
||||||
|
|
||||||
|
FSError FSOpenDirWrapper(const char *path,
|
||||||
|
FSDirectoryHandle *handle) override;
|
||||||
|
|
||||||
|
FSError FSReadDirWrapper(FSDirectoryHandle handle,
|
||||||
|
FSDirectoryEntry *entry) override;
|
||||||
|
|
||||||
|
FSError FSCloseDirWrapper(FSDirectoryHandle handle) override;
|
||||||
|
|
||||||
|
FSError FSRewindDirWrapper(FSDirectoryHandle handle) override;
|
||||||
|
|
||||||
|
bool SkipDeletedFilesInReadDir() override;
|
||||||
|
|
||||||
|
uint32_t getLayerId() override {
|
||||||
|
return static_cast<uint32_t>(mClientHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] std::string GetNewPath(const std::string_view &path) const override;
|
||||||
|
|
||||||
|
std::shared_ptr<DirInfo> getNewDirInfoHandle() override {
|
||||||
|
OSFatal("FSWrapperReplaceSingleFile::getNewDirInfoHandle. Not implemented");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool IsDirPathToReplace(const std::string_view &path) const;
|
||||||
|
|
||||||
|
std::shared_ptr<DirInfoExSingleFile> getDirExFromHandle(FSDirectoryHandle handle);
|
||||||
|
|
||||||
|
FSAClientHandle mClientHandle;
|
||||||
|
std::string mPathToReplace;
|
||||||
|
std::string mFileNameToReplace;
|
||||||
|
std::string mFullPathToReplace;
|
||||||
|
std::string mReplacedWithPath;
|
||||||
|
std::string mReplacedWithFileName;
|
||||||
|
};
|
@ -6,6 +6,8 @@
|
|||||||
#include "utils/StringTools.h"
|
#include "utils/StringTools.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
#include "utils/utils.h"
|
#include "utils/utils.h"
|
||||||
|
|
||||||
|
#include <FSWrapperReplaceSingleFile.h>
|
||||||
#include <content_redirection/redirection.h>
|
#include <content_redirection/redirection.h>
|
||||||
#include <coreinit/dynload.h>
|
#include <coreinit/dynload.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@ -142,6 +144,46 @@ ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *l
|
|||||||
return CONTENT_REDIRECTION_API_ERROR_NO_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) {
|
ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) {
|
||||||
if (!remove_locked_first_if(gFSLayerMutex, gFSLayers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == 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);
|
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
|
||||||
@ -167,7 +209,7 @@ ContentRedirectionApiErrorType CRGetVersion(ContentRedirectionVersion *outVersio
|
|||||||
if (outVersion == nullptr) {
|
if (outVersion == nullptr) {
|
||||||
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
|
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
*outVersion = 1;
|
*outVersion = 2;
|
||||||
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,6 +222,7 @@ int CRRemoveDevice(const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WUMS_EXPORT_FUNCTION(CRGetVersion);
|
WUMS_EXPORT_FUNCTION(CRGetVersion);
|
||||||
|
WUMS_EXPORT_FUNCTION(CRAddFSLayerEx);
|
||||||
WUMS_EXPORT_FUNCTION(CRAddFSLayer);
|
WUMS_EXPORT_FUNCTION(CRAddFSLayer);
|
||||||
WUMS_EXPORT_FUNCTION(CRRemoveFSLayer);
|
WUMS_EXPORT_FUNCTION(CRRemoveFSLayer);
|
||||||
WUMS_EXPORT_FUNCTION(CRSetActive);
|
WUMS_EXPORT_FUNCTION(CRSetActive);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user