Compare commits

..

31 Commits

Author SHA1 Message Date
mariomadproductions
04872a3e83 README.md: documented autoskip mode 2023-12-26 13:19:29 +01:00
dependabot[bot]
498696953a Bump wiiu-env/devkitppc from 20221228 to 20230621
Bumps wiiu-env/devkitppc from 20221228 to 20230621.

---
updated-dependencies:
- dependency-name: wiiu-env/devkitppc
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-24 13:19:31 +02:00
Maschell
86815beb77 Create dependabot.yml 2023-07-23 10:39:36 +02:00
Maschell
c3dfb55869 Change docker registry to ghcr.io 2023-03-18 16:33:40 +01:00
Maschell
57f823a5de Improve logging 2023-01-10 16:45:57 +01:00
Maschell
0da71f9420 Init AX to stop boot sound while running WUDD 2023-01-10 16:45:57 +01:00
Maschell
60688c0663 Use latest libmocha 2023-01-10 16:45:57 +01:00
Maschell
8a61dda7df Update the CI to use a non-deprecated release action 2023-01-10 16:45:57 +01:00
Maschell
eab18ef051 Bump version to v1.2.2 2023-01-10 16:45:57 +01:00
Maschell
2b46671df6 Store the size of H3HashArray in a uint32_t instead of int8_t to avoid an overflow of the size. 2023-01-02 17:14:49 +01:00
Maschell
cda26ddfd4 Update CI to use actions/checkout@v3 2023-01-02 17:14:49 +01:00
Maschell
5462d030d5 Update Makefile to be compatible with CLion 2023-01-02 17:14:49 +01:00
Maschell
16496baa65 Bump version to v1.2.1 2022-09-20 20:40:46 +02:00
Maschell
359d2e1450 Use ubuntu-22.04 for the CI 2022-09-20 20:40:46 +02:00
Maschell
84a32a5142 Only distribute WUDD as .wuhb 2022-09-20 20:40:46 +02:00
Maschell
bb559cb904 Add a icon to the WUHB 2022-09-20 20:40:46 +02:00
Maschell
6e3cea9b93 Bump version 2022-08-06 22:11:31 +02:00
Maschell
6899987864 Fix decrypted reading with the offset is bigger than UINT32_MAX 2022-08-05 18:48:42 +02:00
Maschell
f09f8f2b29 Use a dedicated FSAClient instead of the wut_devoptab_fs_client. 2022-08-03 22:31:30 +02:00
Maschell
c8a687950f Close raw odd handle in GMPartitionsState constructor 2022-08-03 22:31:30 +02:00
Maschell
2d2267807b Update Dockerfile 2022-08-01 06:10:53 -07:00
Maschell
d6e6b9165d Display the version in the menu 2022-07-28 08:43:42 -07:00
Maschell
a53b47f2b8 Update workflows to not pull submodules anymore 2022-07-28 08:43:42 -07:00
Maschell
4b5a1eca5f Update Dockerfile to use latest wut version 2022-07-28 08:43:42 -07:00
Maschell
26f69ca852 Update github action to build PRs will all logs levels 2022-07-28 08:43:42 -07:00
Maschell
8ece8d1886 Improve displayed error messages 2022-07-28 08:43:42 -07:00
Maschell
bb6734a499 Improve write error handling 2022-07-28 08:43:42 -07:00
Maschell
bc74da90dc Properly check write results 2022-07-28 08:43:42 -07:00
Maschell
4a6269a8e5 Fix exiting via the menu when not running from HBL 2022-07-28 08:43:42 -07:00
Maschell
5a4f9484c3 Adjust debug levels to always log errors 2022-07-28 08:43:42 -07:00
Maschell
d58486e9c6 Remove unused functions / files 2022-07-28 08:43:42 -07:00
30 changed files with 275 additions and 558 deletions

10
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

View File

@ -7,39 +7,35 @@ on:
jobs: jobs:
clang-format: clang-format:
runs-on: ubuntu-18.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: clang-format - name: clang-format
run: | run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source
build-binary: build-binary:
runs-on: ubuntu-18.04 runs-on: ubuntu-22.04
needs: clang-format needs: clang-format
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Checkout submodules using a PAT - name: create version.h
run: | run: |
git config --file .gitmodules --get-regexp url | while read url; do git_hash=$(git rev-parse --short "$GITHUB_SHA")
git config --file=.gitmodules $(echo "$url" | sed -E "s/git@github.com:|https:\/\/github.com\//https:\/\/${{ secrets.CI_PAT }}:${{ secrets.CI_PAT }}@github.com\//") cat <<EOF > ./source/version.h
done #pragma once
git submodule sync #define VERSION_EXTRA " (nightly-$git_hash)"
git submodule update --init --recursive EOF
- name: build binary - name: build binary
run: | run: |
docker build . -t builder docker build . -t builder
docker run --rm -v ${PWD}:/project builder make docker run --rm -v ${PWD}:/project builder make
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
with: with:
name: wuhb-binary name: wuhb-binary
path: "*.wuhb" path: "*.wuhb"
- uses: actions/upload-artifact@master
with:
name: rpx-binary
path: "*.rpx"
deploy-binary: deploy-binary:
needs: build-binary needs: build-binary
runs-on: ubuntu-18.04 runs-on: ubuntu-22.04
steps: steps:
- name: Get environment variables - name: Get environment variables
id: get_repository_name id: get_repository_name
@ -50,32 +46,15 @@ jobs:
with: with:
name: wuhb-binary name: wuhb-binary
path: wiiu/apps/wudd path: wiiu/apps/wudd
- uses: actions/download-artifact@master
with:
name: rpx-binary
path: wiiu/apps/wudd
- name: zip artifact - name: zip artifact
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip wiiu run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip wiiu
- name: Create Release - name: Create Release
id: create_release uses: "softprops/action-gh-release@v1"
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }} tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
release_name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
draft: false draft: false
prerelease: true prerelease: true
body: | generate_release_notes: true
Not a stable release: name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
${{ github.event.head_commit.message }} files: |
- name: Upload Release Asset ./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
asset_name: ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
asset_content_type: application/zip

View File

@ -4,29 +4,40 @@ on: [pull_request]
jobs: jobs:
clang-format: clang-format:
runs-on: ubuntu-18.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: clang-format - name: clang-format
run: | run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source
build-binary: check-build-with-logging:
runs-on: ubuntu-18.04 runs-on: ubuntu-22.04
needs: clang-format needs: clang-format
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Checkout submodules using a PAT - name: build binary with logging
run: |
docker build . -t builder
docker run --rm -v ${PWD}:/project builder make DEBUG=VERBOSE
docker run --rm -v ${PWD}:/project builder make clean
docker run --rm -v ${PWD}:/project builder make DEBUG=1
build-binary:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v3
- name: create version.h
run: | run: |
git config --file .gitmodules --get-regexp url | while read url; do git_hash=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")
git config --file=.gitmodules $(echo "$url" | sed -E "s/git@github.com:|https:\/\/github.com\//https:\/\/${{ secrets.CI_PAT }}:${{ secrets.CI_PAT }}@github.com\//") cat <<EOF > ./source/version.h
done #pragma once
git submodule sync #define VERSION_EXTRA " (nightly-$git_hash)"
git submodule update --init --recursive EOF
- name: build binary - name: build binary
run: | run: |
docker build . -t builder docker build . -t builder
docker run --rm -v ${PWD}:/project builder make docker run --rm -v ${PWD}:/project builder make
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
with: with:
name: binary name: binary
path: "*.rpx" path: "*.wuhb"

View File

@ -1,6 +1,6 @@
FROM wiiuenv/devkitppc:20220724 FROM ghcr.io/wiiu-env/devkitppc:20230621
COPY --from=wiiuenv/libntfs:20220726 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libntfs:20220726 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libmocha:20220726 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libmocha:20220919 /artifacts $DEVKITPRO
WORKDIR project WORKDIR project

View File

@ -52,6 +52,7 @@ SOURCES := source \
DATA := data DATA := data
INCLUDES := source INCLUDES := source
ICON := data/icon.png
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# options for code generation # options for code generation
@ -164,7 +165,7 @@ endif
all: $(BUILD) all: $(BUILD)
$(BUILD): $(BUILD):
@[ -d $@ ] || mkdir -p $@ @$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------

View File

@ -9,6 +9,8 @@ Features:
Files will be dumped to `/wudump/[DISC-ID]/`. The disc id of a game can be found on the disc (e.g. WUP-P-ARDP for the EUR version of Super Mario 3D World). If WUDD fails to determine the disc id, "DISC" with a timestamp will be used instead. Files will be dumped to `/wudump/[DISC-ID]/`. The disc id of a game can be found on the disc (e.g. WUP-P-ARDP for the EUR version of Super Mario 3D World). If WUDD fails to determine the disc id, "DISC" with a timestamp will be used instead.
If you want to create a partial dump (skipped sectors represented by 00 bytes) for discs with unreadable sectors, you can avoid the need to manually choose the skip sectors option on each error, by pressing Y at the error message to activate auto skip mode
## How to merge splitted files ## How to merge splitted files
When you dump a .wux or .wud to the SD card it gets splitted into 2 GiB parts (FAT32 limitation). To merge them you can use the `copy` cmd tool. When you dump a .wux or .wud to the SD card it gets splitted into 2 GiB parts (FAT32 limitation). To merge them you can use the `copy` cmd tool.
@ -51,4 +53,4 @@ docker run -it --rm -v ${PWD}:/project wudd-builder make clean
## Format the code via docker ## Format the code via docker
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source -i` `docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source -i`

BIN
data/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -4,6 +4,7 @@
#include "input/Input.h" #include "input/Input.h"
#include "utils/ScreenUtils.h" #include "utils/ScreenUtils.h"
#include "utils/WiiUScreen.h" #include "utils/WiiUScreen.h"
#include "version.h"
#include <stdint.h> #include <stdint.h>
class ApplicationState { class ApplicationState {
@ -55,7 +56,7 @@ public:
} }
virtual void printHeader() { virtual void printHeader() {
WiiUScreen::drawLine("WUDD - Wii U Disc Dumper"); WiiUScreen::drawLine("WUDD - Wii U Disc Dumper v1.2.2" VERSION_EXTRA);
WiiUScreen::drawLine("=================="); WiiUScreen::drawLine("==================");
WiiUScreen::drawLine(""); WiiUScreen::drawLine("");
} }
@ -76,4 +77,4 @@ public:
int selectedOptionY = 0; int selectedOptionY = 0;
int selectedOptionX = 0; int selectedOptionX = 0;
}; };

View File

@ -36,6 +36,10 @@ GMPartitionsDumperState::GMPartitionsDumperState(eDumpTarget pTargetDevice) : ta
} }
GMPartitionsDumperState::~GMPartitionsDumperState() { GMPartitionsDumperState::~GMPartitionsDumperState() {
if (this->oddFd != -1) {
FSAEx_RawCloseEx(gFSAClientHandle, this->oddFd);
this->oddFd = -1;
}
free(this->sectorBuf); free(this->sectorBuf);
this->sectorBuf = nullptr; this->sectorBuf = nullptr;
free(this->readBuffer); free(this->readBuffer);
@ -178,7 +182,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
} }
if (this->state == STATE_OPEN_ODD1) { if (this->state == STATE_OPEN_ODD1) {
auto ret = FSAEx_RawOpen(__wut_devoptab_fs_client, "/dev/odd01", &(this->oddFd)); auto ret = FSAEx_RawOpenEx(gFSAClientHandle, "/dev/odd01", &(this->oddFd));
if (ret >= 0) { if (ret >= 0) {
if (this->sectorBuf == nullptr) { if (this->sectorBuf == nullptr) {
this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize); this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize);
@ -196,13 +200,13 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
return ApplicationState::SUBSTATE_RETURN; return ApplicationState::SUBSTATE_RETURN;
} }
} else if (this->state == STATE_READ_DISC_INFO) { } else if (this->state == STATE_READ_DISC_INFO) {
if (FSAEx_RawRead(__wut_devoptab_fs_client, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) { if (FSAEx_RawReadEx(gFSAClientHandle, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) {
this->discId[10] = '\0'; this->discId[10] = '\0';
memcpy(this->discId.data(), sectorBuf, 10); memcpy(this->discId.data(), sectorBuf, 10);
this->state = STATE_READ_DISC_INFO_DONE; this->state = STATE_READ_DISC_INFO_DONE;
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} }
FSAEx_RawClose(__wut_devoptab_fs_client, this->oddFd); FSAEx_RawCloseEx(gFSAClientHandle, this->oddFd);
this->oddFd = -1; this->oddFd = -1;
this->setError(ERROR_READ_FIRST_SECTOR); this->setError(ERROR_READ_FIRST_SECTOR);
@ -226,7 +230,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
auto discHeaderOpt = WiiUDiscHeader::make_unique(discReader); auto discHeaderOpt = WiiUDiscHeader::make_unique(discReader);
if (!discHeaderOpt.has_value()) { if (!discHeaderOpt.has_value()) {
DEBUG_FUNCTION_LINE_ERR("Failed to read DiscHeader"); DEBUG_FUNCTION_LINE_ERR("Failed to read DiscHeader");
this->setError(ERROR_PARSE_DISCHEADER); this->setError(ERROR_PARSE_DISC_HEADER);
return SUBSTATE_RUNNING; return SUBSTATE_RUNNING;
} }
this->discHeader = std::move(discHeaderOpt.value()); this->discHeader = std::move(discHeaderOpt.value());
@ -269,7 +273,7 @@ ApplicationState::eSubState GMPartitionsDumperState::update(Input *input) {
this->curNUSTitle = gmPartitionPair.second; this->curNUSTitle = gmPartitionPair.second;
this->dataProvider = this->curNUSTitle->dataProcessor->getDataProvider(); this->dataProvider = this->curNUSTitle->dataProcessor->getDataProvider();
} else { } else {
DEBUG_FUNCTION_LINE("Failed to find a GM partition"); DEBUG_FUNCTION_LINE_ERR("Failed to find a GM partition");
this->setError(ERROR_NO_GM_PARTITION); this->setError(ERROR_NO_GM_PARTITION);
return SUBSTATE_RUNNING; return SUBSTATE_RUNNING;
} }
@ -448,108 +452,77 @@ std::string GMPartitionsDumperState::getPathForDevice(eDumpTarget target) const
} }
std::string GMPartitionsDumperState::ErrorMessage() const { std::string GMPartitionsDumperState::ErrorMessage() const {
if (this->errorState == ERROR_MALLOC_FAILED) { switch (this->errorState) {
return "ERROR_MALLOC_FAILED"; case ERROR_NONE:
} return "ERROR_NONE";
if (this->errorState == ERROR_NO_DISC_ID) { case ERROR_MALLOC_FAILED:
return "ERROR_NO_DISC_ID"; return "ERROR_MALLOC_FAILED";
} case ERROR_READ_FIRST_SECTOR:
if (this->errorState == ERROR_READ_FIRST_SECTOR) { return "ERROR_READ_FIRST_SECTOR";
return "ERROR_READ_FIRST_SECTOR"; case ERROR_OPEN_ODD1:
} return "ERROR_OPEN_ODD1";
if (this->errorState == ERROR_OPEN_ODD1) { case ERROR_PARSE_DISC_HEADER:
return "ERROR_OPEN_ODD1"; return "ERROR_PARSE_DISC_HEADER";
} case ERROR_NO_GM_PARTITION:
if (this->errorState == ERROR_PARSE_DISCHEADER) { return "ERROR_NO_GM_PARTITION";
return "ERROR_PARSE_DISCHEADER"; case ERROR_CREATE_DIR:
} return "ERROR_CREATE_DIR";
if (this->errorState == ERROR_NO_GM_PARTITION) { case ERROR_FAILED_TO_GET_NUSTITLE:
return "ERROR_NO_GM_PARTITION"; return "ERROR_FAILED_TO_GET_NUSTITLE";
} case ERROR_FAILED_WRITE_TMD:
if (this->errorState == ERROR_CREATE_DIR) { return "ERROR_FAILED_WRITE_TMD";
return "ERROR_CREATE_DIR"; case ERROR_FAILED_WRITE_TICKET:
} return "ERROR_FAILED_WRITE_TICKET";
if (this->errorState == ERROR_FAILED_TO_GET_NUSTITLE) { case ERROR_FAILED_WRITE_CERT:
return "ERROR_FAILED_TO_GET_NUSTITLE"; return "ERROR_FAILED_WRITE_CERT";
} case ERROR_FIND_CONTENT_BY_INDEX:
if (this->errorState == ERROR_FAILED_WRITE_TMD) { return "ERROR_FIND_CONTENT_BY_INDEX";
return "ERROR_FAILED_WRITE_TMD"; case ERROR_FAILED_CREATE_FILE:
} return "ERROR_FAILED_CREATE_FILE";
if (this->errorState == ERROR_FAILED_WRITE_TICKET) { case ERROR_FAILED_WRITE_H3:
return "ERROR_FAILED_WRITE_TICKET"; return "ERROR_FAILED_WRITE_H3";
} case ERROR_READ_CONTENT:
if (this->errorState == ERROR_FAILED_WRITE_CERT) { return "ERROR_READ_CONTENT";
return "ERROR_FAILED_WRITE_CERT"; case ERROR_WRITE_CONTENT:
} return "ERROR_WRITE_CONTENT";
if (this->errorState == ERROR_FIND_CONTENT_BY_INDEX) {
return "ERROR_FIND_CONTENT_BY_INDEX";
}
if (this->errorState == ERROR_FAILED_CREATE_FILE) {
return "ERROR_FAILED_CREATE_FILE";
}
if (this->errorState == ERROR_FAILED_WRITE_H3) {
return "ERROR_FAILED_WRITE_H3";
}
if (this->errorState == ERROR_READ_CONTENT) {
return "ERROR_READ_CONTENT";
}
if (this->errorState == ERROR_WRITE_CONTENT) {
return "ERROR_WRITE_CONTENT";
}
if (this->errorState == ERROR_MALLOC_FAILED) {
return "ERROR_MALLOC_FAILED";
} }
return "UNKNOWN_ERROR"; return "UNKNOWN_ERROR";
} }
std::string GMPartitionsDumperState::ErrorDescription() const { std::string GMPartitionsDumperState::ErrorDescription() const {
if (this->errorState == ERROR_MALLOC_FAILED) { switch (this->errorState) {
return "ERROR_MALLOC_FAILED"; case ERROR_NONE:
} break;
if (this->errorState == ERROR_NO_DISC_ID) { case ERROR_MALLOC_FAILED:
return "ERROR_NO_DISC_ID"; return "Failed to allocate memory.";
} case ERROR_READ_FIRST_SECTOR:
if (this->errorState == ERROR_READ_FIRST_SECTOR) { return "Failed to read first sector.";
return "ERROR_READ_FIRST_SECTOR"; case ERROR_OPEN_ODD1:
} return "Failed to read from disc.";
if (this->errorState == ERROR_OPEN_ODD1) { case ERROR_PARSE_DISC_HEADER:
return "ERROR_OPEN_ODD1"; return "Failed to parse the disc header.";
} case ERROR_NO_GM_PARTITION:
if (this->errorState == ERROR_PARSE_DISCHEADER) { return "No games were found on this disc.";
return "ERROR_PARSE_DISCHEADER"; case ERROR_CREATE_DIR:
} return "Failed to create a directory. \nMake sure to have enough space on the storage device.";
if (this->errorState == ERROR_NO_GM_PARTITION) { case ERROR_FAILED_TO_GET_NUSTITLE:
return "ERROR_NO_GM_PARTITION"; return "Failed to parse partition as NUSTitle";
} case ERROR_FAILED_WRITE_TMD:
if (this->errorState == ERROR_FAILED_TO_GET_NUSTITLE) { return "Failed to dump the title.tmd";
return "ERROR_FAILED_TO_GET_NUSTITLE"; case ERROR_FAILED_WRITE_TICKET:
} return "Failed to dump the title.tik";
if (this->errorState == ERROR_FAILED_WRITE_TMD) { case ERROR_FAILED_WRITE_CERT:
return "ERROR_FAILED_WRITE_TMD"; return "Failed to dump the title.cert";
} case ERROR_FIND_CONTENT_BY_INDEX:
if (this->errorState == ERROR_FAILED_WRITE_TICKET) { return "Failed to find requested index";
return "ERROR_FAILED_WRITE_TICKET"; case ERROR_FAILED_CREATE_FILE:
} return "Failed to create a file. \nMake sure to have enough space on the storage device.";
if (this->errorState == ERROR_FAILED_WRITE_CERT) { case ERROR_FAILED_WRITE_H3:
return "ERROR_FAILED_WRITE_CERT"; return "Failed to dump the a .h3 file";
} case ERROR_READ_CONTENT:
if (this->errorState == ERROR_FIND_CONTENT_BY_INDEX) { return "Failed to read the a .app file from disc";
return "ERROR_FIND_CONTENT_BY_INDEX"; case ERROR_WRITE_CONTENT:
} return "Failed to dump a .app. \nMake sure to have enough space on the storage device.";
if (this->errorState == ERROR_FAILED_CREATE_FILE) {
return "ERROR_FAILED_CREATE_FILE";
}
if (this->errorState == ERROR_FAILED_WRITE_H3) {
return "ERROR_FAILED_WRITE_H3";
}
if (this->errorState == ERROR_READ_CONTENT) {
return "ERROR_READ_CONTENT";
}
if (this->errorState == ERROR_WRITE_CONTENT) {
return "ERROR_WRITE_CONTENT";
}
if (this->errorState == ERROR_MALLOC_FAILED) {
return "ERROR_MALLOC_FAILED";
} }
return "UNKNOWN_ERROR"; return "UNKNOWN_ERROR";
} }

View File

@ -55,10 +55,9 @@ public:
enum eErrorState { enum eErrorState {
ERROR_NONE, ERROR_NONE,
ERROR_MALLOC_FAILED, ERROR_MALLOC_FAILED,
ERROR_NO_DISC_ID,
ERROR_READ_FIRST_SECTOR, ERROR_READ_FIRST_SECTOR,
ERROR_OPEN_ODD1, ERROR_OPEN_ODD1,
ERROR_PARSE_DISCHEADER, ERROR_PARSE_DISC_HEADER,
ERROR_NO_GM_PARTITION, ERROR_NO_GM_PARTITION,
ERROR_CREATE_DIR, ERROR_CREATE_DIR,
ERROR_FAILED_TO_GET_NUSTITLE, ERROR_FAILED_TO_GET_NUSTITLE,

View File

@ -88,7 +88,7 @@ ApplicationState::eSubState MainApplicationState::update(Input *input) {
} else if (this->selectedOptionY == 3) { } else if (this->selectedOptionY == 3) {
// //
} else { } else {
if (gRunFromHBL) { if (!gRunFromHBL) {
SYSLaunchMenu(); SYSLaunchMenu();
} }
} }

View File

@ -81,7 +81,7 @@ bool DiscReader::readDecrypted(uint8_t *out_buffer, uint64_t clusterOffset, uint
uint32_t blockNumber = (totalOffset / BLOCK_SIZE); uint32_t blockNumber = (totalOffset / BLOCK_SIZE);
uint32_t blockOffset = (totalOffset % BLOCK_SIZE); uint32_t blockOffset = (totalOffset % BLOCK_SIZE);
readOffset = (blockNumber * BLOCK_SIZE); readOffset = ((uint64_t) blockNumber * BLOCK_SIZE);
if (!useFixedIV) { if (!useFixedIV) {
memset(usedIV, 0, 16); memset(usedIV, 0, 16);
uint64_t ivTemp = usedFileOffset >> 16; uint64_t ivTemp = usedFileOffset >> 16;

View File

@ -31,13 +31,13 @@ DiscReaderDiscDrive::DiscReaderDiscDrive() : DiscReader() {
return; return;
} }
auto ret = FSAEx_RawOpen(__wut_devoptab_fs_client, "/dev/odd01", &device_handle); auto ret = FSAEx_RawOpenEx(gFSAClientHandle, "/dev/odd01", &device_handle);
if (ret < 0) { if (ret < 0) {
free(sector_buf); free(sector_buf);
return; return;
} }
auto res = FSAEx_RawRead(__wut_devoptab_fs_client, sector_buf, READ_SECTOR_SIZE, 1, 3, device_handle); auto res = FSAEx_RawReadEx(gFSAClientHandle, sector_buf, READ_SECTOR_SIZE, 1, 3, device_handle);
if (res >= 0) { if (res >= 0) {
if (((uint32_t *) sector_buf)[0] != WiiUDiscContentsHeader::MAGIC) { if (((uint32_t *) sector_buf)[0] != WiiUDiscContentsHeader::MAGIC) {
uint8_t iv[16]; uint8_t iv[16];
@ -75,7 +75,7 @@ DiscReaderDiscDrive::DiscReaderDiscDrive() : DiscReader() {
} }
bool DiscReaderDiscDrive::readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint32_t block_offset) const { bool DiscReaderDiscDrive::readEncryptedSector(uint8_t *buffer, uint32_t block_cnt, uint32_t block_offset) const {
if (FSAEx_RawRead(__wut_devoptab_fs_client, buffer, READ_SECTOR_SIZE, block_cnt, block_offset, device_handle) < 0) { if (FSAEx_RawReadEx(gFSAClientHandle, buffer, READ_SECTOR_SIZE, block_cnt, block_offset, device_handle) < 0) {
return false; return false;
} }
return true; return true;
@ -87,7 +87,7 @@ bool DiscReaderDiscDrive::IsReady() {
DiscReaderDiscDrive::~DiscReaderDiscDrive() { DiscReaderDiscDrive::~DiscReaderDiscDrive() {
if (device_handle != -1) { if (device_handle != -1) {
FSAEx_RawClose(__wut_devoptab_fs_client, device_handle); FSAEx_RawCloseEx(gFSAClientHandle, device_handle);
device_handle = -1; device_handle = -1;
} }
} }
@ -102,8 +102,8 @@ bool DiscReaderDiscDrive::readEncrypted(uint8_t *buf, uint64_t offset, uint32_t
} }
uint32_t block_cnt = size >> 15; uint32_t block_cnt = size >> 15;
uint32_t offset_in_sectors = offset >> 15; uint32_t offset_in_sectors = offset >> 15;
if (FSAEx_RawRead(__wut_devoptab_fs_client, buf, 0x8000, block_cnt, offset_in_sectors, device_handle) < 0) { if (FSAEx_RawReadEx(gFSAClientHandle, buf, 0x8000, block_cnt, offset_in_sectors, device_handle) < 0) {
DEBUG_FUNCTION_LINE("Failed to read from Disc"); DEBUG_FUNCTION_LINE_ERR("Failed to read from Disc");
return false; return false;
} }
return true; return true;

View File

@ -26,7 +26,6 @@ std::optional<std::unique_ptr<WiiUDiscContentsHeader>> WiiUDiscContentsHeader::m
return {}; return {};
} }
if (!discReader->hasDiscKey) { if (!discReader->hasDiscKey) {
DEBUG_FUNCTION_LINE_ERR();
if (!discReader->readEncrypted(buffer.get(), offset, LENGTH)) { if (!discReader->readEncrypted(buffer.get(), offset, LENGTH)) {
DEBUG_FUNCTION_LINE_ERR("Failed to read data"); DEBUG_FUNCTION_LINE_ERR("Failed to read data");
return {}; return {};

View File

@ -28,5 +28,5 @@ public:
~H3HashArray(); ~H3HashArray();
std::unique_ptr<uint8_t[]> data; std::unique_ptr<uint8_t[]> data;
uint8_t size; uint32_t size;
}; };

View File

@ -35,7 +35,7 @@ WUDDumperState::WUDDumperState(WUDDumperState::eDumpTargetFormat pTargetFormat,
WUDDumperState::~WUDDumperState() { WUDDumperState::~WUDDumperState() {
if (this->oddFd >= 0) { if (this->oddFd >= 0) {
FSAEx_RawClose(__wut_devoptab_fs_client, oddFd); FSAEx_RawCloseEx(gFSAClientHandle, oddFd);
} }
free(sectorBuf); free(sectorBuf);
free(emptySector); free(emptySector);
@ -51,7 +51,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
} }
if (this->state == STATE_OPEN_ODD1) { if (this->state == STATE_OPEN_ODD1) {
if (this->currentSector > 0) { if (this->currentSector > 0) {
auto ret = FSAEx_RawOpen(__wut_devoptab_fs_client, "/dev/odd01", &(this->oddFd)); auto ret = FSAEx_RawOpenEx(gFSAClientHandle, "/dev/odd01", &(this->oddFd));
if (ret >= 0) { if (ret >= 0) {
// continue! // continue!
this->state = STATE_DUMP_DISC; this->state = STATE_DUMP_DISC;
@ -65,12 +65,12 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
this->state = STATE_PLEASE_INSERT_DISC; this->state = STATE_PLEASE_INSERT_DISC;
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} }
auto ret = FSAEx_RawOpen(__wut_devoptab_fs_client, "/dev/odd01", &(this->oddFd)); auto ret = FSAEx_RawOpenEx(gFSAClientHandle, "/dev/odd01", &(this->oddFd));
if (ret >= 0) { if (ret >= 0) {
if (this->sectorBuf == nullptr) { if (this->sectorBuf == nullptr) {
this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize); this->sectorBuf = (void *) memalign(0x100, this->sectorBufSize);
if (this->sectorBuf == nullptr) { if (this->sectorBuf == nullptr) {
DEBUG_FUNCTION_LINE("ERROR_MALLOC_FAILED"); DEBUG_FUNCTION_LINE_ERR("ERROR_MALLOC_FAILED");
this->setError(ERROR_MALLOC_FAILED); this->setError(ERROR_MALLOC_FAILED);
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} }
@ -83,7 +83,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
return SUBSTATE_RETURN; return SUBSTATE_RETURN;
} }
} else if (this->state == STATE_READ_DISC_INFO) { } else if (this->state == STATE_READ_DISC_INFO) {
if (FSAEx_RawRead(__wut_devoptab_fs_client, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) { if (FSAEx_RawReadEx(gFSAClientHandle, this->sectorBuf, READ_SECTOR_SIZE, 1, 0, this->oddFd) >= 0) {
this->discId[10] = '\0'; this->discId[10] = '\0';
memcpy(this->discId.data(), sectorBuf, 10); memcpy(this->discId.data(), sectorBuf, 10);
this->state = STATE_READ_DISC_INFO_DONE; this->state = STATE_READ_DISC_INFO_DONE;
@ -96,7 +96,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
this->state = STATE_DUMP_DISC_KEY; this->state = STATE_DUMP_DISC_KEY;
} else if (this->state == STATE_DUMP_DISC_KEY) { } else if (this->state == STATE_DUMP_DISC_KEY) {
// Read the WiiUDiscContentsHeader to determine if we need disckey and if it's the correct one. // Read the WiiUDiscContentsHeader to determine if we need disckey and if it's the correct one.
auto res = FSAEx_RawRead(__wut_devoptab_fs_client, this->sectorBuf, READ_SECTOR_SIZE, 1, 3, this->oddFd); auto res = FSAEx_RawReadEx(gFSAClientHandle, this->sectorBuf, READ_SECTOR_SIZE, 1, 3, this->oddFd);
WUDDiscKey discKey; WUDDiscKey discKey;
bool hasDiscKey = false; bool hasDiscKey = false;
if (res >= 0) { if (res >= 0) {
@ -132,7 +132,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
SECTOR_SIZE, targetDevice == TARGET_SD); SECTOR_SIZE, targetDevice == TARGET_SD);
} }
if (!this->fileHandle->isOpen()) { if (!this->fileHandle->isOpen()) {
DEBUG_FUNCTION_LINE("Failed to open file"); DEBUG_FUNCTION_LINE_ERR("Failed to open file.");
this->setError(ERROR_FILE_OPEN_FAILED); this->setError(ERROR_FILE_OPEN_FAILED);
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} }
@ -151,7 +151,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
} }
size_t numSectors = this->currentSector + READ_NUM_SECTORS > this->totalSectorCount ? this->totalSectorCount - this->currentSector : READ_NUM_SECTORS; size_t numSectors = this->currentSector + READ_NUM_SECTORS > this->totalSectorCount ? this->totalSectorCount - this->currentSector : READ_NUM_SECTORS;
if ((this->readResult = FSAEx_RawRead(__wut_devoptab_fs_client, sectorBuf, READ_SECTOR_SIZE, numSectors, this->currentSector, this->oddFd)) >= 0) { if ((this->readResult = FSAEx_RawReadEx(gFSAClientHandle, sectorBuf, READ_SECTOR_SIZE, numSectors, this->currentSector, this->oddFd)) >= 0) {
auto curWrittenSectors = fileHandle->writeSector((const uint8_t *) this->sectorBuf, numSectors); auto curWrittenSectors = fileHandle->writeSector((const uint8_t *) this->sectorBuf, numSectors);
if (curWrittenSectors < 0) { if (curWrittenSectors < 0) {
this->setError(ERROR_WRITE_FAILED); this->setError(ERROR_WRITE_FAILED);
@ -165,18 +165,22 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
this->state = STATE_DUMP_DISC_DONE; this->state = STATE_DUMP_DISC_DONE;
if (this->fileHandle->isOpen()) { if (this->fileHandle->isOpen()) {
if (!this->fileHandle->flush()) { if (!this->fileHandle->flush()) {
DEBUG_FUNCTION_LINE("Flush failed"); DEBUG_FUNCTION_LINE_ERR("Final flush failed");
this->setError(ERROR_WRITE_FAILED);
return ApplicationState::SUBSTATE_RUNNING;
}
if (!this->fileHandle->finalize()) {
DEBUG_FUNCTION_LINE_ERR("Finalize failed");
this->setError(ERROR_WRITE_FAILED); this->setError(ERROR_WRITE_FAILED);
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
} }
this->fileHandle->finalize();
this->fileHandle->close(); this->fileHandle->close();
} }
} }
} else { } else {
this->state = STATE_WAIT_USER_ERROR_CONFIRM; this->state = STATE_WAIT_USER_ERROR_CONFIRM;
if (this->oddFd >= 0) { if (this->oddFd >= 0) {
FSAEx_RawClose(__wut_devoptab_fs_client, this->oddFd); FSAEx_RawCloseEx(gFSAClientHandle, this->oddFd);
this->oddFd = -1; this->oddFd = -1;
} }
return ApplicationState::SUBSTATE_RUNNING; return ApplicationState::SUBSTATE_RUNNING;
@ -199,7 +203,7 @@ ApplicationState::eSubState WUDDumperState::update(Input *input) {
} else if (this->state == STATE_WAIT_USER_ERROR_CONFIRM) { } else if (this->state == STATE_WAIT_USER_ERROR_CONFIRM) {
if (this->autoSkipOnError) { if (this->autoSkipOnError) {
if (this->oddFd >= 0) { if (this->oddFd >= 0) {
FSAEx_RawClose(__wut_devoptab_fs_client, this->oddFd); FSAEx_RawCloseEx(gFSAClientHandle, this->oddFd);
this->oddFd = -1; this->oddFd = -1;
} }
} }
@ -251,6 +255,7 @@ void WUDDumperState::render() {
WiiUScreen::drawLinef("Error: %s", ErrorMessage().c_str()); WiiUScreen::drawLinef("Error: %s", ErrorMessage().c_str());
WiiUScreen::drawLinef("Description: %s", ErrorDescription().c_str()); WiiUScreen::drawLinef("Description: %s", ErrorDescription().c_str());
WiiUScreen::drawLine(); WiiUScreen::drawLine();
WiiUScreen::drawLine();
WiiUScreen::drawLine("Press A to return."); WiiUScreen::drawLine("Press A to return.");
} else if (this->state == STATE_OPEN_ODD1) { } else if (this->state == STATE_OPEN_ODD1) {
WiiUScreen::drawLine("Open /dev/odd01"); WiiUScreen::drawLine("Open /dev/odd01");
@ -324,31 +329,37 @@ void WUDDumperState::setError(WUDDumperState::eErrorState err) {
} }
std::string WUDDumperState::ErrorMessage() const { std::string WUDDumperState::ErrorMessage() const {
if (this->errorState == ERROR_READ_FIRST_SECTOR) { switch (this->errorState) {
return "ERROR_READ_FIRST_SECTOR"; case ERROR_READ_FIRST_SECTOR:
} else if (this->errorState == ERROR_FILE_OPEN_FAILED) { return "ERROR_READ_FIRST_SECTOR";
return "ERROR_FILE_OPEN_FAILED"; case ERROR_NONE:
} else if (this->errorState == ERROR_MALLOC_FAILED) { return "ERROR_NONE";
return "ERROR_MALLOC_FAILED"; case ERROR_FILE_OPEN_FAILED:
} else if (this->errorState == ERROR_NO_DISC_ID) { return "ERROR_FILE_OPEN_FAILED";
return "ERROR_NO_DISC_ID"; case ERROR_MALLOC_FAILED:
} else if (this->errorState == ERROR_WRITE_FAILED) { return "ERROR_MALLOC_FAILED";
return "ERROR_WRITE_FAILED"; case ERROR_WRITE_FAILED:
return "ERROR_WRITE_FAILED";
case ERROR_NO_DISC_FOUND:
return "ERROR_NO_DISC_FOUND";
} }
return "UNKNOWN_ERROR"; return "UNKNOWN_ERROR";
} }
std::string WUDDumperState::ErrorDescription() const { std::string WUDDumperState::ErrorDescription() const {
if (this->errorState == ERROR_READ_FIRST_SECTOR) { switch (this->errorState) {
return "Failed to read first sector."; case ERROR_READ_FIRST_SECTOR:
} else if (this->errorState == ERROR_MALLOC_FAILED) { return "Failed to read first sector.";
return "Failed to allocate data."; case ERROR_NONE:
} else if (this->errorState == ERROR_FILE_OPEN_FAILED) { return "ERROR_NONE";
return "Failed to create file"; case ERROR_FILE_OPEN_FAILED:
} else if (this->errorState == ERROR_NO_DISC_ID) { return "Failed to create file \nMake sure to have enough space on the storage device.";
return "Failed to get the disc id"; case ERROR_MALLOC_FAILED:
} else if (this->errorState == ERROR_WRITE_FAILED) { return "Failed to allocate data.";
return "Failed to write the file. \nMake sure to have enough space on the storage"; case ERROR_WRITE_FAILED:
return "Failed to write the file. \nMake sure to have enough space on the storage device.";
case ERROR_NO_DISC_FOUND:
return "Please insert a Wii U disc.";
} }
return "UNKNOWN_ERROR"; return "UNKNOWN_ERROR";
} }

View File

@ -57,7 +57,6 @@ public:
ERROR_READ_FIRST_SECTOR, ERROR_READ_FIRST_SECTOR,
ERROR_FILE_OPEN_FAILED, ERROR_FILE_OPEN_FAILED,
ERROR_MALLOC_FAILED, ERROR_MALLOC_FAILED,
ERROR_NO_DISC_ID,
ERROR_WRITE_FAILED, ERROR_WRITE_FAILED,
ERROR_NO_DISC_FOUND ERROR_NO_DISC_FOUND
}; };

View File

@ -4,3 +4,4 @@ int ntfs_mount_count = 0;
BOOL gRunFromHBL = false; BOOL gRunFromHBL = false;
BOOL gBlockHomeButton = false; BOOL gBlockHomeButton = false;
uint32_t gBlockHomeButtonCooldown = 0; uint32_t gBlockHomeButtonCooldown = 0;
FSAClientHandle gFSAClientHandle = 0;

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <coreinit/filesystem_fsa.h>
#include <ntfs.h> #include <ntfs.h>
#include <wut.h> #include <wut.h>
@ -9,12 +10,13 @@
extern ntfs_md *ntfs_mounts; extern ntfs_md *ntfs_mounts;
extern int ntfs_mount_count; extern int ntfs_mount_count;
extern "C" FSClient *__wut_devoptab_fs_client; extern FSAClientHandle gFSAClientHandle;
extern BOOL gRunFromHBL; extern BOOL gRunFromHBL;
extern BOOL gBlockHomeButton; extern BOOL gBlockHomeButton;
extern uint32_t gBlockHomeButtonCooldown; extern uint32_t gBlockHomeButtonCooldown;
enum eDumpTarget { enum eDumpTarget {
TARGET_SD, TARGET_SD,
TARGET_NTFS TARGET_NTFS

View File

@ -1,64 +1,10 @@
#include "FSUtils.h" #include "FSUtils.h"
#include "CFile.hpp" #include "CFile.hpp"
#include "utils/logger.h" #include <cstdio>
#include "utils/utils.h" #include <cstring>
#include <fcntl.h> #include <fcntl.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
//! always initialze input
*inbuffer = nullptr;
if (size)
*size = 0;
int32_t iFd = open(filepath, O_RDONLY);
if (iFd < 0)
return -1;
uint32_t filesize = lseek(iFd, 0, SEEK_END);
lseek(iFd, 0, SEEK_SET);
auto *buffer = (uint8_t *) memalign(0x40, ROUNDUP(filesize, 0x40));
if (buffer == nullptr) {
close(iFd);
return -2;
}
uint32_t blocksize = 0x4000;
uint32_t done = 0;
int32_t readBytes = 0;
while (done < filesize) {
if (done + blocksize > filesize) {
blocksize = filesize - done;
}
readBytes = read(iFd, buffer + done, blocksize);
if (readBytes <= 0)
break;
done += readBytes;
}
close(iFd);
if (done != filesize) {
free(buffer);
buffer = nullptr;
return -3;
}
*inbuffer = buffer;
//! sign is optional input
if (size) {
*size = filesize;
}
return filesize;
}
int32_t FSUtils::CheckFile(const char *filepath) { int32_t FSUtils::CheckFile(const char *filepath) {
if (!filepath) if (!filepath)
return 0; return 0;
@ -130,39 +76,6 @@ int32_t FSUtils::CreateSubfolder(const char *fullpath) {
return 1; return 1;
} }
bool FSUtils::copyFile(const std::string &in, const std::string &out) {
// Using C++ buffers is **really** slow. Copying in 1023 byte chunks.
// Let's do it the old way.
size_t size;
int source = open(in.c_str(), O_RDONLY, 0);
int dest = open(out.c_str(), 0x602, 0644);
if (source < 0) {
return false;
}
if (dest < 0) {
close(source);
return false;
}
auto bufferSize = 1024 * 1024;
char *buf = (char *) memalign(0x40, ROUNDUP(bufferSize, 0x40));
if (buf == NULL) {
return false;
}
while ((size = read(source, buf, bufferSize)) > 0) {
write(dest, buf, size);
}
free(buf);
close(source);
close(dest);
return true;
}
int32_t FSUtils::saveBufferToFile(const char *path, void *buffer, uint32_t size) { int32_t FSUtils::saveBufferToFile(const char *path, void *buffer, uint32_t size) {
CFile file(path, CFile::WriteOnly); CFile file(path, CFile::WriteOnly);
if (!file.isOpen()) { if (!file.isOpen()) {

View File

@ -5,13 +5,9 @@
class FSUtils { class FSUtils {
public: public:
static int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);
static int32_t CreateSubfolder(const char *fullpath); static int32_t CreateSubfolder(const char *fullpath);
static int32_t CheckFile(const char *filepath); static int32_t CheckFile(const char *filepath);
static bool copyFile(const std::string &in, const std::string &out);
static int32_t saveBufferToFile(const char *path, void *buffer, uint32_t size); static int32_t saveBufferToFile(const char *path, void *buffer, uint32_t size);
}; };

View File

@ -29,5 +29,6 @@ int32_t WUDFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSecto
return -1; return -1;
} }
void WUDFileWriter::finalize() { bool WUDFileWriter::finalize() {
return true;
} }

View File

@ -24,7 +24,7 @@ public:
virtual int32_t writeSector(const uint8_t *buffer, uint32_t numberOfSectors); virtual int32_t writeSector(const uint8_t *buffer, uint32_t numberOfSectors);
virtual void finalize(); virtual bool finalize();
protected: protected:
int32_t sectorSize; int32_t sectorSize;

View File

@ -27,19 +27,24 @@ WUXFileWriter::WUXFileWriter(const char *path, int32_t cacheSize, int32_t sector
wuxHeader.uncompressedSize = swap_uint64(WUD_FILE_SIZE); wuxHeader.uncompressedSize = swap_uint64(WUD_FILE_SIZE);
wuxHeader.flags = 0; wuxHeader.flags = 0;
this->write((uint8_t *) &wuxHeader, sizeof(wuxHeader_t)); if (this->write((uint8_t *) &wuxHeader, sizeof(wuxHeader_t)) != sizeof(wuxHeader_t)) {
DEBUG_FUNCTION_LINE_ERR("Failed to write header");
WUDFileWriter::close();
return;
}
this->sectorTableStart = this->tell(); this->sectorTableStart = this->tell();
this->totalSectorCount = WUD_FILE_SIZE / this->sectorSize; this->totalSectorCount = WUD_FILE_SIZE / this->sectorSize;
this->sectorIndexTable = (void *) memalign(0x40, ROUNDUP(totalSectorCount * 4, 0x40)); this->sectorIndexTable = (void *) memalign(0x40, ROUNDUP(totalSectorCount * 4, 0x40));
if (sectorIndexTable == nullptr) { if (sectorIndexTable == nullptr) {
DEBUG_FUNCTION_LINE("Failed to alloc"); DEBUG_FUNCTION_LINE_ERR("Failed to alloc");
WUDFileWriter::close(); WUDFileWriter::close();
return; return;
} }
memset(this->sectorIndexTable, 0, totalSectorCount * 4); memset(this->sectorIndexTable, 0, totalSectorCount * 4);
if (this->write((uint8_t *) this->sectorIndexTable, totalSectorCount * 4) < 0) { if (this->write((uint8_t *) this->sectorIndexTable, totalSectorCount * 4) != (int32_t) ((uint32_t) totalSectorCount * 4)) {
DEBUG_FUNCTION_LINE_ERR("Failed to write initial sector index table");
WUDFileWriter::close(); WUDFileWriter::close();
return; return;
} }
@ -53,14 +58,24 @@ WUXFileWriter::WUXFileWriter(const char *path, int32_t cacheSize, int32_t sector
uint64_t padding = this->sectorTableEnd - tableEnd; uint64_t padding = this->sectorTableEnd - tableEnd;
auto *paddingData = (uint8_t *) memalign(0x40, ROUNDUP(padding, 0x40)); auto *paddingData = (uint8_t *) memalign(0x40, ROUNDUP(padding, 0x40));
memset(paddingData, 0, padding); memset(paddingData, 0, padding);
this->write(reinterpret_cast<const uint8_t *>(paddingData), padding); if (this->write(reinterpret_cast<const uint8_t *>(paddingData), padding) != (int32_t) padding) {
DEBUG_FUNCTION_LINE_ERR("Failed to write padding.");
WUDFileWriter::close();
return;
}
free(paddingData); free(paddingData);
this->hashMap.clear(); this->hashMap.clear();
flush(); if (!flush()) {
WUXFileWriter::close();
}
} }
int32_t WUXFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSectors) { int32_t WUXFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSectors) {
if (!isOpen()) {
DEBUG_FUNCTION_LINE_ERR("Failed to write sector, file is not open");
return -1;
}
int32_t curWrittenSectors = 0; int32_t curWrittenSectors = 0;
for (uint32_t i = 0; i < numberOfSectors; i++) { for (uint32_t i = 0; i < numberOfSectors; i++) {
uint32_t addr = ((uint32_t) buffer) + (i * this->sectorSize); uint32_t addr = ((uint32_t) buffer) + (i * this->sectorSize);
@ -76,8 +91,8 @@ int32_t WUXFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSecto
indexTable[this->currentSector] = swap_uint32(this->writtenSector); indexTable[this->currentSector] = swap_uint32(this->writtenSector);
hashMap[hashOut] = writtenSector; hashMap[hashOut] = writtenSector;
if (isOpen()) { if (isOpen()) {
if (!write((uint8_t *) addr, this->sectorSize)) { if (write((uint8_t *) addr, this->sectorSize) != this->sectorSize) {
DEBUG_FUNCTION_LINE("Write failed"); DEBUG_FUNCTION_LINE_ERR("Write failed");
return -1; return -1;
} }
} }
@ -89,23 +104,36 @@ int32_t WUXFileWriter::writeSector(const uint8_t *buffer, uint32_t numberOfSecto
return curWrittenSectors; return curWrittenSectors;
} }
void WUXFileWriter::writeSectorIndexTable() { bool WUXFileWriter::writeSectorIndexTable() {
if (this->isOpen()) { if (this->isOpen()) {
flush(); if (!flush()) {
return false;
}
// We need to make sure to call CFile::seek! // We need to make sure to call CFile::seek!
seek((int64_t) sectorTableStart, SEEK_SET_BASE_CLASS); if (seek((int64_t) sectorTableStart, SEEK_SET_BASE_CLASS) < 0) {
write((uint8_t *) sectorIndexTable, totalSectorCount * 4); DEBUG_FUNCTION_LINE_ERR("Seek failed");
flush(); return false;
}
if (write((uint8_t *) sectorIndexTable, totalSectorCount * 4) != (int32_t) ((uint32_t) totalSectorCount * 4)) {
DEBUG_FUNCTION_LINE_ERR("Failed to write sector index table");
return false;
}
if (!flush()) {
return false;
}
} }
return true;
} }
WUXFileWriter::~WUXFileWriter() { WUXFileWriter::~WUXFileWriter() {
WUXFileWriter::flush();
WUXFileWriter::close(); WUXFileWriter::close();
free(sectorIndexTable); free(sectorIndexTable);
} }
void WUXFileWriter::finalize() { bool WUXFileWriter::finalize() {
WUDFileWriter::finalize(); WUDFileWriter::finalize();
writeSectorIndexTable(); bool res = writeSectorIndexTable();
WUXFileWriter::close(); WUXFileWriter::close();
return res;
} }

View File

@ -39,10 +39,10 @@ public:
int32_t writeSector(const uint8_t *buffer, uint32_t numberOfSectors) override; int32_t writeSector(const uint8_t *buffer, uint32_t numberOfSectors) override;
void finalize() override; bool finalize() override;
private: private:
void writeSectorIndexTable(); bool writeSectorIndexTable();
uint64_t totalSectorCount; uint64_t totalSectorCount;

View File

@ -45,8 +45,8 @@ WriteOnlyFileWithCache::~WriteOnlyFileWithCache() {
bool WriteOnlyFileWithCache::flush() { bool WriteOnlyFileWithCache::flush() {
if (this->writeBufferPos > 0) { if (this->writeBufferPos > 0) {
int32_t res = CFile::write(static_cast<const uint8_t *>(this->writeBuffer), this->writeBufferPos); int32_t res = CFile::write(static_cast<const uint8_t *>(this->writeBuffer), this->writeBufferPos);
if (res < 0) { if (res != (int32_t) this->writeBufferPos) {
DEBUG_FUNCTION_LINE("Failed to flush cache, write failed: %d", res); DEBUG_FUNCTION_LINE_ERR("Failed to flush cache, write failed: %d (expected %d)", res, this->writeBufferPos);
return false; return false;
} }
this->writeBufferPos = 0; this->writeBufferPos = 0;
@ -58,8 +58,8 @@ int32_t WriteOnlyFileWithCache::write(const uint8_t *addr, size_t writeSize) {
auto finalAddr = addr; auto finalAddr = addr;
size_t finalWriteSize = writeSize; size_t finalWriteSize = writeSize;
if (splitFile) { if (splitFile) {
if (pos + writeBufferPos + finalWriteSize >= SPLIT_SIZE) { if (pos + writeBufferPos + finalWriteSize >= (uint64_t) SPLIT_SIZE) {
DEBUG_FUNCTION_LINE("We need to split"); DEBUG_FUNCTION_LINE("We need to split files");
if (!flush()) { if (!flush()) {
return -2; return -2;
} }
@ -67,7 +67,7 @@ int32_t WriteOnlyFileWithCache::write(const uint8_t *addr, size_t writeSize) {
uint32_t realWriteSize = SPLIT_SIZE - pos; uint32_t realWriteSize = SPLIT_SIZE - pos;
if (realWriteSize > 0) { if (realWriteSize > 0) {
DEBUG_FUNCTION_LINE("Write remaining %8d bytes", realWriteSize); DEBUG_FUNCTION_LINE_VERBOSE("Write remaining %8d bytes", realWriteSize);
if (CFile::write(reinterpret_cast<const uint8_t *>(addr), realWriteSize) != (int32_t) realWriteSize) { if (CFile::write(reinterpret_cast<const uint8_t *>(addr), realWriteSize) != (int32_t) realWriteSize) {
return -3; return -3;
} }
@ -91,7 +91,7 @@ int32_t WriteOnlyFileWithCache::write(const uint8_t *addr, size_t writeSize) {
if (finalWriteSize == this->writeBufferSize) { if (finalWriteSize == this->writeBufferSize) {
if (!this->flush()) { if (!this->flush()) {
DEBUG_FUNCTION_LINE("Flush failed"); DEBUG_FUNCTION_LINE_ERR("Flush failed");
return -1; return -1;
} }
return CFile::write(reinterpret_cast<const uint8_t *>(addr), finalWriteSize); return CFile::write(reinterpret_cast<const uint8_t *>(addr), finalWriteSize);
@ -115,7 +115,7 @@ int32_t WriteOnlyFileWithCache::write(const uint8_t *addr, size_t writeSize) {
if (this->writeBufferPos == this->writeBufferSize) { if (this->writeBufferPos == this->writeBufferSize) {
if (!this->flush()) { if (!this->flush()) {
DEBUG_FUNCTION_LINE("Flush failed"); DEBUG_FUNCTION_LINE_ERR("Flush failed");
return -2; return -2;
} }
} }

View File

@ -11,6 +11,7 @@
#include <mocha/mocha.h> #include <mocha/mocha.h>
#include <ntfs.h> #include <ntfs.h>
#include <padscore/kpad.h> #include <padscore/kpad.h>
#include <sndcore2/core.h>
#include <thread> #include <thread>
#include <whb/log.h> #include <whb/log.h>
#include <whb/proc.h> #include <whb/proc.h>
@ -37,7 +38,7 @@ procHomeButtonDeniedCustom(void *context) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
initLogging(); initLogging();
DEBUG_FUNCTION_LINE("Hello from wudump!"); AXInit();
WHBProcInit(); WHBProcInit();
WiiUScreen::Init(); WiiUScreen::Init();
@ -53,9 +54,7 @@ int main(int argc, char **argv) {
ProcUIClearCallbacks(); ProcUIClearCallbacks();
ProcUIRegisterCallback(PROCUI_CALLBACK_HOME_BUTTON_DENIED, ProcUIRegisterCallback(PROCUI_CALLBACK_HOME_BUTTON_DENIED,
&procHomeButtonDeniedCustom, NULL, 100); &procHomeButtonDeniedCustom, nullptr, 100);
} else { } else {
gRunFromHBL = false; gRunFromHBL = false;
} }
@ -64,7 +63,7 @@ int main(int argc, char **argv) {
IMIsAPDEnabled(&isAPDEnabled); IMIsAPDEnabled(&isAPDEnabled);
if (isAPDEnabled) { if (isAPDEnabled) {
DEBUG_FUNCTION_LINE("Disable auto shutdown"); DEBUG_FUNCTION_LINE_VERBOSE("Disable auto shutdown");
IMDisableAPD(); IMDisableAPD();
} }
@ -76,8 +75,19 @@ int main(int argc, char **argv) {
WPADInput::init(); WPADInput::init();
gFSAClientHandle = FSAAddClient(nullptr);
if (!gFSAClientHandle) {
OSFatal("FSAAddClient failed");
}
if (Mocha_UnlockFSClientEx(gFSAClientHandle) != MOCHA_RESULT_SUCCESS) {
OSFatal("Failed to unlock FSAClientHandle");
}
main_loop(); main_loop();
FSADelClient(gFSAClientHandle);
WPADInput::close(); WPADInput::close();
if (ntfs_mounts != nullptr) { if (ntfs_mounts != nullptr) {
@ -89,7 +99,7 @@ int main(int argc, char **argv) {
} }
if (isAPDEnabled) { if (isAPDEnabled) {
DEBUG_FUNCTION_LINE("Enable auto shutdown"); DEBUG_FUNCTION_LINE_VERBOSE("Enable auto shutdown");
IMEnableAPD(); IMEnableAPD();
} }
@ -97,12 +107,13 @@ int main(int argc, char **argv) {
WiiUScreen::DeInit(); WiiUScreen::DeInit();
WHBProcShutdown(); WHBProcShutdown();
AXQuit();
return 0; return 0;
} }
void main_loop() { void main_loop() {
DEBUG_FUNCTION_LINE("Creating state"); DEBUG_FUNCTION_LINE_VERBOSE("Creating state");
std::unique_ptr<MainApplicationState> state = std::make_unique<MainApplicationState>(); std::unique_ptr<MainApplicationState> state = std::make_unique<MainApplicationState>();
CombinedInput baseInput; CombinedInput baseInput;
VPadInput vpadInput; VPadInput vpadInput;
@ -112,7 +123,7 @@ void main_loop() {
WPAD_CHAN_2, WPAD_CHAN_2,
WPAD_CHAN_3}; WPAD_CHAN_3};
DEBUG_FUNCTION_LINE("Entering main loop"); DEBUG_FUNCTION_LINE_VERBOSE("Entering main loop");
while (WHBProcIsRunning()) { while (WHBProcIsRunning()) {
baseInput.reset(); baseInput.reset();
if (vpadInput.update(1280, 720)) { if (vpadInput.update(1280, 720)) {
@ -142,7 +153,7 @@ void initMochaLib() {
void deInitMochaLib() { void deInitMochaLib() {
if (slibMochaMount) { if (slibMochaMount) {
Mocha_DeinitLibrary(); Mocha_DeInitLibrary();
} }
Mocha_sdio_disc_interface.shutdown(); Mocha_sdio_disc_interface.shutdown();

View File

@ -1,197 +0,0 @@
// clang-format off
/*
*
* TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based
* on the implementation in boost::uuid::details.
*
* SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1
*
* Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _TINY_SHA1_HPP_
#define _TINY_SHA1_HPP_
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdint.h>
namespace sha1
{
class SHA1
{
public:
typedef uint32_t digest32_t[5];
typedef uint8_t digest8_t[20];
inline static uint32_t LeftRotate(uint32_t value, size_t count) {
return (value << count) ^ (value >> (32-count));
}
SHA1(){ reset(); }
virtual ~SHA1() {}
SHA1(const SHA1& s) { *this = s; }
const SHA1& operator = (const SHA1& s) {
memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t));
memcpy(m_block, s.m_block, 64);
m_blockByteIndex = s.m_blockByteIndex;
m_byteCount = s.m_byteCount;
return *this;
}
SHA1& reset() {
m_digest[0] = 0x67452301;
m_digest[1] = 0xEFCDAB89;
m_digest[2] = 0x98BADCFE;
m_digest[3] = 0x10325476;
m_digest[4] = 0xC3D2E1F0;
m_blockByteIndex = 0;
m_byteCount = 0;
return *this;
}
SHA1& processByte(uint8_t octet) {
this->m_block[this->m_blockByteIndex++] = octet;
++this->m_byteCount;
if(m_blockByteIndex == 64) {
this->m_blockByteIndex = 0;
processBlock();
}
return *this;
}
SHA1& processBlock(const void* const start, const void* const end) {
const uint8_t* begin = static_cast<const uint8_t*>(start);
const uint8_t* finish = static_cast<const uint8_t*>(end);
while(begin != finish) {
processByte(*begin);
begin++;
}
return *this;
}
SHA1& processBytes(const void* const data, size_t len) {
const uint8_t* block = static_cast<const uint8_t*>(data);
processBlock(block, block + len);
return *this;
}
const uint32_t* getDigest(digest32_t digest) {
size_t bitCount = this->m_byteCount * 8;
processByte(0x80);
if (this->m_blockByteIndex > 56) {
while (m_blockByteIndex != 0) {
processByte(0);
}
while (m_blockByteIndex < 56) {
processByte(0);
}
} else {
while (m_blockByteIndex < 56) {
processByte(0);
}
}
processByte(0);
processByte(0);
processByte(0);
processByte(0);
processByte( static_cast<unsigned char>((bitCount>>24) & 0xFF));
processByte( static_cast<unsigned char>((bitCount>>16) & 0xFF));
processByte( static_cast<unsigned char>((bitCount>>8 ) & 0xFF));
processByte( static_cast<unsigned char>((bitCount) & 0xFF));
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
return digest;
}
const uint8_t* getDigestBytes(digest8_t digest) {
digest32_t d32;
getDigest(d32);
size_t di = 0;
digest[di++] = ((d32[0] >> 24) & 0xFF);
digest[di++] = ((d32[0] >> 16) & 0xFF);
digest[di++] = ((d32[0] >> 8) & 0xFF);
digest[di++] = ((d32[0]) & 0xFF);
digest[di++] = ((d32[1] >> 24) & 0xFF);
digest[di++] = ((d32[1] >> 16) & 0xFF);
digest[di++] = ((d32[1] >> 8) & 0xFF);
digest[di++] = ((d32[1]) & 0xFF);
digest[di++] = ((d32[2] >> 24) & 0xFF);
digest[di++] = ((d32[2] >> 16) & 0xFF);
digest[di++] = ((d32[2] >> 8) & 0xFF);
digest[di++] = ((d32[2]) & 0xFF);
digest[di++] = ((d32[3] >> 24) & 0xFF);
digest[di++] = ((d32[3] >> 16) & 0xFF);
digest[di++] = ((d32[3] >> 8) & 0xFF);
digest[di++] = ((d32[3]) & 0xFF);
digest[di++] = ((d32[4] >> 24) & 0xFF);
digest[di++] = ((d32[4] >> 16) & 0xFF);
digest[di++] = ((d32[4] >> 8) & 0xFF);
digest[di++] = ((d32[4]) & 0xFF);
return digest;
}
protected:
void processBlock() {
uint32_t w[80];
for (size_t i = 0; i < 16; i++) {
w[i] = (m_block[i*4 + 0] << 24);
w[i] |= (m_block[i*4 + 1] << 16);
w[i] |= (m_block[i*4 + 2] << 8);
w[i] |= (m_block[i*4 + 3]);
}
for (size_t i = 16; i < 80; i++) {
w[i] = LeftRotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
}
uint32_t a = m_digest[0];
uint32_t b = m_digest[1];
uint32_t c = m_digest[2];
uint32_t d = m_digest[3];
uint32_t e = m_digest[4];
for (std::size_t i=0; i<80; ++i) {
uint32_t f = 0;
uint32_t k = 0;
if (i<20) {
f = (b & c) | (~b & d);
k = 0x5A827999;
} else if (i<40) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (i<60) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = LeftRotate(b, 30);
b = a;
a = temp;
}
m_digest[0] += a;
m_digest[1] += b;
m_digest[2] += c;
m_digest[3] += d;
m_digest[4] += e;
}
private:
digest32_t m_digest;
uint8_t m_block[64];
size_t m_blockByteIndex;
size_t m_byteCount;
};
}
#endif

View File

@ -1,6 +1,4 @@
#include "utils.h" #include "utils.h"
#include "../fs/FSUtils.h"
#include "TinySHA1.hpp"
#include "logger.h" #include "logger.h"
#include <cstddef> #include <cstddef>
#include <cstring> #include <cstring>
@ -40,29 +38,6 @@ void Utils::dumpHex(const void *data, size_t size) {
} }
} }
std::string Utils::calculateSHA1(const char *buffer, size_t size) {
sha1::SHA1 s;
s.processBytes(buffer, size);
uint32_t digest[5];
s.getDigest(digest);
char tmp[48];
snprintf(tmp, 45, "%08X%08X%08X%08X%08X", digest[0], digest[1], digest[2], digest[3], digest[4]);
return tmp;
}
std::string Utils::hashFile(const std::string &path) {
uint8_t *data = NULL;
uint32_t size = 0;
FSUtils::LoadFileToMem(path.c_str(), &data, &size);
if (data == NULL) {
return calculateSHA1(NULL, 0);
}
std::string result = calculateSHA1(reinterpret_cast<const char *>(data), size);
free(data);
return result;
}
unsigned int swap_uint32(unsigned int val) { unsigned int swap_uint32(unsigned int val) {
val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF); val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
return (val << 16) | (val >> 16); return (val << 16) | (val >> 16);

2
source/version.h Normal file
View File

@ -0,0 +1,2 @@
#pragma once
#define VERSION_EXTRA ""