RPXLoadingModule/src/FileUtils.cpp

204 lines
5.8 KiB
C++
Raw Normal View History

2021-01-01 01:39:28 +01:00
#include "FileUtils.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <mutex>
#include <coreinit/debug.h>
#include <map>
#include <coreinit/thread.h>
#include <dirent.h>
#include <coreinit/cache.h>
#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.");
2021-01-01 01:39:28 +01:00
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) {
2022-01-26 23:19:27 +01:00
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
2021-01-01 01:39:28 +01:00
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;
2022-01-26 23:19:27 +01:00
// int32_t toRead = 0;
2021-01-01 01:39:28 +01:00
while (sizeToRead > 0) {
curResult = read(handle, newBuffer, sizeToRead);
if (curResult < 0) {
2022-01-26 23:19:27 +01:00
DEBUG_FUNCTION_LINE("Error: Reading %08X bytes from handle %08X. result %08X errno: %d ", size * count, handle, curResult, errno);
2021-01-01 01:39:28 +01:00
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);
}
}
2021-01-24 15:45:30 +01:00
//DEBUG_FUNCTION_LINE("Success: Read %08X bytes from handle %08X. result %08X \n", size * count, handle, totalSize);
2021-01-01 01:39:28 +01:00
return totalSize;
}
2021-09-24 17:14:38 +02:00
int32_t CheckFile(const char *filepath) {
2021-01-24 15:45:30 +01:00
if (!filepath) {
2021-01-01 01:39:28 +01:00
return 0;
2021-01-24 15:45:30 +01:00
}
2021-01-01 01:39:28 +01:00
struct stat filestat{};
2021-01-24 15:45:30 +01:00
char dirnoslash[strlen(filepath) + 2];
2021-01-01 01:39:28 +01:00
snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath);
2021-01-24 15:45:30 +01:00
while (dirnoslash[strlen(dirnoslash) - 1] == '/') {
dirnoslash[strlen(dirnoslash) - 1] = '\0';
}
2021-01-01 01:39:28 +01:00
2021-01-24 15:45:30 +01:00
char *notRoot = strrchr(dirnoslash, '/');
if (!notRoot) {
2021-01-01 01:39:28 +01:00
strcat(dirnoslash, "/");
}
2021-01-24 15:45:30 +01:00
if (stat(dirnoslash, &filestat) == 0) {
2021-01-01 01:39:28 +01:00
return 1;
2021-01-24 15:45:30 +01:00
}
2021-01-01 01:39:28 +01:00
return 0;
}
2021-09-24 17:14:38 +02:00
int32_t CreateSubfolder(const char *fullpath) {
if (!fullpath)
2021-01-01 01:39:28 +01:00
return 0;
int32_t result = 0;
2021-09-24 17:14:38 +02:00
char dirnoslash[strlen(fullpath) + 1];
2021-01-01 01:39:28 +01:00
strcpy(dirnoslash, fullpath);
2021-09-24 17:14:38 +02:00
int32_t pos = strlen(dirnoslash) - 1;
while (dirnoslash[pos] == '/') {
2021-01-01 01:39:28 +01:00
dirnoslash[pos] = '\0';
pos--;
}
2021-09-24 17:14:38 +02:00
if (CheckFile(dirnoslash)) {
2021-01-01 01:39:28 +01:00
return 1;
} else {
2021-09-24 17:14:38 +02:00
char parentpath[strlen(dirnoslash) + 2];
2021-01-01 01:39:28 +01:00
strcpy(parentpath, dirnoslash);
2021-09-24 17:14:38 +02:00
char *ptr = strrchr(parentpath, '/');
2021-01-01 01:39:28 +01:00
2021-09-24 17:14:38 +02:00
if (!ptr) {
2021-01-01 01:39:28 +01:00
//!Device root directory (must be with '/')
strcat(parentpath, "/");
struct stat filestat{};
2021-09-24 17:14:38 +02:00
if (stat(parentpath, &filestat) == 0) {
2021-01-01 01:39:28 +01:00
return 1;
2021-01-24 15:45:30 +01:00
}
2021-01-01 01:39:28 +01:00
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:/code/"))) {
2021-01-01 01:39:28 +01:00
romfsUnmount("rcc");
return -2;
}
bool found = false;
int res = -3;
while ((entry = readdir(dir)) != nullptr) {
if (StringTools::EndsWith(entry->d_name, ".rpx")) {
if (romfsGetFileInfoPerPath("rcc", (std::string("code/") + entry->d_name).c_str(), info) >= 0) {
2021-01-01 01:39:28 +01:00
found = true;
res = 0;
2021-09-24 17:14:38 +02:00
} else {
DEBUG_FUNCTION_LINE("Failed to get info for %s", entry->d_name);
2021-01-01 01:39:28 +01:00
}
break;
}
}
closedir(dir);
romfsUnmount("rcc");
if (!found) {
return -4;
}
return res;
}