RPXLoadingModule/src/FSWrapper.cpp

866 lines
34 KiB
C++
Raw Normal View History

2021-01-01 01:39:28 +01:00
#include "FSWrapper.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <mutex>
#include <coreinit/cache.h>
#include <coreinit/debug.h>
#include "utils/logger.h"
#include "FileUtils.h"
#include "globals.h"
dirMagic_t dir_handles[DIR_HANDLES_LENGTH];
fileMagic_t file_handles[FILE_HANDLES_LENGTH];
std::mutex dir_handle_mutex;
std::mutex file_handle_mutex;
2021-04-05 19:54:50 +02:00
static inline void replaceContentPath(char *pathForCheck, int pathForCheckSize, int replaceLen, char *replaceWith);
2021-01-01 01:39:28 +01:00
inline void getFullPath(char *pathForCheck, int pathSize, char *path) {
if (path[0] != '/' && path[0] != '\\') {
2021-04-05 19:54:50 +02:00
snprintf(pathForCheck, pathSize, "%s%s", gReplacementInfo.contentReplacementInfo.workingDir, path);
2021-01-01 01:39:28 +01:00
DEBUG_FUNCTION_LINE_VERBOSE("Real path is %s", path);
} else {
2021-04-05 19:54:50 +02:00
pathForCheck[0] = '\0';
strncat(pathForCheck, path, pathSize - 1);
}
for(int i = 0; i < strlen(pathForCheck);i++){
if(pathForCheck[i] == '\\'){
pathForCheck[i] = '/';
}
2021-01-01 01:39:28 +01:00
}
}
inline bool checkForSave(char *pathForCheck, int pathSize, char *path) {
if (!gReplacementInfo.contentReplacementInfo.replaceSave) {
return false;
}
2021-01-01 01:39:28 +01:00
if (strncmp(path, "/vol/save", 9) == 0) {
int copyLen = strlen(path);
2021-04-05 19:54:50 +02:00
char copy[copyLen + 1];
2021-01-01 01:39:28 +01:00
memcpy(copy, path, copyLen);
copy[copyLen] = 0;
2021-04-05 19:54:50 +02:00
memset(pathForCheck, 0, pathSize);
snprintf(pathForCheck, pathSize, "%s%s", gReplacementInfo.contentReplacementInfo.savePath, &copy[9]);
2021-01-01 01:39:28 +01:00
return true;
}
return false;
}
int getNewFileHandleIndex() {
file_handle_mutex.lock();
int32_t handle_id = -1;
for (int i = 0; i < FILE_HANDLES_LENGTH; i++) {
if (!file_handles[i].in_use) {
handle_id = i;
if (!file_handles[i].mutex) {
file_handles[i].mutex = (OSMutex *) malloc(sizeof(OSMutex));
OSInitMutex(file_handles[i].mutex);
if (!file_handles[i].mutex) {
OSFatal("Failed to alloc memory for mutex");
}
DCFlushRange(file_handles[i].mutex, sizeof(OSMutex));
DCFlushRange(&file_handles[i], sizeof(fileMagic_t));
}
break;
}
}
file_handle_mutex.unlock();
return handle_id;
}
bool isValidDirHandle(int32_t handle) {
return (handle & HANDLE_INDICATOR_MASK) == DIR_HANDLE_MAGIC;
}
bool isValidFileHandle(int32_t handle) {
return (handle & HANDLE_INDICATOR_MASK) == FILE_HANDLE_MAGIC;
}
int32_t getNewDirHandleIndex() {
dir_handle_mutex.lock();
int32_t handle_id;
for (int i = 0; i < DIR_HANDLES_LENGTH; i++) {
if (!dir_handles[i].in_use) {
handle_id = i;
if (!dir_handles[i].mutex) {
dir_handles[i].mutex = (OSMutex *) malloc(sizeof(OSMutex));
OSInitMutex(dir_handles[i].mutex);
if (!dir_handles[i].mutex) {
OSFatal("Failed to alloc memory for mutex");
}
DCFlushRange(dir_handles[i].mutex, sizeof(OSMutex));
DCFlushRange(&dir_handles[i], sizeof(dirMagic_t));
}
break;
}
}
dir_handle_mutex.unlock();
return handle_id;
}
void freeFileHandle(uint32_t handle) {
if (handle >= FILE_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return;
}
file_handle_mutex.lock();
file_handles[handle].in_use = false;
if (file_handles[handle].mutex) {
free(file_handles[handle].mutex);
file_handles[handle].mutex = nullptr;
}
DCFlushRange(&file_handles[handle], sizeof(fileMagic_t));
file_handle_mutex.unlock();
}
void freeDirHandle(uint32_t handle) {
if (handle >= DIR_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return;
}
dir_handle_mutex.lock();
dir_handles[handle].in_use = false;
if (dir_handles[handle].mutex) {
free(dir_handles[handle].mutex);
dir_handles[handle].mutex = nullptr;
}
memset(&dir_handles[handle], 0, sizeof(dirMagic_t));
DCFlushRange(&dir_handles[handle], sizeof(dirMagic_t));
dir_handle_mutex.unlock();
}
FSStatus FSOpenDirWrapper(char *path,
FSDirectoryHandle *handle,
FSErrorFlag errorMask,
std::function<FSStatus(char *_path)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
char pathForCheck[256];
getFullPath(pathForCheck, sizeof(pathForCheck), path);
if (checkForSave(pathForCheck, sizeof(pathForCheck), pathForCheck)) {
DEBUG_FUNCTION_LINE("Redirect save to %s", pathForCheck);
return fallback_function(pathForCheck);
}
if (handle == nullptr) {
DEBUG_FUNCTION_LINE("Invalid args");
return FS_STATUS_FATAL_ERROR;
}
if (strncmp(pathForCheck, "/vol/content", 12) == 0) {
2021-04-05 19:54:50 +02:00
replaceContentPath(pathForCheck, sizeof(pathForCheck), 12, gReplacementInfo.contentReplacementInfo.replacementPath);
2021-01-01 01:39:28 +01:00
2021-04-05 19:54:50 +02:00
DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", path, pathForCheck);
2021-01-01 01:39:28 +01:00
FSStatus result = FS_STATUS_OK;
int handle_index = getNewDirHandleIndex();
if (handle_index >= 0) {
DIR *dir;
if ((dir = opendir(pathForCheck))) {
OSLockMutex(dir_handles[handle_index].mutex);
dir_handles[handle_index].handle = DIR_HANDLE_MAGIC | handle_index;
*handle = dir_handles[handle_index].handle;
dir_handles[handle_index].dir = dir;
dir_handles[handle_index].in_use = true;
2021-04-05 19:54:50 +02:00
dir_handles[handle_index].path[0] = '\0';
strncat(dir_handles[handle_index].path, pathForCheck, sizeof(dir_handles[handle_index].path) - 1);
2021-01-01 01:39:28 +01:00
DCFlushRange(&dir_handles[handle_index], sizeof(dirMagic_t));
OSUnlockMutex(dir_handles[handle_index].mutex);
} else {
DEBUG_FUNCTION_LINE("Dir not found %s", pathForCheck);
2021-04-05 19:54:50 +02:00
if (gReplacementInfo.contentReplacementInfo.fallbackOnError) {
return FS_STATUS_USE_REAL_OS;
}
2021-01-01 01:39:28 +01:00
if (errorMask & FS_ERROR_FLAG_NOT_FOUND) {
result = FS_STATUS_NOT_FOUND;
}
}
} else {
if (errorMask & FS_ERROR_FLAG_MAX) {
result = FS_STATUS_MAX;
}
}
return result_handler(result);
}
return FS_STATUS_USE_REAL_OS;
}
FSStatus FSReadDirWrapper(FSDirectoryHandle handle,
FSDirectoryEntry *entry,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidDirHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
if (handle_index >= DIR_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return result_handler(FS_STATUS_FATAL_ERROR);
}
OSLockMutex(dir_handles[handle_index].mutex);
DIR *dir = dir_handles[handle_index].dir;
struct dirent *entry_ = readdir(dir);
FSStatus result = FS_STATUS_END;
if (entry_) {
2021-04-05 19:54:50 +02:00
entry->name[0] = '\0';
strncat(entry->name, entry_->d_name, sizeof(entry->name)-1);
2021-01-01 01:39:28 +01:00
entry->info.mode = (FSMode) FS_MODE_READ_OWNER;
if (entry_->d_type == DT_DIR) {
entry->info.flags = (FSStatFlags) ((uint32_t) FS_STAT_DIRECTORY);
entry->info.size = 0;
} else {
entry->info.flags = (FSStatFlags) 0;
if (strcmp(entry_->d_name, ".") == 0 || strcmp(entry_->d_name, "..") == 0) {
entry->info.size = 0;
} else {
struct stat sb{};
int strLen = strlen(dir_handles[handle_index].path) + 1 + strlen(entry_->d_name) + 1;
char path[strLen];
snprintf(path, sizeof(path), "%s/%s", dir_handles[handle_index].path, entry_->d_name);
if (stat(path, &sb) >= 0) {
entry->info.size = sb.st_size;
entry->info.flags = (FSStatFlags) 0;
entry->info.owner = sb.st_uid;
entry->info.group = sb.st_gid;
}
}
}
result = FS_STATUS_OK;
}
OSUnlockMutex(dir_handles[handle_index].mutex);
return result_handler(result);
}
FSStatus FSCloseDirWrapper(FSDirectoryHandle handle,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidDirHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
if (handle_index >= DIR_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return FS_STATUS_FATAL_ERROR;
}
OSLockMutex(dir_handles[handle_index].mutex);
DIR *dir = dir_handles[handle_index].dir;
FSStatus result = FS_STATUS_OK;
if (closedir(dir) != 0) {
result = FS_STATUS_MEDIA_ERROR;
}
OSUnlockMutex(dir_handles[handle_index].mutex);
freeDirHandle(handle_index);
return result_handler(result);
}
FSStatus FSRewindDirWrapper(FSDirectoryHandle handle,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidDirHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
if (handle_index >= DIR_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return FS_STATUS_FATAL_ERROR;
}
uint32_t real_handle = handle & HANDLE_MASK;
OSLockMutex(dir_handles[handle_index].mutex);
DIR *dir = dir_handles[real_handle].dir;
rewinddir(dir);
OSUnlockMutex(dir_handles[handle_index].mutex);
return result_handler(FS_STATUS_OK);
}
FSStatus FSMakeDirWrapper(char *path,
FSErrorFlag errorMask,
std::function<FSStatus(char *_path)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
char pathForCheck[256];
getFullPath(pathForCheck, sizeof(pathForCheck), path);
if (checkForSave(pathForCheck, sizeof(pathForCheck), pathForCheck)) {
DEBUG_FUNCTION_LINE("Redirect save to %s", pathForCheck);
return fallback_function(pathForCheck);
}
if (strncmp(pathForCheck, "/vol/content", 12) == 0) {
FSStatus result = FS_STATUS_OK;
if (errorMask & FS_ERROR_FLAG_ACCESS_ERROR) {
result = FS_STATUS_ACCESS_ERROR;
}
return result_handler(result);
}
return FS_STATUS_USE_REAL_OS;
}
FSStatus FSOpenFileWrapper(char *path,
const char *mode,
FSFileHandle *handle,
FSErrorFlag errorMask,
std::function<FSStatus(char *_path)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
if (path == nullptr) {
OSFATAL_FUNCTION_LINE("Invalid args");
return FS_STATUS_FATAL_ERROR;
}
char pathForCheck[256];
getFullPath(pathForCheck, sizeof(pathForCheck), path);
2021-04-05 19:54:50 +02:00
DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", path, pathForCheck);
2021-01-01 01:39:28 +01:00
if (checkForSave(pathForCheck, sizeof(pathForCheck), pathForCheck)) {
DEBUG_FUNCTION_LINE("Redirect save to %s", pathForCheck);
return fallback_function(pathForCheck);
}
if (mode == nullptr || handle == nullptr) {
DEBUG_FUNCTION_LINE("Invalid args");
return FS_STATUS_FATAL_ERROR;
}
if (strncmp(pathForCheck, "/vol/content", 12) == 0) {
2021-04-05 19:54:50 +02:00
replaceContentPath(pathForCheck, sizeof(pathForCheck), 12, gReplacementInfo.contentReplacementInfo.replacementPath);
DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", path, pathForCheck);
2021-01-01 01:39:28 +01:00
int handle_index = getNewFileHandleIndex();
FSStatus result = FS_STATUS_OK;
if (handle_index >= 0) {
OSLockMutex(file_handles[handle_index].mutex);
int _mode = 0;
// Map flags to open modes
if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0) {
_mode = 0x000;
} else if (strcmp(mode, "r+") == 0) {
_mode = 0x002;
} else if (strcmp(mode, "w") == 0) {
_mode = 0x601;
} else if (strcmp(mode, "w+") == 0) {
_mode = 0x602;
} else if (strcmp(mode, "a") == 0) {
_mode = 0x209;
} else if (strcmp(mode, "a+") == 0) {
_mode = 0x20A;
} else {
//DEBUG_FUNCTION_LINE("%s", mode);
if (errorMask & FS_ERROR_FLAG_ACCESS_ERROR) {
result = FS_STATUS_ACCESS_ERROR;
}
}
int32_t fd = open(pathForCheck, _mode);
if (fd >= 0) {
DEBUG_FUNCTION_LINE_VERBOSE("opened file successfully %d", fd);
file_handles[handle_index].handle = FILE_HANDLE_MAGIC + handle_index;
//DEBUG_FUNCTION_LINE("handle %08X", file_handles[handle_index].handle);
*handle = file_handles[handle_index].handle;
file_handles[handle_index].fd = fd;
file_handles[handle_index].in_use = true;
DCFlushRange(&file_handles[handle_index], sizeof(fileMagic_t));
} else {
DEBUG_FUNCTION_LINE("File not found %s", pathForCheck);
2021-04-05 19:54:50 +02:00
if (gReplacementInfo.contentReplacementInfo.fallbackOnError) {
result = FS_STATUS_USE_REAL_OS;
} else if (errorMask & FS_ERROR_FLAG_NOT_FOUND) {
2021-01-01 01:39:28 +01:00
result = FS_STATUS_NOT_FOUND;
}
}
OSUnlockMutex(file_handles[handle_index].mutex);
} else {
2021-04-05 19:54:50 +02:00
if (gReplacementInfo.contentReplacementInfo.fallbackOnError) {
result = FS_STATUS_USE_REAL_OS;
} else if (errorMask & FS_ERROR_FLAG_MAX) {
2021-01-01 01:39:28 +01:00
result = FS_STATUS_MAX;
}
}
2021-04-05 19:54:50 +02:00
if (result != FS_STATUS_USE_REAL_OS) {
DEBUG_FUNCTION_LINE_VERBOSE("return error %d", result);
return result_handler(result);
}
2021-01-01 01:39:28 +01:00
}
return FS_STATUS_USE_REAL_OS;
}
FSStatus FSCloseFileWrapper(FSFileHandle handle,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidFileHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
if (handle_index >= FILE_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return FS_STATUS_FATAL_ERROR;
}
OSLockMutex(file_handles[handle_index].mutex);
int real_fd = file_handles[handle_index].fd;
file_handles[handle_index].in_use = false;
DEBUG_FUNCTION_LINE_VERBOSE("closing %d", real_fd);
FSStatus result = FS_STATUS_OK;
if (close(real_fd) != 0) {
result = FS_STATUS_MEDIA_ERROR;
}
OSUnlockMutex(file_handles[handle_index].mutex);
freeFileHandle(handle_index);
return result_handler(result);
}
FSStatus FSGetStatWrapper(char *path, FSStat *stats, FSErrorFlag errorMask,
std::function<FSStatus(char *_path)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
if (path == nullptr) {
OSFATAL_FUNCTION_LINE("Invalid args");
return FS_STATUS_FATAL_ERROR;
}
char pathForCheck[256];
getFullPath(pathForCheck, sizeof(pathForCheck), path);
if (checkForSave(pathForCheck, sizeof(pathForCheck), pathForCheck)) {
2021-01-01 01:39:28 +01:00
DEBUG_FUNCTION_LINE("Redirect save to %s", pathForCheck);
return fallback_function(pathForCheck);
}
if (strncmp(pathForCheck, "/vol/content", 12) == 0) {
2021-04-05 19:54:50 +02:00
replaceContentPath(pathForCheck, sizeof(pathForCheck), 12, gReplacementInfo.contentReplacementInfo.replacementPath);
DEBUG_FUNCTION_LINE("%s -> %s", path, pathForCheck);
2021-01-01 01:39:28 +01:00
FSStatus result = FS_STATUS_OK;
if (stats == nullptr) {
2021-04-05 19:54:50 +02:00
if (gReplacementInfo.contentReplacementInfo.fallbackOnError) {
return FS_STATUS_USE_REAL_OS;
}
2021-01-01 01:39:28 +01:00
DEBUG_FUNCTION_LINE("Invalid args");
return FS_STATUS_FATAL_ERROR;
} else {
struct stat path_stat{};
memset(&path_stat, 0, sizeof(path_stat));
if (stat(pathForCheck, &path_stat) < 0) {
2021-04-05 19:54:50 +02:00
if (gReplacementInfo.contentReplacementInfo.fallbackOnError) {
return FS_STATUS_USE_REAL_OS;
} else if (errorMask & FS_ERROR_FLAG_NOT_FOUND) {
DEBUG_FUNCTION_LINE("Path not found %s", pathForCheck);
2021-01-01 01:39:28 +01:00
result = FS_STATUS_NOT_FOUND;
}
} else {
memset(&(stats->flags), 0, sizeof(stats->flags));
if (S_ISDIR(path_stat.st_mode)) {
stats->flags = (FSStatFlags) ((uint32_t) FS_STAT_DIRECTORY);
} else {
stats->size = path_stat.st_size;
stats->mode = (FSMode) FS_MODE_READ_OWNER;
stats->flags = (FSStatFlags) 0;
stats->owner = path_stat.st_uid;
stats->group = path_stat.st_gid;
}
//DEBUG_FUNCTION_LINE("stats file for %s, size %016lLX", path, stats->size);
}
}
return result_handler(result);
}
return FS_STATUS_USE_REAL_OS;
}
2021-04-05 19:54:50 +02:00
static inline void replaceContentPath(char *pathForCheck, int pathForCheckSize, int skipLen, char *replaceWith) {
int subStrLen = strlen(pathForCheck) - skipLen;
if (subStrLen <= 0) {
pathForCheck[0] = '\0';
strncat(pathForCheck, replaceWith, sizeof(pathForCheck) - 1);
} else {
char pathCopy[subStrLen+1];
pathCopy[0] = '\0';
strncat(pathCopy, &pathForCheck[skipLen], sizeof(pathCopy) - 1);
snprintf(pathForCheck, pathForCheckSize, "%s%s", replaceWith, pathCopy);
}
}
2021-01-01 01:39:28 +01:00
FSStatus FSGetStatFileWrapper(FSFileHandle handle,
FSStat *stats,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidFileHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
if (handle_index >= FILE_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return FS_STATUS_FATAL_ERROR;
}
OSLockMutex(file_handles[handle_index].mutex);
int real_fd = file_handles[handle_index].fd;
//DEBUG_FUNCTION_LINE("FSGetStatFileAsync real_fd %d", real_fd);
struct stat path_stat{};
FSStatus result = FS_STATUS_OK;
if (fstat(real_fd, &path_stat) < 0) {
result = FS_STATUS_MEDIA_ERROR;
} else {
memset(&(stats->flags), 0, sizeof(stats->flags));
stats->size = path_stat.st_size;
stats->mode = (FSMode) FS_MODE_READ_OWNER;
stats->flags = (FSStatFlags) 0;
stats->owner = path_stat.st_uid;
stats->group = path_stat.st_gid;
}
OSUnlockMutex(file_handles[handle_index].mutex);
return result_handler(result);
}
FSStatus FSReadFileWrapper(void *buffer,
uint32_t size,
uint32_t count,
FSFileHandle handle,
uint32_t unk1,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidFileHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
if (handle_index >= FILE_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return FS_STATUS_FATAL_ERROR;
}
if (size * count == 0) {
return result_handler(FS_STATUS_OK);
}
if (buffer == nullptr && (size * count != 0)) {
DEBUG_FUNCTION_LINE("Fatal read FSErrorFlag errorMask, buffer is null but size*count is not");
return FS_STATUS_FATAL_ERROR;
}
FSStatus result;
OSLockMutex(file_handles[handle_index].mutex);
int real_fd = file_handles[handle_index].fd;
int32_t read = readIntoBuffer(real_fd, buffer, size, count);
if (read < 0) {
DEBUG_FUNCTION_LINE("Failed to read from handle");
result = FS_STATUS_MEDIA_ERROR;
} else {
result = (FSStatus) (read / size);
}
OSUnlockMutex(file_handles[handle_index].mutex);
return result_handler(result);
}
FSStatus FSReadFileWithPosWrapper(void *buffer,
uint32_t size,
uint32_t count,
uint32_t pos,
FSFileHandle handle,
int32_t unk1,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidFileHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
FSStatus result;
if ((result = FSSetPosFileWrapper(handle, pos, errorMask,
[](FSStatus res) -> FSStatus { return res; })
) != FS_STATUS_OK) {
return result;
}
result = FSReadFileWrapper(buffer, size, count, handle, unk1, errorMask,
[](FSStatus res) -> FSStatus { return res; }
);
if (result != FS_STATUS_USE_REAL_OS && result != FS_STATUS_FATAL_ERROR) {
return result_handler(result);
}
return result;
}
FSStatus FSSetPosFileWrapper(FSFileHandle handle,
uint32_t pos,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidFileHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
if (handle_index >= FILE_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return FS_STATUS_FATAL_ERROR;
}
FSStatus result = FS_STATUS_OK;
OSLockMutex(file_handles[handle_index].mutex);
int real_fd = file_handles[handle_index].fd;
if (lseek(real_fd, (off_t) pos, SEEK_SET) != pos) {
DEBUG_FUNCTION_LINE("Seek failed");
result = FS_STATUS_MEDIA_ERROR;
}
DEBUG_FUNCTION_LINE_VERBOSE("pos set to %d ", pos, real_fd);
OSUnlockMutex(file_handles[handle_index].mutex);
return result_handler(result);
}
FSStatus FSGetPosFileWrapper(FSFileHandle handle,
uint32_t *pos,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidFileHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
if (handle_index >= FILE_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return FS_STATUS_FATAL_ERROR;
}
FSStatus result = FS_STATUS_OK;
OSLockMutex(file_handles[handle_index].mutex);
int real_fd = file_handles[handle_index].fd;
off_t currentPos = lseek(real_fd, (off_t) 0, SEEK_CUR);
if (currentPos == -1) {
DEBUG_FUNCTION_LINE("Failed to get current pos");
result = FS_STATUS_MEDIA_ERROR;
} else {
*pos = currentPos;
DEBUG_FUNCTION_LINE_VERBOSE("result was %d for %d", *pos, real_fd);
}
OSUnlockMutex(file_handles[handle_index].mutex);
return result_handler(result);
}
FSStatus FSIsEofWrapper(FSFileHandle handle,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidFileHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
if (handle_index >= FILE_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return FS_STATUS_FATAL_ERROR;
}
FSStatus result = FS_STATUS_OK;
OSLockMutex(file_handles[handle_index].mutex);
int real_fd = file_handles[handle_index].fd;
off_t currentPos = lseek(real_fd, (off_t) 0, SEEK_CUR);
off_t endPos = lseek(real_fd, (off_t) 0, SEEK_END);
if (currentPos == endPos) {
DEBUG_FUNCTION_LINE_VERBOSE("FSIsEof END for %d\n", real_fd);
result = FS_STATUS_END;
} else {
lseek(real_fd, currentPos, SEEK_CUR);
DEBUG_FUNCTION_LINE_VERBOSE("FSIsEof OK for %d\n", real_fd);
result = FS_STATUS_OK;
}
OSUnlockMutex(file_handles[handle_index].mutex);
return result_handler(result);
}
FSStatus FSTruncateFileWrapper(FSFileHandle handle,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidFileHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
if (handle_index >= FILE_HANDLES_LENGTH) {
DEBUG_FUNCTION_LINE("Invalid handle");
return FS_STATUS_FATAL_ERROR;
}
FSStatus result = FS_STATUS_OK;
if (errorMask & FS_ERROR_FLAG_ACCESS_ERROR) {
result = FS_STATUS_ACCESS_ERROR;
}
return result_handler(result);
}
FSStatus FSWriteFileWrapper(uint8_t *buffer,
uint32_t size,
uint32_t count,
FSFileHandle handle,
uint32_t unk1,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) ||
!isValidFileHandle(handle)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
FSStatus result = FS_STATUS_OK;
if (errorMask & FS_ERROR_FLAG_ACCESS_ERROR) {
result = FS_STATUS_ACCESS_ERROR;
}
return result_handler(result);
}
FSStatus FSRemoveWrapper(char *path,
FSErrorFlag errorMask,
std::function<FSStatus(char *_path)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
if (path == nullptr) {
OSFATAL_FUNCTION_LINE("Invalid args");
return FS_STATUS_USE_REAL_OS;
}
char pathForCheck[256];
getFullPath(pathForCheck, sizeof(pathForCheck), path);
if (checkForSave(pathForCheck, sizeof(pathForCheck), pathForCheck)) {
DEBUG_FUNCTION_LINE("Redirect save to %s", pathForCheck);
return fallback_function(pathForCheck);
}
FSStatus result = FS_STATUS_OK;
if (errorMask & FS_ERROR_FLAG_ACCESS_ERROR) {
result = FS_STATUS_ACCESS_ERROR;
}
return result_handler(result);
}
FSStatus FSRenameWrapper(char *oldPath,
char *newPath,
FSErrorFlag errorMask,
std::function<FSStatus(char *_oldPath, char *_newPath)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
char pathForCheck1[256];
char pathForCheck2[256];
getFullPath(pathForCheck1, sizeof(pathForCheck1), oldPath);
getFullPath(pathForCheck2, sizeof(pathForCheck2), newPath);
if (checkForSave(pathForCheck1, sizeof(pathForCheck1), pathForCheck1)) {
if (checkForSave(pathForCheck2, sizeof(pathForCheck2), pathForCheck2)) {
DEBUG_FUNCTION_LINE("Redirect save to %s/%s", pathForCheck1, pathForCheck2);
return fallback_function(pathForCheck1, pathForCheck2);
}
}
FSStatus result = FS_STATUS_OK;
if (errorMask & FS_ERROR_FLAG_ACCESS_ERROR) {
result = FS_STATUS_ACCESS_ERROR;
}
return result_handler(result);
}
FSStatus FSFlushFileWrapper(FSFileHandle handle, FSErrorFlag errorMask, std::function<FSStatus(FSStatus)> result_handler) {
2021-04-05 19:54:50 +02:00
if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) ||
(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) {
2021-01-01 01:39:28 +01:00
return FS_STATUS_USE_REAL_OS;
}
FSStatus result = FS_STATUS_OK;
2021-04-05 19:54:50 +02:00
2021-01-01 01:39:28 +01:00
if (errorMask & FS_ERROR_FLAG_ACCESS_ERROR) {
result = FS_STATUS_ACCESS_ERROR;
}
return result_handler(result);
}