summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt6
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt14
-rw-r--r--src/android/app/src/main/jni/native.cpp9
-rw-r--r--src/android/app/src/main/jni/native_input.cpp76
-rw-r--r--src/common/settings.h6
-rw-r--r--src/common/settings_enums.h2
-rw-r--r--src/core/CMakeLists.txt26
-rw-r--r--src/core/device_memory_manager.inc12
-rw-r--r--src/core/file_sys/fs_filesystem.h27
-rw-r--r--src/core/file_sys/fs_memory_management.h8
-rw-r--r--src/core/file_sys/fs_path.h2
-rw-r--r--src/core/file_sys/fs_path_utility.h7
-rw-r--r--src/core/file_sys/fs_save_data_types.h175
-rw-r--r--src/core/file_sys/fs_string_util.h15
-rw-r--r--src/core/file_sys/fsa/fs_i_directory.h91
-rw-r--r--src/core/file_sys/fsa/fs_i_file.h167
-rw-r--r--src/core/file_sys/fsa/fs_i_filesystem.h206
-rw-r--r--src/core/file_sys/fssrv/fssrv_sf_path.h36
-rw-r--r--src/core/file_sys/fssystem/fssystem_aes_xts_storage.h1
-rw-r--r--src/core/file_sys/savedata_factory.cpp90
-rw-r--r--src/core/file_sys/savedata_factory.h68
-rw-r--r--src/core/hle/service/am/service/application_functions.cpp6
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.cpp72
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.h13
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.cpp124
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.h21
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp283
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.h62
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp33
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h23
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp161
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h50
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.cpp47
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.h7
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.cpp589
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.h72
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_types.h (renamed from src/core/hle/service/filesystem/fsp/fsp_util.h)12
-rw-r--r--src/core/hle/service/psc/ovln/ovln_types.h21
-rw-r--r--src/core/hle/service/psc/ovln/receiver.cpp24
-rw-r--r--src/core/hle/service/psc/ovln/receiver.h16
-rw-r--r--src/core/hle/service/psc/ovln/receiver_service.cpp28
-rw-r--r--src/core/hle/service/psc/ovln/receiver_service.h22
-rw-r--r--src/core/hle/service/psc/ovln/sender.cpp32
-rw-r--r--src/core/hle/service/psc/ovln/sender.h21
-rw-r--r--src/core/hle/service/psc/ovln/sender_service.cpp30
-rw-r--r--src/core/hle/service/psc/ovln/sender_service.h23
-rw-r--r--src/core/hle/service/psc/pm_control.cpp28
-rw-r--r--src/core/hle/service/psc/pm_control.h16
-rw-r--r--src/core/hle/service/psc/pm_module.cpp24
-rw-r--r--src/core/hle/service/psc/pm_module.h16
-rw-r--r--src/core/hle/service/psc/pm_service.cpp28
-rw-r--r--src/core/hle/service/psc/pm_service.h22
-rw-r--r--src/core/hle/service/psc/psc.cpp71
-rw-r--r--src/core/hle/service/psc/psc.h4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_special.cpp8
-rw-r--r--src/shader_recompiler/profile.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp1
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp14
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h5
-rw-r--r--src/yuzu/configuration/shared_translation.cpp10
-rw-r--r--src/yuzu/main.cpp94
62 files changed, 1997 insertions, 1185 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt
index d35de80c4..a84ac77a2 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt
@@ -64,17 +64,17 @@ data class PlayerInput(
64 fun hasMapping(): Boolean { 64 fun hasMapping(): Boolean {
65 var hasMapping = false 65 var hasMapping = false
66 buttons.forEach { 66 buttons.forEach {
67 if (it != "[empty]") { 67 if (it != "[empty]" && it.isNotEmpty()) {
68 hasMapping = true 68 hasMapping = true
69 } 69 }
70 } 70 }
71 analogs.forEach { 71 analogs.forEach {
72 if (it != "[empty]") { 72 if (it != "[empty]" && it.isNotEmpty()) {
73 hasMapping = true 73 hasMapping = true
74 } 74 }
75 } 75 }
76 motions.forEach { 76 motions.forEach {
77 if (it != "[empty]") { 77 if (it != "[empty]" && it.isNotEmpty()) {
78 hasMapping = true 78 hasMapping = true
79 } 79 }
80 } 80 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index 6907bec02..3ea5f5008 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -780,7 +780,7 @@ class SettingsFragmentPresenter(
780 playerIndex: Int, 780 playerIndex: Int,
781 paramName: String, 781 paramName: String,
782 stick: NativeAnalog, 782 stick: NativeAnalog,
783 defaultValue: Int 783 defaultValue: Float
784 ): AbstractIntSetting = 784 ): AbstractIntSetting =
785 object : AbstractIntSetting { 785 object : AbstractIntSetting {
786 val params get() = NativeInput.getStickParam(playerIndex, stick) 786 val params get() = NativeInput.getStickParam(playerIndex, stick)
@@ -788,7 +788,7 @@ class SettingsFragmentPresenter(
788 override val key = "" 788 override val key = ""
789 789
790 override fun getInt(needsGlobal: Boolean): Int = 790 override fun getInt(needsGlobal: Boolean): Int =
791 (params.get(paramName, 0.15f) * 100).toInt() 791 (params.get(paramName, defaultValue) * 100).toInt()
792 792
793 override fun setInt(value: Int) { 793 override fun setInt(value: Int) {
794 val tempParams = params 794 val tempParams = params
@@ -796,12 +796,12 @@ class SettingsFragmentPresenter(
796 NativeInput.setStickParam(playerIndex, stick, tempParams) 796 NativeInput.setStickParam(playerIndex, stick, tempParams)
797 } 797 }
798 798
799 override val defaultValue = defaultValue 799 override val defaultValue = (defaultValue * 100).toInt()
800 800
801 override fun getValueAsString(needsGlobal: Boolean): String = 801 override fun getValueAsString(needsGlobal: Boolean): String =
802 getInt(needsGlobal).toString() 802 getInt(needsGlobal).toString()
803 803
804 override fun reset() = setInt(defaultValue) 804 override fun reset() = setInt(this.defaultValue)
805 } 805 }
806 806
807 private fun getExtraStickSettings( 807 private fun getExtraStickSettings(
@@ -811,11 +811,11 @@ class SettingsFragmentPresenter(
811 val stickIsController = 811 val stickIsController =
812 NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog)) 812 NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog))
813 val modifierRangeSetting = 813 val modifierRangeSetting =
814 getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50) 814 getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 0.5f)
815 val stickRangeSetting = 815 val stickRangeSetting =
816 getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95) 816 getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 0.95f)
817 val stickDeadzoneSetting = 817 val stickDeadzoneSetting =
818 getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15) 818 getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 0.15f)
819 819
820 val out = mutableListOf<SettingsItem>().apply { 820 val out = mutableListOf<SettingsItem>().apply {
821 if (stickIsController) { 821 if (stickIsController) {
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 4ea82e217..5d484a85e 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -292,6 +292,9 @@ void EmulationSession::ShutdownEmulation() {
292 // Unload user input. 292 // Unload user input.
293 m_system.HIDCore().UnloadInputDevices(); 293 m_system.HIDCore().UnloadInputDevices();
294 294
295 // Enable all controllers
296 m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
297
295 // Shutdown the main emulated process 298 // Shutdown the main emulated process
296 if (m_load_result == Core::SystemResultStatus::Success) { 299 if (m_load_result == Core::SystemResultStatus::Success) {
297 m_system.DetachDebugger(); 300 m_system.DetachDebugger();
@@ -665,7 +668,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
665 ASSERT(user_id); 668 ASSERT(user_id);
666 669
667 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 670 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
668 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1, 671 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, 1,
669 user_id->AsU128(), 0); 672 user_id->AsU128(), 0);
670 673
671 const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); 674 const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
@@ -833,8 +836,8 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
833 FileSys::OpenMode::Read); 836 FileSys::OpenMode::Read);
834 837
835 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 838 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
836 {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 839 {}, vfsNandDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id,
837 program_id, user_id->AsU128(), 0); 840 user_id->AsU128(), 0);
838 return Common::Android::ToJString(env, user_save_data_path); 841 return Common::Android::ToJString(env, user_save_data_path);
839} 842}
840 843
diff --git a/src/android/app/src/main/jni/native_input.cpp b/src/android/app/src/main/jni/native_input.cpp
index 37a65f2b8..4935a4607 100644
--- a/src/android/app/src/main/jni/native_input.cpp
+++ b/src/android/app/src/main/jni/native_input.cpp
@@ -102,8 +102,50 @@ void ApplyControllerConfig(size_t player_index,
102 } 102 }
103} 103}
104 104
105std::vector<s32> GetSupportedStyles(int player_index) {
106 auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
107 const auto npad_style_set = hid_core.GetSupportedStyleTag();
108 std::vector<s32> supported_indexes;
109 if (npad_style_set.fullkey == 1) {
110 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Fullkey));
111 }
112
113 if (npad_style_set.joycon_dual == 1) {
114 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconDual));
115 }
116
117 if (npad_style_set.joycon_left == 1) {
118 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconLeft));
119 }
120
121 if (npad_style_set.joycon_right == 1) {
122 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconRight));
123 }
124
125 if (player_index == 0 && npad_style_set.handheld == 1) {
126 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Handheld));
127 }
128
129 if (npad_style_set.gamecube == 1) {
130 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::GameCube));
131 }
132
133 return supported_indexes;
134}
135
105void ConnectController(size_t player_index, bool connected) { 136void ConnectController(size_t player_index, bool connected) {
106 auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); 137 auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
138 ApplyControllerConfig(player_index, [&](Core::HID::EmulatedController* controller) {
139 auto supported_styles = GetSupportedStyles(player_index);
140 auto controller_style = controller->GetNpadStyleIndex(true);
141 auto style = std::find(supported_styles.begin(), supported_styles.end(),
142 static_cast<int>(controller_style));
143 if (style == supported_styles.end() && !supported_styles.empty()) {
144 controller->SetNpadStyleIndex(
145 static_cast<Core::HID::NpadStyleIndex>(supported_styles[0]));
146 }
147 });
148
107 if (player_index == 0) { 149 if (player_index == 0) {
108 auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); 150 auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
109 auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); 151 auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
@@ -522,36 +564,10 @@ jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonNameImpl(JNIEnv
522 564
523jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl( 565jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl(
524 JNIEnv* env, jobject j_obj, jint j_player_index) { 566 JNIEnv* env, jobject j_obj, jint j_player_index) {
525 auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); 567 auto supported_styles = GetSupportedStyles(j_player_index);
526 const auto npad_style_set = hid_core.GetSupportedStyleTag(); 568 jintArray j_supported_indexes = env->NewIntArray(supported_styles.size());
527 std::vector<s32> supported_indexes; 569 env->SetIntArrayRegion(j_supported_indexes, 0, supported_styles.size(),
528 if (npad_style_set.fullkey == 1) { 570 supported_styles.data());
529 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Fullkey));
530 }
531
532 if (npad_style_set.joycon_dual == 1) {
533 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconDual));
534 }
535
536 if (npad_style_set.joycon_left == 1) {
537 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconLeft));
538 }
539
540 if (npad_style_set.joycon_right == 1) {
541 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconRight));
542 }
543
544 if (j_player_index == 0 && npad_style_set.handheld == 1) {
545 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Handheld));
546 }
547
548 if (npad_style_set.gamecube == 1) {
549 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::GameCube));
550 }
551
552 jintArray j_supported_indexes = env->NewIntArray(supported_indexes.size());
553 env->SetIntArrayRegion(j_supported_indexes, 0, supported_indexes.size(),
554 supported_indexes.data());
555 return j_supported_indexes; 571 return j_supported_indexes;
556} 572}
557 573
diff --git a/src/common/settings.h b/src/common/settings.h
index aa054dc24..b2b071e7e 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -384,6 +384,12 @@ struct Values {
384 AstcRecompression::Bc3, 384 AstcRecompression::Bc3,
385 "astc_recompression", 385 "astc_recompression",
386 Category::RendererAdvanced}; 386 Category::RendererAdvanced};
387 SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
388 VramUsageMode::Conservative,
389 VramUsageMode::Conservative,
390 VramUsageMode::Aggressive,
391 "vram_usage_mode",
392 Category::RendererAdvanced};
387 SwitchableSetting<bool> async_presentation{linkage, 393 SwitchableSetting<bool> async_presentation{linkage,
388#ifdef ANDROID 394#ifdef ANDROID
389 true, 395 true,
diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h
index f42367e67..6e247e930 100644
--- a/src/common/settings_enums.h
+++ b/src/common/settings_enums.h
@@ -122,6 +122,8 @@ ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
122 122
123ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed); 123ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
124 124
125ENUM(VramUsageMode, Conservative, Aggressive);
126
125ENUM(RendererBackend, OpenGL, Vulkan, Null); 127ENUM(RendererBackend, OpenGL, Vulkan, Null);
126 128
127ENUM(ShaderBackend, Glsl, Glasm, SpirV); 129ENUM(ShaderBackend, Glsl, Glasm, SpirV);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c49560789..3400c512d 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -58,9 +58,14 @@ add_library(core STATIC
58 file_sys/fs_operate_range.h 58 file_sys/fs_operate_range.h
59 file_sys/fs_path.h 59 file_sys/fs_path.h
60 file_sys/fs_path_utility.h 60 file_sys/fs_path_utility.h
61 file_sys/fs_save_data_types.h
61 file_sys/fs_string_util.h 62 file_sys/fs_string_util.h
63 file_sys/fsa/fs_i_directory.h
64 file_sys/fsa/fs_i_file.h
65 file_sys/fsa/fs_i_filesystem.h
62 file_sys/fsmitm_romfsbuild.cpp 66 file_sys/fsmitm_romfsbuild.cpp
63 file_sys/fsmitm_romfsbuild.h 67 file_sys/fsmitm_romfsbuild.h
68 file_sys/fssrv/fssrv_sf_path.h
64 file_sys/fssystem/fs_i_storage.h 69 file_sys/fssystem/fs_i_storage.h
65 file_sys/fssystem/fs_types.h 70 file_sys/fssystem/fs_types.h
66 file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp 71 file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
@@ -605,6 +610,10 @@ add_library(core STATIC
605 hle/service/filesystem/fsp/fs_i_file.h 610 hle/service/filesystem/fsp/fs_i_file.h
606 hle/service/filesystem/fsp/fs_i_filesystem.cpp 611 hle/service/filesystem/fsp/fs_i_filesystem.cpp
607 hle/service/filesystem/fsp/fs_i_filesystem.h 612 hle/service/filesystem/fsp/fs_i_filesystem.h
613 hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
614 hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
615 hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
616 hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
608 hle/service/filesystem/fsp/fs_i_storage.cpp 617 hle/service/filesystem/fsp/fs_i_storage.cpp
609 hle/service/filesystem/fsp/fs_i_storage.h 618 hle/service/filesystem/fsp/fs_i_storage.h
610 hle/service/filesystem/fsp/fsp_ldr.cpp 619 hle/service/filesystem/fsp/fsp_ldr.cpp
@@ -613,7 +622,7 @@ add_library(core STATIC
613 hle/service/filesystem/fsp/fsp_pr.h 622 hle/service/filesystem/fsp/fsp_pr.h
614 hle/service/filesystem/fsp/fsp_srv.cpp 623 hle/service/filesystem/fsp/fsp_srv.cpp
615 hle/service/filesystem/fsp/fsp_srv.h 624 hle/service/filesystem/fsp/fsp_srv.h
616 hle/service/filesystem/fsp/fsp_util.h 625 hle/service/filesystem/fsp/fsp_types.h
617 hle/service/filesystem/romfs_controller.cpp 626 hle/service/filesystem/romfs_controller.cpp
618 hle/service/filesystem/romfs_controller.h 627 hle/service/filesystem/romfs_controller.h
619 hle/service/filesystem/save_data_controller.cpp 628 hle/service/filesystem/save_data_controller.cpp
@@ -901,6 +910,21 @@ add_library(core STATIC
901 hle/service/pm/pm.h 910 hle/service/pm/pm.h
902 hle/service/prepo/prepo.cpp 911 hle/service/prepo/prepo.cpp
903 hle/service/prepo/prepo.h 912 hle/service/prepo/prepo.h
913 hle/service/psc/ovln/ovln_types.h
914 hle/service/psc/ovln/receiver_service.cpp
915 hle/service/psc/ovln/receiver_service.h
916 hle/service/psc/ovln/receiver.cpp
917 hle/service/psc/ovln/receiver.h
918 hle/service/psc/ovln/sender_service.cpp
919 hle/service/psc/ovln/sender_service.h
920 hle/service/psc/ovln/sender.cpp
921 hle/service/psc/ovln/sender.h
922 hle/service/psc/pm_control.cpp
923 hle/service/psc/pm_control.h
924 hle/service/psc/pm_module.cpp
925 hle/service/psc/pm_module.h
926 hle/service/psc/pm_service.cpp
927 hle/service/psc/pm_service.h
904 hle/service/psc/psc.cpp 928 hle/service/psc/psc.cpp
905 hle/service/psc/psc.h 929 hle/service/psc/psc.h
906 hle/service/psc/time/alarms.cpp 930 hle/service/psc/time/alarms.cpp
diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc
index 37c1e69c3..f104d495b 100644
--- a/src/core/device_memory_manager.inc
+++ b/src/core/device_memory_manager.inc
@@ -522,13 +522,17 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
522 auto* memory_device_inter = registered_processes[asid.id]; 522 auto* memory_device_inter = registered_processes[asid.id];
523 const auto release_pending = [&] { 523 const auto release_pending = [&] {
524 if (uncache_bytes > 0) { 524 if (uncache_bytes > 0) {
525 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, 525 if (memory_device_inter != nullptr) {
526 uncache_bytes, false); 526 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
527 uncache_bytes, false);
528 }
527 uncache_bytes = 0; 529 uncache_bytes = 0;
528 } 530 }
529 if (cache_bytes > 0) { 531 if (cache_bytes > 0) {
530 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, 532 if (memory_device_inter != nullptr) {
531 cache_bytes, true); 533 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
534 cache_bytes, true);
535 }
532 cache_bytes = 0; 536 cache_bytes = 0;
533 } 537 }
534 }; 538 };
diff --git a/src/core/file_sys/fs_filesystem.h b/src/core/file_sys/fs_filesystem.h
index 7f237b7fa..329b5aca5 100644
--- a/src/core/file_sys/fs_filesystem.h
+++ b/src/core/file_sys/fs_filesystem.h
@@ -23,6 +23,8 @@ enum class OpenDirectoryMode : u64 {
23 File = (1 << 1), 23 File = (1 << 1),
24 24
25 All = (Directory | File), 25 All = (Directory | File),
26
27 NotRequireFileSize = (1ULL << 31),
26}; 28};
27DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode) 29DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
28 30
@@ -36,4 +38,29 @@ enum class CreateOption : u8 {
36 BigFile = (1 << 0), 38 BigFile = (1 << 0),
37}; 39};
38 40
41struct FileSystemAttribute {
42 u8 dir_entry_name_length_max_defined;
43 u8 file_entry_name_length_max_defined;
44 u8 dir_path_name_length_max_defined;
45 u8 file_path_name_length_max_defined;
46 INSERT_PADDING_BYTES_NOINIT(0x5);
47 u8 utf16_dir_entry_name_length_max_defined;
48 u8 utf16_file_entry_name_length_max_defined;
49 u8 utf16_dir_path_name_length_max_defined;
50 u8 utf16_file_path_name_length_max_defined;
51 INSERT_PADDING_BYTES_NOINIT(0x18);
52 s32 dir_entry_name_length_max;
53 s32 file_entry_name_length_max;
54 s32 dir_path_name_length_max;
55 s32 file_path_name_length_max;
56 INSERT_PADDING_WORDS_NOINIT(0x5);
57 s32 utf16_dir_entry_name_length_max;
58 s32 utf16_file_entry_name_length_max;
59 s32 utf16_dir_path_name_length_max;
60 s32 utf16_file_path_name_length_max;
61 INSERT_PADDING_WORDS_NOINIT(0x18);
62 INSERT_PADDING_WORDS_NOINIT(0x1);
63};
64static_assert(sizeof(FileSystemAttribute) == 0xC0, "FileSystemAttribute has incorrect size");
65
39} // namespace FileSys 66} // namespace FileSys
diff --git a/src/core/file_sys/fs_memory_management.h b/src/core/file_sys/fs_memory_management.h
index f03c6354b..080017c5d 100644
--- a/src/core/file_sys/fs_memory_management.h
+++ b/src/core/file_sys/fs_memory_management.h
@@ -10,7 +10,7 @@ namespace FileSys {
10 10
11constexpr size_t RequiredAlignment = alignof(u64); 11constexpr size_t RequiredAlignment = alignof(u64);
12 12
13void* AllocateUnsafe(size_t size) { 13inline void* AllocateUnsafe(size_t size) {
14 // Allocate 14 // Allocate
15 void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment}); 15 void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
16 16
@@ -21,16 +21,16 @@ void* AllocateUnsafe(size_t size) {
21 return ptr; 21 return ptr;
22} 22}
23 23
24void DeallocateUnsafe(void* ptr, size_t size) { 24inline void DeallocateUnsafe(void* ptr, size_t size) {
25 // Deallocate the pointer 25 // Deallocate the pointer
26 ::operator delete(ptr, std::align_val_t{RequiredAlignment}); 26 ::operator delete(ptr, std::align_val_t{RequiredAlignment});
27} 27}
28 28
29void* Allocate(size_t size) { 29inline void* Allocate(size_t size) {
30 return AllocateUnsafe(size); 30 return AllocateUnsafe(size);
31} 31}
32 32
33void Deallocate(void* ptr, size_t size) { 33inline void Deallocate(void* ptr, size_t size) {
34 // If the pointer is non-null, deallocate it 34 // If the pointer is non-null, deallocate it
35 if (ptr != nullptr) { 35 if (ptr != nullptr) {
36 DeallocateUnsafe(ptr, size); 36 DeallocateUnsafe(ptr, size);
diff --git a/src/core/file_sys/fs_path.h b/src/core/file_sys/fs_path.h
index 56ba08a6a..1566e82b9 100644
--- a/src/core/file_sys/fs_path.h
+++ b/src/core/file_sys/fs_path.h
@@ -381,7 +381,7 @@ public:
381 381
382 // Check that it's possible for us to remove a child 382 // Check that it's possible for us to remove a child
383 auto* p = m_write_buffer.Get(); 383 auto* p = m_write_buffer.Get();
384 s32 len = std::strlen(p); 384 s32 len = static_cast<s32>(std::strlen(p));
385 R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented); 385 R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
386 386
387 // Handle a trailing separator 387 // Handle a trailing separator
diff --git a/src/core/file_sys/fs_path_utility.h b/src/core/file_sys/fs_path_utility.h
index 5643141f9..cdfd8c772 100644
--- a/src/core/file_sys/fs_path_utility.h
+++ b/src/core/file_sys/fs_path_utility.h
@@ -426,9 +426,10 @@ public:
426 R_SUCCEED(); 426 R_SUCCEED();
427 } 427 }
428 428
429 static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size, 429 static constexpr Result Normalize(char* dst, size_t* out_len, const char* path,
430 bool is_windows_path, bool is_drive_relative_path, 430 size_t max_out_size, bool is_windows_path,
431 bool allow_all_characters = false) { 431 bool is_drive_relative_path,
432 bool allow_all_characters = false) {
432 // Use StringTraits names for remainder of scope 433 // Use StringTraits names for remainder of scope
433 using namespace StringTraits; 434 using namespace StringTraits;
434 435
diff --git a/src/core/file_sys/fs_save_data_types.h b/src/core/file_sys/fs_save_data_types.h
new file mode 100644
index 000000000..86a83d217
--- /dev/null
+++ b/src/core/file_sys/fs_save_data_types.h
@@ -0,0 +1,175 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <fmt/format.h>
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11namespace FileSys {
12
13using SaveDataId = u64;
14using SystemSaveDataId = u64;
15using SystemBcatSaveDataId = SystemSaveDataId;
16using ProgramId = u64;
17
18enum class SaveDataSpaceId : u8 {
19 System = 0,
20 User = 1,
21 SdSystem = 2,
22 Temporary = 3,
23 SdUser = 4,
24
25 ProperSystem = 100,
26 SafeMode = 101,
27};
28
29enum class SaveDataType : u8 {
30 System = 0,
31 Account = 1,
32 Bcat = 2,
33 Device = 3,
34 Temporary = 4,
35 Cache = 5,
36 SystemBcat = 6,
37};
38
39enum class SaveDataRank : u8 {
40 Primary = 0,
41 Secondary = 1,
42};
43
44struct SaveDataSize {
45 u64 normal;
46 u64 journal;
47};
48static_assert(sizeof(SaveDataSize) == 0x10, "SaveDataSize has invalid size.");
49
50using UserId = u128;
51static_assert(std::is_trivially_copyable_v<UserId>, "Data type must be trivially copyable.");
52static_assert(sizeof(UserId) == 0x10, "UserId has invalid size.");
53
54constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0;
55constexpr inline UserId InvalidUserId = {};
56
57enum class SaveDataFlags : u32 {
58 None = (0 << 0),
59 KeepAfterResettingSystemSaveData = (1 << 0),
60 KeepAfterRefurbishment = (1 << 1),
61 KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
62 NeedsSecureDelete = (1 << 3),
63};
64
65enum class SaveDataMetaType : u8 {
66 None = 0,
67 Thumbnail = 1,
68 ExtensionContext = 2,
69};
70
71struct SaveDataMetaInfo {
72 u32 size;
73 SaveDataMetaType type;
74 INSERT_PADDING_BYTES(0xB);
75};
76static_assert(std::is_trivially_copyable_v<SaveDataMetaInfo>,
77 "Data type must be trivially copyable.");
78static_assert(sizeof(SaveDataMetaInfo) == 0x10, "SaveDataMetaInfo has invalid size.");
79
80struct SaveDataCreationInfo {
81 s64 size;
82 s64 journal_size;
83 s64 block_size;
84 u64 owner_id;
85 u32 flags;
86 SaveDataSpaceId space_id;
87 bool pseudo;
88 INSERT_PADDING_BYTES(0x1A);
89};
90static_assert(std::is_trivially_copyable_v<SaveDataCreationInfo>,
91 "Data type must be trivially copyable.");
92static_assert(sizeof(SaveDataCreationInfo) == 0x40, "SaveDataCreationInfo has invalid size.");
93
94struct SaveDataAttribute {
95 ProgramId program_id;
96 UserId user_id;
97 SystemSaveDataId system_save_data_id;
98 SaveDataType type;
99 SaveDataRank rank;
100 u16 index;
101 INSERT_PADDING_BYTES(0x1C);
102
103 static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
104 SystemSaveDataId system_save_data_id, u16 index,
105 SaveDataRank rank) {
106 return {
107 .program_id = program_id,
108 .user_id = user_id,
109 .system_save_data_id = system_save_data_id,
110 .type = type,
111 .rank = rank,
112 .index = index,
113 };
114 }
115
116 static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
117 SystemSaveDataId system_save_data_id, u16 index) {
118 return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary);
119 }
120
121 static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
122 SystemSaveDataId system_save_data_id) {
123 return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary);
124 }
125
126 std::string DebugInfo() const {
127 return fmt::format(
128 "[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
129 "rank={}, index={}]",
130 program_id, user_id[1], user_id[0], system_save_data_id, static_cast<u8>(type),
131 static_cast<u8>(rank), index);
132 }
133};
134static_assert(sizeof(SaveDataAttribute) == 0x40);
135static_assert(std::is_trivially_destructible<SaveDataAttribute>::value);
136
137constexpr inline bool operator<(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
138 return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) <
139 std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank);
140}
141
142constexpr inline bool operator==(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
143 return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank,
144 lhs.index) == std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id,
145 rhs.type, rhs.rank, rhs.index);
146}
147
148constexpr inline bool operator!=(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
149 return !(lhs == rhs);
150}
151
152struct SaveDataExtraData {
153 SaveDataAttribute attr;
154 u64 owner_id;
155 s64 timestamp;
156 u32 flags;
157 INSERT_PADDING_BYTES(4);
158 s64 available_size;
159 s64 journal_size;
160 s64 commit_id;
161 INSERT_PADDING_BYTES(0x190);
162};
163static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has invalid size.");
164static_assert(std::is_trivially_copyable_v<SaveDataExtraData>,
165 "Data type must be trivially copyable.");
166
167struct HashSalt {
168 static constexpr size_t Size = 32;
169
170 std::array<u8, Size> value;
171};
172static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable.");
173static_assert(sizeof(HashSalt) == HashSalt::Size);
174
175} // namespace FileSys
diff --git a/src/core/file_sys/fs_string_util.h b/src/core/file_sys/fs_string_util.h
index 874e09054..c751a8f1a 100644
--- a/src/core/file_sys/fs_string_util.h
+++ b/src/core/file_sys/fs_string_util.h
@@ -20,6 +20,11 @@ constexpr int Strlen(const T* str) {
20} 20}
21 21
22template <typename T> 22template <typename T>
23constexpr int Strnlen(const T* str, std::size_t count) {
24 return Strnlen(str, static_cast<int>(count));
25}
26
27template <typename T>
23constexpr int Strnlen(const T* str, int count) { 28constexpr int Strnlen(const T* str, int count) {
24 ASSERT(str != nullptr); 29 ASSERT(str != nullptr);
25 ASSERT(count >= 0); 30 ASSERT(count >= 0);
@@ -33,6 +38,11 @@ constexpr int Strnlen(const T* str, int count) {
33} 38}
34 39
35template <typename T> 40template <typename T>
41constexpr int Strncmp(const T* lhs, const T* rhs, std::size_t count) {
42 return Strncmp(lhs, rhs, static_cast<int>(count));
43}
44
45template <typename T>
36constexpr int Strncmp(const T* lhs, const T* rhs, int count) { 46constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
37 ASSERT(lhs != nullptr); 47 ASSERT(lhs != nullptr);
38 ASSERT(rhs != nullptr); 48 ASSERT(rhs != nullptr);
@@ -52,6 +62,11 @@ constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
52} 62}
53 63
54template <typename T> 64template <typename T>
65static constexpr int Strlcpy(T* dst, const T* src, std::size_t count) {
66 return Strlcpy<T>(dst, src, static_cast<int>(count));
67}
68
69template <typename T>
55static constexpr int Strlcpy(T* dst, const T* src, int count) { 70static constexpr int Strlcpy(T* dst, const T* src, int count) {
56 ASSERT(dst != nullptr); 71 ASSERT(dst != nullptr);
57 ASSERT(src != nullptr); 72 ASSERT(src != nullptr);
diff --git a/src/core/file_sys/fsa/fs_i_directory.h b/src/core/file_sys/fsa/fs_i_directory.h
new file mode 100644
index 000000000..c8e895eab
--- /dev/null
+++ b/src/core/file_sys/fsa/fs_i_directory.h
@@ -0,0 +1,91 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/file_sys/errors.h"
8#include "core/file_sys/fs_directory.h"
9#include "core/file_sys/fs_file.h"
10#include "core/file_sys/fs_filesystem.h"
11#include "core/file_sys/savedata_factory.h"
12#include "core/file_sys/vfs/vfs.h"
13#include "core/hle/result.h"
14
15namespace FileSys::Fsa {
16
17class IDirectory {
18public:
19 explicit IDirectory(VirtualDir backend_, OpenDirectoryMode mode)
20 : backend(std::move(backend_)) {
21 // TODO(DarkLordZach): Verify that this is the correct behavior.
22 // Build entry index now to save time later.
23 if (True(mode & OpenDirectoryMode::Directory)) {
24 BuildEntryIndex(backend->GetSubdirectories(), DirectoryEntryType::Directory);
25 }
26 if (True(mode & OpenDirectoryMode::File)) {
27 BuildEntryIndex(backend->GetFiles(), DirectoryEntryType::File);
28 }
29 }
30 virtual ~IDirectory() {}
31
32 Result Read(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
33 R_UNLESS(out_count != nullptr, ResultNullptrArgument);
34 if (max_entries == 0) {
35 *out_count = 0;
36 R_SUCCEED();
37 }
38 R_UNLESS(out_entries != nullptr, ResultNullptrArgument);
39 R_UNLESS(max_entries > 0, ResultInvalidArgument);
40 R_RETURN(this->DoRead(out_count, out_entries, max_entries));
41 }
42
43 Result GetEntryCount(s64* out) {
44 R_UNLESS(out != nullptr, ResultNullptrArgument);
45 R_RETURN(this->DoGetEntryCount(out));
46 }
47
48private:
49 Result DoRead(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
50 const u64 actual_entries =
51 std::min(static_cast<u64>(max_entries), entries.size() - next_entry_index);
52 const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
53 const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
54 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
55
56 next_entry_index += actual_entries;
57 *out_count = actual_entries;
58
59 std::memcpy(out_entries, begin, range_size);
60
61 R_SUCCEED();
62 }
63
64 Result DoGetEntryCount(s64* out) {
65 *out = entries.size() - next_entry_index;
66 R_SUCCEED();
67 }
68
69 // TODO: Remove this when VFS is gone
70 template <typename T>
71 void BuildEntryIndex(const std::vector<T>& new_data, DirectoryEntryType type) {
72 entries.reserve(entries.size() + new_data.size());
73
74 for (const auto& new_entry : new_data) {
75 auto name = new_entry->GetName();
76
77 if (type == DirectoryEntryType::File && name == GetSaveDataSizeFileName()) {
78 continue;
79 }
80
81 entries.emplace_back(name, static_cast<s8>(type),
82 type == DirectoryEntryType::Directory ? 0 : new_entry->GetSize());
83 }
84 }
85
86 VirtualDir backend;
87 std::vector<DirectoryEntry> entries;
88 u64 next_entry_index = 0;
89};
90
91} // namespace FileSys::Fsa
diff --git a/src/core/file_sys/fsa/fs_i_file.h b/src/core/file_sys/fsa/fs_i_file.h
new file mode 100644
index 000000000..1188ae8ca
--- /dev/null
+++ b/src/core/file_sys/fsa/fs_i_file.h
@@ -0,0 +1,167 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/overflow.h"
7#include "core/file_sys/errors.h"
8#include "core/file_sys/fs_file.h"
9#include "core/file_sys/fs_filesystem.h"
10#include "core/file_sys/fs_operate_range.h"
11#include "core/file_sys/vfs/vfs.h"
12#include "core/file_sys/vfs/vfs_types.h"
13#include "core/hle/result.h"
14
15namespace FileSys::Fsa {
16
17class IFile {
18public:
19 explicit IFile(VirtualFile backend_) : backend(std::move(backend_)) {}
20 virtual ~IFile() {}
21
22 Result Read(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
23 // Check that we have an output pointer
24 R_UNLESS(out != nullptr, ResultNullptrArgument);
25
26 // If we have nothing to read, just succeed
27 if (size == 0) {
28 *out = 0;
29 R_SUCCEED();
30 }
31
32 // Check that the read is valid
33 R_UNLESS(buffer != nullptr, ResultNullptrArgument);
34 R_UNLESS(offset >= 0, ResultOutOfRange);
35 R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
36
37 // Do the read
38 R_RETURN(this->DoRead(out, offset, buffer, size, option));
39 }
40
41 Result Read(size_t* out, s64 offset, void* buffer, size_t size) {
42 R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None));
43 }
44
45 Result GetSize(s64* out) {
46 R_UNLESS(out != nullptr, ResultNullptrArgument);
47 R_RETURN(this->DoGetSize(out));
48 }
49
50 Result Flush() {
51 R_RETURN(this->DoFlush());
52 }
53
54 Result Write(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
55 // Handle the zero-size case
56 if (size == 0) {
57 if (option.HasFlushFlag()) {
58 R_TRY(this->Flush());
59 }
60 R_SUCCEED();
61 }
62
63 // Check the write is valid
64 R_UNLESS(buffer != nullptr, ResultNullptrArgument);
65 R_UNLESS(offset >= 0, ResultOutOfRange);
66 R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
67
68 R_RETURN(this->DoWrite(offset, buffer, size, option));
69 }
70
71 Result SetSize(s64 size) {
72 R_UNLESS(size >= 0, ResultOutOfRange);
73 R_RETURN(this->DoSetSize(size));
74 }
75
76 Result OperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
77 const void* src, size_t src_size) {
78 R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size));
79 }
80
81 Result OperateRange(OperationId op_id, s64 offset, s64 size) {
82 R_RETURN(this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0));
83 }
84
85protected:
86 Result DryRead(size_t* out, s64 offset, size_t size, const ReadOption& option,
87 OpenMode open_mode) {
88 // Check that we can read
89 R_UNLESS(static_cast<u32>(open_mode & OpenMode::Read) != 0, ResultReadNotPermitted);
90
91 // Get the file size, and validate our offset
92 s64 file_size = 0;
93 R_TRY(this->DoGetSize(std::addressof(file_size)));
94 R_UNLESS(offset <= file_size, ResultOutOfRange);
95
96 *out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size)));
97 R_SUCCEED();
98 }
99
100 Result DrySetSize(s64 size, OpenMode open_mode) {
101 // Check that we can write
102 R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
103 R_SUCCEED();
104 }
105
106 Result DryWrite(bool* out_append, s64 offset, size_t size, const WriteOption& option,
107 OpenMode open_mode) {
108 // Check that we can write
109 R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
110
111 // Get the file size
112 s64 file_size = 0;
113 R_TRY(this->DoGetSize(&file_size));
114
115 // Determine if we need to append
116 *out_append = false;
117 if (file_size < offset + static_cast<s64>(size)) {
118 R_UNLESS(static_cast<u32>(open_mode & OpenMode::AllowAppend) != 0,
119 ResultFileExtensionWithoutOpenModeAllowAppend);
120 *out_append = true;
121 }
122
123 R_SUCCEED();
124 }
125
126private:
127 Result DoRead(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
128 const auto read_size = backend->Read(static_cast<u8*>(buffer), size, offset);
129 *out = read_size;
130
131 R_SUCCEED();
132 }
133
134 Result DoGetSize(s64* out) {
135 *out = backend->GetSize();
136 R_SUCCEED();
137 }
138
139 Result DoFlush() {
140 // Exists for SDK compatibiltity -- No need to flush file.
141 R_SUCCEED();
142 }
143
144 Result DoWrite(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
145 const std::size_t written = backend->Write(static_cast<const u8*>(buffer), size, offset);
146
147 ASSERT_MSG(written == size,
148 "Could not write all bytes to file (requested={:016X}, actual={:016X}).", size,
149 written);
150
151 R_SUCCEED();
152 }
153
154 Result DoSetSize(s64 size) {
155 backend->Resize(size);
156 R_SUCCEED();
157 }
158
159 Result DoOperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
160 const void* src, size_t src_size) {
161 R_THROW(ResultNotImplemented);
162 }
163
164 VirtualFile backend;
165};
166
167} // namespace FileSys::Fsa
diff --git a/src/core/file_sys/fsa/fs_i_filesystem.h b/src/core/file_sys/fsa/fs_i_filesystem.h
new file mode 100644
index 000000000..8172190f4
--- /dev/null
+++ b/src/core/file_sys/fsa/fs_i_filesystem.h
@@ -0,0 +1,206 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/errors.h"
7#include "core/file_sys/fs_filesystem.h"
8#include "core/file_sys/fs_path.h"
9#include "core/file_sys/vfs/vfs_types.h"
10#include "core/hle/result.h"
11#include "core/hle/service/filesystem/filesystem.h"
12
13namespace FileSys::Fsa {
14
15class IFile;
16class IDirectory;
17
18enum class QueryId : u32 {
19 SetConcatenationFileAttribute = 0,
20 UpdateMac = 1,
21 IsSignedSystemPartitionOnSdCardValid = 2,
22 QueryUnpreparedFileInformation = 3,
23};
24
25class IFileSystem {
26public:
27 explicit IFileSystem(VirtualDir backend_) : backend{std::move(backend_)} {}
28 virtual ~IFileSystem() {}
29
30 Result CreateFile(const Path& path, s64 size, CreateOption option) {
31 R_UNLESS(size >= 0, ResultOutOfRange);
32 R_RETURN(this->DoCreateFile(path, size, static_cast<int>(option)));
33 }
34
35 Result CreateFile(const Path& path, s64 size) {
36 R_RETURN(this->CreateFile(path, size, CreateOption::None));
37 }
38
39 Result DeleteFile(const Path& path) {
40 R_RETURN(this->DoDeleteFile(path));
41 }
42
43 Result CreateDirectory(const Path& path) {
44 R_RETURN(this->DoCreateDirectory(path));
45 }
46
47 Result DeleteDirectory(const Path& path) {
48 R_RETURN(this->DoDeleteDirectory(path));
49 }
50
51 Result DeleteDirectoryRecursively(const Path& path) {
52 R_RETURN(this->DoDeleteDirectoryRecursively(path));
53 }
54
55 Result RenameFile(const Path& old_path, const Path& new_path) {
56 R_RETURN(this->DoRenameFile(old_path, new_path));
57 }
58
59 Result RenameDirectory(const Path& old_path, const Path& new_path) {
60 R_RETURN(this->DoRenameDirectory(old_path, new_path));
61 }
62
63 Result GetEntryType(DirectoryEntryType* out, const Path& path) {
64 R_RETURN(this->DoGetEntryType(out, path));
65 }
66
67 Result OpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
68 R_UNLESS(out_file != nullptr, ResultNullptrArgument);
69 R_UNLESS(static_cast<u32>(mode & OpenMode::ReadWrite) != 0, ResultInvalidOpenMode);
70 R_UNLESS(static_cast<u32>(mode & ~OpenMode::All) == 0, ResultInvalidOpenMode);
71 R_RETURN(this->DoOpenFile(out_file, path, mode));
72 }
73
74 Result OpenDirectory(VirtualDir* out_dir, const Path& path, OpenDirectoryMode mode) {
75 R_UNLESS(out_dir != nullptr, ResultNullptrArgument);
76 R_UNLESS(static_cast<u64>(mode & OpenDirectoryMode::All) != 0, ResultInvalidOpenMode);
77 R_UNLESS(static_cast<u64>(
78 mode & ~(OpenDirectoryMode::All | OpenDirectoryMode::NotRequireFileSize)) == 0,
79 ResultInvalidOpenMode);
80 R_RETURN(this->DoOpenDirectory(out_dir, path, mode));
81 }
82
83 Result Commit() {
84 R_RETURN(this->DoCommit());
85 }
86
87 Result GetFreeSpaceSize(s64* out, const Path& path) {
88 R_UNLESS(out != nullptr, ResultNullptrArgument);
89 R_RETURN(this->DoGetFreeSpaceSize(out, path));
90 }
91
92 Result GetTotalSpaceSize(s64* out, const Path& path) {
93 R_UNLESS(out != nullptr, ResultNullptrArgument);
94 R_RETURN(this->DoGetTotalSpaceSize(out, path));
95 }
96
97 Result CleanDirectoryRecursively(const Path& path) {
98 R_RETURN(this->DoCleanDirectoryRecursively(path));
99 }
100
101 Result GetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
102 R_UNLESS(out != nullptr, ResultNullptrArgument);
103 R_RETURN(this->DoGetFileTimeStampRaw(out, path));
104 }
105
106 Result QueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
107 const Path& path) {
108 R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path));
109 }
110
111 // These aren't accessible as commands
112 Result CommitProvisionally(s64 counter) {
113 R_RETURN(this->DoCommitProvisionally(counter));
114 }
115
116 Result Rollback() {
117 R_RETURN(this->DoRollback());
118 }
119
120 Result Flush() {
121 R_RETURN(this->DoFlush());
122 }
123
124private:
125 Result DoCreateFile(const Path& path, s64 size, int flags) {
126 R_RETURN(backend.CreateFile(path.GetString(), size));
127 }
128
129 Result DoDeleteFile(const Path& path) {
130 R_RETURN(backend.DeleteFile(path.GetString()));
131 }
132
133 Result DoCreateDirectory(const Path& path) {
134 R_RETURN(backend.CreateDirectory(path.GetString()));
135 }
136
137 Result DoDeleteDirectory(const Path& path) {
138 R_RETURN(backend.DeleteDirectory(path.GetString()));
139 }
140
141 Result DoDeleteDirectoryRecursively(const Path& path) {
142 R_RETURN(backend.DeleteDirectoryRecursively(path.GetString()));
143 }
144
145 Result DoRenameFile(const Path& old_path, const Path& new_path) {
146 R_RETURN(backend.RenameFile(old_path.GetString(), new_path.GetString()));
147 }
148
149 Result DoRenameDirectory(const Path& old_path, const Path& new_path) {
150 R_RETURN(backend.RenameDirectory(old_path.GetString(), new_path.GetString()));
151 }
152
153 Result DoGetEntryType(DirectoryEntryType* out, const Path& path) {
154 R_RETURN(backend.GetEntryType(out, path.GetString()));
155 }
156
157 Result DoOpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
158 R_RETURN(backend.OpenFile(out_file, path.GetString(), mode));
159 }
160
161 Result DoOpenDirectory(VirtualDir* out_directory, const Path& path, OpenDirectoryMode mode) {
162 R_RETURN(backend.OpenDirectory(out_directory, path.GetString()));
163 }
164
165 Result DoCommit() {
166 R_THROW(ResultNotImplemented);
167 }
168
169 Result DoGetFreeSpaceSize(s64* out, const Path& path) {
170 R_THROW(ResultNotImplemented);
171 }
172
173 Result DoGetTotalSpaceSize(s64* out, const Path& path) {
174 R_THROW(ResultNotImplemented);
175 }
176
177 Result DoCleanDirectoryRecursively(const Path& path) {
178 R_RETURN(backend.CleanDirectoryRecursively(path.GetString()));
179 }
180
181 Result DoGetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
182 R_RETURN(backend.GetFileTimeStampRaw(out, path.GetString()));
183 }
184
185 Result DoQueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
186 const Path& path) {
187 R_THROW(ResultNotImplemented);
188 }
189
190 // These aren't accessible as commands
191 Result DoCommitProvisionally(s64 counter) {
192 R_THROW(ResultNotImplemented);
193 }
194
195 Result DoRollback() {
196 R_THROW(ResultNotImplemented);
197 }
198
199 Result DoFlush() {
200 R_THROW(ResultNotImplemented);
201 }
202
203 Service::FileSystem::VfsDirectoryServiceWrapper backend;
204};
205
206} // namespace FileSys::Fsa
diff --git a/src/core/file_sys/fssrv/fssrv_sf_path.h b/src/core/file_sys/fssrv/fssrv_sf_path.h
new file mode 100644
index 000000000..a0c0b2dac
--- /dev/null
+++ b/src/core/file_sys/fssrv/fssrv_sf_path.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/fs_directory.h"
7
8namespace FileSys::Sf {
9
10struct Path {
11 char str[EntryNameLengthMax + 1];
12
13 static constexpr Path Encode(const char* p) {
14 Path path = {};
15 for (size_t i = 0; i < sizeof(path) - 1; i++) {
16 path.str[i] = p[i];
17 if (p[i] == '\x00') {
18 break;
19 }
20 }
21 return path;
22 }
23
24 static constexpr size_t GetPathLength(const Path& path) {
25 size_t len = 0;
26 for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) {
27 len++;
28 }
29 return len;
30 }
31};
32static_assert(std::is_trivially_copyable_v<Path>, "Path must be trivially copyable.");
33
34using FspPath = Path;
35
36} // namespace FileSys::Sf
diff --git a/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h b/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h
index f342efb57..0e83ca1b9 100644
--- a/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h
+++ b/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <mutex>
6#include <optional> 7#include <optional>
7 8
8#include "core/crypto/aes_util.h" 9#include "core/crypto/aes_util.h"
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index cbf411a20..106922e04 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -14,48 +14,11 @@ namespace FileSys {
14 14
15namespace { 15namespace {
16 16
17void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
18 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
19 if (meta.zero_1 != 0) {
20 LOG_WARNING(Service_FS,
21 "Possibly incorrect SaveDataAttribute, type is "
22 "SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
23 meta.zero_1);
24 }
25 if (meta.zero_2 != 0) {
26 LOG_WARNING(Service_FS,
27 "Possibly incorrect SaveDataAttribute, type is "
28 "SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
29 meta.zero_2);
30 }
31 if (meta.zero_3 != 0) {
32 LOG_WARNING(Service_FS,
33 "Possibly incorrect SaveDataAttribute, type is "
34 "SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
35 meta.zero_3);
36 }
37 }
38
39 if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
40 LOG_WARNING(Service_FS,
41 "Possibly incorrect SaveDataAttribute, type is SystemSaveData but title_id is "
42 "non-zero ({:016X}).",
43 meta.title_id);
44 }
45
46 if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) {
47 LOG_WARNING(Service_FS,
48 "Possibly incorrect SaveDataAttribute, type is DeviceSaveData but user_id is "
49 "non-zero ({:016X}{:016X})",
50 meta.user_id[1], meta.user_id[0]);
51 }
52}
53
54bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) { 17bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
55 return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage || 18 return attr.type == SaveDataType::Cache || attr.type == SaveDataType::Temporary ||
56 (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User 19 (space == SaveDataSpaceId::User && ///< Normal Save Data -- Current Title & User
57 (attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) && 20 (attr.type == SaveDataType::Account || attr.type == SaveDataType::Device) &&
58 attr.title_id == 0 && attr.save_id == 0); 21 attr.program_id == 0 && attr.system_save_data_id == 0);
59} 22}
60 23
61std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id, 24std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
@@ -63,7 +26,7 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
63 // Only detect nand user saves. 26 // Only detect nand user saves.
64 const auto space_id_path = [space_id]() -> std::string_view { 27 const auto space_id_path = [space_id]() -> std::string_view {
65 switch (space_id) { 28 switch (space_id) {
66 case SaveDataSpaceId::NandUser: 29 case SaveDataSpaceId::User:
67 return "/user/save"; 30 return "/user/save";
68 default: 31 default:
69 return ""; 32 return "";
@@ -79,9 +42,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
79 42
80 // Only detect account/device saves from the future location. 43 // Only detect account/device saves from the future location.
81 switch (type) { 44 switch (type) {
82 case SaveDataType::SaveData: 45 case SaveDataType::Account:
83 return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id); 46 return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
84 case SaveDataType::DeviceSaveData: 47 case SaveDataType::Device:
85 return fmt::format("{}/device/{:016X}/0", space_id_path, title_id); 48 return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
86 default: 49 default:
87 return ""; 50 return "";
@@ -90,13 +53,6 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
90 53
91} // Anonymous namespace 54} // Anonymous namespace
92 55
93std::string SaveDataAttribute::DebugInfo() const {
94 return fmt::format("[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
95 "rank={}, index={}]",
96 title_id, user_id[1], user_id[0], save_id, static_cast<u8>(type),
97 static_cast<u8>(rank), index);
98}
99
100SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_, 56SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
101 VirtualDir save_directory_) 57 VirtualDir save_directory_)
102 : system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} { 58 : system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} {
@@ -108,18 +64,16 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
108SaveDataFactory::~SaveDataFactory() = default; 64SaveDataFactory::~SaveDataFactory() = default;
109 65
110VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const { 66VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
111 PrintSaveDataAttributeWarnings(meta); 67 const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
112 68 meta.user_id, meta.system_save_data_id);
113 const auto save_directory =
114 GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
115 69
116 return dir->CreateDirectoryRelative(save_directory); 70 return dir->CreateDirectoryRelative(save_directory);
117} 71}
118 72
119VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const { 73VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
120 74
121 const auto save_directory = 75 const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
122 GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); 76 meta.user_id, meta.system_save_data_id);
123 77
124 auto out = dir->GetDirectoryRelative(save_directory); 78 auto out = dir->GetDirectoryRelative(save_directory);
125 79
@@ -136,11 +90,11 @@ VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) con
136 90
137std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { 91std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
138 switch (space) { 92 switch (space) {
139 case SaveDataSpaceId::NandSystem: 93 case SaveDataSpaceId::System:
140 return "/system/"; 94 return "/system/";
141 case SaveDataSpaceId::NandUser: 95 case SaveDataSpaceId::User:
142 return "/user/"; 96 return "/user/";
143 case SaveDataSpaceId::TemporaryStorage: 97 case SaveDataSpaceId::Temporary:
144 return "/temp/"; 98 return "/temp/";
145 default: 99 default:
146 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); 100 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
@@ -153,7 +107,7 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
153 u128 user_id, u64 save_id) { 107 u128 user_id, u64 save_id) {
154 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should 108 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
155 // be interpreted as the title id of the current process. 109 // be interpreted as the title id of the current process.
156 if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { 110 if (type == SaveDataType::Account || type == SaveDataType::Device) {
157 if (title_id == 0) { 111 if (title_id == 0) {
158 title_id = program_id; 112 title_id = program_id;
159 } 113 }
@@ -173,16 +127,16 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
173 std::string out = GetSaveDataSpaceIdPath(space); 127 std::string out = GetSaveDataSpaceIdPath(space);
174 128
175 switch (type) { 129 switch (type) {
176 case SaveDataType::SystemSaveData: 130 case SaveDataType::System:
177 return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); 131 return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
178 case SaveDataType::SaveData: 132 case SaveDataType::Account:
179 case SaveDataType::DeviceSaveData: 133 case SaveDataType::Device:
180 return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], 134 return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
181 title_id); 135 title_id);
182 case SaveDataType::TemporaryStorage: 136 case SaveDataType::Temporary:
183 return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], 137 return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
184 title_id); 138 title_id);
185 case SaveDataType::CacheStorage: 139 case SaveDataType::Cache:
186 return fmt::format("{}save/cache/{:016X}", out, title_id); 140 return fmt::format("{}save/cache/{:016X}", out, title_id);
187 default: 141 default:
188 ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type)); 142 ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
@@ -202,7 +156,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
202SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, 156SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
203 u128 user_id) const { 157 u128 user_id) const {
204 const auto path = 158 const auto path =
205 GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 159 GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
206 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); 160 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
207 161
208 const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName()); 162 const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
@@ -221,7 +175,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
221void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, 175void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
222 SaveDataSize new_value) const { 176 SaveDataSize new_value) const {
223 const auto path = 177 const auto path =
224 GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 178 GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
225 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); 179 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
226 180
227 const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName()); 181 const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index 5ab7e4d32..15dd4ec7d 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -7,6 +7,7 @@
7#include <string> 7#include <string>
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/fs_save_data_types.h"
10#include "core/file_sys/vfs/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
11#include "core/hle/result.h" 12#include "core/hle/result.h"
12 13
@@ -16,73 +17,6 @@ class System;
16 17
17namespace FileSys { 18namespace FileSys {
18 19
19enum class SaveDataSpaceId : u8 {
20 NandSystem = 0,
21 NandUser = 1,
22 SdCardSystem = 2,
23 TemporaryStorage = 3,
24 SdCardUser = 4,
25 ProperSystem = 100,
26 SafeMode = 101,
27};
28
29enum class SaveDataType : u8 {
30 SystemSaveData = 0,
31 SaveData = 1,
32 BcatDeliveryCacheStorage = 2,
33 DeviceSaveData = 3,
34 TemporaryStorage = 4,
35 CacheStorage = 5,
36 SystemBcat = 6,
37};
38
39enum class SaveDataRank : u8 {
40 Primary = 0,
41 Secondary = 1,
42};
43
44enum class SaveDataFlags : u32 {
45 None = (0 << 0),
46 KeepAfterResettingSystemSaveData = (1 << 0),
47 KeepAfterRefurbishment = (1 << 1),
48 KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
49 NeedsSecureDelete = (1 << 3),
50};
51
52struct SaveDataAttribute {
53 u64 title_id;
54 u128 user_id;
55 u64 save_id;
56 SaveDataType type;
57 SaveDataRank rank;
58 u16 index;
59 INSERT_PADDING_BYTES_NOINIT(4);
60 u64 zero_1;
61 u64 zero_2;
62 u64 zero_3;
63
64 std::string DebugInfo() const;
65};
66static_assert(sizeof(SaveDataAttribute) == 0x40, "SaveDataAttribute has incorrect size.");
67
68struct SaveDataExtraData {
69 SaveDataAttribute attr;
70 u64 owner_id;
71 s64 timestamp;
72 SaveDataFlags flags;
73 INSERT_PADDING_BYTES_NOINIT(4);
74 s64 available_size;
75 s64 journal_size;
76 s64 commit_id;
77 std::array<u8, 0x190> unused;
78};
79static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has incorrect size.");
80
81struct SaveDataSize {
82 u64 normal;
83 u64 journal;
84};
85
86constexpr const char* GetSaveDataSizeFileName() { 20constexpr const char* GetSaveDataSizeFileName() {
87 return ".yuzu_save_size"; 21 return ".yuzu_save_size";
88} 22}
diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp
index cb53b07e0..bfccb6b09 100644
--- a/src/core/hle/service/am/service/application_functions.cpp
+++ b/src/core/hle/service/am/service/application_functions.cpp
@@ -123,13 +123,13 @@ Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID use
123 LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString()); 123 LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
124 124
125 FileSys::SaveDataAttribute attribute{}; 125 FileSys::SaveDataAttribute attribute{};
126 attribute.title_id = m_applet->program_id; 126 attribute.program_id = m_applet->program_id;
127 attribute.user_id = user_id.AsU128(); 127 attribute.user_id = user_id.AsU128();
128 attribute.type = FileSys::SaveDataType::SaveData; 128 attribute.type = FileSys::SaveDataType::Account;
129 129
130 FileSys::VirtualDir save_data{}; 130 FileSys::VirtualDir save_data{};
131 R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( 131 R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
132 &save_data, FileSys::SaveDataSpaceId::NandUser, attribute)); 132 &save_data, FileSys::SaveDataSpaceId::User, attribute));
133 133
134 *out_size = 0; 134 *out_size = 0;
135 R_SUCCEED(); 135 R_SUCCEED();
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
index 39690018b..8483394d0 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
@@ -3,82 +3,34 @@
3 3
4#include "core/file_sys/fs_filesystem.h" 4#include "core/file_sys/fs_filesystem.h"
5#include "core/file_sys/savedata_factory.h" 5#include "core/file_sys/savedata_factory.h"
6#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/filesystem/fsp/fs_i_directory.h" 7#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
7#include "core/hle/service/ipc_helpers.h"
8 8
9namespace Service::FileSystem { 9namespace Service::FileSystem {
10 10
11template <typename T> 11IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
12static void BuildEntryIndex(std::vector<FileSys::DirectoryEntry>& entries,
13 const std::vector<T>& new_data, FileSys::DirectoryEntryType type) {
14 entries.reserve(entries.size() + new_data.size());
15
16 for (const auto& new_entry : new_data) {
17 auto name = new_entry->GetName();
18
19 if (type == FileSys::DirectoryEntryType::File &&
20 name == FileSys::GetSaveDataSizeFileName()) {
21 continue;
22 }
23
24 entries.emplace_back(name, static_cast<s8>(type),
25 type == FileSys::DirectoryEntryType::Directory ? 0
26 : new_entry->GetSize());
27 }
28}
29
30IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
31 FileSys::OpenDirectoryMode mode) 12 FileSys::OpenDirectoryMode mode)
32 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { 13 : ServiceFramework{system_, "IDirectory"},
14 backend(std::make_unique<FileSys::Fsa::IDirectory>(directory_, mode)) {
33 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
34 {0, &IDirectory::Read, "Read"}, 16 {0, D<&IDirectory::Read>, "Read"},
35 {1, &IDirectory::GetEntryCount, "GetEntryCount"}, 17 {1, D<&IDirectory::GetEntryCount>, "GetEntryCount"},
36 }; 18 };
37 RegisterHandlers(functions); 19 RegisterHandlers(functions);
38
39 // TODO(DarkLordZach): Verify that this is the correct behavior.
40 // Build entry index now to save time later.
41 if (True(mode & FileSys::OpenDirectoryMode::Directory)) {
42 BuildEntryIndex(entries, backend->GetSubdirectories(),
43 FileSys::DirectoryEntryType::Directory);
44 }
45 if (True(mode & FileSys::OpenDirectoryMode::File)) {
46 BuildEntryIndex(entries, backend->GetFiles(), FileSys::DirectoryEntryType::File);
47 }
48} 20}
49 21
50void IDirectory::Read(HLERequestContext& ctx) { 22Result IDirectory::Read(
23 Out<s64> out_count,
24 const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries) {
51 LOG_DEBUG(Service_FS, "called."); 25 LOG_DEBUG(Service_FS, "called.");
52 26
53 // Calculate how many entries we can fit in the output buffer 27 R_RETURN(backend->Read(out_count, out_entries.data(), out_entries.size()));
54 const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::DirectoryEntry>();
55
56 // Cap at total number of entries.
57 const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
58
59 // Determine data start and end
60 const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
61 const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
62 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
63
64 next_entry_index += actual_entries;
65
66 // Write the data to memory
67 ctx.WriteBuffer(begin, range_size);
68
69 IPC::ResponseBuilder rb{ctx, 4};
70 rb.Push(ResultSuccess);
71 rb.Push(actual_entries);
72} 28}
73 29
74void IDirectory::GetEntryCount(HLERequestContext& ctx) { 30Result IDirectory::GetEntryCount(Out<s64> out_count) {
75 LOG_DEBUG(Service_FS, "called"); 31 LOG_DEBUG(Service_FS, "called");
76 32
77 u64 count = entries.size() - next_entry_index; 33 R_RETURN(backend->GetEntryCount(out_count));
78
79 IPC::ResponseBuilder rb{ctx, 4};
80 rb.Push(ResultSuccess);
81 rb.Push(count);
82} 34}
83 35
84} // namespace Service::FileSystem 36} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.h b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
index 793ecfcd7..b6251f7fd 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_directory.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
@@ -3,7 +3,9 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/fsa/fs_i_directory.h"
6#include "core/file_sys/vfs/vfs.h" 7#include "core/file_sys/vfs/vfs.h"
8#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 9#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
9 11
@@ -15,16 +17,15 @@ namespace Service::FileSystem {
15 17
16class IDirectory final : public ServiceFramework<IDirectory> { 18class IDirectory final : public ServiceFramework<IDirectory> {
17public: 19public:
18 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, 20 explicit IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
19 FileSys::OpenDirectoryMode mode); 21 FileSys::OpenDirectoryMode mode);
20 22
21private: 23private:
22 FileSys::VirtualDir backend; 24 std::unique_ptr<FileSys::Fsa::IDirectory> backend;
23 std::vector<FileSys::DirectoryEntry> entries;
24 u64 next_entry_index = 0;
25 25
26 void Read(HLERequestContext& ctx); 26 Result Read(Out<s64> out_count,
27 void GetEntryCount(HLERequestContext& ctx); 27 const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries);
28 Result GetEntryCount(Out<s64> out_count);
28}; 29};
29 30
30} // namespace Service::FileSystem 31} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
index 9a18f6ec5..a355d46ae 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
@@ -2,126 +2,64 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/file_sys/errors.h" 4#include "core/file_sys/errors.h"
5#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_file.h" 6#include "core/hle/service/filesystem/fsp/fs_i_file.h"
6#include "core/hle/service/ipc_helpers.h"
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_) 10IFile::IFile(Core::System& system_, FileSys::VirtualFile file_)
11 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { 11 : ServiceFramework{system_, "IFile"}, backend{std::make_unique<FileSys::Fsa::IFile>(file_)} {
12 // clang-format off
12 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
13 {0, &IFile::Read, "Read"}, 14 {0, D<&IFile::Read>, "Read"},
14 {1, &IFile::Write, "Write"}, 15 {1, D<&IFile::Write>, "Write"},
15 {2, &IFile::Flush, "Flush"}, 16 {2, D<&IFile::Flush>, "Flush"},
16 {3, &IFile::SetSize, "SetSize"}, 17 {3, D<&IFile::SetSize>, "SetSize"},
17 {4, &IFile::GetSize, "GetSize"}, 18 {4, D<&IFile::GetSize>, "GetSize"},
18 {5, nullptr, "OperateRange"}, 19 {5, nullptr, "OperateRange"},
19 {6, nullptr, "OperateRangeWithBuffer"}, 20 {6, nullptr, "OperateRangeWithBuffer"},
20 }; 21 };
22 // clang-format on
21 RegisterHandlers(functions); 23 RegisterHandlers(functions);
22} 24}
23 25
24void IFile::Read(HLERequestContext& ctx) { 26Result IFile::Read(
25 IPC::RequestParser rp{ctx}; 27 FileSys::ReadOption option, Out<s64> out_size, s64 offset,
26 const u64 option = rp.Pop<u64>(); 28 const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_buffer,
27 const s64 offset = rp.Pop<s64>(); 29 s64 size) {
28 const s64 length = rp.Pop<s64>(); 30 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
29 31 size);
30 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
31
32 // Error checking
33 if (length < 0) {
34 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
35 IPC::ResponseBuilder rb{ctx, 2};
36 rb.Push(FileSys::ResultInvalidSize);
37 return;
38 }
39 if (offset < 0) {
40 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
41 IPC::ResponseBuilder rb{ctx, 2};
42 rb.Push(FileSys::ResultInvalidOffset);
43 return;
44 }
45 32
46 // Read the data from the Storage backend 33 // Read the data from the Storage backend
47 std::vector<u8> output = backend->ReadBytes(length, offset); 34 R_RETURN(
48 35 backend->Read(reinterpret_cast<size_t*>(out_size.Get()), offset, out_buffer.data(), size));
49 // Write the data to memory
50 ctx.WriteBuffer(output);
51
52 IPC::ResponseBuilder rb{ctx, 4};
53 rb.Push(ResultSuccess);
54 rb.Push(static_cast<u64>(output.size()));
55} 36}
56 37
57void IFile::Write(HLERequestContext& ctx) { 38Result IFile::Write(
58 IPC::RequestParser rp{ctx}; 39 const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
59 const u64 option = rp.Pop<u64>(); 40 FileSys::WriteOption option, s64 offset, s64 size) {
60 const s64 offset = rp.Pop<s64>(); 41 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
61 const s64 length = rp.Pop<s64>(); 42 size);
62
63 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
64
65 // Error checking
66 if (length < 0) {
67 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
68 IPC::ResponseBuilder rb{ctx, 2};
69 rb.Push(FileSys::ResultInvalidSize);
70 return;
71 }
72 if (offset < 0) {
73 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
74 IPC::ResponseBuilder rb{ctx, 2};
75 rb.Push(FileSys::ResultInvalidOffset);
76 return;
77 }
78
79 const auto data = ctx.ReadBuffer();
80 43
81 ASSERT_MSG(static_cast<s64>(data.size()) <= length, 44 R_RETURN(backend->Write(offset, buffer.data(), size, option));
82 "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
83 length, data.size());
84
85 // Write the data to the Storage backend
86 const auto write_size =
87 static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
88 const std::size_t written = backend->Write(data.data(), write_size, offset);
89
90 ASSERT_MSG(static_cast<s64>(written) == length,
91 "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
92 written);
93
94 IPC::ResponseBuilder rb{ctx, 2};
95 rb.Push(ResultSuccess);
96} 45}
97 46
98void IFile::Flush(HLERequestContext& ctx) { 47Result IFile::Flush() {
99 LOG_DEBUG(Service_FS, "called"); 48 LOG_DEBUG(Service_FS, "called");
100 49
101 // Exists for SDK compatibiltity -- No need to flush file. 50 R_RETURN(backend->Flush());
102
103 IPC::ResponseBuilder rb{ctx, 2};
104 rb.Push(ResultSuccess);
105} 51}
106 52
107void IFile::SetSize(HLERequestContext& ctx) { 53Result IFile::SetSize(s64 size) {
108 IPC::RequestParser rp{ctx};
109 const u64 size = rp.Pop<u64>();
110 LOG_DEBUG(Service_FS, "called, size={}", size); 54 LOG_DEBUG(Service_FS, "called, size={}", size);
111 55
112 backend->Resize(size); 56 R_RETURN(backend->SetSize(size));
113
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(ResultSuccess);
116} 57}
117 58
118void IFile::GetSize(HLERequestContext& ctx) { 59Result IFile::GetSize(Out<s64> out_size) {
119 const u64 size = backend->GetSize(); 60 LOG_DEBUG(Service_FS, "called");
120 LOG_DEBUG(Service_FS, "called, size={}", size);
121 61
122 IPC::ResponseBuilder rb{ctx, 4}; 62 R_RETURN(backend->GetSize(out_size));
123 rb.Push(ResultSuccess);
124 rb.Push<u64>(size);
125} 63}
126 64
127} // namespace Service::FileSystem 65} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.h b/src/core/hle/service/filesystem/fsp/fs_i_file.h
index 5e5430c67..e8599ee2f 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_file.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.h
@@ -3,6 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/fsa/fs_i_file.h"
7#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/filesystem/filesystem.h" 8#include "core/hle/service/filesystem/filesystem.h"
7#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
8 10
@@ -10,16 +12,21 @@ namespace Service::FileSystem {
10 12
11class IFile final : public ServiceFramework<IFile> { 13class IFile final : public ServiceFramework<IFile> {
12public: 14public:
13 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_); 15 explicit IFile(Core::System& system_, FileSys::VirtualFile file_);
14 16
15private: 17private:
16 FileSys::VirtualFile backend; 18 std::unique_ptr<FileSys::Fsa::IFile> backend;
17 19
18 void Read(HLERequestContext& ctx); 20 Result Read(FileSys::ReadOption option, Out<s64> out_size, s64 offset,
19 void Write(HLERequestContext& ctx); 21 const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure>
20 void Flush(HLERequestContext& ctx); 22 out_buffer,
21 void SetSize(HLERequestContext& ctx); 23 s64 size);
22 void GetSize(HLERequestContext& ctx); 24 Result Write(
25 const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
26 FileSys::WriteOption option, s64 offset, s64 size);
27 Result Flush();
28 Result SetSize(s64 size);
29 Result GetSize(Out<s64> out_size);
23}; 30};
24 31
25} // namespace Service::FileSystem 32} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
index efa394dd1..d881e144d 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
@@ -2,261 +2,172 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/string_util.h" 4#include "common/string_util.h"
5#include "core/file_sys/fssrv/fssrv_sf_path.h"
6#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_directory.h" 7#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
6#include "core/hle/service/filesystem/fsp/fs_i_file.h" 8#include "core/hle/service/filesystem/fsp/fs_i_file.h"
7#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" 9#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
8#include "core/hle/service/ipc_helpers.h"
9 10
10namespace Service::FileSystem { 11namespace Service::FileSystem {
11 12
12IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) 13IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_)
13 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( 14 : ServiceFramework{system_, "IFileSystem"}, backend{std::make_unique<FileSys::Fsa::IFileSystem>(
14 size_)} { 15 dir_)},
16 size_getter{std::move(size_getter_)} {
15 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
16 {0, &IFileSystem::CreateFile, "CreateFile"}, 18 {0, D<&IFileSystem::CreateFile>, "CreateFile"},
17 {1, &IFileSystem::DeleteFile, "DeleteFile"}, 19 {1, D<&IFileSystem::DeleteFile>, "DeleteFile"},
18 {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, 20 {2, D<&IFileSystem::CreateDirectory>, "CreateDirectory"},
19 {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, 21 {3, D<&IFileSystem::DeleteDirectory>, "DeleteDirectory"},
20 {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, 22 {4, D<&IFileSystem::DeleteDirectoryRecursively>, "DeleteDirectoryRecursively"},
21 {5, &IFileSystem::RenameFile, "RenameFile"}, 23 {5, D<&IFileSystem::RenameFile>, "RenameFile"},
22 {6, nullptr, "RenameDirectory"}, 24 {6, nullptr, "RenameDirectory"},
23 {7, &IFileSystem::GetEntryType, "GetEntryType"}, 25 {7, D<&IFileSystem::GetEntryType>, "GetEntryType"},
24 {8, &IFileSystem::OpenFile, "OpenFile"}, 26 {8, D<&IFileSystem::OpenFile>, "OpenFile"},
25 {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, 27 {9, D<&IFileSystem::OpenDirectory>, "OpenDirectory"},
26 {10, &IFileSystem::Commit, "Commit"}, 28 {10, D<&IFileSystem::Commit>, "Commit"},
27 {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"}, 29 {11, D<&IFileSystem::GetFreeSpaceSize>, "GetFreeSpaceSize"},
28 {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"}, 30 {12, D<&IFileSystem::GetTotalSpaceSize>, "GetTotalSpaceSize"},
29 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, 31 {13, D<&IFileSystem::CleanDirectoryRecursively>, "CleanDirectoryRecursively"},
30 {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, 32 {14, D<&IFileSystem::GetFileTimeStampRaw>, "GetFileTimeStampRaw"},
31 {15, nullptr, "QueryEntry"}, 33 {15, nullptr, "QueryEntry"},
32 {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, 34 {16, D<&IFileSystem::GetFileSystemAttribute>, "GetFileSystemAttribute"},
33 }; 35 };
34 RegisterHandlers(functions); 36 RegisterHandlers(functions);
35} 37}
36 38
37void IFileSystem::CreateFile(HLERequestContext& ctx) { 39Result IFileSystem::CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
38 IPC::RequestParser rp{ctx}; 40 s32 option, s64 size) {
41 LOG_DEBUG(Service_FS, "called. file={}, option=0x{:X}, size=0x{:08X}", path->str, option, size);
39 42
40 const auto file_buffer = ctx.ReadBuffer(); 43 R_RETURN(backend->CreateFile(FileSys::Path(path->str), size));
41 const std::string name = Common::StringFromBuffer(file_buffer);
42
43 const u64 file_mode = rp.Pop<u64>();
44 const u32 file_size = rp.Pop<u32>();
45
46 LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
47 file_size);
48
49 IPC::ResponseBuilder rb{ctx, 2};
50 rb.Push(backend.CreateFile(name, file_size));
51} 44}
52 45
53void IFileSystem::DeleteFile(HLERequestContext& ctx) { 46Result IFileSystem::DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
54 const auto file_buffer = ctx.ReadBuffer(); 47 LOG_DEBUG(Service_FS, "called. file={}", path->str);
55 const std::string name = Common::StringFromBuffer(file_buffer);
56 48
57 LOG_DEBUG(Service_FS, "called. file={}", name); 49 R_RETURN(backend->DeleteFile(FileSys::Path(path->str)));
58
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(backend.DeleteFile(name));
61} 50}
62 51
63void IFileSystem::CreateDirectory(HLERequestContext& ctx) { 52Result IFileSystem::CreateDirectory(
64 const auto file_buffer = ctx.ReadBuffer(); 53 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
65 const std::string name = Common::StringFromBuffer(file_buffer); 54 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
66
67 LOG_DEBUG(Service_FS, "called. directory={}", name);
68 55
69 IPC::ResponseBuilder rb{ctx, 2}; 56 R_RETURN(backend->CreateDirectory(FileSys::Path(path->str)));
70 rb.Push(backend.CreateDirectory(name));
71} 57}
72 58
73void IFileSystem::DeleteDirectory(HLERequestContext& ctx) { 59Result IFileSystem::DeleteDirectory(
74 const auto file_buffer = ctx.ReadBuffer(); 60 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
75 const std::string name = Common::StringFromBuffer(file_buffer); 61 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
76
77 LOG_DEBUG(Service_FS, "called. directory={}", name);
78 62
79 IPC::ResponseBuilder rb{ctx, 2}; 63 R_RETURN(backend->DeleteDirectory(FileSys::Path(path->str)));
80 rb.Push(backend.DeleteDirectory(name));
81} 64}
82 65
83void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) { 66Result IFileSystem::DeleteDirectoryRecursively(
84 const auto file_buffer = ctx.ReadBuffer(); 67 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
85 const std::string name = Common::StringFromBuffer(file_buffer); 68 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
86 69
87 LOG_DEBUG(Service_FS, "called. directory={}", name); 70 R_RETURN(backend->DeleteDirectoryRecursively(FileSys::Path(path->str)));
88
89 IPC::ResponseBuilder rb{ctx, 2};
90 rb.Push(backend.DeleteDirectoryRecursively(name));
91} 71}
92 72
93void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) { 73Result IFileSystem::CleanDirectoryRecursively(
94 const auto file_buffer = ctx.ReadBuffer(); 74 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
95 const std::string name = Common::StringFromBuffer(file_buffer); 75 LOG_DEBUG(Service_FS, "called. Directory: {}", path->str);
96
97 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
98 76
99 IPC::ResponseBuilder rb{ctx, 2}; 77 R_RETURN(backend->CleanDirectoryRecursively(FileSys::Path(path->str)));
100 rb.Push(backend.CleanDirectoryRecursively(name));
101} 78}
102 79
103void IFileSystem::RenameFile(HLERequestContext& ctx) { 80Result IFileSystem::RenameFile(
104 const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); 81 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
105 const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); 82 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path) {
106 83 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", old_path->str, new_path->str);
107 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
108 84
109 IPC::ResponseBuilder rb{ctx, 2}; 85 R_RETURN(backend->RenameFile(FileSys::Path(old_path->str), FileSys::Path(new_path->str)));
110 rb.Push(backend.RenameFile(src_name, dst_name));
111} 86}
112 87
113void IFileSystem::OpenFile(HLERequestContext& ctx) { 88Result IFileSystem::OpenFile(OutInterface<IFile> out_interface,
114 IPC::RequestParser rp{ctx}; 89 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
115 90 u32 mode) {
116 const auto file_buffer = ctx.ReadBuffer(); 91 LOG_DEBUG(Service_FS, "called. file={}, mode={}", path->str, mode);
117 const std::string name = Common::StringFromBuffer(file_buffer);
118
119 const auto mode = static_cast<FileSys::OpenMode>(rp.Pop<u32>());
120
121 LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
122 92
123 FileSys::VirtualFile vfs_file{}; 93 FileSys::VirtualFile vfs_file{};
124 auto result = backend.OpenFile(&vfs_file, name, mode); 94 R_TRY(backend->OpenFile(&vfs_file, FileSys::Path(path->str),
125 if (result != ResultSuccess) { 95 static_cast<FileSys::OpenMode>(mode)));
126 IPC::ResponseBuilder rb{ctx, 2};
127 rb.Push(result);
128 return;
129 }
130
131 auto file = std::make_shared<IFile>(system, vfs_file);
132
133 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
134 rb.Push(ResultSuccess);
135 rb.PushIpcInterface<IFile>(std::move(file));
136}
137
138void IFileSystem::OpenDirectory(HLERequestContext& ctx) {
139 IPC::RequestParser rp{ctx};
140 96
141 const auto file_buffer = ctx.ReadBuffer(); 97 *out_interface = std::make_shared<IFile>(system, vfs_file);
142 const std::string name = Common::StringFromBuffer(file_buffer); 98 R_SUCCEED();
143 const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>(); 99}
144 100
145 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); 101Result IFileSystem::OpenDirectory(OutInterface<IDirectory> out_interface,
102 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
103 u32 mode) {
104 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", path->str, mode);
146 105
147 FileSys::VirtualDir vfs_dir{}; 106 FileSys::VirtualDir vfs_dir{};
148 auto result = backend.OpenDirectory(&vfs_dir, name); 107 R_TRY(backend->OpenDirectory(&vfs_dir, FileSys::Path(path->str),
149 if (result != ResultSuccess) { 108 static_cast<FileSys::OpenDirectoryMode>(mode)));
150 IPC::ResponseBuilder rb{ctx, 2};
151 rb.Push(result);
152 return;
153 }
154
155 auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
156
157 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
158 rb.Push(ResultSuccess);
159 rb.PushIpcInterface<IDirectory>(std::move(directory));
160}
161 109
162void IFileSystem::GetEntryType(HLERequestContext& ctx) { 110 *out_interface = std::make_shared<IDirectory>(system, vfs_dir,
163 const auto file_buffer = ctx.ReadBuffer(); 111 static_cast<FileSys::OpenDirectoryMode>(mode));
164 const std::string name = Common::StringFromBuffer(file_buffer); 112 R_SUCCEED();
113}
165 114
166 LOG_DEBUG(Service_FS, "called. file={}", name); 115Result IFileSystem::GetEntryType(
116 Out<u32> out_type, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
117 LOG_DEBUG(Service_FS, "called. file={}", path->str);
167 118
168 FileSys::DirectoryEntryType vfs_entry_type{}; 119 FileSys::DirectoryEntryType vfs_entry_type{};
169 auto result = backend.GetEntryType(&vfs_entry_type, name); 120 R_TRY(backend->GetEntryType(&vfs_entry_type, FileSys::Path(path->str)));
170 if (result != ResultSuccess) { 121
171 IPC::ResponseBuilder rb{ctx, 2}; 122 *out_type = static_cast<u32>(vfs_entry_type);
172 rb.Push(result); 123 R_SUCCEED();
173 return;
174 }
175
176 IPC::ResponseBuilder rb{ctx, 3};
177 rb.Push(ResultSuccess);
178 rb.Push<u32>(static_cast<u32>(vfs_entry_type));
179} 124}
180 125
181void IFileSystem::Commit(HLERequestContext& ctx) { 126Result IFileSystem::Commit() {
182 LOG_WARNING(Service_FS, "(STUBBED) called"); 127 LOG_WARNING(Service_FS, "(STUBBED) called");
183 128
184 IPC::ResponseBuilder rb{ctx, 2}; 129 R_SUCCEED();
185 rb.Push(ResultSuccess);
186} 130}
187 131
188void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) { 132Result IFileSystem::GetFreeSpaceSize(
133 Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
189 LOG_DEBUG(Service_FS, "called"); 134 LOG_DEBUG(Service_FS, "called");
190 135
191 IPC::ResponseBuilder rb{ctx, 4}; 136 *out_size = size_getter.get_free_size();
192 rb.Push(ResultSuccess); 137 R_SUCCEED();
193 rb.Push(size.get_free_size());
194} 138}
195 139
196void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) { 140Result IFileSystem::GetTotalSpaceSize(
141 Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
197 LOG_DEBUG(Service_FS, "called"); 142 LOG_DEBUG(Service_FS, "called");
198 143
199 IPC::ResponseBuilder rb{ctx, 4}; 144 *out_size = size_getter.get_total_size();
200 rb.Push(ResultSuccess); 145 R_SUCCEED();
201 rb.Push(size.get_total_size());
202} 146}
203 147
204void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) { 148Result IFileSystem::GetFileTimeStampRaw(
205 const auto file_buffer = ctx.ReadBuffer(); 149 Out<FileSys::FileTimeStampRaw> out_timestamp,
206 const std::string name = Common::StringFromBuffer(file_buffer); 150 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
207 151 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", path->str);
208 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
209 152
210 FileSys::FileTimeStampRaw vfs_timestamp{}; 153 FileSys::FileTimeStampRaw vfs_timestamp{};
211 auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name); 154 R_TRY(backend->GetFileTimeStampRaw(&vfs_timestamp, FileSys::Path(path->str)));
212 if (result != ResultSuccess) { 155
213 IPC::ResponseBuilder rb{ctx, 2}; 156 *out_timestamp = vfs_timestamp;
214 rb.Push(result); 157 R_SUCCEED();
215 return;
216 }
217
218 IPC::ResponseBuilder rb{ctx, 10};
219 rb.Push(ResultSuccess);
220 rb.PushRaw(vfs_timestamp);
221} 158}
222 159
223void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) { 160Result IFileSystem::GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute) {
224 LOG_WARNING(Service_FS, "(STUBBED) called"); 161 LOG_WARNING(Service_FS, "(STUBBED) called");
225 162
226 struct FileSystemAttribute { 163 FileSys::FileSystemAttribute savedata_attribute{};
227 u8 dir_entry_name_length_max_defined;
228 u8 file_entry_name_length_max_defined;
229 u8 dir_path_name_length_max_defined;
230 u8 file_path_name_length_max_defined;
231 INSERT_PADDING_BYTES_NOINIT(0x5);
232 u8 utf16_dir_entry_name_length_max_defined;
233 u8 utf16_file_entry_name_length_max_defined;
234 u8 utf16_dir_path_name_length_max_defined;
235 u8 utf16_file_path_name_length_max_defined;
236 INSERT_PADDING_BYTES_NOINIT(0x18);
237 s32 dir_entry_name_length_max;
238 s32 file_entry_name_length_max;
239 s32 dir_path_name_length_max;
240 s32 file_path_name_length_max;
241 INSERT_PADDING_WORDS_NOINIT(0x5);
242 s32 utf16_dir_entry_name_length_max;
243 s32 utf16_file_entry_name_length_max;
244 s32 utf16_dir_path_name_length_max;
245 s32 utf16_file_path_name_length_max;
246 INSERT_PADDING_WORDS_NOINIT(0x18);
247 INSERT_PADDING_WORDS_NOINIT(0x1);
248 };
249 static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size");
250
251 FileSystemAttribute savedata_attribute{};
252 savedata_attribute.dir_entry_name_length_max_defined = true; 164 savedata_attribute.dir_entry_name_length_max_defined = true;
253 savedata_attribute.file_entry_name_length_max_defined = true; 165 savedata_attribute.file_entry_name_length_max_defined = true;
254 savedata_attribute.dir_entry_name_length_max = 0x40; 166 savedata_attribute.dir_entry_name_length_max = 0x40;
255 savedata_attribute.file_entry_name_length_max = 0x40; 167 savedata_attribute.file_entry_name_length_max = 0x40;
256 168
257 IPC::ResponseBuilder rb{ctx, 50}; 169 *out_attribute = savedata_attribute;
258 rb.Push(ResultSuccess); 170 R_SUCCEED();
259 rb.PushRaw(savedata_attribute);
260} 171}
261 172
262} // namespace Service::FileSystem 173} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
index b06b3ef0e..dd069f36f 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
@@ -3,36 +3,58 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/common_funcs.h"
7#include "core/file_sys/fs_filesystem.h"
8#include "core/file_sys/fsa/fs_i_filesystem.h"
6#include "core/file_sys/vfs/vfs.h" 9#include "core/file_sys/vfs/vfs.h"
10#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 11#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/filesystem/fsp/fsp_util.h" 12#include "core/hle/service/filesystem/fsp/fsp_types.h"
9#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
10 14
15namespace FileSys::Sf {
16struct Path;
17}
18
11namespace Service::FileSystem { 19namespace Service::FileSystem {
12 20
21class IFile;
22class IDirectory;
23
13class IFileSystem final : public ServiceFramework<IFileSystem> { 24class IFileSystem final : public ServiceFramework<IFileSystem> {
14public: 25public:
15 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_); 26 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_);
16 27
17 void CreateFile(HLERequestContext& ctx); 28 Result CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, s32 option,
18 void DeleteFile(HLERequestContext& ctx); 29 s64 size);
19 void CreateDirectory(HLERequestContext& ctx); 30 Result DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
20 void DeleteDirectory(HLERequestContext& ctx); 31 Result CreateDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
21 void DeleteDirectoryRecursively(HLERequestContext& ctx); 32 Result DeleteDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
22 void CleanDirectoryRecursively(HLERequestContext& ctx); 33 Result DeleteDirectoryRecursively(
23 void RenameFile(HLERequestContext& ctx); 34 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
24 void OpenFile(HLERequestContext& ctx); 35 Result CleanDirectoryRecursively(
25 void OpenDirectory(HLERequestContext& ctx); 36 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
26 void GetEntryType(HLERequestContext& ctx); 37 Result RenameFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
27 void Commit(HLERequestContext& ctx); 38 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path);
28 void GetFreeSpaceSize(HLERequestContext& ctx); 39 Result OpenFile(OutInterface<IFile> out_interface,
29 void GetTotalSpaceSize(HLERequestContext& ctx); 40 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, u32 mode);
30 void GetFileTimeStampRaw(HLERequestContext& ctx); 41 Result OpenDirectory(OutInterface<IDirectory> out_interface,
31 void GetFileSystemAttribute(HLERequestContext& ctx); 42 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
43 u32 mode);
44 Result GetEntryType(Out<u32> out_type,
45 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
46 Result Commit();
47 Result GetFreeSpaceSize(Out<s64> out_size,
48 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
49 Result GetTotalSpaceSize(Out<s64> out_size,
50 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
51 Result GetFileTimeStampRaw(Out<FileSys::FileTimeStampRaw> out_timestamp,
52 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
53 Result GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute);
32 54
33private: 55private:
34 VfsDirectoryServiceWrapper backend; 56 std::unique_ptr<FileSys::Fsa::IFileSystem> backend;
35 SizeGetter size; 57 SizeGetter size_getter;
36}; 58};
37 59
38} // namespace Service::FileSystem 60} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
new file mode 100644
index 000000000..626328234
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
6#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
7
8namespace Service::FileSystem {
9
10IMultiCommitManager::IMultiCommitManager(Core::System& system_)
11 : ServiceFramework{system_, "IMultiCommitManager"} {
12 static const FunctionInfo functions[] = {
13 {1, D<&IMultiCommitManager::Add>, "Add"},
14 {2, D<&IMultiCommitManager::Commit>, "Commit"},
15 };
16 RegisterHandlers(functions);
17}
18
19IMultiCommitManager::~IMultiCommitManager() = default;
20
21Result IMultiCommitManager::Add(std::shared_ptr<IFileSystem> filesystem) {
22 LOG_WARNING(Service_FS, "(STUBBED) called");
23
24 R_SUCCEED();
25}
26
27Result IMultiCommitManager::Commit() {
28 LOG_WARNING(Service_FS, "(STUBBED) called");
29
30 R_SUCCEED();
31}
32
33} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
new file mode 100644
index 000000000..8ebf7c7d9
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/vfs/vfs.h"
7#include "core/hle/service/service.h"
8
9namespace Service::FileSystem {
10
11class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
12public:
13 explicit IMultiCommitManager(Core::System& system_);
14 ~IMultiCommitManager() override;
15
16private:
17 Result Add(std::shared_ptr<IFileSystem> filesystem);
18 Result Commit();
19
20 FileSys::VirtualFile backend;
21};
22
23} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
new file mode 100644
index 000000000..ff823586b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
@@ -0,0 +1,161 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/hex_util.h"
5#include "core/file_sys/savedata_factory.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
8#include "core/hle/service/filesystem/save_data_controller.h"
9
10namespace Service::FileSystem {
11
12ISaveDataInfoReader::ISaveDataInfoReader(Core::System& system_,
13 std::shared_ptr<SaveDataController> save_data_controller_,
14 FileSys::SaveDataSpaceId space)
15 : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
16 save_data_controller_} {
17 static const FunctionInfo functions[] = {
18 {0, D<&ISaveDataInfoReader::ReadSaveDataInfo>, "ReadSaveDataInfo"},
19 };
20 RegisterHandlers(functions);
21
22 FindAllSaves(space);
23}
24
25ISaveDataInfoReader::~ISaveDataInfoReader() = default;
26
27static u64 stoull_be(std::string_view str) {
28 if (str.size() != 16) {
29 return 0;
30 }
31
32 const auto bytes = Common::HexStringToArray<0x8>(str);
33 u64 out{};
34 std::memcpy(&out, bytes.data(), sizeof(u64));
35
36 return Common::swap64(out);
37}
38
39Result ISaveDataInfoReader::ReadSaveDataInfo(
40 Out<u64> out_count, OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries) {
41 LOG_DEBUG(Service_FS, "called");
42
43 // Calculate how many entries we can fit in the output buffer
44 const u64 count_entries = out_entries.size();
45
46 // Cap at total number of entries.
47 const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
48
49 // Determine data start and end
50 const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
51 const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
52 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
53
54 next_entry_index += actual_entries;
55
56 // Write the data to memory
57 std::memcpy(out_entries.data(), begin, range_size);
58 *out_count = actual_entries;
59
60 R_SUCCEED();
61}
62
63void ISaveDataInfoReader::FindAllSaves(FileSys::SaveDataSpaceId space) {
64 FileSys::VirtualDir save_root{};
65 const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
66
67 if (result != ResultSuccess || save_root == nullptr) {
68 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
69 return;
70 }
71
72 for (const auto& type : save_root->GetSubdirectories()) {
73 if (type->GetName() == "save") {
74 FindNormalSaves(space, type);
75 } else if (space == FileSys::SaveDataSpaceId::Temporary) {
76 FindTemporaryStorageSaves(space, type);
77 }
78 }
79}
80
81void ISaveDataInfoReader::FindNormalSaves(FileSys::SaveDataSpaceId space,
82 const FileSys::VirtualDir& type) {
83 for (const auto& save_id : type->GetSubdirectories()) {
84 for (const auto& user_id : save_id->GetSubdirectories()) {
85 // Skip non user id subdirectories
86 if (user_id->GetName().size() != 0x20) {
87 continue;
88 }
89
90 const auto save_id_numeric = stoull_be(save_id->GetName());
91 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
92 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
93
94 if (save_id_numeric != 0) {
95 // System Save Data
96 info.emplace_back(SaveDataInfo{
97 0,
98 space,
99 FileSys::SaveDataType::System,
100 {},
101 user_id_numeric,
102 save_id_numeric,
103 0,
104 user_id->GetSize(),
105 {},
106 {},
107 });
108
109 continue;
110 }
111
112 for (const auto& title_id : user_id->GetSubdirectories()) {
113 const auto device = std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
114 [](u8 val) { return val == 0; });
115 info.emplace_back(SaveDataInfo{
116 0,
117 space,
118 device ? FileSys::SaveDataType::Device : FileSys::SaveDataType::Account,
119 {},
120 user_id_numeric,
121 save_id_numeric,
122 stoull_be(title_id->GetName()),
123 title_id->GetSize(),
124 {},
125 {},
126 });
127 }
128 }
129 }
130}
131
132void ISaveDataInfoReader::FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space,
133 const FileSys::VirtualDir& type) {
134 for (const auto& user_id : type->GetSubdirectories()) {
135 // Skip non user id subdirectories
136 if (user_id->GetName().size() != 0x20) {
137 continue;
138 }
139 for (const auto& title_id : user_id->GetSubdirectories()) {
140 if (!title_id->GetFiles().empty() || !title_id->GetSubdirectories().empty()) {
141 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
142 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
143
144 info.emplace_back(SaveDataInfo{
145 0,
146 space,
147 FileSys::SaveDataType::Temporary,
148 {},
149 user_id_numeric,
150 stoull_be(type->GetName()),
151 stoull_be(title_id->GetName()),
152 title_id->GetSize(),
153 {},
154 {},
155 });
156 }
157 }
158 }
159}
160
161} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
new file mode 100644
index 000000000..e45ad852b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
@@ -0,0 +1,50 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <vector>
7#include "common/common_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::FileSystem {
12
13class SaveDataController;
14
15class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
16public:
17 explicit ISaveDataInfoReader(Core::System& system_,
18 std::shared_ptr<SaveDataController> save_data_controller_,
19 FileSys::SaveDataSpaceId space);
20 ~ISaveDataInfoReader() override;
21
22 struct SaveDataInfo {
23 u64_le save_id_unknown;
24 FileSys::SaveDataSpaceId space;
25 FileSys::SaveDataType type;
26 INSERT_PADDING_BYTES(0x6);
27 std::array<u8, 0x10> user_id;
28 u64_le save_id;
29 u64_le title_id;
30 u64_le save_image_size;
31 u16_le index;
32 FileSys::SaveDataRank rank;
33 INSERT_PADDING_BYTES(0x25);
34 };
35 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
36
37 Result ReadSaveDataInfo(Out<u64> out_count,
38 OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries);
39
40private:
41 void FindAllSaves(FileSys::SaveDataSpaceId space);
42 void FindNormalSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
43 void FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
44
45 std::shared_ptr<SaveDataController> save_data_controller;
46 std::vector<SaveDataInfo> info;
47 u64 next_entry_index = 0;
48};
49
50} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
index 98223c1f9..213f19808 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
@@ -2,61 +2,44 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/file_sys/errors.h" 4#include "core/file_sys/errors.h"
5#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_storage.h" 6#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
6#include "core/hle/service/ipc_helpers.h"
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_) 10IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_)
11 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { 11 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, &IStorage::Read, "Read"}, 13 {0, D<&IStorage::Read>, "Read"},
14 {1, nullptr, "Write"}, 14 {1, nullptr, "Write"},
15 {2, nullptr, "Flush"}, 15 {2, nullptr, "Flush"},
16 {3, nullptr, "SetSize"}, 16 {3, nullptr, "SetSize"},
17 {4, &IStorage::GetSize, "GetSize"}, 17 {4, D<&IStorage::GetSize>, "GetSize"},
18 {5, nullptr, "OperateRange"}, 18 {5, nullptr, "OperateRange"},
19 }; 19 };
20 RegisterHandlers(functions); 20 RegisterHandlers(functions);
21} 21}
22 22
23void IStorage::Read(HLERequestContext& ctx) { 23Result IStorage::Read(
24 IPC::RequestParser rp{ctx}; 24 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
25 const s64 offset = rp.Pop<s64>(); 25 s64 offset, s64 length) {
26 const s64 length = rp.Pop<s64>();
27
28 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); 26 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
29 27
30 // Error checking 28 R_UNLESS(length >= 0, FileSys::ResultInvalidSize);
31 if (length < 0) { 29 R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset);
32 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
33 IPC::ResponseBuilder rb{ctx, 2};
34 rb.Push(FileSys::ResultInvalidSize);
35 return;
36 }
37 if (offset < 0) {
38 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
39 IPC::ResponseBuilder rb{ctx, 2};
40 rb.Push(FileSys::ResultInvalidOffset);
41 return;
42 }
43 30
44 // Read the data from the Storage backend 31 // Read the data from the Storage backend
45 std::vector<u8> output = backend->ReadBytes(length, offset); 32 backend->Read(out_bytes.data(), length, offset);
46 // Write the data to memory
47 ctx.WriteBuffer(output);
48 33
49 IPC::ResponseBuilder rb{ctx, 2}; 34 R_SUCCEED();
50 rb.Push(ResultSuccess);
51} 35}
52 36
53void IStorage::GetSize(HLERequestContext& ctx) { 37Result IStorage::GetSize(Out<u64> out_size) {
54 const u64 size = backend->GetSize(); 38 *out_size = backend->GetSize();
55 LOG_DEBUG(Service_FS, "called, size={}", size); 39
40 LOG_DEBUG(Service_FS, "called, size={}", *out_size);
56 41
57 IPC::ResponseBuilder rb{ctx, 4}; 42 R_SUCCEED();
58 rb.Push(ResultSuccess);
59 rb.Push<u64>(size);
60} 43}
61 44
62} // namespace Service::FileSystem 45} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
index cb5bebcc9..74d879386 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_storage.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/vfs/vfs.h" 6#include "core/file_sys/vfs/vfs.h"
7#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 8#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
9 10
@@ -16,8 +17,10 @@ public:
16private: 17private:
17 FileSys::VirtualFile backend; 18 FileSys::VirtualFile backend;
18 19
19 void Read(HLERequestContext& ctx); 20 Result Read(
20 void GetSize(HLERequestContext& ctx); 21 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
22 s64 offset, s64 length);
23 Result GetSize(Out<u64> out_size);
21}; 24};
22 25
23} // namespace Service::FileSystem 26} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
index 2d49f30c8..fc67a4713 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
@@ -27,8 +27,11 @@
27#include "core/file_sys/system_archive/system_archive.h" 27#include "core/file_sys/system_archive/system_archive.h"
28#include "core/file_sys/vfs/vfs.h" 28#include "core/file_sys/vfs/vfs.h"
29#include "core/hle/result.h" 29#include "core/hle/result.h"
30#include "core/hle/service/cmif_serialization.h"
30#include "core/hle/service/filesystem/filesystem.h" 31#include "core/hle/service/filesystem/filesystem.h"
31#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" 32#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
33#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
34#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
32#include "core/hle/service/filesystem/fsp/fs_i_storage.h" 35#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
33#include "core/hle/service/filesystem/fsp/fsp_srv.h" 36#include "core/hle/service/filesystem/fsp/fsp_srv.h"
34#include "core/hle/service/filesystem/romfs_controller.h" 37#include "core/hle/service/filesystem/romfs_controller.h"
@@ -39,182 +42,6 @@
39#include "core/reporter.h" 42#include "core/reporter.h"
40 43
41namespace Service::FileSystem { 44namespace Service::FileSystem {
42enum class FileSystemProxyType : u8 {
43 Code = 0,
44 Rom = 1,
45 Logo = 2,
46 Control = 3,
47 Manual = 4,
48 Meta = 5,
49 Data = 6,
50 Package = 7,
51 RegisteredUpdate = 8,
52};
53
54class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
55public:
56 explicit ISaveDataInfoReader(Core::System& system_,
57 std::shared_ptr<SaveDataController> save_data_controller_,
58 FileSys::SaveDataSpaceId space)
59 : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
60 save_data_controller_} {
61 static const FunctionInfo functions[] = {
62 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
63 };
64 RegisterHandlers(functions);
65
66 FindAllSaves(space);
67 }
68
69 void ReadSaveDataInfo(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_FS, "called");
71
72 // Calculate how many entries we can fit in the output buffer
73 const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>();
74
75 // Cap at total number of entries.
76 const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
77
78 // Determine data start and end
79 const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
80 const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
81 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
82
83 next_entry_index += actual_entries;
84
85 // Write the data to memory
86 ctx.WriteBuffer(begin, range_size);
87
88 IPC::ResponseBuilder rb{ctx, 4};
89 rb.Push(ResultSuccess);
90 rb.Push<u64>(actual_entries);
91 }
92
93private:
94 static u64 stoull_be(std::string_view str) {
95 if (str.size() != 16)
96 return 0;
97
98 const auto bytes = Common::HexStringToArray<0x8>(str);
99 u64 out{};
100 std::memcpy(&out, bytes.data(), sizeof(u64));
101
102 return Common::swap64(out);
103 }
104
105 void FindAllSaves(FileSys::SaveDataSpaceId space) {
106 FileSys::VirtualDir save_root{};
107 const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
108
109 if (result != ResultSuccess || save_root == nullptr) {
110 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
111 return;
112 }
113
114 for (const auto& type : save_root->GetSubdirectories()) {
115 if (type->GetName() == "save") {
116 for (const auto& save_id : type->GetSubdirectories()) {
117 for (const auto& user_id : save_id->GetSubdirectories()) {
118 // Skip non user id subdirectories
119 if (user_id->GetName().size() != 0x20) {
120 continue;
121 }
122
123 const auto save_id_numeric = stoull_be(save_id->GetName());
124 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
125 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
126
127 if (save_id_numeric != 0) {
128 // System Save Data
129 info.emplace_back(SaveDataInfo{
130 0,
131 space,
132 FileSys::SaveDataType::SystemSaveData,
133 {},
134 user_id_numeric,
135 save_id_numeric,
136 0,
137 user_id->GetSize(),
138 {},
139 {},
140 });
141
142 continue;
143 }
144
145 for (const auto& title_id : user_id->GetSubdirectories()) {
146 const auto device =
147 std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
148 [](u8 val) { return val == 0; });
149 info.emplace_back(SaveDataInfo{
150 0,
151 space,
152 device ? FileSys::SaveDataType::DeviceSaveData
153 : FileSys::SaveDataType::SaveData,
154 {},
155 user_id_numeric,
156 save_id_numeric,
157 stoull_be(title_id->GetName()),
158 title_id->GetSize(),
159 {},
160 {},
161 });
162 }
163 }
164 }
165 } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
166 // Temporary Storage
167 for (const auto& user_id : type->GetSubdirectories()) {
168 // Skip non user id subdirectories
169 if (user_id->GetName().size() != 0x20) {
170 continue;
171 }
172 for (const auto& title_id : user_id->GetSubdirectories()) {
173 if (!title_id->GetFiles().empty() ||
174 !title_id->GetSubdirectories().empty()) {
175 auto user_id_numeric =
176 Common::HexStringToArray<0x10>(user_id->GetName());
177 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
178
179 info.emplace_back(SaveDataInfo{
180 0,
181 space,
182 FileSys::SaveDataType::TemporaryStorage,
183 {},
184 user_id_numeric,
185 stoull_be(type->GetName()),
186 stoull_be(title_id->GetName()),
187 title_id->GetSize(),
188 {},
189 {},
190 });
191 }
192 }
193 }
194 }
195 }
196 }
197
198 struct SaveDataInfo {
199 u64_le save_id_unknown;
200 FileSys::SaveDataSpaceId space;
201 FileSys::SaveDataType type;
202 INSERT_PADDING_BYTES(0x6);
203 std::array<u8, 0x10> user_id;
204 u64_le save_id;
205 u64_le title_id;
206 u64_le save_image_size;
207 u16_le index;
208 FileSys::SaveDataRank rank;
209 INSERT_PADDING_BYTES(0x25);
210 };
211 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
212
213 ProcessId process_id = 0;
214 std::shared_ptr<SaveDataController> save_data_controller;
215 std::vector<SaveDataInfo> info;
216 u64 next_entry_index = 0;
217};
218 45
219FSP_SRV::FSP_SRV(Core::System& system_) 46FSP_SRV::FSP_SRV(Core::System& system_)
220 : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()}, 47 : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
@@ -222,20 +49,20 @@ FSP_SRV::FSP_SRV(Core::System& system_)
222 // clang-format off 49 // clang-format off
223 static const FunctionInfo functions[] = { 50 static const FunctionInfo functions[] = {
224 {0, nullptr, "OpenFileSystem"}, 51 {0, nullptr, "OpenFileSystem"},
225 {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"}, 52 {1, D<&FSP_SRV::SetCurrentProcess>, "SetCurrentProcess"},
226 {2, nullptr, "OpenDataFileSystemByCurrentProcess"}, 53 {2, nullptr, "OpenDataFileSystemByCurrentProcess"},
227 {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"}, 54 {7, D<&FSP_SRV::OpenFileSystemWithPatch>, "OpenFileSystemWithPatch"},
228 {8, nullptr, "OpenFileSystemWithId"}, 55 {8, nullptr, "OpenFileSystemWithId"},
229 {9, nullptr, "OpenDataFileSystemByApplicationId"}, 56 {9, nullptr, "OpenDataFileSystemByApplicationId"},
230 {11, nullptr, "OpenBisFileSystem"}, 57 {11, nullptr, "OpenBisFileSystem"},
231 {12, nullptr, "OpenBisStorage"}, 58 {12, nullptr, "OpenBisStorage"},
232 {13, nullptr, "InvalidateBisCache"}, 59 {13, nullptr, "InvalidateBisCache"},
233 {17, nullptr, "OpenHostFileSystem"}, 60 {17, nullptr, "OpenHostFileSystem"},
234 {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"}, 61 {18, D<&FSP_SRV::OpenSdCardFileSystem>, "OpenSdCardFileSystem"},
235 {19, nullptr, "FormatSdCardFileSystem"}, 62 {19, nullptr, "FormatSdCardFileSystem"},
236 {21, nullptr, "DeleteSaveDataFileSystem"}, 63 {21, nullptr, "DeleteSaveDataFileSystem"},
237 {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"}, 64 {22, D<&FSP_SRV::CreateSaveDataFileSystem>, "CreateSaveDataFileSystem"},
238 {23, &FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId, "CreateSaveDataFileSystemBySystemSaveDataId"}, 65 {23, D<&FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId>, "CreateSaveDataFileSystemBySystemSaveDataId"},
239 {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"}, 66 {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
240 {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"}, 67 {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
241 {26, nullptr, "FormatSdCardDryRun"}, 68 {26, nullptr, "FormatSdCardDryRun"},
@@ -245,26 +72,26 @@ FSP_SRV::FSP_SRV(Core::System& system_)
245 {31, nullptr, "OpenGameCardFileSystem"}, 72 {31, nullptr, "OpenGameCardFileSystem"},
246 {32, nullptr, "ExtendSaveDataFileSystem"}, 73 {32, nullptr, "ExtendSaveDataFileSystem"},
247 {33, nullptr, "DeleteCacheStorage"}, 74 {33, nullptr, "DeleteCacheStorage"},
248 {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"}, 75 {34, D<&FSP_SRV::GetCacheStorageSize>, "GetCacheStorageSize"},
249 {35, nullptr, "CreateSaveDataFileSystemByHashSalt"}, 76 {35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
250 {36, nullptr, "OpenHostFileSystemWithOption"}, 77 {36, nullptr, "OpenHostFileSystemWithOption"},
251 {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"}, 78 {51, D<&FSP_SRV::OpenSaveDataFileSystem>, "OpenSaveDataFileSystem"},
252 {52, &FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId, "OpenSaveDataFileSystemBySystemSaveDataId"}, 79 {52, D<&FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId>, "OpenSaveDataFileSystemBySystemSaveDataId"},
253 {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"}, 80 {53, D<&FSP_SRV::OpenReadOnlySaveDataFileSystem>, "OpenReadOnlySaveDataFileSystem"},
254 {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"}, 81 {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
255 {58, nullptr, "ReadSaveDataFileSystemExtraData"}, 82 {58, nullptr, "ReadSaveDataFileSystemExtraData"},
256 {59, nullptr, "WriteSaveDataFileSystemExtraData"}, 83 {59, nullptr, "WriteSaveDataFileSystemExtraData"},
257 {60, nullptr, "OpenSaveDataInfoReader"}, 84 {60, nullptr, "OpenSaveDataInfoReader"},
258 {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, 85 {61, D<&FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId>, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
259 {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"}, 86 {62, D<&FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage>, "OpenSaveDataInfoReaderOnlyCacheStorage"},
260 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, 87 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
261 {65, nullptr, "UpdateSaveDataMacForDebug"}, 88 {65, nullptr, "UpdateSaveDataMacForDebug"},
262 {66, nullptr, "WriteSaveDataFileSystemExtraData2"}, 89 {66, nullptr, "WriteSaveDataFileSystemExtraData2"},
263 {67, nullptr, "FindSaveDataWithFilter"}, 90 {67, nullptr, "FindSaveDataWithFilter"},
264 {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"}, 91 {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
265 {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"}, 92 {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
266 {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"}, 93 {70, D<&FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute>, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
267 {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"}, 94 {71, D<&FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute>, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
268 {80, nullptr, "OpenSaveDataMetaFile"}, 95 {80, nullptr, "OpenSaveDataMetaFile"},
269 {81, nullptr, "OpenSaveDataTransferManager"}, 96 {81, nullptr, "OpenSaveDataTransferManager"},
270 {82, nullptr, "OpenSaveDataTransferManagerVersion2"}, 97 {82, nullptr, "OpenSaveDataTransferManagerVersion2"},
@@ -279,12 +106,12 @@ FSP_SRV::FSP_SRV(Core::System& system_)
279 {110, nullptr, "OpenContentStorageFileSystem"}, 106 {110, nullptr, "OpenContentStorageFileSystem"},
280 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, 107 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
281 {130, nullptr, "OpenCustomStorageFileSystem"}, 108 {130, nullptr, "OpenCustomStorageFileSystem"},
282 {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, 109 {200, D<&FSP_SRV::OpenDataStorageByCurrentProcess>, "OpenDataStorageByCurrentProcess"},
283 {201, nullptr, "OpenDataStorageByProgramId"}, 110 {201, nullptr, "OpenDataStorageByProgramId"},
284 {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, 111 {202, D<&FSP_SRV::OpenDataStorageByDataId>, "OpenDataStorageByDataId"},
285 {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, 112 {203, D<&FSP_SRV::OpenPatchDataStorageByCurrentProcess>, "OpenPatchDataStorageByCurrentProcess"},
286 {204, nullptr, "OpenDataFileSystemByProgramIndex"}, 113 {204, nullptr, "OpenDataFileSystemByProgramIndex"},
287 {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"}, 114 {205, D<&FSP_SRV::OpenDataStorageWithProgramIndex>, "OpenDataStorageWithProgramIndex"},
288 {206, nullptr, "OpenDataStorageByPath"}, 115 {206, nullptr, "OpenDataStorageByPath"},
289 {400, nullptr, "OpenDeviceOperator"}, 116 {400, nullptr, "OpenDeviceOperator"},
290 {500, nullptr, "OpenSdCardDetectionEventNotifier"}, 117 {500, nullptr, "OpenSdCardDetectionEventNotifier"},
@@ -324,25 +151,25 @@ FSP_SRV::FSP_SRV(Core::System& system_)
324 {1000, nullptr, "SetBisRootForHost"}, 151 {1000, nullptr, "SetBisRootForHost"},
325 {1001, nullptr, "SetSaveDataSize"}, 152 {1001, nullptr, "SetSaveDataSize"},
326 {1002, nullptr, "SetSaveDataRootPath"}, 153 {1002, nullptr, "SetSaveDataRootPath"},
327 {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"}, 154 {1003, D<&FSP_SRV::DisableAutoSaveDataCreation>, "DisableAutoSaveDataCreation"},
328 {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"}, 155 {1004, D<&FSP_SRV::SetGlobalAccessLogMode>, "SetGlobalAccessLogMode"},
329 {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, 156 {1005, D<&FSP_SRV::GetGlobalAccessLogMode>, "GetGlobalAccessLogMode"},
330 {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"}, 157 {1006, D<&FSP_SRV::OutputAccessLogToSdCard>, "OutputAccessLogToSdCard"},
331 {1007, nullptr, "RegisterUpdatePartition"}, 158 {1007, nullptr, "RegisterUpdatePartition"},
332 {1008, nullptr, "OpenRegisteredUpdatePartition"}, 159 {1008, nullptr, "OpenRegisteredUpdatePartition"},
333 {1009, nullptr, "GetAndClearMemoryReportInfo"}, 160 {1009, nullptr, "GetAndClearMemoryReportInfo"},
334 {1010, nullptr, "SetDataStorageRedirectTarget"}, 161 {1010, nullptr, "SetDataStorageRedirectTarget"},
335 {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"}, 162 {1011, D<&FSP_SRV::GetProgramIndexForAccessLog>, "GetProgramIndexForAccessLog"},
336 {1012, nullptr, "GetFsStackUsage"}, 163 {1012, nullptr, "GetFsStackUsage"},
337 {1013, nullptr, "UnsetSaveDataRootPath"}, 164 {1013, nullptr, "UnsetSaveDataRootPath"},
338 {1014, nullptr, "OutputMultiProgramTagAccessLog"}, 165 {1014, nullptr, "OutputMultiProgramTagAccessLog"},
339 {1016, &FSP_SRV::FlushAccessLogOnSdCard, "FlushAccessLogOnSdCard"}, 166 {1016, D<&FSP_SRV::FlushAccessLogOnSdCard>, "FlushAccessLogOnSdCard"},
340 {1017, nullptr, "OutputApplicationInfoAccessLog"}, 167 {1017, nullptr, "OutputApplicationInfoAccessLog"},
341 {1018, nullptr, "SetDebugOption"}, 168 {1018, nullptr, "SetDebugOption"},
342 {1019, nullptr, "UnsetDebugOption"}, 169 {1019, nullptr, "UnsetDebugOption"},
343 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, 170 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
344 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, 171 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
345 {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, 172 {1200, D<&FSP_SRV::OpenMultiCommitManager>, "OpenMultiCommitManager"},
346 {1300, nullptr, "OpenBisWiper"}, 173 {1300, nullptr, "OpenBisWiper"},
347 }; 174 };
348 // clang-format on 175 // clang-format on
@@ -355,234 +182,177 @@ FSP_SRV::FSP_SRV(Core::System& system_)
355 182
356FSP_SRV::~FSP_SRV() = default; 183FSP_SRV::~FSP_SRV() = default;
357 184
358void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { 185Result FSP_SRV::SetCurrentProcess(ClientProcessId pid) {
359 current_process_id = ctx.GetPID(); 186 current_process_id = *pid;
360 187
361 LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id); 188 LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
362 189
363 const auto res = 190 R_RETURN(
364 fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id); 191 fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id));
365
366 IPC::ResponseBuilder rb{ctx, 2};
367 rb.Push(res);
368} 192}
369 193
370void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { 194Result FSP_SRV::OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
371 IPC::RequestParser rp{ctx}; 195 FileSystemProxyType type, u64 open_program_id) {
372 196 LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", type,
373 struct InputParameters { 197 open_program_id);
374 FileSystemProxyType type;
375 u64 program_id;
376 };
377 static_assert(sizeof(InputParameters) == 0x10, "InputParameters has wrong size");
378
379 const auto params = rp.PopRaw<InputParameters>();
380 LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", params.type,
381 params.program_id);
382 198
383 // FIXME: many issues with this 199 // FIXME: many issues with this
384 ASSERT(params.type == FileSystemProxyType::Manual); 200 ASSERT(type == FileSystemProxyType::Manual);
385 const auto manual_romfs = romfs_controller->OpenPatchedRomFS( 201 const auto manual_romfs = romfs_controller->OpenPatchedRomFS(
386 params.program_id, FileSys::ContentRecordType::HtmlDocument); 202 open_program_id, FileSys::ContentRecordType::HtmlDocument);
387 203
388 ASSERT(manual_romfs != nullptr); 204 ASSERT(manual_romfs != nullptr);
389 205
390 const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs); 206 const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs);
391 ASSERT(extracted_romfs != nullptr); 207 ASSERT(extracted_romfs != nullptr);
392 208
393 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 209 *out_interface = std::make_shared<IFileSystem>(
394 rb.Push(ResultSuccess); 210 system, extracted_romfs, SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser));
395 rb.PushIpcInterface<IFileSystem>(system, extracted_romfs, 211
396 SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser)); 212 R_SUCCEED();
397} 213}
398 214
399void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) { 215Result FSP_SRV::OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface) {
400 LOG_DEBUG(Service_FS, "called"); 216 LOG_DEBUG(Service_FS, "called");
401 217
402 FileSys::VirtualDir sdmc_dir{}; 218 FileSys::VirtualDir sdmc_dir{};
403 fsc.OpenSDMC(&sdmc_dir); 219 fsc.OpenSDMC(&sdmc_dir);
404 220
405 auto filesystem = std::make_shared<IFileSystem>( 221 *out_interface = std::make_shared<IFileSystem>(
406 system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); 222 system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
407 223
408 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 224 R_SUCCEED();
409 rb.Push(ResultSuccess);
410 rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
411} 225}
412 226
413void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) { 227Result FSP_SRV::CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
414 IPC::RequestParser rp{ctx}; 228 FileSys::SaveDataAttribute save_struct, u128 uid) {
415
416 auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
417 [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
418 u128 uid = rp.PopRaw<u128>();
419
420 LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(), 229 LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
421 uid[1], uid[0]); 230 uid[1], uid[0]);
422 231
423 FileSys::VirtualDir save_data_dir{}; 232 FileSys::VirtualDir save_data_dir{};
424 save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, 233 R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::User,
425 save_struct); 234 save_struct));
426
427 IPC::ResponseBuilder rb{ctx, 2};
428 rb.Push(ResultSuccess);
429} 235}
430 236
431void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { 237Result FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(
432 IPC::RequestParser rp{ctx}; 238 FileSys::SaveDataCreationInfo save_create_struct, FileSys::SaveDataAttribute save_struct) {
433
434 auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
435 [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
436
437 LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo()); 239 LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
438 240
439 FileSys::VirtualDir save_data_dir{}; 241 FileSys::VirtualDir save_data_dir{};
440 save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, 242 R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::System,
441 save_struct); 243 save_struct));
442
443 IPC::ResponseBuilder rb{ctx, 2};
444 rb.Push(ResultSuccess);
445} 244}
446 245
447void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) { 246Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
448 IPC::RequestParser rp{ctx}; 247 FileSys::SaveDataSpaceId space_id,
449 248 FileSys::SaveDataAttribute attribute) {
450 struct Parameters {
451 FileSys::SaveDataSpaceId space_id;
452 FileSys::SaveDataAttribute attribute;
453 };
454
455 const auto parameters = rp.PopRaw<Parameters>();
456
457 LOG_INFO(Service_FS, "called."); 249 LOG_INFO(Service_FS, "called.");
458 250
459 FileSys::VirtualDir dir{}; 251 FileSys::VirtualDir dir{};
460 auto result = 252 R_TRY(save_data_controller->OpenSaveData(&dir, space_id, attribute));
461 save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute);
462 if (result != ResultSuccess) {
463 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
464 rb.Push(FileSys::ResultTargetNotFound);
465 return;
466 }
467 253
468 FileSys::StorageId id{}; 254 FileSys::StorageId id{};
469 switch (parameters.space_id) { 255 switch (space_id) {
470 case FileSys::SaveDataSpaceId::NandUser: 256 case FileSys::SaveDataSpaceId::User:
471 id = FileSys::StorageId::NandUser; 257 id = FileSys::StorageId::NandUser;
472 break; 258 break;
473 case FileSys::SaveDataSpaceId::SdCardSystem: 259 case FileSys::SaveDataSpaceId::SdSystem:
474 case FileSys::SaveDataSpaceId::SdCardUser: 260 case FileSys::SaveDataSpaceId::SdUser:
475 id = FileSys::StorageId::SdCard; 261 id = FileSys::StorageId::SdCard;
476 break; 262 break;
477 case FileSys::SaveDataSpaceId::NandSystem: 263 case FileSys::SaveDataSpaceId::System:
478 id = FileSys::StorageId::NandSystem; 264 id = FileSys::StorageId::NandSystem;
479 break; 265 break;
480 case FileSys::SaveDataSpaceId::TemporaryStorage: 266 case FileSys::SaveDataSpaceId::Temporary:
481 case FileSys::SaveDataSpaceId::ProperSystem: 267 case FileSys::SaveDataSpaceId::ProperSystem:
482 case FileSys::SaveDataSpaceId::SafeMode: 268 case FileSys::SaveDataSpaceId::SafeMode:
483 ASSERT(false); 269 ASSERT(false);
484 } 270 }
485 271
486 auto filesystem = 272 *out_interface =
487 std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id)); 273 std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
488 274
489 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 275 R_SUCCEED();
490 rb.Push(ResultSuccess);
491 rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
492} 276}
493 277
494void FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { 278Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
279 FileSys::SaveDataSpaceId space_id,
280 FileSys::SaveDataAttribute attribute) {
495 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); 281 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
496 OpenSaveDataFileSystem(ctx); 282 R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
497} 283}
498 284
499void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) { 285Result FSP_SRV::OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
286 FileSys::SaveDataSpaceId space_id,
287 FileSys::SaveDataAttribute attribute) {
500 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); 288 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
501 OpenSaveDataFileSystem(ctx); 289 R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
502} 290}
503 291
504void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) { 292Result FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(
505 IPC::RequestParser rp{ctx}; 293 OutInterface<ISaveDataInfoReader> out_interface, FileSys::SaveDataSpaceId space) {
506 const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
507 LOG_INFO(Service_FS, "called, space={}", space); 294 LOG_INFO(Service_FS, "called, space={}", space);
508 295
509 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 296 *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space);
510 rb.Push(ResultSuccess); 297
511 rb.PushIpcInterface<ISaveDataInfoReader>( 298 R_SUCCEED();
512 std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space));
513} 299}
514 300
515void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { 301Result FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(
302 OutInterface<ISaveDataInfoReader> out_interface) {
516 LOG_WARNING(Service_FS, "(STUBBED) called"); 303 LOG_WARNING(Service_FS, "(STUBBED) called");
517 304
518 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 305 *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller,
519 rb.Push(ResultSuccess); 306 FileSys::SaveDataSpaceId::Temporary);
520 rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller, 307
521 FileSys::SaveDataSpaceId::TemporaryStorage); 308 R_SUCCEED();
522} 309}
523 310
524void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { 311Result FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute() {
525 LOG_WARNING(Service_FS, "(STUBBED) called."); 312 LOG_WARNING(Service_FS, "(STUBBED) called.");
526 313
527 IPC::ResponseBuilder rb{ctx, 2}; 314 R_SUCCEED();
528 rb.Push(ResultSuccess);
529} 315}
530 316
531void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) { 317Result FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
532 IPC::RequestParser rp{ctx}; 318 FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
533 319 InBuffer<BufferAttr_HipcMapAlias> mask_buffer, OutBuffer<BufferAttr_HipcMapAlias> out_buffer) {
534 struct Parameters {
535 FileSys::SaveDataSpaceId space_id;
536 FileSys::SaveDataAttribute attribute;
537 };
538
539 const auto parameters = rp.PopRaw<Parameters>();
540 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData 320 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
541 constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None); 321 // In an earlier version of the code, this was returned as an out argument, but this is not
322 // correct
323 [[maybe_unused]] constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
542 324
543 LOG_WARNING(Service_FS, 325 LOG_WARNING(Service_FS,
544 "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n" 326 "(STUBBED) called, flags={}, space_id={}, attribute.program_id={:016X}\n"
545 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n" 327 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
546 "attribute.type={}, attribute.rank={}, attribute.index={}", 328 "attribute.type={}, attribute.rank={}, attribute.index={}",
547 flags, parameters.space_id, parameters.attribute.title_id, 329 flags, space_id, attribute.program_id, attribute.user_id[1], attribute.user_id[0],
548 parameters.attribute.user_id[1], parameters.attribute.user_id[0], 330 attribute.system_save_data_id, attribute.type, attribute.rank, attribute.index);
549 parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank, 331
550 parameters.attribute.index); 332 R_SUCCEED();
551
552 IPC::ResponseBuilder rb{ctx, 3};
553 rb.Push(ResultSuccess);
554 rb.Push(flags);
555} 333}
556 334
557void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) { 335Result FSP_SRV::OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface) {
558 LOG_DEBUG(Service_FS, "called"); 336 LOG_DEBUG(Service_FS, "called");
559 337
560 if (!romfs) { 338 if (!romfs) {
561 auto current_romfs = romfs_controller->OpenRomFSCurrentProcess(); 339 auto current_romfs = romfs_controller->OpenRomFSCurrentProcess();
562 if (!current_romfs) { 340 if (!current_romfs) {
563 // TODO (bunnei): Find the right error code to use here 341 // TODO (bunnei): Find the right error code to use here
564 LOG_CRITICAL(Service_FS, "no file system interface available!"); 342 LOG_CRITICAL(Service_FS, "No file system interface available!");
565 IPC::ResponseBuilder rb{ctx, 2}; 343 R_RETURN(ResultUnknown);
566 rb.Push(ResultUnknown);
567 return;
568 } 344 }
569 345
570 romfs = current_romfs; 346 romfs = current_romfs;
571 } 347 }
572 348
573 auto storage = std::make_shared<IStorage>(system, romfs); 349 *out_interface = std::make_shared<IStorage>(system, romfs);
574 350
575 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 351 R_SUCCEED();
576 rb.Push(ResultSuccess);
577 rb.PushIpcInterface<IStorage>(std::move(storage));
578} 352}
579 353
580void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) { 354Result FSP_SRV::OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
581 IPC::RequestParser rp{ctx}; 355 FileSys::StorageId storage_id, u32 unknown, u64 title_id) {
582 const auto storage_id = rp.PopRaw<FileSys::StorageId>();
583 const auto unknown = rp.PopRaw<u32>();
584 const auto title_id = rp.PopRaw<u64>();
585
586 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", 356 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
587 storage_id, unknown, title_id); 357 storage_id, unknown, title_id);
588 358
@@ -592,19 +362,15 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
592 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); 362 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
593 363
594 if (archive != nullptr) { 364 if (archive != nullptr) {
595 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 365 *out_interface = std::make_shared<IStorage>(system, archive);
596 rb.Push(ResultSuccess); 366 R_SUCCEED();
597 rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
598 return;
599 } 367 }
600 368
601 // TODO(DarkLordZach): Find the right error code to use here 369 // TODO(DarkLordZach): Find the right error code to use here
602 LOG_ERROR(Service_FS, 370 LOG_ERROR(Service_FS,
603 "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, 371 "Could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
604 storage_id); 372 storage_id);
605 IPC::ResponseBuilder rb{ctx, 2}; 373 R_RETURN(ResultUnknown);
606 rb.Push(ResultUnknown);
607 return;
608 } 374 }
609 375
610 const FileSys::PatchManager pm{title_id, fsc, content_provider}; 376 const FileSys::PatchManager pm{title_id, fsc, content_provider};
@@ -614,28 +380,20 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
614 auto storage = std::make_shared<IStorage>( 380 auto storage = std::make_shared<IStorage>(
615 system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data)); 381 system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
616 382
617 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 383 *out_interface = std::move(storage);
618 rb.Push(ResultSuccess); 384 R_SUCCEED();
619 rb.PushIpcInterface<IStorage>(std::move(storage));
620} 385}
621 386
622void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) { 387Result FSP_SRV::OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
623 IPC::RequestParser rp{ctx}; 388 FileSys::StorageId storage_id, u64 title_id) {
624 389 LOG_WARNING(Service_FS, "(STUBBED) called with storage_id={:02X}, title_id={:016X}", storage_id,
625 const auto storage_id = rp.PopRaw<FileSys::StorageId>(); 390 title_id);
626 const auto title_id = rp.PopRaw<u64>();
627 391
628 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id); 392 R_RETURN(FileSys::ResultTargetNotFound);
629
630 IPC::ResponseBuilder rb{ctx, 2};
631 rb.Push(FileSys::ResultTargetNotFound);
632} 393}
633 394
634void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { 395Result FSP_SRV::OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface,
635 IPC::RequestParser rp{ctx}; 396 u8 program_index) {
636
637 const auto program_index = rp.PopRaw<u8>();
638
639 LOG_DEBUG(Service_FS, "called, program_index={}", program_index); 397 LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
640 398
641 auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex( 399 auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex(
@@ -643,123 +401,80 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
643 401
644 if (!patched_romfs) { 402 if (!patched_romfs) {
645 // TODO: Find the right error code to use here 403 // TODO: Find the right error code to use here
646 LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index); 404 LOG_ERROR(Service_FS, "Could not open storage with program_index={}", program_index);
647 405 R_RETURN(ResultUnknown);
648 IPC::ResponseBuilder rb{ctx, 2};
649 rb.Push(ResultUnknown);
650 return;
651 } 406 }
652 407
653 auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs)); 408 *out_interface = std::make_shared<IStorage>(system, std::move(patched_romfs));
654 409
655 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 410 R_SUCCEED();
656 rb.Push(ResultSuccess);
657 rb.PushIpcInterface<IStorage>(std::move(storage));
658} 411}
659 412
660void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) { 413Result FSP_SRV::DisableAutoSaveDataCreation() {
661 LOG_DEBUG(Service_FS, "called"); 414 LOG_DEBUG(Service_FS, "called");
662 415
663 save_data_controller->SetAutoCreate(false); 416 save_data_controller->SetAutoCreate(false);
664 417
665 IPC::ResponseBuilder rb{ctx, 2}; 418 R_SUCCEED();
666 rb.Push(ResultSuccess);
667} 419}
668 420
669void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) { 421Result FSP_SRV::SetGlobalAccessLogMode(AccessLogMode access_log_mode_) {
670 IPC::RequestParser rp{ctx}; 422 LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode_);
671 access_log_mode = rp.PopEnum<AccessLogMode>();
672 423
673 LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode); 424 access_log_mode = access_log_mode_;
674 425
675 IPC::ResponseBuilder rb{ctx, 2}; 426 R_SUCCEED();
676 rb.Push(ResultSuccess);
677} 427}
678 428
679void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) { 429Result FSP_SRV::GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode) {
680 LOG_DEBUG(Service_FS, "called"); 430 LOG_DEBUG(Service_FS, "called");
681 431
682 IPC::ResponseBuilder rb{ctx, 3}; 432 *out_access_log_mode = access_log_mode;
683 rb.Push(ResultSuccess);
684 rb.PushEnum(access_log_mode);
685}
686 433
687void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) { 434 R_SUCCEED();
688 const auto raw = ctx.ReadBufferCopy(); 435}
689 auto log = Common::StringFromFixedZeroTerminatedBuffer(
690 reinterpret_cast<const char*>(raw.data()), raw.size());
691 436
437Result FSP_SRV::OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer) {
692 LOG_DEBUG(Service_FS, "called"); 438 LOG_DEBUG(Service_FS, "called");
693 439
440 auto log = Common::StringFromFixedZeroTerminatedBuffer(
441 reinterpret_cast<const char*>(log_message_buffer.data()), log_message_buffer.size());
694 reporter.SaveFSAccessLog(log); 442 reporter.SaveFSAccessLog(log);
695 443
696 IPC::ResponseBuilder rb{ctx, 2}; 444 R_SUCCEED();
697 rb.Push(ResultSuccess);
698} 445}
699 446
700void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) { 447Result FSP_SRV::GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
701 LOG_DEBUG(Service_FS, "called"); 448 Out<u32> out_access_log_program_index) {
449 LOG_DEBUG(Service_FS, "(STUBBED) called");
450
451 *out_access_log_version = AccessLogVersion::Latest;
452 *out_access_log_program_index = access_log_program_index;
702 453
703 IPC::ResponseBuilder rb{ctx, 4}; 454 R_SUCCEED();
704 rb.Push(ResultSuccess);
705 rb.PushEnum(AccessLogVersion::Latest);
706 rb.Push(access_log_program_index);
707} 455}
708 456
709void FSP_SRV::FlushAccessLogOnSdCard(HLERequestContext& ctx) { 457Result FSP_SRV::FlushAccessLogOnSdCard() {
710 LOG_DEBUG(Service_FS, "(STUBBED) called"); 458 LOG_DEBUG(Service_FS, "(STUBBED) called");
711 459
712 IPC::ResponseBuilder rb{ctx, 2}; 460 R_SUCCEED();
713 rb.Push(ResultSuccess);
714} 461}
715 462
716void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) { 463Result FSP_SRV::GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size) {
717 IPC::RequestParser rp{ctx};
718 const auto index{rp.Pop<s32>()};
719
720 LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index); 464 LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index);
721 465
722 IPC::ResponseBuilder rb{ctx, 6}; 466 *out_data_size = 0;
723 rb.Push(ResultSuccess); 467 *out_journal_size = 0;
724 rb.Push(s64{0});
725 rb.Push(s64{0});
726}
727
728class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
729public:
730 explicit IMultiCommitManager(Core::System& system_)
731 : ServiceFramework{system_, "IMultiCommitManager"} {
732 static const FunctionInfo functions[] = {
733 {1, &IMultiCommitManager::Add, "Add"},
734 {2, &IMultiCommitManager::Commit, "Commit"},
735 };
736 RegisterHandlers(functions);
737 }
738 468
739private: 469 R_SUCCEED();
740 FileSys::VirtualFile backend; 470}
741
742 void Add(HLERequestContext& ctx) {
743 LOG_WARNING(Service_FS, "(STUBBED) called");
744
745 IPC::ResponseBuilder rb{ctx, 2};
746 rb.Push(ResultSuccess);
747 }
748
749 void Commit(HLERequestContext& ctx) {
750 LOG_WARNING(Service_FS, "(STUBBED) called");
751
752 IPC::ResponseBuilder rb{ctx, 2};
753 rb.Push(ResultSuccess);
754 }
755};
756 471
757void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) { 472Result FSP_SRV::OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface) {
758 LOG_DEBUG(Service_FS, "called"); 473 LOG_DEBUG(Service_FS, "called");
759 474
760 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 475 *out_interface = std::make_shared<IMultiCommitManager>(system);
761 rb.Push(ResultSuccess); 476
762 rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system)); 477 R_SUCCEED();
763} 478}
764 479
765} // namespace Service::FileSystem 480} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h
index 59406e6f9..ee67f6bc1 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h
@@ -4,6 +4,9 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include "core/file_sys/fs_save_data_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/filesystem/fsp/fsp_types.h"
7#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
8 11
9namespace Core { 12namespace Core {
@@ -20,6 +23,11 @@ namespace Service::FileSystem {
20class RomFsController; 23class RomFsController;
21class SaveDataController; 24class SaveDataController;
22 25
26class IFileSystem;
27class ISaveDataInfoReader;
28class IStorage;
29class IMultiCommitManager;
30
23enum class AccessLogVersion : u32 { 31enum class AccessLogVersion : u32 {
24 V7_0_0 = 2, 32 V7_0_0 = 2,
25 33
@@ -38,30 +46,46 @@ public:
38 ~FSP_SRV() override; 46 ~FSP_SRV() override;
39 47
40private: 48private:
41 void SetCurrentProcess(HLERequestContext& ctx); 49 Result SetCurrentProcess(ClientProcessId pid);
42 void OpenFileSystemWithPatch(HLERequestContext& ctx); 50 Result OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
43 void OpenSdCardFileSystem(HLERequestContext& ctx); 51 FileSystemProxyType type, u64 open_program_id);
44 void CreateSaveDataFileSystem(HLERequestContext& ctx); 52 Result OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface);
45 void CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); 53 Result CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
46 void OpenSaveDataFileSystem(HLERequestContext& ctx); 54 FileSys::SaveDataAttribute save_struct, u128 uid);
47 void OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); 55 Result CreateSaveDataFileSystemBySystemSaveDataId(
48 void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx); 56 FileSys::SaveDataCreationInfo save_create_struct, FileSys::SaveDataAttribute save_struct);
49 void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx); 57 Result OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
50 void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx); 58 FileSys::SaveDataSpaceId space_id,
51 void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx); 59 FileSys::SaveDataAttribute attribute);
52 void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx); 60 Result OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
53 void OpenDataStorageByCurrentProcess(HLERequestContext& ctx); 61 FileSys::SaveDataSpaceId space_id,
54 void OpenDataStorageByDataId(HLERequestContext& ctx); 62 FileSys::SaveDataAttribute attribute);
55 void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx); 63 Result OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
56 void OpenDataStorageWithProgramIndex(HLERequestContext& ctx); 64 FileSys::SaveDataSpaceId space_id,
57 void DisableAutoSaveDataCreation(HLERequestContext& ctx); 65 FileSys::SaveDataAttribute attribute);
58 void SetGlobalAccessLogMode(HLERequestContext& ctx); 66 Result OpenSaveDataInfoReaderBySaveDataSpaceId(OutInterface<ISaveDataInfoReader> out_interface,
59 void GetGlobalAccessLogMode(HLERequestContext& ctx); 67 FileSys::SaveDataSpaceId space);
60 void OutputAccessLogToSdCard(HLERequestContext& ctx); 68 Result OpenSaveDataInfoReaderOnlyCacheStorage(OutInterface<ISaveDataInfoReader> out_interface);
61 void FlushAccessLogOnSdCard(HLERequestContext& ctx); 69 Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute();
62 void GetProgramIndexForAccessLog(HLERequestContext& ctx); 70 Result ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
63 void OpenMultiCommitManager(HLERequestContext& ctx); 71 FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
64 void GetCacheStorageSize(HLERequestContext& ctx); 72 InBuffer<BufferAttr_HipcMapAlias> mask_buffer,
73 OutBuffer<BufferAttr_HipcMapAlias> out_buffer);
74 Result OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface);
75 Result OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
76 FileSys::StorageId storage_id, u32 unknown, u64 title_id);
77 Result OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
78 FileSys::StorageId storage_id, u64 title_id);
79 Result OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface, u8 program_index);
80 Result DisableAutoSaveDataCreation();
81 Result SetGlobalAccessLogMode(AccessLogMode access_log_mode_);
82 Result GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode);
83 Result OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer);
84 Result FlushAccessLogOnSdCard();
85 Result GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
86 Out<u32> out_access_log_program_index);
87 Result OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface);
88 Result GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size);
65 89
66 FileSystemController& fsc; 90 FileSystemController& fsc;
67 const FileSys::ContentProvider& content_provider; 91 const FileSys::ContentProvider& content_provider;
diff --git a/src/core/hle/service/filesystem/fsp/fsp_util.h b/src/core/hle/service/filesystem/fsp/fsp_types.h
index 253f866db..294da6a2d 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_util.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_types.h
@@ -7,6 +7,18 @@
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10enum class FileSystemProxyType : u8 {
11 Code = 0,
12 Rom = 1,
13 Logo = 2,
14 Control = 3,
15 Manual = 4,
16 Meta = 5,
17 Data = 6,
18 Package = 7,
19 RegisteredUpdate = 8,
20};
21
10struct SizeGetter { 22struct SizeGetter {
11 std::function<u64()> get_free_size; 23 std::function<u64()> get_free_size;
12 std::function<u64()> get_total_size; 24 std::function<u64()> get_total_size;
diff --git a/src/core/hle/service/psc/ovln/ovln_types.h b/src/core/hle/service/psc/ovln/ovln_types.h
new file mode 100644
index 000000000..343b05dcc
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/ovln_types.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8
9namespace Service::PSC {
10
11using OverlayNotification = std::array<u64, 0x10>;
12static_assert(sizeof(OverlayNotification) == 0x80, "OverlayNotification has incorrect size");
13
14union MessageFlags {
15 u64 raw;
16 BitField<0, 8, u64> message_type;
17 BitField<8, 8, u64> queue_type;
18};
19static_assert(sizeof(MessageFlags) == 0x8, "MessageFlags has incorrect size");
20
21} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver.cpp b/src/core/hle/service/psc/ovln/receiver.cpp
new file mode 100644
index 000000000..85f62816d
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver.cpp
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/ovln/receiver.h"
5
6namespace Service::PSC {
7
8IReceiver::IReceiver(Core::System& system_) : ServiceFramework{system_, "IReceiver"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "AddSource"},
12 {1, nullptr, "RemoveSource"},
13 {2, nullptr, "GetReceiveEventHandle"},
14 {3, nullptr, "Receive"},
15 {4, nullptr, "ReceiveWithTick"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IReceiver::~IReceiver() = default;
23
24} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver.h b/src/core/hle/service/psc/ovln/receiver.h
new file mode 100644
index 000000000..c47a4ff7e
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IReceiver final : public ServiceFramework<IReceiver> {
11public:
12 explicit IReceiver(Core::System& system_);
13 ~IReceiver() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver_service.cpp b/src/core/hle/service/psc/ovln/receiver_service.cpp
new file mode 100644
index 000000000..bb988e905
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver_service.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/receiver.h"
6#include "core/hle/service/psc/ovln/receiver_service.h"
7
8namespace Service::PSC {
9
10IReceiverService::IReceiverService(Core::System& system_) : ServiceFramework{system_, "ovln:rcv"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IReceiverService::OpenReceiver>, "OpenReceiver"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20IReceiverService::~IReceiverService() = default;
21
22Result IReceiverService::OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver) {
23 LOG_DEBUG(Service_PSC, "called");
24 *out_receiver = std::make_shared<IReceiver>(system);
25 R_SUCCEED();
26}
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver_service.h b/src/core/hle/service/psc/ovln/receiver_service.h
new file mode 100644
index 000000000..b3b31ba4a
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver_service.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class IReceiver;
12
13class IReceiverService final : public ServiceFramework<IReceiverService> {
14public:
15 explicit IReceiverService(Core::System& system_);
16 ~IReceiverService() override;
17
18private:
19 Result OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver);
20};
21
22} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender.cpp b/src/core/hle/service/psc/ovln/sender.cpp
new file mode 100644
index 000000000..3227a56f2
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender.cpp
@@ -0,0 +1,32 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/sender.h"
6
7namespace Service::PSC {
8
9ISender::ISender(Core::System& system_) : ServiceFramework{system_, "ISender"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, D<&ISender::Send>, "Send"},
13 {1, nullptr, "GetUnreceivedMessageCount"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20ISender::~ISender() = default;
21
22Result ISender::Send(const OverlayNotification& notification, MessageFlags flags) {
23 std::string data;
24 for (const auto m : notification) {
25 data += fmt::format("{:016X} ", m);
26 }
27
28 LOG_WARNING(Service_PSC, "(STUBBED) called, flags={} notification={}", flags.raw, data);
29 R_SUCCEED();
30}
31
32} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender.h b/src/core/hle/service/psc/ovln/sender.h
new file mode 100644
index 000000000..c1575428e
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/psc/ovln/ovln_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::PSC {
11
12class ISender final : public ServiceFramework<ISender> {
13public:
14 explicit ISender(Core::System& system_);
15 ~ISender() override;
16
17private:
18 Result Send(const OverlayNotification& notification, MessageFlags flags);
19};
20
21} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender_service.cpp b/src/core/hle/service/psc/ovln/sender_service.cpp
new file mode 100644
index 000000000..18d2c83a3
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender_service.cpp
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/sender.h"
6#include "core/hle/service/psc/ovln/sender_service.h"
7
8namespace Service::PSC {
9
10ISenderService::ISenderService(Core::System& system_) : ServiceFramework{system_, "ovln:snd"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&ISenderService::OpenSender>, "OpenSender"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20ISenderService::~ISenderService() = default;
21
22Result ISenderService::OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
23 std::array<u64, 2> data) {
24 LOG_WARNING(Service_PSC, "(STUBBED) called, sender_id={}, data={:016X} {:016X}", sender_id,
25 data[0], data[1]);
26 *out_sender = std::make_shared<ISender>(system);
27 R_SUCCEED();
28}
29
30} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender_service.h b/src/core/hle/service/psc/ovln/sender_service.h
new file mode 100644
index 000000000..10027701f
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender_service.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class ISender;
12
13class ISenderService final : public ServiceFramework<ISenderService> {
14public:
15 explicit ISenderService(Core::System& system_);
16 ~ISenderService() override;
17
18private:
19 Result OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
20 std::array<u64, 2> data);
21};
22
23} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_control.cpp b/src/core/hle/service/psc/pm_control.cpp
new file mode 100644
index 000000000..7dedb7662
--- /dev/null
+++ b/src/core/hle/service/psc/pm_control.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/pm_control.h"
5
6namespace Service::PSC {
7
8IPmControl::IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "Initialize"},
12 {1, nullptr, "DispatchRequest"},
13 {2, nullptr, "GetResult"},
14 {3, nullptr, "GetState"},
15 {4, nullptr, "Cancel"},
16 {5, nullptr, "PrintModuleInformation"},
17 {6, nullptr, "GetModuleInformation"},
18 {10, nullptr, "AcquireStateLock"},
19 {11, nullptr, "HasStateLock"},
20 };
21 // clang-format on
22
23 RegisterHandlers(functions);
24}
25
26IPmControl::~IPmControl() = default;
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_control.h b/src/core/hle/service/psc/pm_control.h
new file mode 100644
index 000000000..e0ae2f39c
--- /dev/null
+++ b/src/core/hle/service/psc/pm_control.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IPmControl final : public ServiceFramework<IPmControl> {
11public:
12 explicit IPmControl(Core::System& system_);
13 ~IPmControl() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_module.cpp b/src/core/hle/service/psc/pm_module.cpp
new file mode 100644
index 000000000..74dc7ed4e
--- /dev/null
+++ b/src/core/hle/service/psc/pm_module.cpp
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/pm_module.h"
5
6namespace Service::PSC {
7
8IPmModule::IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "Initialize"},
12 {1, nullptr, "GetRequest"},
13 {2, nullptr, "Acknowledge"},
14 {3, nullptr, "Finalize"},
15 {4, nullptr, "AcknowledgeEx"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IPmModule::~IPmModule() = default;
23
24} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_module.h b/src/core/hle/service/psc/pm_module.h
new file mode 100644
index 000000000..b3a2d2584
--- /dev/null
+++ b/src/core/hle/service/psc/pm_module.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IPmModule final : public ServiceFramework<IPmModule> {
11public:
12 explicit IPmModule(Core::System& system_);
13 ~IPmModule() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_service.cpp b/src/core/hle/service/psc/pm_service.cpp
new file mode 100644
index 000000000..c4e0ad228
--- /dev/null
+++ b/src/core/hle/service/psc/pm_service.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/pm_module.h"
6#include "core/hle/service/psc/pm_service.h"
7
8namespace Service::PSC {
9
10IPmService::IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IPmService::GetPmModule>, "GetPmModule"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20IPmService::~IPmService() = default;
21
22Result IPmService::GetPmModule(Out<SharedPointer<IPmModule>> out_module) {
23 LOG_DEBUG(Service_PSC, "called");
24 *out_module = std::make_shared<IPmModule>(system);
25 R_SUCCEED();
26}
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_service.h b/src/core/hle/service/psc/pm_service.h
new file mode 100644
index 000000000..08e14c6f8
--- /dev/null
+++ b/src/core/hle/service/psc/pm_service.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class IPmModule;
12
13class IPmService final : public ServiceFramework<IPmService> {
14public:
15 explicit IPmService(Core::System& system_);
16 ~IPmService() override;
17
18private:
19 Result GetPmModule(Out<SharedPointer<IPmModule>> out_module);
20};
21
22} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index 44310756b..e1762d694 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -1,11 +1,10 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <memory> 4#include "core/hle/service/psc/ovln/receiver_service.h"
5 5#include "core/hle/service/psc/ovln/sender_service.h"
6#include "common/logging/log.h" 6#include "core/hle/service/psc/pm_control.h"
7#include "core/core.h" 7#include "core/hle/service/psc/pm_service.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/psc/psc.h" 8#include "core/hle/service/psc/psc.h"
10#include "core/hle/service/psc/time/manager.h" 9#include "core/hle/service/psc/time/manager.h"
11#include "core/hle/service/psc/time/power_state_service.h" 10#include "core/hle/service/psc/time/power_state_service.h"
@@ -15,71 +14,13 @@
15 14
16namespace Service::PSC { 15namespace Service::PSC {
17 16
18class IPmControl final : public ServiceFramework<IPmControl> {
19public:
20 explicit IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, nullptr, "Initialize"},
24 {1, nullptr, "DispatchRequest"},
25 {2, nullptr, "GetResult"},
26 {3, nullptr, "GetState"},
27 {4, nullptr, "Cancel"},
28 {5, nullptr, "PrintModuleInformation"},
29 {6, nullptr, "GetModuleInformation"},
30 {10, nullptr, "AcquireStateLock"},
31 {11, nullptr, "HasStateLock"},
32 };
33 // clang-format on
34
35 RegisterHandlers(functions);
36 }
37};
38
39class IPmModule final : public ServiceFramework<IPmModule> {
40public:
41 explicit IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
42 // clang-format off
43 static const FunctionInfo functions[] = {
44 {0, nullptr, "Initialize"},
45 {1, nullptr, "GetRequest"},
46 {2, nullptr, "Acknowledge"},
47 {3, nullptr, "Finalize"},
48 {4, nullptr, "AcknowledgeEx"},
49 };
50 // clang-format on
51
52 RegisterHandlers(functions);
53 }
54};
55
56class IPmService final : public ServiceFramework<IPmService> {
57public:
58 explicit IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
59 // clang-format off
60 static const FunctionInfo functions[] = {
61 {0, &IPmService::GetPmModule, "GetPmModule"},
62 };
63 // clang-format on
64
65 RegisterHandlers(functions);
66 }
67
68private:
69 void GetPmModule(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_PSC, "called");
71
72 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
73 rb.Push(ResultSuccess);
74 rb.PushIpcInterface<IPmModule>(system);
75 }
76};
77
78void LoopProcess(Core::System& system) { 17void LoopProcess(Core::System& system) {
79 auto server_manager = std::make_unique<ServerManager>(system); 18 auto server_manager = std::make_unique<ServerManager>(system);
80 19
81 server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system)); 20 server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system));
82 server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system)); 21 server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system));
22 server_manager->RegisterNamedService("ovln:rcv", std::make_shared<IReceiverService>(system));
23 server_manager->RegisterNamedService("ovln:snd", std::make_shared<ISenderService>(system));
83 24
84 auto time = std::make_shared<Time::TimeManager>(system); 25 auto time = std::make_shared<Time::TimeManager>(system);
85 26
diff --git a/src/core/hle/service/psc/psc.h b/src/core/hle/service/psc/psc.h
index 459137f42..c83d07ca8 100644
--- a/src/core/hle/service/psc/psc.h
+++ b/src/core/hle/service/psc/psc.h
@@ -7,10 +7,6 @@ namespace Core {
7class System; 7class System;
8} 8}
9 9
10namespace Service::SM {
11class ServiceManager;
12}
13
14namespace Service::PSC { 10namespace Service::PSC {
15 11
16void LoopProcess(Core::System& system); 12void LoopProcess(Core::System& system);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index 0031fa5fb..3f9698d6b 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -261,7 +261,9 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
261 case Stage::Geometry: 261 case Stage::Geometry:
262 execution_model = spv::ExecutionModel::Geometry; 262 execution_model = spv::ExecutionModel::Geometry;
263 ctx.AddCapability(spv::Capability::Geometry); 263 ctx.AddCapability(spv::Capability::Geometry);
264 ctx.AddCapability(spv::Capability::GeometryStreams); 264 if (ctx.profile.support_geometry_streams) {
265 ctx.AddCapability(spv::Capability::GeometryStreams);
266 }
265 switch (ctx.runtime_info.input_topology) { 267 switch (ctx.runtime_info.input_topology) {
266 case InputTopology::Points: 268 case InputTopology::Points:
267 ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints); 269 ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
index 9f7b6bb4b..f60da758e 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
@@ -129,7 +129,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
129 if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) { 129 if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) {
130 ConvertDepthMode(ctx); 130 ConvertDepthMode(ctx);
131 } 131 }
132 if (stream.IsImmediate()) { 132 if (!ctx.profile.support_geometry_streams) {
133 throw NotImplementedException("Geometry streams");
134 } else if (stream.IsImmediate()) {
133 ctx.OpEmitStreamVertex(ctx.Def(stream)); 135 ctx.OpEmitStreamVertex(ctx.Def(stream));
134 } else { 136 } else {
135 LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); 137 LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
@@ -140,7 +142,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
140} 142}
141 143
142void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { 144void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
143 if (stream.IsImmediate()) { 145 if (!ctx.profile.support_geometry_streams) {
146 throw NotImplementedException("Geometry streams");
147 } else if (stream.IsImmediate()) {
144 ctx.OpEndStreamPrimitive(ctx.Def(stream)); 148 ctx.OpEndStreamPrimitive(ctx.Def(stream));
145 } else { 149 } else {
146 LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); 150 LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index 7578d41cc..90e46bb1b 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -44,6 +44,7 @@ struct Profile {
44 bool support_gl_derivative_control{}; 44 bool support_gl_derivative_control{};
45 bool support_scaled_attributes{}; 45 bool support_scaled_attributes{};
46 bool support_multi_viewport{}; 46 bool support_multi_viewport{};
47 bool support_geometry_streams{};
47 48
48 bool warp_size_potentially_larger_than_guest{}; 49 bool warp_size_potentially_larger_than_guest{};
49 50
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 20f7a9702..d34b585d6 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -352,6 +352,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
352 .support_native_ndc = device.IsExtDepthClipControlSupported(), 352 .support_native_ndc = device.IsExtDepthClipControlSupported(),
353 .support_scaled_attributes = !device.MustEmulateScaledFormats(), 353 .support_scaled_attributes = !device.MustEmulateScaledFormats(),
354 .support_multi_viewport = device.SupportsMultiViewport(), 354 .support_multi_viewport = device.SupportsMultiViewport(),
355 .support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
355 356
356 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), 357 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
357 358
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index d7216d349..b94924a58 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -1297,10 +1297,6 @@ u64 Device::GetDeviceMemoryUsage() const {
1297} 1297}
1298 1298
1299void Device::CollectPhysicalMemoryInfo() { 1299void Device::CollectPhysicalMemoryInfo() {
1300 // Account for resolution scaling in memory limits
1301 const size_t normal_memory = 6_GiB;
1302 const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
1303
1304 // Calculate limits using memory budget 1300 // Calculate limits using memory budget
1305 VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{}; 1301 VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{};
1306 budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; 1302 budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
@@ -1331,7 +1327,15 @@ void Device::CollectPhysicalMemoryInfo() {
1331 if (!is_integrated) { 1327 if (!is_integrated) {
1332 const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB); 1328 const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB);
1333 device_access_memory -= reserve_memory; 1329 device_access_memory -= reserve_memory;
1334 device_access_memory = std::min<u64>(device_access_memory, normal_memory + scaler_memory); 1330
1331 if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) {
1332 // Account for resolution scaling in memory limits
1333 const size_t normal_memory = 6_GiB;
1334 const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
1335 device_access_memory =
1336 std::min<u64>(device_access_memory, normal_memory + scaler_memory);
1337 }
1338
1335 return; 1339 return;
1336 } 1340 }
1337 const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage); 1341 const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index a2ec26697..e3abe8ddf 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -499,6 +499,11 @@ public:
499 return extensions.transform_feedback; 499 return extensions.transform_feedback;
500 } 500 }
501 501
502 /// Returns true if the device supports VK_EXT_transform_feedback properly.
503 bool AreTransformFeedbackGeometryStreamsSupported() const {
504 return features.transform_feedback.geometryStreams;
505 }
506
502 /// Returns true if the device supports VK_EXT_custom_border_color. 507 /// Returns true if the device supports VK_EXT_custom_border_color.
503 bool IsExtCustomBorderColorSupported() const { 508 bool IsExtCustomBorderColorSupported() const {
504 return extensions.custom_border_color; 509 return extensions.custom_border_color;
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp
index d138b53c8..0549e8ae4 100644
--- a/src/yuzu/configuration/shared_translation.cpp
+++ b/src/yuzu/configuration/shared_translation.cpp
@@ -164,6 +164,11 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
164 "the emulator to decompress to an intermediate format any card supports, RGBA8.\n" 164 "the emulator to decompress to an intermediate format any card supports, RGBA8.\n"
165 "This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but " 165 "This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but "
166 "negatively affecting image quality.")); 166 "negatively affecting image quality."));
167 INSERT(Settings, vram_usage_mode, tr("VRAM Usage Mode:"),
168 tr("Selects whether the emulator should prefer to conserve memory or make maximum usage "
169 "of available video memory for performance. Has no effect on integrated graphics. "
170 "Aggressive mode may severely impact the performance of other applications such as "
171 "recording software."));
167 INSERT( 172 INSERT(
168 Settings, vsync_mode, tr("VSync Mode:"), 173 Settings, vsync_mode, tr("VSync Mode:"),
169 tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " 174 tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
@@ -315,6 +320,11 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
315 PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")), 320 PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
316 PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")), 321 PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
317 }}); 322 }});
323 translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
324 {
325 PAIR(VramUsageMode, Conservative, tr("Conservative")),
326 PAIR(VramUsageMode, Aggressive, tr("Aggressive")),
327 }});
318 translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(), 328 translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(),
319 { 329 {
320#ifdef HAS_OPENGL 330#ifdef HAS_OPENGL
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b2ae3db52..c0c0a19b8 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2325,15 +2325,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
2325 ASSERT(user_id); 2325 ASSERT(user_id);
2326 2326
2327 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 2327 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
2328 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, 2328 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account,
2329 FileSys::SaveDataType::SaveData, program_id, user_id->AsU128(), 0); 2329 program_id, user_id->AsU128(), 0);
2330 2330
2331 path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); 2331 path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
2332 } else { 2332 } else {
2333 // Device save data 2333 // Device save data
2334 const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath( 2334 const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath(
2335 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, 2335 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account,
2336 FileSys::SaveDataType::SaveData, program_id, {}, 0); 2336 program_id, {}, 0);
2337 2337
2338 path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path); 2338 path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path);
2339 } 2339 }
@@ -2674,7 +2674,7 @@ void GMainWindow::RemoveCacheStorage(u64 program_id) {
2674 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); 2674 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
2675 2675
2676 const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( 2676 const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath(
2677 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::CacheStorage, 2677 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Cache,
2678 0 /* program_id */, {}, 0); 2678 0 /* program_id */, {}, 0);
2679 2679
2680 const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); 2680 const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path);
@@ -3010,9 +3010,6 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi
3010 3010
3011void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, 3011void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
3012 GameListShortcutTarget target) { 3012 GameListShortcutTarget target) {
3013 std::string game_title;
3014 QString qt_game_title;
3015 std::filesystem::path out_icon_path;
3016 // Get path to yuzu executable 3013 // Get path to yuzu executable
3017 const QStringList args = QApplication::arguments(); 3014 const QStringList args = QApplication::arguments();
3018 std::filesystem::path yuzu_command = args[0].toStdString(); 3015 std::filesystem::path yuzu_command = args[0].toStdString();
@@ -3029,48 +3026,51 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
3029 shortcut_path = 3026 shortcut_path =
3030 QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); 3027 QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
3031 } 3028 }
3032 // Icon path and title 3029
3033 if (std::filesystem::exists(shortcut_path)) { 3030 if (!std::filesystem::exists(shortcut_path)) {
3034 // Get title from game file 3031 GMainWindow::CreateShortcutMessagesGUI(
3035 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), 3032 this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
3036 system->GetContentProvider()}; 3033 QString::fromStdString(shortcut_path.generic_string()));
3037 const auto control = pm.GetControlMetadata(); 3034 LOG_ERROR(Frontend, "Invalid shortcut target {}", shortcut_path.generic_string());
3038 const auto loader = 3035 return;
3039 Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); 3036 }
3040 game_title = fmt::format("{:016X}", program_id); 3037
3041 if (control.first != nullptr) { 3038 // Get title from game file
3042 game_title = control.first->GetApplicationName(); 3039 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
3043 } else { 3040 system->GetContentProvider()};
3044 loader->ReadTitle(game_title); 3041 const auto control = pm.GetControlMetadata();
3045 } 3042 const auto loader =
3046 // Delete illegal characters from title 3043 Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read));
3047 const std::string illegal_chars = "<>:\"/\\|?*."; 3044 std::string game_title = fmt::format("{:016X}", program_id);
3048 for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) { 3045 if (control.first != nullptr) {
3049 if (illegal_chars.find(*it) != std::string::npos) { 3046 game_title = control.first->GetApplicationName();
3050 game_title.erase(it.base() - 1); 3047 } else {
3051 } 3048 loader->ReadTitle(game_title);
3052 } 3049 }
3053 qt_game_title = QString::fromStdString(game_title); 3050 // Delete illegal characters from title
3054 // Get icon from game file 3051 const std::string illegal_chars = "<>:\"/\\|?*.";
3055 std::vector<u8> icon_image_file{}; 3052 for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) {
3056 if (control.second != nullptr) { 3053 if (illegal_chars.find(*it) != std::string::npos) {
3057 icon_image_file = control.second->ReadAllBytes(); 3054 game_title.erase(it.base() - 1);
3058 } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
3059 LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
3060 } 3055 }
3061 QImage icon_data = 3056 }
3062 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size())); 3057 const QString qt_game_title = QString::fromStdString(game_title);
3063 if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { 3058 // Get icon from game file
3064 if (!SaveIconToFile(out_icon_path, icon_data)) { 3059 std::vector<u8> icon_image_file{};
3065 LOG_ERROR(Frontend, "Could not write icon to file"); 3060 if (control.second != nullptr) {
3066 } 3061 icon_image_file = control.second->ReadAllBytes();
3062 } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
3063 LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
3064 }
3065 QImage icon_data =
3066 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
3067 std::filesystem::path out_icon_path;
3068 if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) {
3069 if (!SaveIconToFile(out_icon_path, icon_data)) {
3070 LOG_ERROR(Frontend, "Could not write icon to file");
3067 } 3071 }
3068 } else {
3069 GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
3070 qt_game_title);
3071 LOG_ERROR(Frontend, "Invalid shortcut target");
3072 return;
3073 } 3072 }
3073
3074#if defined(__linux__) 3074#if defined(__linux__)
3075 // Special case for AppImages 3075 // Special case for AppImages
3076 // Warn once if we are making a shortcut to a volatile AppImage 3076 // Warn once if we are making a shortcut to a volatile AppImage