/****************************************************************************
* Copyright (C) 2012 FIX94
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
****************************************************************************/
#include
#include "memory/mem2.hpp"
#include "nand_save.hpp"
#include "nand.hpp"
#include "gecko/gecko.hpp"
#include "loader/fs.h"
#include "loader/sys.h"
#include "banner/AnimatedBanner.h"
#include "unzip/U8Archive.h"
extern const u8 save_bin[];
extern const u32 save_bin_size;
NandSave InternalSave;
bool cur_load = false;
u8 cur_ios = 0;
#define BANNER_PATH "/title/00010000/57465346/data/banner.bin"
#define IOS_SAVE_PATH "/title/00010000/57465346/data/ios"
#define PORT_SAVE_PATH "/title/00010000/57465346/data/port"
#define SD_SAVE_PATH "/title/00010000/57465346/data/sdonly"
NandSave::NandSave()
{
ret = 0;
fd = 0;
memset(&ISFS_Path, 0, ISFS_MAXPATH);
loaded = false;
}
/* checks for wiiflow save WFSF by searching for the banner.bin. if found then wiiflow save found. */
/* if not found then we use save.bin to create banner.bin, tik.bin, and tmd.bin which are compressed into save.bin. */
/* the IOS and port settings are only created if they are changed in startup settings menu. */
/* also the ticket and its folder are deleted after the tmd is created. */
bool NandSave::CheckSave()
{
/* 10 million variables */
u32 u8_bin_size = 0;
u8 *u8_bin = NULL;
u32 certSize = 0;
signed_blob *certBuffer = NULL;
u32 tmd_bin_size = 0;
const signed_blob *tmd_bin = NULL;
u32 tik_bin_size = 0;
const signed_blob *tik_bin = NULL;
u32 banner_bin_size = 0;
const u8 *banner_bin = NULL;
u32 entries = 0;
/* Maybe our banner already exist */
memset(&ISFS_Path, 0, ISFS_MAXPATH);
strcpy(ISFS_Path, BANNER_PATH);
fd = ISFS_Open(ISFS_Path, ISFS_OPEN_READ);
if(fd >= 0)
{
ISFS_Close(fd);
gprintf("Found WiiFlow Save\n");
goto done;
}
// save_bin only contains the tik.bin, tmd.bin, and banner.bin
// tik.bin and tmd.bin are used to install "/title/00010000/57465346/data/banner.bin"
// "/title/00010000/57465346/data/ios and port" are not written until you change them in startup settings menu.
/* extract our archive */
u8_bin = DecompressCopy(save_bin, save_bin_size, &u8_bin_size);
if(u8_bin == NULL || u8_bin_size == 0)
goto error;
/* grab cert.sys */
memset(&ISFS_Path, 0, ISFS_MAXPATH);
strcpy(ISFS_Path, "/sys/cert.sys");
certBuffer = (signed_blob*)ISFS_GetFile(ISFS_Path, &certSize, -1);
if(certBuffer == NULL || certSize == 0)
goto error;
/* Install tik and tmd */
tik_bin = (const signed_blob*)u8_get_file(u8_bin, "tik.bin", &tik_bin_size);
if(tik_bin == NULL || tik_bin_size == 0)
goto error;
ret = ES_AddTicket(tik_bin, tik_bin_size, certBuffer, certSize, NULL, 0);
if(ret < 0)
goto error;
tmd_bin = (const signed_blob*)u8_get_file(u8_bin, "tmd.bin", &tmd_bin_size);
if(tmd_bin == NULL || tmd_bin_size == 0)
goto error;
ret = ES_AddTitleStart(tmd_bin, tmd_bin_size, certBuffer, certSize, NULL, 0);
if(ret < 0)
goto error;
ret = ES_AddTitleFinish();
if(ret < 0)
goto error;
/* WARNING dirty, delete tik again */
memset(&ISFS_Path, 0, ISFS_MAXPATH);
strcpy(ISFS_Path, "/ticket/00010000/57465346.tik");
ret = ISFS_Delete(ISFS_Path);
if(ret < 0)
goto error;
/* Delete the unused ticket folder */
memset(&ISFS_Path, 0, ISFS_MAXPATH);
strcpy(ISFS_Path, "/ticket/00010000");
ret = ISFS_ReadDir(ISFS_Path, NULL, &entries);
if(ret < 0)
goto error;
if(entries == 0)
{
ret = ISFS_Delete(ISFS_Path);
if(ret < 0)
goto error;
}
banner_bin = u8_get_file(u8_bin, "banner.bin", &banner_bin_size);
if(banner_bin == NULL || banner_bin_size == 0)
goto error;
memset(&ISFS_Path, 0, ISFS_MAXPATH);
strcpy(ISFS_Path, BANNER_PATH);
/* Write our banner */
ISFS_CreateFile(ISFS_Path, 0, 3, 3, 3);
fd = ISFS_Open(ISFS_Path, ISFS_OPEN_WRITE);
if(fd < 0)
goto error;
ret = ISFS_Write(fd, banner_bin, banner_bin_size);
ISFS_Close(fd);
if(ret < 0)
{
ISFS_Delete(ISFS_Path);
goto error;
}
MEM2_free(certBuffer);
if(u8_bin != save_bin)
free(u8_bin);
gprintf("Created WiiFlow Save\n");
done:
loaded = true;
return loaded;
error:
gprintf("Error while creating WiiFlow Save\n");
loaded = false;
ES_AddTitleCancel();
if(certBuffer != NULL)
MEM2_free(certBuffer);
certBuffer = NULL;
if(u8_bin != NULL)
free(u8_bin);
u8_bin = NULL;
tik_bin = NULL;
tmd_bin = NULL;
banner_bin = NULL;
return loaded;
}
void NandSave::LoadSettings()
{
if(loaded == false)
return;
u32 size = 0;
memset(&ISFS_Path, 0, ISFS_MAXPATH);
// on very first boot (no save file exist yet)
// "/title/00010000/57465346/data/ios"
// "/title/00010000/57465346/data/port"
// will not exist. wiiflow will simply use useMainIOS and mainIOS defined in main.cpp
// they are only created when you change settings in the startup settings menu.
strcpy(ISFS_Path, IOS_SAVE_PATH);
ios_settings_t *file = (ios_settings_t*)ISFS_GetFile(ISFS_Path, &size, -1);
if(file != NULL && size == sizeof(ios_settings_t))
{
gprintf("Loading IOS Settings from wiiflow save\n");
cur_ios = file->cios;
if(cur_ios > 0)
mainIOS = cur_ios;
cur_load = file->use_cios;
useMainIOS = cur_load;
}
if(file != NULL)
MEM2_free(file);
strcpy(ISFS_Path, PORT_SAVE_PATH);
u8 *port = ISFS_GetFile(ISFS_Path, &size, -1);
if(port != NULL && size == sizeof(u8))
{
gprintf("Using Port Settings from wiiflow save\n");
currentPort = port[0] & 1;
}
if(port != NULL)
MEM2_free(port);
strcpy(ISFS_Path, SD_SAVE_PATH);
u8 *sdonly = ISFS_GetFile(ISFS_Path, &size, -1);
if(sdonly != NULL && size == sizeof(u8))
{
gprintf("Using SD Only Settings from wiiflow save\n");
sdOnly = ((sdonly[0] & 1) == 1);
}
if(sdonly != NULL)
MEM2_free(sdonly);
}
void NandSave::SaveIOS()
{
if(loaded == false)
return;
memset(&ios_settings, 0, sizeof(ios_settings_t));
ios_settings.cios = cur_ios;
ios_settings.use_cios = cur_load;
gprintf("Saving IOS Settings to wiiflow save\n");
WriteFile(IOS_SAVE_PATH, (u8*)&ios_settings, sizeof(ios_settings_t));
}
void NandSave::SavePort(u8 port)
{
if(loaded == false)
return;
gprintf("Saving Port Setting to wiiflow save\n");
WriteFile(PORT_SAVE_PATH, &port, sizeof(port));
}
void NandSave::SaveSDOnly(bool sd_only)
{
if(loaded == false)
return;
gprintf("Saving SD Only Setting to wiiflow save\n");
u8 sdonly = sd_only ? 1 : 0;
WriteFile(SD_SAVE_PATH, &sdonly, sizeof(sdonly));
}
void NandSave::WriteFile(const char *file_name, u8 *content, u32 size)
{
memset(&ISFS_Path, 0, ISFS_MAXPATH);
if(file_name == NULL || content == NULL || size == 0)
return;
strcpy(ISFS_Path, file_name);
ISFS_CreateFile(ISFS_Path, 0, 3, 3, 3);
fd = ISFS_Open(ISFS_Path, ISFS_OPEN_WRITE);
if(fd < 0)
return;
ret = ISFS_Write(fd, content, size);
ISFS_Close(fd);
if(ret < 0)
ISFS_Delete(ISFS_Path);
}