Add vWii savefile backup/restore

This commit is contained in:
Lázaro Vieira 2017-04-04 03:03:22 -03:00
parent c1fcc54831
commit ba51de6c57
5 changed files with 119 additions and 39 deletions

View File

@ -1,16 +1,15 @@
# savemii
Wii U Save Manager
WiiU/vWii Save Manager
**You need to run iosuhax/mocha cfw first in order for this homebrew to work.**
This homebrew allows you to backup your Wii U savegames to the SD card and also restore them.
This homebrew allows you to backup your Wii U and vWii savegames to the SD card and also restore them.
Up to 256 backups can be made per title.
Backups are stored in sd:/wiiu/apps/savemii/backups.
Please report any issues that may occur.
TODO:
- add vWii support
- installable package
Credits:

View File

@ -4,10 +4,10 @@
<coder>Ryuzaki_MrL</coder>
<version>1.0.0</version>
<release_date>20170404000000</release_date>
<short_description>Wii U Save Manager</short_description>
<long_description>Wii U Save Manager
<short_description>WiiU/vWii Save Manager</short_description>
<long_description>WiiU/vWii Save Manager
You need to run iosuhax/mocha cfw first in order for this homebrew to work.
This homebrew allows you to backup your Wii U savegames to the SD card and also restore them. Up to 256 backups can be made per title. Backups are stored in sd:/wiiu/apps/savemii/backups.</long_description>
This homebrew allows you to backup your Wii U and vWii savegames to the SD card and also restore them. Up to 256 backups can be made per title. Backups are stored in sd:/wiiu/apps/savemii/backups.</long_description>
</app>

View File

@ -16,7 +16,7 @@
u8 slot = 0;
int menu = 0, mode = 0, task = 0, targ = 0;
int cursor = 0, scroll = 0;
int titlecount = 0;
int titleswiiu = 0, titlesvwii = 0;
typedef struct {
u32 highID;
@ -57,7 +57,7 @@ void MCPHookClose() {
mcp_hook_fd = -1;
}
Title* loadTitles() {
Title* loadWiiUTitles() {
int mcp_handle = MCP_Open();
int count = MCP_TitleCount(mcp_handle);
@ -69,6 +69,10 @@ Title* loadTitles() {
MCP_Close(mcp_handle);
Title* titles = malloc(receivedCount*sizeof(Title));
if (!titles) {
promptError("Out of memory.");
return NULL;
}
for (int i = 0; i < receivedCount; i++) {
@ -86,31 +90,39 @@ Title* loadTitles() {
size_t xmlSize = ftell(xmlFile);
fseek(xmlFile, 0, SEEK_SET);
char* xmlBuf = malloc(xmlSize+1);
memset(xmlBuf, 0, xmlSize+1);
fread(xmlBuf, 1, xmlSize, xmlFile);
fclose(xmlFile);
if (xmlBuf) {
memset(xmlBuf, 0, xmlSize+1);
fread(xmlBuf, 1, xmlSize, xmlFile);
fclose(xmlFile);
xmlDocPtr tmp = xmlReadMemory(xmlBuf, xmlSize, "meta.xml", "utf-8", 0);
xmlNode* root_element = xmlDocGetRootElement(tmp);
xmlNode* cur_node = NULL;
for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
if (
(cur_node->type != XML_ELEMENT_NODE) ||
(memcmp(cur_node->name, "shortname_en", 13) != 0) ||
(xmlNodeGetContent(cur_node) == NULL) ||
(!strlen((char*)xmlNodeGetContent(cur_node)))
) continue;
strcpy(titles[titlecount].shortname, (char*)xmlNodeGetContent(cur_node));
xmlDocPtr tmp = xmlReadMemory(xmlBuf, xmlSize, "meta.xml", "utf-8", 0);
xmlNode* root_element = xmlDocGetRootElement(tmp);
xmlNode* cur_node = NULL;
for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
if (
(cur_node->type != XML_ELEMENT_NODE) ||
(memcmp(cur_node->name, "shortname_en", 13) != 0) ||
(xmlNodeGetContent(cur_node) == NULL) ||
(!strlen((char*)xmlNodeGetContent(cur_node)))
) continue;
strcpy(titles[titleswiiu].shortname, (char*)xmlNodeGetContent(cur_node));
}
xmlFreeDoc(tmp);
free(xmlBuf);
}
xmlFreeDoc(tmp);
free(xmlBuf);
}
titles[titlecount].highID = highID;
titles[titlecount].lowID = lowID;
titles[titlecount].isTitleOnUSB = isTitleOnUSB;
titlecount++;
titles[titleswiiu].highID = highID;
titles[titleswiiu].lowID = lowID;
titles[titleswiiu].isTitleOnUSB = isTitleOnUSB;
titleswiiu++;
OSScreenClearBufferEx(0, 0);
OSScreenClearBufferEx(1, 0);
console_print_pos(0, 0, "Loaded %i Wii U titles.", titleswiiu);
OSScreenFlipBuffersEx(0);
OSScreenFlipBuffersEx(1);
}
@ -119,6 +131,66 @@ Title* loadTitles() {
}
Title* loadWiiTitles() {
struct dirent *dirent = NULL;
DIR *dir = NULL;
dir = opendir("slccmpt01:/title/00010000");
if (dir == NULL) {
promptError("Failed to open directory.");
return NULL;
}
while ((dirent = readdir(dir)) != 0) {
if(strcmp(dirent->d_name, "..")==0 || strcmp(dirent->d_name, ".")==0) continue;
titlesvwii++;
} rewinddir(dir);
Title* titles = malloc(titlesvwii*sizeof(Title));
if (!titles) {
promptError("Out of memory.");
return NULL;
}
int i = 0;
while ((dirent = readdir(dir)) != 0) {
if(strcmp(dirent->d_name, "..")==0 || strcmp(dirent->d_name, ".")==0) continue;
char path[256];
sprintf(path, "slccmpt01:/title/00010000/%s/data/banner.bin", dirent->d_name);
FILE* bnrFile = fopen(path, "rb");
if (bnrFile) {
fseek(bnrFile, 0x20, SEEK_SET);
u16* bnrBuf = (u16*)malloc(0x40);
if (bnrBuf) {
fread(bnrBuf, 0x02, 0x20, bnrFile);
fclose(bnrFile);
for (int j = 0, k = 0; j < 0x20; j++) {
titles[i].shortname[k++] = (char)bnrBuf[j];
}
free(bnrBuf);
}
}
titles[i].highID = 0x00010000;
titles[i].lowID = strtoul(dirent->d_name, NULL, 16);
i++;
OSScreenClearBufferEx(0, 0);
OSScreenClearBufferEx(1, 0);
console_print_pos(0, 1, "Loaded %i Wii titles.", i);
OSScreenFlipBuffersEx(0);
OSScreenFlipBuffersEx(1);
}
closedir(dir);
return titles;
}
void unloadTitles(Title* titles) {
free(titles);
}
@ -142,6 +214,9 @@ int Menu_Main(void) {
int fsaFd = IOSUHAX_FSA_Open();
if (fsaFd < 0) {
promptError("IOSUHAX_FSA_Open failed.");
if (mcp_hook_fd >= 0) MCPHookClose();
else IOSUHAX_Close();
return EXIT_SUCCESS;
}
mount_fs("slccmpt01", fsaFd, "/dev/slccmpt01", "/vol/storage_slccmpt01");
@ -149,7 +224,8 @@ int Menu_Main(void) {
mount_fs("storage_usb", fsaFd, NULL, "/vol/storage_usb01");
ucls();
Title* titles = loadTitles();
Title* wiiutitles = loadWiiUTitles();
Title* wiititles = loadWiiTitles();
while(1) {
@ -159,10 +235,13 @@ int Menu_Main(void) {
console_print_pos(0, 0, "SaveMii v%u.%u.%u", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO);
console_print_pos(0, 1, "--------------------------------------------------");
Title* titles = mode ? wiititles : wiiutitles;
int count = mode ? titlesvwii : titleswiiu;
switch(menu) {
case 0: { // Main Menu
console_print_pos(0, 2, " Wii U Save Management");
// console_print_pos(0, 3, " vWii Save Management");
console_print_pos(0, 3, " vWii Save Management");
console_print_pos(0, 2 + cursor, "->");
} break;
case 1: { // WiiU/vWii Save Management
@ -171,9 +250,9 @@ int Menu_Main(void) {
// console_print_pos(0, 4, " Wipe savedata");
console_print_pos(0, 2 + cursor, "->");
} break;
case 2: { // vWii/Wii U Title List
case 2: { // Wii/Wii U Title List
for (int i = 0; i < 14; i++) {
if (i+scroll<0 || i+scroll>=titlecount) break;
if (i+scroll<0 || i+scroll>=count) break;
if (strlen(titles[i+scroll].shortname)) console_print_pos(0, i+2, " %s", titles[i+scroll].shortname);
else console_print_pos(0, i+2, " %08lx%08lx", titles[i+scroll].highID, titles[i+scroll].lowID);
} console_print_pos(0, 2 + cursor, "->");
@ -193,7 +272,7 @@ int Menu_Main(void) {
updatePressedButtons();
updateHeldButtons();
int entrycount = ((menu==0) ? 1 : ((menu==1) ? 2 : titlecount));
int entrycount = ((menu==0) ? 2 : ((menu==1) ? 2 : count));
if (isPressed(VPAD_BUTTON_DOWN) || isHeld(VPAD_BUTTON_DOWN)) {
if (entrycount<=14) cursor = (cursor + 1) % entrycount;
@ -242,7 +321,8 @@ int Menu_Main(void) {
}
unloadTitles(titles);
unloadTitles(wiiutitles);
unloadTitles(wiititles);
fatUnmount("sd");
fatUnmount("usb");

View File

@ -1,5 +1,3 @@
#include <sys/dirent.h>
#include "savemng.h"
#define BUFFER_SIZE 0x80000
@ -129,7 +127,8 @@ void backupSavedata(u32 highID, u32 lowID, bool isUSB, int slot) {
char srcPath[256];
char dstPath[256];
sprintf(srcPath, "storage_%s:/usr/save/%08x/%08x/user", isUSB ? "usb" : "mlc", highID, lowID);
const char* path = ((highID==0x00010000) ? "slccmpt01:/title" : (isUSB ? "storage_usb:/usr/save" : "storage_mlc:/usr/save"));
sprintf(srcPath, "%s/%08x/%08x/%s", path, highID, lowID, (highID==0x00010000) ? "data" : "user");
sprintf(dstPath, "sd:/wiiu/apps/savemii/backups/%08x%08x/%i", highID, lowID, slot);
DumpDir(srcPath, dstPath);
@ -139,8 +138,9 @@ void restoreSavedata(u32 highID, u32 lowID, bool isUSB, int slot) {
char srcPath[256];
char dstPath[256];
const char* path = ((highID==0x00010000) ? "slccmpt01:/title" : (isUSB ? "storage_usb:/usr/save" : "storage_mlc:/usr/save"));
sprintf(srcPath, "sd:/wiiu/apps/savemii/backups/%08x%08x/%i", highID, lowID, slot);
sprintf(dstPath, "storage_%s:/usr/save/%08x/%08x/user", isUSB ? "usb" : "mlc", highID, lowID);
sprintf(dstPath, "%s/%08x/%08x/%s", path, highID, lowID, (highID==0x00010000) ? "data" : "user");
DumpDir(srcPath, dstPath);
}

View File

@ -1,6 +1,7 @@
#ifndef _SAVEMNG_H_
#define _SAVEMNG_H_
#include <sys/dirent.h>
#include <gctypes.h>
#include <fat.h>
#include <iosuhax.h>