From 783e7af5b283f307b036665122d3de335c5e5b60 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Wed, 15 Apr 2020 16:38:37 -0500
Subject: [PATCH] Services/FS: Stubbed GetSdmcArchiveResource and
 GetNandArchiveResource.

Also rewritten how GetArchiveResource works so that they all use the same interface.
We should decide what to do with these at some point.

Related to #3131 and #3110
---
 src/core/hle/service/fs/archive.cpp | 10 ++++++
 src/core/hle/service/fs/archive.h   | 15 ++++++++
 src/core/hle/service/fs/fs_user.cpp | 55 ++++++++++++++++++++++++-----
 src/core/hle/service/fs/fs_user.h   | 26 ++++++++++++++
 4 files changed, 98 insertions(+), 8 deletions(-)

diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 6e179978b..971ae5c0e 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -288,6 +288,16 @@ ResultCode ArchiveManager::CreateSystemSaveData(u32 high, u32 low) {
     return RESULT_SUCCESS;
 }
 
+ResultVal<ArchiveResource> ArchiveManager::GetArchiveResource(MediaType media_type) const {
+    // TODO(Subv): Implement querying the actual size information for these storages.
+    ArchiveResource resource{};
+    resource.sector_size_in_bytes = 512;
+    resource.cluster_size_in_bytes = 16384;
+    resource.partition_capacity_in_clusters = 0x80000; // 8GiB capacity
+    resource.free_space_in_clusters = 0x80000;         // 8GiB free
+    return MakeResult(resource);
+}
+
 void ArchiveManager::RegisterArchiveTypes() {
     // TODO(Subv): Add the other archive types (see here for the known types:
     // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes).
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 862e74980..3c6d20b71 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -49,6 +49,14 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 };
 
 typedef u64 ArchiveHandle;
 
+struct ArchiveResource {
+    u32 sector_size_in_bytes;
+    u32 cluster_size_in_bytes;
+    u32 partition_capacity_in_clusters;
+    u32 free_space_in_clusters;
+};
+static_assert(sizeof(ArchiveResource) == 0x10, "ArchiveResource has incorrect size");
+
 using FileSys::ArchiveBackend;
 using FileSys::ArchiveFactory;
 
@@ -230,6 +238,13 @@ public:
      */
     ResultCode CreateSystemSaveData(u32 high, u32 low);
 
+    /**
+     * Returns capacity and free space information about the given media type.
+     * @param media_type The media type to obtain the information about.
+     * @return The capacity information of the media type, or an error code if failed.
+     */
+    ResultVal<ArchiveResource> GetArchiveResource(MediaType media_type) const;
+
     /// Registers a new NCCH file with the SelfNCCH archive factory
     void RegisterSelfNCCH(Loader::AppLoader& app_loader);
 
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index bca8e77e5..0d3e37e0c 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -449,6 +449,41 @@ void FS_USER::GetFreeBytes(Kernel::HLERequestContext& ctx) {
     }
 }
 
+void FS_USER::GetSdmcArchiveResource(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp(ctx, 0x814, 0, 0);
+
+    LOG_WARNING(Service_FS, "(STUBBED) called");
+
+    auto resource = archives.GetArchiveResource(MediaType::SDMC);
+
+    if (resource.Failed()) {
+        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        rb.Push(resource.Code());
+        return;
+    }
+
+    IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
+    rb.Push(RESULT_SUCCESS);
+    rb.PushRaw(*resource);
+}
+
+void FS_USER::GetNandArchiveResource(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp(ctx, 0x815, 0, 0);
+
+    LOG_WARNING(Service_FS, "(STUBBED) called");
+
+    auto resource = archives.GetArchiveResource(MediaType::NAND);
+    if (resource.Failed()) {
+        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        rb.Push(resource.Code());
+        return;
+    }
+
+    IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
+    rb.Push(RESULT_SUCCESS);
+    rb.PushRaw(*resource);
+}
+
 void FS_USER::CreateExtSaveData(Kernel::HLERequestContext& ctx) {
     // TODO(Subv): Figure out the other parameters.
     IPC::RequestParser rp(ctx, 0x0851, 9, 2);
@@ -601,16 +636,20 @@ void FS_USER::GetPriority(Kernel::HLERequestContext& ctx) {
 
 void FS_USER::GetArchiveResource(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp(ctx, 0x849, 1, 0);
-    u32 system_media_type = rp.Pop<u32>();
+    auto media_type = rp.PopEnum<MediaType>();
 
-    LOG_WARNING(Service_FS, "(STUBBED) called Media type=0x{:08X}", system_media_type);
+    LOG_WARNING(Service_FS, "(STUBBED) called Media type=0x{:08X}", static_cast<u32>(media_type));
+
+    auto resource = archives.GetArchiveResource(media_type);
+    if (resource.Failed()) {
+        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        rb.Push(resource.Code());
+        return;
+    }
 
     IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
     rb.Push(RESULT_SUCCESS);
-    rb.Push<u32>(512);
-    rb.Push<u32>(16384);
-    rb.Push<u32>(0x80000); // 8GiB capacity
-    rb.Push<u32>(0x80000); // 8GiB free
+    rb.PushRaw(*resource);
 }
 
 void FS_USER::GetFormatInfo(Kernel::HLERequestContext& ctx) {
@@ -798,8 +837,8 @@ FS_USER::FS_USER(Core::System& system)
         {0x08110040, nullptr, "DeleteSystemSaveData"},
         {0x08120080, &FS_USER::GetFreeBytes, "GetFreeBytes"},
         {0x08130000, nullptr, "GetCardType"},
-        {0x08140000, nullptr, "GetSdmcArchiveResource"},
-        {0x08150000, nullptr, "GetNandArchiveResource"},
+        {0x08140000, &FS_USER::GetSdmcArchiveResource, "GetSdmcArchiveResource"},
+        {0x08150000, &FS_USER::GetNandArchiveResource, "GetNandArchiveResource"},
         {0x08160000, nullptr, "GetSdmcFatfsError"},
         {0x08170000, &FS_USER::IsSdmcDetected, "IsSdmcDetected"},
         {0x08180000, &FS_USER::IsSdmcWriteable, "IsSdmcWritable"},
diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h
index 97b45714b..36a1866fb 100644
--- a/src/core/hle/service/fs/fs_user.h
+++ b/src/core/hle/service/fs/fs_user.h
@@ -291,6 +291,32 @@ private:
      */
     void GetFreeBytes(Kernel::HLERequestContext& ctx);
 
+    /**
+     * FS_User::GetSdmcArchiveResource service function.
+     *  Inputs:
+     *      0 : 0x08140000
+     *  Outputs:
+     *      1 : Result of function, 0 on success, otherwise error code
+     *      2 : Sector byte-size
+     *      3 : Cluster byte-size
+     *      4 : Partition capacity in clusters
+     *      5 : Available free space in clusters
+     */
+    void GetSdmcArchiveResource(Kernel::HLERequestContext& ctx);
+
+    /**
+     * FS_User::GetNandArchiveResource service function.
+     *  Inputs:
+     *      0 : 0x08150000
+     *  Outputs:
+     *      1 : Result of function, 0 on success, otherwise error code
+     *      2 : Sector byte-size
+     *      3 : Cluster byte-size
+     *      4 : Partition capacity in clusters
+     *      5 : Available free space in clusters
+     */
+    void GetNandArchiveResource(Kernel::HLERequestContext& ctx);
+
     /**
      * FS_User::CreateExtSaveData service function
      *  Inputs: