From 4082c4eda6d8282abf0ba7763ed4fd66ecd176f1 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Thu, 6 Dec 2018 20:28:51 -0500
Subject: [PATCH] savedata_factory: Partially implement IVFC save sizes using
 files

This stores a file in the save directory called '.yuzu_save_size' which stores the two save sizes (normal area and journaled area) sequentially as u64s.
---
 src/core/file_sys/savedata_factory.cpp | 30 ++++++++++++++++++++++++++
 src/core/file_sys/savedata_factory.h   |  8 +++++++
 2 files changed, 38 insertions(+)

diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index d63b7f19b..54f5b698a 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -13,6 +13,8 @@
 
 namespace FileSys {
 
+constexpr const char* SAVE_DATA_SIZE_FILENAME = ".yuzu_save_size";
+
 std::string SaveDataDescriptor::DebugInfo() const {
     return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]",
                        static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id);
@@ -132,4 +134,32 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
     }
 }
 
+SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
+                                               u128 user_id) const {
+    const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
+    const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
+
+    const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME);
+    if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize))
+        return {0, 0};
+
+    SaveDataSize out;
+    if (size_file->ReadObject(&out) != sizeof(SaveDataSize))
+        return {0, 0};
+    return out;
+}
+
+void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
+                                        SaveDataSize new_value) {
+    const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
+    const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
+
+    const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME);
+    if (size_file == nullptr)
+        return;
+
+    size_file->Resize(sizeof(SaveDataSize));
+    size_file->WriteObject(new_value);
+}
+
 } // namespace FileSys
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index bd4919610..3a1caf292 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -46,6 +46,11 @@ struct SaveDataDescriptor {
 };
 static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorrect size.");
 
+struct SaveDataSize {
+    u64 normal;
+    u64 journal;
+};
+
 /// File system interface to the SaveData archive
 class SaveDataFactory {
 public:
@@ -60,6 +65,9 @@ public:
     static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
                                    u128 user_id, u64 save_id);
 
+    SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
+    void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, SaveDataSize new_value);
+
 private:
     VirtualDir dir;
 };