New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WiiSave: Refactor the import/export code #6988
Conversation
9e271d6
to
3d1eacd
Compare
The current WiiSave code is extremely messy, as it exposes all kinds of implementation details in the header (including internal struct definitions and magic numbers that don't have to be). The read/write code is intermingled, so it's hard to tell which members are used, or when/where they are set at all. It also implicitly relies on some functions being called in a specific order since it doesn't seek manually every time, which makes the code even more fragile. The logic is also hardcoded to only support bin->nand or nand->bin, even though it would be useful to support nand->nand (for the Movie save copying code, for example). This commit attempts to solve these problems by getting rid of the WiiSave class: * Read/write code is moved to new Storage classes (NandStorage and DataBinStorage) with small, clear functions that do one and only one thing. * The import/export logic was refactored into a generic Copy function that takes two storages as parameters. * The existing import and export functions are now just small wrappers that call Copy with the appropriate storages.
3d1eacd
to
a46a8dd
Compare
WriteHeader should just write the header and not do anything else.
std::transform(m_files_list.begin(), m_files_list.end(), ret.begin(), [this](const auto& path) { | ||
const File::FileInfo file_info{path}; | ||
SaveFile save_file; | ||
save_file.mode = 0x3c; |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
raw_save_file.WriteBytes(file_data.data(), file_hdr_tmp.size); | ||
for (u32 i = 0; i < directories.size(); ++i) | ||
{ | ||
if (i != 0) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
Source/Core/Core/HW/WiiSave.cpp
Outdated
SaveFile save_file; | ||
save_file.mode = 0x3c; | ||
save_file.attributes = 0; | ||
save_file.type = file_info.IsDirectory() ? 2 : 1; |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
Source/Core/Core/HW/WiiSave.cpp
Outdated
file_hdr.permissions = save_file.mode; | ||
file_hdr.attrib = save_file.attributes; | ||
file_hdr.type = save_file.type; | ||
if (save_file.path.length() > 0x44) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
Source/Core/Core/HW/WiiSave.cpp
Outdated
// Read data to sign. | ||
const u32 data_size = bk_header->size_of_files + 0x80; | ||
auto data = std::make_unique<u8[]>(data_size); | ||
m_file.Seek(0xf0c0, SEEK_SET); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
Source/Core/Core/HW/WiiSave.cpp
Outdated
else | ||
const auto nand = MakeNandStorage(ios.GetFS().get(), header->hdr.tid); | ||
if (nand->SaveExists() && !AskYesNoT("Save data for this title already exists. Consider backing " | ||
"up the current data before overwriting.\nOverwrite now?")) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
359d537
to
ec778ca
Compare
Paths can never exceed 0x40 characters as this is the maximum length that is allowed by IOS (and probably the common FS library too).
ec778ca
to
8eafd19
Compare
@BhaaLseN fixed (except first and second comments, since the code will be replaced very soon, and the 0xf0c0 comment since I don't know what the values actually are) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we can leave it at that. I tried reviewing it a couple of times and only now came thru; and even with that I can only say it looks good, but I haven't really tested it. My NAND seems to be in an abysmal state, so it probably wouldn't help me anyways.
Some other reviews (or some actual testing with a good NAND) would be nice.
Source/Core/Core/HW/WiiSave.cpp
Outdated
// Read data to sign. | ||
const u32 data_size = bk_header->size_of_files + 0x80; | ||
auto data = std::make_unique<u8[]>(data_size); | ||
m_file.Seek(0xf0c0, SEEK_SET); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
It would make sense for 0x80 and 0xf0c0 to be respectively sizeof(BkHeader) and sizeof(Header) as Nintendo is signing anything that comes after the header, including the BkHeader.
DataBinHeader is not used anywhere in the code other than via Header, so let's merge them to reduce noise when accessing header fields (currently we have to do header.hdr which looks silly).
Nice, that struct size actually matches those magic numbers 👍 |
The current WiiSave code is extremely messy, as it exposes all kinds of implementation details in the header (including internal struct definitions and magic numbers that don't have to be public).
The read/write code is intermingled, so it's hard to tell which members are used, or when/where they are set at all.
It also implicitly relies on some functions being called in a specific order since it doesn't seek manually every time, which makes the code even more fragile.
The logic is also hardcoded to only support bin->nand or nand->bin, even though it would be useful to support nand->nand (for the Movie save copying code, for example).
This commit attempts to solve these problems by getting rid of the WiiSave class:
Read/write code is moved to new Storage classes (NandStorage and DataBinStorage) with small, clear functions that do one and only one thing.
The import/export logic was refactored into a generic Copy function that takes two storages as parameters.
The existing import and export functions are now just small wrappers that call Copy with the appropriate storages.
Because tons of code was moved, the diff may seem pretty large even though most of the code is the same, so I recommend using WiiBrew as a reference for the save code.