#include "FSWrapper.h" #include #include #include #include #include #include #include #include #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; static inline void replaceContentPath(char *pathForCheck, int pathForCheckSize, int replaceLen, char *replaceWith); inline void getFullPath(char *pathForCheck, int pathSize, char *path) { if (path[0] != '/' && path[0] != '\\') { snprintf(pathForCheck, pathSize, "%s%s", gReplacementInfo.contentReplacementInfo.workingDir, path); DEBUG_FUNCTION_LINE_VERBOSE("Real path is %s", path); } else { pathForCheck[0] = '\0'; strncat(pathForCheck, path, pathSize - 1); } for(int i = 0; i < strlen(pathForCheck);i++){ if(pathForCheck[i] == '\\'){ pathForCheck[i] = '/'; } } } inline bool checkForSave(char *pathForCheck, int pathSize, char *path) { if (strncmp(path, "/vol/save", 9) == 0) { int copyLen = strlen(path); char copy[copyLen + 1]; memcpy(copy, path, copyLen); copy[copyLen] = 0; memset(pathForCheck, 0, pathSize); snprintf(pathForCheck, pathSize, "%s%s", gReplacementInfo.contentReplacementInfo.savePath, ©[9]); 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 fallback_function, std::function result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { 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) { replaceContentPath(pathForCheck, sizeof(pathForCheck), 12, gReplacementInfo.contentReplacementInfo.replacementPath); DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", path, pathForCheck); 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; dir_handles[handle_index].path[0] = '\0'; strncat(dir_handles[handle_index].path, pathForCheck, sizeof(dir_handles[handle_index].path) - 1); DCFlushRange(&dir_handles[handle_index], sizeof(dirMagic_t)); OSUnlockMutex(dir_handles[handle_index].mutex); } else { DEBUG_FUNCTION_LINE("Dir not found %s", pathForCheck); if (gReplacementInfo.contentReplacementInfo.fallbackOnError) { return FS_STATUS_USE_REAL_OS; } 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 result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || !isValidDirHandle(handle)) { 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_) { entry->name[0] = '\0'; strncat(entry->name, entry_->d_name, sizeof(entry->name)-1); 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 result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || !isValidDirHandle(handle)) { 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 result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || !isValidDirHandle(handle)) { 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 fallback_function, std::function result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { 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 fallback_function, std::function result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { 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); DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", path, pathForCheck); 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) { replaceContentPath(pathForCheck, sizeof(pathForCheck), 12, gReplacementInfo.contentReplacementInfo.replacementPath); DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", path, pathForCheck); 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); if (gReplacementInfo.contentReplacementInfo.fallbackOnError) { result = FS_STATUS_USE_REAL_OS; } else if (errorMask & FS_ERROR_FLAG_NOT_FOUND) { result = FS_STATUS_NOT_FOUND; } } OSUnlockMutex(file_handles[handle_index].mutex); } else { if (gReplacementInfo.contentReplacementInfo.fallbackOnError) { result = FS_STATUS_USE_REAL_OS; } else if (errorMask & FS_ERROR_FLAG_MAX) { result = FS_STATUS_MAX; } } if (result != FS_STATUS_USE_REAL_OS) { DEBUG_FUNCTION_LINE_VERBOSE("return error %d", result); return result_handler(result); } } return FS_STATUS_USE_REAL_OS; } FSStatus FSCloseFileWrapper(FSFileHandle handle, FSErrorFlag errorMask, std::function result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || !isValidFileHandle(handle)) { 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 fallback_function, std::function result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { 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 (gReplacementInfo.contentReplacementInfo.replaceSave && checkForSave(pathForCheck, sizeof(pathForCheck), pathForCheck)) { DEBUG_FUNCTION_LINE("Redirect save to %s", pathForCheck); return fallback_function(pathForCheck); } if (strncmp(pathForCheck, "/vol/content", 12) == 0) { replaceContentPath(pathForCheck, sizeof(pathForCheck), 12, gReplacementInfo.contentReplacementInfo.replacementPath); DEBUG_FUNCTION_LINE("%s -> %s", path, pathForCheck); FSStatus result = FS_STATUS_OK; if (stats == nullptr) { if (gReplacementInfo.contentReplacementInfo.fallbackOnError) { return FS_STATUS_USE_REAL_OS; } 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) { 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); 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; } 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); } } FSStatus FSGetStatFileWrapper(FSFileHandle handle, FSStat *stats, FSErrorFlag errorMask, std::function result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || !isValidFileHandle(handle)) { 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 result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || !isValidFileHandle(handle)) { 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 result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || !isValidFileHandle(handle)) { 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 result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || !isValidFileHandle(handle)) { 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 result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || !isValidFileHandle(handle)) { 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 result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || !isValidFileHandle(handle)) { 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 result_handler) { 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)) { 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 result_handler) { 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)) { 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 fallback_function, std::function result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { 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 fallback_function, std::function result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { 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 result_handler) { if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) || (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { 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); }