mirror of
https://github.com/zeldaret/ss
synced 2026-06-29 11:10:50 -04:00
NandRequestThread
This commit is contained in:
@@ -0,0 +1,321 @@
|
||||
#include "toBeSorted/nand_request_thread.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "egg/core/eggAssertHeap.h" // IWYU pragma: export
|
||||
#include "egg/core/eggThread.h"
|
||||
#include "m/m_heap.h"
|
||||
#include "rvl/NAND/NANDCheck.h"
|
||||
#include "rvl/NAND/NANDCore.h"
|
||||
#include "rvl/NAND/nand.h"
|
||||
#include "rvl/OS/OSMessage.h"
|
||||
#include "rvl/OS/OSMutex.h"
|
||||
#include "rvl/OS/OSThread.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" void fn_802F2920(OSThread *, size_t);
|
||||
|
||||
NandRequestThread::NandRequestThread(
|
||||
int priority, EGG::Heap *commandHeap, void *bufFromGameHeap, size_t bufSize, void *mThreadArg, EGG::Heap *heap
|
||||
)
|
||||
: EGG::Thread(0x4000, 0, priority, heap), mMessageBuffer(nullptr) {
|
||||
// TODO suffers from TList ctor
|
||||
sInstance = this;
|
||||
|
||||
mpCommandHeap = commandHeap;
|
||||
mBufFromGameHeap = bufFromGameHeap;
|
||||
mBufSize = bufSize;
|
||||
|
||||
setThreadCurrentHeap(mHeap::g_assertHeap);
|
||||
fn_802F2920(mOSThread, bufSize);
|
||||
OSInitMessageQueue(&mMessageQueue, &mMessageBuffer, 1);
|
||||
OSInitMutex(&mMutex);
|
||||
OSResumeThread(mOSThread);
|
||||
}
|
||||
|
||||
NandRequestThread::~NandRequestThread() {
|
||||
sInstance = nullptr;
|
||||
}
|
||||
|
||||
void *NandRequestThread::run() {
|
||||
NandRequest *req;
|
||||
while (waitForMessage()) {
|
||||
while (mRequestList.mCount != 0) {
|
||||
req = dequeueRequest();
|
||||
req->execute();
|
||||
req->bHandled = true;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NandRequestCheck *NandRequestThread::checkRequest(u32 neededBlocks, u32 neededFiles) {
|
||||
NandRequestCheck *req = new NandRequestCheck(neededBlocks, neededFiles);
|
||||
if (req != nullptr) {
|
||||
enqueueRequest(req);
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
NandRequestCreate *NandRequestThread::createRequest(const char *filePath, u8 perm, u8 attr) {
|
||||
NandRequestCreate *req = new NandRequestCreate(filePath, perm, attr);
|
||||
if (req != nullptr) {
|
||||
enqueueRequest(req);
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
NandRequestWrite *NandRequestThread::writeRequest(const char *filePath, void *data, size_t dataSize) {
|
||||
NandRequestWrite *req = new NandRequestWrite(filePath, data, dataSize);
|
||||
if (req != nullptr) {
|
||||
enqueueRequest(req);
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
bool NandRequestThread::waitForMessage() {
|
||||
return OSReceiveMessage(&mMessageQueue, nullptr, OS_MSG_PERSISTENT);
|
||||
}
|
||||
|
||||
void NandRequestThread::sendMessage() {
|
||||
OSSendMessage(&mMessageQueue, nullptr, 0);
|
||||
}
|
||||
|
||||
void NandRequestThread::enqueueRequest(NandRequest *request) {
|
||||
mRequestList.insert(request);
|
||||
sendMessage();
|
||||
}
|
||||
|
||||
NandRequest *NandRequestThread::dequeueRequest() {
|
||||
// TODO TList
|
||||
NandRequest *req = mRequestList.GetFirst();
|
||||
|
||||
OSLockMutex(&mMutex);
|
||||
mRequestList.RemoveFirst();
|
||||
OSUnlockMutex(&mMutex);
|
||||
|
||||
sendMessage();
|
||||
return req;
|
||||
}
|
||||
|
||||
NandRequestThread *NandRequestThread::create(
|
||||
int priority, EGG::Heap *commandHeap, void *bufFromGameHeap, size_t bufSize, void *mThreadArg, EGG::Heap *heap
|
||||
) {
|
||||
return new (heap, 0x04) NandRequestThread(priority, commandHeap, bufFromGameHeap, bufSize, mThreadArg, heap);
|
||||
}
|
||||
|
||||
void *NandRequest::operator new(size_t size) {
|
||||
return NandRequestThread::sInstance->mpCommandHeap->alloc(size, -4);
|
||||
}
|
||||
|
||||
void NandRequest::free(NandRequest *ptr) {
|
||||
return NandRequestThread::sInstance->mpCommandHeap->free(ptr);
|
||||
}
|
||||
|
||||
NANDResult NandRequest::getStatus() const {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
NandRequestCheck::NandRequestCheck(u32 neededBlocks, u32 neededFiles) {
|
||||
mResult = 0;
|
||||
mNeededBlocks = neededBlocks;
|
||||
mNeededFiles = neededFiles;
|
||||
}
|
||||
|
||||
bool NandRequestCheck::execute() {
|
||||
mStatus = NANDCheck(mNeededBlocks, mNeededFiles, &mResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
NandRequestCreate::NandRequestCreate(const char *filePath, u8 perm, u8 attr) {
|
||||
mPerm = perm;
|
||||
mAttr = attr;
|
||||
mFilePath = filePath;
|
||||
}
|
||||
|
||||
const char *splitComponent(const char *inPath, char *outPath, size_t size) {
|
||||
char *end = outPath + size - 1;
|
||||
while (true) {
|
||||
if (outPath >= end) {
|
||||
break;
|
||||
}
|
||||
char curr = inPath[0];
|
||||
char next = inPath[1];
|
||||
inPath++;
|
||||
*outPath = curr;
|
||||
outPath++;
|
||||
if (next == '\0' || next == '/') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*outPath = '\0';
|
||||
char curr = *inPath;
|
||||
if (curr != '/') {
|
||||
return inPath;
|
||||
}
|
||||
return inPath + 1;
|
||||
}
|
||||
|
||||
extern "C" NANDResult NANDChangeDir(const char *path);
|
||||
extern "C" NANDResult NANDCreateDir(const char *path, u8 perm, u8 attr);
|
||||
|
||||
bool NandRequestCreate::execute() {
|
||||
char homeDir[64];
|
||||
char pathComponent[64];
|
||||
|
||||
mStatus = NANDGetHomeDir(homeDir);
|
||||
if (mStatus != NAND_RESULT_OK) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *ptr = mFilePath;
|
||||
if (ptr[0] == '/') {
|
||||
ptr = splitComponent(ptr, pathComponent, sizeof(pathComponent));
|
||||
} else {
|
||||
std::strncpy(pathComponent, homeDir, sizeof(pathComponent));
|
||||
}
|
||||
|
||||
mStatus = NANDChangeDir(pathComponent);
|
||||
if (mStatus != NAND_RESULT_OK) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *component = splitComponent(ptr, pathComponent, sizeof(pathComponent));
|
||||
while (component[0] != '\0') {
|
||||
mStatus = NANDCreateDir(pathComponent, mPerm, mAttr);
|
||||
if (mStatus != NAND_RESULT_OK && mStatus != NAND_RESULT_EXISTS) {
|
||||
return true;
|
||||
}
|
||||
mStatus = NANDChangeDir(pathComponent);
|
||||
if (mStatus != NAND_RESULT_OK) {
|
||||
return true;
|
||||
}
|
||||
component = splitComponent(component, pathComponent, sizeof(pathComponent));
|
||||
}
|
||||
|
||||
mStatus = NANDChangeDir(homeDir);
|
||||
if (mStatus != NAND_RESULT_OK) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mStatus = NANDCreate(mFilePath, mPerm, mAttr);
|
||||
return mStatus == NAND_RESULT_OK || mStatus == NAND_RESULT_EXISTS;
|
||||
}
|
||||
|
||||
NandRequestWrite::NandRequestWrite(const char *someString, void *data, size_t dataSize) {
|
||||
mData = data;
|
||||
mDataSize = dataSize;
|
||||
mFailedWrite = false;
|
||||
mFilePath = someString;
|
||||
}
|
||||
|
||||
extern "C" NANDResult NANDSimpleSafeOpen(const char *path, NANDFileInfo *outInfo, int, void *buf, size_t bufLen);
|
||||
extern "C" NANDResult NANDSimpleSafeCancel(NANDFileInfo *info);
|
||||
extern "C" NANDResult NANDSimpleSafeClose(NANDFileInfo *info);
|
||||
|
||||
bool NandRequestWrite::execute() {
|
||||
NANDFileInfo info;
|
||||
mStatus = NANDSimpleSafeOpen(
|
||||
mFilePath, &info, 2, NandRequestThread::getInstance()->getBuf(), NandRequestThread::getInstance()->getBufSize()
|
||||
);
|
||||
if (mStatus != NAND_RESULT_OK) {
|
||||
NANDResult res = NANDSimpleSafeCancel(&info);
|
||||
if (res != NAND_RESULT_OK) {
|
||||
mStatus = res;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
mStatus = NANDWrite(&info, mData, mDataSize);
|
||||
if (mStatus == NAND_RESULT_ECC_CRIT || mStatus == NAND_RESULT_AUTHENTICATION) {
|
||||
mStatus = NANDSimpleSafeCancel(&info);
|
||||
if (mStatus == NAND_RESULT_OK) {
|
||||
mFailedWrite = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NANDResult res = NANDSimpleSafeClose(&info);
|
||||
if (mStatus != mDataSize) {
|
||||
mFailedWrite = true;
|
||||
} else {
|
||||
mStatus = res;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NandRequestHolderBase::isCompleted() const {
|
||||
if (mpRequest != nullptr) {
|
||||
return mpRequest->bHandled;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NANDResult NandRequestHolderBase::getStatus() const {
|
||||
if (mpRequest != nullptr) {
|
||||
return mpRequest->getStatus();
|
||||
}
|
||||
return NAND_RESULT_BUSY;
|
||||
}
|
||||
|
||||
bool NandRequestHolderBase::runToCompletion() {
|
||||
if (mpRequest == nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
do {
|
||||
} while (!isCompleted());
|
||||
NandRequest::free(mpRequest);
|
||||
mpRequest = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NandRequestCheckHolder::check(u32 neededBlocks, u32 neededFiles) {
|
||||
if (mpRequest != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NandRequestCheck *req = NandRequestThread::getInstance()->checkRequest(neededBlocks, neededFiles);
|
||||
if (req == nullptr) {
|
||||
return false;
|
||||
}
|
||||
mpRequest = req;
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 NandRequestCheckHolder::getCheckResult() {
|
||||
return static_cast<NandRequestCheck *>(mpRequest)->mResult;
|
||||
}
|
||||
|
||||
bool NandRequestCreateHolder::create(const char *filePath, u8 perm, u8 attr) {
|
||||
if (mpRequest != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NandRequestCreate *req = NandRequestThread::getInstance()->createRequest(filePath, perm, attr);
|
||||
if (req == nullptr) {
|
||||
return false;
|
||||
}
|
||||
mpRequest = req;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NandRequestWriteHolder::write(const char *filePath, void *data, size_t dataSize) {
|
||||
if (mpRequest != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NandRequestWrite *req = NandRequestThread::getInstance()->writeRequest(filePath, data, dataSize);
|
||||
if (req == nullptr) {
|
||||
return false;
|
||||
}
|
||||
mpRequest = req;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NandRequestWriteHolder::failedWrite() {
|
||||
return static_cast<NandRequestWrite *>(mpRequest)->mFailedWrite;
|
||||
}
|
||||
Reference in New Issue
Block a user