summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2022-11-15 03:42:26 +0100
committerGitHub <noreply@github.com>2022-11-15 03:42:26 +0100
commit09c0321997fe4a5c418d24f248b58782de2b30bd (patch)
treeb2dfe02514702c454e77252f4ec0d41971b12aa9 /Source/Core
parentb6503d7585ef10ea0790335ad59a03f35ed2d001 (diff)
parented54e1905a92b4e84a1fed67d2ef4ac2a01eec03 (diff)
Merge pull request #11184 from Lobsterzelda/save-all-nand-files-to-save-state
HostFileSystem: Set all NAND folders to be saved in save states
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Common/ChunkFile.h16
-rw-r--r--Source/Core/Core/IOS/FS/HostBackend/FS.cpp210
-rw-r--r--Source/Core/Core/IOS/FS/HostBackend/FS.h4
-rw-r--r--Source/Core/Core/State.cpp2
4 files changed, 153 insertions, 79 deletions
diff --git a/Source/Core/Common/ChunkFile.h b/Source/Core/Common/ChunkFile.h
index e6bc09322e..ef9be1b7ce 100644
--- a/Source/Core/Common/ChunkFile.h
+++ b/Source/Core/Common/ChunkFile.h
@@ -229,6 +229,22 @@ public:
return current;
}
+ // The reserved u32 is set to 0, and a pointer to it is returned.
+ // The caller needs to fill in the reserved u32 with the appropriate value later on, if they
+ // want a non-zero value there.
+ [[nodiscard]] u8* ReserveU32()
+ {
+ u32 temp = 0;
+ u8* previous_pointer = *m_ptr_current;
+ Do(temp);
+ return previous_pointer;
+ }
+
+ u32 GetOffsetFromPreviousPosition(u8* previous_pointer)
+ {
+ return static_cast<u32>((*m_ptr_current) - previous_pointer);
+ }
+
void Do(Common::Flag& flag)
{
bool s = flag.IsSet();
diff --git a/Source/Core/Core/IOS/FS/HostBackend/FS.cpp b/Source/Core/Core/IOS/FS/HostBackend/FS.cpp
index 1ca9a2faa1..15cc6bd762 100644
--- a/Source/Core/Core/IOS/FS/HostBackend/FS.cpp
+++ b/Source/Core/Core/IOS/FS/HostBackend/FS.cpp
@@ -20,9 +20,13 @@
#include "Common/Swap.h"
#include "Core/IOS/ES/ES.h"
#include "Core/IOS/IOS.h"
+#include "Core/Movie.h"
+#include "Core/WiiRoot.h"
namespace IOS::HLE::FS
{
+constexpr u32 BUFFER_CHUNK_SIZE = 65536;
+
HostFileSystem::HostFilename HostFileSystem::BuildFilename(const std::string& wii_path) const
{
for (const auto& redirect : m_nand_redirects)
@@ -252,99 +256,151 @@ HostFileSystem::FstEntry* HostFileSystem::GetFstEntryForPath(const std::string&
return entry;
}
-void HostFileSystem::DoState(PointerWrap& p)
+void HostFileSystem::DoStateRead(PointerWrap& p, std::string start_directory_path)
{
- // Temporarily close the file, to prevent any issues with the savestating of /tmp
- for (Handle& handle : m_handles)
- handle.host_file.reset();
+ std::string path = BuildFilename(start_directory_path).host_path;
+ File::DeleteDirRecursively(path);
+ File::CreateDir(path);
- // handle /tmp
- std::string Path = BuildFilename("/tmp").host_path;
- if (p.IsReadMode())
+ // now restore from the stream
+ while (1)
{
- File::DeleteDirRecursively(Path);
- File::CreateDir(Path);
-
- // now restore from the stream
- while (1)
+ char type = 0;
+ p.Do(type);
+ if (!type)
+ break;
+ std::string file_name;
+ p.Do(file_name);
+ std::string name = path + "/" + file_name;
+ switch (type)
{
- char type = 0;
- p.Do(type);
- if (!type)
- break;
- std::string file_name;
- p.Do(file_name);
- std::string name = Path + "/" + file_name;
- switch (type)
- {
- case 'd':
- {
- File::CreateDir(name);
- break;
- }
- case 'f':
+ case 'd':
+ {
+ File::CreateDir(name);
+ break;
+ }
+ case 'f':
+ {
+ u32 size = 0;
+ p.Do(size);
+
+ File::IOFile handle(name, "wb");
+ char buf[BUFFER_CHUNK_SIZE];
+ u32 count = size;
+ while (count > BUFFER_CHUNK_SIZE)
{
- u32 size = 0;
- p.Do(size);
-
- File::IOFile handle(name, "wb");
- char buf[65536];
- u32 count = size;
- while (count > 65536)
- {
- p.DoArray(buf);
- handle.WriteArray(&buf[0], 65536);
- count -= 65536;
- }
- p.DoArray(&buf[0], count);
- handle.WriteArray(&buf[0], count);
- break;
- }
+ p.DoArray(buf);
+ handle.WriteArray(&buf[0], BUFFER_CHUNK_SIZE);
+ count -= BUFFER_CHUNK_SIZE;
}
+ p.DoArray(&buf[0], count);
+ handle.WriteArray(&buf[0], count);
+ break;
+ }
}
}
- else
- {
- // recurse through tmp and save dirs and files
+}
- File::FSTEntry parent_entry = File::ScanDirectoryTree(Path, true);
- std::deque<File::FSTEntry> todo;
- todo.insert(todo.end(), parent_entry.children.begin(), parent_entry.children.end());
+void HostFileSystem::DoStateWriteOrMeasure(PointerWrap& p, std::string start_directory_path)
+{
+ std::string path = BuildFilename(start_directory_path).host_path;
+ File::FSTEntry parent_entry = File::ScanDirectoryTree(path, true);
+ std::deque<File::FSTEntry> todo;
+ todo.insert(todo.end(), parent_entry.children.begin(), parent_entry.children.end());
- while (!todo.empty())
+ while (!todo.empty())
+ {
+ File::FSTEntry& entry = todo.front();
+ std::string name = entry.physicalName;
+ name.erase(0, path.length() + 1);
+ char type = entry.isDirectory ? 'd' : 'f';
+ p.Do(type);
+ p.Do(name);
+ if (entry.isDirectory)
+ {
+ todo.insert(todo.end(), entry.children.begin(), entry.children.end());
+ }
+ else
{
- File::FSTEntry& entry = todo.front();
- std::string name = entry.physicalName;
- name.erase(0, Path.length() + 1);
- char type = entry.isDirectory ? 'd' : 'f';
- p.Do(type);
- p.Do(name);
- if (entry.isDirectory)
+ u32 size = (u32)entry.size;
+ p.Do(size);
+
+ File::IOFile handle(entry.physicalName, "rb");
+ char buf[BUFFER_CHUNK_SIZE];
+ u32 count = size;
+ while (count > BUFFER_CHUNK_SIZE)
{
- todo.insert(todo.end(), entry.children.begin(), entry.children.end());
+ handle.ReadArray(&buf[0], BUFFER_CHUNK_SIZE);
+ p.DoArray(buf);
+ count -= BUFFER_CHUNK_SIZE;
}
- else
+ handle.ReadArray(&buf[0], count);
+ p.DoArray(&buf[0], count);
+ }
+ todo.pop_front();
+ }
+
+ char type = 0;
+ p.Do(type);
+}
+
+void HostFileSystem::DoState(PointerWrap& p)
+{
+ // Temporarily close the file, to prevent any issues with the savestating of files/folders.
+ for (Handle& handle : m_handles)
+ handle.host_file.reset();
+
+ // The format for the next part of the save state is follows:
+ // 1. bool Movie::WasMovieActiveWhenStateSaved() &&
+ // WiiRoot::WasWiiRootTemporaryDirectoryWhenStateSaved()
+ // 2. Contents of the "/tmp" directory recursively.
+ // 3. u32 size_of_nand_folder_saved_below (or 0, if the root
+ // of the NAND folder is not savestated below).
+ // 4. Contents of the "/" directory recursively (or nothing, if the
+ // root of the NAND folder is not save stated).
+
+ // The "/" directory is only saved when a savestate is made during a movie recording
+ // and when the directory root is temporary (i.e. WiiSession).
+ // If a save state is made during a movie recording and is loaded when no movie is active,
+ // then a call to p.DoExternal() will be used to skip over reading the contents of the "/"
+ // directory (it skips over the number of bytes specified by size_of_nand_folder_saved)
+
+ bool original_save_state_made_during_movie_recording =
+ Movie::IsMovieActive() && Core::WiiRootIsTemporary();
+ p.Do(original_save_state_made_during_movie_recording);
+
+ u32 temp_val = 0;
+
+ if (!p.IsReadMode())
+ {
+ DoStateWriteOrMeasure(p, "/tmp");
+ u8* previous_position = p.ReserveU32();
+ if (original_save_state_made_during_movie_recording)
+ {
+ DoStateWriteOrMeasure(p, "/");
+ if (p.IsWriteMode())
{
- u32 size = (u32)entry.size;
- p.Do(size);
-
- File::IOFile handle(entry.physicalName, "rb");
- char buf[65536];
- u32 count = size;
- while (count > 65536)
- {
- handle.ReadArray(&buf[0], 65536);
- p.DoArray(buf);
- count -= 65536;
- }
- handle.ReadArray(&buf[0], count);
- p.DoArray(&buf[0], count);
+ u32 size_of_nand = p.GetOffsetFromPreviousPosition(previous_position) - sizeof(u32);
+ memcpy(previous_position, &size_of_nand, sizeof(u32));
}
- todo.pop_front();
}
-
- char type = 0;
- p.Do(type);
+ }
+ else // case where we're in read mode.
+ {
+ DoStateRead(p, "/tmp");
+ if (!Movie::IsMovieActive() || !original_save_state_made_during_movie_recording ||
+ !Core::WiiRootIsTemporary() ||
+ (original_save_state_made_during_movie_recording !=
+ (Movie::IsMovieActive() && Core::WiiRootIsTemporary())))
+ {
+ (void)p.DoExternal(temp_val);
+ }
+ else
+ {
+ p.Do(temp_val);
+ if (Movie::IsMovieActive() && Core::WiiRootIsTemporary())
+ DoStateRead(p, "/");
+ }
}
for (Handle& handle : m_handles)
diff --git a/Source/Core/Core/IOS/FS/HostBackend/FS.h b/Source/Core/Core/IOS/FS/HostBackend/FS.h
index 17ef9baf36..1248c06736 100644
--- a/Source/Core/Core/IOS/FS/HostBackend/FS.h
+++ b/Source/Core/Core/IOS/FS/HostBackend/FS.h
@@ -59,10 +59,12 @@ public:
void SetNandRedirects(std::vector<NandRedirect> nand_redirects) override;
private:
+ void DoStateWriteOrMeasure(PointerWrap& p, std::string start_directory_path);
+ void DoStateRead(PointerWrap& p, std::string start_directory_path);
+
struct FstEntry
{
bool CheckPermission(Uid uid, Gid gid, Mode requested_mode) const;
-
std::string name;
Metadata data{};
/// Children of this FST entry. Only valid for directories.
diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp
index 5c175c8ae6..a735dc322f 100644
--- a/Source/Core/Core/State.cpp
+++ b/Source/Core/Core/State.cpp
@@ -94,7 +94,7 @@ static size_t s_state_writes_in_queue;
static std::condition_variable s_state_write_queue_is_empty;
// Don't forget to increase this after doing changes on the savestate system
-constexpr u32 STATE_VERSION = 155; // Last changed in PR 10890
+constexpr u32 STATE_VERSION = 156; // Last changed in PR 11184
// Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list,