ctr_Repair/trunk/ConsoleDataMigration/sources/ConsoleRestore/Importer.cpp
N2614 04a8694cf1 r373を巻き戻し。FATレベルではなくIS-FSレベルでのReadテストが必要。
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@375 385bec56-5757-e545-9c3a-d8741f4650f1
2011-07-08 09:06:44 +00:00

1892 lines
62 KiB
C++

/*---------------------------------------------------------------------------*
Project: Horizon
File: Importer.cpp
Copyright 2009 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Rev$
*---------------------------------------------------------------------------*/
#include <nn.h>
#include <nn/fs/CTR/fs_ArchiveTypesForSystem.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include <nn/cfg/CTR/cfg_ApiInit.h>
#include <nn/cfg/CTR/cfg_ApiNor.h> // cfg:norの初期化に必要
#include <nn/cfg/CTR/cfg_Api.h>
#include <nn/am/am_ApiSystemMenu.h>
#include <nn/cfg/CTR/cfg_NtrSettings.h>
#include <nn/cfg/CTR/cfg_ApiSys.h>
#include <nn/cfg/CTR/detail/cfg_DataStructures.h>
#include <nn/cfg/CTR/detail/cfg_Keys.h>
#include <nn/cfg/CTR/detail/cfg_Default.h>
#include <nn/drivers/aes/CTR/ARM946ES/driverAes_Types.h>
#include <nn/crypto/crypto_SwAesCtrContext.h>
#include <nn/ac/CTR/private/ac_NetworkSetting.h>
#include <nn/ac/CTR/private/ac_InternalApi.h>
#include <nn/socket.h>
#include <nn/nwm/CTR/nwm_InfraAPI.h>
#include <nn/mcu.h>
#include <nn/drivers/mcu/CTR/driverMcuRegisterMap.h>
#include <nn/ndm.h>
#include "FileName.h"
#include "Importer.h"
#include "SdMountManager.h"
#include "HeapManager.h"
#include "SdReaderWriter.h"
#include "CommonLogger.h"
#include "FileTransfer.h"
#include "common_Types.h"
#include "Aes_define.h"
#include "configLoader.h"
#include "FileChecker.h"
#include "VersionDetect.h"
#include <string>
#include <cstring>
namespace ConsoleRestore
{
namespace
{
const size_t IMPORT_THREAD_STACK_SIZE = 0x4000;
nn::os::Thread s_ImportThread;
nn::os::StackBuffer<IMPORT_THREAD_STACK_SIZE> s_ImportThreadStack;
bool s_IsImportSucceeded;
const size_t TIME_ZONE_LENGTH = 9; // "+23:45"
char s_TimeZoneStr[TIME_ZONE_LENGTH];
TimeZone s_TimeZone;
const size_t NTP_SERVER_NAME_LENGTH = 256;
char s_NtpServerName[NTP_SERVER_NAME_LENGTH];
bool s_CheckedEqualsDeviceIdFileandDeviceId = false;
bool s_CheckedEqualsRegionDataandRegion = false;
bool s_ReadSerialNumber = false;
struct SdFileSize
{
s64 totalFileSize;
s64 twlFileSize;
s64 twlSoundFileSize;
s64 twlPhotoFileSize;
s64 ctrFileSize;
};
SdFileSize s_SdFileSize;
// シリアルナンバー
u8 s_SerialNo[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN];
// 空のファイルを作成する
bool CreateEmptyFile(const wchar_t* path);
// SDからNANDにセーブデータをコピーする
void ImportSaveData();
// SDからNORにNORデータをコピーする
nn::Result ImportNorData();
// SDカードに保存してあるバージョン情報
common::VerDef s_SDVersionData;
// SDカードから読み込んだファイル一覧
common::ImportDataList s_FileLists;
}
// SDからファイル一覧を読み込む
nn::Result ReadFileList(SdFileSize* sdFileSize, common::ImportDataList* fileList);
CheckedNetworkSetting s_CurrentNetowrkSetting1;
void ConvertTimeZoneString(const char* str)
{
s_TimeZone.hour = 0;
s_TimeZone.minutes = 0;
s_TimeZone.isMinus = false;
bool hour = true;
bool ten = true;
u32 count = 0;
for(u32 i = 0; i < TIME_ZONE_LENGTH && count < 2; i++)
{
switch (str[i])
{
case ':':
{
hour = false;
}
break;
case '"':
{
// 2回読んだら終了
count++;
}
break;
case '+':
{
s_TimeZone.isMinus = false;
}
break;
case '-':
{
s_TimeZone.isMinus = true;
}
break;
default:
{
if(hour)
{
if(ten)
{
s_TimeZone.hour += (str[i] - '0') * 10;
ten = false;
}
else
{
s_TimeZone.hour += str[i] - '0';
ten = true;
}
}
else
{
if(ten)
{
s_TimeZone.minutes += (str[i] - '0') * 10;
ten = false;
}
else
{
s_TimeZone.minutes += str[i] - '0';
ten = true;
}
}
}
break;
}
}
NN_LOG("Converted TimeZone = ");
if(s_TimeZone.isMinus)
{
NN_LOG("-");
}
NN_LOG("%02d:%02d\n", s_TimeZone.hour, s_TimeZone.minutes);
}
namespace
{
bool CreateEmptyFile(const wchar_t* path)
{
nn::Result result;
bool create = false;
result = common::SdMountManager::Mount();
if (result.IsSuccess())
{
nn::fs::FileOutputStream fos;
result = fos.TryInitialize(path, true);
if(result.IsSuccess())
{
fos.TryFlush();
create = true;
}
fos.Finalize();
}
common::SdMountManager::Unmount();
return create;
}
}
nn::Result ReadSerialNumber(u8* serial)
{
static nn::Result result = nn::ResultSuccess();
if(s_ReadSerialNumber)
{
std::memcpy(serial, s_SerialNo, sizeof(s_SerialNo));
return result;
}
COMMON_LOGGER("Read Serial Number in SD.\n");
size_t readSize;
common::SdReaderWriter sdReader;
size_t bufSize = 1024;
common::HeapManager readHeap(bufSize);
void* buf = readHeap.GetAddr();
if(buf != NULL)
{
result = sdReader.ReadBufWithCmac(common::SERIAL_PATHNAME, buf, bufSize, &readSize);
if(result.IsSuccess())
{
std::memcpy(s_SerialNo, buf, sizeof(s_SerialNo));
std::memcpy(serial, s_SerialNo, sizeof(s_SerialNo));
s_ReadSerialNumber = true;
}
}
else
{
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
nn::Result EqualsDeviceIdFileandDeviceId(common::HardwareStateManager& manager)
{
static nn::Result result = nn::ResultSuccess();
if(s_CheckedEqualsDeviceIdFileandDeviceId)
{
return result;
}
COMMON_LOGGER("Check Device Id\n");
bit32 sdDeviceId;
common::SdReaderWriter sdReader;
size_t totalSize;
size_t bufSize = 1024;
common::HeapManager heap(bufSize);
void* buf = heap.GetAddr();
if (buf != NULL)
{
result = sdReader.ReadBufWithCmac(common::DEVICE_ID_PATHNAME, buf, bufSize, &totalSize);
if (result.IsSuccess())
{
s_CheckedEqualsDeviceIdFileandDeviceId = true;
std::memcpy(&sdDeviceId, buf, sizeof(sdDeviceId));
if (manager.GetDeviceId() == sdDeviceId)
{
result = nn::ResultSuccess();
}
else
{
result = nn::Result(nn::Result::LEVEL_STATUS, nn::Result::SUMMARY_INVALID_RESULT_VALUE,
nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_INVALID_RESULT_VALUE);
}
}
}
else
{
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
nn::Result EqualsRegionDataandRegion()
{
static nn::Result result = nn::ResultSuccess();
if(s_CheckedEqualsRegionDataandRegion)
{
return result;
}
COMMON_LOGGER("Check Region\n");
nn::cfg::CTR::CfgRegionCode region;
region = nn::cfg::CTR::GetRegion();
nn::cfg::CTR::CfgRegionCode sdRegion;
common::SdReaderWriter sdReader;
size_t readSize;
size_t bufSize = 1024;
common::HeapManager heap(bufSize);
void* buf = heap.GetAddr();
if (buf != NULL)
{
result = sdReader.ReadBufWithCmac(common::REGION_DATA_PATHNAME, buf, bufSize, &readSize);
if (result.IsSuccess())
{
std::memcpy(&sdRegion, buf, sizeof(sdRegion));
s_CheckedEqualsRegionDataandRegion = true;
if(region == sdRegion)
{
result = nn::ResultSuccess();
}
else
{
result = nn::Result(nn::Result::LEVEL_STATUS, nn::Result::SUMMARY_INVALID_RESULT_VALUE,
nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_INVALID_RESULT_VALUE);
}
}
}
else
{
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
void SetCountry(nn::cfg::CTR::CfgCountryCode countryCode)
{
using namespace nn::cfg::CTR;
using namespace nn::cfg::CTR::detail;
SimpleAddressIdCfgData simpleAddressId;
TwlCountryCodeCfgData countryData;
nn::cfg::CTR::system::Initialize();
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::GetConfig(&simpleAddressId, sizeof(SimpleAddressIdCfgData), GET_CFG_KEY(NN_CFG_SIMPLE_ADDRESS, NN_CFG_SIMPLE_ADDRESS_ID)));
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::GetConfig(&countryData, sizeof(TwlCountryCodeCfgData), GET_CFG_KEY(NN_CFG_TWL, NN_CFG_TWL_COUNTRY_CODE)));
nn::cfg::CTR::system::Finalize();
simpleAddressId.id = (countryCode << CFG_SIMPLE_ADDRESS_ID_COUNTRY_SHIFT) | (1
<< CFG_SIMPLE_ADDRESS_ID_REGION_SHIFT);
countryData.country = countryCode;
nn::cfg::CTR::system::Initialize();
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::SetConfig(GET_CFG_KEY(NN_CFG_SIMPLE_ADDRESS, NN_CFG_SIMPLE_ADDRESS_ID), &simpleAddressId, sizeof(SimpleAddressIdCfgData)));
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::SetConfig(GET_CFG_KEY(NN_CFG_TWL, NN_CFG_TWL_COUNTRY_CODE), &countryData, sizeof(TwlCountryCodeCfgData)));
nn::cfg::CTR::system::FlushConfig();
nn::cfg::CTR::system::Finalize();
}
void SetLanguage(nn::cfg::CTR::CfgLanguageCode languageCode)
{
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::init::SetConfig(
GET_CFG_KEY(nn::cfg::CTR::detail::NN_CFG_USER_INFO,
nn::cfg::CTR::detail::NN_CFG_USER_INFO_LANGUAGE),
&languageCode,
sizeof(nn::cfg::CTR::detail::LanguageCfgData)));
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::init::FlushConfig());
nn::cfg::nor::CTR::Initialize();
NN_UTIL_PANIC_IF_FAILED(nn::cfg::nor::CTR::SetLanguage(static_cast<nn::cfg::CTR::CfgLanguageCode>(languageCode)));
nn::cfg::nor::CTR::Finalize();
}
nn::Result ImportCountryLanguageData()
{
nn::Result result = nn::ResultSuccess();
if (common::ExistsCountryLanguageFile())
{
size_t bufSize = 1024;
common::HeapManager heap(bufSize);
void* buf = heap.GetAddr();
if (buf != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::COUNTRY_SETTING_PATHNAME, buf, bufSize, &readSize);
if (result.IsSuccess())
{
// SDから読み出し成功
SetCountry(reinterpret_cast<common::CfgCountryLanguage*> (buf)->country);
SetLanguage(reinterpret_cast<common::CfgCountryLanguage*> (buf)->language);
}
NN_UTIL_RETURN_IF_FAILED(result);
}
}
else
{
// リージョンから適当な国を指定する
nn::cfg::CTR::CfgRegionCode region;
region = nn::cfg::CTR::GetRegion();
NN_LOG("Country Setting does not exist. Use Default Setting\n");
switch(region)
{
case nn::cfg::CTR::CFG_REGION_JAPAN:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_JAPAN);
}
break;
case nn::cfg::CTR::CFG_REGION_AMERICA:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_UNITED_STATES);
}
break;
case nn::cfg::CTR::CFG_REGION_EUROPE:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_FRANCE);
}
break;
case nn::cfg::CTR::CFG_REGION_AUSTRALIA:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_AUSTRALIA);
}
break;
case nn::cfg::CTR::CFG_REGION_CHINA:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_CHINA);
}
break;
case nn::cfg::CTR::CFG_REGION_KOREA:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_SOUTH_KOREA);
}
break;
case nn::cfg::CTR::CFG_REGION_TAIWAN:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_TAIWAN);
}
break;
}
}
return result;
}
inline u8 DecimalToBcd(u8 param)
{
u8 theTen, theOne;
theTen = param / 10;
theOne = param - theTen * 10;
return (theTen << 4 | theOne);
}
nn::Result ImportMcuRtc(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Import RTC Data.\n");
nn::Result result = nn::ResultSuccess();
nn::Handle handle = manager.GetMcuHandle();
if(handle.IsValid())
{
if (common::CheckFileExists(common::MCU_RTC_PATHNAME))
{
size_t bufSize = 1024;
NN_LOG("AllocatableSize = %d\n", bufSize);
common::HeapManager heap(bufSize);
void* buf = heap.GetAddr();
if (buf != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::MCU_RTC_PATHNAME, buf, bufSize, &readSize);
if (result.IsSuccess())
{
// mcuを使ってセットする
nn::mcu::CTR::HwCheck mcu(handle);
nn::mcu::CTR::RtcData* rtc = reinterpret_cast<nn::mcu::CTR::RtcData*> (buf);
NN_LOG("RTC = 20%02d/%02d/%02d %02d:%02d:%02d\n", rtc->m_Year, rtc->m_Month, rtc->m_Day, rtc->m_Hour, rtc->m_Minute, rtc->m_Second);
// BCD変換が必要
size_t RTC_PARAM_SIZE = sizeof(nn::mcu::CTR::RtcData);
u8 bcd[RTC_PARAM_SIZE];
for (int i = 0; i < RTC_PARAM_SIZE; i++)
{
bcd[i] = DecimalToBcd(reinterpret_cast<u8*> (rtc)[i]);
}
const u8 RETRY = 10;
for (u8 i = 0; i < RETRY; i++)
{
result = mcu.WriteBySend(nn::drivers::mcu::CTR::MCU_RTC_SEC_ADDR, bcd, RTC_PARAM_SIZE);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if(result.IsSuccess())
{
break;
}
nn::os::Thread::Sleep(
nn::fnd::TimeSpan::FromMilliSeconds(
nn::os::Tick::GetSystemCurrent().ToTimeSpan().GetMilliSeconds() % 100));
}
}
NN_UTIL_RETURN_IF_FAILED(result);
}
else
{
COMMON_LOGGER("Failed Allocate Heap!!\n");
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
}
}
else
{
result = nn::Result(nn::Result::LEVEL_PERMANENT, nn::Result::SUMMARY_INVALID_STATE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_INVALID_HANDLE);
}
return result;
}
bool InitializeFileSystem()
{
nn::Result result;
for (u32 i = 0; i < common::TWL_PATHNAME_MAX; i++)
{
result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[i], common::TWL_FS_ARCHIVE_KIND[i]);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
nn::fs::Directory dir;
std::vector<nn::fs::DirectoryEntry> entryList; //カレントディレクトリのエントリ一覧を格納
std::vector<nn::fs::DirectoryEntry>::iterator entryIndex;
std::wstring currentDirectory = common::NAND_TWL_ROOT_PATHNAME_WITH_SLASH_TABLE[i];
result = dir.TryInitialize(currentDirectory.c_str());
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (numEntry == 0)
{
// ルートディレクトリを閉じる
dir.Finalize();
// ルートディレクトリの子を開く
for (entryIndex = entryList.begin(); entryIndex != entryList.end(); entryIndex++)
{
// ディレクトリなら削除する
if (entryIndex->attributes.isDirectory)
{
NN_LOG("Try Delete %ls%ls/\n", currentDirectory.c_str(), entryIndex->entryName);
result = nn::fs::TryDeleteDirectoryRecursively(
(currentDirectory + ::std::wstring(entryIndex->entryName)).c_str());
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
// ファイルなら削除する
else
{
NN_LOG("Try Delete %ls%ls\n", currentDirectory.c_str(), entryIndex->entryName);
result = nn::fs::TryDeleteFile(
(currentDirectory + ::std::wstring(entryIndex->entryName)).c_str());
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
}
// 削除完了
break;
}
else
{
// vectorに保存する
entryList.push_back(entry);
if (entry.attributes.isDirectory)
{
NN_LOG("%ls%ls/\n", currentDirectory.c_str(), entry.entryName);
}
else
{
NN_LOG("%ls%ls\n", currentDirectory.c_str(), entry.entryName);
}
}
}
result = nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[i]);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
result = nn::am::DeleteAllTwlUserPrograms();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
nn::fs::InitializeCtrFileSystem();
return true;
}
nn::Result ImportIvs()
{
nn::Result result = nn::ResultSuccess();
nn::fs::FileOutputStream fos;
size_t bufSize = 1024;
common::HeapManager encHeap(bufSize);
void* enc = encHeap.GetAddr();
if (enc != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::IVS_PATHNAME, enc, bufSize, &readSize);
if(result.IsSuccess())
{
// SDから読み出し成功
result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND);
if (result.IsSuccess())
{
common::HeapManager decHeap(bufSize);
void *dec = decHeap.GetAddr();
if (dec != NULL)
{
// AES復号化する
nn::crypto::Initialize();
nn::crypto::SwAesCtrContext swAesCtrContest;
swAesCtrContest.Initialize(common::iv, common::key, sizeof(common::key));
swAesCtrContest.Decrypt(dec, enc, readSize);
// IVS書き込み
result = fos.TryInitialize(common::IVS_NAND_PATHNAME, true);
if (result.IsSuccess())
{
if (result.IsSuccess())
{
s32 writeSize;
result = fos.TryWrite(&writeSize, dec, readSize, true);
if (result.IsSuccess())
{
COMMON_LOGGER("Import SDCI.\n");
}
}
}
}
else
{
COMMON_LOGGER("Failed Allocate Heap!!\n");
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
}
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
}
NN_UTIL_RETURN_IF_FAILED(result);
}
else
{
COMMON_LOGGER("Failed Allocate Heap!!\n");
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
bool ImportIvsData()
{
return ImportIvs().IsSuccess();
}
void ImportThreadFunc()
{
nn::Result result;
s_IsImportSucceeded = true;
result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2);
NN_LOG("AllocatableSize = %d\n", bufSize);
common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2);
void* buf = heap.GetAddr();
if (buf != NULL)
{
if(!common::CopyDirectory(
&s_FileLists,
(::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(),
common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH,
buf, bufSize, false, NULL, NULL))
{
s_IsImportSucceeded = false;
return;
}
}
common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
NN_LOG("Import Thread Finalize\n");
}
namespace
{
void ImportSaveData()
{
// SDカードからNANDに読み込み
nn::Result result;
// ファイルサイズ設定
common::InitializeTransferProgress(s_SdFileSize.ctrFileSize);
// SDカードにあるセーブデータディレクトリ以下のデータをNANDにコピー
COMMON_LOGGER("Import NAND Data Start...\n");
s_ImportThread.Start(ImportThreadFunc, s_ImportThreadStack);
}
nn::Result ImportNorData()
{
COMMON_LOGGER("Import NOR Data.\n");
nn::Result result = nn::ResultSuccess();
nn::cfg::nor::CTR::Initialize();
size_t bufSize = common::GetAllocatableSize() / 2;
NN_LOG("AllocatableSize = %d\n", bufSize);
common::HeapManager heap(bufSize);
void* buf = heap.GetAddr();
if (buf != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::NOR_PATHNAME, buf, bufSize, &readSize);
if(result.IsSuccess())
{
// cfgを使ってセットする
result = nn::cfg::nor::CTR::SetNtrSetting(&reinterpret_cast<common::NtrNorData*>(buf)->ntrConfig.ncd,
&reinterpret_cast<common::NtrNorData*>(buf)->ntrConfig.ncd_ex);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// WiFiコネクションIDが仮の値であればWiFi設定は移行しない
// TWL修理に準拠している
u64 attestedUserId1 = 0;
u64 attestedUserId2 = 0;
const u32 WIFI_CONNECTION_USERID_OFFSET1 = 0xf0;
const u32 WIFI_CONNECTION_USERID_OFFSET2 = 0x1f0;
const u32 USERID_SIZE = 6;
const bit64 USERID_MASK = 0x7FFFFFFFFFF; // 43bit
void* NtrWifiSettingAddr = &reinterpret_cast<common::NtrNorData*>(buf)->NtrWiFiSetting;
std::memcpy(&attestedUserId1,
&reinterpret_cast<u8*>(NtrWifiSettingAddr)[WIFI_CONNECTION_USERID_OFFSET1],
USERID_SIZE);
attestedUserId1 &= USERID_MASK;
std::memcpy(&attestedUserId2,
&reinterpret_cast<u8*>(NtrWifiSettingAddr)[WIFI_CONNECTION_USERID_OFFSET2],
USERID_SIZE);
attestedUserId2 &= USERID_MASK;
if (attestedUserId1 == attestedUserId2 && attestedUserId1 != 0)
{
// TWL WiFi設定
result = nn::cfg::nor::CTR::WriteTwlWifiSetting(0,
reinterpret_cast<common::NtrNorData*> (buf)->TwlWiFiSetting, common::TWL_WIFI_SETTING_SIZE);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// NTR WiFi設定
result = nn::cfg::nor::CTR::WriteNtrWifiSetting(0,
reinterpret_cast<common::NtrNorData*> (buf)->NtrWiFiSetting, common::NTR_WIFI_SETTING_SIZE);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
else
{
// クリアしておく
result = nn::cfg::nor::CTR::ClearTwlWifiSetting();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::cfg::nor::CTR::ClearNtrWifiSetting();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
else
{
COMMON_LOGGER("Failed Allocate Heap!!\n");
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
}
nn::Result ReadVersionData()
{
nn::Result result = nn::ResultSuccess();
std::memset(&s_SDVersionData, 0, sizeof(common::VerDef));
size_t bufSize = common::GetAllocatableSize() / 2;
NN_LOG("AllocatableSize = %d\n", bufSize);
common::HeapManager heap(bufSize);
void* buf = heap.GetAddr();
if (buf != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::VERSION_DATA_PATHNAME, buf, bufSize, &readSize);
if(result.IsSuccess())
{
// バージョン情報を保持する
std::memcpy(&s_SDVersionData, buf, readSize);
NN_LOG("SD Version = %02d.%02d.%02d-%02d\n", s_SDVersionData.cup.majorVersion,
s_SDVersionData.cup.minorVersion,
s_SDVersionData.cup.microVersion,
s_SDVersionData.nup.majorVersion);
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
else
{
COMMON_LOGGER("Failed Allocate Heap!!\n");
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
bool ExistsIvsDirectory(std::string& ivsRoot)
{
nn::Result result;
nn::fs::Directory dir;
common::SdMountManager::Mount();
result = dir.TryInitialize(common::SD_NINTENDO_3DS_ROOT_PATH);
if(result.IsFailure())
{
NN_DBG_PRINT_RESULT(result);
common::SdMountManager::Unmount();
return false;
}
wchar_t ivs[34];
std::mbstowcs(ivs, ivsRoot.c_str(), ivsRoot.size() + 1);
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
if (result.IsFailure())
{
dir.Finalize();
common::SdMountManager::Unmount();
return false;
}
if (numEntry == 0)
{
dir.Finalize();
common::SdMountManager::Unmount();
return false;
}
else
{
// 比較する
if (entry.attributes.isDirectory)
{
NN_LOG("%ls\n", entry.entryName);
if(std::wcscmp(ivs, entry.entryName) == 0)
{
common::SdMountManager::Unmount();
return true;
}
}
}
}
}
nn::Result Cleanup()
{
nn::Result result;
bool execCleanup;
result = nn::am::NeedsCleanup(&execCleanup, nn::fs::MEDIA_TYPE_NAND);
if(result.IsSuccess())
{
if(execCleanup)
{
COMMON_LOGGER("Cleanup NAND\n");
return nn::am::DoCleanup(nn::fs::MEDIA_TYPE_NAND);
}
}
return result;
}
void DeleteAllCheckFiles()
{
nn::Result result;
common::SdMountManager::Mount();
for(u32 i = 0; i < sizeof(CHECK_FILENAME_TABLE) / sizeof(CHECK_FILENAME_TABLE[0]); i++)
{
if(common::CheckFileExists(CHECK_FILENAME_TABLE[i]))
{
result = nn::fs::TryDeleteFile(CHECK_FILENAME_TABLE[i]);
COMMON_LOGGER_RESULT_IF_FAILED(result);
}
}
common::SdMountManager::Unmount();
}
void FinalizeImportThread()
{
s_ImportThread.Join();
s_ImportThread.Finalize();
}
bool IsImportThreadFinished()
{
return s_ImportThread.IsValid() && !s_ImportThread.IsAlive();
}
void CreateWriteFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_WRITE_FINISHED]);
common::ClearFileCheck(common::EXISTS_WRITE_FINISHED);
}
void CreateConsoleInitializedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_CONSOLE_INTIALIZED]);
common::ClearFileCheck(common::EXISTS_CONSOLE_INTIALIZED);
}
void CreateUpdateFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_UPDATE_FINISHED]);
common::ClearFileCheck(common::EXISTS_UPDATE_FINISHED);
}
void CreateRtcSyncFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_RTC_SYNC_FINISHED]);
common::ClearFileCheck(common::EXISTS_RTC_SYNC_FINISHED);
}
void CreateDownloadIvsFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_DOWNLOAD_IVS]);
common::ClearFileCheck(common::EXISTS_DOWNLOAD_IVS);
}
void CreateDeleteAccountFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_DELETE_ACCOUNT]);
common::ClearFileCheck(common::EXISTS_DELETE_ACCOUNT);
}
void CreateTransferAccountFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_TRANSFER_ACCOUNT]);
common::ClearFileCheck(common::EXISTS_TRANSFER_ACCOUNT);
}
u32 GetImportProgress()
{
return common::GetProgress();
}
bool UpdateNetworkSetting(nn::ac::NetworkSetting& networkSetting)
{
nn::Result result;
bool retval = true;
result = nn::ac::InitializeInternal();
if(result.IsFailure())
{
retval = false;
COMMON_LOGGER("Error: nn::ac::InitializeInternal() failed\n");
}
else
{
//特に入力させる必要のない自動で設定する項目
networkSetting.wireless.enable = true;
networkSetting.wireless.multiSsid.enable = false;
networkSetting.ip.enableDHCP = true;
networkSetting.scanlessConnect.hasConnected = false;
networkSetting.proxy.enable = false;
networkSetting.other.enableUPnP = false;
// 現在のインターネット設定1を一時的に保持
result = nn::ac::LoadNetworkSetting(0, s_CurrentNetowrkSetting1.setting);
if(result.IsSuccess())
{
s_CurrentNetowrkSetting1.isValid = true;
}
else
{
s_CurrentNetowrkSetting1.isValid = false;
}
result = nn::ac::UpdateNetworkSetting( 0, networkSetting );
if(!result.IsSuccess())
{
retval = false;
COMMON_LOGGER("Error: SetNetworkSetting (Update Error)\n");
}
else
{
result = nn::ac::FinalizeInternal();
if (!result.IsSuccess())
{
retval = false;
COMMON_LOGGER("Error: SetNetworkSetting (Finalize Error)\n");
}
}
}
return retval;
}
bool ReadSetting(bool* nupOnly, bool* getIvs, bool* checkSd, bool* skipNup)
{
nn::Result result;
bool retval = true;
common::ConfigFileLoader configfileLoader;
common::SdMountManager::Mount();
size_t size = 10240;
common::HeapManager heap(size);
void* heapAddr = heap.GetAddr();
if(heapAddr != NULL)
{
result = configfileLoader.Initialize(common::AP_SETTING_PATHNAME, heapAddr, size);
if (result.IsSuccess())
{
nn::ac::NetworkSetting networkSetting;
{
const char* ssid = configfileLoader.ReadAsChar(L"SSID"); // SSID
if(ssid == NULL)
{
COMMON_LOGGER("SSID: is missing\n");
retval = false;
}
else
{
std::strncpy(reinterpret_cast<char*> (networkSetting.wireless.essidSecurity.ssid), ssid, 32);
networkSetting.wireless.essidSecurity.ssidLength = std::strlen(ssid) % 33;
COMMON_LOGGER("SSID = %s\n", networkSetting.wireless.essidSecurity.ssid);
}
}
{
const char* mode = configfileLoader.ReadAsChar(L"MODE"); // MODE
if(mode == NULL)
{
COMMON_LOGGER("MODE: is missing\n");
retval = false;
}
else
{
if (std::strcmp(mode, "OPEN") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::OPEN;
}
else if (std::strcmp(mode, "WEP40") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_40BIT;
}
else if (std::strcmp(mode, "WEP104") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_104BIT;
}
else if (std::strcmp(mode, "WEP128") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_128BIT;
}
else if (std::strcmp(mode, "WPA-TKIP") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA_TKIP;
}
else if (std::strcmp(mode, "WPA2-TKIP") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA2_TKIP;
}
else if (std::strcmp(mode, "WPA-AES") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA_AES;
}
else if (std::strcmp(mode, "WPA2-AES") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA2_AES;
}
else
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::OPEN;
}
switch (networkSetting.wireless.essidSecurity.securityMode)
{
case nn::ac::OPEN:
{
COMMON_LOGGER("MODE = OPEN\n");
}
break;
case nn::ac::WEP_40BIT:
{
COMMON_LOGGER("MODE = WEP_40BIT\n");
}
break;
case nn::ac::WEP_104BIT:
{
COMMON_LOGGER("MODE = WEP_104BIT\n");
}
break;
case nn::ac::WEP_128BIT:
{
COMMON_LOGGER("MODE = WEP_128BIT\n");
}
break;
case nn::ac::WPA_TKIP:
{
COMMON_LOGGER("MODE = WPA_TKIP\n");
}
break;
case nn::ac::WPA2_TKIP:
{
COMMON_LOGGER("MODE = WPA2_TKIP\n");
}
break;
case nn::ac::WPA_AES:
{
COMMON_LOGGER("MODE = WPA_AES\n");
}
break;
case nn::ac::WPA2_AES:
{
COMMON_LOGGER("MODE = WPA2_AES\n");
}
break;
}
}
}
{
const char* pass = configfileLoader.ReadAsChar(L"PASS"); // PASS
if(pass == NULL)
{
COMMON_LOGGER("PASS: is missing\n");
retval = false;
}
else
{
switch (networkSetting.wireless.essidSecurity.securityMode)
{
case nn::ac::WEP_40BIT:
case nn::ac::WEP_104BIT:
case nn::ac::WEP_128BIT:
{
std::strncpy(reinterpret_cast<char *> (networkSetting.wireless.essidSecurity.passphrase),
pass, 64);
std::memcpy(networkSetting.wireless.essidSecurity.key,
networkSetting.wireless.essidSecurity.passphrase, 64);
}
break;
case nn::ac::WPA_TKIP:
case nn::ac::WPA2_TKIP:
case nn::ac::WPA_AES:
case nn::ac::WPA2_AES:
{
std::strncpy(reinterpret_cast<char *> (networkSetting.wireless.essidSecurity.passphrase),
pass, 64);
size_t phrase_size = std::strlen(
reinterpret_cast<char *> (networkSetting.wireless.essidSecurity.passphrase));
nn::nwm::Ssid ssid(reinterpret_cast<char *> (networkSetting.wireless.essidSecurity.ssid));
nn::nwm::ConvertPasswordToPsk(
reinterpret_cast<char *> (networkSetting.wireless.essidSecurity.passphrase),
phrase_size, ssid, networkSetting.wireless.essidSecurity.key);
}
break;
case nn::ac::OPEN:
default:
{
//do nothing
}
break;
}
}
}
{
s32 dnsAuto; // DNS_AUTO
if(configfileLoader.ReadAsChar(L"DNS_AUTO") == NULL)
{
COMMON_LOGGER("DNS_AUTO: is missing\n");
retval = false;
}
else
{
dnsAuto = configfileLoader.ReadAsInteger(L"DNS_AUTO");
if (dnsAuto == 1)
{
networkSetting.ip.autoDNSSetting = true;
}
else
{
networkSetting.ip.autoDNSSetting = false;
}
COMMON_LOGGER("DNS_AUTO = %d\n", networkSetting.ip.autoDNSSetting);
}
}
{
const char* dnsPrimary = configfileLoader.ReadAsChar(L"DNS_PRI"); // プライマリDNS
if(!networkSetting.ip.autoDNSSetting)
{
if (dnsPrimary == NULL)
{
COMMON_LOGGER("DNS_PRI: is missing\n");
retval = false;
}
else
{
u8 dns[4];
nn::socket::InAddr addr;
if (1 == nn::socket::InetAtoN(dnsPrimary, &addr))
{
dns[3] = (0xff & (addr.addr >> 24));
dns[2] = (0xff & (addr.addr >> 16));
dns[1] = (0xff & (addr.addr >> 8));
dns[0] = (0xff & (addr.addr));
}
std::memcpy(networkSetting.ip.dns[0], dns, 4);
COMMON_LOGGER("DNS_PRI = %03d.%03d.%03d.%03d\n", networkSetting.ip.dns[0][0],
networkSetting.ip.dns[0][1],
networkSetting.ip.dns[0][2],
networkSetting.ip.dns[0][3]);
}
}
}
{
const char* dnsSecondary = configfileLoader.ReadAsChar(L"DNS_SEC"); // セカンダリDNS
if(!networkSetting.ip.autoDNSSetting)
{
if(dnsSecondary == NULL)
{
COMMON_LOGGER("DNS_SEC: is missing\n");
retval = false;
}
else
{
u8 dns[4];
nn::socket::InAddr addr;
if (1 == nn::socket::InetAtoN(dnsSecondary, &addr))
{
dns[3] = (0xff & (addr.addr >> 24));
dns[2] = (0xff & (addr.addr >> 16));
dns[1] = (0xff & (addr.addr >> 8));
dns[0] = (0xff & (addr.addr));
}
std::memcpy(networkSetting.ip.dns[1], dns, 4);
COMMON_LOGGER("DNS_SEC = %03d.%03d.%03d.%03d\n", networkSetting.ip.dns[1][0],
networkSetting.ip.dns[1][1],
networkSetting.ip.dns[1][2],
networkSetting.ip.dns[1][3]);
}
}
}
{
const char* ntpServerName = configfileLoader.ReadAsChar(L"NTPSRV"); // NTPサーバ
if(ntpServerName == NULL)
{
COMMON_LOGGER("NTPSRV: is missing\n");
retval = false;
}
else
{
std::strlcpy(s_NtpServerName, ntpServerName, sizeof(s_NtpServerName));
COMMON_LOGGER("NTPSRV = %s\n", s_NtpServerName);
}
}
{
const char* timeZone = configfileLoader.ReadAsChar(L"TIMEZONE"); // タイムゾーン
if(timeZone == NULL)
{
COMMON_LOGGER("TIMEZONE: is missing\n");
retval = false;
}
else
{
std::strlcpy(s_TimeZoneStr, timeZone, sizeof(s_TimeZoneStr));
COMMON_LOGGER("TIMEZONE = %s\n", s_TimeZoneStr);
ConvertTimeZoneString(s_TimeZoneStr);
}
}
{
const wchar_t* const NUP_ONLY_STR = L"NUP_ONLY";
NN_NULL_ASSERT(nupOnly);
if (configfileLoader.ReadAsChar(NUP_ONLY_STR) != NULL)
{
s32 num = configfileLoader.ReadAsInteger(NUP_ONLY_STR);
if (num == 1)
{
*nupOnly = true;
COMMON_LOGGER("NUP Only Mode.\n");
}
}
}
{
const wchar_t* const GET_IVS_STR = L"GET_SDCI";
NN_NULL_ASSERT(getIvs);
if (configfileLoader.ReadAsChar(GET_IVS_STR) != NULL)
{
s32 num = configfileLoader.ReadAsInteger(GET_IVS_STR);
if (num == 1)
{
*getIvs = true;
COMMON_LOGGER("GET SDCI Mode.\n");
}
}
}
{
const wchar_t* const CHECK_SD_STR = L"CHECK_SD";
NN_NULL_ASSERT(checkSd);
if (configfileLoader.ReadAsChar(CHECK_SD_STR) != NULL)
{
s32 num = configfileLoader.ReadAsInteger(CHECK_SD_STR);
if (num == 1)
{
*checkSd = true;
COMMON_LOGGER("CHECK SD Mode.\n");
}
}
}
{
const wchar_t* const SKIP_NUP_STR = L"SKIP_NUP";
NN_NULL_ASSERT(skipNup);
if (configfileLoader.ReadAsChar(SKIP_NUP_STR) != NULL)
{
s32 num = configfileLoader.ReadAsInteger(SKIP_NUP_STR);
if (num == 1)
{
*skipNup = true;
COMMON_LOGGER("Skip NUP Mode.\n");
}
}
}
configfileLoader.Finalize();
// 書き込み完了しなければfalse
if(!UpdateNetworkSetting(networkSetting))
{
retval = false;
}
}
else
{
NN_LOG("configfileLoader Initialize Failed\n");
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
retval = false;
}
}
else
{
NN_LOG("Can't Allocate Heap\n");
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
retval = false;
}
common::SdMountManager::Unmount();
return retval;
}
char* GetNtpServerName()
{
return s_NtpServerName;
}
TimeZone GetTimeZone()
{
return s_TimeZone;
}
CheckedNetworkSetting* GetTempNetworkSetting()
{
return &s_CurrentNetowrkSetting1;
}
void ImportTwlData(enum common::TWL_PATH_INDEX path, s64 fileSize)
{
NN_ASSERT(path < common::TWL_PATHNAME_MAX);
nn::Result result;
s_IsImportSucceeded = true;
result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[path], common::TWL_FS_ARCHIVE_KIND[path]);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2);
NN_LOG("AllocatableSize = %d\n", bufSize);
// ファイルサイズ設定
common::InitializeTransferProgress(fileSize);
common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2);
void* buf = heap.GetAddr();
if (buf != NULL)
{
wchar_t archiveName[nn::fs::MAX_FILE_PATH_LENGTH];
::std::mbstowcs(archiveName, common::TWL_ARCHIVE_NAME_TABLE[path], std::strlen(common::TWL_ARCHIVE_NAME_TABLE[path]) + 1);
std::wstring archiveString(archiveName);
if(!common::CopyDirectory(
&s_FileLists,
(::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(),
(archiveString + ::std::wstring(L"/")).c_str(),
buf, bufSize, false, NULL, NULL))
{
s_IsImportSucceeded = false;
return;
}
}
common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[path]);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
}
void ImportTwlTitleSaveData(s64 fileSize)
{
nn::Result result;
s_IsImportSucceeded = true;
result = nn::fs::MountSpecialArchive(common::NAND_TWL_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_TWL_NAND);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2);
NN_LOG("AllocatableSize = %d\n", bufSize);
// ファイルサイズ設定
common::InitializeTransferProgress(fileSize);
common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2);
void* buf = heap.GetAddr();
if (buf != NULL)
{
if(!common::CopyDirectory(
&s_FileLists,
(::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str(),
(std::wstring(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH) + ::std::wstring(L"/")).c_str(),
buf, bufSize, false, NULL, NULL))
{
s_IsImportSucceeded = false;
return;
}
}
common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
nn::fs::Unmount(common::NAND_TWL_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded);
}
void ImportTwlPhotoDataFunc()
{
COMMON_LOGGER("Import Twl Photo Data.\n");
ImportTwlData(common::TWL_PHOTO, s_SdFileSize.twlPhotoFileSize);
}
void ImportTwlSoundDataFunc()
{
COMMON_LOGGER("Import Twl Sound Data.\n");
ImportTwlData(common::TWL_SOUND, s_SdFileSize.twlSoundFileSize);
}
void ImportTwlSaveDataFunc()
{
COMMON_LOGGER("Import Twl Save Data.\n");
ImportTwlTitleSaveData(s_SdFileSize.twlFileSize);
}
void ImportTwlPhotoData()
{
s_ImportThread.Start(ImportTwlPhotoDataFunc, s_ImportThreadStack);
}
void ImportTwlSoundData()
{
s_ImportThread.Start(ImportTwlSoundDataFunc, s_ImportThreadStack);
}
void ImportTwlSaveData()
{
s_ImportThread.Start(ImportTwlSaveDataFunc, s_ImportThreadStack);
}
void ClearFileReadResult()
{
s_CheckedEqualsDeviceIdFileandDeviceId = false;
s_CheckedEqualsRegionDataandRegion = false;
s_ReadSerialNumber = false;
}
nn::Result ExportCalData()
{
using namespace nn::cfg::CTR::detail;
nn::Result result;
common::CfgCalData cfgCalData;
common::SdReaderWriter sdWriter;
COMMON_LOGGER("Export CalData\n");
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.touchPanelCfgData, sizeof(TouchPanelCfgData),
GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_TOUCHPANEL));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.lcdFlickerCfgData, sizeof(LcdFlickerCfgData),
GET_CFG_KEY(NN_CFG_LCD, NN_CFG_LCD_CAL_FLICKER));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.fcramCfgData, sizeof(FcramCfgData),
GET_CFG_KEY(NN_CFG_FCRAM, NN_CFG_FCRAM_CAL_DELAY));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.rtcCfgData, sizeof(RtcCfgData),
GET_CFG_KEY(NN_CFG_RTC, NN_CFG_RTC_CAL_COMPENSATION));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.gyroscopeCfgData, sizeof(GyroscopeCfgData),
GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_GYROSCOPE));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.accelCfgData, sizeof(AccelCfgData),
GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_ACCELEROMETER));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.codecCfgData, sizeof(CodecCfgData),
GET_CFG_KEY(NN_CFG_CODEC, NN_CFG_CODEC_CAL));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.mcuSlideVolumeRangeCfgData, sizeof(McuSlideVolumeRangeCfgData),
GET_CFG_KEY(NN_CFG_MCU, NN_CFG_MCU_SLIDE_VOLUME));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = sdWriter.WriteBufWithCmac(common::CFG_CALIBRATION_PATHNAME, &cfgCalData, sizeof(cfgCalData));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
return nn::ResultSuccess();
}
nn::Result ImportCalData(common::CfgCalData *data)
{
using namespace nn::cfg::CTR::detail;
nn::Result result = nn::ResultSuccess();
COMMON_LOGGER("Import CalData\n");
common::SdMountManager::Mount();
size_t bufSize = common::GetAllocatableSize() / 2;
common::HeapManager heap(bufSize);
void* buf = heap.GetAddr();
if (buf != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::CFG_CALIBRATION_PATHNAME, buf, bufSize, &readSize);
if(result.IsSuccess())
{
// SDから読み出し成功
std::memcpy(data, buf, readSize);
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
else
{
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
common::SdMountManager::Unmount();
return result;
}
nn::Result InitializeHardwareDependentSetting()
{
using namespace nn::cfg::CTR::detail;
nn::Result result = nn::ResultSuccess();
common::CfgCalData cfgCalData;
result = ImportCalData(&cfgCalData);
NN_UTIL_RETURN_IF_FAILED(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_TOUCHPANEL),
&cfgCalData.touchPanelCfgData, sizeof(TouchPanelCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_LCD, NN_CFG_LCD_CAL_FLICKER),
&cfgCalData.lcdFlickerCfgData, sizeof(LcdFlickerCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_FCRAM, NN_CFG_FCRAM_CAL_DELAY), &cfgCalData.fcramCfgData,
sizeof(FcramCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_RTC, NN_CFG_RTC_CAL_COMPENSATION),
&cfgCalData.rtcCfgData, sizeof(RtcCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_GYROSCOPE),
&cfgCalData.gyroscopeCfgData, sizeof(GyroscopeCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_ACCELEROMETER),
&cfgCalData.accelCfgData, sizeof(AccelCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_CODEC, NN_CFG_CODEC_CAL), &cfgCalData.codecCfgData,
sizeof(CodecCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_MCU, NN_CFG_MCU_SLIDE_VOLUME),
&cfgCalData.mcuSlideVolumeRangeCfgData, sizeof(McuSlideVolumeRangeCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_LOG("Set cfgCalData\n");
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
nn::cfg::CTR::init::ResetCameraCalibration();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
nn::cfg::CTR::init::ResetAnalogStickCalibration();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return result;
}
nn::Result SetupFileList()
{
std::memset(&s_SdFileSize, 0, sizeof(s_SdFileSize));
// ファイル一覧を読み込む
nn::Result result = ReadFileList(&s_SdFileSize, &s_FileLists);
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result ReadFileList(SdFileSize* sdFiles, common::ImportDataList* fileList)
{
nn::Result result = nn::ResultSuccess();
COMMON_LOGGER("Read File List\n");
size_t readSize;
common::SdReaderWriter sdReader;
s64 fileSize;
{
nn::fs::FileInputStream file;
// サイズ取得のため一時的に開く
result = file.TryInitialize(common::FILE_LIST_PATHNAME);
NN_UTIL_RETURN_IF_FAILED(result);
result = file.TryGetSize(&fileSize);
if (result.IsFailure())
{
file.Finalize();
return result;
}
file.Finalize();
}
common::HeapManager heap(fileSize);
void* buf = heap.GetAddr();
if(buf != NULL)
{
result = sdReader.ReadBufWithCmac(common::FILE_LIST_PATHNAME, buf, fileSize, &readSize);
if(result.IsSuccess())
{
// ファイル一覧
const char comma[] = ",";
const char newLine[] = "\n";
char *token = NULL;
token = std::strtok(reinterpret_cast<char*>(buf), comma);
bool parseFileName = false;
common::ImportDataEntry entry;
entry.fileName = std::string(token);
while( token != NULL)
{
if(parseFileName)
{
token = std::strtok(NULL, comma);
if(token != NULL)
{
entry.fileName = std::string(token);
}
}
else
{
token = std::strtok(NULL, newLine);
if(token != NULL)
{
s64 size = std::atoll(token);
if(size != -1)
{
entry.isDirectory = false;
sdFiles->totalFileSize += size;
wchar_t wcToken[nn::fs::MAX_FILE_PATH_LENGTH];
if(std::mbstowcs(wcToken, entry.fileName.c_str(), entry.fileName.size()) != entry.fileName.size() - 1)
{
if(std::wcsstr(wcToken, common::SD_SAVEDATA_ROOT_NAME) != NULL)
{
sdFiles->ctrFileSize += size;
}
else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME) != NULL)
{
sdFiles->twlPhotoFileSize += size;
}
else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME) != NULL)
{
sdFiles->twlSoundFileSize += size;
}
else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_ROOT_NAME) != NULL)
{
sdFiles->twlFileSize += size;
}
}
}
else
{
entry.isDirectory = true;
}
fileList->push_back(entry);
}
}
parseFileName = !parseFileName;
}
}
}
else
{
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
bool IsImportSucceeded()
{
return s_IsImportSucceeded;
}
nn::Result ImportData()
{
static nn::Result result = nn::ResultSuccess();
static bool init = true;
if(init)
{
init = false;
// インポート前にACを止める
result = nn::ndm::SuspendScheduler();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// NANDのごみを削除する
result = Cleanup();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// NORデータを書き込む
result = ImportNorData();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// 固体固有calLデータをSDカードに出力する
// 本体初期化後はcal値が設定されている
result = ExportCalData();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// SDカードのセーブデータをNANDに書き込む
ImportSaveData();
}
return result;
}
}