#include "FileUtils.h" #include #include #include #include #include #include #include #include #include #include "utils/StringTools.h" #include "utils/utils.h" #include "utils/logger.h" extern "C" OSMessageQueue *OSGetDefaultAppIOQueue(); FSCmdBlockBody *fsCmdBlockGetBody(FSCmdBlock *cmdBlock) { if (!cmdBlock) { return nullptr; } auto body = (FSCmdBlockBody *) (ROUNDUP((uint32_t) cmdBlock, 0x40)); return body; } std::mutex sendMutex; FSStatus send_result_async(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus status) { if (asyncData->callback != nullptr) { if (asyncData->ioMsgQueue != nullptr) { OSFatal("ERROR: callback and ioMsgQueue both set."); return FS_STATUS_FATAL_ERROR; } // userCallbacks are called in the DefaultAppIOQueue. asyncData->ioMsgQueue = OSGetDefaultAppIOQueue(); //DEBUG_FUNCTION_LINE("Force to OSGetDefaultAppIOQueue (%08X)", asyncData->ioMsgQueue); } if (asyncData->ioMsgQueue != nullptr) { FSAsyncResult *result = &(fsCmdBlockGetBody(block)->asyncResult); //DEBUG_FUNCTION_LINE("Send result %d to ioMsgQueue (%08X)", status, asyncData->ioMsgQueue); result->asyncData.callback = asyncData->callback; result->asyncData.param = asyncData->param; result->asyncData.ioMsgQueue = asyncData->ioMsgQueue; memset(&result->ioMsg, 0, sizeof(result->ioMsg)); result->ioMsg.data = result; result->ioMsg.type = OS_FUNCTION_TYPE_FS_CMD_ASYNC; result->client = client; result->block = block; result->status = status; while (!OSSendMessage(asyncData->ioMsgQueue, (OSMessage *) &(result->ioMsg), OS_MESSAGE_FLAGS_NONE)) { DEBUG_FUNCTION_LINE("Failed to send message"); } } return FS_STATUS_OK; } int32_t readIntoBuffer(int32_t handle, void *buffer, size_t size, size_t count) { int32_t sizeToRead = size * count; /* // https://github.com/decaf-emu/decaf-emu/blob/131aeb14fccff8461a5fd9f2aa5c040ba3880ef5/src/libdecaf/src/cafe/libraries/coreinit/coreinit_fs_cmd.cpp#L2346 if (sizeToRead > 0x100000) { sizeToRead = 0x100000; }*/ void *newBuffer = buffer; int32_t curResult = -1; int32_t totalSize = 0; int32_t toRead = 0; while (sizeToRead > 0) { curResult = read(handle, newBuffer, sizeToRead); if (curResult < 0) { int errsv = errno; DEBUG_FUNCTION_LINE("Error: Reading %08X bytes from handle %08X. result %08X errno: %d ", size * count, handle, curResult, errsv); return -1; } if (curResult == 0) { //DEBUG_FUNCTION_LINE("EOF"); break; } newBuffer = (void *) (((uint32_t) newBuffer) + curResult); totalSize += curResult; sizeToRead -= curResult; if (sizeToRead > 0) { //DEBUG_FUNCTION_LINE("Reading. missing %08X bytes\n", sizeToRead); } } ////DEBUG_FUNCTION_LINE("Success: Read %08X bytes from handle %08X. result %08X \n", size * count, handle, totalSize); return totalSize; } int32_t CheckFile(const char * filepath) { if(!filepath) return 0; struct stat filestat{}; char dirnoslash[strlen(filepath)+2]; snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath); while(dirnoslash[strlen(dirnoslash)-1] == '/') dirnoslash[strlen(dirnoslash)-1] = '\0'; char * notRoot = strrchr(dirnoslash, '/'); if(!notRoot) { strcat(dirnoslash, "/"); } if (stat(dirnoslash, &filestat) == 0) return 1; return 0; } int32_t CreateSubfolder(const char * fullpath) { if(!fullpath) return 0; int32_t result = 0; char dirnoslash[strlen(fullpath)+1]; strcpy(dirnoslash, fullpath); int32_t pos = strlen(dirnoslash)-1; while(dirnoslash[pos] == '/') { dirnoslash[pos] = '\0'; pos--; } if(CheckFile(dirnoslash)) { return 1; } else { char parentpath[strlen(dirnoslash)+2]; strcpy(parentpath, dirnoslash); char * ptr = strrchr(parentpath, '/'); if(!ptr) { //!Device root directory (must be with '/') strcat(parentpath, "/"); struct stat filestat{}; if (stat(parentpath, &filestat) == 0) return 1; return 0; } ptr++; ptr[0] = '\0'; result = CreateSubfolder(parentpath); } if (!result) { return 0; } if (mkdir(dirnoslash, 0777) == -1) { return 0; } return 1; } int32_t getRPXInfoForPath(const std::string &path, romfs_fileInfo *info) { if (romfsMount("rcc", path.c_str(), RomfsSource_FileDescriptor_CafeOS) < 0) { return -1; } DIR *dir; struct dirent *entry; if (!(dir = opendir("rcc:/"))) { romfsUnmount("rcc"); return -2; } bool found = false; int res = -3; while ((entry = readdir(dir)) != nullptr) { DEBUG_FUNCTION_LINE("%s", entry->d_name); if (StringTools::EndsWith(entry->d_name, ".rpx")) { if (romfsGetFileInfoPerPath("rcc", entry->d_name, info) >= 0) { found = true; res = 0; } break; } } closedir(dir); romfsUnmount("rcc"); if (!found) { return -4; } return res; }