diff --git a/source/ApplicationState.h b/source/ApplicationState.h index 2b12bb4..dc43df1 100644 --- a/source/ApplicationState.h +++ b/source/ApplicationState.h @@ -17,16 +17,29 @@ public: virtual eSubState update(Input *input) = 0; - virtual void proccessMenuNavigation(Input *input, int32_t maxOptionValue) { + virtual void proccessMenuNavigationY(Input *input, int32_t maxOptionValue) { if (input->data.buttons_d & Input::BUTTON_UP) { - this->selectedOption--; + this->selectedOptionY--; } else if (input->data.buttons_d & Input::BUTTON_DOWN) { - this->selectedOption++; + this->selectedOptionY++; } - if (this->selectedOption < 0) { - this->selectedOption = maxOptionValue; - } else if (this->selectedOption >= maxOptionValue) { - this->selectedOption = 0; + if (this->selectedOptionY < 0) { + this->selectedOptionY = maxOptionValue; + } else if (this->selectedOptionY >= maxOptionValue) { + this->selectedOptionY = 0; + } + } + + virtual void proccessMenuNavigationX(Input *input, int32_t maxOptionValue) { + if (input->data.buttons_d & Input::BUTTON_LEFT) { + this->selectedOptionX--; + } else if (input->data.buttons_d & Input::BUTTON_RIGHT) { + this->selectedOptionX++; + } + if (this->selectedOptionX < 0) { + this->selectedOptionX = maxOptionValue; + } else if (this->selectedOptionX >= maxOptionValue) { + this->selectedOptionX = 0; } } @@ -46,5 +59,6 @@ public: } - int selectedOption = 0; + int selectedOptionY = 0; + int selectedOptionX = 0; }; \ No newline at end of file diff --git a/source/GMPartitionsDumperState.cpp b/source/GMPartitionsDumperState.cpp index 602acba..6162651 100644 --- a/source/GMPartitionsDumperState.cpp +++ b/source/GMPartitionsDumperState.cpp @@ -27,7 +27,7 @@ #define READ_BUFFER_SIZE (SECTOR_SIZE * 128) -GMPartitionsDumperState::GMPartitionsDumperState() { +GMPartitionsDumperState::GMPartitionsDumperState(eDumpTarget pTargetDevice) : targetDevice(pTargetDevice) { this->sectorBufSize = SECTOR_SIZE; this->state = STATE_OPEN_ODD1; } @@ -77,11 +77,11 @@ void GMPartitionsDumperState::render() { for (auto &content: partitionPair.second->tmd->contentList) { size += ROUNDUP(content->encryptedFileSize, 16); } - WiiUScreen::drawLinef("%s %s (~%0.2f MiB)", index == (uint32_t) selectedOption ? ">" : " ", partitionPair.first->getVolumeId().c_str(), (float) size / 1024.0f / 1024.0f); + WiiUScreen::drawLinef("%s %s (~%0.2f MiB)", index == (uint32_t) selectedOptionY ? ">" : " ", partitionPair.first->getVolumeId().c_str(), (float) size / 1024.0f / 1024.0f); index++; } WiiUScreen::drawLine(); - WiiUScreen::drawLinef("%s Back", index == (uint32_t) selectedOption ? ">" : " "); + WiiUScreen::drawLinef("%s Back", index == (uint32_t) selectedOptionY ? ">" : " "); } } else if (this->state == STATE_CREATE_DATA_PROVIDER) { WiiUScreen::drawLine("Create data provider from partition"); @@ -227,12 +227,12 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) { return SUBSTATE_RETURN; } } - proccessMenuNavigation(input, (int32_t) gmPartitionPairs.size() + 1); + proccessMenuNavigationY(input, (int32_t) gmPartitionPairs.size() + 1); if (entrySelected(input)) { - if (selectedOption >= (int32_t) gmPartitionPairs.size()) { + if (selectedOptionY >= (int32_t) gmPartitionPairs.size()) { return SUBSTATE_RETURN; } - auto gmPartitionPair = gmPartitionPairs[selectedOption]; + auto gmPartitionPair = gmPartitionPairs[selectedOptionY]; if (gmPartitionPair.first != nullptr) { this->curPartition = gmPartitionPair.first; this->curNUSTitle = gmPartitionPair.second; @@ -243,8 +243,11 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) { return SUBSTATE_RUNNING; } - this->targetPath = StringTools::strfmt("%swudump/%s/%s", "ntfs0:/", this->discId, curPartition->getVolumeId().c_str()); - FSUtils::CreateSubfolder(targetPath.c_str()); + this->targetPath = StringTools::strfmt("%swudump/%s/%s", getPathForDevice(targetDevice).c_str(), this->discId, curPartition->getVolumeId().c_str()); + if (!FSUtils::CreateSubfolder(targetPath.c_str())) { + this->setError(ERROR_CREATE_DIR); + return SUBSTATE_RUNNING; + } this->state = STATE_DUMP_PARTITION_TMD; } @@ -388,6 +391,14 @@ void GMPartitionsDumperState::setError(GMPartitionsDumperState::eErrorState err) //OSEnableHomeButtonMenu(true); } +std::string GMPartitionsDumperState::getPathForDevice(eDumpTarget target) const { + if(target == TARGET_SD){ + return "fs:/vol/external01/"; + } else if (target == TARGET_NTFS){ + return "ntfs0:/"; + } +} + std::string GMPartitionsDumperState::ErrorMessage() const { if (this->errorState == ERROR_MALLOC_FAILED) { return "ERROR_MALLOC_FAILED"; @@ -407,6 +418,9 @@ std::string GMPartitionsDumperState::ErrorMessage() const { if (this->errorState == ERROR_NO_GM_PARTITION) { return "ERROR_NO_GM_PARTITION"; } + if (this->errorState == ERROR_CREATE_DIR) { + return "ERROR_CREATE_DIR"; + } if (this->errorState == ERROR_FAILED_TO_GET_NUSTITLE) { return "ERROR_FAILED_TO_GET_NUSTITLE"; } diff --git a/source/GMPartitionsDumperState.h b/source/GMPartitionsDumperState.h index ef155ac..2a2bd49 100644 --- a/source/GMPartitionsDumperState.h +++ b/source/GMPartitionsDumperState.h @@ -58,6 +58,7 @@ public: ERROR_OPEN_ODD1, ERROR_PARSE_DISCHEADER, ERROR_NO_GM_PARTITION, + ERROR_CREATE_DIR, ERROR_FAILED_TO_GET_NUSTITLE, ERROR_FAILED_WRITE_TMD, ERROR_FAILED_WRITE_TICKET, @@ -69,7 +70,7 @@ public: ERROR_WRITE_CONTENT }; - explicit GMPartitionsDumperState(); + explicit GMPartitionsDumperState(eDumpTarget pTargetDevice); ~GMPartitionsDumperState() override; @@ -82,6 +83,8 @@ public: void setError(eErrorState err); + [[nodiscard]] std::string getPathForDevice(eDumpTarget target) const; + std::array discId{}; std::array cKey{}; @@ -107,4 +110,6 @@ public: [[nodiscard]] std::string ErrorDescription() const; std::vector, std::shared_ptr>> gmPartitionPairs; + + eDumpTarget targetDevice = TARGET_SD; }; \ No newline at end of file diff --git a/source/MainApplicationState.cpp b/source/MainApplicationState.cpp index 23e338c..69d5e67 100644 --- a/source/MainApplicationState.cpp +++ b/source/MainApplicationState.cpp @@ -40,10 +40,18 @@ void MainApplicationState::render() { if (this->state == STATE_WELCOME_SCREEN) { WiiUScreen::drawLine("Welcome to Wudump"); WiiUScreen::drawLine(""); - WiiUScreen::drawLinef("%s Dump as WUX", this->selectedOption == 0 ? ">" : " "); - WiiUScreen::drawLinef("%s Dump as WUD", this->selectedOption == 1 ? ">" : " "); - WiiUScreen::drawLinef("%s Dump partition as .app", this->selectedOption == 2 ? ">" : " "); - WiiUScreen::drawLinef("%s Exit", this->selectedOption == 3 ? ">" : " "); + WiiUScreen::drawLinef("%s Dump as WUX", this->selectedOptionY == 0 ? ">" : " "); + WiiUScreen::drawLinef("%s Dump as WUD", this->selectedOptionY == 1 ? ">" : " "); + WiiUScreen::drawLinef("%s Dump partition as .app", this->selectedOptionY == 2 ? ">" : " "); + WiiUScreen::drawLine(); + WiiUScreen::drawLinef("%s Dumptarget:", this->selectedOptionY == 3 ? ">" : " "); + if (ntfs_mount_count > 0) { + WiiUScreen::drawLinef(" [%s] SD [%s] NTFS (USB)", dumpTarget == TARGET_SD ? "x" : " ", dumpTarget == TARGET_NTFS ? "x" : " "); + } else { + WiiUScreen::drawLinef(" [%s] SD ??? NTFS (USB) (not connected)", dumpTarget == TARGET_SD ? "*" : " "); + } + WiiUScreen::drawLine(); + WiiUScreen::drawLinef("%s Exit", this->selectedOptionY == 4 ? ">" : " "); } printFooter(); @@ -52,21 +60,33 @@ void MainApplicationState::render() { ApplicationState::eSubState MainApplicationState::update(Input *input) { if (this->state == STATE_WELCOME_SCREEN) { - proccessMenuNavigation(input, 4); + proccessMenuNavigationY(input, 5); + if (selectedOptionY == 3) { + if (ntfs_mount_count > 0) { + proccessMenuNavigationX(input, 2); + if (selectedOptionX == 0) { + dumpTarget = TARGET_SD; + } else { + dumpTarget = TARGET_NTFS; + } + } + } if (entrySelected(input)) { - if (this->selectedOption == 0) { + if (this->selectedOptionY == 0) { this->state = STATE_DO_SUBSTATE; - this->subState = std::make_unique(WUDDumperState::DUMP_AS_WUX); - } else if (this->selectedOption == 1) { + this->subState = std::make_unique(WUDDumperState::DUMP_AS_WUX, dumpTarget); + } else if (this->selectedOptionY == 1) { this->state = STATE_DO_SUBSTATE; - this->subState = std::make_unique(WUDDumperState::DUMP_AS_WUD); - } else if (this->selectedOption == 2) { + this->subState = std::make_unique(WUDDumperState::DUMP_AS_WUD, dumpTarget); + } else if (this->selectedOptionY == 2) { this->state = STATE_DO_SUBSTATE; - this->subState = std::make_unique(); + this->subState = std::make_unique(dumpTarget); + } else if (this->selectedOptionY == 3) { + // } else { SYSLaunchMenu(); } - this->selectedOption = 0; + this->selectedOptionY = 0; } } else if (this->state == STATE_DO_SUBSTATE) { auto retSubState = this->subState->update(input); @@ -74,7 +94,6 @@ ApplicationState::eSubState MainApplicationState::update(Input *input) { // keep running. return SUBSTATE_RUNNING; } else if (retSubState == SUBSTATE_RETURN) { - DEBUG_FUNCTION_LINE("Delete sub state"); this->subState.reset(); this->state = STATE_WELCOME_SCREEN; } diff --git a/source/MainApplicationState.h b/source/MainApplicationState.h index 14564c3..57de14d 100644 --- a/source/MainApplicationState.h +++ b/source/MainApplicationState.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "input/Input.h" #include "fs/CFile.hpp" #include "ApplicationState.h" @@ -46,4 +47,6 @@ private: std::unique_ptr subState{}; eGameState state = STATE_WELCOME_SCREEN; + + eDumpTarget dumpTarget = TARGET_SD; }; \ No newline at end of file diff --git a/source/WUDDumperState.cpp b/source/WUDDumperState.cpp index 753d12b..789b95b 100644 --- a/source/WUDDumperState.cpp +++ b/source/WUDDumperState.cpp @@ -24,8 +24,8 @@ #include #include "WUDDumperState.h" -WUDDumperState::WUDDumperState(WUDDumperState::eDumpTargetFormat pTarget) - : target(pTarget) { +WUDDumperState::WUDDumperState(WUDDumperState::eDumpTargetFormat pTargetFormat, eDumpTarget pTargetDevice) + : targetFormat(pTargetFormat), targetDevice(pTargetDevice) { this->sectorBufSize = READ_SECTOR_SIZE * READ_NUM_SECTORS; this->state = STATE_OPEN_ODD1; } @@ -38,7 +38,6 @@ WUDDumperState::~WUDDumperState() { free(emptySector); } - ApplicationState::eSubState WUDDumperState::update(Input *input) { if (this->state == STATE_RETURN) { return ApplicationState::SUBSTATE_RETURN; @@ -113,25 +112,27 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) { } if (hasDiscKey) { - if (!FSUtils::CreateSubfolder(StringTools::fmt("%swudump/%s", "ntfs0:/", discId))) { + if (!FSUtils::CreateSubfolder(StringTools::fmt("%swudump/%s", getPathForDevice(targetDevice).c_str(), discId))) { setError(ERROR_WRITE_FAILED); return SUBSTATE_RUNNING; } - if (!FSUtils::saveBufferToFile(StringTools::fmt("%swudump/%s/game.key", "ntfs0:/", discId), discKey, 16)) { + if (!FSUtils::saveBufferToFile(StringTools::fmt("%swudump/%s/game.key", getPathForDevice(targetDevice).c_str(), discId), discKey, 16)) { setError(ERROR_WRITE_FAILED); return SUBSTATE_RUNNING; } } this->state = STATE_DUMP_DISC_START; } else if (this->state == STATE_DUMP_DISC_START) { - if (!FSUtils::CreateSubfolder(StringTools::fmt("%swudump/%s", "ntfs0:/", discId))) { + if (!FSUtils::CreateSubfolder(StringTools::fmt("%swudump/%s", getPathForDevice(targetDevice).c_str(), discId))) { setError(ERROR_WRITE_FAILED); return ApplicationState::SUBSTATE_RUNNING; } - if (target == DUMP_AS_WUX) { - this->fileHandle = std::make_unique(StringTools::fmt("%swudump/%s/game.wux", "ntfs0:/", discId), CFile::WriteOnly, READ_SECTOR_SIZE * WRITE_BUFFER_NUM_SECTORS, SECTOR_SIZE); + if (targetFormat == DUMP_AS_WUX) { + this->fileHandle = std::make_unique(StringTools::fmt("%swudump/%s/game.wux", getPathForDevice(targetDevice).c_str(), discId), READ_SECTOR_SIZE * WRITE_BUFFER_NUM_SECTORS, + SECTOR_SIZE, true); } else { - this->fileHandle = std::make_unique(StringTools::fmt("%swudump/%s/game.wud", "ntfs0:/", discId), CFile::WriteOnly, READ_SECTOR_SIZE * WRITE_BUFFER_NUM_SECTORS, SECTOR_SIZE); + this->fileHandle = std::make_unique(StringTools::fmt("%swudump/%s/game.wud", getPathForDevice(targetDevice).c_str(), discId), READ_SECTOR_SIZE * WRITE_BUFFER_NUM_SECTORS, + SECTOR_SIZE, true); } if (!this->fileHandle->isOpen()) { DEBUG_FUNCTION_LINE("Failed to open file"); @@ -166,6 +167,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) { this->setError(ERROR_WRITE_FAILED); return ApplicationState::SUBSTATE_RUNNING; } + this->fileHandle->finalize(); this->fileHandle->close(); } } @@ -224,7 +226,6 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) { return ApplicationState::SUBSTATE_RUNNING; } - void WUDDumperState::render() { WiiUScreen::clearScreen(); ApplicationState::printHeader(); @@ -238,6 +239,8 @@ void WUDDumperState::render() { WiiUScreen::drawLine("Open /dev/odd01"); } else if (this->state == STATE_PLEASE_INSERT_DISC) { WiiUScreen::drawLine("Please insert a Wii U disc and try again.\n\nPress A to return"); + } else if (this->state == STATE_DUMP_DISC_KEY) { + WiiUScreen::drawLine("Read disc key"); } else if (this->state == STATE_READ_DISC_INFO) { WiiUScreen::drawLine("Read disc information"); } else if (this->state == STATE_READ_DISC_INFO_DONE) { @@ -247,7 +250,7 @@ void WUDDumperState::render() { float percent = this->currentSector / (WUD_FILE_SIZE / READ_SECTOR_SIZE * 1.0f) * 100.0f; WiiUScreen::drawLinef("Progress: %0.2f MiB / %5.2f MiB (%2.1f %%)", this->currentSector * (READ_SECTOR_SIZE / 1024.0f / 1024.0f), WUD_FILE_SIZE / 1024.0f / 1024.0f, percent); - if (target == DUMP_AS_WUX) { + if (targetFormat == DUMP_AS_WUX) { WiiUScreen::drawLinef("Written %0.2f MiB. Compression ratio 1:%0.2f", writtenSectors * (READ_SECTOR_SIZE / 1024.0f / 1024.0f), 1.0f / (writtenSectors / (float) this->currentSector)); } @@ -324,3 +327,10 @@ std::string WUDDumperState::ErrorDescription() const { } return "UNKNOWN_ERROR"; } + +std::string WUDDumperState::getPathForDevice(eDumpTarget target) const { + if (target == TARGET_NTFS) { + return "ntfs0:/"; + } + return "fs:/vol/external01/"; +} diff --git a/source/WUDDumperState.h b/source/WUDDumperState.h index 1ed98d5..124a631 100644 --- a/source/WUDDumperState.h +++ b/source/WUDDumperState.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "ApplicationState.h" #include "fs/WriteOnlyFileWithCache.h" #include "fs/WUXFileWriter.h" @@ -61,12 +62,12 @@ public: ERROR_NO_DISC_FOUND }; - explicit WUDDumperState(eDumpTargetFormat pTarget); + explicit WUDDumperState(eDumpTargetFormat pTarget, eDumpTarget pTargetDevice); ~WUDDumperState() override; eDumpState state; - eDumpTargetFormat target; + eDumpTargetFormat targetFormat; WUDDumperState::eErrorState errorState = ERROR_NONE; void render() override; @@ -79,6 +80,10 @@ public: [[nodiscard]] std::string ErrorDescription() const; + [[nodiscard]] std::string getPathForDevice(eDumpTarget target) const; + + eDumpTarget targetDevice = TARGET_SD; + void *sectorBuf = nullptr; int readResult = 0; @@ -105,4 +110,5 @@ public: int32_t writtenSectors{}; void *emptySector = nullptr; + }; \ No newline at end of file diff --git a/source/common/common.cpp b/source/common/common.cpp index e20c3cc..d67aefc 100644 --- a/source/common/common.cpp +++ b/source/common/common.cpp @@ -1,3 +1,6 @@ #include "common.h" -int32_t gFSAfd = -1; \ No newline at end of file +int32_t gFSAfd = -1; + +ntfs_md *ntfs_mounts = nullptr; +int ntfs_mount_count = 0; diff --git a/source/common/common.h b/source/common/common.h index 7e80796..e758788 100644 --- a/source/common/common.h +++ b/source/common/common.h @@ -1,8 +1,17 @@ #pragma once #include +#include extern int32_t gFSAfd; #define SECTOR_SIZE 0x8000 -#define READ_SECTOR_SIZE SECTOR_SIZE \ No newline at end of file +#define READ_SECTOR_SIZE SECTOR_SIZE + +extern ntfs_md *ntfs_mounts; +extern int ntfs_mount_count; + +enum eDumpTarget { + TARGET_SD, + TARGET_NTFS +}; \ No newline at end of file diff --git a/source/fs/CFile.hpp b/source/fs/CFile.hpp index a49720e..29a8869 100644 --- a/source/fs/CFile.hpp +++ b/source/fs/CFile.hpp @@ -40,7 +40,7 @@ public: return false; } - virtual void close(); + void close(); virtual int32_t read(uint8_t *ptr, size_t size); @@ -50,7 +50,7 @@ public: virtual int32_t seek(int64_t offset, int32_t origin); - [[nodiscard]] uint64_t tell() const { + [[nodiscard]] virtual uint64_t tell() const { return pos; }; diff --git a/source/fs/WUDFileWriter.cpp b/source/fs/WUDFileWriter.cpp index 4c1cb38..b45039d 100644 --- a/source/fs/WUDFileWriter.cpp +++ b/source/fs/WUDFileWriter.cpp @@ -17,8 +17,8 @@ #include #include "WUDFileWriter.h" -WUDFileWriter::WUDFileWriter(const char *path, eOpenTypes mode, int32_t cacheSize, int32_t pSectorSize) : - WriteOnlyFileWithCache(path, mode, cacheSize), +WUDFileWriter::WUDFileWriter(const char *path, int32_t cacheSize, int32_t pSectorSize, bool split) : + WriteOnlyFileWithCache(path, cacheSize, split), sectorSize(pSectorSize) { } @@ -30,6 +30,6 @@ int32_t WUDFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSecto return -1; } -WUDFileWriter::~WUDFileWriter() { - WUDFileWriter::close(); +void WUDFileWriter::finalize() { + } diff --git a/source/fs/WUDFileWriter.h b/source/fs/WUDFileWriter.h index 12b8048..1cc59a3 100644 --- a/source/fs/WUDFileWriter.h +++ b/source/fs/WUDFileWriter.h @@ -20,12 +20,11 @@ class WUDFileWriter : public WriteOnlyFileWithCache { public: - WUDFileWriter(const char *string, eOpenTypes types, int32_t cacheSize, int32_t sectorSize); - - ~WUDFileWriter() override; + WUDFileWriter(const char *string, int32_t cacheSize, int32_t sectorSize, bool split = false); virtual int32_t writeSector(const uint8_t *buffer, uint32_t numberOfSectors); + virtual void finalize(); protected: int32_t sectorSize; }; diff --git a/source/fs/WUXFileWriter.cpp b/source/fs/WUXFileWriter.cpp index 996600d..431af49 100644 --- a/source/fs/WUXFileWriter.cpp +++ b/source/fs/WUXFileWriter.cpp @@ -18,8 +18,8 @@ #include "WUXFileWriter.h" #include "WUDDumperState.h" -WUXFileWriter::WUXFileWriter(const char *path, CFile::eOpenTypes mode, int32_t cacheSize, int32_t sectorSize) : - WUDFileWriter(path, mode, cacheSize, sectorSize) { +WUXFileWriter::WUXFileWriter(const char *path, int32_t cacheSize, int32_t sectorSize, bool split) : + WUDFileWriter(path, cacheSize, sectorSize, split) { wuxHeader_t wuxHeader = {0}; wuxHeader.magic0 = WUX_MAGIC_0; wuxHeader.magic1 = WUX_MAGIC_1; @@ -28,7 +28,6 @@ WUXFileWriter::WUXFileWriter(const char *path, CFile::eOpenTypes mode, int32_t c wuxHeader.flags = 0; this->write((uint8_t *) &wuxHeader, sizeof(wuxHeader_t)); - this->flush(); this->sectorTableStart = this->tell(); this->totalSectorCount = WUD_FILE_SIZE / this->sectorSize; @@ -44,7 +43,6 @@ WUXFileWriter::WUXFileWriter(const char *path, CFile::eOpenTypes mode, int32_t c WUDFileWriter::close(); return; } - this->flush(); this->sectorTableEnd = this->tell(); uint64_t tableEnd = this->sectorTableEnd; @@ -56,9 +54,9 @@ WUXFileWriter::WUXFileWriter(const char *path, CFile::eOpenTypes mode, int32_t c auto *paddingData = (uint8_t *) malloc(padding); memset(paddingData, 0, padding); this->write(reinterpret_cast(paddingData), padding); - this->flush(); free(paddingData); this->hashMap.clear(); + flush(); } int32_t WUXFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSectors) { @@ -96,18 +94,22 @@ int32_t WUXFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSecto void WUXFileWriter::writeSectorIndexTable() { if (this->isOpen()) { + flush(); // We need to make sure to call CFile::seek! - CFile::seek((int64_t) sectorTableStart, SEEK_SET); - CFile::write((uint8_t *) sectorIndexTable, totalSectorCount * 4); + seek((int64_t) sectorTableStart, SEEK_SET_BASE_CLASS); + write((uint8_t *) sectorIndexTable, totalSectorCount * 4); + flush(); } } -void WUXFileWriter::close() { - writeSectorIndexTable(); - CFile::close(); -} - WUXFileWriter::~WUXFileWriter() { WUXFileWriter::close(); free(sectorIndexTable); } + +void WUXFileWriter::finalize() { + WUDFileWriter::finalize(); + writeSectorIndexTable(); + WUXFileWriter::close(); + +} diff --git a/source/fs/WUXFileWriter.h b/source/fs/WUXFileWriter.h index 1880777..ad2b4d8 100644 --- a/source/fs/WUXFileWriter.h +++ b/source/fs/WUXFileWriter.h @@ -33,13 +33,13 @@ typedef struct { class WUXFileWriter : public WUDFileWriter { public: - WUXFileWriter(const char *string, eOpenTypes types, int32_t cacheSize, int32_t pSectorSize); + WUXFileWriter(const char *string, int32_t cacheSize, int32_t pSectorSize, bool split = false); ~WUXFileWriter() override; int32_t writeSector(const uint8_t *buffer, uint32_t numberOfSectors) override; - void close() override; + void finalize() override; private: void writeSectorIndexTable(); diff --git a/source/fs/WriteOnlyFileWithCache.cpp b/source/fs/WriteOnlyFileWithCache.cpp index b53df06..6bb148d 100644 --- a/source/fs/WriteOnlyFileWithCache.cpp +++ b/source/fs/WriteOnlyFileWithCache.cpp @@ -17,9 +17,14 @@ #include #include #include +#include #include "WriteOnlyFileWithCache.h" -WriteOnlyFileWithCache::WriteOnlyFileWithCache(const char *path, CFile::eOpenTypes mode, int32_t cacheSize) : CFile(path, mode) { +#define SPLIT_SIZE (0x80000000) + +WriteOnlyFileWithCache::WriteOnlyFileWithCache(const char *path, int32_t cacheSize, bool split) : CFile(split ? std::string(path) + ".part1" : path, WriteOnly), + originalPath(path), + splitFile(split) { if (!this->isOpen()) { return; } @@ -50,20 +55,54 @@ bool WriteOnlyFileWithCache::flush() { } int32_t WriteOnlyFileWithCache::write(const uint8_t *addr, size_t writeSize) { - if (writeSize == this->writeBufferSize) { + auto finalAddr = addr; + size_t finalWriteSize = writeSize; + if (splitFile) { + if (pos + writeBufferPos + finalWriteSize >= SPLIT_SIZE) { + DEBUG_FUNCTION_LINE("We need to split"); + if (!flush()) { + return -2; + } + + uint32_t realWriteSize = SPLIT_SIZE - pos; + + if (realWriteSize > 0) { + DEBUG_FUNCTION_LINE("Write remaining %016lld bytes", realWriteSize); + if (CFile::write(reinterpret_cast(addr), realWriteSize) != (int32_t) realWriteSize) { + return -3; + } + } + finalWriteSize = writeSize - realWriteSize; + finalAddr = (uint8_t *) ((uint32_t) addr + realWriteSize); + part++; + if (!flush()) { + return -2; + } + CFile::close(); + + // open the next part + DEBUG_FUNCTION_LINE("Open %s", StringTools::strfmt("%s.part%d", originalPath.c_str(), part).c_str()); + this->open(StringTools::strfmt("%s.part%d", originalPath.c_str(), part), WriteOnly); + } + if (finalWriteSize == 0) { + return (int32_t) writeSize; + } + } + + if (finalWriteSize == this->writeBufferSize) { if (!this->flush()) { DEBUG_FUNCTION_LINE("Flush failed"); return -1; } - return CFile::write(reinterpret_cast(addr), writeSize); + return CFile::write(reinterpret_cast(addr), finalWriteSize); } - auto toWrite = (int32_t) writeSize; + auto toWrite = (int32_t) finalWriteSize; if (toWrite == 0) { return 0; } - int32_t written = 0; + auto written = (int32_t) (writeSize - finalWriteSize); do { int32_t curWrite = toWrite; @@ -71,7 +110,7 @@ int32_t WriteOnlyFileWithCache::write(const uint8_t *addr, size_t writeSize) { if (this->writeBufferPos + curWrite > this->writeBufferSize) { curWrite = this->writeBufferSize - this->writeBufferPos; } - OSBlockMove((void *) (((uint32_t) this->writeBuffer) + this->writeBufferPos), (void *) (addr + written), curWrite, 1); + OSBlockMove((void *) (((uint32_t) this->writeBuffer) + this->writeBufferPos), (void *) (finalAddr + written), curWrite, 1); this->writeBufferPos += curWrite; if (this->writeBufferPos == this->writeBufferSize) { @@ -88,6 +127,20 @@ int32_t WriteOnlyFileWithCache::write(const uint8_t *addr, size_t writeSize) { } int32_t WriteOnlyFileWithCache::seek(int64_t offset, int32_t origin) { + // Hacky trick because we may need a seek. + if (origin == SEEK_SET_BASE_CLASS) { + if (splitFile) { + if ((offset / SPLIT_SIZE) + 1 != part) { + flush(); + close(); + part = (offset / SPLIT_SIZE) + 1; + DEBUG_FUNCTION_LINE("Open %s", StringTools::strfmt("%s.part%d", originalPath.c_str(), part).c_str()); + this->open(StringTools::strfmt("%s.part%d", originalPath.c_str(), part), ReadWrite); + } + return CFile::seek(offset % SPLIT_SIZE, SEEK_SET); + } + return CFile::seek(offset, SEEK_SET); + } return -1; } diff --git a/source/fs/WriteOnlyFileWithCache.h b/source/fs/WriteOnlyFileWithCache.h index b46e4d5..1a51cef 100644 --- a/source/fs/WriteOnlyFileWithCache.h +++ b/source/fs/WriteOnlyFileWithCache.h @@ -18,9 +18,11 @@ #include +#define SEEK_SET_BASE_CLASS 0x4242 + class WriteOnlyFileWithCache : public CFile { public: - WriteOnlyFileWithCache(const char *string, eOpenTypes types, int32_t cacheSize); + WriteOnlyFileWithCache(const char *string, int32_t cacheSize, bool split = false); ~WriteOnlyFileWithCache() override; @@ -30,9 +32,17 @@ public: int32_t read(uint8_t *ptr, size_t size) override; + [[nodiscard]] uint64_t tell() const override { + return pos + writeBufferPos; + }; + bool flush(); void *writeBuffer = nullptr; size_t writeBufferSize; size_t writeBufferPos; + + bool splitFile = false; + int32_t part = 1; + std::string originalPath; }; diff --git a/source/main.cpp b/source/main.cpp index 4b0dae7..168fb88 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "utils/logger.h" #include "utils/WiiUScreen.h" @@ -23,9 +24,6 @@ void main_loop(); bool sIosuhaxMount = false; -ntfs_md *ntfs_mounts = nullptr; -int ntfs_mount_count = 0; - int main(int argc, char **argv) { WHBLogUdpInit(); DEBUG_FUNCTION_LINE("Hello from wudump!"); @@ -37,6 +35,14 @@ int main(int argc, char **argv) { //DEBUG_FUNCTION_LINE("init fat"); //fatInitDefault(); + uint32_t isAPDEnabled; + IMIsAPDEnabled(&isAPDEnabled); + + if (isAPDEnabled) { + DEBUG_FUNCTION_LINE("Disable auto shutdown"); + IMDisableAPD(); + } + ntfs_mount_count = ntfsMountAll((ntfs_md **) &ntfs_mounts, NTFS_DEFAULT | NTFS_RECOVER); for (int i = 0; i < ntfs_mount_count; i++) { @@ -53,6 +59,11 @@ int main(int argc, char **argv) { free(ntfs_mounts); } + if (isAPDEnabled) { + DEBUG_FUNCTION_LINE("Enable auto shutdown"); + IMEnableAPD(); + } + deInitIOSUHax(); WiiUScreen::DeInit();