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) {
|
2021-04-05 19:46:38 +02:00
|
|
|
//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;
|
|
|
|
|
2021-01-09 21:23:33 +01:00
|
|
|
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")) {
|
2021-01-09 21:23:33 +01:00
|
|
|
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 {
|
2021-01-09 21:23:33 +01:00
|
|
|
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;
|
|
|
|
}
|