From ea49f43d11d60a1f0fd3e8904d37a112510f5886 Mon Sep 17 00:00:00 2001 From: GabyPCgeeK Date: Sun, 16 Jul 2017 23:39:34 -0400 Subject: [PATCH] Added some warnings, Shows "disc" saves -Now title list is by default sorted by name. -Instead of only asking the WiiU what titles are installed, now also goes through save folders to find saves of titles not installed (disc games). -Now warns if save folder hasn't been initialized. Run title at least one time to init save folder and metadata. (Posible to restore without been initialized but can lead to unwanted behavior.) -Now warns when entering task selection screen of Haxchi/CBHC DS VC save. (Restoring or Wiping save could lead to problems.) --- meta/meta.xml | 4 +- src/main.c | 170 ++++++++++++++++++++++++++++++++++++++++++-------- src/savemng.c | 17 +++-- src/savemng.h | 8 +++ 4 files changed, 161 insertions(+), 38 deletions(-) diff --git a/meta/meta.xml b/meta/meta.xml index bdb68d4..c235fb2 100644 --- a/meta/meta.xml +++ b/meta/meta.xml @@ -2,8 +2,8 @@ SaveMii Mod Ryuzaki_MrL original (GabyPCgeeK mod) - 1.2.0.mod3 - 20170714000000 + 1.2.0.mod4 + 20170716000000 WiiU/vWii Save Manager WiiU/vWii Save Manager diff --git a/src/main.c b/src/main.c index 1c097d0..fcc5a51 100644 --- a/src/main.c +++ b/src/main.c @@ -12,11 +12,11 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_MICRO 0 -#define VERSION_MOD "mod3" +#define VERSION_MOD "mod4" u8 slot = 0; bool allusers = 0, common = 1; -int menu = 0, mode = 0, task = 0, targ = 0, tsort = 0, sorta = 1; +int menu = 0, mode = 0, task = 0, targ = 0, tsort = 1, sorta = 1; int cursor = 0, scroll = 0; int cursorb = 0, scrollb = 0; int titleswiiu = 0, titlesvwii = 0; @@ -63,15 +63,15 @@ int titleSort(const void *c1, const void *c2) if (((Title*)c1)->isTitleOnUSB == ((Title*)c2)->isTitleOnUSB) return 0; if (((Title*)c1)->isTitleOnUSB) - return 1 * sorta; - if (((Title*)c2)->isTitleOnUSB) return -1 * sorta; + if (((Title*)c2)->isTitleOnUSB) + return 1 * sorta; return 0; } else if (tsort==3) { if (((Title*)c1)->isTitleOnUSB && !((Title*)c2)->isTitleOnUSB) - return 1 * sorta; - if (!((Title*)c1)->isTitleOnUSB && ((Title*)c2)->isTitleOnUSB) return -1 * sorta; + if (!((Title*)c1)->isTitleOnUSB && ((Title*)c2)->isTitleOnUSB) + return 1 * sorta; return strcmp(((Title*)c1)->shortName,((Title*)c2)->shortName) * sorta; } @@ -93,22 +93,112 @@ Title* loadWiiUTitles(int run, int fsaFd) { return NULL; } - Title* titles = malloc(receivedCount*sizeof(Title)); + int usable = receivedCount, j = 0; + Saves* savesl = malloc(receivedCount*sizeof(Saves)); + if (!savesl) { + promptError("Out of memory."); + return NULL; + } + for (int i = 0; i < receivedCount; i++) { + char* element = tList+(i*0x61); + savesl[j].highID = *(u32*)(element); + if (savesl[j].highID != 0x00050000) { + usable--; + continue; + } + savesl[j].lowID = *(u32*)(element+4); + savesl[j].dev = !(memcmp(element+0x56, "usb", 4) == 0); + savesl[j].found = false; + j++; + } + savesl = realloc(savesl, usable*sizeof(Saves)); + + int dirUH, dirNH, foundCount = 0, pos = 0, tNoSave = usable; + for(int i = 0; i <= 1; i++) { + char path[255]; + sprintf(path, "/vol/storage_%s01/usr/save/00050000", (i == 0) ? "usb" : "mlc"); + if (IOSUHAX_FSA_OpenDir(fsaFd, path, &dirUH) >= 0) { + while (1) { + directoryEntry_s data; + int ret = IOSUHAX_FSA_ReadDir(fsaFd, dirUH, &data); + if (ret != 0) + break; + + sprintf(path, "/vol/storage_%s01/usr/save/00050000/%s/user", (i == 0) ? "usb" : "mlc", data.name); + if (checkEntry(path) == 2) { + sprintf(path, "/vol/storage_%s01/usr/save/00050000/%s/meta/meta.xml", (i == 0) ? "usb" : "mlc", data.name); + if (checkEntry(path) == 1) { + for (int i = 0; i < usable; i++) { + if ((savesl[i].highID == 0x00050000) && (strtoul(data.name, NULL, 16) == savesl[i].lowID)) { + savesl[i].found = true; + tNoSave--; + break; + } + } + foundCount++; + } + } + } + IOSUHAX_FSA_CloseDir(fsaFd, dirUH); + } + } + + foundCount += tNoSave; + Saves* saves = malloc((foundCount + tNoSave)*sizeof(Saves)); + if (!saves) { + promptError("Out of memory."); + return NULL; + } + for(int i = 0; i <= 1; i++) { + char path[255]; + sprintf(path, "/vol/storage_%s01/usr/save/00050000", (i == 0) ? "usb" : "mlc"); + if (IOSUHAX_FSA_OpenDir(fsaFd, path, &dirUH) >= 0) { + while (1) { + directoryEntry_s data; + int ret = IOSUHAX_FSA_ReadDir(fsaFd, dirUH, &data); + if (ret != 0) + break; + + sprintf(path, "/vol/storage_%s01/usr/save/00050000/%s/meta/meta.xml", (i == 0) ? "usb" : "mlc", data.name); + if (checkEntry(path) == 1) { + saves[pos].highID = 0x00050000; + saves[pos].lowID = strtoul(data.name, NULL, 16); + saves[pos].dev = i; + saves[pos].found = false; + pos++; + } + } + IOSUHAX_FSA_CloseDir(fsaFd, dirUH); + } + } + for (int i = 0; i < usable; i++) { + if (!savesl[i].found) { + saves[pos].highID = savesl[i].highID; + saves[pos].lowID = savesl[i].lowID; + saves[pos].dev = savesl[i].dev; + saves[pos].found = true; + pos++; + } + } + + Title* titles = malloc(foundCount*sizeof(Title)); if (!titles) { promptError("Out of memory."); return NULL; } - for (int i = 0; i < receivedCount; i++) { + for (int i = 0; i < foundCount; i++) { int srcFd = -1; - char* element = tList+(i*0x61); - u32 highID = *(u32*)(element), lowID = *(u32*)(element+4); - if (highID!=0x00050000) continue; - bool isTitleOnUSB = (memcmp(element+0x56,"usb",4)==0); + u32 highID = saves[i].highID, lowID = saves[i].lowID; + bool isTitleOnUSB = !saves[i].dev; + char path[255]; memset(path, 0, 255); - if (memcmp(element+0x56,"odd",4)==0) strcpy(path, "/vol/storage_odd_content/meta/meta.xml"); - else sprintf(path, "/vol/storage_%s01/usr/title/%08x/%08x/meta/meta.xml", element+0x56, highID, lowID); + if (saves[i].found) + sprintf(path, "/vol/storage_%s01/usr/title/%08x/%08x/meta/meta.xml", isTitleOnUSB ? "usb" : "mlc", highID, lowID); + else + sprintf(path, "/vol/storage_%s01/usr/save/%08x/%08x/meta/meta.xml", isTitleOnUSB ? "usb" : "mlc", highID, lowID); + titles[titleswiiu].saveInit = !saves[i].found; int ret = IOSUHAX_FSA_OpenFile(fsaFd, path, "rb", &srcFd); if (ret >= 0) { @@ -157,6 +247,8 @@ Title* loadWiiUTitles(int run, int fsaFd) { } + free(savesl); + free(saves); free(tList); return titles; @@ -166,14 +258,12 @@ Title* loadWiiTitles(int fsaFd) { int dirH; if (IOSUHAX_FSA_OpenDir(fsaFd, "/vol/storage_slccmpt01/title/00010000", &dirH) < 0) return -1; - while (1) { directoryEntry_s data; int ret = IOSUHAX_FSA_ReadDir(fsaFd, dirH, &data); if (ret != 0) break; - if (strcmp(data.name, "..") == 0 || strcmp(data.name, ".") == 0) continue; titlesvwii++; } IOSUHAX_FSA_RewindDir(fsaFd, dirH); @@ -190,8 +280,6 @@ Title* loadWiiTitles(int fsaFd) { if (ret != 0) break; - if (strcmp(data.name, "..") == 0 || strcmp(data.name, ".") == 0) continue; - int srcFd = -1; char path[256]; sprintf(path, "/vol/storage_slccmpt01/title/00010000/%s/data/banner.bin", data.name); @@ -288,6 +376,8 @@ int Menu_Main(void) { Title* wiititles = loadWiiTitles(fsaFd); int* versionList = (int*)malloc(0x100*sizeof(int)); + qsort(wiiutitles, titleswiiu, sizeof(Title), titleSort); + qsort(wiititles, titlesvwii, sizeof(Title), titleSort); while(1) { OSScreenClearBufferEx(0, 0); @@ -312,7 +402,7 @@ int Menu_Main(void) { entrycount = count; for (int i = 0; i < 14; i++) { if (i+scroll<0 || i+scroll>=count) break; - if (strlen(titles[i+scroll].shortName)) console_print_pos(0, i+2, " %s %s %s", titles[i+scroll].shortName, titles[i+scroll].isTitleOnUSB ? "(USB)" : ((mode == 0) ? "(NAND)" : ""), titles[i+scroll].isTitleDupe ? "[D]" : ""); + if (strlen(titles[i+scroll].shortName)) console_print_pos(0, i+2, " %s %s%s%s", titles[i+scroll].shortName, titles[i+scroll].isTitleOnUSB ? "(USB)" : ((mode == 0) ? "(NAND)" : ""), titles[i+scroll].isTitleDupe ? " [D]" : "", titles[i+scroll].saveInit ? "" : " [Not Init]"); else console_print_pos(0, i+2, " %08lx%08lx", titles[i+scroll].highID, titles[i+scroll].lowID); } console_print_pos(0, 2 + cursor, "->"); } break; @@ -330,8 +420,6 @@ int Menu_Main(void) { console_print_pos(0, 7+3, " Copy Savedata to Title in %s", titles[targ].isTitleOnUSB ? "NAND" : "USB"); } } - - console_print_pos(0, 2+3 + cursor, "->"); } break; case 3: { // Select Options @@ -403,12 +491,12 @@ int Menu_Main(void) { if (isPressed(VPAD_BUTTON_R) && (menu==1)) { tsort = (tsort + 1) % 4; - qsort(wiiutitles, titleswiiu, sizeof(Title), titleSort); + qsort(titles, count, sizeof(Title), titleSort); } if (isPressed(VPAD_BUTTON_L) && (menu==1) && (tsort > 0)) { sorta *= -1; - qsort(wiiutitles, titleswiiu, sizeof(Title), titleSort); + qsort(titles, count, sizeof(Title), titleSort); } if (isPressed(VPAD_BUTTON_X) && (menu == 1) && (mode == 0)) { @@ -441,12 +529,37 @@ int Menu_Main(void) { cursorb = cursor; scrollb = scroll; if (titles[targ].highID==0 || titles[targ].lowID==0) continue; + if ((mode == 0) && (strcmp(titles[targ].shortName, "DONT TOUCH ME") == 0)) { + if (!promptConfirm("Haxchi/CBHC save. Could be dangerous to modify. Continue?") || !promptConfirm("Are you REALLY sure?")) { + cursor = cursorb; + scroll = scrollb; + continue; + } + } + if ((mode == 0) && (!titles[targ].saveInit)) { + if (!promptConfirm("Recommended to run Game at least one time. Continue?") || !promptConfirm("Are you REALLY sure?")) { + cursor = cursorb; + scroll = scrollb; + continue; + } + } } if (menu == 2) { task = cursor; + if (task == 0) { + if (!titles[targ].saveInit) { + promptError("No save to Backup."); + continue; + } + } if (task == 2) { - allusers = promptConfirm("Delete save from all users?"); - wipeSavedata(&titles[targ], allusers, hasCommonSave(&titles[targ], false, false, 0, 0)); + allusers = promptConfirm("Delete save from all users? A-Yes B-No"); + if (hasCommonSave(&titles[targ], false, false, 0, 0)) { + if (!allusers) promptConfirm("Delete common save? A-Yes B-No"); + } else { + common = false; + } + wipeSavedata(&titles[targ], allusers, common); break; continue; } if (task > 2) { @@ -464,7 +577,12 @@ int Menu_Main(void) { case 1: restoreSavedata(&titles[targ], slot, allusers, common); break; case 2: allusers = promptConfirm("Delete save from all users? A-Yes B-No"); - wipeSavedata(&titles[targ], allusers, hasCommonSave(&titles[targ], false, false, 0, 0)); break; + if (hasCommonSave(&titles[targ], false, false, 0, 0)) { + if (!allusers) promptConfirm("Delete common save? A-Yes B-No"); + } else { + common = false; + } + wipeSavedata(&titles[targ], allusers, common); break; case 3: importFromLoadiine(&titles[targ], common, versionList ? versionList[slot] : 0); break; case 4: exportToLoadiine(&titles[targ], common, versionList ? versionList[slot] : 0); break; case 5: copySavedata(&titles[targ], &titles[titles[targ].dupeID], allusers, common); break; diff --git a/src/savemng.c b/src/savemng.c index bf03d6f..7603982 100644 --- a/src/savemng.c +++ b/src/savemng.c @@ -100,20 +100,14 @@ void console_print_pos(int x, int y, const char* format, ...) { // Source: ftpii } void console_print_pos_va(int x, int y, const char* format, va_list va) { // Source: ftpiiu - char* tmp = NULL; if ((vasprintf(&tmp, format, va) >= 0) && tmp) { - if (strlen(tmp) > 79) tmp[79] = 0; - OSScreenPutFontEx(0, x, y, tmp); OSScreenPutFontEx(1, x, y, tmp); - } - if (tmp) free(tmp); - } bool promptConfirm(const char* question) { @@ -526,6 +520,8 @@ void copySavedata(Title* title, Title* titleb, bool allusers, bool common) { const char* pathb = (isUSBb ? "/vol/storage_usb01/usr/save" : "/vol/storage_mlc01/usr/save"); sprintf(srcPath, "%s/%08x/%08x/%s", path, highID, lowID, "user"); sprintf(dstPath, "%s/%08x/%08x/%s", pathb, highIDb, lowIDb, "user"); + createFolder(dstPath); + if (!allusers) { char usrPath[16]; getUserID(usrPath); @@ -557,11 +553,9 @@ void backupSavedata(Title* title, u8 slot, bool allusers, bool common) { char dstPath[PATH_SIZE]; const char* path = (isWii ? "/vol/storage_slccmpt01/title" : (isUSB ? "/vol/storage_usb01/usr/save" : "/vol/storage_mlc01/usr/save")); sprintf(srcPath, "%s/%08x/%08x/%s", path, highID, lowID, isWii ? "data" : "user"); - IOSUHAX_FSA_MakeDir(fsaFd, "/vol/storage_sdcard/wiiu/backups", 0x666); - sprintf(dstPath, "/vol/storage_sdcard/wiiu/backups/%08x%08x", highID, lowID); - IOSUHAX_FSA_MakeDir(fsaFd, dstPath, 0x666); sprintf(dstPath, "/vol/storage_sdcard/wiiu/backups/%08x%08x/%u", highID, lowID, slot); - IOSUHAX_FSA_MakeDir(fsaFd, dstPath, 0x666); + createFolder(dstPath); + if (!allusers && !isWii) { char usrPath[16]; getUserID(usrPath); @@ -604,6 +598,8 @@ void restoreSavedata(Title* title, u8 slot, bool allusers, bool common) { const char* path = (isWii ? "/vol/storage_slccmpt01/title" : (isUSB ? "/vol/storage_usb01/usr/save" : "/vol/storage_mlc01/usr/save")); sprintf(srcPath, "/vol/storage_sdcard/wiiu/backups/%08x%08x/%u", highID, lowID, slot); sprintf(dstPath, "%s/%08x/%08x/%s", path, highID, lowID, isWii ? "data" : "user"); + createFolder(dstPath); + if (!allusers && !isWii) { char usrPath[16]; getUserID(usrPath); @@ -676,6 +672,7 @@ void importFromLoadiine(Title* title, bool common, int version) { u32 srcOffset = strlen(srcPath); getLoadiineUserDir(srcPath, srcPath, usrPath); sprintf(dstPath, "/vol/storage_%s01/usr/save/%08x/%08x/user", isUSB ? "usb" : "mlc", highID, lowID); + createFolder(dstPath); u32 dstOffset = strlen(dstPath); sprintf(dstPath + dstOffset, "/%s", usrPath); if (DumpDir(srcPath, dstPath) != 0) promptError("Failed to import savedata from loadiine."); diff --git a/src/savemng.h b/src/savemng.h index f0ed349..b1a357d 100644 --- a/src/savemng.h +++ b/src/savemng.h @@ -22,11 +22,19 @@ typedef struct { u16 listID; char shortName[256]; char productCode[32]; + bool saveInit; bool isTitleOnUSB; bool isTitleDupe; u16 dupeID; } Title; +typedef struct { + u32 highID; + u32 lowID; + u8 dev; + bool found; +} Saves; + void console_print_pos(int x, int y, const char* format, ...); bool promptConfirm(const char* question); void promptError(const char* message, ...);