summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeModules/FindSimpleIni.cmake22
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt29
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt8
-rw-r--r--src/android/app/src/main/jni/game_metadata.cpp12
-rw-r--r--src/android/app/src/main/jni/native.cpp15
-rw-r--r--src/android/app/src/main/res/layout-w600dp/fragment_about.xml5
-rw-r--r--src/android/app/src/main/res/layout-w600dp/fragment_game_info.xml155
-rw-r--r--src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml1
-rw-r--r--src/android/app/src/main/res/layout/card_driver_option.xml1
-rw-r--r--src/android/app/src/main/res/layout/card_folder.xml6
-rw-r--r--src/android/app/src/main/res/layout/fragment_about.xml5
-rw-r--r--src/android/app/src/main/res/layout/fragment_addons.xml4
-rw-r--r--src/android/app/src/main/res/layout/fragment_applet_launcher.xml4
-rw-r--r--src/android/app/src/main/res/layout/fragment_driver_manager.xml2
-rw-r--r--src/android/app/src/main/res/layout/fragment_early_access.xml5
-rw-r--r--src/android/app/src/main/res/layout/fragment_emulation.xml8
-rw-r--r--src/android/app/src/main/res/layout/fragment_folders.xml3
-rw-r--r--src/android/app/src/main/res/layout/fragment_game_info.xml3
-rw-r--r--src/android/app/src/main/res/layout/fragment_game_properties.xml5
-rw-r--r--src/android/app/src/main/res/layout/fragment_games.xml1
-rw-r--r--src/android/app/src/main/res/layout/fragment_home_settings.xml3
-rw-r--r--src/android/app/src/main/res/layout/fragment_installables.xml4
-rw-r--r--src/android/app/src/main/res/layout/fragment_licenses.xml4
-rw-r--r--src/android/app/src/main/res/layout/fragment_settings.xml2
-rw-r--r--src/android/app/src/main/res/layout/list_item_addon.xml2
-rw-r--r--src/android/app/src/main/res/layout/list_item_settings_header.xml1
-rw-r--r--src/common/overflow.h18
-rw-r--r--src/core/CMakeLists.txt161
-rw-r--r--src/core/core.cpp12
-rw-r--r--src/core/core.h2
-rw-r--r--src/core/crypto/aes_util.h2
-rw-r--r--src/core/crypto/encryption_layer.h2
-rw-r--r--src/core/crypto/partition_data_manager.cpp6
-rw-r--r--src/core/crypto/partition_data_manager.h2
-rw-r--r--src/core/file_sys/bis_factory.cpp5
-rw-r--r--src/core/file_sys/bis_factory.h2
-rw-r--r--src/core/file_sys/card_image.cpp4
-rw-r--r--src/core/file_sys/card_image.h2
-rw-r--r--src/core/file_sys/content_archive.cpp2
-rw-r--r--src/core/file_sys/content_archive.h2
-rw-r--r--src/core/file_sys/control_metadata.cpp2
-rw-r--r--src/core/file_sys/control_metadata.h2
-rw-r--r--src/core/file_sys/directory.h39
-rw-r--r--src/core/file_sys/errors.h26
-rw-r--r--src/core/file_sys/fs_directory.h33
-rw-r--r--src/core/file_sys/fs_file.h65
-rw-r--r--src/core/file_sys/fs_filesystem.h39
-rw-r--r--src/core/file_sys/fs_memory_management.h40
-rw-r--r--src/core/file_sys/fs_operate_range.h22
-rw-r--r--src/core/file_sys/fs_path.h566
-rw-r--r--src/core/file_sys/fs_path_utility.h1239
-rw-r--r--src/core/file_sys/fs_string_util.h226
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp4
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.h2
-rw-r--r--src/core/file_sys/fssystem/fs_i_storage.h2
-rw-r--r--src/core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp2
-rw-r--r--src/core/file_sys/fssystem/fssystem_aes_ctr_storage.h2
-rw-r--r--src/core/file_sys/fssystem/fssystem_bucket_tree.h2
-rw-r--r--src/core/file_sys/fssystem/fssystem_compressed_storage.h2
-rw-r--r--src/core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.cpp2
-rw-r--r--src/core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h2
-rw-r--r--src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h2
-rw-r--r--src/core/file_sys/fssystem/fssystem_indirect_storage.h4
-rw-r--r--src/core/file_sys/fssystem/fssystem_integrity_romfs_storage.h2
-rw-r--r--src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp4
-rw-r--r--src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h2
-rw-r--r--src/core/file_sys/fssystem/fssystem_nca_reader.cpp2
-rw-r--r--src/core/file_sys/ips_layer.cpp2
-rw-r--r--src/core/file_sys/ips_layer.h2
-rw-r--r--src/core/file_sys/kernel_executable.cpp2
-rw-r--r--src/core/file_sys/kernel_executable.h2
-rw-r--r--src/core/file_sys/mode.h23
-rw-r--r--src/core/file_sys/nca_metadata.cpp2
-rw-r--r--src/core/file_sys/nca_metadata.h2
-rw-r--r--src/core/file_sys/partition_filesystem.cpp2
-rw-r--r--src/core/file_sys/partition_filesystem.h2
-rw-r--r--src/core/file_sys/patch_manager.cpp6
-rw-r--r--src/core/file_sys/patch_manager.h2
-rw-r--r--src/core/file_sys/program_metadata.cpp2
-rw-r--r--src/core/file_sys/program_metadata.h2
-rw-r--r--src/core/file_sys/registered_cache.cpp2
-rw-r--r--src/core/file_sys/registered_cache.h2
-rw-r--r--src/core/file_sys/romfs.cpp10
-rw-r--r--src/core/file_sys/romfs.h2
-rw-r--r--src/core/file_sys/romfs_factory.h2
-rw-r--r--src/core/file_sys/savedata_factory.cpp2
-rw-r--r--src/core/file_sys/savedata_factory.h2
-rw-r--r--src/core/file_sys/sdmc_factory.cpp2
-rw-r--r--src/core/file_sys/sdmc_factory.h2
-rw-r--r--src/core/file_sys/submission_package.h2
-rw-r--r--src/core/file_sys/system_archive/mii_model.cpp2
-rw-r--r--src/core/file_sys/system_archive/mii_model.h2
-rw-r--r--src/core/file_sys/system_archive/ng_word.cpp2
-rw-r--r--src/core/file_sys/system_archive/ng_word.h2
-rw-r--r--src/core/file_sys/system_archive/shared_font.cpp2
-rw-r--r--src/core/file_sys/system_archive/shared_font.h2
-rw-r--r--src/core/file_sys/system_archive/system_archive.h2
-rw-r--r--src/core/file_sys/system_archive/system_version.cpp2
-rw-r--r--src/core/file_sys/system_archive/system_version.h2
-rw-r--r--src/core/file_sys/system_archive/time_zone_binary.cpp2
-rw-r--r--src/core/file_sys/system_archive/time_zone_binary.h2
-rw-r--r--src/core/file_sys/vfs/vfs.cpp (renamed from src/core/file_sys/vfs.cpp)29
-rw-r--r--src/core/file_sys/vfs/vfs.h (renamed from src/core/file_sys/vfs.h)13
-rw-r--r--src/core/file_sys/vfs/vfs_cached.cpp (renamed from src/core/file_sys/vfs_cached.cpp)4
-rw-r--r--src/core/file_sys/vfs/vfs_cached.h (renamed from src/core/file_sys/vfs_cached.h)2
-rw-r--r--src/core/file_sys/vfs/vfs_concat.cpp (renamed from src/core/file_sys/vfs_concat.cpp)4
-rw-r--r--src/core/file_sys/vfs/vfs_concat.h (renamed from src/core/file_sys/vfs_concat.h)2
-rw-r--r--src/core/file_sys/vfs/vfs_layered.cpp (renamed from src/core/file_sys/vfs_layered.cpp)2
-rw-r--r--src/core/file_sys/vfs/vfs_layered.h (renamed from src/core/file_sys/vfs_layered.h)2
-rw-r--r--src/core/file_sys/vfs/vfs_offset.cpp (renamed from src/core/file_sys/vfs_offset.cpp)2
-rw-r--r--src/core/file_sys/vfs/vfs_offset.h (renamed from src/core/file_sys/vfs_offset.h)2
-rw-r--r--src/core/file_sys/vfs/vfs_real.cpp (renamed from src/core/file_sys/vfs_real.cpp)55
-rw-r--r--src/core/file_sys/vfs/vfs_real.h (renamed from src/core/file_sys/vfs_real.h)27
-rw-r--r--src/core/file_sys/vfs/vfs_static.h (renamed from src/core/file_sys/vfs_static.h)2
-rw-r--r--src/core/file_sys/vfs/vfs_types.h (renamed from src/core/file_sys/vfs_types.h)0
-rw-r--r--src/core/file_sys/vfs/vfs_vector.cpp (renamed from src/core/file_sys/vfs_vector.cpp)2
-rw-r--r--src/core/file_sys/vfs/vfs_vector.h (renamed from src/core/file_sys/vfs_vector.h)2
-rw-r--r--src/core/file_sys/xts_archive.cpp2
-rw-r--r--src/core/file_sys/xts_archive.h2
-rw-r--r--src/core/frontend/applets/error.cpp6
-rw-r--r--src/core/hle/result.h38
-rw-r--r--src/core/hle/service/am/applets/applet_error.cpp4
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser.cpp8
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser.h2
-rw-r--r--src/core/hle/service/audio/audren_u.cpp3
-rw-r--r--src/core/hle/service/bcat/backend/backend.h2
-rw-r--r--src/core/hle/service/bcat/bcat_module.cpp2
-rw-r--r--src/core/hle/service/caps/caps_a.cpp13
-rw-r--r--src/core/hle/service/cmif_serialization.h71
-rw-r--r--src/core/hle/service/cmif_types.h112
-rw-r--r--src/core/hle/service/fatal/fatal.cpp4
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp78
-rw-r--r--src/core/hle/service/filesystem/filesystem.h18
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.cpp84
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.h30
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.cpp127
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.h25
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp262
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.h38
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.cpp62
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.h23
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_ldr.cpp (renamed from src/core/hle/service/filesystem/fsp_ldr.cpp)2
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_ldr.h (renamed from src/core/hle/service/filesystem/fsp_ldr.h)0
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_pr.cpp (renamed from src/core/hle/service/filesystem/fsp_pr.cpp)2
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_pr.h (renamed from src/core/hle/service/filesystem/fsp_pr.h)0
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.cpp (renamed from src/core/hle/service/filesystem/fsp_srv.cpp)546
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.h (renamed from src/core/hle/service/filesystem/fsp_srv.h)0
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_util.h22
-rw-r--r--src/core/hle/service/filesystem/romfs_controller.h2
-rw-r--r--src/core/hle/service/filesystem/save_data_controller.cpp6
-rw-r--r--src/core/hle/service/filesystem/save_data_controller.h2
-rw-r--r--src/core/hle/service/glue/time/manager.cpp2
-rw-r--r--src/core/hle/service/glue/time/manager.h2
-rw-r--r--src/core/hle/service/glue/time/time_zone_binary.cpp2
-rw-r--r--src/core/hle/service/jit/jit.cpp14
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp2
-rw-r--r--src/core/hle/service/ns/ns.cpp2
-rw-r--r--src/core/hle/service/ro/ro.cpp3
-rw-r--r--src/core/hle/service/set/system_settings_server.cpp4
-rw-r--r--src/core/loader/loader.h2
-rw-r--r--src/core/loader/nro.cpp2
-rw-r--r--src/core/reporter.cpp4
-rw-r--r--src/frontend_common/content_manager.h11
-rw-r--r--src/yuzu/applets/qt_error.cpp12
-rw-r--r--src/yuzu/configuration/configure_per_game.h2
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.h2
-rw-r--r--src/yuzu/game_list_worker.cpp4
-rw-r--r--src/yuzu/main.cpp19
-rw-r--r--src/yuzu_cmd/yuzu.cpp2
171 files changed, 3738 insertions, 1079 deletions
diff --git a/CMakeModules/FindSimpleIni.cmake b/CMakeModules/FindSimpleIni.cmake
index ce75d7690..13426b25b 100644
--- a/CMakeModules/FindSimpleIni.cmake
+++ b/CMakeModules/FindSimpleIni.cmake
@@ -2,18 +2,20 @@
2# 2#
3# SPDX-License-Identifier: GPL-3.0-or-later 3# SPDX-License-Identifier: GPL-3.0-or-later
4 4
5find_path(SimpleIni_INCLUDE_DIR SimpleIni.h)
6
7include(FindPackageHandleStandardArgs) 5include(FindPackageHandleStandardArgs)
8find_package_handle_standard_args(SimpleIni
9 REQUIRED_VARS SimpleIni_INCLUDE_DIR
10)
11 6
12if (SimpleIni_FOUND AND NOT TARGET SimpleIni::SimpleIni) 7find_package(SimpleIni QUIET CONFIG)
13 add_library(SimpleIni::SimpleIni INTERFACE IMPORTED) 8if (SimpleIni_CONSIDERED_CONFIGS)
14 set_target_properties(SimpleIni::SimpleIni PROPERTIES 9 find_package_handle_standard_args(SimpleIni CONFIG_MODE)
15 INTERFACE_INCLUDE_DIRECTORIES "${SimpleIni_INCLUDE_DIR}" 10else()
11 find_package(PkgConfig QUIET)
12 pkg_search_module(SIMPLEINI QUIET IMPORTED_TARGET simpleini)
13 find_package_handle_standard_args(SimpleIni
14 REQUIRED_VARS SIMPLEINI_INCLUDEDIR
15 VERSION_VAR SIMPLEINI_VERSION
16 ) 16 )
17endif() 17endif()
18 18
19mark_as_advanced(SimpleIni_INCLUDE_DIR) 19if (SimpleIni_FOUND AND NOT TARGET SimpleIni::SimpleIni)
20 add_library(SimpleIni::SimpleIni ALIAS PkgConfig::SIMPLEINI)
21endif()
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
index 9b08f008d..26cddecf4 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
@@ -193,6 +193,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
193 return super.dispatchKeyEvent(event) 193 return super.dispatchKeyEvent(event)
194 } 194 }
195 195
196 if (emulationViewModel.drawerOpen.value) {
197 return super.dispatchKeyEvent(event)
198 }
199
196 return InputHandler.dispatchKeyEvent(event) 200 return InputHandler.dispatchKeyEvent(event)
197 } 201 }
198 202
@@ -203,6 +207,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
203 return super.dispatchGenericMotionEvent(event) 207 return super.dispatchGenericMotionEvent(event)
204 } 208 }
205 209
210 if (emulationViewModel.drawerOpen.value) {
211 return super.dispatchGenericMotionEvent(event)
212 }
213
206 // Don't attempt to do anything if we are disconnecting a device. 214 // Don't attempt to do anything if we are disconnecting a device.
207 if (event.actionMasked == MotionEvent.ACTION_CANCEL) { 215 if (event.actionMasked == MotionEvent.ACTION_CANCEL) {
208 return true 216 return true
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
index 5b5f800c1..5ab38ffda 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
@@ -77,7 +77,7 @@ class AboutFragment : Fragment() {
77 } 77 }
78 78
79 binding.textVersionName.text = BuildConfig.VERSION_NAME 79 binding.textVersionName.text = BuildConfig.VERSION_NAME
80 binding.textVersionName.setOnClickListener { 80 binding.buttonVersionName.setOnClickListener {
81 val clipBoard = 81 val clipBoard =
82 requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager 82 requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
83 val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH) 83 val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index d17e087fe..22da1d0e5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -38,6 +38,7 @@ import androidx.window.layout.WindowLayoutInfo
38import com.google.android.material.dialog.MaterialAlertDialogBuilder 38import com.google.android.material.dialog.MaterialAlertDialogBuilder
39import com.google.android.material.slider.Slider 39import com.google.android.material.slider.Slider
40import kotlinx.coroutines.Dispatchers 40import kotlinx.coroutines.Dispatchers
41import kotlinx.coroutines.flow.collect
41import kotlinx.coroutines.flow.collectLatest 42import kotlinx.coroutines.flow.collectLatest
42import kotlinx.coroutines.launch 43import kotlinx.coroutines.launch
43import org.yuzu.yuzu_emu.HomeNavigationDirections 44import org.yuzu.yuzu_emu.HomeNavigationDirections
@@ -184,10 +185,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
184 185
185 override fun onDrawerOpened(drawerView: View) { 186 override fun onDrawerOpened(drawerView: View) {
186 binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) 187 binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
188 binding.inGameMenu.requestFocus()
189 emulationViewModel.setDrawerOpen(true)
187 } 190 }
188 191
189 override fun onDrawerClosed(drawerView: View) { 192 override fun onDrawerClosed(drawerView: View) {
190 binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt()) 193 binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
194 emulationViewModel.setDrawerOpen(false)
191 } 195 }
192 196
193 override fun onDrawerStateChanged(newState: Int) { 197 override fun onDrawerStateChanged(newState: Int) {
@@ -239,6 +243,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
239 requireContext().theme 243 requireContext().theme
240 ) 244 )
241 } 245 }
246 binding.inGameMenu.requestFocus()
242 true 247 true
243 } 248 }
244 249
@@ -247,6 +252,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
247 null, 252 null,
248 Settings.MenuTag.SECTION_ROOT 253 Settings.MenuTag.SECTION_ROOT
249 ) 254 )
255 binding.inGameMenu.requestFocus()
250 binding.root.findNavController().navigate(action) 256 binding.root.findNavController().navigate(action)
251 true 257 true
252 } 258 }
@@ -256,6 +262,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
256 args.game, 262 args.game,
257 Settings.MenuTag.SECTION_ROOT 263 Settings.MenuTag.SECTION_ROOT
258 ) 264 )
265 binding.inGameMenu.requestFocus()
259 binding.root.findNavController().navigate(action) 266 binding.root.findNavController().navigate(action)
260 true 267 true
261 } 268 }
@@ -287,6 +294,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
287 ) 294 )
288 } 295 }
289 } 296 }
297 binding.inGameMenu.requestFocus()
290 NativeConfig.saveGlobalConfig() 298 NativeConfig.saveGlobalConfig()
291 true 299 true
292 } 300 }
@@ -295,7 +303,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
295 emulationState.stop() 303 emulationState.stop()
296 emulationViewModel.setIsEmulationStopping(true) 304 emulationViewModel.setIsEmulationStopping(true)
297 binding.drawerLayout.close() 305 binding.drawerLayout.close()
298 binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) 306 binding.inGameMenu.requestFocus()
299 true 307 true
300 } 308 }
301 309
@@ -312,12 +320,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
312 if (!NativeLibrary.isRunning()) { 320 if (!NativeLibrary.isRunning()) {
313 return 321 return
314 } 322 }
315 323 emulationViewModel.setDrawerOpen(!binding.drawerLayout.isOpen)
316 if (binding.drawerLayout.isOpen) {
317 binding.drawerLayout.close()
318 } else {
319 binding.drawerLayout.open()
320 }
321 } 324 }
322 } 325 }
323 ) 326 )
@@ -408,6 +411,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
408 } 411 }
409 } 412 }
410 } 413 }
414 launch {
415 repeatOnLifecycle(Lifecycle.State.CREATED) {
416 emulationViewModel.drawerOpen.collect {
417 if (it) {
418 binding.drawerLayout.open()
419 binding.inGameMenu.requestFocus()
420 } else {
421 binding.drawerLayout.close()
422 }
423 }
424 }
425 }
411 } 426 }
412 } 427 }
413 428
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt
index f34870c2d..b66f47fe7 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt
@@ -6,6 +6,7 @@ package org.yuzu.yuzu_emu.model
6import androidx.lifecycle.ViewModel 6import androidx.lifecycle.ViewModel
7import kotlinx.coroutines.flow.MutableStateFlow 7import kotlinx.coroutines.flow.MutableStateFlow
8import kotlinx.coroutines.flow.StateFlow 8import kotlinx.coroutines.flow.StateFlow
9import kotlinx.coroutines.flow.asStateFlow
9 10
10class EmulationViewModel : ViewModel() { 11class EmulationViewModel : ViewModel() {
11 val emulationStarted: StateFlow<Boolean> get() = _emulationStarted 12 val emulationStarted: StateFlow<Boolean> get() = _emulationStarted
@@ -23,6 +24,9 @@ class EmulationViewModel : ViewModel() {
23 val shaderMessage: StateFlow<String> get() = _shaderMessage 24 val shaderMessage: StateFlow<String> get() = _shaderMessage
24 private val _shaderMessage = MutableStateFlow("") 25 private val _shaderMessage = MutableStateFlow("")
25 26
27 private val _drawerOpen = MutableStateFlow(false)
28 val drawerOpen = _drawerOpen.asStateFlow()
29
26 fun setEmulationStarted(started: Boolean) { 30 fun setEmulationStarted(started: Boolean) {
27 _emulationStarted.value = started 31 _emulationStarted.value = started
28 } 32 }
@@ -49,6 +53,10 @@ class EmulationViewModel : ViewModel() {
49 setTotalShaders(max) 53 setTotalShaders(max)
50 } 54 }
51 55
56 fun setDrawerOpen(value: Boolean) {
57 _drawerOpen.value = value
58 }
59
52 fun clear() { 60 fun clear() {
53 setEmulationStarted(false) 61 setEmulationStarted(false)
54 setIsEmulationStopping(false) 62 setIsEmulationStopping(false)
diff --git a/src/android/app/src/main/jni/game_metadata.cpp b/src/android/app/src/main/jni/game_metadata.cpp
index 78f604c70..8f0da1413 100644
--- a/src/android/app/src/main/jni/game_metadata.cpp
+++ b/src/android/app/src/main/jni/game_metadata.cpp
@@ -1,12 +1,12 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 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 <core/core.h> 4#include "core/core.h"
5#include <core/file_sys/mode.h> 5#include "core/file_sys/fs_filesystem.h"
6#include <core/file_sys/patch_manager.h> 6#include "core/file_sys/patch_manager.h"
7#include <core/loader/nro.h>
8#include <jni.h>
9#include "core/loader/loader.h" 7#include "core/loader/loader.h"
8#include "core/loader/nro.h"
9#include "jni.h"
10#include "jni/android_common/android_common.h" 10#include "jni/android_common/android_common.h"
11#include "native.h" 11#include "native.h"
12 12
@@ -79,7 +79,7 @@ extern "C" {
79jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj, 79jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj,
80 jstring jpath) { 80 jstring jpath) {
81 const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( 81 const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
82 GetJString(env, jpath), FileSys::Mode::Read); 82 GetJString(env, jpath), FileSys::OpenMode::Read);
83 if (!file) { 83 if (!file) {
84 return false; 84 return false;
85 } 85 }
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 247f2c2b3..3fd9a500c 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -35,9 +35,10 @@
35#include "core/crypto/key_manager.h" 35#include "core/crypto/key_manager.h"
36#include "core/file_sys/card_image.h" 36#include "core/file_sys/card_image.h"
37#include "core/file_sys/content_archive.h" 37#include "core/file_sys/content_archive.h"
38#include "core/file_sys/fs_filesystem.h"
38#include "core/file_sys/submission_package.h" 39#include "core/file_sys/submission_package.h"
39#include "core/file_sys/vfs.h" 40#include "core/file_sys/vfs/vfs.h"
40#include "core/file_sys/vfs_real.h" 41#include "core/file_sys/vfs/vfs_real.h"
41#include "core/frontend/applets/cabinet.h" 42#include "core/frontend/applets/cabinet.h"
42#include "core/frontend/applets/controller.h" 43#include "core/frontend/applets/controller.h"
43#include "core/frontend/applets/error.h" 44#include "core/frontend/applets/error.h"
@@ -154,7 +155,7 @@ void EmulationSession::SurfaceChanged() {
154} 155}
155 156
156void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) { 157void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) {
157 const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read); 158 const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::OpenMode::Read);
158 if (!file) { 159 if (!file) {
159 return; 160 return;
160 } 161 }
@@ -475,8 +476,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
475 u64 program_id = EmulationSession::GetProgramId(env, jprogramId); 476 u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
476 std::string updatePath = GetJString(env, jupdatePath); 477 std::string updatePath = GetJString(env, jupdatePath);
477 std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>( 478 std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
478 EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(updatePath, 479 EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
479 FileSys::Mode::Read)); 480 updatePath, FileSys::OpenMode::Read));
480 for (const auto& item : nsp->GetNCAs()) { 481 for (const auto& item : nsp->GetNCAs()) {
481 for (const auto& nca_details : item.second) { 482 for (const auto& nca_details : item.second) {
482 if (nca_details.second->GetName().ends_with(".cnmt.nca")) { 483 if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
@@ -719,7 +720,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
719 jobject instance) { 720 jobject instance) {
720 const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); 721 const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
721 auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory( 722 auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory(
722 Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); 723 Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
723 724
724 const auto user_id = EmulationSession::GetInstance().System().GetProfileManager().GetUser( 725 const auto user_id = EmulationSession::GetInstance().System().GetProfileManager().GetUser(
725 static_cast<std::size_t>(0)); 726 static_cast<std::size_t>(0));
@@ -889,7 +890,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
889 890
890 const auto nandDir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); 891 const auto nandDir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
891 auto vfsNandDir = system.GetFilesystem()->OpenDirectory(Common::FS::PathToUTF8String(nandDir), 892 auto vfsNandDir = system.GetFilesystem()->OpenDirectory(Common::FS::PathToUTF8String(nandDir),
892 FileSys::Mode::Read); 893 FileSys::OpenMode::Read);
893 894
894 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 895 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
895 {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 896 {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml
index 655e49219..a5eba6474 100644
--- a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml
+++ b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml
@@ -11,12 +11,14 @@
11 android:id="@+id/appbar_about" 11 android:id="@+id/appbar_about"
12 android:layout_width="match_parent" 12 android:layout_width="match_parent"
13 android:layout_height="wrap_content" 13 android:layout_height="wrap_content"
14 android:fitsSystemWindows="true"> 14 android:fitsSystemWindows="true"
15 android:touchscreenBlocksFocus="false">
15 16
16 <com.google.android.material.appbar.MaterialToolbar 17 <com.google.android.material.appbar.MaterialToolbar
17 android:id="@+id/toolbar_about" 18 android:id="@+id/toolbar_about"
18 android:layout_width="match_parent" 19 android:layout_width="match_parent"
19 android:layout_height="?attr/actionBarSize" 20 android:layout_height="?attr/actionBarSize"
21 android:touchscreenBlocksFocus="false"
20 app:navigationIcon="@drawable/ic_back" 22 app:navigationIcon="@drawable/ic_back"
21 app:title="@string/about" /> 23 app:title="@string/about" />
22 24
@@ -28,6 +30,7 @@
28 android:layout_height="match_parent" 30 android:layout_height="match_parent"
29 android:fadeScrollbars="false" 31 android:fadeScrollbars="false"
30 android:scrollbars="vertical" 32 android:scrollbars="vertical"
33 android:defaultFocusHighlightEnabled="false"
31 app:layout_behavior="@string/appbar_scrolling_view_behavior"> 34 app:layout_behavior="@string/appbar_scrolling_view_behavior">
32 35
33 <LinearLayout 36 <LinearLayout
diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_game_info.xml b/src/android/app/src/main/res/layout-w600dp/fragment_game_info.xml
new file mode 100644
index 000000000..90d95dbb7
--- /dev/null
+++ b/src/android/app/src/main/res/layout-w600dp/fragment_game_info.xml
@@ -0,0 +1,155 @@
1<?xml version="1.0" encoding="utf-8"?>
2<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:id="@+id/coordinator_about"
6 android:layout_width="match_parent"
7 android:layout_height="match_parent"
8 android:background="?attr/colorSurface">
9
10 <com.google.android.material.appbar.AppBarLayout
11 android:id="@+id/appbar_info"
12 android:layout_width="match_parent"
13 android:layout_height="wrap_content"
14 android:fitsSystemWindows="true"
15 android:touchscreenBlocksFocus="false">
16
17 <com.google.android.material.appbar.MaterialToolbar
18 android:id="@+id/toolbar_info"
19 android:layout_width="match_parent"
20 android:layout_height="?attr/actionBarSize"
21 android:touchscreenBlocksFocus="false"
22 app:navigationIcon="@drawable/ic_back" />
23
24 </com.google.android.material.appbar.AppBarLayout>
25
26 <androidx.core.widget.NestedScrollView
27 android:id="@+id/scroll_info"
28 android:layout_width="match_parent"
29 android:layout_height="wrap_content"
30 android:defaultFocusHighlightEnabled="false"
31 app:layout_behavior="@string/appbar_scrolling_view_behavior">
32
33 <LinearLayout
34 android:id="@+id/content_info"
35 android:layout_width="match_parent"
36 android:layout_height="wrap_content"
37 android:orientation="horizontal"
38 android:paddingHorizontal="16dp"
39 android:baselineAligned="false">
40
41 <LinearLayout
42 android:layout_width="match_parent"
43 android:layout_height="match_parent"
44 android:orientation="vertical"
45 android:layout_weight="3"
46 android:gravity="top|center_horizontal"
47 android:paddingHorizontal="16dp">
48
49 <com.google.android.material.button.MaterialButton
50 android:id="@+id/button_copy"
51 style="@style/Widget.Material3.Button"
52 android:layout_width="wrap_content"
53 android:layout_height="wrap_content"
54 android:layout_marginTop="16dp"
55 android:text="@string/copy_details" />
56
57 <com.google.android.material.button.MaterialButton
58 android:id="@+id/button_verify_integrity"
59 style="@style/Widget.Material3.Button"
60 android:layout_width="wrap_content"
61 android:layout_height="wrap_content"
62 android:layout_marginTop="10dp"
63 android:text="@string/verify_integrity" />
64
65 </LinearLayout>
66
67 <LinearLayout
68 android:layout_width="match_parent"
69 android:layout_height="match_parent"
70 android:orientation="vertical"
71 android:layout_weight="1">
72
73 <com.google.android.material.textfield.TextInputLayout
74 android:id="@+id/path"
75 android:layout_width="match_parent"
76 android:layout_height="wrap_content"
77 android:paddingTop="16dp">
78
79 <com.google.android.material.textfield.TextInputEditText
80 android:id="@+id/path_field"
81 android:layout_width="match_parent"
82 android:layout_height="wrap_content"
83 android:editable="false"
84 android:importantForAutofill="no"
85 android:inputType="none"
86 android:minHeight="48dp"
87 android:textAlignment="viewStart"
88 tools:text="1.0.0" />
89
90 </com.google.android.material.textfield.TextInputLayout>
91
92 <com.google.android.material.textfield.TextInputLayout
93 android:id="@+id/program_id"
94 android:layout_width="match_parent"
95 android:layout_height="wrap_content"
96 android:paddingTop="16dp">
97
98 <com.google.android.material.textfield.TextInputEditText
99 android:id="@+id/program_id_field"
100 android:layout_width="match_parent"
101 android:layout_height="wrap_content"
102 android:editable="false"
103 android:importantForAutofill="no"
104 android:inputType="none"
105 android:minHeight="48dp"
106 android:textAlignment="viewStart"
107 tools:text="1.0.0" />
108
109 </com.google.android.material.textfield.TextInputLayout>
110
111 <com.google.android.material.textfield.TextInputLayout
112 android:id="@+id/developer"
113 android:layout_width="match_parent"
114 android:layout_height="wrap_content"
115 android:paddingTop="16dp">
116
117 <com.google.android.material.textfield.TextInputEditText
118 android:id="@+id/developer_field"
119 android:layout_width="match_parent"
120 android:layout_height="wrap_content"
121 android:editable="false"
122 android:importantForAutofill="no"
123 android:inputType="none"
124 android:minHeight="48dp"
125 android:textAlignment="viewStart"
126 tools:text="1.0.0" />
127
128 </com.google.android.material.textfield.TextInputLayout>
129
130 <com.google.android.material.textfield.TextInputLayout
131 android:id="@+id/version"
132 android:layout_width="match_parent"
133 android:layout_height="wrap_content"
134 android:paddingTop="16dp">
135
136 <com.google.android.material.textfield.TextInputEditText
137 android:id="@+id/version_field"
138 android:layout_width="match_parent"
139 android:layout_height="wrap_content"
140 android:editable="false"
141 android:importantForAutofill="no"
142 android:inputType="none"
143 android:minHeight="48dp"
144 android:textAlignment="viewStart"
145 tools:text="1.0.0" />
146
147 </com.google.android.material.textfield.TextInputLayout>
148
149 </LinearLayout>
150
151 </LinearLayout>
152
153 </androidx.core.widget.NestedScrollView>
154
155</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml b/src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml
index 551f255c0..7cdef569f 100644
--- a/src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml
+++ b/src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml
@@ -14,6 +14,7 @@
14 android:clipToPadding="false" 14 android:clipToPadding="false"
15 android:fadeScrollbars="false" 15 android:fadeScrollbars="false"
16 android:scrollbars="vertical" 16 android:scrollbars="vertical"
17 android:defaultFocusHighlightEnabled="false"
17 app:layout_constraintEnd_toEndOf="parent" 18 app:layout_constraintEnd_toEndOf="parent"
18 app:layout_constraintStart_toEndOf="@+id/icon_layout" 19 app:layout_constraintStart_toEndOf="@+id/icon_layout"
19 app:layout_constraintTop_toTopOf="parent"> 20 app:layout_constraintTop_toTopOf="parent">
diff --git a/src/android/app/src/main/res/layout/card_driver_option.xml b/src/android/app/src/main/res/layout/card_driver_option.xml
index 1dd9a6d7d..bda524f0f 100644
--- a/src/android/app/src/main/res/layout/card_driver_option.xml
+++ b/src/android/app/src/main/res/layout/card_driver_option.xml
@@ -23,6 +23,7 @@
23 android:layout_width="wrap_content" 23 android:layout_width="wrap_content"
24 android:layout_height="wrap_content" 24 android:layout_height="wrap_content"
25 android:layout_gravity="center_vertical" 25 android:layout_gravity="center_vertical"
26 android:focusable="false"
26 android:clickable="false" 27 android:clickable="false"
27 android:checked="false" /> 28 android:checked="false" />
28 29
diff --git a/src/android/app/src/main/res/layout/card_folder.xml b/src/android/app/src/main/res/layout/card_folder.xml
index 4e0c04b6b..ed4a7ca8f 100644
--- a/src/android/app/src/main/res/layout/card_folder.xml
+++ b/src/android/app/src/main/res/layout/card_folder.xml
@@ -6,16 +6,14 @@
6 android:layout_width="match_parent" 6 android:layout_width="match_parent"
7 android:layout_height="wrap_content" 7 android:layout_height="wrap_content"
8 android:layout_marginHorizontal="16dp" 8 android:layout_marginHorizontal="16dp"
9 android:layout_marginVertical="12dp" 9 android:layout_marginVertical="12dp">
10 android:focusable="true">
11 10
12 <androidx.constraintlayout.widget.ConstraintLayout 11 <androidx.constraintlayout.widget.ConstraintLayout
13 android:layout_width="match_parent" 12 android:layout_width="match_parent"
14 android:layout_height="wrap_content" 13 android:layout_height="wrap_content"
15 android:orientation="horizontal" 14 android:orientation="horizontal"
16 android:padding="16dp" 15 android:padding="16dp"
17 android:layout_gravity="center_vertical" 16 android:layout_gravity="center_vertical">
18 android:animateLayoutChanges="true">
19 17
20 <com.google.android.material.textview.MaterialTextView 18 <com.google.android.material.textview.MaterialTextView
21 android:id="@+id/path" 19 android:id="@+id/path"
diff --git a/src/android/app/src/main/res/layout/fragment_about.xml b/src/android/app/src/main/res/layout/fragment_about.xml
index 38090fa50..7f32e139a 100644
--- a/src/android/app/src/main/res/layout/fragment_about.xml
+++ b/src/android/app/src/main/res/layout/fragment_about.xml
@@ -11,12 +11,14 @@
11 android:id="@+id/appbar_about" 11 android:id="@+id/appbar_about"
12 android:layout_width="match_parent" 12 android:layout_width="match_parent"
13 android:layout_height="wrap_content" 13 android:layout_height="wrap_content"
14 android:fitsSystemWindows="true"> 14 android:fitsSystemWindows="true"
15 android:touchscreenBlocksFocus="false">
15 16
16 <com.google.android.material.appbar.MaterialToolbar 17 <com.google.android.material.appbar.MaterialToolbar
17 android:id="@+id/toolbar_about" 18 android:id="@+id/toolbar_about"
18 android:layout_width="match_parent" 19 android:layout_width="match_parent"
19 android:layout_height="?attr/actionBarSize" 20 android:layout_height="?attr/actionBarSize"
21 android:touchscreenBlocksFocus="false"
20 app:title="@string/about" 22 app:title="@string/about"
21 app:navigationIcon="@drawable/ic_back" /> 23 app:navigationIcon="@drawable/ic_back" />
22 24
@@ -28,6 +30,7 @@
28 android:layout_height="match_parent" 30 android:layout_height="match_parent"
29 android:scrollbars="vertical" 31 android:scrollbars="vertical"
30 android:fadeScrollbars="false" 32 android:fadeScrollbars="false"
33 android:defaultFocusHighlightEnabled="false"
31 app:layout_behavior="@string/appbar_scrolling_view_behavior"> 34 app:layout_behavior="@string/appbar_scrolling_view_behavior">
32 35
33 <LinearLayout 36 <LinearLayout
diff --git a/src/android/app/src/main/res/layout/fragment_addons.xml b/src/android/app/src/main/res/layout/fragment_addons.xml
index a25e82766..b029b4209 100644
--- a/src/android/app/src/main/res/layout/fragment_addons.xml
+++ b/src/android/app/src/main/res/layout/fragment_addons.xml
@@ -11,6 +11,7 @@
11 android:layout_width="match_parent" 11 android:layout_width="match_parent"
12 android:layout_height="wrap_content" 12 android:layout_height="wrap_content"
13 android:fitsSystemWindows="true" 13 android:fitsSystemWindows="true"
14 android:touchscreenBlocksFocus="false"
14 app:layout_constraintEnd_toEndOf="parent" 15 app:layout_constraintEnd_toEndOf="parent"
15 app:layout_constraintStart_toStartOf="parent" 16 app:layout_constraintStart_toStartOf="parent"
16 app:layout_constraintTop_toTopOf="parent"> 17 app:layout_constraintTop_toTopOf="parent">
@@ -19,6 +20,7 @@
19 android:id="@+id/toolbar_addons" 20 android:id="@+id/toolbar_addons"
20 android:layout_width="match_parent" 21 android:layout_width="match_parent"
21 android:layout_height="?attr/actionBarSize" 22 android:layout_height="?attr/actionBarSize"
23 android:touchscreenBlocksFocus="false"
22 app:navigationIcon="@drawable/ic_back" /> 24 app:navigationIcon="@drawable/ic_back" />
23 25
24 </com.google.android.material.appbar.AppBarLayout> 26 </com.google.android.material.appbar.AppBarLayout>
@@ -28,6 +30,8 @@
28 android:layout_width="match_parent" 30 android:layout_width="match_parent"
29 android:layout_height="0dp" 31 android:layout_height="0dp"
30 android:clipToPadding="false" 32 android:clipToPadding="false"
33 android:defaultFocusHighlightEnabled="false"
34 android:nextFocusDown="@id/button_install"
31 app:layout_behavior="@string/appbar_scrolling_view_behavior" 35 app:layout_behavior="@string/appbar_scrolling_view_behavior"
32 app:layout_constraintBottom_toBottomOf="parent" 36 app:layout_constraintBottom_toBottomOf="parent"
33 app:layout_constraintEnd_toEndOf="parent" 37 app:layout_constraintEnd_toEndOf="parent"
diff --git a/src/android/app/src/main/res/layout/fragment_applet_launcher.xml b/src/android/app/src/main/res/layout/fragment_applet_launcher.xml
index fe8fae40f..95e6d6a6b 100644
--- a/src/android/app/src/main/res/layout/fragment_applet_launcher.xml
+++ b/src/android/app/src/main/res/layout/fragment_applet_launcher.xml
@@ -10,12 +10,14 @@
10 android:id="@+id/appbar_applets" 10 android:id="@+id/appbar_applets"
11 android:layout_width="match_parent" 11 android:layout_width="match_parent"
12 android:layout_height="wrap_content" 12 android:layout_height="wrap_content"
13 android:fitsSystemWindows="true"> 13 android:fitsSystemWindows="true"
14 android:touchscreenBlocksFocus="false">
14 15
15 <com.google.android.material.appbar.MaterialToolbar 16 <com.google.android.material.appbar.MaterialToolbar
16 android:id="@+id/toolbar_applets" 17 android:id="@+id/toolbar_applets"
17 android:layout_width="match_parent" 18 android:layout_width="match_parent"
18 android:layout_height="?attr/actionBarSize" 19 android:layout_height="?attr/actionBarSize"
20 android:touchscreenBlocksFocus="false"
19 app:navigationIcon="@drawable/ic_back" 21 app:navigationIcon="@drawable/ic_back"
20 app:title="@string/applets" /> 22 app:title="@string/applets" />
21 23
diff --git a/src/android/app/src/main/res/layout/fragment_driver_manager.xml b/src/android/app/src/main/res/layout/fragment_driver_manager.xml
index 6cea2d164..56d8e6bb8 100644
--- a/src/android/app/src/main/res/layout/fragment_driver_manager.xml
+++ b/src/android/app/src/main/res/layout/fragment_driver_manager.xml
@@ -15,12 +15,14 @@
15 android:layout_width="match_parent" 15 android:layout_width="match_parent"
16 android:layout_height="wrap_content" 16 android:layout_height="wrap_content"
17 android:fitsSystemWindows="true" 17 android:fitsSystemWindows="true"
18 android:touchscreenBlocksFocus="false"
18 app:liftOnScrollTargetViewId="@id/list_drivers"> 19 app:liftOnScrollTargetViewId="@id/list_drivers">
19 20
20 <com.google.android.material.appbar.MaterialToolbar 21 <com.google.android.material.appbar.MaterialToolbar
21 android:id="@+id/toolbar_drivers" 22 android:id="@+id/toolbar_drivers"
22 android:layout_width="match_parent" 23 android:layout_width="match_parent"
23 android:layout_height="?attr/actionBarSize" 24 android:layout_height="?attr/actionBarSize"
25 android:touchscreenBlocksFocus="false"
24 app:navigationIcon="@drawable/ic_back" 26 app:navigationIcon="@drawable/ic_back"
25 app:title="@string/gpu_driver_manager" /> 27 app:title="@string/gpu_driver_manager" />
26 28
diff --git a/src/android/app/src/main/res/layout/fragment_early_access.xml b/src/android/app/src/main/res/layout/fragment_early_access.xml
index 644b4dd45..12e233afc 100644
--- a/src/android/app/src/main/res/layout/fragment_early_access.xml
+++ b/src/android/app/src/main/res/layout/fragment_early_access.xml
@@ -11,12 +11,14 @@
11 android:id="@+id/appbar_ea" 11 android:id="@+id/appbar_ea"
12 android:layout_width="match_parent" 12 android:layout_width="match_parent"
13 android:layout_height="wrap_content" 13 android:layout_height="wrap_content"
14 android:fitsSystemWindows="true"> 14 android:fitsSystemWindows="true"
15 android:touchscreenBlocksFocus="false">
15 16
16 <com.google.android.material.appbar.MaterialToolbar 17 <com.google.android.material.appbar.MaterialToolbar
17 android:id="@+id/toolbar_about" 18 android:id="@+id/toolbar_about"
18 android:layout_width="match_parent" 19 android:layout_width="match_parent"
19 android:layout_height="?attr/actionBarSize" 20 android:layout_height="?attr/actionBarSize"
21 android:touchscreenBlocksFocus="false"
20 app:navigationIcon="@drawable/ic_back" 22 app:navigationIcon="@drawable/ic_back"
21 app:title="@string/early_access" /> 23 app:title="@string/early_access" />
22 24
@@ -30,6 +32,7 @@
30 android:paddingBottom="20dp" 32 android:paddingBottom="20dp"
31 android:scrollbars="vertical" 33 android:scrollbars="vertical"
32 android:fadeScrollbars="false" 34 android:fadeScrollbars="false"
35 android:defaultFocusHighlightEnabled="false"
33 app:layout_behavior="@string/appbar_scrolling_view_behavior"> 36 app:layout_behavior="@string/appbar_scrolling_view_behavior">
34 37
35 <LinearLayout 38 <LinearLayout
diff --git a/src/android/app/src/main/res/layout/fragment_emulation.xml b/src/android/app/src/main/res/layout/fragment_emulation.xml
index 5252adf54..c01117d14 100644
--- a/src/android/app/src/main/res/layout/fragment_emulation.xml
+++ b/src/android/app/src/main/res/layout/fragment_emulation.xml
@@ -5,6 +5,7 @@
5 android:layout_width="match_parent" 5 android:layout_width="match_parent"
6 android:layout_height="match_parent" 6 android:layout_height="match_parent"
7 android:keepScreenOn="true" 7 android:keepScreenOn="true"
8 android:defaultFocusHighlightEnabled="false"
8 tools:context="org.yuzu.yuzu_emu.fragments.EmulationFragment" 9 tools:context="org.yuzu.yuzu_emu.fragments.EmulationFragment"
9 tools:openDrawer="start"> 10 tools:openDrawer="start">
10 11
@@ -24,7 +25,8 @@
24 android:layout_height="match_parent" 25 android:layout_height="match_parent"
25 android:layout_gravity="center" 26 android:layout_gravity="center"
26 android:focusable="false" 27 android:focusable="false"
27 android:focusableInTouchMode="false" /> 28 android:focusableInTouchMode="false"
29 android:defaultFocusHighlightEnabled="false" />
28 30
29 <com.google.android.material.card.MaterialCardView 31 <com.google.android.material.card.MaterialCardView
30 android:id="@+id/loading_indicator" 32 android:id="@+id/loading_indicator"
@@ -32,7 +34,7 @@
32 android:layout_width="wrap_content" 34 android:layout_width="wrap_content"
33 android:layout_height="wrap_content" 35 android:layout_height="wrap_content"
34 android:layout_gravity="center" 36 android:layout_gravity="center"
35 android:focusable="false" 37 android:defaultFocusHighlightEnabled="false"
36 android:clickable="false"> 38 android:clickable="false">
37 39
38 <androidx.constraintlayout.widget.ConstraintLayout 40 <androidx.constraintlayout.widget.ConstraintLayout
@@ -118,6 +120,7 @@
118 android:layout_gravity="center" 120 android:layout_gravity="center"
119 android:focusable="true" 121 android:focusable="true"
120 android:focusableInTouchMode="true" 122 android:focusableInTouchMode="true"
123 android:defaultFocusHighlightEnabled="false"
121 android:visibility="invisible" /> 124 android:visibility="invisible" />
122 125
123 <Button 126 <Button
@@ -160,6 +163,7 @@
160 android:layout_width="wrap_content" 163 android:layout_width="wrap_content"
161 android:layout_height="match_parent" 164 android:layout_height="match_parent"
162 android:layout_gravity="start" 165 android:layout_gravity="start"
166 android:focusedByDefault="true"
163 app:headerLayout="@layout/header_in_game" 167 app:headerLayout="@layout/header_in_game"
164 app:menu="@menu/menu_in_game" 168 app:menu="@menu/menu_in_game"
165 tools:visibility="gone" /> 169 tools:visibility="gone" />
diff --git a/src/android/app/src/main/res/layout/fragment_folders.xml b/src/android/app/src/main/res/layout/fragment_folders.xml
index 74f2f3754..b5c7676d8 100644
--- a/src/android/app/src/main/res/layout/fragment_folders.xml
+++ b/src/android/app/src/main/res/layout/fragment_folders.xml
@@ -15,12 +15,14 @@
15 android:layout_width="match_parent" 15 android:layout_width="match_parent"
16 android:layout_height="wrap_content" 16 android:layout_height="wrap_content"
17 android:fitsSystemWindows="true" 17 android:fitsSystemWindows="true"
18 android:touchscreenBlocksFocus="false"
18 app:liftOnScrollTargetViewId="@id/list_folders"> 19 app:liftOnScrollTargetViewId="@id/list_folders">
19 20
20 <com.google.android.material.appbar.MaterialToolbar 21 <com.google.android.material.appbar.MaterialToolbar
21 android:id="@+id/toolbar_folders" 22 android:id="@+id/toolbar_folders"
22 android:layout_width="match_parent" 23 android:layout_width="match_parent"
23 android:layout_height="?attr/actionBarSize" 24 android:layout_height="?attr/actionBarSize"
25 android:touchscreenBlocksFocus="false"
24 app:navigationIcon="@drawable/ic_back" 26 app:navigationIcon="@drawable/ic_back"
25 app:title="@string/game_folders" /> 27 app:title="@string/game_folders" />
26 28
@@ -31,6 +33,7 @@
31 android:layout_width="match_parent" 33 android:layout_width="match_parent"
32 android:layout_height="wrap_content" 34 android:layout_height="wrap_content"
33 android:clipToPadding="false" 35 android:clipToPadding="false"
36 android:defaultFocusHighlightEnabled="false"
34 app:layout_behavior="@string/appbar_scrolling_view_behavior" /> 37 app:layout_behavior="@string/appbar_scrolling_view_behavior" />
35 38
36 </androidx.coordinatorlayout.widget.CoordinatorLayout> 39 </androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/src/android/app/src/main/res/layout/fragment_game_info.xml b/src/android/app/src/main/res/layout/fragment_game_info.xml
index 53af15787..f29e7e376 100644
--- a/src/android/app/src/main/res/layout/fragment_game_info.xml
+++ b/src/android/app/src/main/res/layout/fragment_game_info.xml
@@ -11,12 +11,14 @@
11 android:id="@+id/appbar_info" 11 android:id="@+id/appbar_info"
12 android:layout_width="match_parent" 12 android:layout_width="match_parent"
13 android:layout_height="wrap_content" 13 android:layout_height="wrap_content"
14 android:touchscreenBlocksFocus="false"
14 android:fitsSystemWindows="true"> 15 android:fitsSystemWindows="true">
15 16
16 <com.google.android.material.appbar.MaterialToolbar 17 <com.google.android.material.appbar.MaterialToolbar
17 android:id="@+id/toolbar_info" 18 android:id="@+id/toolbar_info"
18 android:layout_width="match_parent" 19 android:layout_width="match_parent"
19 android:layout_height="?attr/actionBarSize" 20 android:layout_height="?attr/actionBarSize"
21 android:touchscreenBlocksFocus="false"
20 app:navigationIcon="@drawable/ic_back" /> 22 app:navigationIcon="@drawable/ic_back" />
21 23
22 </com.google.android.material.appbar.AppBarLayout> 24 </com.google.android.material.appbar.AppBarLayout>
@@ -25,6 +27,7 @@
25 android:id="@+id/scroll_info" 27 android:id="@+id/scroll_info"
26 android:layout_width="match_parent" 28 android:layout_width="match_parent"
27 android:layout_height="wrap_content" 29 android:layout_height="wrap_content"
30 android:defaultFocusHighlightEnabled="false"
28 app:layout_behavior="@string/appbar_scrolling_view_behavior"> 31 app:layout_behavior="@string/appbar_scrolling_view_behavior">
29 32
30 <LinearLayout 33 <LinearLayout
diff --git a/src/android/app/src/main/res/layout/fragment_game_properties.xml b/src/android/app/src/main/res/layout/fragment_game_properties.xml
index cadd0bc4a..436ebd79d 100644
--- a/src/android/app/src/main/res/layout/fragment_game_properties.xml
+++ b/src/android/app/src/main/res/layout/fragment_game_properties.xml
@@ -12,7 +12,8 @@
12 android:layout_height="match_parent" 12 android:layout_height="match_parent"
13 android:scrollbars="vertical" 13 android:scrollbars="vertical"
14 android:fadeScrollbars="false" 14 android:fadeScrollbars="false"
15 android:clipToPadding="false"> 15 android:clipToPadding="false"
16 android:defaultFocusHighlightEnabled="false">
16 17
17 <LinearLayout 18 <LinearLayout
18 android:id="@+id/layout_all" 19 android:id="@+id/layout_all"
@@ -86,7 +87,7 @@
86 android:id="@+id/list_properties" 87 android:id="@+id/list_properties"
87 android:layout_width="match_parent" 88 android:layout_width="match_parent"
88 android:layout_height="match_parent" 89 android:layout_height="match_parent"
89 tools:listitem="@layout/card_simple_outlined" /> 90 android:defaultFocusHighlightEnabled="false" />
90 91
91 </LinearLayout> 92 </LinearLayout>
92 93
diff --git a/src/android/app/src/main/res/layout/fragment_games.xml b/src/android/app/src/main/res/layout/fragment_games.xml
index a0568668a..cc280b1ff 100644
--- a/src/android/app/src/main/res/layout/fragment_games.xml
+++ b/src/android/app/src/main/res/layout/fragment_games.xml
@@ -27,6 +27,7 @@
27 android:layout_width="match_parent" 27 android:layout_width="match_parent"
28 android:layout_height="match_parent" 28 android:layout_height="match_parent"
29 android:clipToPadding="false" 29 android:clipToPadding="false"
30 android:defaultFocusHighlightEnabled="false"
30 tools:listitem="@layout/card_game" /> 31 tools:listitem="@layout/card_game" />
31 32
32 </RelativeLayout> 33 </RelativeLayout>
diff --git a/src/android/app/src/main/res/layout/fragment_home_settings.xml b/src/android/app/src/main/res/layout/fragment_home_settings.xml
index d84093ba3..c179f9341 100644
--- a/src/android/app/src/main/res/layout/fragment_home_settings.xml
+++ b/src/android/app/src/main/res/layout/fragment_home_settings.xml
@@ -7,7 +7,8 @@
7 android:background="?attr/colorSurface" 7 android:background="?attr/colorSurface"
8 android:scrollbars="vertical" 8 android:scrollbars="vertical"
9 android:fadeScrollbars="false" 9 android:fadeScrollbars="false"
10 android:clipToPadding="false"> 10 android:clipToPadding="false"
11 android:defaultFocusHighlightEnabled="false">
11 12
12 <androidx.appcompat.widget.LinearLayoutCompat 13 <androidx.appcompat.widget.LinearLayoutCompat
13 android:id="@+id/linear_layout_settings" 14 android:id="@+id/linear_layout_settings"
diff --git a/src/android/app/src/main/res/layout/fragment_installables.xml b/src/android/app/src/main/res/layout/fragment_installables.xml
index 3a4df81a6..47ef3869f 100644
--- a/src/android/app/src/main/res/layout/fragment_installables.xml
+++ b/src/android/app/src/main/res/layout/fragment_installables.xml
@@ -10,12 +10,14 @@
10 android:id="@+id/appbar_installables" 10 android:id="@+id/appbar_installables"
11 android:layout_width="match_parent" 11 android:layout_width="match_parent"
12 android:layout_height="wrap_content" 12 android:layout_height="wrap_content"
13 android:fitsSystemWindows="true"> 13 android:fitsSystemWindows="true"
14 android:touchscreenBlocksFocus="false">
14 15
15 <com.google.android.material.appbar.MaterialToolbar 16 <com.google.android.material.appbar.MaterialToolbar
16 android:id="@+id/toolbar_installables" 17 android:id="@+id/toolbar_installables"
17 android:layout_width="match_parent" 18 android:layout_width="match_parent"
18 android:layout_height="?attr/actionBarSize" 19 android:layout_height="?attr/actionBarSize"
20 android:touchscreenBlocksFocus="false"
19 app:title="@string/manage_yuzu_data" 21 app:title="@string/manage_yuzu_data"
20 app:navigationIcon="@drawable/ic_back" /> 22 app:navigationIcon="@drawable/ic_back" />
21 23
diff --git a/src/android/app/src/main/res/layout/fragment_licenses.xml b/src/android/app/src/main/res/layout/fragment_licenses.xml
index 6b31ff5b4..59d68b112 100644
--- a/src/android/app/src/main/res/layout/fragment_licenses.xml
+++ b/src/android/app/src/main/res/layout/fragment_licenses.xml
@@ -10,12 +10,14 @@
10 android:id="@+id/appbar_licenses" 10 android:id="@+id/appbar_licenses"
11 android:layout_width="match_parent" 11 android:layout_width="match_parent"
12 android:layout_height="wrap_content" 12 android:layout_height="wrap_content"
13 android:fitsSystemWindows="true"> 13 android:fitsSystemWindows="true"
14 android:touchscreenBlocksFocus="false">
14 15
15 <com.google.android.material.appbar.MaterialToolbar 16 <com.google.android.material.appbar.MaterialToolbar
16 android:id="@+id/toolbar_licenses" 17 android:id="@+id/toolbar_licenses"
17 android:layout_width="match_parent" 18 android:layout_width="match_parent"
18 android:layout_height="?attr/actionBarSize" 19 android:layout_height="?attr/actionBarSize"
20 android:touchscreenBlocksFocus="false"
19 app:title="@string/licenses" 21 app:title="@string/licenses"
20 app:navigationIcon="@drawable/ic_back" /> 22 app:navigationIcon="@drawable/ic_back" />
21 23
diff --git a/src/android/app/src/main/res/layout/fragment_settings.xml b/src/android/app/src/main/res/layout/fragment_settings.xml
index ebedbf1ec..110c70eef 100644
--- a/src/android/app/src/main/res/layout/fragment_settings.xml
+++ b/src/android/app/src/main/res/layout/fragment_settings.xml
@@ -11,6 +11,7 @@
11 android:layout_width="match_parent" 11 android:layout_width="match_parent"
12 android:layout_height="wrap_content" 12 android:layout_height="wrap_content"
13 android:fitsSystemWindows="true" 13 android:fitsSystemWindows="true"
14 android:touchscreenBlocksFocus="false"
14 app:elevation="0dp"> 15 app:elevation="0dp">
15 16
16 <com.google.android.material.appbar.CollapsingToolbarLayout 17 <com.google.android.material.appbar.CollapsingToolbarLayout
@@ -24,6 +25,7 @@
24 android:id="@+id/toolbar_settings" 25 android:id="@+id/toolbar_settings"
25 android:layout_width="match_parent" 26 android:layout_width="match_parent"
26 android:layout_height="?attr/actionBarSize" 27 android:layout_height="?attr/actionBarSize"
28 android:touchscreenBlocksFocus="false"
27 app:layout_collapseMode="pin" 29 app:layout_collapseMode="pin"
28 app:navigationIcon="@drawable/ic_back" /> 30 app:navigationIcon="@drawable/ic_back" />
29 31
diff --git a/src/android/app/src/main/res/layout/list_item_addon.xml b/src/android/app/src/main/res/layout/list_item_addon.xml
index 3a1382fe2..9b1c0e6fc 100644
--- a/src/android/app/src/main/res/layout/list_item_addon.xml
+++ b/src/android/app/src/main/res/layout/list_item_addon.xml
@@ -6,7 +6,7 @@
6 android:layout_width="match_parent" 6 android:layout_width="match_parent"
7 android:layout_height="wrap_content" 7 android:layout_height="wrap_content"
8 android:background="?attr/selectableItemBackground" 8 android:background="?attr/selectableItemBackground"
9 android:focusable="true" 9 android:focusable="false"
10 android:paddingHorizontal="20dp" 10 android:paddingHorizontal="20dp"
11 android:paddingVertical="16dp"> 11 android:paddingVertical="16dp">
12 12
diff --git a/src/android/app/src/main/res/layout/list_item_settings_header.xml b/src/android/app/src/main/res/layout/list_item_settings_header.xml
index 21276b19e..615860368 100644
--- a/src/android/app/src/main/res/layout/list_item_settings_header.xml
+++ b/src/android/app/src/main/res/layout/list_item_settings_header.xml
@@ -12,4 +12,5 @@
12 android:textAlignment="viewStart" 12 android:textAlignment="viewStart"
13 android:textColor="?attr/colorPrimary" 13 android:textColor="?attr/colorPrimary"
14 android:textStyle="bold" 14 android:textStyle="bold"
15 android:focusable="false"
15 tools:text="CPU Settings" /> 16 tools:text="CPU Settings" />
diff --git a/src/common/overflow.h b/src/common/overflow.h
index 44d8e7e73..e184ead95 100644
--- a/src/common/overflow.h
+++ b/src/common/overflow.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <algorithm>
6#include <type_traits> 7#include <type_traits>
7#include "bit_cast.h" 8#include "bit_cast.h"
8 9
@@ -19,4 +20,21 @@ inline T WrappingAdd(T lhs, T rhs) {
19 return BitCast<T>(lhs_u + rhs_u); 20 return BitCast<T>(lhs_u + rhs_u);
20} 21}
21 22
23template <typename T>
24 requires(std::is_integral_v<T> && std::is_signed_v<T>)
25inline bool CanAddWithoutOverflow(T lhs, T rhs) {
26#ifdef _MSC_VER
27 if (lhs >= 0 && rhs >= 0) {
28 return WrappingAdd(lhs, rhs) >= std::max(lhs, rhs);
29 } else if (lhs < 0 && rhs < 0) {
30 return WrappingAdd(lhs, rhs) <= std::min(lhs, rhs);
31 } else {
32 return true;
33 }
34#else
35 T res;
36 return !__builtin_add_overflow(lhs, rhs, &res);
37#endif
38}
39
22} // namespace Common 40} // namespace Common
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 45a0d8746..347bbf2d0 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -20,28 +20,49 @@ add_library(core STATIC
20 cpu_manager.h 20 cpu_manager.h
21 crypto/aes_util.cpp 21 crypto/aes_util.cpp
22 crypto/aes_util.h 22 crypto/aes_util.h
23 crypto/ctr_encryption_layer.cpp
24 crypto/ctr_encryption_layer.h
23 crypto/encryption_layer.cpp 25 crypto/encryption_layer.cpp
24 crypto/encryption_layer.h 26 crypto/encryption_layer.h
25 crypto/key_manager.cpp 27 crypto/key_manager.cpp
26 crypto/key_manager.h 28 crypto/key_manager.h
27 crypto/partition_data_manager.cpp 29 crypto/partition_data_manager.cpp
28 crypto/partition_data_manager.h 30 crypto/partition_data_manager.h
29 crypto/ctr_encryption_layer.cpp
30 crypto/ctr_encryption_layer.h
31 crypto/xts_encryption_layer.cpp 31 crypto/xts_encryption_layer.cpp
32 crypto/xts_encryption_layer.h 32 crypto/xts_encryption_layer.h
33 debugger/debugger_interface.h
34 debugger/debugger.cpp 33 debugger/debugger.cpp
35 debugger/debugger.h 34 debugger/debugger.h
36 debugger/gdbstub_arch.cpp 35 debugger/debugger_interface.h
37 debugger/gdbstub_arch.h
38 debugger/gdbstub.cpp 36 debugger/gdbstub.cpp
39 debugger/gdbstub.h 37 debugger/gdbstub.h
38 debugger/gdbstub_arch.cpp
39 debugger/gdbstub_arch.h
40 device_memory_manager.h 40 device_memory_manager.h
41 device_memory_manager.inc 41 device_memory_manager.inc
42 device_memory.cpp 42 device_memory.cpp
43 device_memory.h 43 device_memory.h
44 file_sys/bis_factory.cpp
45 file_sys/bis_factory.h
46 file_sys/card_image.cpp
47 file_sys/card_image.h
48 file_sys/common_funcs.h
49 file_sys/content_archive.cpp
50 file_sys/content_archive.h
51 file_sys/control_metadata.cpp
52 file_sys/control_metadata.h
53 file_sys/errors.h
54 file_sys/fs_directory.h
55 file_sys/fs_file.h
56 file_sys/fs_filesystem.h
57 file_sys/fs_memory_management.h
58 file_sys/fs_operate_range.h
59 file_sys/fs_path.h
60 file_sys/fs_path_utility.h
61 file_sys/fs_string_util.h
62 file_sys/fsmitm_romfsbuild.cpp
63 file_sys/fsmitm_romfsbuild.h
44 file_sys/fssystem/fs_i_storage.h 64 file_sys/fssystem/fs_i_storage.h
65 file_sys/fssystem/fs_types.h
45 file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp 66 file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
46 file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h 67 file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h
47 file_sys/fssystem/fssystem_aes_ctr_storage.cpp 68 file_sys/fssystem/fssystem_aes_ctr_storage.cpp
@@ -83,25 +104,10 @@ add_library(core STATIC
83 file_sys/fssystem/fssystem_switch_storage.h 104 file_sys/fssystem/fssystem_switch_storage.h
84 file_sys/fssystem/fssystem_utility.cpp 105 file_sys/fssystem/fssystem_utility.cpp
85 file_sys/fssystem/fssystem_utility.h 106 file_sys/fssystem/fssystem_utility.h
86 file_sys/fssystem/fs_types.h
87 file_sys/bis_factory.cpp
88 file_sys/bis_factory.h
89 file_sys/card_image.cpp
90 file_sys/card_image.h
91 file_sys/common_funcs.h
92 file_sys/content_archive.cpp
93 file_sys/content_archive.h
94 file_sys/control_metadata.cpp
95 file_sys/control_metadata.h
96 file_sys/directory.h
97 file_sys/errors.h
98 file_sys/fsmitm_romfsbuild.cpp
99 file_sys/fsmitm_romfsbuild.h
100 file_sys/ips_layer.cpp 107 file_sys/ips_layer.cpp
101 file_sys/ips_layer.h 108 file_sys/ips_layer.h
102 file_sys/kernel_executable.cpp 109 file_sys/kernel_executable.cpp
103 file_sys/kernel_executable.h 110 file_sys/kernel_executable.h
104 file_sys/mode.h
105 file_sys/nca_metadata.cpp 111 file_sys/nca_metadata.cpp
106 file_sys/nca_metadata.h 112 file_sys/nca_metadata.h
107 file_sys/partition_filesystem.cpp 113 file_sys/partition_filesystem.cpp
@@ -146,22 +152,22 @@ add_library(core STATIC
146 file_sys/system_archive/system_version.h 152 file_sys/system_archive/system_version.h
147 file_sys/system_archive/time_zone_binary.cpp 153 file_sys/system_archive/time_zone_binary.cpp
148 file_sys/system_archive/time_zone_binary.h 154 file_sys/system_archive/time_zone_binary.h
149 file_sys/vfs.cpp 155 file_sys/vfs/vfs.cpp
150 file_sys/vfs.h 156 file_sys/vfs/vfs.h
151 file_sys/vfs_cached.cpp 157 file_sys/vfs/vfs_cached.cpp
152 file_sys/vfs_cached.h 158 file_sys/vfs/vfs_cached.h
153 file_sys/vfs_concat.cpp 159 file_sys/vfs/vfs_concat.cpp
154 file_sys/vfs_concat.h 160 file_sys/vfs/vfs_concat.h
155 file_sys/vfs_layered.cpp 161 file_sys/vfs/vfs_layered.cpp
156 file_sys/vfs_layered.h 162 file_sys/vfs/vfs_layered.h
157 file_sys/vfs_offset.cpp 163 file_sys/vfs/vfs_offset.cpp
158 file_sys/vfs_offset.h 164 file_sys/vfs/vfs_offset.h
159 file_sys/vfs_real.cpp 165 file_sys/vfs/vfs_real.cpp
160 file_sys/vfs_real.h 166 file_sys/vfs/vfs_real.h
161 file_sys/vfs_static.h 167 file_sys/vfs/vfs_static.h
162 file_sys/vfs_types.h 168 file_sys/vfs/vfs_types.h
163 file_sys/vfs_vector.cpp 169 file_sys/vfs/vfs_vector.cpp
164 file_sys/vfs_vector.h 170 file_sys/vfs/vfs_vector.h
165 file_sys/xts_archive.cpp 171 file_sys/xts_archive.cpp
166 file_sys/xts_archive.h 172 file_sys/xts_archive.h
167 frontend/applets/cabinet.cpp 173 frontend/applets/cabinet.cpp
@@ -194,7 +200,6 @@ add_library(core STATIC
194 hle/kernel/board/nintendo/nx/secure_monitor.h 200 hle/kernel/board/nintendo/nx/secure_monitor.h
195 hle/kernel/code_set.cpp 201 hle/kernel/code_set.cpp
196 hle/kernel/code_set.h 202 hle/kernel/code_set.h
197 hle/kernel/svc_results.h
198 hle/kernel/global_scheduler_context.cpp 203 hle/kernel/global_scheduler_context.cpp
199 hle/kernel/global_scheduler_context.h 204 hle/kernel/global_scheduler_context.h
200 hle/kernel/init/init_slab_setup.cpp 205 hle/kernel/init/init_slab_setup.cpp
@@ -204,11 +209,11 @@ add_library(core STATIC
204 hle/kernel/k_address_arbiter.h 209 hle/kernel/k_address_arbiter.h
205 hle/kernel/k_address_space_info.cpp 210 hle/kernel/k_address_space_info.cpp
206 hle/kernel/k_address_space_info.h 211 hle/kernel/k_address_space_info.h
212 hle/kernel/k_affinity_mask.h
207 hle/kernel/k_auto_object.cpp 213 hle/kernel/k_auto_object.cpp
208 hle/kernel/k_auto_object.h 214 hle/kernel/k_auto_object.h
209 hle/kernel/k_auto_object_container.cpp 215 hle/kernel/k_auto_object_container.cpp
210 hle/kernel/k_auto_object_container.h 216 hle/kernel/k_auto_object_container.h
211 hle/kernel/k_affinity_mask.h
212 hle/kernel/k_capabilities.cpp 217 hle/kernel/k_capabilities.cpp
213 hle/kernel/k_capabilities.h 218 hle/kernel/k_capabilities.h
214 hle/kernel/k_class_token.cpp 219 hle/kernel/k_class_token.cpp
@@ -232,9 +237,9 @@ add_library(core STATIC
232 hle/kernel/k_event_info.h 237 hle/kernel/k_event_info.h
233 hle/kernel/k_handle_table.cpp 238 hle/kernel/k_handle_table.cpp
234 hle/kernel/k_handle_table.h 239 hle/kernel/k_handle_table.h
235 hle/kernel/k_hardware_timer_base.h
236 hle/kernel/k_hardware_timer.cpp 240 hle/kernel/k_hardware_timer.cpp
237 hle/kernel/k_hardware_timer.h 241 hle/kernel/k_hardware_timer.h
242 hle/kernel/k_hardware_timer_base.h
238 hle/kernel/k_interrupt_manager.cpp 243 hle/kernel/k_interrupt_manager.cpp
239 hle/kernel/k_interrupt_manager.h 244 hle/kernel/k_interrupt_manager.h
240 hle/kernel/k_light_client_session.cpp 245 hle/kernel/k_light_client_session.cpp
@@ -261,10 +266,10 @@ add_library(core STATIC
261 hle/kernel/k_page_bitmap.h 266 hle/kernel/k_page_bitmap.h
262 hle/kernel/k_page_buffer.cpp 267 hle/kernel/k_page_buffer.cpp
263 hle/kernel/k_page_buffer.h 268 hle/kernel/k_page_buffer.h
264 hle/kernel/k_page_heap.cpp
265 hle/kernel/k_page_heap.h
266 hle/kernel/k_page_group.cpp 269 hle/kernel/k_page_group.cpp
267 hle/kernel/k_page_group.h 270 hle/kernel/k_page_group.h
271 hle/kernel/k_page_heap.cpp
272 hle/kernel/k_page_heap.h
268 hle/kernel/k_page_table.h 273 hle/kernel/k_page_table.h
269 hle/kernel/k_page_table_base.cpp 274 hle/kernel/k_page_table_base.cpp
270 hle/kernel/k_page_table_base.h 275 hle/kernel/k_page_table_base.h
@@ -329,8 +334,6 @@ add_library(core STATIC
329 hle/kernel/slab_helpers.h 334 hle/kernel/slab_helpers.h
330 hle/kernel/svc.cpp 335 hle/kernel/svc.cpp
331 hle/kernel/svc.h 336 hle/kernel/svc.h
332 hle/kernel/svc_common.h
333 hle/kernel/svc_types.h
334 hle/kernel/svc/svc_activity.cpp 337 hle/kernel/svc/svc_activity.cpp
335 hle/kernel/svc/svc_address_arbiter.cpp 338 hle/kernel/svc/svc_address_arbiter.cpp
336 hle/kernel/svc/svc_address_translation.cpp 339 hle/kernel/svc/svc_address_translation.cpp
@@ -368,6 +371,9 @@ add_library(core STATIC
368 hle/kernel/svc/svc_thread_profiler.cpp 371 hle/kernel/svc/svc_thread_profiler.cpp
369 hle/kernel/svc/svc_tick.cpp 372 hle/kernel/svc/svc_tick.cpp
370 hle/kernel/svc/svc_transfer_memory.cpp 373 hle/kernel/svc/svc_transfer_memory.cpp
374 hle/kernel/svc_common.h
375 hle/kernel/svc_results.h
376 hle/kernel/svc_types.h
371 hle/result.h 377 hle/result.h
372 hle/service/acc/acc.cpp 378 hle/service/acc/acc.cpp
373 hle/service/acc/acc.h 379 hle/service/acc/acc.h
@@ -486,14 +492,25 @@ add_library(core STATIC
486 hle/service/fatal/fatal_p.h 492 hle/service/fatal/fatal_p.h
487 hle/service/fatal/fatal_u.cpp 493 hle/service/fatal/fatal_u.cpp
488 hle/service/fatal/fatal_u.h 494 hle/service/fatal/fatal_u.h
495 hle/service/fgm/fgm.cpp
496 hle/service/fgm/fgm.h
489 hle/service/filesystem/filesystem.cpp 497 hle/service/filesystem/filesystem.cpp
490 hle/service/filesystem/filesystem.h 498 hle/service/filesystem/filesystem.h
491 hle/service/filesystem/fsp_ldr.cpp 499 hle/service/filesystem/fsp/fs_i_directory.cpp
492 hle/service/filesystem/fsp_ldr.h 500 hle/service/filesystem/fsp/fs_i_directory.h
493 hle/service/filesystem/fsp_pr.cpp 501 hle/service/filesystem/fsp/fs_i_file.cpp
494 hle/service/filesystem/fsp_pr.h 502 hle/service/filesystem/fsp/fs_i_file.h
495 hle/service/filesystem/fsp_srv.cpp 503 hle/service/filesystem/fsp/fs_i_filesystem.cpp
496 hle/service/filesystem/fsp_srv.h 504 hle/service/filesystem/fsp/fs_i_filesystem.h
505 hle/service/filesystem/fsp/fs_i_storage.cpp
506 hle/service/filesystem/fsp/fs_i_storage.h
507 hle/service/filesystem/fsp/fsp_ldr.cpp
508 hle/service/filesystem/fsp/fsp_ldr.h
509 hle/service/filesystem/fsp/fsp_pr.cpp
510 hle/service/filesystem/fsp/fsp_pr.h
511 hle/service/filesystem/fsp/fsp_srv.cpp
512 hle/service/filesystem/fsp/fsp_srv.h
513 hle/service/filesystem/fsp/fsp_util.h
497 hle/service/filesystem/romfs_controller.cpp 514 hle/service/filesystem/romfs_controller.cpp
498 hle/service/filesystem/romfs_controller.h 515 hle/service/filesystem/romfs_controller.h
499 hle/service/filesystem/save_data_controller.cpp 516 hle/service/filesystem/save_data_controller.cpp
@@ -551,13 +568,18 @@ add_library(core STATIC
551 hle/service/hid/irs.h 568 hle/service/hid/irs.h
552 hle/service/hid/xcd.cpp 569 hle/service/hid/xcd.cpp
553 hle/service/hid/xcd.h 570 hle/service/hid/xcd.h
571 hle/service/hle_ipc.cpp
572 hle/service/hle_ipc.h
573 hle/service/ipc_helpers.h
574 hle/service/kernel_helpers.cpp
575 hle/service/kernel_helpers.h
554 hle/service/lbl/lbl.cpp 576 hle/service/lbl/lbl.cpp
555 hle/service/lbl/lbl.h 577 hle/service/lbl/lbl.h
556 hle/service/ldn/lan_discovery.cpp 578 hle/service/ldn/lan_discovery.cpp
557 hle/service/ldn/lan_discovery.h 579 hle/service/ldn/lan_discovery.h
558 hle/service/ldn/ldn_results.h
559 hle/service/ldn/ldn.cpp 580 hle/service/ldn/ldn.cpp
560 hle/service/ldn/ldn.h 581 hle/service/ldn/ldn.h
582 hle/service/ldn/ldn_results.h
561 hle/service/ldn/ldn_types.h 583 hle/service/ldn/ldn_types.h
562 hle/service/ldr/ldr.cpp 584 hle/service/ldr/ldr.cpp
563 hle/service/ldr/ldr.h 585 hle/service/ldr/ldr.h
@@ -565,16 +587,6 @@ add_library(core STATIC
565 hle/service/lm/lm.h 587 hle/service/lm/lm.h
566 hle/service/mig/mig.cpp 588 hle/service/mig/mig.cpp
567 hle/service/mig/mig.h 589 hle/service/mig/mig.h
568 hle/service/mii/types/char_info.cpp
569 hle/service/mii/types/char_info.h
570 hle/service/mii/types/core_data.cpp
571 hle/service/mii/types/core_data.h
572 hle/service/mii/types/raw_data.cpp
573 hle/service/mii/types/raw_data.h
574 hle/service/mii/types/store_data.cpp
575 hle/service/mii/types/store_data.h
576 hle/service/mii/types/ver3_store_data.cpp
577 hle/service/mii/types/ver3_store_data.h
578 hle/service/mii/mii.cpp 590 hle/service/mii/mii.cpp
579 hle/service/mii/mii.h 591 hle/service/mii/mii.h
580 hle/service/mii/mii_database.cpp 592 hle/service/mii/mii_database.cpp
@@ -586,10 +598,22 @@ add_library(core STATIC
586 hle/service/mii/mii_result.h 598 hle/service/mii/mii_result.h
587 hle/service/mii/mii_types.h 599 hle/service/mii/mii_types.h
588 hle/service/mii/mii_util.h 600 hle/service/mii/mii_util.h
601 hle/service/mii/types/char_info.cpp
602 hle/service/mii/types/char_info.h
603 hle/service/mii/types/core_data.cpp
604 hle/service/mii/types/core_data.h
605 hle/service/mii/types/raw_data.cpp
606 hle/service/mii/types/raw_data.h
607 hle/service/mii/types/store_data.cpp
608 hle/service/mii/types/store_data.h
609 hle/service/mii/types/ver3_store_data.cpp
610 hle/service/mii/types/ver3_store_data.h
589 hle/service/mm/mm_u.cpp 611 hle/service/mm/mm_u.cpp
590 hle/service/mm/mm_u.h 612 hle/service/mm/mm_u.h
591 hle/service/mnpp/mnpp_app.cpp 613 hle/service/mnpp/mnpp_app.cpp
592 hle/service/mnpp/mnpp_app.h 614 hle/service/mnpp/mnpp_app.h
615 hle/service/mutex.cpp
616 hle/service/mutex.h
593 hle/service/ncm/ncm.cpp 617 hle/service/ncm/ncm.cpp
594 hle/service/ncm/ncm.h 618 hle/service/ncm/ncm.h
595 hle/service/nfc/common/amiibo_crypto.cpp 619 hle/service/nfc/common/amiibo_crypto.cpp
@@ -759,19 +783,12 @@ add_library(core STATIC
759 hle/service/ptm/ptm.h 783 hle/service/ptm/ptm.h
760 hle/service/ptm/ts.cpp 784 hle/service/ptm/ts.cpp
761 hle/service/ptm/ts.h 785 hle/service/ptm/ts.h
762 hle/service/hle_ipc.cpp 786 hle/service/ro/ro.cpp
763 hle/service/hle_ipc.h 787 hle/service/ro/ro.h
764 hle/service/ipc_helpers.h
765 hle/service/kernel_helpers.cpp
766 hle/service/kernel_helpers.h
767 hle/service/mutex.cpp
768 hle/service/mutex.h
769 hle/service/ro/ro_nro_utils.cpp 788 hle/service/ro/ro_nro_utils.cpp
770 hle/service/ro/ro_nro_utils.h 789 hle/service/ro/ro_nro_utils.h
771 hle/service/ro/ro_results.h 790 hle/service/ro/ro_results.h
772 hle/service/ro/ro_types.h 791 hle/service/ro/ro_types.h
773 hle/service/ro/ro.cpp
774 hle/service/ro/ro.h
775 hle/service/server_manager.cpp 792 hle/service/server_manager.cpp
776 hle/service/server_manager.h 793 hle/service/server_manager.h
777 hle/service/service.cpp 794 hle/service/service.cpp
@@ -838,9 +855,9 @@ add_library(core STATIC
838 internal_network/network.h 855 internal_network/network.h
839 internal_network/network_interface.cpp 856 internal_network/network_interface.cpp
840 internal_network/network_interface.h 857 internal_network/network_interface.h
841 internal_network/sockets.h
842 internal_network/socket_proxy.cpp 858 internal_network/socket_proxy.cpp
843 internal_network/socket_proxy.h 859 internal_network/socket_proxy.h
860 internal_network/sockets.h
844 loader/deconstructed_rom_directory.cpp 861 loader/deconstructed_rom_directory.cpp
845 loader/deconstructed_rom_directory.h 862 loader/deconstructed_rom_directory.h
846 loader/kip.cpp 863 loader/kip.cpp
@@ -859,13 +876,13 @@ add_library(core STATIC
859 loader/nsp.h 876 loader/nsp.h
860 loader/xci.cpp 877 loader/xci.cpp
861 loader/xci.h 878 loader/xci.h
879 memory.cpp
880 memory.h
862 memory/cheat_engine.cpp 881 memory/cheat_engine.cpp
863 memory/cheat_engine.h 882 memory/cheat_engine.h
864 memory/dmnt_cheat_types.h 883 memory/dmnt_cheat_types.h
865 memory/dmnt_cheat_vm.cpp 884 memory/dmnt_cheat_vm.cpp
866 memory/dmnt_cheat_vm.h 885 memory/dmnt_cheat_vm.h
867 memory.cpp
868 memory.h
869 perf_stats.cpp 886 perf_stats.cpp
870 perf_stats.h 887 perf_stats.h
871 precompiled_headers.h 888 precompiled_headers.h
diff --git a/src/core/core.cpp b/src/core/core.cpp
index dd9de948c..1b412ac98 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -21,13 +21,13 @@
21#include "core/debugger/debugger.h" 21#include "core/debugger/debugger.h"
22#include "core/device_memory.h" 22#include "core/device_memory.h"
23#include "core/file_sys/bis_factory.h" 23#include "core/file_sys/bis_factory.h"
24#include "core/file_sys/mode.h" 24#include "core/file_sys/fs_filesystem.h"
25#include "core/file_sys/patch_manager.h" 25#include "core/file_sys/patch_manager.h"
26#include "core/file_sys/registered_cache.h" 26#include "core/file_sys/registered_cache.h"
27#include "core/file_sys/romfs_factory.h" 27#include "core/file_sys/romfs_factory.h"
28#include "core/file_sys/savedata_factory.h" 28#include "core/file_sys/savedata_factory.h"
29#include "core/file_sys/vfs_concat.h" 29#include "core/file_sys/vfs/vfs_concat.h"
30#include "core/file_sys/vfs_real.h" 30#include "core/file_sys/vfs/vfs_real.h"
31#include "core/gpu_dirty_memory_manager.h" 31#include "core/gpu_dirty_memory_manager.h"
32#include "core/hle/kernel/k_memory_manager.h" 32#include "core/hle/kernel/k_memory_manager.h"
33#include "core/hle/kernel/k_process.h" 33#include "core/hle/kernel/k_process.h"
@@ -102,7 +102,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
102 Common::SplitPath(path, &dir_name, &filename, nullptr); 102 Common::SplitPath(path, &dir_name, &filename, nullptr);
103 103
104 if (filename == "00") { 104 if (filename == "00") {
105 const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read); 105 const auto dir = vfs->OpenDirectory(dir_name, FileSys::OpenMode::Read);
106 std::vector<FileSys::VirtualFile> concat; 106 std::vector<FileSys::VirtualFile> concat;
107 107
108 for (u32 i = 0; i < 0x10; ++i) { 108 for (u32 i = 0; i < 0x10; ++i) {
@@ -127,10 +127,10 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
127 } 127 }
128 128
129 if (Common::FS::IsDir(path)) { 129 if (Common::FS::IsDir(path)) {
130 return vfs->OpenFile(path + "/main", FileSys::Mode::Read); 130 return vfs->OpenFile(path + "/main", FileSys::OpenMode::Read);
131 } 131 }
132 132
133 return vfs->OpenFile(path, FileSys::Mode::Read); 133 return vfs->OpenFile(path, FileSys::OpenMode::Read);
134} 134}
135 135
136struct System::Impl { 136struct System::Impl {
diff --git a/src/core/core.h b/src/core/core.h
index 183410602..d8862e9ce 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -13,7 +13,7 @@
13#include <vector> 13#include <vector>
14 14
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "core/file_sys/vfs_types.h" 16#include "core/file_sys/vfs/vfs_types.h"
17 17
18namespace Core::Frontend { 18namespace Core::Frontend {
19class EmuWindow; 19class EmuWindow;
diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h
index a67ba5352..c2fd587a7 100644
--- a/src/core/crypto/aes_util.h
+++ b/src/core/crypto/aes_util.h
@@ -7,7 +7,7 @@
7#include <span> 7#include <span>
8#include <type_traits> 8#include <type_traits>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs/vfs.h"
11 11
12namespace Core::Crypto { 12namespace Core::Crypto {
13 13
diff --git a/src/core/crypto/encryption_layer.h b/src/core/crypto/encryption_layer.h
index d3082ba53..b53f0b12e 100644
--- a/src/core/crypto/encryption_layer.h
+++ b/src/core/crypto/encryption_layer.h
@@ -4,7 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/file_sys/vfs.h" 7#include "core/file_sys/vfs/vfs.h"
8 8
9namespace Core::Crypto { 9namespace Core::Crypto {
10 10
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp
index 97f5c8cea..4b45e72c4 100644
--- a/src/core/crypto/partition_data_manager.cpp
+++ b/src/core/crypto/partition_data_manager.cpp
@@ -21,9 +21,9 @@
21#include "core/crypto/partition_data_manager.h" 21#include "core/crypto/partition_data_manager.h"
22#include "core/crypto/xts_encryption_layer.h" 22#include "core/crypto/xts_encryption_layer.h"
23#include "core/file_sys/kernel_executable.h" 23#include "core/file_sys/kernel_executable.h"
24#include "core/file_sys/vfs.h" 24#include "core/file_sys/vfs/vfs.h"
25#include "core/file_sys/vfs_offset.h" 25#include "core/file_sys/vfs/vfs_offset.h"
26#include "core/file_sys/vfs_vector.h" 26#include "core/file_sys/vfs/vfs_vector.h"
27#include "core/loader/loader.h" 27#include "core/loader/loader.h"
28 28
29using Common::AsArray; 29using Common::AsArray;
diff --git a/src/core/crypto/partition_data_manager.h b/src/core/crypto/partition_data_manager.h
index 057a70683..4354a21e6 100644
--- a/src/core/crypto/partition_data_manager.h
+++ b/src/core/crypto/partition_data_manager.h
@@ -5,7 +5,7 @@
5 5
6#include <vector> 6#include <vector>
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/file_sys/vfs_types.h" 8#include "core/file_sys/vfs/vfs_types.h"
9 9
10namespace Core::Crypto { 10namespace Core::Crypto {
11 11
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index c750c0da7..db667438e 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -4,9 +4,8 @@
4#include <fmt/format.h> 4#include <fmt/format.h>
5#include "common/fs/path_util.h" 5#include "common/fs/path_util.h"
6#include "core/file_sys/bis_factory.h" 6#include "core/file_sys/bis_factory.h"
7#include "core/file_sys/mode.h"
8#include "core/file_sys/registered_cache.h" 7#include "core/file_sys/registered_cache.h"
9#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs/vfs.h"
10 9
11namespace FileSys { 10namespace FileSys {
12 11
@@ -84,7 +83,7 @@ VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id,
84 VirtualFilesystem file_system) const { 83 VirtualFilesystem file_system) const {
85 auto& keys = Core::Crypto::KeyManager::Instance(); 84 auto& keys = Core::Crypto::KeyManager::Instance();
86 Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory( 85 Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory(
87 Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir), Mode::Read)}; 86 Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir), OpenMode::Read)};
88 keys.PopulateFromPartitionData(pdm); 87 keys.PopulateFromPartitionData(pdm);
89 88
90 switch (id) { 89 switch (id) {
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
index 26f0c6e5e..23680b60c 100644
--- a/src/core/file_sys/bis_factory.h
+++ b/src/core/file_sys/bis_factory.h
@@ -6,7 +6,7 @@
6#include <memory> 6#include <memory>
7 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/file_sys/vfs_types.h" 9#include "core/file_sys/vfs/vfs_types.h"
10 10
11namespace FileSys { 11namespace FileSys {
12 12
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 8b9a4fc5a..0bcf40cf8 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -13,8 +13,8 @@
13#include "core/file_sys/nca_metadata.h" 13#include "core/file_sys/nca_metadata.h"
14#include "core/file_sys/partition_filesystem.h" 14#include "core/file_sys/partition_filesystem.h"
15#include "core/file_sys/submission_package.h" 15#include "core/file_sys/submission_package.h"
16#include "core/file_sys/vfs_offset.h" 16#include "core/file_sys/vfs/vfs_offset.h"
17#include "core/file_sys/vfs_vector.h" 17#include "core/file_sys/vfs/vfs_vector.h"
18#include "core/loader/loader.h" 18#include "core/loader/loader.h"
19 19
20namespace FileSys { 20namespace FileSys {
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
index 9886123e7..97871da4a 100644
--- a/src/core/file_sys/card_image.h
+++ b/src/core/file_sys/card_image.h
@@ -8,7 +8,7 @@
8#include <vector> 8#include <vector>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/swap.h" 10#include "common/swap.h"
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
12 12
13namespace Core::Crypto { 13namespace Core::Crypto {
14class KeyManager; 14class KeyManager;
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 7d2f0abb8..285fe4db6 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -13,7 +13,7 @@
13#include "core/crypto/key_manager.h" 13#include "core/crypto/key_manager.h"
14#include "core/file_sys/content_archive.h" 14#include "core/file_sys/content_archive.h"
15#include "core/file_sys/partition_filesystem.h" 15#include "core/file_sys/partition_filesystem.h"
16#include "core/file_sys/vfs_offset.h" 16#include "core/file_sys/vfs/vfs_offset.h"
17#include "core/loader/loader.h" 17#include "core/loader/loader.h"
18 18
19#include "core/file_sys/fssystem/fssystem_compression_configuration.h" 19#include "core/file_sys/fssystem/fssystem_compression_configuration.h"
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index af521d453..f68464eb0 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -13,7 +13,7 @@
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/swap.h" 14#include "common/swap.h"
15#include "core/crypto/key_manager.h" 15#include "core/crypto/key_manager.h"
16#include "core/file_sys/vfs.h" 16#include "core/file_sys/vfs/vfs.h"
17 17
18namespace Loader { 18namespace Loader {
19enum class ResultStatus : u16; 19enum class ResultStatus : u16;
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 0697c29ae..f98594335 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -5,7 +5,7 @@
5#include "common/string_util.h" 5#include "common/string_util.h"
6#include "common/swap.h" 6#include "common/swap.h"
7#include "core/file_sys/control_metadata.h" 7#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs/vfs.h"
9 9
10namespace FileSys { 10namespace FileSys {
11 11
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index c98efb00d..555b9d8f7 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -8,7 +8,7 @@
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 "common/swap.h" 10#include "common/swap.h"
11#include "core/file_sys/vfs_types.h" 11#include "core/file_sys/vfs/vfs_types.h"
12 12
13namespace FileSys { 13namespace FileSys {
14 14
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h
deleted file mode 100644
index a853c00f3..000000000
--- a/src/core/file_sys/directory.h
+++ /dev/null
@@ -1,39 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <cstddef>
7#include "common/common_funcs.h"
8#include "common/common_types.h"
9
10////////////////////////////////////////////////////////////////////////////////////////////////////
11// FileSys namespace
12
13namespace FileSys {
14
15enum class EntryType : u8 {
16 Directory = 0,
17 File = 1,
18};
19
20// Structure of a directory entry, from
21// http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry
22struct Entry {
23 Entry(std::string_view view, EntryType entry_type, u64 entry_size)
24 : type{entry_type}, file_size{entry_size} {
25 const std::size_t copy_size = view.copy(filename, std::size(filename) - 1);
26 filename[copy_size] = '\0';
27 }
28
29 char filename[0x301];
30 INSERT_PADDING_BYTES(3);
31 EntryType type;
32 INSERT_PADDING_BYTES(3);
33 u64 file_size;
34};
35static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x310 bytes long!");
36static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry.");
37static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry.");
38
39} // namespace FileSys
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h
index 2f5045a67..d4e0eb6f4 100644
--- a/src/core/file_sys/errors.h
+++ b/src/core/file_sys/errors.h
@@ -7,18 +7,13 @@
7 7
8namespace FileSys { 8namespace FileSys {
9 9
10constexpr Result ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1}; 10constexpr Result ResultPathNotFound{ErrorModule::FS, 1};
11constexpr Result ERROR_PATH_ALREADY_EXISTS{ErrorModule::FS, 2}; 11constexpr Result ResultPathAlreadyExists{ErrorModule::FS, 2};
12constexpr Result ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002};
13constexpr Result ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001};
14constexpr Result ERROR_OUT_OF_BOUNDS{ErrorModule::FS, 3005};
15constexpr Result ERROR_FAILED_MOUNT_ARCHIVE{ErrorModule::FS, 3223};
16constexpr Result ERROR_INVALID_ARGUMENT{ErrorModule::FS, 6001};
17constexpr Result ERROR_INVALID_OFFSET{ErrorModule::FS, 6061};
18constexpr Result ERROR_INVALID_SIZE{ErrorModule::FS, 6062};
19
20constexpr Result ResultUnsupportedSdkVersion{ErrorModule::FS, 50}; 12constexpr Result ResultUnsupportedSdkVersion{ErrorModule::FS, 50};
21constexpr Result ResultPartitionNotFound{ErrorModule::FS, 1001}; 13constexpr Result ResultPartitionNotFound{ErrorModule::FS, 1001};
14constexpr Result ResultTargetNotFound{ErrorModule::FS, 1002};
15constexpr Result ResultPortSdCardNoDevice{ErrorModule::FS, 2001};
16constexpr Result ResultNotImplemented{ErrorModule::FS, 3001};
22constexpr Result ResultUnsupportedVersion{ErrorModule::FS, 3002}; 17constexpr Result ResultUnsupportedVersion{ErrorModule::FS, 3002};
23constexpr Result ResultOutOfRange{ErrorModule::FS, 3005}; 18constexpr Result ResultOutOfRange{ErrorModule::FS, 3005};
24constexpr Result ResultAllocationMemoryFailedInFileSystemBuddyHeapA{ErrorModule::FS, 3294}; 19constexpr Result ResultAllocationMemoryFailedInFileSystemBuddyHeapA{ErrorModule::FS, 3294};
@@ -78,10 +73,21 @@ constexpr Result ResultUnexpectedInCompressedStorageA{ErrorModule::FS, 5324};
78constexpr Result ResultUnexpectedInCompressedStorageB{ErrorModule::FS, 5325}; 73constexpr Result ResultUnexpectedInCompressedStorageB{ErrorModule::FS, 5325};
79constexpr Result ResultUnexpectedInCompressedStorageC{ErrorModule::FS, 5326}; 74constexpr Result ResultUnexpectedInCompressedStorageC{ErrorModule::FS, 5326};
80constexpr Result ResultUnexpectedInCompressedStorageD{ErrorModule::FS, 5327}; 75constexpr Result ResultUnexpectedInCompressedStorageD{ErrorModule::FS, 5327};
76constexpr Result ResultUnexpectedInPathA{ErrorModule::FS, 5328};
81constexpr Result ResultInvalidArgument{ErrorModule::FS, 6001}; 77constexpr Result ResultInvalidArgument{ErrorModule::FS, 6001};
78constexpr Result ResultInvalidPath{ErrorModule::FS, 6002};
79constexpr Result ResultTooLongPath{ErrorModule::FS, 6003};
80constexpr Result ResultInvalidCharacter{ErrorModule::FS, 6004};
81constexpr Result ResultInvalidPathFormat{ErrorModule::FS, 6005};
82constexpr Result ResultDirectoryUnobtainable{ErrorModule::FS, 6006};
83constexpr Result ResultNotNormalized{ErrorModule::FS, 6007};
82constexpr Result ResultInvalidOffset{ErrorModule::FS, 6061}; 84constexpr Result ResultInvalidOffset{ErrorModule::FS, 6061};
83constexpr Result ResultInvalidSize{ErrorModule::FS, 6062}; 85constexpr Result ResultInvalidSize{ErrorModule::FS, 6062};
84constexpr Result ResultNullptrArgument{ErrorModule::FS, 6063}; 86constexpr Result ResultNullptrArgument{ErrorModule::FS, 6063};
87constexpr Result ResultInvalidOpenMode{ErrorModule::FS, 6072};
88constexpr Result ResultFileExtensionWithoutOpenModeAllowAppend{ErrorModule::FS, 6201};
89constexpr Result ResultReadNotPermitted{ErrorModule::FS, 6202};
90constexpr Result ResultWriteNotPermitted{ErrorModule::FS, 6203};
85constexpr Result ResultUnsupportedSetSizeForIndirectStorage{ErrorModule::FS, 6325}; 91constexpr Result ResultUnsupportedSetSizeForIndirectStorage{ErrorModule::FS, 6325};
86constexpr Result ResultUnsupportedWriteForCompressedStorage{ErrorModule::FS, 6387}; 92constexpr Result ResultUnsupportedWriteForCompressedStorage{ErrorModule::FS, 6387};
87constexpr Result ResultUnsupportedOperateRangeForCompressedStorage{ErrorModule::FS, 6388}; 93constexpr Result ResultUnsupportedOperateRangeForCompressedStorage{ErrorModule::FS, 6388};
diff --git a/src/core/file_sys/fs_directory.h b/src/core/file_sys/fs_directory.h
new file mode 100644
index 000000000..25c9cb18a
--- /dev/null
+++ b/src/core/file_sys/fs_directory.h
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6namespace FileSys {
7
8constexpr inline size_t EntryNameLengthMax = 0x300;
9
10struct DirectoryEntry {
11 DirectoryEntry(std::string_view view, s8 entry_type, u64 entry_size)
12 : type{entry_type}, file_size{static_cast<s64>(entry_size)} {
13 const std::size_t copy_size = view.copy(name, std::size(name) - 1);
14 name[copy_size] = '\0';
15 }
16
17 char name[EntryNameLengthMax + 1];
18 INSERT_PADDING_BYTES(3);
19 s8 type;
20 INSERT_PADDING_BYTES(3);
21 s64 file_size;
22};
23
24static_assert(sizeof(DirectoryEntry) == 0x310,
25 "Directory Entry struct isn't exactly 0x310 bytes long!");
26static_assert(offsetof(DirectoryEntry, type) == 0x304, "Wrong offset for type in Entry.");
27static_assert(offsetof(DirectoryEntry, file_size) == 0x308, "Wrong offset for file_size in Entry.");
28
29struct DirectoryHandle {
30 void* handle;
31};
32
33} // namespace FileSys
diff --git a/src/core/file_sys/fs_file.h b/src/core/file_sys/fs_file.h
new file mode 100644
index 000000000..4fb77e8db
--- /dev/null
+++ b/src/core/file_sys/fs_file.h
@@ -0,0 +1,65 @@
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
8namespace FileSys {
9
10struct ReadOption {
11 u32 value;
12
13 static const ReadOption None;
14};
15
16enum ReadOptionFlag : u32 {
17 ReadOptionFlag_None = (0 << 0),
18};
19
20inline constexpr const ReadOption ReadOption::None = {ReadOptionFlag_None};
21
22inline constexpr bool operator==(const ReadOption& lhs, const ReadOption& rhs) {
23 return lhs.value == rhs.value;
24}
25
26inline constexpr bool operator!=(const ReadOption& lhs, const ReadOption& rhs) {
27 return !(lhs == rhs);
28}
29
30static_assert(sizeof(ReadOption) == sizeof(u32));
31
32enum WriteOptionFlag : u32 {
33 WriteOptionFlag_None = (0 << 0),
34 WriteOptionFlag_Flush = (1 << 0),
35};
36
37struct WriteOption {
38 u32 value;
39
40 constexpr inline bool HasFlushFlag() const {
41 return value & WriteOptionFlag_Flush;
42 }
43
44 static const WriteOption None;
45 static const WriteOption Flush;
46};
47
48inline constexpr const WriteOption WriteOption::None = {WriteOptionFlag_None};
49inline constexpr const WriteOption WriteOption::Flush = {WriteOptionFlag_Flush};
50
51inline constexpr bool operator==(const WriteOption& lhs, const WriteOption& rhs) {
52 return lhs.value == rhs.value;
53}
54
55inline constexpr bool operator!=(const WriteOption& lhs, const WriteOption& rhs) {
56 return !(lhs == rhs);
57}
58
59static_assert(sizeof(WriteOption) == sizeof(u32));
60
61struct FileHandle {
62 void* handle;
63};
64
65} // namespace FileSys
diff --git a/src/core/file_sys/fs_filesystem.h b/src/core/file_sys/fs_filesystem.h
new file mode 100644
index 000000000..7f237b7fa
--- /dev/null
+++ b/src/core/file_sys/fs_filesystem.h
@@ -0,0 +1,39 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace FileSys {
10
11enum class OpenMode : u32 {
12 Read = (1 << 0),
13 Write = (1 << 1),
14 AllowAppend = (1 << 2),
15
16 ReadWrite = (Read | Write),
17 All = (ReadWrite | AllowAppend),
18};
19DECLARE_ENUM_FLAG_OPERATORS(OpenMode)
20
21enum class OpenDirectoryMode : u64 {
22 Directory = (1 << 0),
23 File = (1 << 1),
24
25 All = (Directory | File),
26};
27DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
28
29enum class DirectoryEntryType : u8 {
30 Directory = 0,
31 File = 1,
32};
33
34enum class CreateOption : u8 {
35 None = (0 << 0),
36 BigFile = (1 << 0),
37};
38
39} // namespace FileSys
diff --git a/src/core/file_sys/fs_memory_management.h b/src/core/file_sys/fs_memory_management.h
new file mode 100644
index 000000000..f03c6354b
--- /dev/null
+++ b/src/core/file_sys/fs_memory_management.h
@@ -0,0 +1,40 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <mutex>
7#include "common/alignment.h"
8
9namespace FileSys {
10
11constexpr size_t RequiredAlignment = alignof(u64);
12
13void* AllocateUnsafe(size_t size) {
14 // Allocate
15 void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
16
17 // Check alignment
18 ASSERT(Common::IsAligned(reinterpret_cast<uintptr_t>(ptr), RequiredAlignment));
19
20 // Return allocated pointer
21 return ptr;
22}
23
24void DeallocateUnsafe(void* ptr, size_t size) {
25 // Deallocate the pointer
26 ::operator delete(ptr, std::align_val_t{RequiredAlignment});
27}
28
29void* Allocate(size_t size) {
30 return AllocateUnsafe(size);
31}
32
33void Deallocate(void* ptr, size_t size) {
34 // If the pointer is non-null, deallocate it
35 if (ptr != nullptr) {
36 DeallocateUnsafe(ptr, size);
37 }
38}
39
40} // namespace FileSys
diff --git a/src/core/file_sys/fs_operate_range.h b/src/core/file_sys/fs_operate_range.h
new file mode 100644
index 000000000..04ea64cc0
--- /dev/null
+++ b/src/core/file_sys/fs_operate_range.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 "common/common_types.h"
7
8namespace FileSys {
9
10enum class OperationId : s64 {
11 FillZero = 0,
12 DestroySignature = 1,
13 Invalidate = 2,
14 QueryRange = 3,
15 QueryUnpreparedRange = 4,
16 QueryLazyLoadCompletionRate = 5,
17 SetLazyLoadPriority = 6,
18
19 ReadLazyLoadFileForciblyForDebug = 10001,
20};
21
22} // namespace FileSys
diff --git a/src/core/file_sys/fs_path.h b/src/core/file_sys/fs_path.h
new file mode 100644
index 000000000..56ba08a6a
--- /dev/null
+++ b/src/core/file_sys/fs_path.h
@@ -0,0 +1,566 @@
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/alignment.h"
7#include "common/common_funcs.h"
8#include "core/file_sys/errors.h"
9#include "core/file_sys/fs_memory_management.h"
10#include "core/file_sys/fs_path_utility.h"
11#include "core/file_sys/fs_string_util.h"
12#include "core/hle/result.h"
13
14namespace FileSys {
15class DirectoryPathParser;
16
17class Path {
18 YUZU_NON_COPYABLE(Path);
19 YUZU_NON_MOVEABLE(Path);
20
21private:
22 static constexpr const char* EmptyPath = "";
23 static constexpr size_t WriteBufferAlignmentLength = 8;
24
25private:
26 friend class DirectoryPathParser;
27
28public:
29 class WriteBuffer {
30 YUZU_NON_COPYABLE(WriteBuffer);
31
32 private:
33 char* m_buffer;
34 size_t m_length_and_is_normalized;
35
36 public:
37 constexpr WriteBuffer() : m_buffer(nullptr), m_length_and_is_normalized(0) {}
38
39 constexpr ~WriteBuffer() {
40 if (m_buffer != nullptr) {
41 Deallocate(m_buffer, this->GetLength());
42 this->ResetBuffer();
43 }
44 }
45
46 constexpr WriteBuffer(WriteBuffer&& rhs)
47 : m_buffer(rhs.m_buffer), m_length_and_is_normalized(rhs.m_length_and_is_normalized) {
48 rhs.ResetBuffer();
49 }
50
51 constexpr WriteBuffer& operator=(WriteBuffer&& rhs) {
52 if (m_buffer != nullptr) {
53 Deallocate(m_buffer, this->GetLength());
54 }
55
56 m_buffer = rhs.m_buffer;
57 m_length_and_is_normalized = rhs.m_length_and_is_normalized;
58
59 rhs.ResetBuffer();
60
61 return *this;
62 }
63
64 constexpr void ResetBuffer() {
65 m_buffer = nullptr;
66 this->SetLength(0);
67 }
68
69 constexpr char* Get() const {
70 return m_buffer;
71 }
72
73 constexpr size_t GetLength() const {
74 return m_length_and_is_normalized >> 1;
75 }
76
77 constexpr bool IsNormalized() const {
78 return static_cast<bool>(m_length_and_is_normalized & 1);
79 }
80
81 constexpr void SetNormalized() {
82 m_length_and_is_normalized |= static_cast<size_t>(1);
83 }
84
85 constexpr void SetNotNormalized() {
86 m_length_and_is_normalized &= ~static_cast<size_t>(1);
87 }
88
89 private:
90 constexpr WriteBuffer(char* buffer, size_t length)
91 : m_buffer(buffer), m_length_and_is_normalized(0) {
92 this->SetLength(length);
93 }
94
95 public:
96 static WriteBuffer Make(size_t length) {
97 if (void* alloc = Allocate(length); alloc != nullptr) {
98 return WriteBuffer(static_cast<char*>(alloc), length);
99 } else {
100 return WriteBuffer();
101 }
102 }
103
104 private:
105 constexpr void SetLength(size_t size) {
106 m_length_and_is_normalized = (m_length_and_is_normalized & 1) | (size << 1);
107 }
108 };
109
110private:
111 const char* m_str;
112 WriteBuffer m_write_buffer;
113
114public:
115 constexpr Path() : m_str(EmptyPath), m_write_buffer() {}
116
117 constexpr Path(const char* s) : m_str(s), m_write_buffer() {
118 m_write_buffer.SetNormalized();
119 }
120
121 constexpr ~Path() = default;
122
123 constexpr Result SetShallowBuffer(const char* buffer) {
124 // Check pre-conditions
125 ASSERT(m_write_buffer.GetLength() == 0);
126
127 // Check the buffer is valid
128 R_UNLESS(buffer != nullptr, ResultNullptrArgument);
129
130 // Set buffer
131 this->SetReadOnlyBuffer(buffer);
132
133 // Note that we're normalized
134 this->SetNormalized();
135
136 R_SUCCEED();
137 }
138
139 constexpr const char* GetString() const {
140 // Check pre-conditions
141 ASSERT(this->IsNormalized());
142
143 return m_str;
144 }
145
146 constexpr size_t GetLength() const {
147 if (std::is_constant_evaluated()) {
148 return Strlen(this->GetString());
149 } else {
150 return std::strlen(this->GetString());
151 }
152 }
153
154 constexpr bool IsEmpty() const {
155 return *m_str == '\x00';
156 }
157
158 constexpr bool IsMatchHead(const char* p, size_t len) const {
159 return Strncmp(this->GetString(), p, len) == 0;
160 }
161
162 Result Initialize(const Path& rhs) {
163 // Check the other path is normalized
164 const bool normalized = rhs.IsNormalized();
165 R_UNLESS(normalized, ResultNotNormalized);
166
167 // Allocate buffer for our path
168 const auto len = rhs.GetLength();
169 R_TRY(this->Preallocate(len + 1));
170
171 // Copy the path
172 const size_t copied = Strlcpy<char>(m_write_buffer.Get(), rhs.GetString(), len + 1);
173 R_UNLESS(copied == len, ResultUnexpectedInPathA);
174
175 // Set normalized
176 this->SetNormalized();
177 R_SUCCEED();
178 }
179
180 Result Initialize(const char* path, size_t len) {
181 // Check the path is valid
182 R_UNLESS(path != nullptr, ResultNullptrArgument);
183
184 // Initialize
185 R_TRY(this->InitializeImpl(path, len));
186
187 // Set not normalized
188 this->SetNotNormalized();
189
190 R_SUCCEED();
191 }
192
193 Result Initialize(const char* path) {
194 // Check the path is valid
195 R_UNLESS(path != nullptr, ResultNullptrArgument);
196
197 R_RETURN(this->Initialize(path, std::strlen(path)));
198 }
199
200 Result InitializeWithReplaceBackslash(const char* path) {
201 // Check the path is valid
202 R_UNLESS(path != nullptr, ResultNullptrArgument);
203
204 // Initialize
205 R_TRY(this->InitializeImpl(path, std::strlen(path)));
206
207 // Replace slashes as desired
208 if (const auto write_buffer_length = m_write_buffer.GetLength(); write_buffer_length > 1) {
209 Replace(m_write_buffer.Get(), write_buffer_length - 1, '\\', '/');
210 }
211
212 // Set not normalized
213 this->SetNotNormalized();
214
215 R_SUCCEED();
216 }
217
218 Result InitializeWithReplaceForwardSlashes(const char* path) {
219 // Check the path is valid
220 R_UNLESS(path != nullptr, ResultNullptrArgument);
221
222 // Initialize
223 R_TRY(this->InitializeImpl(path, std::strlen(path)));
224
225 // Replace slashes as desired
226 if (m_write_buffer.GetLength() > 1) {
227 if (auto* p = m_write_buffer.Get(); p[0] == '/' && p[1] == '/') {
228 p[0] = '\\';
229 p[1] = '\\';
230 }
231 }
232
233 // Set not normalized
234 this->SetNotNormalized();
235
236 R_SUCCEED();
237 }
238
239 Result InitializeWithNormalization(const char* path, size_t size) {
240 // Check the path is valid
241 R_UNLESS(path != nullptr, ResultNullptrArgument);
242
243 // Initialize
244 R_TRY(this->InitializeImpl(path, size));
245
246 // Set not normalized
247 this->SetNotNormalized();
248
249 // Perform normalization
250 PathFlags path_flags;
251 if (IsPathRelative(m_str)) {
252 path_flags.AllowRelativePath();
253 } else if (IsWindowsPath(m_str, true)) {
254 path_flags.AllowWindowsPath();
255 } else {
256 /* NOTE: In this case, Nintendo checks is normalized, then sets is normalized, then
257 * returns success. */
258 /* This seems like a bug. */
259 size_t dummy;
260 bool normalized;
261 R_TRY(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(dummy),
262 m_str));
263
264 this->SetNormalized();
265 R_SUCCEED();
266 }
267
268 // Normalize
269 R_TRY(this->Normalize(path_flags));
270
271 this->SetNormalized();
272 R_SUCCEED();
273 }
274
275 Result InitializeWithNormalization(const char* path) {
276 // Check the path is valid
277 R_UNLESS(path != nullptr, ResultNullptrArgument);
278
279 R_RETURN(this->InitializeWithNormalization(path, std::strlen(path)));
280 }
281
282 Result InitializeAsEmpty() {
283 // Clear our buffer
284 this->ClearBuffer();
285
286 // Set normalized
287 this->SetNormalized();
288
289 R_SUCCEED();
290 }
291
292 Result AppendChild(const char* child) {
293 // Check the path is valid
294 R_UNLESS(child != nullptr, ResultNullptrArgument);
295
296 // Basic checks. If we have a path and the child is empty, we have nothing to do
297 const char* c = child;
298 if (m_str[0]) {
299 // Skip an early separator
300 if (*c == '/') {
301 ++c;
302 }
303
304 R_SUCCEED_IF(*c == '\x00');
305 }
306
307 // If we don't have a string, we can just initialize
308 auto cur_len = std::strlen(m_str);
309 if (cur_len == 0) {
310 R_RETURN(this->Initialize(child));
311 }
312
313 // Remove a trailing separator
314 if (m_str[cur_len - 1] == '/' || m_str[cur_len - 1] == '\\') {
315 --cur_len;
316 }
317
318 // Get the child path's length
319 auto child_len = std::strlen(c);
320
321 // Reset our write buffer
322 WriteBuffer old_write_buffer;
323 if (m_write_buffer.Get() != nullptr) {
324 old_write_buffer = std::move(m_write_buffer);
325 this->ClearBuffer();
326 }
327
328 // Pre-allocate the new buffer
329 R_TRY(this->Preallocate(cur_len + 1 + child_len + 1));
330
331 // Get our write buffer
332 auto* dst = m_write_buffer.Get();
333 if (old_write_buffer.Get() != nullptr && cur_len > 0) {
334 Strlcpy<char>(dst, old_write_buffer.Get(), cur_len + 1);
335 }
336
337 // Add separator
338 dst[cur_len] = '/';
339
340 // Copy the child path
341 const size_t copied = Strlcpy<char>(dst + cur_len + 1, c, child_len + 1);
342 R_UNLESS(copied == child_len, ResultUnexpectedInPathA);
343
344 R_SUCCEED();
345 }
346
347 Result AppendChild(const Path& rhs) {
348 R_RETURN(this->AppendChild(rhs.GetString()));
349 }
350
351 Result Combine(const Path& parent, const Path& child) {
352 // Get the lengths
353 const auto p_len = parent.GetLength();
354 const auto c_len = child.GetLength();
355
356 // Allocate our buffer
357 R_TRY(this->Preallocate(p_len + c_len + 1));
358
359 // Initialize as parent
360 R_TRY(this->Initialize(parent));
361
362 // If we're empty, we can just initialize as child
363 if (this->IsEmpty()) {
364 R_TRY(this->Initialize(child));
365 } else {
366 // Otherwise, we should append the child
367 R_TRY(this->AppendChild(child));
368 }
369
370 R_SUCCEED();
371 }
372
373 Result RemoveChild() {
374 // If we don't have a write-buffer, ensure that we have one
375 if (m_write_buffer.Get() == nullptr) {
376 if (const auto len = std::strlen(m_str); len > 0) {
377 R_TRY(this->Preallocate(len));
378 Strlcpy<char>(m_write_buffer.Get(), m_str, len + 1);
379 }
380 }
381
382 // Check that it's possible for us to remove a child
383 auto* p = m_write_buffer.Get();
384 s32 len = std::strlen(p);
385 R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
386
387 // Handle a trailing separator
388 if (len > 0 && (p[len - 1] == '\\' || p[len - 1] == '/')) {
389 --len;
390 }
391
392 // Remove the child path segment
393 while ((--len) >= 0 && p[len]) {
394 if (p[len] == '/' || p[len] == '\\') {
395 if (len > 0) {
396 p[len] = 0;
397 } else {
398 p[1] = 0;
399 len = 1;
400 }
401 break;
402 }
403 }
404
405 // Check that length remains > 0
406 R_UNLESS(len > 0, ResultNotImplemented);
407
408 R_SUCCEED();
409 }
410
411 Result Normalize(const PathFlags& flags) {
412 // If we're already normalized, nothing to do
413 R_SUCCEED_IF(this->IsNormalized());
414
415 // Check if we're normalized
416 bool normalized;
417 size_t dummy;
418 R_TRY(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(dummy), m_str,
419 flags));
420
421 // If we're not normalized, normalize
422 if (!normalized) {
423 // Determine necessary buffer length
424 auto len = m_write_buffer.GetLength();
425 if (flags.IsRelativePathAllowed() && IsPathRelative(m_str)) {
426 len += 2;
427 }
428 if (flags.IsWindowsPathAllowed() && IsWindowsPath(m_str, true)) {
429 len += 1;
430 }
431
432 // Allocate a new buffer
433 const size_t size = Common::AlignUp(len, WriteBufferAlignmentLength);
434 auto buf = WriteBuffer::Make(size);
435 R_UNLESS(buf.Get() != nullptr, ResultAllocationMemoryFailedMakeUnique);
436
437 // Normalize into it
438 R_TRY(PathFormatter::Normalize(buf.Get(), size, m_write_buffer.Get(),
439 m_write_buffer.GetLength(), flags));
440
441 // Set the normalized buffer as our buffer
442 this->SetModifiableBuffer(std::move(buf));
443 }
444
445 // Set normalized
446 this->SetNormalized();
447 R_SUCCEED();
448 }
449
450private:
451 void ClearBuffer() {
452 m_write_buffer.ResetBuffer();
453 m_str = EmptyPath;
454 }
455
456 void SetModifiableBuffer(WriteBuffer&& buffer) {
457 // Check pre-conditions
458 ASSERT(buffer.Get() != nullptr);
459 ASSERT(buffer.GetLength() > 0);
460 ASSERT(Common::IsAligned(buffer.GetLength(), WriteBufferAlignmentLength));
461
462 // Get whether we're normalized
463 if (m_write_buffer.IsNormalized()) {
464 buffer.SetNormalized();
465 } else {
466 buffer.SetNotNormalized();
467 }
468
469 // Set write buffer
470 m_write_buffer = std::move(buffer);
471 m_str = m_write_buffer.Get();
472 }
473
474 constexpr void SetReadOnlyBuffer(const char* buffer) {
475 m_str = buffer;
476 m_write_buffer.ResetBuffer();
477 }
478
479 Result Preallocate(size_t length) {
480 // Allocate additional space, if needed
481 if (length > m_write_buffer.GetLength()) {
482 // Allocate buffer
483 const size_t size = Common::AlignUp(length, WriteBufferAlignmentLength);
484 auto buf = WriteBuffer::Make(size);
485 R_UNLESS(buf.Get() != nullptr, ResultAllocationMemoryFailedMakeUnique);
486
487 // Set write buffer
488 this->SetModifiableBuffer(std::move(buf));
489 }
490
491 R_SUCCEED();
492 }
493
494 Result InitializeImpl(const char* path, size_t size) {
495 if (size > 0 && path[0]) {
496 // Pre allocate a buffer for the path
497 R_TRY(this->Preallocate(size + 1));
498
499 // Copy the path
500 const size_t copied = Strlcpy<char>(m_write_buffer.Get(), path, size + 1);
501 R_UNLESS(copied >= size, ResultUnexpectedInPathA);
502 } else {
503 // We can just clear the buffer
504 this->ClearBuffer();
505 }
506
507 R_SUCCEED();
508 }
509
510 constexpr char* GetWriteBuffer() {
511 ASSERT(m_write_buffer.Get() != nullptr);
512 return m_write_buffer.Get();
513 }
514
515 constexpr size_t GetWriteBufferLength() const {
516 return m_write_buffer.GetLength();
517 }
518
519 constexpr bool IsNormalized() const {
520 return m_write_buffer.IsNormalized();
521 }
522
523 constexpr void SetNormalized() {
524 m_write_buffer.SetNormalized();
525 }
526
527 constexpr void SetNotNormalized() {
528 m_write_buffer.SetNotNormalized();
529 }
530
531public:
532 bool operator==(const FileSys::Path& rhs) const {
533 return std::strcmp(this->GetString(), rhs.GetString()) == 0;
534 }
535 bool operator!=(const FileSys::Path& rhs) const {
536 return !(*this == rhs);
537 }
538 bool operator==(const char* p) const {
539 return std::strcmp(this->GetString(), p) == 0;
540 }
541 bool operator!=(const char* p) const {
542 return !(*this == p);
543 }
544};
545
546inline Result SetUpFixedPath(FileSys::Path* out, const char* s) {
547 // Verify the path is normalized
548 bool normalized;
549 size_t dummy;
550 R_TRY(PathNormalizer::IsNormalized(std::addressof(normalized), std::addressof(dummy), s));
551
552 R_UNLESS(normalized, ResultInvalidPathFormat);
553
554 // Set the fixed path
555 R_RETURN(out->SetShallowBuffer(s));
556}
557
558constexpr inline bool IsWindowsDriveRootPath(const FileSys::Path& path) {
559 const char* const str = path.GetString();
560 return IsWindowsDrive(str) &&
561 (str[2] == StringTraits::DirectorySeparator ||
562 str[2] == StringTraits::AlternateDirectorySeparator) &&
563 str[3] == StringTraits::NullTerminator;
564}
565
566} // namespace FileSys
diff --git a/src/core/file_sys/fs_path_utility.h b/src/core/file_sys/fs_path_utility.h
new file mode 100644
index 000000000..e9011d065
--- /dev/null
+++ b/src/core/file_sys/fs_path_utility.h
@@ -0,0 +1,1239 @@
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/assert.h"
7#include "common/common_funcs.h"
8#include "common/common_types.h"
9#include "common/scope_exit.h"
10#include "core/file_sys/fs_directory.h"
11#include "core/file_sys/fs_memory_management.h"
12#include "core/file_sys/fs_string_util.h"
13#include "core/hle/result.h"
14
15namespace FileSys {
16
17constexpr inline size_t MountNameLengthMax = 15;
18
19namespace StringTraits {
20
21constexpr inline char DirectorySeparator = '/';
22constexpr inline char DriveSeparator = ':';
23constexpr inline char Dot = '.';
24constexpr inline char NullTerminator = '\x00';
25
26constexpr inline char AlternateDirectorySeparator = '\\';
27
28constexpr inline const char InvalidCharacters[6] = {':', '*', '?', '<', '>', '|'};
29constexpr inline const char InvalidCharactersForHostName[6] = {':', '*', '<', '>', '|', '$'};
30constexpr inline const char InvalidCharactersForMountName[5] = {'*', '?', '<', '>', '|'};
31
32namespace impl {
33
34template <const char* InvalidCharacterSet, size_t NumInvalidCharacters>
35consteval u64 MakeInvalidCharacterMask(size_t n) {
36 u64 mask = 0;
37 for (size_t i = 0; i < NumInvalidCharacters; ++i) {
38 if ((static_cast<u64>(InvalidCharacterSet[i]) >> 6) == n) {
39 mask |= static_cast<u64>(1) << (static_cast<u64>(InvalidCharacterSet[i]) & 0x3F);
40 }
41 }
42 return mask;
43}
44
45template <const char* InvalidCharacterSet, size_t NumInvalidCharacters>
46constexpr bool IsInvalidCharacterImpl(char c) {
47 constexpr u64 Masks[4] = {
48 MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(0),
49 MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(1),
50 MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(2),
51 MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(3)};
52
53 return (Masks[static_cast<u64>(c) >> 6] &
54 (static_cast<u64>(1) << (static_cast<u64>(c) & 0x3F))) != 0;
55}
56
57} // namespace impl
58
59constexpr bool IsInvalidCharacter(char c) {
60 return impl::IsInvalidCharacterImpl<InvalidCharacters, Common::Size(InvalidCharacters)>(c);
61}
62constexpr bool IsInvalidCharacterForHostName(char c) {
63 return impl::IsInvalidCharacterImpl<InvalidCharactersForHostName,
64 Common::Size(InvalidCharactersForHostName)>(c);
65}
66constexpr bool IsInvalidCharacterForMountName(char c) {
67 return impl::IsInvalidCharacterImpl<InvalidCharactersForMountName,
68 Common::Size(InvalidCharactersForMountName)>(c);
69}
70
71} // namespace StringTraits
72
73constexpr inline size_t WindowsDriveLength = 2;
74constexpr inline size_t UncPathPrefixLength = 2;
75constexpr inline size_t DosDevicePathPrefixLength = 4;
76
77class PathFlags {
78private:
79 static constexpr u32 WindowsPathFlag = (1 << 0);
80 static constexpr u32 RelativePathFlag = (1 << 1);
81 static constexpr u32 EmptyPathFlag = (1 << 2);
82 static constexpr u32 MountNameFlag = (1 << 3);
83 static constexpr u32 BackslashFlag = (1 << 4);
84 static constexpr u32 AllCharactersFlag = (1 << 5);
85
86private:
87 u32 m_value;
88
89public:
90 constexpr PathFlags() : m_value(0) { /* ... */
91 }
92
93#define DECLARE_PATH_FLAG_HANDLER(__WHICH__) \
94 constexpr bool Is##__WHICH__##Allowed() const { return (m_value & __WHICH__##Flag) != 0; } \
95 constexpr void Allow##__WHICH__() { m_value |= __WHICH__##Flag; }
96
97 DECLARE_PATH_FLAG_HANDLER(WindowsPath)
98 DECLARE_PATH_FLAG_HANDLER(RelativePath)
99 DECLARE_PATH_FLAG_HANDLER(EmptyPath)
100 DECLARE_PATH_FLAG_HANDLER(MountName)
101 DECLARE_PATH_FLAG_HANDLER(Backslash)
102 DECLARE_PATH_FLAG_HANDLER(AllCharacters)
103
104#undef DECLARE_PATH_FLAG_HANDLER
105};
106
107template <typename T>
108 requires(std::same_as<T, char> || std::same_as<T, wchar_t>)
109constexpr inline bool IsDosDevicePath(const T* path) {
110 ASSERT(path != nullptr);
111
112 using namespace StringTraits;
113
114 return path[0] == AlternateDirectorySeparator && path[1] == AlternateDirectorySeparator &&
115 (path[2] == Dot || path[2] == '?') &&
116 (path[3] == DirectorySeparator || path[3] == AlternateDirectorySeparator);
117}
118
119template <typename T>
120 requires(std::same_as<T, char> || std::same_as<T, wchar_t>)
121constexpr inline bool IsUncPath(const T* path, bool allow_forward_slash = true,
122 bool allow_back_slash = true) {
123 ASSERT(path != nullptr);
124
125 using namespace StringTraits;
126
127 return (allow_forward_slash && path[0] == DirectorySeparator &&
128 path[1] == DirectorySeparator) ||
129 (allow_back_slash && path[0] == AlternateDirectorySeparator &&
130 path[1] == AlternateDirectorySeparator);
131}
132
133constexpr inline bool IsWindowsDrive(const char* path) {
134 ASSERT(path != nullptr);
135
136 return (('a' <= path[0] && path[0] <= 'z') || ('A' <= path[0] && path[0] <= 'Z')) &&
137 path[1] == StringTraits::DriveSeparator;
138}
139
140constexpr inline bool IsWindowsPath(const char* path, bool allow_forward_slash_unc) {
141 return IsWindowsDrive(path) || IsDosDevicePath(path) ||
142 IsUncPath(path, allow_forward_slash_unc, true);
143}
144
145constexpr inline int GetWindowsSkipLength(const char* path) {
146 if (IsDosDevicePath(path)) {
147 return DosDevicePathPrefixLength;
148 } else if (IsWindowsDrive(path)) {
149 return WindowsDriveLength;
150 } else if (IsUncPath(path)) {
151 return UncPathPrefixLength;
152 } else {
153 return 0;
154 }
155}
156
157constexpr inline bool IsPathAbsolute(const char* path) {
158 return IsWindowsPath(path, false) || path[0] == StringTraits::DirectorySeparator;
159}
160
161constexpr inline bool IsPathRelative(const char* path) {
162 return path[0] && !IsPathAbsolute(path);
163}
164
165constexpr inline bool IsCurrentDirectory(const char* path) {
166 return path[0] == StringTraits::Dot &&
167 (path[1] == StringTraits::NullTerminator || path[1] == StringTraits::DirectorySeparator);
168}
169
170constexpr inline bool IsParentDirectory(const char* path) {
171 return path[0] == StringTraits::Dot && path[1] == StringTraits::Dot &&
172 (path[2] == StringTraits::NullTerminator || path[2] == StringTraits::DirectorySeparator);
173}
174
175constexpr inline bool IsPathStartWithCurrentDirectory(const char* path) {
176 return IsCurrentDirectory(path) || IsParentDirectory(path);
177}
178
179constexpr inline bool IsSubPath(const char* lhs, const char* rhs) {
180 // Check pre-conditions
181 ASSERT(lhs != nullptr);
182 ASSERT(rhs != nullptr);
183
184 // Import StringTraits names for current scope
185 using namespace StringTraits;
186
187 // Special case certain paths
188 if (IsUncPath(lhs) && !IsUncPath(rhs)) {
189 return false;
190 }
191 if (!IsUncPath(lhs) && IsUncPath(rhs)) {
192 return false;
193 }
194
195 if (lhs[0] == DirectorySeparator && lhs[1] == NullTerminator && rhs[0] == DirectorySeparator &&
196 rhs[1] != NullTerminator) {
197 return true;
198 }
199 if (rhs[0] == DirectorySeparator && rhs[1] == NullTerminator && lhs[0] == DirectorySeparator &&
200 lhs[1] != NullTerminator) {
201 return true;
202 }
203
204 // Check subpath
205 for (size_t i = 0; /* ... */; ++i) {
206 if (lhs[i] == NullTerminator) {
207 return rhs[i] == DirectorySeparator;
208 } else if (rhs[i] == NullTerminator) {
209 return lhs[i] == DirectorySeparator;
210 } else if (lhs[i] != rhs[i]) {
211 return false;
212 }
213 }
214}
215
216// Path utilities
217constexpr inline void Replace(char* dst, size_t dst_size, char old_char, char new_char) {
218 ASSERT(dst != nullptr);
219 for (char* cur = dst; cur < dst + dst_size && *cur; ++cur) {
220 if (*cur == old_char) {
221 *cur = new_char;
222 }
223 }
224}
225
226constexpr inline Result CheckUtf8(const char* s) {
227 // Check pre-conditions
228 ASSERT(s != nullptr);
229
230 // Iterate, checking for utf8-validity
231 while (*s) {
232 char utf8_buf[4] = {};
233
234 const auto pick_res = PickOutCharacterFromUtf8String(utf8_buf, std::addressof(s));
235 R_UNLESS(pick_res == CharacterEncodingResult_Success, ResultInvalidPathFormat);
236
237 u32 dummy;
238 const auto cvt_res = ConvertCharacterUtf8ToUtf32(std::addressof(dummy), utf8_buf);
239 R_UNLESS(cvt_res == CharacterEncodingResult_Success, ResultInvalidPathFormat);
240 }
241
242 R_SUCCEED();
243}
244
245// Path formatting
246class PathNormalizer {
247private:
248 enum class PathState {
249 Start,
250 Normal,
251 FirstSeparator,
252 Separator,
253 CurrentDir,
254 ParentDir,
255 };
256
257private:
258 static constexpr void ReplaceParentDirectoryPath(char* dst, const char* src) {
259 // Use StringTraits names for remainder of scope
260 using namespace StringTraits;
261
262 // Start with a dir-separator
263 dst[0] = DirectorySeparator;
264
265 auto i = 1;
266 while (src[i] != NullTerminator) {
267 if ((src[i - 1] == DirectorySeparator || src[i - 1] == AlternateDirectorySeparator) &&
268 src[i + 0] == Dot && src[i + 1] == Dot &&
269 (src[i + 2] == DirectorySeparator || src[i + 2] == AlternateDirectorySeparator)) {
270 dst[i - 1] = DirectorySeparator;
271 dst[i + 0] = Dot;
272 dst[i + 1] = Dot;
273 dst[i + 2] = DirectorySeparator;
274 i += 3;
275 } else {
276 if (src[i - 1] == AlternateDirectorySeparator && src[i + 0] == Dot &&
277 src[i + 1] == Dot && src[i + 2] == NullTerminator) {
278 dst[i - 1] = DirectorySeparator;
279 dst[i + 0] = Dot;
280 dst[i + 1] = Dot;
281 i += 2;
282 break;
283 }
284
285 dst[i] = src[i];
286 ++i;
287 }
288 }
289
290 dst[i] = StringTraits::NullTerminator;
291 }
292
293public:
294 static constexpr bool IsParentDirectoryPathReplacementNeeded(const char* path) {
295 // Use StringTraits names for remainder of scope
296 using namespace StringTraits;
297
298 if (path[0] != DirectorySeparator && path[0] != AlternateDirectorySeparator) {
299 return false;
300 }
301
302 // Check to find a parent reference using alternate separators
303 if (path[0] != NullTerminator && path[1] != NullTerminator && path[2] != NullTerminator) {
304 size_t i;
305 for (i = 0; path[i + 3] != NullTerminator; ++path) {
306 if (path[i + 1] != Dot || path[i + 2] != Dot) {
307 continue;
308 }
309
310 const char c0 = path[i + 0];
311 const char c3 = path[i + 3];
312
313 if (c0 == AlternateDirectorySeparator &&
314 (c3 == DirectorySeparator || c3 == AlternateDirectorySeparator ||
315 c3 == NullTerminator)) {
316 return true;
317 }
318
319 if (c3 == AlternateDirectorySeparator &&
320 (c0 == DirectorySeparator || c0 == AlternateDirectorySeparator)) {
321 return true;
322 }
323 }
324
325 if (path[i + 0] == AlternateDirectorySeparator && path[i + 1] == Dot &&
326 path[i + 2] == Dot /* && path[i + 3] == NullTerminator */) {
327 return true;
328 }
329 }
330
331 return false;
332 }
333
334 static constexpr Result IsNormalized(bool* out, size_t* out_len, const char* path,
335 bool allow_all_characters = false) {
336 // Use StringTraits names for remainder of scope
337 using namespace StringTraits;
338
339 // Parse the path
340 auto state = PathState::Start;
341 size_t len = 0;
342 while (path[len] != NullTerminator) {
343 // Get the current character
344 const char c = path[len++];
345
346 // Check the current character is valid
347 if (!allow_all_characters && state != PathState::Start) {
348 R_UNLESS(!IsInvalidCharacter(c), ResultInvalidCharacter);
349 }
350
351 // Process depending on current state
352 switch (state) {
353 // Import the PathState enums for convenience
354 using enum PathState;
355
356 case Start:
357 R_UNLESS(c == DirectorySeparator, ResultInvalidPathFormat);
358 state = FirstSeparator;
359 break;
360 case Normal:
361 if (c == DirectorySeparator) {
362 state = Separator;
363 }
364 break;
365 case FirstSeparator:
366 case Separator:
367 if (c == DirectorySeparator) {
368 *out = false;
369 R_SUCCEED();
370 }
371
372 if (c == Dot) {
373 state = CurrentDir;
374 } else {
375 state = Normal;
376 }
377 break;
378 case CurrentDir:
379 if (c == DirectorySeparator) {
380 *out = false;
381 R_SUCCEED();
382 }
383
384 if (c == Dot) {
385 state = ParentDir;
386 } else {
387 state = Normal;
388 }
389 break;
390 case ParentDir:
391 if (c == DirectorySeparator) {
392 *out = false;
393 R_SUCCEED();
394 }
395
396 state = Normal;
397 break;
398 default:
399 UNREACHABLE();
400 break;
401 }
402 }
403
404 // Check the final state
405 switch (state) {
406 // Import the PathState enums for convenience
407 using enum PathState;
408 case Start:
409 R_THROW(ResultInvalidPathFormat);
410 case Normal:
411 case FirstSeparator:
412 *out = true;
413 break;
414 case Separator:
415 case CurrentDir:
416 case ParentDir:
417 *out = false;
418 break;
419 default:
420 UNREACHABLE();
421 break;
422 }
423
424 // Set the output length
425 *out_len = len;
426 R_SUCCEED();
427 }
428
429 static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size,
430 bool is_windows_path, bool is_drive_relative_path,
431 bool allow_all_characters = false) {
432 // Use StringTraits names for remainder of scope
433 using namespace StringTraits;
434
435 // Prepare to iterate
436 const char* cur_path = path;
437 size_t total_len = 0;
438
439 // If path begins with a separator, check that we're not drive relative
440 if (cur_path[0] != DirectorySeparator) {
441 R_UNLESS(is_drive_relative_path, ResultInvalidPathFormat);
442
443 dst[total_len++] = DirectorySeparator;
444 }
445
446 // We're going to need to do path replacement, potentially
447 char* replacement_path = nullptr;
448 size_t replacement_path_size = 0;
449
450 SCOPE_EXIT({
451 if (replacement_path != nullptr) {
452 if (std::is_constant_evaluated()) {
453 delete[] replacement_path;
454 } else {
455 Deallocate(replacement_path, replacement_path_size);
456 }
457 }
458 });
459
460 // Perform path replacement, if necessary
461 if (IsParentDirectoryPathReplacementNeeded(cur_path)) {
462 if (std::is_constant_evaluated()) {
463 replacement_path_size = EntryNameLengthMax + 1;
464 replacement_path = new char[replacement_path_size];
465 } else {
466 replacement_path_size = EntryNameLengthMax + 1;
467 replacement_path = static_cast<char*>(Allocate(replacement_path_size));
468 }
469
470 ReplaceParentDirectoryPath(replacement_path, cur_path);
471
472 cur_path = replacement_path;
473 }
474
475 // Iterate, normalizing path components
476 bool skip_next_sep = false;
477 size_t i = 0;
478
479 while (cur_path[i] != NullTerminator) {
480 // Process a directory separator, if we run into one
481 if (cur_path[i] == DirectorySeparator) {
482 // Swallow separators
483 do {
484 ++i;
485 } while (cur_path[i] == DirectorySeparator);
486
487 // Check if we hit end of string
488 if (cur_path[i] == NullTerminator) {
489 break;
490 }
491
492 // If we aren't skipping the separator, write it, checking that we remain in bounds.
493 if (!skip_next_sep) {
494 if (total_len + 1 == max_out_size) {
495 dst[total_len] = NullTerminator;
496 *out_len = total_len;
497 R_THROW(ResultTooLongPath);
498 }
499
500 dst[total_len++] = DirectorySeparator;
501 }
502
503 // Don't skip the next separator
504 skip_next_sep = false;
505 }
506
507 // Get the length of the current directory component
508 size_t dir_len = 0;
509 while (cur_path[i + dir_len] != DirectorySeparator &&
510 cur_path[i + dir_len] != NullTerminator) {
511 // Check for validity
512 if (!allow_all_characters) {
513 R_UNLESS(!IsInvalidCharacter(cur_path[i + dir_len]), ResultInvalidCharacter);
514 }
515
516 ++dir_len;
517 }
518
519 // Handle the current dir component
520 if (IsCurrentDirectory(cur_path + i)) {
521 skip_next_sep = true;
522 } else if (IsParentDirectory(cur_path + i)) {
523 // We should have just written a separator
524 ASSERT(dst[total_len - 1] == DirectorySeparator);
525
526 // We should have started with a separator, for non-windows paths
527 if (!is_windows_path) {
528 ASSERT(dst[0] == DirectorySeparator);
529 }
530
531 // Remove the previous component
532 if (total_len == 1) {
533 R_UNLESS(is_windows_path, ResultDirectoryUnobtainable);
534
535 --total_len;
536 } else {
537 total_len -= 2;
538
539 do {
540 if (dst[total_len] == DirectorySeparator) {
541 break;
542 }
543 } while ((--total_len) != 0);
544 }
545
546 // We should be pointing to a directory separator, for non-windows paths
547 if (!is_windows_path) {
548 ASSERT(dst[total_len] == DirectorySeparator);
549 }
550
551 // We should remain in bounds
552 ASSERT(total_len < max_out_size);
553 } else {
554 // Copy, possibly truncating
555 if (total_len + dir_len + 1 > max_out_size) {
556 const size_t copy_len = max_out_size - (total_len + 1);
557
558 for (size_t j = 0; j < copy_len; ++j) {
559 dst[total_len++] = cur_path[i + j];
560 }
561
562 dst[total_len] = NullTerminator;
563 *out_len = total_len;
564 R_THROW(ResultTooLongPath);
565 }
566
567 for (size_t j = 0; j < dir_len; ++j) {
568 dst[total_len++] = cur_path[i + j];
569 }
570 }
571
572 // Advance past the current directory component
573 i += dir_len;
574 }
575
576 if (skip_next_sep) {
577 --total_len;
578 }
579
580 if (total_len == 0 && max_out_size != 0) {
581 total_len = 1;
582 dst[0] = DirectorySeparator;
583 }
584
585 // NOTE: Probable nintendo bug, as max_out_size must be at least total_len + 1 for the null
586 // terminator.
587 R_UNLESS(max_out_size >= total_len - 1, ResultTooLongPath);
588
589 dst[total_len] = NullTerminator;
590
591 // Check that the result path is normalized
592 bool is_normalized;
593 size_t dummy;
594 R_TRY(IsNormalized(std::addressof(is_normalized), std::addressof(dummy), dst,
595 allow_all_characters));
596
597 // Assert that the result path is normalized
598 ASSERT(is_normalized);
599
600 // Set the output length
601 *out_len = total_len;
602 R_SUCCEED();
603 }
604};
605
606class PathFormatter {
607private:
608 static constexpr Result CheckSharedName(const char* name, size_t len) {
609 // Use StringTraits names for remainder of scope
610 using namespace StringTraits;
611
612 if (len == 1) {
613 R_UNLESS(name[0] != Dot, ResultInvalidPathFormat);
614 } else if (len == 2) {
615 R_UNLESS(name[0] != Dot || name[1] != Dot, ResultInvalidPathFormat);
616 }
617
618 for (size_t i = 0; i < len; ++i) {
619 R_UNLESS(!IsInvalidCharacter(name[i]), ResultInvalidCharacter);
620 }
621
622 R_SUCCEED();
623 }
624
625 static constexpr Result CheckHostName(const char* name, size_t len) {
626 // Use StringTraits names for remainder of scope
627 using namespace StringTraits;
628
629 if (len == 2) {
630 R_UNLESS(name[0] != Dot || name[1] != Dot, ResultInvalidPathFormat);
631 }
632
633 for (size_t i = 0; i < len; ++i) {
634 R_UNLESS(!IsInvalidCharacterForHostName(name[i]), ResultInvalidCharacter);
635 }
636
637 R_SUCCEED();
638 }
639
640 static constexpr Result CheckInvalidBackslash(bool* out_contains_backslash, const char* path,
641 bool allow_backslash) {
642 // Use StringTraits names for remainder of scope
643 using namespace StringTraits;
644
645 // Default to no backslashes, so we can just write if we see one
646 *out_contains_backslash = false;
647
648 while (*path != NullTerminator) {
649 if (*(path++) == AlternateDirectorySeparator) {
650 *out_contains_backslash = true;
651
652 R_UNLESS(allow_backslash, ResultInvalidCharacter);
653 }
654 }
655
656 R_SUCCEED();
657 }
658
659public:
660 static constexpr Result CheckPathFormat(const char* path, const PathFlags& flags) {
661 bool normalized;
662 size_t len;
663 R_RETURN(IsNormalized(std::addressof(normalized), std::addressof(len), path, flags));
664 }
665
666 static constexpr Result SkipMountName(const char** out, size_t* out_len, const char* path) {
667 R_RETURN(ParseMountName(out, out_len, nullptr, 0, path));
668 }
669
670 static constexpr Result ParseMountName(const char** out, size_t* out_len, char* out_mount_name,
671 size_t out_mount_name_buffer_size, const char* path) {
672 // Check pre-conditions
673 ASSERT(path != nullptr);
674 ASSERT(out_len != nullptr);
675 ASSERT(out != nullptr);
676 ASSERT((out_mount_name == nullptr) == (out_mount_name_buffer_size == 0));
677
678 // Use StringTraits names for remainder of scope
679 using namespace StringTraits;
680
681 // Determine max mount length
682 const auto max_mount_len =
683 out_mount_name_buffer_size == 0
684 ? MountNameLengthMax + 1
685 : std::min(MountNameLengthMax + 1, out_mount_name_buffer_size);
686
687 // Parse the path until we see a drive separator
688 size_t mount_len = 0;
689 for (/* ... */; mount_len < max_mount_len && path[mount_len]; ++mount_len) {
690 const char c = path[mount_len];
691
692 // If we see a drive separator, advance, then we're done with the pre-drive separator
693 // part of the mount.
694 if (c == DriveSeparator) {
695 ++mount_len;
696 break;
697 }
698
699 // If we see a directory separator, we're not in a mount name
700 if (c == DirectorySeparator || c == AlternateDirectorySeparator) {
701 *out = path;
702 *out_len = 0;
703 R_SUCCEED();
704 }
705 }
706
707 // Check to be sure we're actually looking at a mount name
708 if (mount_len <= 2 || path[mount_len - 1] != DriveSeparator) {
709 *out = path;
710 *out_len = 0;
711 R_SUCCEED();
712 }
713
714 // Check that all characters in the mount name are allowable
715 for (size_t i = 0; i < mount_len; ++i) {
716 R_UNLESS(!IsInvalidCharacterForMountName(path[i]), ResultInvalidCharacter);
717 }
718
719 // Copy out the mount name
720 if (out_mount_name_buffer_size > 0) {
721 R_UNLESS(mount_len < out_mount_name_buffer_size, ResultTooLongPath);
722
723 for (size_t i = 0; i < mount_len; ++i) {
724 out_mount_name[i] = path[i];
725 }
726 out_mount_name[mount_len] = NullTerminator;
727 }
728
729 // Set the output
730 *out = path + mount_len;
731 *out_len = mount_len;
732 R_SUCCEED();
733 }
734
735 static constexpr Result SkipRelativeDotPath(const char** out, size_t* out_len,
736 const char* path) {
737 R_RETURN(ParseRelativeDotPath(out, out_len, nullptr, 0, path));
738 }
739
740 static constexpr Result ParseRelativeDotPath(const char** out, size_t* out_len,
741 char* out_relative,
742 size_t out_relative_buffer_size,
743 const char* path) {
744 // Check pre-conditions
745 ASSERT(path != nullptr);
746 ASSERT(out_len != nullptr);
747 ASSERT(out != nullptr);
748 ASSERT((out_relative == nullptr) == (out_relative_buffer_size == 0));
749
750 // Use StringTraits names for remainder of scope
751 using namespace StringTraits;
752
753 // Initialize the output buffer, if we have one
754 if (out_relative_buffer_size > 0) {
755 out_relative[0] = NullTerminator;
756 }
757
758 // Check if the path is relative
759 if (path[0] == Dot && (path[1] == NullTerminator || path[1] == DirectorySeparator ||
760 path[1] == AlternateDirectorySeparator)) {
761 if (out_relative_buffer_size > 0) {
762 R_UNLESS(out_relative_buffer_size >= 2, ResultTooLongPath);
763
764 out_relative[0] = Dot;
765 out_relative[1] = NullTerminator;
766 }
767
768 *out = path + 1;
769 *out_len = 1;
770 R_SUCCEED();
771 }
772
773 // Ensure the path isn't a parent directory
774 R_UNLESS(!(path[0] == Dot && path[1] == Dot), ResultDirectoryUnobtainable);
775
776 // There was no relative dot path
777 *out = path;
778 *out_len = 0;
779 R_SUCCEED();
780 }
781
782 static constexpr Result SkipWindowsPath(const char** out, size_t* out_len, bool* out_normalized,
783 const char* path, bool has_mount_name) {
784 // We're normalized if and only if the parsing doesn't throw ResultNotNormalized()
785 *out_normalized = true;
786
787 R_TRY_CATCH(ParseWindowsPath(out, out_len, nullptr, 0, path, has_mount_name)) {
788 R_CATCH(ResultNotNormalized) {
789 *out_normalized = false;
790 }
791 }
792 R_END_TRY_CATCH;
793 ON_RESULT_INCLUDED(ResultNotNormalized) {
794 *out_normalized = false;
795 };
796
797 R_SUCCEED();
798 }
799
800 static constexpr Result ParseWindowsPath(const char** out, size_t* out_len, char* out_win,
801 size_t out_win_buffer_size, const char* path,
802 bool has_mount_name) {
803 // Check pre-conditions
804 ASSERT(path != nullptr);
805 ASSERT(out_len != nullptr);
806 ASSERT(out != nullptr);
807 ASSERT((out_win == nullptr) == (out_win_buffer_size == 0));
808
809 // Use StringTraits names for remainder of scope
810 using namespace StringTraits;
811
812 // Initialize the output buffer, if we have one
813 if (out_win_buffer_size > 0) {
814 out_win[0] = NullTerminator;
815 }
816
817 // Handle path start
818 const char* cur_path = path;
819 if (has_mount_name && path[0] == DirectorySeparator) {
820 if (path[1] == AlternateDirectorySeparator && path[2] == AlternateDirectorySeparator) {
821 R_UNLESS(out_win_buffer_size > 0, ResultNotNormalized);
822
823 ++cur_path;
824 } else if (IsWindowsDrive(path + 1)) {
825 R_UNLESS(out_win_buffer_size > 0, ResultNotNormalized);
826
827 ++cur_path;
828 }
829 }
830
831 // Handle windows drive
832 if (IsWindowsDrive(cur_path)) {
833 // Parse up to separator
834 size_t win_path_len = WindowsDriveLength;
835 for (/* ... */; cur_path[win_path_len] != NullTerminator; ++win_path_len) {
836 R_UNLESS(!IsInvalidCharacter(cur_path[win_path_len]), ResultInvalidCharacter);
837
838 if (cur_path[win_path_len] == DirectorySeparator ||
839 cur_path[win_path_len] == AlternateDirectorySeparator) {
840 break;
841 }
842 }
843
844 // Ensure that we're normalized, if we're required to be
845 if (out_win_buffer_size == 0) {
846 for (size_t i = 0; i < win_path_len; ++i) {
847 R_UNLESS(cur_path[i] != AlternateDirectorySeparator, ResultNotNormalized);
848 }
849 } else {
850 // Ensure we can copy into the normalized buffer
851 R_UNLESS(win_path_len < out_win_buffer_size, ResultTooLongPath);
852
853 for (size_t i = 0; i < win_path_len; ++i) {
854 out_win[i] = cur_path[i];
855 }
856 out_win[win_path_len] = NullTerminator;
857
858 Replace(out_win, win_path_len, AlternateDirectorySeparator, DirectorySeparator);
859 }
860
861 *out = cur_path + win_path_len;
862 *out_len = win_path_len;
863 R_SUCCEED();
864 }
865
866 // Handle DOS device
867 if (IsDosDevicePath(cur_path)) {
868 size_t dos_prefix_len = DosDevicePathPrefixLength;
869
870 if (IsWindowsDrive(cur_path + dos_prefix_len)) {
871 dos_prefix_len += WindowsDriveLength;
872 } else {
873 --dos_prefix_len;
874 }
875
876 if (out_win_buffer_size > 0) {
877 // Ensure we can copy into the normalized buffer
878 R_UNLESS(dos_prefix_len < out_win_buffer_size, ResultTooLongPath);
879
880 for (size_t i = 0; i < dos_prefix_len; ++i) {
881 out_win[i] = cur_path[i];
882 }
883 out_win[dos_prefix_len] = NullTerminator;
884
885 Replace(out_win, dos_prefix_len, DirectorySeparator, AlternateDirectorySeparator);
886 }
887
888 *out = cur_path + dos_prefix_len;
889 *out_len = dos_prefix_len;
890 R_SUCCEED();
891 }
892
893 // Handle UNC path
894 if (IsUncPath(cur_path, false, true)) {
895 const char* final_path = cur_path;
896
897 R_UNLESS(cur_path[UncPathPrefixLength] != DirectorySeparator, ResultInvalidPathFormat);
898 R_UNLESS(cur_path[UncPathPrefixLength] != AlternateDirectorySeparator,
899 ResultInvalidPathFormat);
900
901 size_t cur_component_offset = 0;
902 size_t pos = UncPathPrefixLength;
903 for (/* ... */; cur_path[pos] != NullTerminator; ++pos) {
904 if (cur_path[pos] == DirectorySeparator ||
905 cur_path[pos] == AlternateDirectorySeparator) {
906 if (cur_component_offset != 0) {
907 R_TRY(CheckSharedName(cur_path + cur_component_offset,
908 pos - cur_component_offset));
909
910 final_path = cur_path + pos;
911 break;
912 }
913
914 R_UNLESS(cur_path[pos + 1] != DirectorySeparator, ResultInvalidPathFormat);
915 R_UNLESS(cur_path[pos + 1] != AlternateDirectorySeparator,
916 ResultInvalidPathFormat);
917
918 R_TRY(CheckHostName(cur_path + 2, pos - 2));
919
920 cur_component_offset = pos + 1;
921 }
922 }
923
924 R_UNLESS(cur_component_offset != pos, ResultInvalidPathFormat);
925
926 if (cur_component_offset != 0 && final_path == cur_path) {
927 R_TRY(CheckSharedName(cur_path + cur_component_offset, pos - cur_component_offset));
928
929 final_path = cur_path + pos;
930 }
931
932 size_t unc_prefix_len = final_path - cur_path;
933
934 // Ensure that we're normalized, if we're required to be
935 if (out_win_buffer_size == 0) {
936 for (size_t i = 0; i < unc_prefix_len; ++i) {
937 R_UNLESS(cur_path[i] != DirectorySeparator, ResultNotNormalized);
938 }
939 } else {
940 // Ensure we can copy into the normalized buffer
941 R_UNLESS(unc_prefix_len < out_win_buffer_size, ResultTooLongPath);
942
943 for (size_t i = 0; i < unc_prefix_len; ++i) {
944 out_win[i] = cur_path[i];
945 }
946 out_win[unc_prefix_len] = NullTerminator;
947
948 Replace(out_win, unc_prefix_len, DirectorySeparator, AlternateDirectorySeparator);
949 }
950
951 *out = cur_path + unc_prefix_len;
952 *out_len = unc_prefix_len;
953 R_SUCCEED();
954 }
955
956 // There's no windows path to parse
957 *out = path;
958 *out_len = 0;
959 R_SUCCEED();
960 }
961
962 static constexpr Result IsNormalized(bool* out, size_t* out_len, const char* path,
963 const PathFlags& flags = {}) {
964 // Ensure nothing is null
965 R_UNLESS(out != nullptr, ResultNullptrArgument);
966 R_UNLESS(out_len != nullptr, ResultNullptrArgument);
967 R_UNLESS(path != nullptr, ResultNullptrArgument);
968
969 // Verify that the path is valid utf-8
970 R_TRY(CheckUtf8(path));
971
972 // Use StringTraits names for remainder of scope
973 using namespace StringTraits;
974
975 // Handle the case where the path is empty
976 if (path[0] == NullTerminator) {
977 R_UNLESS(flags.IsEmptyPathAllowed(), ResultInvalidPathFormat);
978
979 *out = true;
980 *out_len = 0;
981 R_SUCCEED();
982 }
983
984 // All normalized paths start with a directory separator...unless they're windows paths,
985 // relative paths, or have mount names.
986 if (path[0] != DirectorySeparator) {
987 R_UNLESS(flags.IsWindowsPathAllowed() || flags.IsRelativePathAllowed() ||
988 flags.IsMountNameAllowed(),
989 ResultInvalidPathFormat);
990 }
991
992 // Check that the path is allowed to be a windows path, if it is
993 if (IsWindowsPath(path, false)) {
994 R_UNLESS(flags.IsWindowsPathAllowed(), ResultInvalidPathFormat);
995 }
996
997 // Skip past the mount name, if one is present
998 size_t total_len = 0;
999 size_t mount_name_len = 0;
1000 R_TRY(SkipMountName(std::addressof(path), std::addressof(mount_name_len), path));
1001
1002 // If we had a mount name, check that that was allowed
1003 if (mount_name_len > 0) {
1004 R_UNLESS(flags.IsMountNameAllowed(), ResultInvalidPathFormat);
1005
1006 total_len += mount_name_len;
1007 }
1008
1009 // Check that the path starts as a normalized path should
1010 if (path[0] != DirectorySeparator && !IsPathStartWithCurrentDirectory(path) &&
1011 !IsWindowsPath(path, false)) {
1012 R_UNLESS(flags.IsRelativePathAllowed(), ResultInvalidPathFormat);
1013 R_UNLESS(!IsInvalidCharacter(path[0]), ResultInvalidPathFormat);
1014
1015 *out = false;
1016 R_SUCCEED();
1017 }
1018
1019 // Process relative path
1020 size_t relative_len = 0;
1021 R_TRY(SkipRelativeDotPath(std::addressof(path), std::addressof(relative_len), path));
1022
1023 // If we have a relative path, check that was allowed
1024 if (relative_len > 0) {
1025 R_UNLESS(flags.IsRelativePathAllowed(), ResultInvalidPathFormat);
1026
1027 total_len += relative_len;
1028
1029 if (path[0] == NullTerminator) {
1030 *out = true;
1031 *out_len = total_len;
1032 R_SUCCEED();
1033 }
1034 }
1035
1036 // Process windows path
1037 size_t windows_len = 0;
1038 bool normalized_win = false;
1039 R_TRY(SkipWindowsPath(std::addressof(path), std::addressof(windows_len),
1040 std::addressof(normalized_win), path, mount_name_len > 0));
1041
1042 // If the windows path wasn't normalized, we're not normalized
1043 if (!normalized_win) {
1044 R_UNLESS(flags.IsWindowsPathAllowed(), ResultInvalidPathFormat);
1045
1046 *out = false;
1047 R_SUCCEED();
1048 }
1049
1050 // If we had a windows path, check that was allowed
1051 if (windows_len > 0) {
1052 R_UNLESS(flags.IsWindowsPathAllowed(), ResultInvalidPathFormat);
1053
1054 total_len += windows_len;
1055
1056 // We can't have both a relative path and a windows path
1057 R_UNLESS(relative_len == 0, ResultInvalidPathFormat);
1058
1059 // A path ending in a windows path isn't normalized
1060 if (path[0] == NullTerminator) {
1061 *out = false;
1062 R_SUCCEED();
1063 }
1064
1065 // Check that there are no windows directory separators in the path
1066 for (size_t i = 0; path[i] != NullTerminator; ++i) {
1067 if (path[i] == AlternateDirectorySeparator) {
1068 *out = false;
1069 R_SUCCEED();
1070 }
1071 }
1072 }
1073
1074 // Check that parent directory replacement is not needed if backslashes are allowed
1075 if (flags.IsBackslashAllowed() &&
1076 PathNormalizer::IsParentDirectoryPathReplacementNeeded(path)) {
1077 *out = false;
1078 R_SUCCEED();
1079 }
1080
1081 // Check that the backslash state is valid
1082 bool is_backslash_contained = false;
1083 R_TRY(CheckInvalidBackslash(std::addressof(is_backslash_contained), path,
1084 flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed()));
1085
1086 // Check that backslashes are contained only if allowed
1087 if (is_backslash_contained && !flags.IsBackslashAllowed()) {
1088 *out = false;
1089 R_SUCCEED();
1090 }
1091
1092 // Check that the final result path is normalized
1093 size_t normal_len = 0;
1094 R_TRY(PathNormalizer::IsNormalized(out, std::addressof(normal_len), path,
1095 flags.IsAllCharactersAllowed()));
1096
1097 // Add the normal length
1098 total_len += normal_len;
1099
1100 // Set the output length
1101 *out_len = total_len;
1102 R_SUCCEED();
1103 }
1104
1105 static Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len,
1106 const PathFlags& flags) {
1107 // Use StringTraits names for remainder of scope
1108 using namespace StringTraits;
1109
1110 // Prepare to iterate
1111 const char* src = path;
1112 size_t cur_pos = 0;
1113 bool is_windows_path = false;
1114
1115 // Check if the path is empty
1116 if (src[0] == NullTerminator) {
1117 if (dst_size != 0) {
1118 dst[0] = NullTerminator;
1119 }
1120
1121 R_UNLESS(flags.IsEmptyPathAllowed(), ResultInvalidPathFormat);
1122
1123 R_SUCCEED();
1124 }
1125
1126 // Handle a mount name
1127 size_t mount_name_len = 0;
1128 if (flags.IsMountNameAllowed()) {
1129 R_TRY(ParseMountName(std::addressof(src), std::addressof(mount_name_len), dst + cur_pos,
1130 dst_size - cur_pos, src));
1131
1132 cur_pos += mount_name_len;
1133 }
1134
1135 // Handle a drive-relative prefix
1136 bool is_drive_relative = false;
1137 if (src[0] != DirectorySeparator && !IsPathStartWithCurrentDirectory(src) &&
1138 !IsWindowsPath(src, false)) {
1139 R_UNLESS(flags.IsRelativePathAllowed(), ResultInvalidPathFormat);
1140 R_UNLESS(!IsInvalidCharacter(src[0]), ResultInvalidPathFormat);
1141
1142 dst[cur_pos++] = Dot;
1143 is_drive_relative = true;
1144 }
1145
1146 size_t relative_len = 0;
1147 if (flags.IsRelativePathAllowed()) {
1148 R_UNLESS(cur_pos < dst_size, ResultTooLongPath);
1149
1150 R_TRY(ParseRelativeDotPath(std::addressof(src), std::addressof(relative_len),
1151 dst + cur_pos, dst_size - cur_pos, src));
1152
1153 cur_pos += relative_len;
1154
1155 if (src[0] == NullTerminator) {
1156 R_UNLESS(cur_pos < dst_size, ResultTooLongPath);
1157
1158 dst[cur_pos] = NullTerminator;
1159 R_SUCCEED();
1160 }
1161 }
1162
1163 // Handle a windows path
1164 if (flags.IsWindowsPathAllowed()) {
1165 const char* const orig = src;
1166
1167 R_UNLESS(cur_pos < dst_size, ResultTooLongPath);
1168
1169 size_t windows_len = 0;
1170 R_TRY(ParseWindowsPath(std::addressof(src), std::addressof(windows_len), dst + cur_pos,
1171 dst_size - cur_pos, src, mount_name_len != 0));
1172
1173 cur_pos += windows_len;
1174
1175 if (src[0] == NullTerminator) {
1176 /* NOTE: Bug in original code here repeated, should be checking cur_pos + 2. */
1177 R_UNLESS(cur_pos + 1 < dst_size, ResultTooLongPath);
1178
1179 dst[cur_pos + 0] = DirectorySeparator;
1180 dst[cur_pos + 1] = NullTerminator;
1181 R_SUCCEED();
1182 }
1183
1184 if ((src - orig) > 0) {
1185 is_windows_path = true;
1186 }
1187 }
1188
1189 // Check for invalid backslash
1190 bool backslash_contained = false;
1191 R_TRY(CheckInvalidBackslash(std::addressof(backslash_contained), src,
1192 flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed()));
1193
1194 // Handle backslash replacement as necessary
1195 if (backslash_contained && flags.IsWindowsPathAllowed()) {
1196 // Create a temporary buffer holding a slash-replaced version of the path.
1197 // NOTE: Nintendo unnecessarily allocates and replaces here a fully copy of the path,
1198 // despite having skipped some of it already.
1199 const size_t replaced_src_len = path_len - (src - path);
1200
1201 char* replaced_src = nullptr;
1202 SCOPE_EXIT({
1203 if (replaced_src != nullptr) {
1204 if (std::is_constant_evaluated()) {
1205 delete[] replaced_src;
1206 } else {
1207 Deallocate(replaced_src, replaced_src_len);
1208 }
1209 }
1210 });
1211
1212 if (std::is_constant_evaluated()) {
1213 replaced_src = new char[replaced_src_len];
1214 } else {
1215 replaced_src = static_cast<char*>(Allocate(replaced_src_len));
1216 }
1217
1218 Strlcpy<char>(replaced_src, src, replaced_src_len);
1219
1220 Replace(replaced_src, replaced_src_len, AlternateDirectorySeparator,
1221 DirectorySeparator);
1222
1223 size_t dummy;
1224 R_TRY(PathNormalizer::Normalize(dst + cur_pos, std::addressof(dummy), replaced_src,
1225 dst_size - cur_pos, is_windows_path, is_drive_relative,
1226 flags.IsAllCharactersAllowed()));
1227 } else {
1228 // We can just do normalization
1229 size_t dummy;
1230 R_TRY(PathNormalizer::Normalize(dst + cur_pos, std::addressof(dummy), src,
1231 dst_size - cur_pos, is_windows_path, is_drive_relative,
1232 flags.IsAllCharactersAllowed()));
1233 }
1234
1235 R_SUCCEED();
1236 }
1237};
1238
1239} // namespace FileSys
diff --git a/src/core/file_sys/fs_string_util.h b/src/core/file_sys/fs_string_util.h
new file mode 100644
index 000000000..874e09054
--- /dev/null
+++ b/src/core/file_sys/fs_string_util.h
@@ -0,0 +1,226 @@
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/assert.h"
7
8namespace FileSys {
9
10template <typename T>
11constexpr int Strlen(const T* str) {
12 ASSERT(str != nullptr);
13
14 int length = 0;
15 while (*str++) {
16 ++length;
17 }
18
19 return length;
20}
21
22template <typename T>
23constexpr int Strnlen(const T* str, int count) {
24 ASSERT(str != nullptr);
25 ASSERT(count >= 0);
26
27 int length = 0;
28 while (count-- && *str++) {
29 ++length;
30 }
31
32 return length;
33}
34
35template <typename T>
36constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
37 ASSERT(lhs != nullptr);
38 ASSERT(rhs != nullptr);
39 ASSERT(count >= 0);
40
41 if (count == 0) {
42 return 0;
43 }
44
45 T l, r;
46 do {
47 l = *(lhs++);
48 r = *(rhs++);
49 } while (l && (l == r) && (--count));
50
51 return l - r;
52}
53
54template <typename T>
55static constexpr int Strlcpy(T* dst, const T* src, int count) {
56 ASSERT(dst != nullptr);
57 ASSERT(src != nullptr);
58
59 const T* cur = src;
60 if (count > 0) {
61 while ((--count) && *cur) {
62 *(dst++) = *(cur++);
63 }
64 *dst = 0;
65 }
66
67 while (*cur) {
68 cur++;
69 }
70
71 return static_cast<int>(cur - src);
72}
73
74enum CharacterEncodingResult {
75 CharacterEncodingResult_Success = 0,
76 CharacterEncodingResult_InsufficientLength = 1,
77 CharacterEncodingResult_InvalidFormat = 2,
78};
79
80namespace impl {
81
82class CharacterEncodingHelper {
83public:
84 static constexpr int8_t Utf8NBytesInnerTable[0x100 + 1] = {
85 -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
86 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
87 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
88 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
89 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
92 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
93 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,
94 };
95
96 static constexpr char GetUtf8NBytes(size_t i) {
97 return static_cast<char>(Utf8NBytesInnerTable[1 + i]);
98 }
99};
100
101} // namespace impl
102
103constexpr inline CharacterEncodingResult ConvertCharacterUtf8ToUtf32(u32* dst, const char* src) {
104 // Check pre-conditions
105 ASSERT(dst != nullptr);
106 ASSERT(src != nullptr);
107
108 // Perform the conversion
109 const auto* p = src;
110 switch (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[0]))) {
111 case 1:
112 *dst = static_cast<u32>(p[0]);
113 return CharacterEncodingResult_Success;
114 case 2:
115 if ((static_cast<u32>(p[0]) & 0x1E) != 0) {
116 if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) ==
117 0) {
118 *dst = (static_cast<u32>(p[0] & 0x1F) << 6) | (static_cast<u32>(p[1] & 0x3F) << 0);
119 return CharacterEncodingResult_Success;
120 }
121 }
122 break;
123 case 3:
124 if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 &&
125 impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0) {
126 const u32 c = (static_cast<u32>(p[0] & 0xF) << 12) |
127 (static_cast<u32>(p[1] & 0x3F) << 6) |
128 (static_cast<u32>(p[2] & 0x3F) << 0);
129 if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) {
130 *dst = c;
131 return CharacterEncodingResult_Success;
132 }
133 }
134 return CharacterEncodingResult_InvalidFormat;
135 case 4:
136 if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 &&
137 impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0 &&
138 impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[3])) == 0) {
139 const u32 c =
140 (static_cast<u32>(p[0] & 0x7) << 18) | (static_cast<u32>(p[1] & 0x3F) << 12) |
141 (static_cast<u32>(p[2] & 0x3F) << 6) | (static_cast<u32>(p[3] & 0x3F) << 0);
142 if (c >= 0x10000 && c < 0x110000) {
143 *dst = c;
144 return CharacterEncodingResult_Success;
145 }
146 }
147 return CharacterEncodingResult_InvalidFormat;
148 default:
149 break;
150 }
151
152 // We failed to convert
153 return CharacterEncodingResult_InvalidFormat;
154}
155
156constexpr inline CharacterEncodingResult PickOutCharacterFromUtf8String(char* dst,
157 const char** str) {
158 // Check pre-conditions
159 ASSERT(dst != nullptr);
160 ASSERT(str != nullptr);
161 ASSERT(*str != nullptr);
162
163 // Clear the output
164 dst[0] = 0;
165 dst[1] = 0;
166 dst[2] = 0;
167 dst[3] = 0;
168
169 // Perform the conversion
170 const auto* p = *str;
171 u32 c = static_cast<u32>(*p);
172 switch (impl::CharacterEncodingHelper::GetUtf8NBytes(c)) {
173 case 1:
174 dst[0] = (*str)[0];
175 ++(*str);
176 break;
177 case 2:
178 if ((p[0] & 0x1E) != 0) {
179 if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) ==
180 0) {
181 c = (static_cast<u32>(p[0] & 0x1F) << 6) | (static_cast<u32>(p[1] & 0x3F) << 0);
182 dst[0] = (*str)[0];
183 dst[1] = (*str)[1];
184 (*str) += 2;
185 break;
186 }
187 }
188 return CharacterEncodingResult_InvalidFormat;
189 case 3:
190 if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 &&
191 impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0) {
192 c = (static_cast<u32>(p[0] & 0xF) << 12) | (static_cast<u32>(p[1] & 0x3F) << 6) |
193 (static_cast<u32>(p[2] & 0x3F) << 0);
194 if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) {
195 dst[0] = (*str)[0];
196 dst[1] = (*str)[1];
197 dst[2] = (*str)[2];
198 (*str) += 3;
199 break;
200 }
201 }
202 return CharacterEncodingResult_InvalidFormat;
203 case 4:
204 if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 &&
205 impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0 &&
206 impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[3])) == 0) {
207 c = (static_cast<u32>(p[0] & 0x7) << 18) | (static_cast<u32>(p[1] & 0x3F) << 12) |
208 (static_cast<u32>(p[2] & 0x3F) << 6) | (static_cast<u32>(p[3] & 0x3F) << 0);
209 if (c >= 0x10000 && c < 0x110000) {
210 dst[0] = (*str)[0];
211 dst[1] = (*str)[1];
212 dst[2] = (*str)[2];
213 dst[3] = (*str)[3];
214 (*str) += 4;
215 break;
216 }
217 }
218 return CharacterEncodingResult_InvalidFormat;
219 default:
220 return CharacterEncodingResult_InvalidFormat;
221 }
222
223 return CharacterEncodingResult_Success;
224}
225
226} // namespace FileSys
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index dd9cca103..8807bbd0f 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -8,8 +8,8 @@
8#include "common/assert.h" 8#include "common/assert.h"
9#include "core/file_sys/fsmitm_romfsbuild.h" 9#include "core/file_sys/fsmitm_romfsbuild.h"
10#include "core/file_sys/ips_layer.h" 10#include "core/file_sys/ips_layer.h"
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
12#include "core/file_sys/vfs_vector.h" 12#include "core/file_sys/vfs/vfs_vector.h"
13 13
14namespace FileSys { 14namespace FileSys {
15 15
diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h
index f387c79f1..dd7ed4a7b 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.h
+++ b/src/core/file_sys/fsmitm_romfsbuild.h
@@ -7,7 +7,7 @@
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs/vfs.h"
11 11
12namespace FileSys { 12namespace FileSys {
13 13
diff --git a/src/core/file_sys/fssystem/fs_i_storage.h b/src/core/file_sys/fssystem/fs_i_storage.h
index 416dd57b8..37336c9ae 100644
--- a/src/core/file_sys/fssystem/fs_i_storage.h
+++ b/src/core/file_sys/fssystem/fs_i_storage.h
@@ -5,7 +5,7 @@
5 5
6#include "common/overflow.h" 6#include "common/overflow.h"
7#include "core/file_sys/errors.h" 7#include "core/file_sys/errors.h"
8#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs/vfs.h"
9 9
10namespace FileSys { 10namespace FileSys {
11 11
diff --git a/src/core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp b/src/core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
index f25c95472..bc1cddbb0 100644
--- a/src/core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
+++ b/src/core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
@@ -4,7 +4,7 @@
4#include "core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h" 4#include "core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h"
5#include "core/file_sys/fssystem/fssystem_aes_ctr_storage.h" 5#include "core/file_sys/fssystem/fssystem_aes_ctr_storage.h"
6#include "core/file_sys/fssystem/fssystem_nca_header.h" 6#include "core/file_sys/fssystem/fssystem_nca_header.h"
7#include "core/file_sys/vfs_offset.h" 7#include "core/file_sys/vfs/vfs_offset.h"
8 8
9namespace FileSys { 9namespace FileSys {
10 10
diff --git a/src/core/file_sys/fssystem/fssystem_aes_ctr_storage.h b/src/core/file_sys/fssystem/fssystem_aes_ctr_storage.h
index 339e49697..5abd93d33 100644
--- a/src/core/file_sys/fssystem/fssystem_aes_ctr_storage.h
+++ b/src/core/file_sys/fssystem/fssystem_aes_ctr_storage.h
@@ -9,7 +9,7 @@
9#include "core/crypto/key_manager.h" 9#include "core/crypto/key_manager.h"
10#include "core/file_sys/errors.h" 10#include "core/file_sys/errors.h"
11#include "core/file_sys/fssystem/fs_i_storage.h" 11#include "core/file_sys/fssystem/fs_i_storage.h"
12#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs/vfs.h"
13 13
14namespace FileSys { 14namespace FileSys {
15 15
diff --git a/src/core/file_sys/fssystem/fssystem_bucket_tree.h b/src/core/file_sys/fssystem/fssystem_bucket_tree.h
index 46850cd48..3a5e21d1a 100644
--- a/src/core/file_sys/fssystem/fssystem_bucket_tree.h
+++ b/src/core/file_sys/fssystem/fssystem_bucket_tree.h
@@ -10,7 +10,7 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/literals.h" 11#include "common/literals.h"
12 12
13#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs/vfs.h"
14#include "core/hle/result.h" 14#include "core/hle/result.h"
15 15
16namespace FileSys { 16namespace FileSys {
diff --git a/src/core/file_sys/fssystem/fssystem_compressed_storage.h b/src/core/file_sys/fssystem/fssystem_compressed_storage.h
index 33d93938e..74c98630e 100644
--- a/src/core/file_sys/fssystem/fssystem_compressed_storage.h
+++ b/src/core/file_sys/fssystem/fssystem_compressed_storage.h
@@ -10,7 +10,7 @@
10#include "core/file_sys/fssystem/fssystem_bucket_tree.h" 10#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
11#include "core/file_sys/fssystem/fssystem_compression_common.h" 11#include "core/file_sys/fssystem/fssystem_compression_common.h"
12#include "core/file_sys/fssystem/fssystem_pooled_buffer.h" 12#include "core/file_sys/fssystem/fssystem_pooled_buffer.h"
13#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs/vfs.h"
14 14
15namespace FileSys { 15namespace FileSys {
16 16
diff --git a/src/core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.cpp b/src/core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.cpp
index 4a75b5308..39bb7b808 100644
--- a/src/core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.cpp
+++ b/src/core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.cpp
@@ -2,7 +2,7 @@
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/fssystem/fssystem_hierarchical_integrity_verification_storage.h" 4#include "core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h"
5#include "core/file_sys/vfs_offset.h" 5#include "core/file_sys/vfs/vfs_offset.h"
6 6
7namespace FileSys { 7namespace FileSys {
8 8
diff --git a/src/core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h b/src/core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h
index 5cf697efe..bd129db47 100644
--- a/src/core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h
+++ b/src/core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h
@@ -8,7 +8,7 @@
8#include "core/file_sys/fssystem/fs_types.h" 8#include "core/file_sys/fssystem/fs_types.h"
9#include "core/file_sys/fssystem/fssystem_alignment_matching_storage.h" 9#include "core/file_sys/fssystem/fssystem_alignment_matching_storage.h"
10#include "core/file_sys/fssystem/fssystem_integrity_verification_storage.h" 10#include "core/file_sys/fssystem/fssystem_integrity_verification_storage.h"
11#include "core/file_sys/vfs_offset.h" 11#include "core/file_sys/vfs/vfs_offset.h"
12 12
13namespace FileSys { 13namespace FileSys {
14 14
diff --git a/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h b/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h
index 18df400af..41d3960b8 100644
--- a/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h
+++ b/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h
@@ -7,7 +7,7 @@
7 7
8#include "core/file_sys/errors.h" 8#include "core/file_sys/errors.h"
9#include "core/file_sys/fssystem/fs_i_storage.h" 9#include "core/file_sys/fssystem/fs_i_storage.h"
10#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs/vfs.h"
11 11
12namespace FileSys { 12namespace FileSys {
13 13
diff --git a/src/core/file_sys/fssystem/fssystem_indirect_storage.h b/src/core/file_sys/fssystem/fssystem_indirect_storage.h
index 7854335bf..d4b95fd27 100644
--- a/src/core/file_sys/fssystem/fssystem_indirect_storage.h
+++ b/src/core/file_sys/fssystem/fssystem_indirect_storage.h
@@ -7,8 +7,8 @@
7#include "core/file_sys/fssystem/fs_i_storage.h" 7#include "core/file_sys/fssystem/fs_i_storage.h"
8#include "core/file_sys/fssystem/fssystem_bucket_tree.h" 8#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
9#include "core/file_sys/fssystem/fssystem_bucket_tree_template_impl.h" 9#include "core/file_sys/fssystem/fssystem_bucket_tree_template_impl.h"
10#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs/vfs.h"
11#include "core/file_sys/vfs_offset.h" 11#include "core/file_sys/vfs/vfs_offset.h"
12 12
13namespace FileSys { 13namespace FileSys {
14 14
diff --git a/src/core/file_sys/fssystem/fssystem_integrity_romfs_storage.h b/src/core/file_sys/fssystem/fssystem_integrity_romfs_storage.h
index 5f8512b2a..240d1e388 100644
--- a/src/core/file_sys/fssystem/fssystem_integrity_romfs_storage.h
+++ b/src/core/file_sys/fssystem/fssystem_integrity_romfs_storage.h
@@ -5,7 +5,7 @@
5 5
6#include "core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h" 6#include "core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h"
7#include "core/file_sys/fssystem/fssystem_nca_header.h" 7#include "core/file_sys/fssystem/fssystem_nca_header.h"
8#include "core/file_sys/vfs_vector.h" 8#include "core/file_sys/vfs/vfs_vector.h"
9 9
10namespace FileSys { 10namespace FileSys {
11 11
diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp
index 0f5432203..ab5a7984e 100644
--- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp
+++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp
@@ -14,8 +14,8 @@
14#include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h" 14#include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h"
15#include "core/file_sys/fssystem/fssystem_sparse_storage.h" 15#include "core/file_sys/fssystem/fssystem_sparse_storage.h"
16#include "core/file_sys/fssystem/fssystem_switch_storage.h" 16#include "core/file_sys/fssystem/fssystem_switch_storage.h"
17#include "core/file_sys/vfs_offset.h" 17#include "core/file_sys/vfs/vfs_offset.h"
18#include "core/file_sys/vfs_vector.h" 18#include "core/file_sys/vfs/vfs_vector.h"
19 19
20namespace FileSys { 20namespace FileSys {
21 21
diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h
index 5771a21fc..5bc838de6 100644
--- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h
+++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h
@@ -5,7 +5,7 @@
5 5
6#include "core/file_sys/fssystem/fssystem_compression_common.h" 6#include "core/file_sys/fssystem/fssystem_compression_common.h"
7#include "core/file_sys/fssystem/fssystem_nca_header.h" 7#include "core/file_sys/fssystem/fssystem_nca_header.h"
8#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs/vfs.h"
9 9
10namespace FileSys { 10namespace FileSys {
11 11
diff --git a/src/core/file_sys/fssystem/fssystem_nca_reader.cpp b/src/core/file_sys/fssystem/fssystem_nca_reader.cpp
index a3714ab37..08924e2a6 100644
--- a/src/core/file_sys/fssystem/fssystem_nca_reader.cpp
+++ b/src/core/file_sys/fssystem/fssystem_nca_reader.cpp
@@ -3,7 +3,7 @@
3 3
4#include "core/file_sys/fssystem/fssystem_aes_xts_storage.h" 4#include "core/file_sys/fssystem/fssystem_aes_xts_storage.h"
5#include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h" 5#include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h"
6#include "core/file_sys/vfs_offset.h" 6#include "core/file_sys/vfs/vfs_offset.h"
7 7
8namespace FileSys { 8namespace FileSys {
9 9
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index 31033634c..d1ac24072 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -12,7 +12,7 @@
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/swap.h" 13#include "common/swap.h"
14#include "core/file_sys/ips_layer.h" 14#include "core/file_sys/ips_layer.h"
15#include "core/file_sys/vfs_vector.h" 15#include "core/file_sys/vfs/vfs_vector.h"
16 16
17namespace FileSys { 17namespace FileSys {
18 18
diff --git a/src/core/file_sys/ips_layer.h b/src/core/file_sys/ips_layer.h
index f2717bae7..d81378e8a 100644
--- a/src/core/file_sys/ips_layer.h
+++ b/src/core/file_sys/ips_layer.h
@@ -8,7 +8,7 @@
8#include <vector> 8#include <vector>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
12 12
13namespace FileSys { 13namespace FileSys {
14 14
diff --git a/src/core/file_sys/kernel_executable.cpp b/src/core/file_sys/kernel_executable.cpp
index 70c062f4c..b84492d30 100644
--- a/src/core/file_sys/kernel_executable.cpp
+++ b/src/core/file_sys/kernel_executable.cpp
@@ -5,7 +5,7 @@
5 5
6#include "common/string_util.h" 6#include "common/string_util.h"
7#include "core/file_sys/kernel_executable.h" 7#include "core/file_sys/kernel_executable.h"
8#include "core/file_sys/vfs_offset.h" 8#include "core/file_sys/vfs/vfs_offset.h"
9#include "core/loader/loader.h" 9#include "core/loader/loader.h"
10 10
11namespace FileSys { 11namespace FileSys {
diff --git a/src/core/file_sys/kernel_executable.h b/src/core/file_sys/kernel_executable.h
index d5b9199b5..928ba2d99 100644
--- a/src/core/file_sys/kernel_executable.h
+++ b/src/core/file_sys/kernel_executable.h
@@ -10,7 +10,7 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/file_sys/vfs_types.h" 13#include "core/file_sys/vfs/vfs_types.h"
14 14
15namespace Loader { 15namespace Loader {
16enum class ResultStatus : u16; 16enum class ResultStatus : u16;
diff --git a/src/core/file_sys/mode.h b/src/core/file_sys/mode.h
deleted file mode 100644
index 9596ef4fd..000000000
--- a/src/core/file_sys/mode.h
+++ /dev/null
@@ -1,23 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace FileSys {
10
11enum class Mode : u32 {
12 Read = 1 << 0,
13 Write = 1 << 1,
14 ReadWrite = Read | Write,
15 Append = 1 << 2,
16 ReadAppend = Read | Append,
17 WriteAppend = Write | Append,
18 All = ReadWrite | Append,
19};
20
21DECLARE_ENUM_FLAG_OPERATORS(Mode)
22
23} // namespace FileSys
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index f4a774675..9e855c50d 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -6,7 +6,7 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "common/swap.h" 7#include "common/swap.h"
8#include "core/file_sys/nca_metadata.h" 8#include "core/file_sys/nca_metadata.h"
9#include "core/file_sys/vfs.h" 9#include "core/file_sys/vfs/vfs.h"
10 10
11namespace FileSys { 11namespace FileSys {
12 12
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index 68e463b5f..6243b822a 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -8,7 +8,7 @@
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 "common/swap.h" 10#include "common/swap.h"
11#include "core/file_sys/vfs_types.h" 11#include "core/file_sys/vfs/vfs_types.h"
12 12
13namespace FileSys { 13namespace FileSys {
14class CNMT; 14class CNMT;
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index 2422cb51b..dd8de9d8a 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -9,7 +9,7 @@
9 9
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/file_sys/partition_filesystem.h" 11#include "core/file_sys/partition_filesystem.h"
12#include "core/file_sys/vfs_offset.h" 12#include "core/file_sys/vfs/vfs_offset.h"
13#include "core/loader/loader.h" 13#include "core/loader/loader.h"
14 14
15namespace FileSys { 15namespace FileSys {
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h
index b6e3a2b0c..777b9ead9 100644
--- a/src/core/file_sys/partition_filesystem.h
+++ b/src/core/file_sys/partition_filesystem.h
@@ -9,7 +9,7 @@
9#include "common/common_funcs.h" 9#include "common/common_funcs.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs/vfs.h"
13 13
14namespace Loader { 14namespace Loader {
15enum class ResultStatus : u16; 15enum class ResultStatus : u16;
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 612122224..21d45235e 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -21,9 +21,9 @@
21#include "core/file_sys/patch_manager.h" 21#include "core/file_sys/patch_manager.h"
22#include "core/file_sys/registered_cache.h" 22#include "core/file_sys/registered_cache.h"
23#include "core/file_sys/romfs.h" 23#include "core/file_sys/romfs.h"
24#include "core/file_sys/vfs_cached.h" 24#include "core/file_sys/vfs/vfs_cached.h"
25#include "core/file_sys/vfs_layered.h" 25#include "core/file_sys/vfs/vfs_layered.h"
26#include "core/file_sys/vfs_vector.h" 26#include "core/file_sys/vfs/vfs_vector.h"
27#include "core/hle/service/filesystem/filesystem.h" 27#include "core/hle/service/filesystem/filesystem.h"
28#include "core/hle/service/ns/language.h" 28#include "core/hle/service/ns/language.h"
29#include "core/hle/service/set/settings_server.h" 29#include "core/hle/service/set/settings_server.h"
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index 2601b8217..552c0fbe2 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -9,7 +9,7 @@
9#include <string> 9#include <string>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/file_sys/nca_metadata.h" 11#include "core/file_sys/nca_metadata.h"
12#include "core/file_sys/vfs_types.h" 12#include "core/file_sys/vfs/vfs_types.h"
13#include "core/memory/dmnt_cheat_types.h" 13#include "core/memory/dmnt_cheat_types.h"
14 14
15namespace Core { 15namespace Core {
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 539c7f7af..ae4e441c9 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -7,7 +7,7 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/scope_exit.h" 8#include "common/scope_exit.h"
9#include "core/file_sys/program_metadata.h" 9#include "core/file_sys/program_metadata.h"
10#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs/vfs.h"
11#include "core/loader/loader.h" 11#include "core/loader/loader.h"
12 12
13namespace FileSys { 13namespace FileSys {
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index a53092b87..115e6d6cd 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -10,7 +10,7 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/file_sys/vfs_types.h" 13#include "core/file_sys/vfs/vfs_types.h"
14 14
15namespace Loader { 15namespace Loader {
16enum class ResultStatus : u16; 16enum class ResultStatus : u16;
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 1cc77ad14..85d30543c 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -17,7 +17,7 @@
17#include "core/file_sys/nca_metadata.h" 17#include "core/file_sys/nca_metadata.h"
18#include "core/file_sys/registered_cache.h" 18#include "core/file_sys/registered_cache.h"
19#include "core/file_sys/submission_package.h" 19#include "core/file_sys/submission_package.h"
20#include "core/file_sys/vfs_concat.h" 20#include "core/file_sys/vfs/vfs_concat.h"
21#include "core/loader/loader.h" 21#include "core/loader/loader.h"
22 22
23namespace FileSys { 23namespace FileSys {
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 64815a845..a7fc55673 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -11,7 +11,7 @@
11#include <boost/container/flat_map.hpp> 11#include <boost/container/flat_map.hpp>
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/crypto/key_manager.h" 13#include "core/crypto/key_manager.h"
14#include "core/file_sys/vfs.h" 14#include "core/file_sys/vfs/vfs.h"
15 15
16namespace FileSys { 16namespace FileSys {
17class CNMT; 17class CNMT;
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index 6182598ae..a2b280973 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -9,11 +9,11 @@
9#include "common/swap.h" 9#include "common/swap.h"
10#include "core/file_sys/fsmitm_romfsbuild.h" 10#include "core/file_sys/fsmitm_romfsbuild.h"
11#include "core/file_sys/romfs.h" 11#include "core/file_sys/romfs.h"
12#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs/vfs.h"
13#include "core/file_sys/vfs_cached.h" 13#include "core/file_sys/vfs/vfs_cached.h"
14#include "core/file_sys/vfs_concat.h" 14#include "core/file_sys/vfs/vfs_concat.h"
15#include "core/file_sys/vfs_offset.h" 15#include "core/file_sys/vfs/vfs_offset.h"
16#include "core/file_sys/vfs_vector.h" 16#include "core/file_sys/vfs/vfs_vector.h"
17 17
18namespace FileSys { 18namespace FileSys {
19namespace { 19namespace {
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h
index b75ff1aad..3c0aca291 100644
--- a/src/core/file_sys/romfs.h
+++ b/src/core/file_sys/romfs.h
@@ -3,7 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/vfs.h" 6#include "core/file_sys/vfs/vfs.h"
7 7
8namespace FileSys { 8namespace FileSys {
9 9
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index e4809bc94..11ecfabdf 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -6,7 +6,7 @@
6#include <memory> 6#include <memory>
7 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/file_sys/vfs_types.h" 9#include "core/file_sys/vfs/vfs_types.h"
10#include "core/hle/result.h" 10#include "core/hle/result.h"
11 11
12namespace Loader { 12namespace Loader {
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 23196cd5f..cbf411a20 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -8,7 +8,7 @@
8#include "common/uuid.h" 8#include "common/uuid.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/file_sys/savedata_factory.h" 10#include "core/file_sys/savedata_factory.h"
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
12 12
13namespace FileSys { 13namespace FileSys {
14 14
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index 30d96928e..5ab7e4d32 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -7,7 +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/vfs.h" 10#include "core/file_sys/vfs/vfs.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12 12
13namespace Core { 13namespace Core {
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index d5158cd64..f3e2e21f4 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -4,7 +4,7 @@
4#include <memory> 4#include <memory>
5#include "core/file_sys/registered_cache.h" 5#include "core/file_sys/registered_cache.h"
6#include "core/file_sys/sdmc_factory.h" 6#include "core/file_sys/sdmc_factory.h"
7#include "core/file_sys/vfs.h" 7#include "core/file_sys/vfs/vfs.h"
8#include "core/file_sys/xts_archive.h" 8#include "core/file_sys/xts_archive.h"
9 9
10namespace FileSys { 10namespace FileSys {
diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h
index a445fdb16..ee69ccd07 100644
--- a/src/core/file_sys/sdmc_factory.h
+++ b/src/core/file_sys/sdmc_factory.h
@@ -4,7 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include "core/file_sys/vfs_types.h" 7#include "core/file_sys/vfs/vfs_types.h"
8#include "core/hle/result.h" 8#include "core/hle/result.h"
9 9
10namespace FileSys { 10namespace FileSys {
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 915bffca9..935e9589d 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -9,7 +9,7 @@
9#include <vector> 9#include <vector>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/file_sys/nca_metadata.h" 11#include "core/file_sys/nca_metadata.h"
12#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs/vfs.h"
13 13
14namespace Core::Crypto { 14namespace Core::Crypto {
15class KeyManager; 15class KeyManager;
diff --git a/src/core/file_sys/system_archive/mii_model.cpp b/src/core/file_sys/system_archive/mii_model.cpp
index 5c87b42f8..a96cb2cd2 100644
--- a/src/core/file_sys/system_archive/mii_model.cpp
+++ b/src/core/file_sys/system_archive/mii_model.cpp
@@ -2,7 +2,7 @@
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/system_archive/mii_model.h" 4#include "core/file_sys/system_archive/mii_model.h"
5#include "core/file_sys/vfs_vector.h" 5#include "core/file_sys/vfs/vfs_vector.h"
6 6
7namespace FileSys::SystemArchive { 7namespace FileSys::SystemArchive {
8 8
diff --git a/src/core/file_sys/system_archive/mii_model.h b/src/core/file_sys/system_archive/mii_model.h
index b6cbefe24..61723ed0d 100644
--- a/src/core/file_sys/system_archive/mii_model.h
+++ b/src/core/file_sys/system_archive/mii_model.h
@@ -3,7 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/vfs_types.h" 6#include "core/file_sys/vfs/vfs_types.h"
7 7
8namespace FileSys::SystemArchive { 8namespace FileSys::SystemArchive {
9 9
diff --git a/src/core/file_sys/system_archive/ng_word.cpp b/src/core/file_sys/system_archive/ng_word.cpp
index 5cf6749da..1fa67877d 100644
--- a/src/core/file_sys/system_archive/ng_word.cpp
+++ b/src/core/file_sys/system_archive/ng_word.cpp
@@ -4,7 +4,7 @@
4#include <fmt/format.h> 4#include <fmt/format.h>
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "core/file_sys/system_archive/ng_word.h" 6#include "core/file_sys/system_archive/ng_word.h"
7#include "core/file_sys/vfs_vector.h" 7#include "core/file_sys/vfs/vfs_vector.h"
8 8
9namespace FileSys::SystemArchive { 9namespace FileSys::SystemArchive {
10 10
diff --git a/src/core/file_sys/system_archive/ng_word.h b/src/core/file_sys/system_archive/ng_word.h
index 1d7b49532..51bcc3327 100644
--- a/src/core/file_sys/system_archive/ng_word.h
+++ b/src/core/file_sys/system_archive/ng_word.h
@@ -3,7 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/vfs_types.h" 6#include "core/file_sys/vfs/vfs_types.h"
7 7
8namespace FileSys::SystemArchive { 8namespace FileSys::SystemArchive {
9 9
diff --git a/src/core/file_sys/system_archive/shared_font.cpp b/src/core/file_sys/system_archive/shared_font.cpp
index 3210583f0..deb52069d 100644
--- a/src/core/file_sys/system_archive/shared_font.cpp
+++ b/src/core/file_sys/system_archive/shared_font.cpp
@@ -8,7 +8,7 @@
8#include "core/file_sys/system_archive/data/font_nintendo_extended.h" 8#include "core/file_sys/system_archive/data/font_nintendo_extended.h"
9#include "core/file_sys/system_archive/data/font_standard.h" 9#include "core/file_sys/system_archive/data/font_standard.h"
10#include "core/file_sys/system_archive/shared_font.h" 10#include "core/file_sys/system_archive/shared_font.h"
11#include "core/file_sys/vfs_vector.h" 11#include "core/file_sys/vfs/vfs_vector.h"
12#include "core/hle/service/ns/iplatform_service_manager.h" 12#include "core/hle/service/ns/iplatform_service_manager.h"
13 13
14namespace FileSys::SystemArchive { 14namespace FileSys::SystemArchive {
diff --git a/src/core/file_sys/system_archive/shared_font.h b/src/core/file_sys/system_archive/shared_font.h
index d1cd1dc44..2d19fcde3 100644
--- a/src/core/file_sys/system_archive/shared_font.h
+++ b/src/core/file_sys/system_archive/shared_font.h
@@ -3,7 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/vfs_types.h" 6#include "core/file_sys/vfs/vfs_types.h"
7 7
8namespace FileSys::SystemArchive { 8namespace FileSys::SystemArchive {
9 9
diff --git a/src/core/file_sys/system_archive/system_archive.h b/src/core/file_sys/system_archive/system_archive.h
index 02d9157bb..2f64247bc 100644
--- a/src/core/file_sys/system_archive/system_archive.h
+++ b/src/core/file_sys/system_archive/system_archive.h
@@ -4,7 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/file_sys/vfs_types.h" 7#include "core/file_sys/vfs/vfs_types.h"
8 8
9namespace FileSys::SystemArchive { 9namespace FileSys::SystemArchive {
10 10
diff --git a/src/core/file_sys/system_archive/system_version.cpp b/src/core/file_sys/system_archive/system_version.cpp
index e4751c2b4..5662004b7 100644
--- a/src/core/file_sys/system_archive/system_version.cpp
+++ b/src/core/file_sys/system_archive/system_version.cpp
@@ -3,7 +3,7 @@
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "core/file_sys/system_archive/system_version.h" 5#include "core/file_sys/system_archive/system_version.h"
6#include "core/file_sys/vfs_vector.h" 6#include "core/file_sys/vfs/vfs_vector.h"
7#include "core/hle/api_version.h" 7#include "core/hle/api_version.h"
8 8
9namespace FileSys::SystemArchive { 9namespace FileSys::SystemArchive {
diff --git a/src/core/file_sys/system_archive/system_version.h b/src/core/file_sys/system_archive/system_version.h
index 21b5514a9..e5f7b952e 100644
--- a/src/core/file_sys/system_archive/system_version.h
+++ b/src/core/file_sys/system_archive/system_version.h
@@ -4,7 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <string> 6#include <string>
7#include "core/file_sys/vfs_types.h" 7#include "core/file_sys/vfs/vfs_types.h"
8 8
9namespace FileSys::SystemArchive { 9namespace FileSys::SystemArchive {
10 10
diff --git a/src/core/file_sys/system_archive/time_zone_binary.cpp b/src/core/file_sys/system_archive/time_zone_binary.cpp
index d4d2eae76..316ff0dc6 100644
--- a/src/core/file_sys/system_archive/time_zone_binary.cpp
+++ b/src/core/file_sys/system_archive/time_zone_binary.cpp
@@ -5,7 +5,7 @@
5 5
6#include "common/swap.h" 6#include "common/swap.h"
7#include "core/file_sys/system_archive/time_zone_binary.h" 7#include "core/file_sys/system_archive/time_zone_binary.h"
8#include "core/file_sys/vfs_vector.h" 8#include "core/file_sys/vfs/vfs_vector.h"
9 9
10#include "nx_tzdb.h" 10#include "nx_tzdb.h"
11 11
diff --git a/src/core/file_sys/system_archive/time_zone_binary.h b/src/core/file_sys/system_archive/time_zone_binary.h
index d0e1a4acd..e44fc5007 100644
--- a/src/core/file_sys/system_archive/time_zone_binary.h
+++ b/src/core/file_sys/system_archive/time_zone_binary.h
@@ -3,7 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/vfs_types.h" 6#include "core/file_sys/vfs/vfs_types.h"
7 7
8namespace FileSys::SystemArchive { 8namespace FileSys::SystemArchive {
9 9
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs/vfs.cpp
index b7105c8ff..a04292760 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs/vfs.cpp
@@ -5,8 +5,7 @@
5#include <numeric> 5#include <numeric>
6#include <string> 6#include <string>
7#include "common/fs/path_util.h" 7#include "common/fs/path_util.h"
8#include "core/file_sys/mode.h" 8#include "core/file_sys/vfs/vfs.h"
9#include "core/file_sys/vfs.h"
10 9
11namespace FileSys { 10namespace FileSys {
12 11
@@ -36,12 +35,12 @@ VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const {
36 return VfsEntryType::None; 35 return VfsEntryType::None;
37} 36}
38 37
39VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) { 38VirtualFile VfsFilesystem::OpenFile(std::string_view path_, OpenMode perms) {
40 const auto path = Common::FS::SanitizePath(path_); 39 const auto path = Common::FS::SanitizePath(path_);
41 return root->GetFileRelative(path); 40 return root->GetFileRelative(path);
42} 41}
43 42
44VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) { 43VirtualFile VfsFilesystem::CreateFile(std::string_view path_, OpenMode perms) {
45 const auto path = Common::FS::SanitizePath(path_); 44 const auto path = Common::FS::SanitizePath(path_);
46 return root->CreateFileRelative(path); 45 return root->CreateFileRelative(path);
47} 46}
@@ -54,17 +53,17 @@ VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view
54 if (Common::FS::GetParentPath(old_path) == Common::FS::GetParentPath(new_path)) { 53 if (Common::FS::GetParentPath(old_path) == Common::FS::GetParentPath(new_path)) {
55 if (!root->Copy(Common::FS::GetFilename(old_path), Common::FS::GetFilename(new_path))) 54 if (!root->Copy(Common::FS::GetFilename(old_path), Common::FS::GetFilename(new_path)))
56 return nullptr; 55 return nullptr;
57 return OpenFile(new_path, Mode::ReadWrite); 56 return OpenFile(new_path, OpenMode::ReadWrite);
58 } 57 }
59 58
60 // Do it using RawCopy. Non-default impls are encouraged to optimize this. 59 // Do it using RawCopy. Non-default impls are encouraged to optimize this.
61 const auto old_file = OpenFile(old_path, Mode::Read); 60 const auto old_file = OpenFile(old_path, OpenMode::Read);
62 if (old_file == nullptr) 61 if (old_file == nullptr)
63 return nullptr; 62 return nullptr;
64 auto new_file = OpenFile(new_path, Mode::Read); 63 auto new_file = OpenFile(new_path, OpenMode::Read);
65 if (new_file != nullptr) 64 if (new_file != nullptr)
66 return nullptr; 65 return nullptr;
67 new_file = CreateFile(new_path, Mode::Write); 66 new_file = CreateFile(new_path, OpenMode::Write);
68 if (new_file == nullptr) 67 if (new_file == nullptr)
69 return nullptr; 68 return nullptr;
70 if (!VfsRawCopy(old_file, new_file)) 69 if (!VfsRawCopy(old_file, new_file))
@@ -87,18 +86,18 @@ VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view
87 86
88bool VfsFilesystem::DeleteFile(std::string_view path_) { 87bool VfsFilesystem::DeleteFile(std::string_view path_) {
89 const auto path = Common::FS::SanitizePath(path_); 88 const auto path = Common::FS::SanitizePath(path_);
90 auto parent = OpenDirectory(Common::FS::GetParentPath(path), Mode::Write); 89 auto parent = OpenDirectory(Common::FS::GetParentPath(path), OpenMode::Write);
91 if (parent == nullptr) 90 if (parent == nullptr)
92 return false; 91 return false;
93 return parent->DeleteFile(Common::FS::GetFilename(path)); 92 return parent->DeleteFile(Common::FS::GetFilename(path));
94} 93}
95 94
96VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { 95VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, OpenMode perms) {
97 const auto path = Common::FS::SanitizePath(path_); 96 const auto path = Common::FS::SanitizePath(path_);
98 return root->GetDirectoryRelative(path); 97 return root->GetDirectoryRelative(path);
99} 98}
100 99
101VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { 100VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, OpenMode perms) {
102 const auto path = Common::FS::SanitizePath(path_); 101 const auto path = Common::FS::SanitizePath(path_);
103 return root->CreateDirectoryRelative(path); 102 return root->CreateDirectoryRelative(path);
104} 103}
@@ -108,13 +107,13 @@ VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_
108 const auto new_path = Common::FS::SanitizePath(new_path_); 107 const auto new_path = Common::FS::SanitizePath(new_path_);
109 108
110 // Non-default impls are highly encouraged to provide a more optimized version of this. 109 // Non-default impls are highly encouraged to provide a more optimized version of this.
111 auto old_dir = OpenDirectory(old_path, Mode::Read); 110 auto old_dir = OpenDirectory(old_path, OpenMode::Read);
112 if (old_dir == nullptr) 111 if (old_dir == nullptr)
113 return nullptr; 112 return nullptr;
114 auto new_dir = OpenDirectory(new_path, Mode::Read); 113 auto new_dir = OpenDirectory(new_path, OpenMode::Read);
115 if (new_dir != nullptr) 114 if (new_dir != nullptr)
116 return nullptr; 115 return nullptr;
117 new_dir = CreateDirectory(new_path, Mode::Write); 116 new_dir = CreateDirectory(new_path, OpenMode::Write);
118 if (new_dir == nullptr) 117 if (new_dir == nullptr)
119 return nullptr; 118 return nullptr;
120 119
@@ -149,7 +148,7 @@ VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_v
149 148
150bool VfsFilesystem::DeleteDirectory(std::string_view path_) { 149bool VfsFilesystem::DeleteDirectory(std::string_view path_) {
151 const auto path = Common::FS::SanitizePath(path_); 150 const auto path = Common::FS::SanitizePath(path_);
152 auto parent = OpenDirectory(Common::FS::GetParentPath(path), Mode::Write); 151 auto parent = OpenDirectory(Common::FS::GetParentPath(path), OpenMode::Write);
153 if (parent == nullptr) 152 if (parent == nullptr)
154 return false; 153 return false;
155 return parent->DeleteSubdirectoryRecursive(Common::FS::GetFilename(path)); 154 return parent->DeleteSubdirectoryRecursive(Common::FS::GetFilename(path));
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs/vfs.h
index a7cd1cae3..f846a9669 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs/vfs.h
@@ -13,12 +13,11 @@
13 13
14#include "common/common_funcs.h" 14#include "common/common_funcs.h"
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "core/file_sys/vfs_types.h" 16#include "core/file_sys/fs_filesystem.h"
17#include "core/file_sys/vfs/vfs_types.h"
17 18
18namespace FileSys { 19namespace FileSys {
19 20
20enum class Mode : u32;
21
22// An enumeration representing what can be at the end of a path in a VfsFilesystem 21// An enumeration representing what can be at the end of a path in a VfsFilesystem
23enum class VfsEntryType { 22enum class VfsEntryType {
24 None, 23 None,
@@ -49,9 +48,9 @@ public:
49 virtual VfsEntryType GetEntryType(std::string_view path) const; 48 virtual VfsEntryType GetEntryType(std::string_view path) const;
50 49
51 // Opens the file with path relative to root. If it doesn't exist, returns nullptr. 50 // Opens the file with path relative to root. If it doesn't exist, returns nullptr.
52 virtual VirtualFile OpenFile(std::string_view path, Mode perms); 51 virtual VirtualFile OpenFile(std::string_view path, OpenMode perms);
53 // Creates a new, empty file at path 52 // Creates a new, empty file at path
54 virtual VirtualFile CreateFile(std::string_view path, Mode perms); 53 virtual VirtualFile CreateFile(std::string_view path, OpenMode perms);
55 // Copies the file from old_path to new_path, returning the new file on success and nullptr on 54 // Copies the file from old_path to new_path, returning the new file on success and nullptr on
56 // failure. 55 // failure.
57 virtual VirtualFile CopyFile(std::string_view old_path, std::string_view new_path); 56 virtual VirtualFile CopyFile(std::string_view old_path, std::string_view new_path);
@@ -62,9 +61,9 @@ public:
62 virtual bool DeleteFile(std::string_view path); 61 virtual bool DeleteFile(std::string_view path);
63 62
64 // Opens the directory with path relative to root. If it doesn't exist, returns nullptr. 63 // Opens the directory with path relative to root. If it doesn't exist, returns nullptr.
65 virtual VirtualDir OpenDirectory(std::string_view path, Mode perms); 64 virtual VirtualDir OpenDirectory(std::string_view path, OpenMode perms);
66 // Creates a new, empty directory at path 65 // Creates a new, empty directory at path
67 virtual VirtualDir CreateDirectory(std::string_view path, Mode perms); 66 virtual VirtualDir CreateDirectory(std::string_view path, OpenMode perms);
68 // Copies the directory from old_path to new_path, returning the new directory on success and 67 // Copies the directory from old_path to new_path, returning the new directory on success and
69 // nullptr on failure. 68 // nullptr on failure.
70 virtual VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path); 69 virtual VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path);
diff --git a/src/core/file_sys/vfs_cached.cpp b/src/core/file_sys/vfs/vfs_cached.cpp
index 7ee5300e5..01cd0f1e0 100644
--- a/src/core/file_sys/vfs_cached.cpp
+++ b/src/core/file_sys/vfs/vfs_cached.cpp
@@ -1,8 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 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 "core/file_sys/vfs_cached.h" 4#include "core/file_sys/vfs/vfs_cached.h"
5#include "core/file_sys/vfs_types.h" 5#include "core/file_sys/vfs/vfs_types.h"
6 6
7namespace FileSys { 7namespace FileSys {
8 8
diff --git a/src/core/file_sys/vfs_cached.h b/src/core/file_sys/vfs/vfs_cached.h
index 1e5300784..47dff7224 100644
--- a/src/core/file_sys/vfs_cached.h
+++ b/src/core/file_sys/vfs/vfs_cached.h
@@ -5,7 +5,7 @@
5 5
6#include <string_view> 6#include <string_view>
7#include <vector> 7#include <vector>
8#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs/vfs.h"
9 9
10namespace FileSys { 10namespace FileSys {
11 11
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs/vfs_concat.cpp
index 7c7298527..b5cc9a9e9 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs/vfs_concat.cpp
@@ -5,8 +5,8 @@
5#include <utility> 5#include <utility>
6 6
7#include "common/assert.h" 7#include "common/assert.h"
8#include "core/file_sys/vfs_concat.h" 8#include "core/file_sys/vfs/vfs_concat.h"
9#include "core/file_sys/vfs_static.h" 9#include "core/file_sys/vfs/vfs_static.h"
10 10
11namespace FileSys { 11namespace FileSys {
12 12
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs/vfs_concat.h
index b5f3d72e3..6d12af762 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs/vfs_concat.h
@@ -6,7 +6,7 @@
6#include <compare> 6#include <compare>
7#include <map> 7#include <map>
8#include <memory> 8#include <memory>
9#include "core/file_sys/vfs.h" 9#include "core/file_sys/vfs/vfs.h"
10 10
11namespace FileSys { 11namespace FileSys {
12 12
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs/vfs_layered.cpp
index 5551743fb..47b2a3c78 100644
--- a/src/core/file_sys/vfs_layered.cpp
+++ b/src/core/file_sys/vfs/vfs_layered.cpp
@@ -5,7 +5,7 @@
5#include <set> 5#include <set>
6#include <unordered_set> 6#include <unordered_set>
7#include <utility> 7#include <utility>
8#include "core/file_sys/vfs_layered.h" 8#include "core/file_sys/vfs/vfs_layered.h"
9 9
10namespace FileSys { 10namespace FileSys {
11 11
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs/vfs_layered.h
index a62112e9d..0027ffa9a 100644
--- a/src/core/file_sys/vfs_layered.h
+++ b/src/core/file_sys/vfs/vfs_layered.h
@@ -4,7 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include "core/file_sys/vfs.h" 7#include "core/file_sys/vfs/vfs.h"
8 8
9namespace FileSys { 9namespace FileSys {
10 10
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs/vfs_offset.cpp
index d950a6633..1a37d2670 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs/vfs_offset.cpp
@@ -4,7 +4,7 @@
4#include <algorithm> 4#include <algorithm>
5#include <utility> 5#include <utility>
6 6
7#include "core/file_sys/vfs_offset.h" 7#include "core/file_sys/vfs/vfs_offset.h"
8 8
9namespace FileSys { 9namespace FileSys {
10 10
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs/vfs_offset.h
index 6c051ca00..4abe41d8e 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs/vfs_offset.h
@@ -5,7 +5,7 @@
5 5
6#include <memory> 6#include <memory>
7 7
8#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs/vfs.h"
9 9
10namespace FileSys { 10namespace FileSys {
11 11
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs/vfs_real.cpp
index cd9b79786..627d5d251 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs/vfs_real.cpp
@@ -10,8 +10,8 @@
10#include "common/fs/fs.h" 10#include "common/fs/fs.h"
11#include "common/fs/path_util.h" 11#include "common/fs/path_util.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs/vfs.h"
14#include "core/file_sys/vfs_real.h" 14#include "core/file_sys/vfs/vfs_real.h"
15 15
16// For FileTimeStampRaw 16// For FileTimeStampRaw
17#include <sys/stat.h> 17#include <sys/stat.h>
@@ -28,16 +28,14 @@ namespace {
28 28
29constexpr size_t MaxOpenFiles = 512; 29constexpr size_t MaxOpenFiles = 512;
30 30
31constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(Mode mode) { 31constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(OpenMode mode) {
32 switch (mode) { 32 switch (mode) {
33 case Mode::Read: 33 case OpenMode::Read:
34 return FS::FileAccessMode::Read; 34 return FS::FileAccessMode::Read;
35 case Mode::Write: 35 case OpenMode::Write:
36 case Mode::ReadWrite: 36 case OpenMode::ReadWrite:
37 case Mode::Append: 37 case OpenMode::AllowAppend:
38 case Mode::ReadAppend: 38 case OpenMode::All:
39 case Mode::WriteAppend:
40 case Mode::All:
41 return FS::FileAccessMode::ReadWrite; 39 return FS::FileAccessMode::ReadWrite;
42 default: 40 default:
43 return {}; 41 return {};
@@ -74,7 +72,7 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
74} 72}
75 73
76VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size, 74VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size,
77 Mode perms) { 75 OpenMode perms) {
78 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); 76 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
79 std::scoped_lock lk{list_lock}; 77 std::scoped_lock lk{list_lock};
80 78
@@ -98,11 +96,11 @@ VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::op
98 return file; 96 return file;
99} 97}
100 98
101VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { 99VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, OpenMode perms) {
102 return OpenFileFromEntry(path_, {}, perms); 100 return OpenFileFromEntry(path_, {}, perms);
103} 101}
104 102
105VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { 103VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, OpenMode perms) {
106 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); 104 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
107 { 105 {
108 std::scoped_lock lk{list_lock}; 106 std::scoped_lock lk{list_lock};
@@ -145,7 +143,7 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
145 if (!FS::RenameFile(old_path, new_path)) { 143 if (!FS::RenameFile(old_path, new_path)) {
146 return nullptr; 144 return nullptr;
147 } 145 }
148 return OpenFile(new_path, Mode::ReadWrite); 146 return OpenFile(new_path, OpenMode::ReadWrite);
149} 147}
150 148
151bool RealVfsFilesystem::DeleteFile(std::string_view path_) { 149bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
@@ -157,12 +155,12 @@ bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
157 return FS::RemoveFile(path); 155 return FS::RemoveFile(path);
158} 156}
159 157
160VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { 158VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, OpenMode perms) {
161 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); 159 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
162 return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); 160 return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
163} 161}
164 162
165VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { 163VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, OpenMode perms) {
166 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); 164 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
167 if (!FS::CreateDirs(path)) { 165 if (!FS::CreateDirs(path)) {
168 return nullptr; 166 return nullptr;
@@ -184,7 +182,7 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
184 if (!FS::RenameDir(old_path, new_path)) { 182 if (!FS::RenameDir(old_path, new_path)) {
185 return nullptr; 183 return nullptr;
186 } 184 }
187 return OpenDirectory(new_path, Mode::ReadWrite); 185 return OpenDirectory(new_path, OpenMode::ReadWrite);
188} 186}
189 187
190bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { 188bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
@@ -193,7 +191,7 @@ bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
193} 191}
194 192
195std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::string& path, 193std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::string& path,
196 Mode perms, 194 OpenMode perms,
197 FileReference& reference) { 195 FileReference& reference) {
198 std::unique_lock lk{list_lock}; 196 std::unique_lock lk{list_lock};
199 197
@@ -266,7 +264,7 @@ void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference)
266} 264}
267 265
268RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_, 266RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_,
269 const std::string& path_, Mode perms_, std::optional<u64> size_) 267 const std::string& path_, OpenMode perms_, std::optional<u64> size_)
270 : base(base_), reference(std::move(reference_)), path(path_), 268 : base(base_), reference(std::move(reference_)), path(path_),
271 parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponentsCopy(path_)), 269 parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponentsCopy(path_)),
272 size(size_), perms(perms_) {} 270 size(size_), perms(perms_) {}
@@ -298,11 +296,11 @@ VirtualDir RealVfsFile::GetContainingDirectory() const {
298} 296}
299 297
300bool RealVfsFile::IsWritable() const { 298bool RealVfsFile::IsWritable() const {
301 return True(perms & Mode::Write); 299 return True(perms & OpenMode::Write);
302} 300}
303 301
304bool RealVfsFile::IsReadable() const { 302bool RealVfsFile::IsReadable() const {
305 return True(perms & Mode::Read); 303 return True(perms & OpenMode::Read);
306} 304}
307 305
308std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { 306std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
@@ -331,7 +329,7 @@ bool RealVfsFile::Rename(std::string_view name) {
331 329
332template <> 330template <>
333std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const { 331std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const {
334 if (perms == Mode::Append) { 332 if (perms == OpenMode::AllowAppend) {
335 return {}; 333 return {};
336 } 334 }
337 335
@@ -353,7 +351,7 @@ std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>(
353 351
354template <> 352template <>
355std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const { 353std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const {
356 if (perms == Mode::Append) { 354 if (perms == OpenMode::AllowAppend) {
357 return {}; 355 return {};
358 } 356 }
359 357
@@ -373,10 +371,11 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi
373 return out; 371 return out;
374} 372}
375 373
376RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_) 374RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_,
375 OpenMode perms_)
377 : base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)), 376 : base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)),
378 path_components(FS::SplitPathComponentsCopy(path)), perms(perms_) { 377 path_components(FS::SplitPathComponentsCopy(path)), perms(perms_) {
379 if (!FS::Exists(path) && True(perms & Mode::Write)) { 378 if (!FS::Exists(path) && True(perms & OpenMode::Write)) {
380 void(FS::CreateDirs(path)); 379 void(FS::CreateDirs(path));
381 } 380 }
382} 381}
@@ -456,11 +455,11 @@ std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const {
456} 455}
457 456
458bool RealVfsDirectory::IsWritable() const { 457bool RealVfsDirectory::IsWritable() const {
459 return True(perms & Mode::Write); 458 return True(perms & OpenMode::Write);
460} 459}
461 460
462bool RealVfsDirectory::IsReadable() const { 461bool RealVfsDirectory::IsReadable() const {
463 return True(perms & Mode::Read); 462 return True(perms & OpenMode::Read);
464} 463}
465 464
466std::string RealVfsDirectory::GetName() const { 465std::string RealVfsDirectory::GetName() const {
@@ -507,7 +506,7 @@ std::string RealVfsDirectory::GetFullPath() const {
507} 506}
508 507
509std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() const { 508std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() const {
510 if (perms == Mode::Append) { 509 if (perms == OpenMode::AllowAppend) {
511 return {}; 510 return {};
512 } 511 }
513 512
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs/vfs_real.h
index 26ea7df62..5c2172cce 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs/vfs_real.h
@@ -8,8 +8,8 @@
8#include <optional> 8#include <optional>
9#include <string_view> 9#include <string_view>
10#include "common/intrusive_list.h" 10#include "common/intrusive_list.h"
11#include "core/file_sys/mode.h" 11#include "core/file_sys/fs_filesystem.h"
12#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs/vfs.h"
13 13
14namespace Common::FS { 14namespace Common::FS {
15class IOFile; 15class IOFile;
@@ -33,13 +33,14 @@ public:
33 bool IsReadable() const override; 33 bool IsReadable() const override;
34 bool IsWritable() const override; 34 bool IsWritable() const override;
35 VfsEntryType GetEntryType(std::string_view path) const override; 35 VfsEntryType GetEntryType(std::string_view path) const override;
36 VirtualFile OpenFile(std::string_view path, Mode perms = Mode::Read) override; 36 VirtualFile OpenFile(std::string_view path, OpenMode perms = OpenMode::Read) override;
37 VirtualFile CreateFile(std::string_view path, Mode perms = Mode::ReadWrite) override; 37 VirtualFile CreateFile(std::string_view path, OpenMode perms = OpenMode::ReadWrite) override;
38 VirtualFile CopyFile(std::string_view old_path, std::string_view new_path) override; 38 VirtualFile CopyFile(std::string_view old_path, std::string_view new_path) override;
39 VirtualFile MoveFile(std::string_view old_path, std::string_view new_path) override; 39 VirtualFile MoveFile(std::string_view old_path, std::string_view new_path) override;
40 bool DeleteFile(std::string_view path) override; 40 bool DeleteFile(std::string_view path) override;
41 VirtualDir OpenDirectory(std::string_view path, Mode perms = Mode::Read) override; 41 VirtualDir OpenDirectory(std::string_view path, OpenMode perms = OpenMode::Read) override;
42 VirtualDir CreateDirectory(std::string_view path, Mode perms = Mode::ReadWrite) override; 42 VirtualDir CreateDirectory(std::string_view path,
43 OpenMode perms = OpenMode::ReadWrite) override;
43 VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path) override; 44 VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path) override;
44 VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path) override; 45 VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path) override;
45 bool DeleteDirectory(std::string_view path) override; 46 bool DeleteDirectory(std::string_view path) override;
@@ -54,14 +55,14 @@ private:
54 55
55private: 56private:
56 friend class RealVfsFile; 57 friend class RealVfsFile;
57 std::unique_lock<std::mutex> RefreshReference(const std::string& path, Mode perms, 58 std::unique_lock<std::mutex> RefreshReference(const std::string& path, OpenMode perms,
58 FileReference& reference); 59 FileReference& reference);
59 void DropReference(std::unique_ptr<FileReference>&& reference); 60 void DropReference(std::unique_ptr<FileReference>&& reference);
60 61
61private: 62private:
62 friend class RealVfsDirectory; 63 friend class RealVfsDirectory;
63 VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size, 64 VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size,
64 Mode perms = Mode::Read); 65 OpenMode perms = OpenMode::Read);
65 66
66private: 67private:
67 void EvictSingleReferenceLocked(); 68 void EvictSingleReferenceLocked();
@@ -89,7 +90,8 @@ public:
89 90
90private: 91private:
91 RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference, 92 RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference,
92 const std::string& path, Mode perms = Mode::Read, std::optional<u64> size = {}); 93 const std::string& path, OpenMode perms = OpenMode::Read,
94 std::optional<u64> size = {});
93 95
94 RealVfsFilesystem& base; 96 RealVfsFilesystem& base;
95 std::unique_ptr<FileReference> reference; 97 std::unique_ptr<FileReference> reference;
@@ -97,7 +99,7 @@ private:
97 std::string parent_path; 99 std::string parent_path;
98 std::vector<std::string> path_components; 100 std::vector<std::string> path_components;
99 std::optional<u64> size; 101 std::optional<u64> size;
100 Mode perms; 102 OpenMode perms;
101}; 103};
102 104
103// An implementation of VfsDirectory that represents a directory on the user's computer. 105// An implementation of VfsDirectory that represents a directory on the user's computer.
@@ -130,7 +132,8 @@ public:
130 std::map<std::string, VfsEntryType, std::less<>> GetEntries() const override; 132 std::map<std::string, VfsEntryType, std::less<>> GetEntries() const override;
131 133
132private: 134private:
133 RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read); 135 RealVfsDirectory(RealVfsFilesystem& base, const std::string& path,
136 OpenMode perms = OpenMode::Read);
134 137
135 template <typename T, typename R> 138 template <typename T, typename R>
136 std::vector<std::shared_ptr<R>> IterateEntries() const; 139 std::vector<std::shared_ptr<R>> IterateEntries() const;
@@ -139,7 +142,7 @@ private:
139 std::string path; 142 std::string path;
140 std::string parent_path; 143 std::string parent_path;
141 std::vector<std::string> path_components; 144 std::vector<std::string> path_components;
142 Mode perms; 145 OpenMode perms;
143}; 146};
144 147
145} // namespace FileSys 148} // namespace FileSys
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs/vfs_static.h
index ca3f989ef..bb53560ac 100644
--- a/src/core/file_sys/vfs_static.h
+++ b/src/core/file_sys/vfs/vfs_static.h
@@ -7,7 +7,7 @@
7#include <memory> 7#include <memory>
8#include <string_view> 8#include <string_view>
9 9
10#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs/vfs.h"
11 11
12namespace FileSys { 12namespace FileSys {
13 13
diff --git a/src/core/file_sys/vfs_types.h b/src/core/file_sys/vfs/vfs_types.h
index 4a583ed64..4a583ed64 100644
--- a/src/core/file_sys/vfs_types.h
+++ b/src/core/file_sys/vfs/vfs_types.h
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs/vfs_vector.cpp
index 251d9d7c9..0d54461c8 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs/vfs_vector.cpp
@@ -3,7 +3,7 @@
3 3
4#include <algorithm> 4#include <algorithm>
5#include <utility> 5#include <utility>
6#include "core/file_sys/vfs_vector.h" 6#include "core/file_sys/vfs/vfs_vector.h"
7 7
8namespace FileSys { 8namespace FileSys {
9VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name_, VirtualDir parent_) 9VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name_, VirtualDir parent_)
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs/vfs_vector.h
index bfedb6e42..587187dd2 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs/vfs_vector.h
@@ -8,7 +8,7 @@
8#include <memory> 8#include <memory>
9#include <string> 9#include <string>
10#include <vector> 10#include <vector>
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
12 12
13namespace FileSys { 13namespace FileSys {
14 14
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index ede0aa11a..6692211e1 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -17,7 +17,7 @@
17#include "core/crypto/key_manager.h" 17#include "core/crypto/key_manager.h"
18#include "core/crypto/xts_encryption_layer.h" 18#include "core/crypto/xts_encryption_layer.h"
19#include "core/file_sys/content_archive.h" 19#include "core/file_sys/content_archive.h"
20#include "core/file_sys/vfs_offset.h" 20#include "core/file_sys/vfs/vfs_offset.h"
21#include "core/file_sys/xts_archive.h" 21#include "core/file_sys/xts_archive.h"
22#include "core/loader/loader.h" 22#include "core/loader/loader.h"
23 23
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h
index abbe5f716..7589b7c38 100644
--- a/src/core/file_sys/xts_archive.h
+++ b/src/core/file_sys/xts_archive.h
@@ -8,7 +8,7 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/swap.h" 9#include "common/swap.h"
10#include "core/crypto/key_manager.h" 10#include "core/crypto/key_manager.h"
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
12 12
13namespace Loader { 13namespace Loader {
14enum class ResultStatus : u16; 14enum class ResultStatus : u16;
diff --git a/src/core/frontend/applets/error.cpp b/src/core/frontend/applets/error.cpp
index 2e6f7a3d9..53d4be2e5 100644
--- a/src/core/frontend/applets/error.cpp
+++ b/src/core/frontend/applets/error.cpp
@@ -12,7 +12,7 @@ void DefaultErrorApplet::Close() const {}
12 12
13void DefaultErrorApplet::ShowError(Result error, FinishedCallback finished) const { 13void DefaultErrorApplet::ShowError(Result error, FinishedCallback finished) const {
14 LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})", 14 LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})",
15 error.module.Value(), error.description.Value(), error.raw); 15 error.GetModule(), error.GetDescription(), error.raw);
16} 16}
17 17
18void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::seconds time, 18void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
@@ -20,7 +20,7 @@ void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::secon
20 LOG_CRITICAL( 20 LOG_CRITICAL(
21 Service_Fatal, 21 Service_Fatal,
22 "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}", 22 "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}",
23 error.module.Value(), error.description.Value(), error.raw, time.count()); 23 error.GetModule(), error.GetDescription(), error.raw, time.count());
24} 24}
25 25
26void DefaultErrorApplet::ShowCustomErrorText(Result error, std::string main_text, 26void DefaultErrorApplet::ShowCustomErrorText(Result error, std::string main_text,
@@ -28,7 +28,7 @@ void DefaultErrorApplet::ShowCustomErrorText(Result error, std::string main_text
28 FinishedCallback finished) const { 28 FinishedCallback finished) const {
29 LOG_CRITICAL(Service_Fatal, 29 LOG_CRITICAL(Service_Fatal,
30 "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})", 30 "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})",
31 error.module.Value(), error.description.Value(), error.raw); 31 error.GetModule(), error.GetDescription(), error.raw);
32 LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text); 32 LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text);
33 LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text); 33 LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text);
34} 34}
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 749f51f69..316370266 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -189,14 +189,14 @@ enum class ErrorModule : u32 {
189union Result { 189union Result {
190 u32 raw; 190 u32 raw;
191 191
192 BitField<0, 9, ErrorModule> module; 192 using Module = BitField<0, 9, ErrorModule>;
193 BitField<9, 13, u32> description; 193 using Description = BitField<9, 13, u32>;
194 194
195 Result() = default; 195 Result() = default;
196 constexpr explicit Result(u32 raw_) : raw(raw_) {} 196 constexpr explicit Result(u32 raw_) : raw(raw_) {}
197 197
198 constexpr Result(ErrorModule module_, u32 description_) 198 constexpr Result(ErrorModule module_, u32 description_)
199 : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} 199 : raw(Module::FormatValue(module_) | Description::FormatValue(description_)) {}
200 200
201 [[nodiscard]] constexpr bool IsSuccess() const { 201 [[nodiscard]] constexpr bool IsSuccess() const {
202 return raw == 0; 202 return raw == 0;
@@ -211,7 +211,15 @@ union Result {
211 } 211 }
212 212
213 [[nodiscard]] constexpr u32 GetInnerValue() const { 213 [[nodiscard]] constexpr u32 GetInnerValue() const {
214 return static_cast<u32>(module.Value()) | (description << module.bits); 214 return raw;
215 }
216
217 [[nodiscard]] constexpr ErrorModule GetModule() const {
218 return Module::ExtractValue(raw);
219 }
220
221 [[nodiscard]] constexpr u32 GetDescription() const {
222 return Description::ExtractValue(raw);
215 } 223 }
216 224
217 [[nodiscard]] constexpr bool Includes(Result result) const { 225 [[nodiscard]] constexpr bool Includes(Result result) const {
@@ -274,8 +282,9 @@ public:
274 } 282 }
275 283
276 [[nodiscard]] constexpr bool Includes(Result other) const { 284 [[nodiscard]] constexpr bool Includes(Result other) const {
277 return code.module == other.module && code.description <= other.description && 285 return code.GetModule() == other.GetModule() &&
278 other.description <= description_end; 286 code.GetDescription() <= other.GetDescription() &&
287 other.GetDescription() <= description_end;
279 } 288 }
280 289
281private: 290private:
@@ -330,6 +339,16 @@ constexpr bool EvaluateResultFailure(const Result& r) {
330 return R_FAILED(r); 339 return R_FAILED(r);
331} 340}
332 341
342template <auto... R>
343constexpr bool EvaluateAnyResultIncludes(const Result& r) {
344 return ((r == R) || ...);
345}
346
347template <auto... R>
348constexpr bool EvaluateResultNotIncluded(const Result& r) {
349 return !EvaluateAnyResultIncludes<R...>(r);
350}
351
333template <typename T> 352template <typename T>
334constexpr void UpdateCurrentResultReference(T result_reference, Result result) = delete; 353constexpr void UpdateCurrentResultReference(T result_reference, Result result) = delete;
335// Intentionally not defined 354// Intentionally not defined
@@ -371,6 +390,13 @@ constexpr void UpdateCurrentResultReference<const Result>(Result result_referenc
371 DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \ 390 DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \
372 ON_RESULT_SUCCESS_2 391 ON_RESULT_SUCCESS_2
373 392
393#define ON_RESULT_INCLUDED_2(...) \
394 ON_RESULT_RETURN_IMPL(ResultImpl::EvaluateAnyResultIncludes<__VA_ARGS__>)
395
396#define ON_RESULT_INCLUDED(...) \
397 DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \
398 ON_RESULT_INCLUDED_2(__VA_ARGS__)
399
374constexpr inline Result __TmpCurrentResultReference = ResultSuccess; 400constexpr inline Result __TmpCurrentResultReference = ResultSuccess;
375 401
376/// Returns a result. 402/// Returns a result.
diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp
index 5d17c353f..084bc138c 100644
--- a/src/core/hle/service/am/applets/applet_error.cpp
+++ b/src/core/hle/service/am/applets/applet_error.cpp
@@ -27,8 +27,8 @@ struct ErrorCode {
27 27
28 static constexpr ErrorCode FromResult(Result result) { 28 static constexpr ErrorCode FromResult(Result result) {
29 return { 29 return {
30 .error_category{2000 + static_cast<u32>(result.module.Value())}, 30 .error_category{2000 + static_cast<u32>(result.GetModule())},
31 .error_number{result.description.Value()}, 31 .error_number{result.GetDescription()},
32 }; 32 };
33 } 33 }
34 34
diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp
index b0ea2b381..19057ad7b 100644
--- a/src/core/hle/service/am/applets/applet_web_browser.cpp
+++ b/src/core/hle/service/am/applets/applet_web_browser.cpp
@@ -9,13 +9,13 @@
9#include "common/string_util.h" 9#include "common/string_util.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/file_sys/content_archive.h" 11#include "core/file_sys/content_archive.h"
12#include "core/file_sys/mode.h" 12#include "core/file_sys/fs_filesystem.h"
13#include "core/file_sys/nca_metadata.h" 13#include "core/file_sys/nca_metadata.h"
14#include "core/file_sys/patch_manager.h" 14#include "core/file_sys/patch_manager.h"
15#include "core/file_sys/registered_cache.h" 15#include "core/file_sys/registered_cache.h"
16#include "core/file_sys/romfs.h" 16#include "core/file_sys/romfs.h"
17#include "core/file_sys/system_archive/system_archive.h" 17#include "core/file_sys/system_archive/system_archive.h"
18#include "core/file_sys/vfs_vector.h" 18#include "core/file_sys/vfs/vfs_vector.h"
19#include "core/frontend/applets/web_browser.h" 19#include "core/frontend/applets/web_browser.h"
20#include "core/hle/result.h" 20#include "core/hle/result.h"
21#include "core/hle/service/am/am.h" 21#include "core/hle/service/am/am.h"
@@ -213,7 +213,7 @@ void ExtractSharedFonts(Core::System& system) {
213 std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]); 213 std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]);
214 214
215 const auto temp_dir = system.GetFilesystem()->CreateDirectory( 215 const auto temp_dir = system.GetFilesystem()->CreateDirectory(
216 Common::FS::PathToUTF8String(fonts_dir), FileSys::Mode::ReadWrite); 216 Common::FS::PathToUTF8String(fonts_dir), FileSys::OpenMode::ReadWrite);
217 217
218 const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]); 218 const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]);
219 219
@@ -333,7 +333,7 @@ void WebBrowser::ExtractOfflineRomFS() {
333 const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs); 333 const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs);
334 334
335 const auto temp_dir = system.GetFilesystem()->CreateDirectory( 335 const auto temp_dir = system.GetFilesystem()->CreateDirectory(
336 Common::FS::PathToUTF8String(offline_cache_dir), FileSys::Mode::ReadWrite); 336 Common::FS::PathToUTF8String(offline_cache_dir), FileSys::OpenMode::ReadWrite);
337 337
338 FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir); 338 FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir);
339} 339}
diff --git a/src/core/hle/service/am/applets/applet_web_browser.h b/src/core/hle/service/am/applets/applet_web_browser.h
index 99fe18659..36adb2510 100644
--- a/src/core/hle/service/am/applets/applet_web_browser.h
+++ b/src/core/hle/service/am/applets/applet_web_browser.h
@@ -7,7 +7,7 @@
7#include <optional> 7#include <optional>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/vfs_types.h" 10#include "core/file_sys/vfs/vfs_types.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12#include "core/hle/service/am/applets/applet_web_browser_types.h" 12#include "core/hle/service/am/applets/applet_web_browser_types.h"
13#include "core/hle/service/am/applets/applets.h" 13#include "core/hle/service/am/applets/applets.h"
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index bd4ca753b..05581e6e0 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -139,7 +139,8 @@ private:
139 ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1); 139 ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
140 } 140 }
141 } else { 141 } else {
142 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description); 142 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!",
143 result.GetDescription());
143 } 144 }
144 145
145 IPC::ResponseBuilder rb{ctx, 2}; 146 IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h
index 205ed0702..aa36d29d5 100644
--- a/src/core/hle/service/bcat/backend/backend.h
+++ b/src/core/hle/service/bcat/backend/backend.h
@@ -8,7 +8,7 @@
8#include <string> 8#include <string>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/file_sys/vfs_types.h" 11#include "core/file_sys/vfs/vfs_types.h"
12#include "core/hle/result.h" 12#include "core/hle/result.h"
13#include "core/hle/service/kernel_helpers.h" 13#include "core/hle/service/kernel_helpers.h"
14 14
diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp
index a6281913a..76d7bb139 100644
--- a/src/core/hle/service/bcat/bcat_module.cpp
+++ b/src/core/hle/service/bcat/bcat_module.cpp
@@ -8,7 +8,7 @@
8#include "common/settings.h" 8#include "common/settings.h"
9#include "common/string_util.h" 9#include "common/string_util.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
12#include "core/hle/kernel/k_readable_event.h" 12#include "core/hle/kernel/k_readable_event.h"
13#include "core/hle/service/bcat/backend/backend.h" 13#include "core/hle/service/bcat/backend/backend.h"
14#include "core/hle/service/bcat/bcat.h" 14#include "core/hle/service/bcat/bcat.h"
diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp
index 9925720a3..69acb3a8b 100644
--- a/src/core/hle/service/caps/caps_a.cpp
+++ b/src/core/hle/service/caps/caps_a.cpp
@@ -202,14 +202,14 @@ Result IAlbumAccessorService::TranslateResult(Result in_result) {
202 } 202 }
203 203
204 if ((in_result.raw & 0x3801ff) == ResultUnknown1024.raw) { 204 if ((in_result.raw & 0x3801ff) == ResultUnknown1024.raw) {
205 if (in_result.description - 0x514 < 100) { 205 if (in_result.GetDescription() - 0x514 < 100) {
206 return ResultInvalidFileData; 206 return ResultInvalidFileData;
207 } 207 }
208 if (in_result.description - 0x5dc < 100) { 208 if (in_result.GetDescription() - 0x5dc < 100) {
209 return ResultInvalidFileData; 209 return ResultInvalidFileData;
210 } 210 }
211 211
212 if (in_result.description - 0x578 < 100) { 212 if (in_result.GetDescription() - 0x578 < 100) {
213 if (in_result == ResultFileCountLimit) { 213 if (in_result == ResultFileCountLimit) {
214 return ResultUnknown22; 214 return ResultUnknown22;
215 } 215 }
@@ -244,9 +244,10 @@ Result IAlbumAccessorService::TranslateResult(Result in_result) {
244 return ResultUnknown1024; 244 return ResultUnknown1024;
245 } 245 }
246 246
247 if (in_result.module == ErrorModule::FS) { 247 if (in_result.GetModule() == ErrorModule::FS) {
248 if ((in_result.description >> 0xc < 0x7d) || (in_result.description - 1000 < 2000) || 248 if ((in_result.GetDescription() >> 0xc < 0x7d) ||
249 (((in_result.description - 3000) >> 3) < 0x271)) { 249 (in_result.GetDescription() - 1000 < 2000) ||
250 (((in_result.GetDescription() - 3000) >> 3) < 0x271)) {
250 // TODO: Translate FS error 251 // TODO: Translate FS error
251 return in_result; 252 return in_result;
252 } 253 }
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h
index 8e8cf2507..9eb10e816 100644
--- a/src/core/hle/service/cmif_serialization.h
+++ b/src/core/hle/service/cmif_serialization.h
@@ -97,20 +97,20 @@ constexpr RequestLayout GetDomainReplyOutLayout() {
97 }; 97 };
98} 98}
99 99
100template <bool Domain, typename MethodArguments> 100template <typename MethodArguments>
101constexpr RequestLayout GetReplyInLayout() { 101constexpr RequestLayout GetReplyInLayout(bool is_domain) {
102 return Domain ? GetDomainReplyInLayout<MethodArguments>() : GetNonDomainReplyInLayout<MethodArguments>(); 102 return is_domain ? GetDomainReplyInLayout<MethodArguments>() : GetNonDomainReplyInLayout<MethodArguments>();
103} 103}
104 104
105template <bool Domain, typename MethodArguments> 105template <typename MethodArguments>
106constexpr RequestLayout GetReplyOutLayout() { 106constexpr RequestLayout GetReplyOutLayout(bool is_domain) {
107 return Domain ? GetDomainReplyOutLayout<MethodArguments>() : GetNonDomainReplyOutLayout<MethodArguments>(); 107 return is_domain ? GetDomainReplyOutLayout<MethodArguments>() : GetNonDomainReplyOutLayout<MethodArguments>();
108} 108}
109 109
110using OutTemporaryBuffers = std::array<Common::ScratchBuffer<u8>, 3>; 110using OutTemporaryBuffers = std::array<Common::ScratchBuffer<u8>, 3>;
111 111
112template <bool Domain, typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t HandleIndex = 0, size_t InBufferIndex = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> 112template <typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t HandleIndex = 0, size_t InBufferIndex = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0>
113void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { 113void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) {
114 if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { 114 if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) {
115 return; 115 return;
116 } else { 116 } else {
@@ -134,25 +134,25 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext&
134 std::memcpy(&std::get<ArgIndex>(args), raw_data + ArgOffset, ArgSize); 134 std::memcpy(&std::get<ArgIndex>(args), raw_data + ArgOffset, ArgSize);
135 } 135 }
136 136
137 return ReadInArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, false, ArgIndex + 1>(args, raw_data, ctx, temp); 137 return ReadInArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, false, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
138 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InInterface) { 138 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InInterface) {
139 constexpr size_t ArgAlign = alignof(u32); 139 constexpr size_t ArgAlign = alignof(u32);
140 constexpr size_t ArgSize = sizeof(u32); 140 constexpr size_t ArgSize = sizeof(u32);
141 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); 141 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
142 constexpr size_t ArgEnd = ArgOffset + ArgSize; 142 constexpr size_t ArgEnd = ArgOffset + ArgSize;
143 143
144 static_assert(Domain); 144 ASSERT(is_domain);
145 ASSERT(ctx.GetDomainMessageHeader().input_object_count > 0); 145 ASSERT(ctx.GetDomainMessageHeader().input_object_count > 0);
146 146
147 u32 value{}; 147 u32 value{};
148 std::memcpy(&value, raw_data + ArgOffset, ArgSize); 148 std::memcpy(&value, raw_data + ArgOffset, ArgSize);
149 std::get<ArgIndex>(args) = ctx.GetDomainHandler<ArgType::Type>(value - 1); 149 std::get<ArgIndex>(args) = ctx.GetDomainHandler<ArgType::Type>(value - 1);
150 150
151 return ReadInArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(args, raw_data, ctx, temp); 151 return ReadInArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
152 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InCopyHandle) { 152 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InCopyHandle) {
153 std::get<ArgIndex>(args) = std::move(ctx.GetObjectFromHandle<typename ArgType::Type>(ctx.GetCopyHandle(HandleIndex))); 153 std::get<ArgIndex>(args) = ctx.GetObjectFromHandle<typename ArgType::Type>(ctx.GetCopyHandle(HandleIndex)).GetPointerUnsafe();
154 154
155 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); 155 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
156 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) { 156 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) {
157 constexpr size_t BufferSize = sizeof(ArgType); 157 constexpr size_t BufferSize = sizeof(ArgType);
158 158
@@ -172,7 +172,7 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext&
172 172
173 std::memcpy(&std::get<ArgIndex>(args), buffer.data(), std::min(BufferSize, buffer.size())); 173 std::memcpy(&std::get<ArgIndex>(args), buffer.data(), std::min(BufferSize, buffer.size()));
174 174
175 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); 175 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
176 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InBuffer) { 176 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InBuffer) {
177 using ElementType = typename ArgType::Type; 177 using ElementType = typename ArgType::Type;
178 178
@@ -193,14 +193,14 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext&
193 193
194 std::get<ArgIndex>(args) = std::span(ptr, size); 194 std::get<ArgIndex>(args) = std::span(ptr, size);
195 195
196 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); 196 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
197 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { 197 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) {
198 constexpr size_t BufferSize = sizeof(ArgType); 198 constexpr size_t BufferSize = sizeof(ArgType);
199 199
200 // Clear the existing data. 200 // Clear the existing data.
201 std::memset(&std::get<ArgIndex>(args), 0, BufferSize); 201 std::memset(&std::get<ArgIndex>(args), 0, BufferSize);
202 202
203 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); 203 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
204 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { 204 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) {
205 using ElementType = typename ArgType::Type; 205 using ElementType = typename ArgType::Type;
206 206
@@ -217,15 +217,15 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext&
217 217
218 std::get<ArgIndex>(args) = std::span(ptr, size); 218 std::get<ArgIndex>(args) = std::span(ptr, size);
219 219
220 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); 220 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
221 } else { 221 } else {
222 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); 222 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
223 } 223 }
224 } 224 }
225} 225}
226 226
227template <bool Domain, typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> 227template <typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0>
228void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { 228void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) {
229 if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { 229 if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) {
230 return; 230 return;
231 } else { 231 } else {
@@ -243,23 +243,23 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx,
243 243
244 std::memcpy(raw_data + ArgOffset, &std::get<ArgIndex>(args), ArgSize); 244 std::memcpy(raw_data + ArgOffset, &std::get<ArgIndex>(args), ArgSize);
245 245
246 return WriteOutArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(args, raw_data, ctx, temp); 246 return WriteOutArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
247 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutInterface) { 247 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutInterface) {
248 if constexpr (Domain) { 248 if (is_domain) {
249 ctx.AddDomainObject(std::get<ArgIndex>(args)); 249 ctx.AddDomainObject(std::get<ArgIndex>(args));
250 } else { 250 } else {
251 ctx.AddMoveInterface(std::get<ArgIndex>(args)); 251 ctx.AddMoveInterface(std::get<ArgIndex>(args));
252 } 252 }
253 253
254 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(args, raw_data, ctx, temp); 254 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
255 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutCopyHandle) { 255 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutCopyHandle) {
256 ctx.AddCopyObject(std::get<ArgIndex>(args).GetPointerUnsafe()); 256 ctx.AddCopyObject(std::get<ArgIndex>(args));
257 257
258 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); 258 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
259 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutMoveHandle) { 259 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutMoveHandle) {
260 ctx.AddMoveObject(std::get<ArgIndex>(args).GetPointerUnsafe()); 260 ctx.AddMoveObject(std::get<ArgIndex>(args));
261 261
262 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); 262 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
263 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { 263 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) {
264 constexpr size_t BufferSize = sizeof(ArgType); 264 constexpr size_t BufferSize = sizeof(ArgType);
265 265
@@ -272,7 +272,7 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx,
272 ctx.WriteBufferC(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex); 272 ctx.WriteBufferC(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex);
273 } 273 }
274 274
275 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); 275 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
276 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { 276 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) {
277 auto& buffer = temp[OutBufferIndex]; 277 auto& buffer = temp[OutBufferIndex];
278 const size_t size = buffer.size(); 278 const size_t size = buffer.size();
@@ -287,9 +287,9 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx,
287 } 287 }
288 } 288 }
289 289
290 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>( args, raw_data, ctx, temp); 290 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
291 } else { 291 } else {
292 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); 292 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
293 } 293 }
294 } 294 }
295} 295}
@@ -297,11 +297,10 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx,
297template <bool Domain, typename T, typename... A> 297template <bool Domain, typename T, typename... A>
298void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { 298void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
299 // Verify domain state. 299 // Verify domain state.
300 if constexpr (Domain) { 300 if constexpr (!Domain) {
301 ASSERT_MSG(ctx.GetManager()->IsDomain(), "Domain reply used on non-domain session");
302 } else {
303 ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Non-domain reply used on domain session"); 301 ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Non-domain reply used on domain session");
304 } 302 }
303 const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false;
305 304
306 using MethodArguments = std::tuple<std::remove_reference_t<A>...>; 305 using MethodArguments = std::tuple<std::remove_reference_t<A>...>;
307 306
@@ -310,7 +309,7 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
310 309
311 // Read inputs. 310 // Read inputs.
312 const size_t offset_plus_command_id = ctx.GetDataPayloadOffset() + 2; 311 const size_t offset_plus_command_id = ctx.GetDataPayloadOffset() + 2;
313 ReadInArgument<Domain, MethodArguments>(call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + offset_plus_command_id), ctx, buffers); 312 ReadInArgument<MethodArguments>(is_domain, call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + offset_plus_command_id), ctx, buffers);
314 313
315 // Call. 314 // Call.
316 const auto Callable = [&]<typename... CallArgs>(CallArgs&... args) { 315 const auto Callable = [&]<typename... CallArgs>(CallArgs&... args) {
@@ -319,12 +318,12 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
319 const Result res = std::apply(Callable, call_arguments); 318 const Result res = std::apply(Callable, call_arguments);
320 319
321 // Write result. 320 // Write result.
322 constexpr RequestLayout layout = GetReplyOutLayout<Domain, MethodArguments>(); 321 const RequestLayout layout = GetReplyOutLayout<MethodArguments>(is_domain);
323 IPC::ResponseBuilder rb{ctx, 2 + Common::DivCeil(layout.cmif_raw_data_size, sizeof(u32)), layout.copy_handle_count, layout.move_handle_count + layout.domain_interface_count}; 322 IPC::ResponseBuilder rb{ctx, 2 + Common::DivCeil(layout.cmif_raw_data_size, sizeof(u32)), layout.copy_handle_count, layout.move_handle_count + layout.domain_interface_count};
324 rb.Push(res); 323 rb.Push(res);
325 324
326 // Write out arguments. 325 // Write out arguments.
327 WriteOutArgument<Domain, MethodArguments>(call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + rb.GetCurrentOffset()), ctx, buffers); 326 WriteOutArgument<MethodArguments>(is_domain, call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + rb.GetCurrentOffset()), ctx, buffers);
328} 327}
329// clang-format on 328// clang-format on
330 329
diff --git a/src/core/hle/service/cmif_types.h b/src/core/hle/service/cmif_types.h
index b80028c19..2610c49f3 100644
--- a/src/core/hle/service/cmif_types.h
+++ b/src/core/hle/service/cmif_types.h
@@ -15,19 +15,21 @@ namespace Service {
15template <typename T> 15template <typename T>
16class Out { 16class Out {
17public: 17public:
18 /* implicit */ Out(T& t) : raw(&t) {} 18 using Type = T;
19
20 /* implicit */ Out(Type& t) : raw(&t) {}
19 ~Out() = default; 21 ~Out() = default;
20 22
21 T* Get() const { 23 Type* Get() const {
22 return raw; 24 return raw;
23 } 25 }
24 26
25 T& operator*() { 27 Type& operator*() {
26 return *raw; 28 return *raw;
27 } 29 }
28 30
29private: 31private:
30 T* raw; 32 Type* raw;
31}; 33};
32 34
33template <typename T> 35template <typename T>
@@ -45,51 +47,93 @@ struct ClientProcessId {
45 u64 pid; 47 u64 pid;
46}; 48};
47 49
50struct ProcessId {
51 explicit operator bool() const {
52 return pid != 0;
53 }
54
55 const u64& operator*() const {
56 return pid;
57 }
58
59 u64 pid;
60};
61
48using ClientAppletResourceUserId = ClientProcessId; 62using ClientAppletResourceUserId = ClientProcessId;
63using AppletResourceUserId = ProcessId;
49 64
50template <typename T> 65template <typename T>
51class InCopyHandle : public Kernel::KScopedAutoObject<T> { 66class InCopyHandle {
52public: 67public:
53 using Type = T; 68 using Type = T;
54 69
55 template <typename... Args> 70 /* implicit */ InCopyHandle(Type* t) : raw(t) {}
56 /* implicit */ InCopyHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {} 71 /* implicit */ InCopyHandle() : raw() {}
57 ~InCopyHandle() = default; 72 ~InCopyHandle() = default;
58 73
59 InCopyHandle& operator=(InCopyHandle&& rhs) { 74 InCopyHandle& operator=(Type* rhs) {
60 Kernel::KScopedAutoObject<T>::operator=(std::move(rhs)); 75 raw = rhs;
61 return *this; 76 return *this;
62 } 77 }
78
79 Type* Get() const {
80 return raw;
81 }
82
83 Type& operator*() const {
84 return *raw;
85 }
86
87 Type* operator->() const {
88 return raw;
89 }
90
91 explicit operator bool() const {
92 return raw != nullptr;
93 }
94
95private:
96 Type* raw;
63}; 97};
64 98
65template <typename T> 99template <typename T>
66class OutCopyHandle : public Kernel::KScopedAutoObject<T> { 100class OutCopyHandle {
67public: 101public:
68 using Type = T; 102 using Type = T*;
69 103
70 template <typename... Args> 104 /* implicit */ OutCopyHandle(Type& t) : raw(&t) {}
71 /* implicit */ OutCopyHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {}
72 ~OutCopyHandle() = default; 105 ~OutCopyHandle() = default;
73 106
74 OutCopyHandle& operator=(OutCopyHandle&& rhs) { 107 Type* Get() const {
75 Kernel::KScopedAutoObject<T>::operator=(std::move(rhs)); 108 return raw;
76 return *this; 109 }
110
111 Type& operator*() {
112 return *raw;
77 } 113 }
114
115private:
116 Type* raw;
78}; 117};
79 118
80template <typename T> 119template <typename T>
81class OutMoveHandle : public Kernel::KScopedAutoObject<T> { 120class OutMoveHandle {
82public: 121public:
83 using Type = T; 122 using Type = T*;
84 123
85 template <typename... Args> 124 /* implicit */ OutMoveHandle(Type& t) : raw(&t) {}
86 /* implicit */ OutMoveHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {}
87 ~OutMoveHandle() = default; 125 ~OutMoveHandle() = default;
88 126
89 OutMoveHandle& operator=(OutMoveHandle&& rhs) { 127 Type* Get() const {
90 Kernel::KScopedAutoObject<T>::operator=(std::move(rhs)); 128 return raw;
91 return *this; 129 }
130
131 Type& operator*() {
132 return *raw;
92 } 133 }
134
135private:
136 Type* raw;
93}; 137};
94 138
95enum BufferAttr : int { 139enum BufferAttr : int {
@@ -105,12 +149,15 @@ enum BufferAttr : int {
105 149
106template <typename T, int A> 150template <typename T, int A>
107struct Buffer : public std::span<T> { 151struct Buffer : public std::span<T> {
108 static_assert(std::is_trivial_v<T>, "Buffer type must be trivial"); 152 static_assert(std::is_trivially_copyable_v<T>, "Buffer type must be trivially copyable");
109 static_assert((A & BufferAttr_FixedSize) == 0, "Buffer attr must not contain FixedSize"); 153 static_assert((A & BufferAttr_FixedSize) == 0, "Buffer attr must not contain FixedSize");
110 static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "Buffer attr must be In or Out"); 154 static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "Buffer attr must be In or Out");
111 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A); 155 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A);
112 using Type = T; 156 using Type = T;
113 157
158 /* implicit */ Buffer(const std::span<T>& rhs) : std::span<T>(rhs) {}
159 /* implicit */ Buffer() = default;
160
114 Buffer& operator=(const std::span<T>& rhs) { 161 Buffer& operator=(const std::span<T>& rhs) {
115 std::span<T>::operator=(rhs); 162 std::span<T>::operator=(rhs);
116 return *this; 163 return *this;
@@ -139,11 +186,14 @@ using OutArray = Buffer<T, BufferAttr_Out | A>;
139 186
140template <typename T, int A> 187template <typename T, int A>
141struct LargeData : public T { 188struct LargeData : public T {
142 static_assert(std::is_trivial_v<T>, "LargeData type must be trivial"); 189 static_assert(std::is_trivially_copyable_v<T>, "LargeData type must be trivially copyable");
143 static_assert((A & BufferAttr_FixedSize) != 0, "LargeData attr must contain FixedSize"); 190 static_assert((A & BufferAttr_FixedSize) != 0, "LargeData attr must contain FixedSize");
144 static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "LargeData attr must be In or Out"); 191 static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "LargeData attr must be In or Out");
145 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A); 192 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A);
146 using Type = T; 193 using Type = T;
194
195 /* implicit */ LargeData(const T& rhs) : T(rhs) {}
196 /* implicit */ LargeData() = default;
147}; 197};
148 198
149template <typename T, BufferAttr A> 199template <typename T, BufferAttr A>
@@ -159,7 +209,17 @@ struct RemoveOut {
159 209
160template <typename T> 210template <typename T>
161struct RemoveOut<Out<T>> { 211struct RemoveOut<Out<T>> {
162 using Type = T; 212 using Type = typename Out<T>::Type;
213};
214
215template <typename T>
216struct RemoveOut<OutCopyHandle<T>> {
217 using Type = typename OutCopyHandle<T>::Type;
218};
219
220template <typename T>
221struct RemoveOut<OutMoveHandle<T>> {
222 using Type = typename OutMoveHandle<T>::Type;
163}; 223};
164 224
165enum class ArgumentType { 225enum class ArgumentType {
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index 31da86074..dfcac1ffd 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -73,8 +73,8 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F
73 "Program entry point: 0x{:16X}\n" 73 "Program entry point: 0x{:16X}\n"
74 "\n", 74 "\n",
75 Common::g_scm_branch, Common::g_scm_desc, title_id, error_code.raw, 75 Common::g_scm_branch, Common::g_scm_desc, title_id, error_code.raw,
76 2000 + static_cast<u32>(error_code.module.Value()), 76 2000 + static_cast<u32>(error_code.GetModule()),
77 static_cast<u32>(error_code.description.Value()), info.set_flags, info.program_entry_point); 77 static_cast<u32>(error_code.GetDescription()), info.set_flags, info.program_entry_point);
78 if (info.backtrace_size != 0x0) { 78 if (info.backtrace_size != 0x0) {
79 crash_report += "Registers:\n"; 79 crash_report += "Registers:\n";
80 for (size_t i = 0; i < info.registers.size(); i++) { 80 for (size_t i = 0; i < info.registers.size(); i++) {
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index ca6d8d607..ae230afc0 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -12,18 +12,17 @@
12#include "core/file_sys/card_image.h" 12#include "core/file_sys/card_image.h"
13#include "core/file_sys/control_metadata.h" 13#include "core/file_sys/control_metadata.h"
14#include "core/file_sys/errors.h" 14#include "core/file_sys/errors.h"
15#include "core/file_sys/mode.h"
16#include "core/file_sys/patch_manager.h" 15#include "core/file_sys/patch_manager.h"
17#include "core/file_sys/registered_cache.h" 16#include "core/file_sys/registered_cache.h"
18#include "core/file_sys/romfs_factory.h" 17#include "core/file_sys/romfs_factory.h"
19#include "core/file_sys/savedata_factory.h" 18#include "core/file_sys/savedata_factory.h"
20#include "core/file_sys/sdmc_factory.h" 19#include "core/file_sys/sdmc_factory.h"
21#include "core/file_sys/vfs.h" 20#include "core/file_sys/vfs/vfs.h"
22#include "core/file_sys/vfs_offset.h" 21#include "core/file_sys/vfs/vfs_offset.h"
23#include "core/hle/service/filesystem/filesystem.h" 22#include "core/hle/service/filesystem/filesystem.h"
24#include "core/hle/service/filesystem/fsp_ldr.h" 23#include "core/hle/service/filesystem/fsp/fsp_ldr.h"
25#include "core/hle/service/filesystem/fsp_pr.h" 24#include "core/hle/service/filesystem/fsp/fsp_pr.h"
26#include "core/hle/service/filesystem/fsp_srv.h" 25#include "core/hle/service/filesystem/fsp/fsp_srv.h"
27#include "core/hle/service/filesystem/romfs_controller.h" 26#include "core/hle/service/filesystem/romfs_controller.h"
28#include "core/hle/service/filesystem/save_data_controller.h" 27#include "core/hle/service/filesystem/save_data_controller.h"
29#include "core/hle/service/server_manager.h" 28#include "core/hle/service/server_manager.h"
@@ -53,12 +52,12 @@ Result VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size
53 std::string path(Common::FS::SanitizePath(path_)); 52 std::string path(Common::FS::SanitizePath(path_));
54 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 53 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
55 if (dir == nullptr) { 54 if (dir == nullptr) {
56 return FileSys::ERROR_PATH_NOT_FOUND; 55 return FileSys::ResultPathNotFound;
57 } 56 }
58 57
59 FileSys::EntryType entry_type{}; 58 FileSys::DirectoryEntryType entry_type{};
60 if (GetEntryType(&entry_type, path) == ResultSuccess) { 59 if (GetEntryType(&entry_type, path) == ResultSuccess) {
61 return FileSys::ERROR_PATH_ALREADY_EXISTS; 60 return FileSys::ResultPathAlreadyExists;
62 } 61 }
63 62
64 auto file = dir->CreateFile(Common::FS::GetFilename(path)); 63 auto file = dir->CreateFile(Common::FS::GetFilename(path));
@@ -82,7 +81,7 @@ Result VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
82 81
83 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 82 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
84 if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { 83 if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
85 return FileSys::ERROR_PATH_NOT_FOUND; 84 return FileSys::ResultPathNotFound;
86 } 85 }
87 if (!dir->DeleteFile(Common::FS::GetFilename(path))) { 86 if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
88 // TODO(DarkLordZach): Find a better error code for this 87 // TODO(DarkLordZach): Find a better error code for this
@@ -153,12 +152,12 @@ Result VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
153 if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { 152 if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
154 // Use more-optimized vfs implementation rename. 153 // Use more-optimized vfs implementation rename.
155 if (src == nullptr) { 154 if (src == nullptr) {
156 return FileSys::ERROR_PATH_NOT_FOUND; 155 return FileSys::ResultPathNotFound;
157 } 156 }
158 157
159 if (dst && Common::FS::Exists(dst->GetFullPath())) { 158 if (dst && Common::FS::Exists(dst->GetFullPath())) {
160 LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath()); 159 LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath());
161 return FileSys::ERROR_PATH_ALREADY_EXISTS; 160 return FileSys::ResultPathAlreadyExists;
162 } 161 }
163 162
164 if (!src->Rename(Common::FS::GetFilename(dest_path))) { 163 if (!src->Rename(Common::FS::GetFilename(dest_path))) {
@@ -195,7 +194,7 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
195 if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { 194 if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
196 // Use more-optimized vfs implementation rename. 195 // Use more-optimized vfs implementation rename.
197 if (src == nullptr) 196 if (src == nullptr)
198 return FileSys::ERROR_PATH_NOT_FOUND; 197 return FileSys::ResultPathNotFound;
199 if (!src->Rename(Common::FS::GetFilename(dest_path))) { 198 if (!src->Rename(Common::FS::GetFilename(dest_path))) {
200 // TODO(DarkLordZach): Find a better error code for this 199 // TODO(DarkLordZach): Find a better error code for this
201 return ResultUnknown; 200 return ResultUnknown;
@@ -214,7 +213,8 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
214} 213}
215 214
216Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file, 215Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file,
217 const std::string& path_, FileSys::Mode mode) const { 216 const std::string& path_,
217 FileSys::OpenMode mode) const {
218 const std::string path(Common::FS::SanitizePath(path_)); 218 const std::string path(Common::FS::SanitizePath(path_));
219 std::string_view npath = path; 219 std::string_view npath = path;
220 while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) { 220 while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
@@ -223,10 +223,10 @@ Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file,
223 223
224 auto file = backing->GetFileRelative(npath); 224 auto file = backing->GetFileRelative(npath);
225 if (file == nullptr) { 225 if (file == nullptr) {
226 return FileSys::ERROR_PATH_NOT_FOUND; 226 return FileSys::ResultPathNotFound;
227 } 227 }
228 228
229 if (mode == FileSys::Mode::Append) { 229 if (mode == FileSys::OpenMode::AllowAppend) {
230 *out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize()); 230 *out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
231 } else { 231 } else {
232 *out_file = file; 232 *out_file = file;
@@ -241,50 +241,50 @@ Result VfsDirectoryServiceWrapper::OpenDirectory(FileSys::VirtualDir* out_direct
241 auto dir = GetDirectoryRelativeWrapped(backing, path); 241 auto dir = GetDirectoryRelativeWrapped(backing, path);
242 if (dir == nullptr) { 242 if (dir == nullptr) {
243 // TODO(DarkLordZach): Find a better error code for this 243 // TODO(DarkLordZach): Find a better error code for this
244 return FileSys::ERROR_PATH_NOT_FOUND; 244 return FileSys::ResultPathNotFound;
245 } 245 }
246 *out_directory = dir; 246 *out_directory = dir;
247 return ResultSuccess; 247 return ResultSuccess;
248} 248}
249 249
250Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::EntryType* out_entry_type, 250Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::DirectoryEntryType* out_entry_type,
251 const std::string& path_) const { 251 const std::string& path_) const {
252 std::string path(Common::FS::SanitizePath(path_)); 252 std::string path(Common::FS::SanitizePath(path_));
253 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 253 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
254 if (dir == nullptr) { 254 if (dir == nullptr) {
255 return FileSys::ERROR_PATH_NOT_FOUND; 255 return FileSys::ResultPathNotFound;
256 } 256 }
257 257
258 auto filename = Common::FS::GetFilename(path); 258 auto filename = Common::FS::GetFilename(path);
259 // TODO(Subv): Some games use the '/' path, find out what this means. 259 // TODO(Subv): Some games use the '/' path, find out what this means.
260 if (filename.empty()) { 260 if (filename.empty()) {
261 *out_entry_type = FileSys::EntryType::Directory; 261 *out_entry_type = FileSys::DirectoryEntryType::Directory;
262 return ResultSuccess; 262 return ResultSuccess;
263 } 263 }
264 264
265 if (dir->GetFile(filename) != nullptr) { 265 if (dir->GetFile(filename) != nullptr) {
266 *out_entry_type = FileSys::EntryType::File; 266 *out_entry_type = FileSys::DirectoryEntryType::File;
267 return ResultSuccess; 267 return ResultSuccess;
268 } 268 }
269 269
270 if (dir->GetSubdirectory(filename) != nullptr) { 270 if (dir->GetSubdirectory(filename) != nullptr) {
271 *out_entry_type = FileSys::EntryType::Directory; 271 *out_entry_type = FileSys::DirectoryEntryType::Directory;
272 return ResultSuccess; 272 return ResultSuccess;
273 } 273 }
274 274
275 return FileSys::ERROR_PATH_NOT_FOUND; 275 return FileSys::ResultPathNotFound;
276} 276}
277 277
278Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw( 278Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw(
279 FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const { 279 FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const {
280 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 280 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
281 if (dir == nullptr) { 281 if (dir == nullptr) {
282 return FileSys::ERROR_PATH_NOT_FOUND; 282 return FileSys::ResultPathNotFound;
283 } 283 }
284 284
285 FileSys::EntryType entry_type; 285 FileSys::DirectoryEntryType entry_type;
286 if (GetEntryType(&entry_type, path) != ResultSuccess) { 286 if (GetEntryType(&entry_type, path) != ResultSuccess) {
287 return FileSys::ERROR_PATH_NOT_FOUND; 287 return FileSys::ResultPathNotFound;
288 } 288 }
289 289
290 *out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path)); 290 *out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path));
@@ -317,7 +317,7 @@ Result FileSystemController::OpenProcess(
317 317
318 const auto it = registrations.find(process_id); 318 const auto it = registrations.find(process_id);
319 if (it == registrations.end()) { 319 if (it == registrations.end()) {
320 return FileSys::ERROR_ENTITY_NOT_FOUND; 320 return FileSys::ResultTargetNotFound;
321 } 321 }
322 322
323 *out_program_id = it->second.program_id; 323 *out_program_id = it->second.program_id;
@@ -347,7 +347,7 @@ std::shared_ptr<SaveDataController> FileSystemController::OpenSaveDataController
347std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory( 347std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory(
348 ProgramId program_id) { 348 ProgramId program_id) {
349 using YuzuPath = Common::FS::YuzuPath; 349 using YuzuPath = Common::FS::YuzuPath;
350 const auto rw_mode = FileSys::Mode::ReadWrite; 350 const auto rw_mode = FileSys::OpenMode::ReadWrite;
351 351
352 auto vfs = system.GetFilesystem(); 352 auto vfs = system.GetFilesystem();
353 const auto nand_directory = 353 const auto nand_directory =
@@ -360,12 +360,12 @@ Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const {
360 LOG_TRACE(Service_FS, "Opening SDMC"); 360 LOG_TRACE(Service_FS, "Opening SDMC");
361 361
362 if (sdmc_factory == nullptr) { 362 if (sdmc_factory == nullptr) {
363 return FileSys::ERROR_SD_CARD_NOT_FOUND; 363 return FileSys::ResultPortSdCardNoDevice;
364 } 364 }
365 365
366 auto sdmc = sdmc_factory->Open(); 366 auto sdmc = sdmc_factory->Open();
367 if (sdmc == nullptr) { 367 if (sdmc == nullptr) {
368 return FileSys::ERROR_SD_CARD_NOT_FOUND; 368 return FileSys::ResultPortSdCardNoDevice;
369 } 369 }
370 370
371 *out_sdmc = sdmc; 371 *out_sdmc = sdmc;
@@ -377,12 +377,12 @@ Result FileSystemController::OpenBISPartition(FileSys::VirtualDir* out_bis_parti
377 LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id); 377 LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id);
378 378
379 if (bis_factory == nullptr) { 379 if (bis_factory == nullptr) {
380 return FileSys::ERROR_ENTITY_NOT_FOUND; 380 return FileSys::ResultTargetNotFound;
381 } 381 }
382 382
383 auto part = bis_factory->OpenPartition(id); 383 auto part = bis_factory->OpenPartition(id);
384 if (part == nullptr) { 384 if (part == nullptr) {
385 return FileSys::ERROR_INVALID_ARGUMENT; 385 return FileSys::ResultInvalidArgument;
386 } 386 }
387 387
388 *out_bis_partition = part; 388 *out_bis_partition = part;
@@ -394,12 +394,12 @@ Result FileSystemController::OpenBISPartitionStorage(
394 LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id); 394 LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id);
395 395
396 if (bis_factory == nullptr) { 396 if (bis_factory == nullptr) {
397 return FileSys::ERROR_ENTITY_NOT_FOUND; 397 return FileSys::ResultTargetNotFound;
398 } 398 }
399 399
400 auto part = bis_factory->OpenPartitionStorage(id, system.GetFilesystem()); 400 auto part = bis_factory->OpenPartitionStorage(id, system.GetFilesystem());
401 if (part == nullptr) { 401 if (part == nullptr) {
402 return FileSys::ERROR_INVALID_ARGUMENT; 402 return FileSys::ResultInvalidArgument;
403 } 403 }
404 404
405 *out_bis_partition_storage = part; 405 *out_bis_partition_storage = part;
@@ -686,15 +686,15 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
686 using YuzuPath = Common::FS::YuzuPath; 686 using YuzuPath = Common::FS::YuzuPath;
687 const auto sdmc_dir_path = Common::FS::GetYuzuPath(YuzuPath::SDMCDir); 687 const auto sdmc_dir_path = Common::FS::GetYuzuPath(YuzuPath::SDMCDir);
688 const auto sdmc_load_dir_path = sdmc_dir_path / "atmosphere/contents"; 688 const auto sdmc_load_dir_path = sdmc_dir_path / "atmosphere/contents";
689 const auto rw_mode = FileSys::Mode::ReadWrite; 689 const auto rw_mode = FileSys::OpenMode::ReadWrite;
690 690
691 auto nand_directory = 691 auto nand_directory =
692 vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode); 692 vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode);
693 auto sd_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_dir_path), rw_mode); 693 auto sd_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_dir_path), rw_mode);
694 auto load_directory = 694 auto load_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir),
695 vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), FileSys::Mode::Read); 695 FileSys::OpenMode::Read);
696 auto sd_load_directory = 696 auto sd_load_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path),
697 vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), FileSys::Mode::Read); 697 FileSys::OpenMode::Read);
698 auto dump_directory = 698 auto dump_directory =
699 vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode); 699 vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode);
700 700
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 48f37d289..718500385 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -4,9 +4,11 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include <mutex>
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "core/file_sys/directory.h" 9#include "core/file_sys/fs_directory.h"
9#include "core/file_sys/vfs.h" 10#include "core/file_sys/fs_filesystem.h"
11#include "core/file_sys/vfs/vfs.h"
10#include "core/hle/result.h" 12#include "core/hle/result.h"
11 13
12namespace Core { 14namespace Core {
@@ -26,7 +28,6 @@ class XCI;
26 28
27enum class BisPartitionId : u32; 29enum class BisPartitionId : u32;
28enum class ContentRecordType : u8; 30enum class ContentRecordType : u8;
29enum class Mode : u32;
30enum class SaveDataSpaceId : u8; 31enum class SaveDataSpaceId : u8;
31enum class SaveDataType : u8; 32enum class SaveDataType : u8;
32enum class StorageId : u8; 33enum class StorageId : u8;
@@ -57,13 +58,6 @@ enum class ImageDirectoryId : u32 {
57 SdCard, 58 SdCard,
58}; 59};
59 60
60enum class OpenDirectoryMode : u64 {
61 Directory = (1 << 0),
62 File = (1 << 1),
63 All = Directory | File
64};
65DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode);
66
67using ProcessId = u64; 61using ProcessId = u64;
68using ProgramId = u64; 62using ProgramId = u64;
69 63
@@ -237,7 +231,7 @@ public:
237 * @return Opened file, or error code 231 * @return Opened file, or error code
238 */ 232 */
239 Result OpenFile(FileSys::VirtualFile* out_file, const std::string& path, 233 Result OpenFile(FileSys::VirtualFile* out_file, const std::string& path,
240 FileSys::Mode mode) const; 234 FileSys::OpenMode mode) const;
241 235
242 /** 236 /**
243 * Open a directory specified by its path 237 * Open a directory specified by its path
@@ -250,7 +244,7 @@ public:
250 * Get the type of the specified path 244 * Get the type of the specified path
251 * @return The type of the specified path or error code 245 * @return The type of the specified path or error code
252 */ 246 */
253 Result GetEntryType(FileSys::EntryType* out_entry_type, const std::string& path) const; 247 Result GetEntryType(FileSys::DirectoryEntryType* out_entry_type, const std::string& path) const;
254 248
255 /** 249 /**
256 * Get the timestamp of the specified path 250 * Get the timestamp of the specified path
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
new file mode 100644
index 000000000..39690018b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
@@ -0,0 +1,84 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/file_sys/fs_filesystem.h"
5#include "core/file_sys/savedata_factory.h"
6#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
7#include "core/hle/service/ipc_helpers.h"
8
9namespace Service::FileSystem {
10
11template <typename T>
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)
32 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
33 static const FunctionInfo functions[] = {
34 {0, &IDirectory::Read, "Read"},
35 {1, &IDirectory::GetEntryCount, "GetEntryCount"},
36 };
37 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}
49
50void IDirectory::Read(HLERequestContext& ctx) {
51 LOG_DEBUG(Service_FS, "called.");
52
53 // Calculate how many entries we can fit in the output buffer
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}
73
74void IDirectory::GetEntryCount(HLERequestContext& ctx) {
75 LOG_DEBUG(Service_FS, "called");
76
77 u64 count = entries.size() - next_entry_index;
78
79 IPC::ResponseBuilder rb{ctx, 4};
80 rb.Push(ResultSuccess);
81 rb.Push(count);
82}
83
84} // 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
new file mode 100644
index 000000000..793ecfcd7
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2023 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/filesystem/filesystem.h"
8#include "core/hle/service/service.h"
9
10namespace FileSys {
11struct DirectoryEntry;
12}
13
14namespace Service::FileSystem {
15
16class IDirectory final : public ServiceFramework<IDirectory> {
17public:
18 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
19 FileSys::OpenDirectoryMode mode);
20
21private:
22 FileSys::VirtualDir backend;
23 std::vector<FileSys::DirectoryEntry> entries;
24 u64 next_entry_index = 0;
25
26 void Read(HLERequestContext& ctx);
27 void GetEntryCount(HLERequestContext& ctx);
28};
29
30} // 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
new file mode 100644
index 000000000..9a18f6ec5
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
@@ -0,0 +1,127 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/file_sys/errors.h"
5#include "core/hle/service/filesystem/fsp/fs_i_file.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::FileSystem {
9
10IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_)
11 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
12 static const FunctionInfo functions[] = {
13 {0, &IFile::Read, "Read"},
14 {1, &IFile::Write, "Write"},
15 {2, &IFile::Flush, "Flush"},
16 {3, &IFile::SetSize, "SetSize"},
17 {4, &IFile::GetSize, "GetSize"},
18 {5, nullptr, "OperateRange"},
19 {6, nullptr, "OperateRangeWithBuffer"},
20 };
21 RegisterHandlers(functions);
22}
23
24void IFile::Read(HLERequestContext& ctx) {
25 IPC::RequestParser rp{ctx};
26 const u64 option = rp.Pop<u64>();
27 const s64 offset = rp.Pop<s64>();
28 const s64 length = rp.Pop<s64>();
29
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
46 // Read the data from the Storage backend
47 std::vector<u8> output = backend->ReadBytes(length, offset);
48
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}
56
57void IFile::Write(HLERequestContext& ctx) {
58 IPC::RequestParser rp{ctx};
59 const u64 option = rp.Pop<u64>();
60 const s64 offset = rp.Pop<s64>();
61 const s64 length = rp.Pop<s64>();
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
81 ASSERT_MSG(static_cast<s64>(data.size()) <= length,
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}
97
98void IFile::Flush(HLERequestContext& ctx) {
99 LOG_DEBUG(Service_FS, "called");
100
101 // Exists for SDK compatibiltity -- No need to flush file.
102
103 IPC::ResponseBuilder rb{ctx, 2};
104 rb.Push(ResultSuccess);
105}
106
107void IFile::SetSize(HLERequestContext& ctx) {
108 IPC::RequestParser rp{ctx};
109 const u64 size = rp.Pop<u64>();
110 LOG_DEBUG(Service_FS, "called, size={}", size);
111
112 backend->Resize(size);
113
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(ResultSuccess);
116}
117
118void IFile::GetSize(HLERequestContext& ctx) {
119 const u64 size = backend->GetSize();
120 LOG_DEBUG(Service_FS, "called, size={}", size);
121
122 IPC::ResponseBuilder rb{ctx, 4};
123 rb.Push(ResultSuccess);
124 rb.Push<u64>(size);
125}
126
127} // 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
new file mode 100644
index 000000000..5e5430c67
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/filesystem/filesystem.h"
7#include "core/hle/service/service.h"
8
9namespace Service::FileSystem {
10
11class IFile final : public ServiceFramework<IFile> {
12public:
13 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_);
14
15private:
16 FileSys::VirtualFile backend;
17
18 void Read(HLERequestContext& ctx);
19 void Write(HLERequestContext& ctx);
20 void Flush(HLERequestContext& ctx);
21 void SetSize(HLERequestContext& ctx);
22 void GetSize(HLERequestContext& ctx);
23};
24
25} // 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
new file mode 100644
index 000000000..efa394dd1
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
@@ -0,0 +1,262 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/string_util.h"
5#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
6#include "core/hle/service/filesystem/fsp/fs_i_file.h"
7#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
8#include "core/hle/service/ipc_helpers.h"
9
10namespace Service::FileSystem {
11
12IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
13 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
14 size_)} {
15 static const FunctionInfo functions[] = {
16 {0, &IFileSystem::CreateFile, "CreateFile"},
17 {1, &IFileSystem::DeleteFile, "DeleteFile"},
18 {2, &IFileSystem::CreateDirectory, "CreateDirectory"},
19 {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"},
20 {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"},
21 {5, &IFileSystem::RenameFile, "RenameFile"},
22 {6, nullptr, "RenameDirectory"},
23 {7, &IFileSystem::GetEntryType, "GetEntryType"},
24 {8, &IFileSystem::OpenFile, "OpenFile"},
25 {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
26 {10, &IFileSystem::Commit, "Commit"},
27 {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"},
28 {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"},
29 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
30 {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"},
31 {15, nullptr, "QueryEntry"},
32 {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"},
33 };
34 RegisterHandlers(functions);
35}
36
37void IFileSystem::CreateFile(HLERequestContext& ctx) {
38 IPC::RequestParser rp{ctx};
39
40 const auto file_buffer = ctx.ReadBuffer();
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}
52
53void IFileSystem::DeleteFile(HLERequestContext& ctx) {
54 const auto file_buffer = ctx.ReadBuffer();
55 const std::string name = Common::StringFromBuffer(file_buffer);
56
57 LOG_DEBUG(Service_FS, "called. file={}", name);
58
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(backend.DeleteFile(name));
61}
62
63void IFileSystem::CreateDirectory(HLERequestContext& ctx) {
64 const auto file_buffer = ctx.ReadBuffer();
65 const std::string name = Common::StringFromBuffer(file_buffer);
66
67 LOG_DEBUG(Service_FS, "called. directory={}", name);
68
69 IPC::ResponseBuilder rb{ctx, 2};
70 rb.Push(backend.CreateDirectory(name));
71}
72
73void IFileSystem::DeleteDirectory(HLERequestContext& ctx) {
74 const auto file_buffer = ctx.ReadBuffer();
75 const std::string name = Common::StringFromBuffer(file_buffer);
76
77 LOG_DEBUG(Service_FS, "called. directory={}", name);
78
79 IPC::ResponseBuilder rb{ctx, 2};
80 rb.Push(backend.DeleteDirectory(name));
81}
82
83void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) {
84 const auto file_buffer = ctx.ReadBuffer();
85 const std::string name = Common::StringFromBuffer(file_buffer);
86
87 LOG_DEBUG(Service_FS, "called. directory={}", name);
88
89 IPC::ResponseBuilder rb{ctx, 2};
90 rb.Push(backend.DeleteDirectoryRecursively(name));
91}
92
93void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) {
94 const auto file_buffer = ctx.ReadBuffer();
95 const std::string name = Common::StringFromBuffer(file_buffer);
96
97 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
98
99 IPC::ResponseBuilder rb{ctx, 2};
100 rb.Push(backend.CleanDirectoryRecursively(name));
101}
102
103void IFileSystem::RenameFile(HLERequestContext& ctx) {
104 const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
105 const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
106
107 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
108
109 IPC::ResponseBuilder rb{ctx, 2};
110 rb.Push(backend.RenameFile(src_name, dst_name));
111}
112
113void IFileSystem::OpenFile(HLERequestContext& ctx) {
114 IPC::RequestParser rp{ctx};
115
116 const auto file_buffer = ctx.ReadBuffer();
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
123 FileSys::VirtualFile vfs_file{};
124 auto result = backend.OpenFile(&vfs_file, name, mode);
125 if (result != ResultSuccess) {
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
141 const auto file_buffer = ctx.ReadBuffer();
142 const std::string name = Common::StringFromBuffer(file_buffer);
143 const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>();
144
145 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode);
146
147 FileSys::VirtualDir vfs_dir{};
148 auto result = backend.OpenDirectory(&vfs_dir, name);
149 if (result != ResultSuccess) {
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
162void IFileSystem::GetEntryType(HLERequestContext& ctx) {
163 const auto file_buffer = ctx.ReadBuffer();
164 const std::string name = Common::StringFromBuffer(file_buffer);
165
166 LOG_DEBUG(Service_FS, "called. file={}", name);
167
168 FileSys::DirectoryEntryType vfs_entry_type{};
169 auto result = backend.GetEntryType(&vfs_entry_type, name);
170 if (result != ResultSuccess) {
171 IPC::ResponseBuilder rb{ctx, 2};
172 rb.Push(result);
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}
180
181void IFileSystem::Commit(HLERequestContext& ctx) {
182 LOG_WARNING(Service_FS, "(STUBBED) called");
183
184 IPC::ResponseBuilder rb{ctx, 2};
185 rb.Push(ResultSuccess);
186}
187
188void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) {
189 LOG_DEBUG(Service_FS, "called");
190
191 IPC::ResponseBuilder rb{ctx, 4};
192 rb.Push(ResultSuccess);
193 rb.Push(size.get_free_size());
194}
195
196void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) {
197 LOG_DEBUG(Service_FS, "called");
198
199 IPC::ResponseBuilder rb{ctx, 4};
200 rb.Push(ResultSuccess);
201 rb.Push(size.get_total_size());
202}
203
204void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) {
205 const auto file_buffer = ctx.ReadBuffer();
206 const std::string name = Common::StringFromBuffer(file_buffer);
207
208 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
209
210 FileSys::FileTimeStampRaw vfs_timestamp{};
211 auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
212 if (result != ResultSuccess) {
213 IPC::ResponseBuilder rb{ctx, 2};
214 rb.Push(result);
215 return;
216 }
217
218 IPC::ResponseBuilder rb{ctx, 10};
219 rb.Push(ResultSuccess);
220 rb.PushRaw(vfs_timestamp);
221}
222
223void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) {
224 LOG_WARNING(Service_FS, "(STUBBED) called");
225
226 struct FileSystemAttribute {
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;
253 savedata_attribute.file_entry_name_length_max_defined = true;
254 savedata_attribute.dir_entry_name_length_max = 0x40;
255 savedata_attribute.file_entry_name_length_max = 0x40;
256
257 IPC::ResponseBuilder rb{ctx, 50};
258 rb.Push(ResultSuccess);
259 rb.PushRaw(savedata_attribute);
260}
261
262} // 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
new file mode 100644
index 000000000..b06b3ef0e
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2023 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/filesystem/filesystem.h"
8#include "core/hle/service/filesystem/fsp/fsp_util.h"
9#include "core/hle/service/service.h"
10
11namespace Service::FileSystem {
12
13class IFileSystem final : public ServiceFramework<IFileSystem> {
14public:
15 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_);
16
17 void CreateFile(HLERequestContext& ctx);
18 void DeleteFile(HLERequestContext& ctx);
19 void CreateDirectory(HLERequestContext& ctx);
20 void DeleteDirectory(HLERequestContext& ctx);
21 void DeleteDirectoryRecursively(HLERequestContext& ctx);
22 void CleanDirectoryRecursively(HLERequestContext& ctx);
23 void RenameFile(HLERequestContext& ctx);
24 void OpenFile(HLERequestContext& ctx);
25 void OpenDirectory(HLERequestContext& ctx);
26 void GetEntryType(HLERequestContext& ctx);
27 void Commit(HLERequestContext& ctx);
28 void GetFreeSpaceSize(HLERequestContext& ctx);
29 void GetTotalSpaceSize(HLERequestContext& ctx);
30 void GetFileTimeStampRaw(HLERequestContext& ctx);
31 void GetFileSystemAttribute(HLERequestContext& ctx);
32
33private:
34 VfsDirectoryServiceWrapper backend;
35 SizeGetter size;
36};
37
38} // 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
new file mode 100644
index 000000000..98223c1f9
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
@@ -0,0 +1,62 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/file_sys/errors.h"
5#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::FileSystem {
9
10IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_)
11 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
12 static const FunctionInfo functions[] = {
13 {0, &IStorage::Read, "Read"},
14 {1, nullptr, "Write"},
15 {2, nullptr, "Flush"},
16 {3, nullptr, "SetSize"},
17 {4, &IStorage::GetSize, "GetSize"},
18 {5, nullptr, "OperateRange"},
19 };
20 RegisterHandlers(functions);
21}
22
23void IStorage::Read(HLERequestContext& ctx) {
24 IPC::RequestParser rp{ctx};
25 const s64 offset = rp.Pop<s64>();
26 const s64 length = rp.Pop<s64>();
27
28 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
29
30 // Error checking
31 if (length < 0) {
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
44 // Read the data from the Storage backend
45 std::vector<u8> output = backend->ReadBytes(length, offset);
46 // Write the data to memory
47 ctx.WriteBuffer(output);
48
49 IPC::ResponseBuilder rb{ctx, 2};
50 rb.Push(ResultSuccess);
51}
52
53void IStorage::GetSize(HLERequestContext& ctx) {
54 const u64 size = backend->GetSize();
55 LOG_DEBUG(Service_FS, "called, size={}", size);
56
57 IPC::ResponseBuilder rb{ctx, 4};
58 rb.Push(ResultSuccess);
59 rb.Push<u64>(size);
60}
61
62} // 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
new file mode 100644
index 000000000..cb5bebcc9
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2023 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/filesystem/filesystem.h"
8#include "core/hle/service/service.h"
9
10namespace Service::FileSystem {
11
12class IStorage final : public ServiceFramework<IStorage> {
13public:
14 explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_);
15
16private:
17 FileSys::VirtualFile backend;
18
19 void Read(HLERequestContext& ctx);
20 void GetSize(HLERequestContext& ctx);
21};
22
23} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp
index 1e3366e71..8ee733f47 100644
--- a/src/core/hle/service/filesystem/fsp_ldr.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp
@@ -1,7 +1,7 @@
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 "core/hle/service/filesystem/fsp_ldr.h" 4#include "core/hle/service/filesystem/fsp/fsp_ldr.h"
5 5
6namespace Service::FileSystem { 6namespace Service::FileSystem {
7 7
diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp/fsp_ldr.h
index 358739a87..358739a87 100644
--- a/src/core/hle/service/filesystem/fsp_ldr.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_ldr.h
diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp/fsp_pr.cpp
index 4ffc31977..7c03ebaea 100644
--- a/src/core/hle/service/filesystem/fsp_pr.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_pr.cpp
@@ -1,7 +1,7 @@
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 "core/hle/service/filesystem/fsp_pr.h" 4#include "core/hle/service/filesystem/fsp/fsp_pr.h"
5 5
6namespace Service::FileSystem { 6namespace Service::FileSystem {
7 7
diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp/fsp_pr.h
index bd4e0a730..bd4e0a730 100644
--- a/src/core/hle/service/filesystem/fsp_pr.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_pr.h
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
index a2397bec4..2be72b021 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
@@ -15,18 +15,20 @@
15#include "common/settings.h" 15#include "common/settings.h"
16#include "common/string_util.h" 16#include "common/string_util.h"
17#include "core/core.h" 17#include "core/core.h"
18#include "core/file_sys/directory.h"
19#include "core/file_sys/errors.h" 18#include "core/file_sys/errors.h"
20#include "core/file_sys/mode.h" 19#include "core/file_sys/fs_directory.h"
20#include "core/file_sys/fs_filesystem.h"
21#include "core/file_sys/nca_metadata.h" 21#include "core/file_sys/nca_metadata.h"
22#include "core/file_sys/patch_manager.h" 22#include "core/file_sys/patch_manager.h"
23#include "core/file_sys/romfs_factory.h" 23#include "core/file_sys/romfs_factory.h"
24#include "core/file_sys/savedata_factory.h" 24#include "core/file_sys/savedata_factory.h"
25#include "core/file_sys/system_archive/system_archive.h" 25#include "core/file_sys/system_archive/system_archive.h"
26#include "core/file_sys/vfs.h" 26#include "core/file_sys/vfs/vfs.h"
27#include "core/hle/result.h" 27#include "core/hle/result.h"
28#include "core/hle/service/filesystem/filesystem.h" 28#include "core/hle/service/filesystem/filesystem.h"
29#include "core/hle/service/filesystem/fsp_srv.h" 29#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
30#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
31#include "core/hle/service/filesystem/fsp/fsp_srv.h"
30#include "core/hle/service/filesystem/romfs_controller.h" 32#include "core/hle/service/filesystem/romfs_controller.h"
31#include "core/hle/service/filesystem/save_data_controller.h" 33#include "core/hle/service/filesystem/save_data_controller.h"
32#include "core/hle/service/hle_ipc.h" 34#include "core/hle/service/hle_ipc.h"
@@ -34,19 +36,6 @@
34#include "core/reporter.h" 36#include "core/reporter.h"
35 37
36namespace Service::FileSystem { 38namespace Service::FileSystem {
37
38struct SizeGetter {
39 std::function<u64()> get_free_size;
40 std::function<u64()> get_total_size;
41
42 static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) {
43 return {
44 [&fsc, id] { return fsc.GetFreeSpaceSize(id); },
45 [&fsc, id] { return fsc.GetTotalSpaceSize(id); },
46 };
47 }
48};
49
50enum class FileSystemType : u8 { 39enum class FileSystemType : u8 {
51 Invalid0 = 0, 40 Invalid0 = 0,
52 Invalid1 = 1, 41 Invalid1 = 1,
@@ -58,525 +47,6 @@ enum class FileSystemType : u8 {
58 ApplicationPackage = 7, 47 ApplicationPackage = 7,
59}; 48};
60 49
61class IStorage final : public ServiceFramework<IStorage> {
62public:
63 explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
64 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
65 static const FunctionInfo functions[] = {
66 {0, &IStorage::Read, "Read"},
67 {1, nullptr, "Write"},
68 {2, nullptr, "Flush"},
69 {3, nullptr, "SetSize"},
70 {4, &IStorage::GetSize, "GetSize"},
71 {5, nullptr, "OperateRange"},
72 };
73 RegisterHandlers(functions);
74 }
75
76private:
77 FileSys::VirtualFile backend;
78
79 void Read(HLERequestContext& ctx) {
80 IPC::RequestParser rp{ctx};
81 const s64 offset = rp.Pop<s64>();
82 const s64 length = rp.Pop<s64>();
83
84 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
85
86 // Error checking
87 if (length < 0) {
88 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
89 IPC::ResponseBuilder rb{ctx, 2};
90 rb.Push(FileSys::ERROR_INVALID_SIZE);
91 return;
92 }
93 if (offset < 0) {
94 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
95 IPC::ResponseBuilder rb{ctx, 2};
96 rb.Push(FileSys::ERROR_INVALID_OFFSET);
97 return;
98 }
99
100 // Read the data from the Storage backend
101 std::vector<u8> output = backend->ReadBytes(length, offset);
102 // Write the data to memory
103 ctx.WriteBuffer(output);
104
105 IPC::ResponseBuilder rb{ctx, 2};
106 rb.Push(ResultSuccess);
107 }
108
109 void GetSize(HLERequestContext& ctx) {
110 const u64 size = backend->GetSize();
111 LOG_DEBUG(Service_FS, "called, size={}", size);
112
113 IPC::ResponseBuilder rb{ctx, 4};
114 rb.Push(ResultSuccess);
115 rb.Push<u64>(size);
116 }
117};
118
119class IFile final : public ServiceFramework<IFile> {
120public:
121 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
122 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
123 static const FunctionInfo functions[] = {
124 {0, &IFile::Read, "Read"},
125 {1, &IFile::Write, "Write"},
126 {2, &IFile::Flush, "Flush"},
127 {3, &IFile::SetSize, "SetSize"},
128 {4, &IFile::GetSize, "GetSize"},
129 {5, nullptr, "OperateRange"},
130 {6, nullptr, "OperateRangeWithBuffer"},
131 };
132 RegisterHandlers(functions);
133 }
134
135private:
136 FileSys::VirtualFile backend;
137
138 void Read(HLERequestContext& ctx) {
139 IPC::RequestParser rp{ctx};
140 const u64 option = rp.Pop<u64>();
141 const s64 offset = rp.Pop<s64>();
142 const s64 length = rp.Pop<s64>();
143
144 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
145 length);
146
147 // Error checking
148 if (length < 0) {
149 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
150 IPC::ResponseBuilder rb{ctx, 2};
151 rb.Push(FileSys::ERROR_INVALID_SIZE);
152 return;
153 }
154 if (offset < 0) {
155 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
156 IPC::ResponseBuilder rb{ctx, 2};
157 rb.Push(FileSys::ERROR_INVALID_OFFSET);
158 return;
159 }
160
161 // Read the data from the Storage backend
162 std::vector<u8> output = backend->ReadBytes(length, offset);
163
164 // Write the data to memory
165 ctx.WriteBuffer(output);
166
167 IPC::ResponseBuilder rb{ctx, 4};
168 rb.Push(ResultSuccess);
169 rb.Push(static_cast<u64>(output.size()));
170 }
171
172 void Write(HLERequestContext& ctx) {
173 IPC::RequestParser rp{ctx};
174 const u64 option = rp.Pop<u64>();
175 const s64 offset = rp.Pop<s64>();
176 const s64 length = rp.Pop<s64>();
177
178 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
179 length);
180
181 // Error checking
182 if (length < 0) {
183 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
184 IPC::ResponseBuilder rb{ctx, 2};
185 rb.Push(FileSys::ERROR_INVALID_SIZE);
186 return;
187 }
188 if (offset < 0) {
189 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
190 IPC::ResponseBuilder rb{ctx, 2};
191 rb.Push(FileSys::ERROR_INVALID_OFFSET);
192 return;
193 }
194
195 const auto data = ctx.ReadBuffer();
196
197 ASSERT_MSG(
198 static_cast<s64>(data.size()) <= length,
199 "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
200 length, data.size());
201
202 // Write the data to the Storage backend
203 const auto write_size =
204 static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
205 const std::size_t written = backend->Write(data.data(), write_size, offset);
206
207 ASSERT_MSG(static_cast<s64>(written) == length,
208 "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
209 written);
210
211 IPC::ResponseBuilder rb{ctx, 2};
212 rb.Push(ResultSuccess);
213 }
214
215 void Flush(HLERequestContext& ctx) {
216 LOG_DEBUG(Service_FS, "called");
217
218 // Exists for SDK compatibiltity -- No need to flush file.
219
220 IPC::ResponseBuilder rb{ctx, 2};
221 rb.Push(ResultSuccess);
222 }
223
224 void SetSize(HLERequestContext& ctx) {
225 IPC::RequestParser rp{ctx};
226 const u64 size = rp.Pop<u64>();
227 LOG_DEBUG(Service_FS, "called, size={}", size);
228
229 backend->Resize(size);
230
231 IPC::ResponseBuilder rb{ctx, 2};
232 rb.Push(ResultSuccess);
233 }
234
235 void GetSize(HLERequestContext& ctx) {
236 const u64 size = backend->GetSize();
237 LOG_DEBUG(Service_FS, "called, size={}", size);
238
239 IPC::ResponseBuilder rb{ctx, 4};
240 rb.Push(ResultSuccess);
241 rb.Push<u64>(size);
242 }
243};
244
245template <typename T>
246static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data,
247 FileSys::EntryType type) {
248 entries.reserve(entries.size() + new_data.size());
249
250 for (const auto& new_entry : new_data) {
251 auto name = new_entry->GetName();
252
253 if (type == FileSys::EntryType::File && name == FileSys::GetSaveDataSizeFileName()) {
254 continue;
255 }
256
257 entries.emplace_back(name, type,
258 type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize());
259 }
260}
261
262class IDirectory final : public ServiceFramework<IDirectory> {
263public:
264 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, OpenDirectoryMode mode)
265 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
266 static const FunctionInfo functions[] = {
267 {0, &IDirectory::Read, "Read"},
268 {1, &IDirectory::GetEntryCount, "GetEntryCount"},
269 };
270 RegisterHandlers(functions);
271
272 // TODO(DarkLordZach): Verify that this is the correct behavior.
273 // Build entry index now to save time later.
274 if (True(mode & OpenDirectoryMode::Directory)) {
275 BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
276 }
277 if (True(mode & OpenDirectoryMode::File)) {
278 BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File);
279 }
280 }
281
282private:
283 FileSys::VirtualDir backend;
284 std::vector<FileSys::Entry> entries;
285 u64 next_entry_index = 0;
286
287 void Read(HLERequestContext& ctx) {
288 LOG_DEBUG(Service_FS, "called.");
289
290 // Calculate how many entries we can fit in the output buffer
291 const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::Entry>();
292
293 // Cap at total number of entries.
294 const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
295
296 // Determine data start and end
297 const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
298 const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
299 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
300
301 next_entry_index += actual_entries;
302
303 // Write the data to memory
304 ctx.WriteBuffer(begin, range_size);
305
306 IPC::ResponseBuilder rb{ctx, 4};
307 rb.Push(ResultSuccess);
308 rb.Push(actual_entries);
309 }
310
311 void GetEntryCount(HLERequestContext& ctx) {
312 LOG_DEBUG(Service_FS, "called");
313
314 u64 count = entries.size() - next_entry_index;
315
316 IPC::ResponseBuilder rb{ctx, 4};
317 rb.Push(ResultSuccess);
318 rb.Push(count);
319 }
320};
321
322class IFileSystem final : public ServiceFramework<IFileSystem> {
323public:
324 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
325 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
326 size_)} {
327 static const FunctionInfo functions[] = {
328 {0, &IFileSystem::CreateFile, "CreateFile"},
329 {1, &IFileSystem::DeleteFile, "DeleteFile"},
330 {2, &IFileSystem::CreateDirectory, "CreateDirectory"},
331 {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"},
332 {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"},
333 {5, &IFileSystem::RenameFile, "RenameFile"},
334 {6, nullptr, "RenameDirectory"},
335 {7, &IFileSystem::GetEntryType, "GetEntryType"},
336 {8, &IFileSystem::OpenFile, "OpenFile"},
337 {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
338 {10, &IFileSystem::Commit, "Commit"},
339 {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"},
340 {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"},
341 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
342 {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"},
343 {15, nullptr, "QueryEntry"},
344 {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"},
345 };
346 RegisterHandlers(functions);
347 }
348
349 void CreateFile(HLERequestContext& ctx) {
350 IPC::RequestParser rp{ctx};
351
352 const auto file_buffer = ctx.ReadBuffer();
353 const std::string name = Common::StringFromBuffer(file_buffer);
354
355 const u64 file_mode = rp.Pop<u64>();
356 const u32 file_size = rp.Pop<u32>();
357
358 LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
359 file_size);
360
361 IPC::ResponseBuilder rb{ctx, 2};
362 rb.Push(backend.CreateFile(name, file_size));
363 }
364
365 void DeleteFile(HLERequestContext& ctx) {
366 const auto file_buffer = ctx.ReadBuffer();
367 const std::string name = Common::StringFromBuffer(file_buffer);
368
369 LOG_DEBUG(Service_FS, "called. file={}", name);
370
371 IPC::ResponseBuilder rb{ctx, 2};
372 rb.Push(backend.DeleteFile(name));
373 }
374
375 void CreateDirectory(HLERequestContext& ctx) {
376 const auto file_buffer = ctx.ReadBuffer();
377 const std::string name = Common::StringFromBuffer(file_buffer);
378
379 LOG_DEBUG(Service_FS, "called. directory={}", name);
380
381 IPC::ResponseBuilder rb{ctx, 2};
382 rb.Push(backend.CreateDirectory(name));
383 }
384
385 void DeleteDirectory(HLERequestContext& ctx) {
386 const auto file_buffer = ctx.ReadBuffer();
387 const std::string name = Common::StringFromBuffer(file_buffer);
388
389 LOG_DEBUG(Service_FS, "called. directory={}", name);
390
391 IPC::ResponseBuilder rb{ctx, 2};
392 rb.Push(backend.DeleteDirectory(name));
393 }
394
395 void DeleteDirectoryRecursively(HLERequestContext& ctx) {
396 const auto file_buffer = ctx.ReadBuffer();
397 const std::string name = Common::StringFromBuffer(file_buffer);
398
399 LOG_DEBUG(Service_FS, "called. directory={}", name);
400
401 IPC::ResponseBuilder rb{ctx, 2};
402 rb.Push(backend.DeleteDirectoryRecursively(name));
403 }
404
405 void CleanDirectoryRecursively(HLERequestContext& ctx) {
406 const auto file_buffer = ctx.ReadBuffer();
407 const std::string name = Common::StringFromBuffer(file_buffer);
408
409 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
410
411 IPC::ResponseBuilder rb{ctx, 2};
412 rb.Push(backend.CleanDirectoryRecursively(name));
413 }
414
415 void RenameFile(HLERequestContext& ctx) {
416 const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
417 const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
418
419 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
420
421 IPC::ResponseBuilder rb{ctx, 2};
422 rb.Push(backend.RenameFile(src_name, dst_name));
423 }
424
425 void OpenFile(HLERequestContext& ctx) {
426 IPC::RequestParser rp{ctx};
427
428 const auto file_buffer = ctx.ReadBuffer();
429 const std::string name = Common::StringFromBuffer(file_buffer);
430
431 const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
432
433 LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
434
435 FileSys::VirtualFile vfs_file{};
436 auto result = backend.OpenFile(&vfs_file, name, mode);
437 if (result != ResultSuccess) {
438 IPC::ResponseBuilder rb{ctx, 2};
439 rb.Push(result);
440 return;
441 }
442
443 auto file = std::make_shared<IFile>(system, vfs_file);
444
445 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
446 rb.Push(ResultSuccess);
447 rb.PushIpcInterface<IFile>(std::move(file));
448 }
449
450 void OpenDirectory(HLERequestContext& ctx) {
451 IPC::RequestParser rp{ctx};
452
453 const auto file_buffer = ctx.ReadBuffer();
454 const std::string name = Common::StringFromBuffer(file_buffer);
455 const auto mode = rp.PopRaw<OpenDirectoryMode>();
456
457 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode);
458
459 FileSys::VirtualDir vfs_dir{};
460 auto result = backend.OpenDirectory(&vfs_dir, name);
461 if (result != ResultSuccess) {
462 IPC::ResponseBuilder rb{ctx, 2};
463 rb.Push(result);
464 return;
465 }
466
467 auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
468
469 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
470 rb.Push(ResultSuccess);
471 rb.PushIpcInterface<IDirectory>(std::move(directory));
472 }
473
474 void GetEntryType(HLERequestContext& ctx) {
475 const auto file_buffer = ctx.ReadBuffer();
476 const std::string name = Common::StringFromBuffer(file_buffer);
477
478 LOG_DEBUG(Service_FS, "called. file={}", name);
479
480 FileSys::EntryType vfs_entry_type{};
481 auto result = backend.GetEntryType(&vfs_entry_type, name);
482 if (result != ResultSuccess) {
483 IPC::ResponseBuilder rb{ctx, 2};
484 rb.Push(result);
485 return;
486 }
487
488 IPC::ResponseBuilder rb{ctx, 3};
489 rb.Push(ResultSuccess);
490 rb.Push<u32>(static_cast<u32>(vfs_entry_type));
491 }
492
493 void Commit(HLERequestContext& ctx) {
494 LOG_WARNING(Service_FS, "(STUBBED) called");
495
496 IPC::ResponseBuilder rb{ctx, 2};
497 rb.Push(ResultSuccess);
498 }
499
500 void GetFreeSpaceSize(HLERequestContext& ctx) {
501 LOG_DEBUG(Service_FS, "called");
502
503 IPC::ResponseBuilder rb{ctx, 4};
504 rb.Push(ResultSuccess);
505 rb.Push(size.get_free_size());
506 }
507
508 void GetTotalSpaceSize(HLERequestContext& ctx) {
509 LOG_DEBUG(Service_FS, "called");
510
511 IPC::ResponseBuilder rb{ctx, 4};
512 rb.Push(ResultSuccess);
513 rb.Push(size.get_total_size());
514 }
515
516 void GetFileTimeStampRaw(HLERequestContext& ctx) {
517 const auto file_buffer = ctx.ReadBuffer();
518 const std::string name = Common::StringFromBuffer(file_buffer);
519
520 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
521
522 FileSys::FileTimeStampRaw vfs_timestamp{};
523 auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
524 if (result != ResultSuccess) {
525 IPC::ResponseBuilder rb{ctx, 2};
526 rb.Push(result);
527 return;
528 }
529
530 IPC::ResponseBuilder rb{ctx, 10};
531 rb.Push(ResultSuccess);
532 rb.PushRaw(vfs_timestamp);
533 }
534
535 void GetFileSystemAttribute(HLERequestContext& ctx) {
536 LOG_WARNING(Service_FS, "(STUBBED) called");
537
538 struct FileSystemAttribute {
539 u8 dir_entry_name_length_max_defined;
540 u8 file_entry_name_length_max_defined;
541 u8 dir_path_name_length_max_defined;
542 u8 file_path_name_length_max_defined;
543 INSERT_PADDING_BYTES_NOINIT(0x5);
544 u8 utf16_dir_entry_name_length_max_defined;
545 u8 utf16_file_entry_name_length_max_defined;
546 u8 utf16_dir_path_name_length_max_defined;
547 u8 utf16_file_path_name_length_max_defined;
548 INSERT_PADDING_BYTES_NOINIT(0x18);
549 s32 dir_entry_name_length_max;
550 s32 file_entry_name_length_max;
551 s32 dir_path_name_length_max;
552 s32 file_path_name_length_max;
553 INSERT_PADDING_WORDS_NOINIT(0x5);
554 s32 utf16_dir_entry_name_length_max;
555 s32 utf16_file_entry_name_length_max;
556 s32 utf16_dir_path_name_length_max;
557 s32 utf16_file_path_name_length_max;
558 INSERT_PADDING_WORDS_NOINIT(0x18);
559 INSERT_PADDING_WORDS_NOINIT(0x1);
560 };
561 static_assert(sizeof(FileSystemAttribute) == 0xc0,
562 "FileSystemAttribute has incorrect size");
563
564 FileSystemAttribute savedata_attribute{};
565 savedata_attribute.dir_entry_name_length_max_defined = true;
566 savedata_attribute.file_entry_name_length_max_defined = true;
567 savedata_attribute.dir_entry_name_length_max = 0x40;
568 savedata_attribute.file_entry_name_length_max = 0x40;
569
570 IPC::ResponseBuilder rb{ctx, 50};
571 rb.Push(ResultSuccess);
572 rb.PushRaw(savedata_attribute);
573 }
574
575private:
576 VfsDirectoryServiceWrapper backend;
577 SizeGetter size;
578};
579
580class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { 50class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
581public: 51public:
582 explicit ISaveDataInfoReader(Core::System& system_, 52 explicit ISaveDataInfoReader(Core::System& system_,
@@ -960,7 +430,7 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
960 save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute); 430 save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute);
961 if (result != ResultSuccess) { 431 if (result != ResultSuccess) {
962 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 432 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
963 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); 433 rb.Push(FileSys::ResultTargetNotFound);
964 return; 434 return;
965 } 435 }
966 436
@@ -1127,7 +597,7 @@ void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) {
1127 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id); 597 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id);
1128 598
1129 IPC::ResponseBuilder rb{ctx, 2}; 599 IPC::ResponseBuilder rb{ctx, 2};
1130 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); 600 rb.Push(FileSys::ResultTargetNotFound);
1131} 601}
1132 602
1133void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { 603void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h
index 26980af99..26980af99 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h
diff --git a/src/core/hle/service/filesystem/fsp/fsp_util.h b/src/core/hle/service/filesystem/fsp/fsp_util.h
new file mode 100644
index 000000000..253f866db
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fsp_util.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/filesystem/filesystem.h"
7
8namespace Service::FileSystem {
9
10struct SizeGetter {
11 std::function<u64()> get_free_size;
12 std::function<u64()> get_total_size;
13
14 static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) {
15 return {
16 [&fsc, id] { return fsc.GetFreeSpaceSize(id); },
17 [&fsc, id] { return fsc.GetTotalSpaceSize(id); },
18 };
19 }
20};
21
22} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/romfs_controller.h b/src/core/hle/service/filesystem/romfs_controller.h
index 9a478f71d..3c3ead344 100644
--- a/src/core/hle/service/filesystem/romfs_controller.h
+++ b/src/core/hle/service/filesystem/romfs_controller.h
@@ -5,7 +5,7 @@
5 5
6#include "core/file_sys/nca_metadata.h" 6#include "core/file_sys/nca_metadata.h"
7#include "core/file_sys/romfs_factory.h" 7#include "core/file_sys/romfs_factory.h"
8#include "core/file_sys/vfs_types.h" 8#include "core/file_sys/vfs/vfs_types.h"
9 9
10namespace Service::FileSystem { 10namespace Service::FileSystem {
11 11
diff --git a/src/core/hle/service/filesystem/save_data_controller.cpp b/src/core/hle/service/filesystem/save_data_controller.cpp
index d19b3ea1e..03e45f7f9 100644
--- a/src/core/hle/service/filesystem/save_data_controller.cpp
+++ b/src/core/hle/service/filesystem/save_data_controller.cpp
@@ -44,7 +44,7 @@ Result SaveDataController::CreateSaveData(FileSys::VirtualDir* out_save_data,
44 44
45 auto save_data = factory->Create(space, attribute); 45 auto save_data = factory->Create(space, attribute);
46 if (save_data == nullptr) { 46 if (save_data == nullptr) {
47 return FileSys::ERROR_ENTITY_NOT_FOUND; 47 return FileSys::ResultTargetNotFound;
48 } 48 }
49 49
50 *out_save_data = save_data; 50 *out_save_data = save_data;
@@ -56,7 +56,7 @@ Result SaveDataController::OpenSaveData(FileSys::VirtualDir* out_save_data,
56 const FileSys::SaveDataAttribute& attribute) { 56 const FileSys::SaveDataAttribute& attribute) {
57 auto save_data = factory->Open(space, attribute); 57 auto save_data = factory->Open(space, attribute);
58 if (save_data == nullptr) { 58 if (save_data == nullptr) {
59 return FileSys::ERROR_ENTITY_NOT_FOUND; 59 return FileSys::ResultTargetNotFound;
60 } 60 }
61 61
62 *out_save_data = save_data; 62 *out_save_data = save_data;
@@ -67,7 +67,7 @@ Result SaveDataController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_
67 FileSys::SaveDataSpaceId space) { 67 FileSys::SaveDataSpaceId space) {
68 auto save_data_space = factory->GetSaveDataSpaceDirectory(space); 68 auto save_data_space = factory->GetSaveDataSpaceDirectory(space);
69 if (save_data_space == nullptr) { 69 if (save_data_space == nullptr) {
70 return FileSys::ERROR_ENTITY_NOT_FOUND; 70 return FileSys::ResultTargetNotFound;
71 } 71 }
72 72
73 *out_save_data_space = save_data_space; 73 *out_save_data_space = save_data_space;
diff --git a/src/core/hle/service/filesystem/save_data_controller.h b/src/core/hle/service/filesystem/save_data_controller.h
index 863188e4c..dc9d713df 100644
--- a/src/core/hle/service/filesystem/save_data_controller.h
+++ b/src/core/hle/service/filesystem/save_data_controller.h
@@ -5,7 +5,7 @@
5 5
6#include "core/file_sys/nca_metadata.h" 6#include "core/file_sys/nca_metadata.h"
7#include "core/file_sys/savedata_factory.h" 7#include "core/file_sys/savedata_factory.h"
8#include "core/file_sys/vfs_types.h" 8#include "core/file_sys/vfs/vfs_types.h"
9 9
10namespace Service::FileSystem { 10namespace Service::FileSystem {
11 11
diff --git a/src/core/hle/service/glue/time/manager.cpp b/src/core/hle/service/glue/time/manager.cpp
index 6423e5089..b56762941 100644
--- a/src/core/hle/service/glue/time/manager.cpp
+++ b/src/core/hle/service/glue/time/manager.cpp
@@ -8,7 +8,7 @@
8 8
9#include "common/settings.h" 9#include "common/settings.h"
10#include "common/time_zone.h" 10#include "common/time_zone.h"
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
12#include "core/hle/kernel/svc.h" 12#include "core/hle/kernel/svc.h"
13#include "core/hle/service/glue/time/manager.h" 13#include "core/hle/service/glue/time/manager.h"
14#include "core/hle/service/glue/time/time_zone_binary.h" 14#include "core/hle/service/glue/time/time_zone_binary.h"
diff --git a/src/core/hle/service/glue/time/manager.h b/src/core/hle/service/glue/time/manager.h
index a46ec6364..1de93f8f9 100644
--- a/src/core/hle/service/glue/time/manager.h
+++ b/src/core/hle/service/glue/time/manager.h
@@ -7,7 +7,7 @@
7#include <string> 7#include <string>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/vfs_types.h" 10#include "core/file_sys/vfs/vfs_types.h"
11#include "core/hle/service/glue/time/file_timestamp_worker.h" 11#include "core/hle/service/glue/time/file_timestamp_worker.h"
12#include "core/hle/service/glue/time/standard_steady_clock_resource.h" 12#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
13#include "core/hle/service/glue/time/worker.h" 13#include "core/hle/service/glue/time/worker.h"
diff --git a/src/core/hle/service/glue/time/time_zone_binary.cpp b/src/core/hle/service/glue/time/time_zone_binary.cpp
index 67969aa3f..d33f784c0 100644
--- a/src/core/hle/service/glue/time/time_zone_binary.cpp
+++ b/src/core/hle/service/glue/time/time_zone_binary.cpp
@@ -7,7 +7,7 @@
7#include "core/file_sys/registered_cache.h" 7#include "core/file_sys/registered_cache.h"
8#include "core/file_sys/romfs.h" 8#include "core/file_sys/romfs.h"
9#include "core/file_sys/system_archive/system_archive.h" 9#include "core/file_sys/system_archive/system_archive.h"
10#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs/vfs.h"
11#include "core/hle/service/filesystem/filesystem.h" 11#include "core/hle/service/filesystem/filesystem.h"
12#include "core/hle/service/glue/time/time_zone_binary.h" 12#include "core/hle/service/glue/time/time_zone_binary.h"
13 13
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
index d8fefff89..1f2cbcb61 100644
--- a/src/core/hle/service/jit/jit.cpp
+++ b/src/core/hle/service/jit/jit.cpp
@@ -27,7 +27,7 @@ static_assert(sizeof(Struct32) == 32, "Struct32 has wrong size");
27class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { 27class IJitEnvironment final : public ServiceFramework<IJitEnvironment> {
28public: 28public:
29 explicit IJitEnvironment(Core::System& system_, 29 explicit IJitEnvironment(Core::System& system_,
30 Kernel::KScopedAutoObject<Kernel::KProcess>&& process_, 30 Kernel::KScopedAutoObject<Kernel::KProcess> process_,
31 CodeMemory&& user_rx_, CodeMemory&& user_ro_) 31 CodeMemory&& user_rx_, CodeMemory&& user_ro_)
32 : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)}, 32 : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)},
33 user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)}, 33 user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)},
@@ -129,7 +129,7 @@ public:
129 Result LoadPlugin(u64 tmem_size, InCopyHandle<Kernel::KTransferMemory>& tmem, 129 Result LoadPlugin(u64 tmem_size, InCopyHandle<Kernel::KTransferMemory>& tmem,
130 InBuffer<BufferAttr_HipcMapAlias> nrr, 130 InBuffer<BufferAttr_HipcMapAlias> nrr,
131 InBuffer<BufferAttr_HipcMapAlias> nro) { 131 InBuffer<BufferAttr_HipcMapAlias> nro) {
132 if (tmem.IsNull()) { 132 if (!tmem) {
133 LOG_ERROR(Service_JIT, "Invalid transfer memory handle!"); 133 LOG_ERROR(Service_JIT, "Invalid transfer memory handle!");
134 R_THROW(ResultUnknown); 134 R_THROW(ResultUnknown);
135 } 135 }
@@ -271,15 +271,15 @@ private:
271 u64 rx_size, u64 ro_size, InCopyHandle<Kernel::KProcess>& process, 271 u64 rx_size, u64 ro_size, InCopyHandle<Kernel::KProcess>& process,
272 InCopyHandle<Kernel::KCodeMemory>& rx_mem, 272 InCopyHandle<Kernel::KCodeMemory>& rx_mem,
273 InCopyHandle<Kernel::KCodeMemory>& ro_mem) { 273 InCopyHandle<Kernel::KCodeMemory>& ro_mem) {
274 if (process.IsNull()) { 274 if (!process) {
275 LOG_ERROR(Service_JIT, "process is null"); 275 LOG_ERROR(Service_JIT, "process is null");
276 R_THROW(ResultUnknown); 276 R_THROW(ResultUnknown);
277 } 277 }
278 if (rx_mem.IsNull()) { 278 if (!rx_mem) {
279 LOG_ERROR(Service_JIT, "rx_mem is null"); 279 LOG_ERROR(Service_JIT, "rx_mem is null");
280 R_THROW(ResultUnknown); 280 R_THROW(ResultUnknown);
281 } 281 }
282 if (rx_mem.IsNull()) { 282 if (!ro_mem) {
283 LOG_ERROR(Service_JIT, "ro_mem is null"); 283 LOG_ERROR(Service_JIT, "ro_mem is null");
284 R_THROW(ResultUnknown); 284 R_THROW(ResultUnknown);
285 } 285 }
@@ -291,8 +291,8 @@ private:
291 R_TRY(ro.Initialize(*process, *ro_mem, ro_size, Kernel::Svc::MemoryPermission::Read, 291 R_TRY(ro.Initialize(*process, *ro_mem, ro_size, Kernel::Svc::MemoryPermission::Read,
292 generate_random)); 292 generate_random));
293 293
294 *out_jit_environment = std::make_shared<IJitEnvironment>(system, std::move(process), 294 *out_jit_environment =
295 std::move(rx), std::move(ro)); 295 std::make_shared<IJitEnvironment>(system, process.Get(), std::move(rx), std::move(ro));
296 R_SUCCEED(); 296 R_SUCCEED();
297 } 297 }
298 298
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index 207ac4efe..3e2c7deab 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -301,7 +301,7 @@ Result NfcInterface::TranslateResultToServiceError(Result result) const {
301 return result; 301 return result;
302 } 302 }
303 303
304 if (result.module != ErrorModule::NFC) { 304 if (result.GetModule() != ErrorModule::NFC) {
305 return result; 305 return result;
306 } 306 }
307 307
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index a25b79513..2258ee609 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -6,7 +6,7 @@
6#include "core/core.h" 6#include "core/core.h"
7#include "core/file_sys/control_metadata.h" 7#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/patch_manager.h" 8#include "core/file_sys/patch_manager.h"
9#include "core/file_sys/vfs.h" 9#include "core/file_sys/vfs/vfs.h"
10#include "core/hle/service/filesystem/filesystem.h" 10#include "core/hle/service/filesystem/filesystem.h"
11#include "core/hle/service/glue/glue_manager.h" 11#include "core/hle/service/glue/glue_manager.h"
12#include "core/hle/service/ipc_helpers.h" 12#include "core/hle/service/ipc_helpers.h"
diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp
index ae62c430e..51196170a 100644
--- a/src/core/hle/service/ro/ro.cpp
+++ b/src/core/hle/service/ro/ro.cpp
@@ -551,8 +551,7 @@ public:
551 Result RegisterProcessHandle(ClientProcessId client_pid, 551 Result RegisterProcessHandle(ClientProcessId client_pid,
552 InCopyHandle<Kernel::KProcess>& process) { 552 InCopyHandle<Kernel::KProcess>& process) {
553 // Register the process. 553 // Register the process.
554 R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process.GetPointerUnsafe(), 554 R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process.Get(), *client_pid));
555 *client_pid));
556 } 555 }
557 556
558 Result RegisterProcessModuleInfo(ClientProcessId client_pid, u64 nrr_address, u64 nrr_size, 557 Result RegisterProcessModuleInfo(ClientProcessId client_pid, u64 nrr_address, u64 nrr_size,
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp
index f40a1c8f3..b527c39a9 100644
--- a/src/core/hle/service/set/system_settings_server.cpp
+++ b/src/core/hle/service/set/system_settings_server.cpp
@@ -67,13 +67,13 @@ Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System&
67 const auto ver_file = romfs->GetFile("file"); 67 const auto ver_file = romfs->GetFile("file");
68 if (ver_file == nullptr) { 68 if (ver_file == nullptr) {
69 return early_exit_failure("The system version archive didn't contain the file 'file'.", 69 return early_exit_failure("The system version archive didn't contain the file 'file'.",
70 FileSys::ERROR_INVALID_ARGUMENT); 70 FileSys::ResultInvalidArgument);
71 } 71 }
72 72
73 auto data = ver_file->ReadAllBytes(); 73 auto data = ver_file->ReadAllBytes();
74 if (data.size() != sizeof(FirmwareVersionFormat)) { 74 if (data.size() != sizeof(FirmwareVersionFormat)) {
75 return early_exit_failure("The system version file 'file' was not the correct size.", 75 return early_exit_failure("The system version file 'file' was not the correct size.",
76 FileSys::ERROR_OUT_OF_BOUNDS); 76 FileSys::ResultOutOfRange);
77 } 77 }
78 78
79 std::memcpy(&out_firmware, data.data(), sizeof(FirmwareVersionFormat)); 79 std::memcpy(&out_firmware, data.data(), sizeof(FirmwareVersionFormat));
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index b4828f7cd..f4e932cec 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -14,7 +14,7 @@
14#include "common/common_funcs.h" 14#include "common/common_funcs.h"
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "core/file_sys/control_metadata.h" 16#include "core/file_sys/control_metadata.h"
17#include "core/file_sys/vfs.h" 17#include "core/file_sys/vfs/vfs.h"
18 18
19namespace Core { 19namespace Core {
20class System; 20class System;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index f8225d697..1d96dc4c8 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -12,7 +12,7 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "core/file_sys/control_metadata.h" 13#include "core/file_sys/control_metadata.h"
14#include "core/file_sys/romfs_factory.h" 14#include "core/file_sys/romfs_factory.h"
15#include "core/file_sys/vfs_offset.h" 15#include "core/file_sys/vfs/vfs_offset.h"
16#include "core/hle/kernel/code_set.h" 16#include "core/hle/kernel/code_set.h"
17#include "core/hle/kernel/k_page_table.h" 17#include "core/hle/kernel/k_page_table.h"
18#include "core/hle/kernel/k_process.h" 18#include "core/hle/kernel/k_process.h"
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index dc3883528..1a0138697 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -68,8 +68,8 @@ json GetReportCommonData(u64 title_id, Result result, const std::string& timesta
68 auto out = json{ 68 auto out = json{
69 {"title_id", fmt::format("{:016X}", title_id)}, 69 {"title_id", fmt::format("{:016X}", title_id)},
70 {"result_raw", fmt::format("{:08X}", result.raw)}, 70 {"result_raw", fmt::format("{:08X}", result.raw)},
71 {"result_module", fmt::format("{:08X}", static_cast<u32>(result.module.Value()))}, 71 {"result_module", fmt::format("{:08X}", static_cast<u32>(result.GetModule()))},
72 {"result_description", fmt::format("{:08X}", result.description.Value())}, 72 {"result_description", fmt::format("{:08X}", result.GetDescription())},
73 {"timestamp", timestamp}, 73 {"timestamp", timestamp},
74 }; 74 };
75 75
diff --git a/src/frontend_common/content_manager.h b/src/frontend_common/content_manager.h
index 1cbaa73f7..f3efe3465 100644
--- a/src/frontend_common/content_manager.h
+++ b/src/frontend_common/content_manager.h
@@ -9,7 +9,7 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/file_sys/common_funcs.h" 10#include "core/file_sys/common_funcs.h"
11#include "core/file_sys/content_archive.h" 11#include "core/file_sys/content_archive.h"
12#include "core/file_sys/mode.h" 12#include "core/file_sys/fs_filesystem.h"
13#include "core/file_sys/nca_metadata.h" 13#include "core/file_sys/nca_metadata.h"
14#include "core/file_sys/patch_manager.h" 14#include "core/file_sys/patch_manager.h"
15#include "core/file_sys/registered_cache.h" 15#include "core/file_sys/registered_cache.h"
@@ -159,7 +159,7 @@ inline InstallResult InstallNSP(Core::System& system, FileSys::VfsFilesystem& vf
159 }; 159 };
160 160
161 std::shared_ptr<FileSys::NSP> nsp; 161 std::shared_ptr<FileSys::NSP> nsp;
162 FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::Mode::Read); 162 FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::OpenMode::Read);
163 if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) { 163 if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) {
164 nsp = std::make_shared<FileSys::NSP>(file); 164 nsp = std::make_shared<FileSys::NSP>(file);
165 if (nsp->IsExtractedType()) { 165 if (nsp->IsExtractedType()) {
@@ -224,7 +224,8 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem& vfs, const std::string&
224 return true; 224 return true;
225 }; 225 };
226 226
227 const auto nca = std::make_shared<FileSys::NCA>(vfs.OpenFile(filename, FileSys::Mode::Read)); 227 const auto nca =
228 std::make_shared<FileSys::NCA>(vfs.OpenFile(filename, FileSys::OpenMode::Read));
228 const auto id = nca->GetStatus(); 229 const auto id = nca->GetStatus();
229 230
230 // Game updates necessary are missing base RomFS 231 // Game updates necessary are missing base RomFS
@@ -345,8 +346,8 @@ inline std::vector<std::string> VerifyInstalledContents(
345inline GameVerificationResult VerifyGameContents( 346inline GameVerificationResult VerifyGameContents(
346 Core::System& system, const std::string& game_path, 347 Core::System& system, const std::string& game_path,
347 const std::function<bool(size_t, size_t)>& callback) { 348 const std::function<bool(size_t, size_t)>& callback) {
348 const auto loader = 349 const auto loader = Loader::GetLoader(
349 Loader::GetLoader(system, system.GetFilesystem()->OpenFile(game_path, FileSys::Mode::Read)); 350 system, system.GetFilesystem()->OpenFile(game_path, FileSys::OpenMode::Read));
350 if (loader == nullptr) { 351 if (loader == nullptr) {
351 return GameVerificationResult::NotImplemented; 352 return GameVerificationResult::NotImplemented;
352 } 353 }
diff --git a/src/yuzu/applets/qt_error.cpp b/src/yuzu/applets/qt_error.cpp
index 1dc4f0383..ad35f4126 100644
--- a/src/yuzu/applets/qt_error.cpp
+++ b/src/yuzu/applets/qt_error.cpp
@@ -25,8 +25,8 @@ void QtErrorDisplay::ShowError(Result error, FinishedCallback finished) const {
25 callback = std::move(finished); 25 callback = std::move(finished);
26 emit MainWindowDisplayError( 26 emit MainWindowDisplayError(
27 tr("Error Code: %1-%2 (0x%3)") 27 tr("Error Code: %1-%2 (0x%3)")
28 .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) 28 .arg(static_cast<u32>(error.GetModule()) + 2000, 4, 10, QChar::fromLatin1('0'))
29 .arg(error.description, 4, 10, QChar::fromLatin1('0')) 29 .arg(error.GetDescription(), 4, 10, QChar::fromLatin1('0'))
30 .arg(error.raw, 8, 16, QChar::fromLatin1('0')), 30 .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
31 tr("An error has occurred.\nPlease try again or contact the developer of the software.")); 31 tr("An error has occurred.\nPlease try again or contact the developer of the software."));
32} 32}
@@ -38,8 +38,8 @@ void QtErrorDisplay::ShowErrorWithTimestamp(Result error, std::chrono::seconds t
38 const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count()); 38 const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count());
39 emit MainWindowDisplayError( 39 emit MainWindowDisplayError(
40 tr("Error Code: %1-%2 (0x%3)") 40 tr("Error Code: %1-%2 (0x%3)")
41 .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) 41 .arg(static_cast<u32>(error.GetModule()) + 2000, 4, 10, QChar::fromLatin1('0'))
42 .arg(error.description, 4, 10, QChar::fromLatin1('0')) 42 .arg(error.GetDescription(), 4, 10, QChar::fromLatin1('0'))
43 .arg(error.raw, 8, 16, QChar::fromLatin1('0')), 43 .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
44 tr("An error occurred on %1 at %2.\nPlease try again or contact the developer of the " 44 tr("An error occurred on %1 at %2.\nPlease try again or contact the developer of the "
45 "software.") 45 "software.")
@@ -53,8 +53,8 @@ void QtErrorDisplay::ShowCustomErrorText(Result error, std::string dialog_text,
53 callback = std::move(finished); 53 callback = std::move(finished);
54 emit MainWindowDisplayError( 54 emit MainWindowDisplayError(
55 tr("Error Code: %1-%2 (0x%3)") 55 tr("Error Code: %1-%2 (0x%3)")
56 .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) 56 .arg(static_cast<u32>(error.GetModule()) + 2000, 4, 10, QChar::fromLatin1('0'))
57 .arg(error.description, 4, 10, QChar::fromLatin1('0')) 57 .arg(error.GetDescription(), 4, 10, QChar::fromLatin1('0'))
58 .arg(error.raw, 8, 16, QChar::fromLatin1('0')), 58 .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
59 tr("An error has occurred.\n\n%1\n\n%2") 59 tr("An error has occurred.\n\n%1\n\n%2")
60 .arg(QString::fromStdString(dialog_text)) 60 .arg(QString::fromStdString(dialog_text))
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h
index c8ee46c04..9daae772c 100644
--- a/src/yuzu/configuration/configure_per_game.h
+++ b/src/yuzu/configuration/configure_per_game.h
@@ -11,7 +11,7 @@
11#include <QList> 11#include <QList>
12 12
13#include "configuration/shared_widget.h" 13#include "configuration/shared_widget.h"
14#include "core/file_sys/vfs_types.h" 14#include "core/file_sys/vfs/vfs_types.h"
15#include "frontend_common/config.h" 15#include "frontend_common/config.h"
16#include "vk_device_info.h" 16#include "vk_device_info.h"
17#include "yuzu/configuration/configuration_shared.h" 17#include "yuzu/configuration/configuration_shared.h"
diff --git a/src/yuzu/configuration/configure_per_game_addons.h b/src/yuzu/configuration/configure_per_game_addons.h
index 53db405c1..32dc5dde6 100644
--- a/src/yuzu/configuration/configure_per_game_addons.h
+++ b/src/yuzu/configuration/configure_per_game_addons.h
@@ -8,7 +8,7 @@
8 8
9#include <QList> 9#include <QList>
10 10
11#include "core/file_sys/vfs_types.h" 11#include "core/file_sys/vfs/vfs_types.h"
12 12
13namespace Core { 13namespace Core {
14class System; 14class System;
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 9747e3fb3..0cbf5f45e 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -17,7 +17,7 @@
17#include "core/file_sys/card_image.h" 17#include "core/file_sys/card_image.h"
18#include "core/file_sys/content_archive.h" 18#include "core/file_sys/content_archive.h"
19#include "core/file_sys/control_metadata.h" 19#include "core/file_sys/control_metadata.h"
20#include "core/file_sys/mode.h" 20#include "core/file_sys/fs_filesystem.h"
21#include "core/file_sys/nca_metadata.h" 21#include "core/file_sys/nca_metadata.h"
22#include "core/file_sys/patch_manager.h" 22#include "core/file_sys/patch_manager.h"
23#include "core/file_sys/registered_cache.h" 23#include "core/file_sys/registered_cache.h"
@@ -347,7 +347,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
347 347
348 if (!is_dir && 348 if (!is_dir &&
349 (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { 349 (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
350 const auto file = vfs->OpenFile(physical_name, FileSys::Mode::Read); 350 const auto file = vfs->OpenFile(physical_name, FileSys::OpenMode::Read);
351 if (!file) { 351 if (!file) {
352 return true; 352 return true;
353 } 353 }
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index e14410f7d..782bcbb61 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -35,8 +35,8 @@
35#include "configuration/configure_per_game.h" 35#include "configuration/configure_per_game.h"
36#include "configuration/configure_tas.h" 36#include "configuration/configure_tas.h"
37#include "core/file_sys/romfs_factory.h" 37#include "core/file_sys/romfs_factory.h"
38#include "core/file_sys/vfs.h" 38#include "core/file_sys/vfs/vfs.h"
39#include "core/file_sys/vfs_real.h" 39#include "core/file_sys/vfs/vfs_real.h"
40#include "core/frontend/applets/cabinet.h" 40#include "core/frontend/applets/cabinet.h"
41#include "core/frontend/applets/controller.h" 41#include "core/frontend/applets/controller.h"
42#include "core/frontend/applets/general_frontend.h" 42#include "core/frontend/applets/general_frontend.h"
@@ -56,7 +56,7 @@
56// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows 56// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
57// defines. 57// defines.
58static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper( 58static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper(
59 const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::Mode mode) { 59 const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::OpenMode mode) {
60 return vfs->CreateDirectory(path, mode); 60 return vfs->CreateDirectory(path, mode);
61} 61}
62 62
@@ -1880,7 +1880,7 @@ bool GMainWindow::SelectAndSetCurrentUser(
1880 1880
1881void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { 1881void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) {
1882 // Ensure all NCAs are registered before launching the game 1882 // Ensure all NCAs are registered before launching the game
1883 const auto file = vfs->OpenFile(filepath, FileSys::Mode::Read); 1883 const auto file = vfs->OpenFile(filepath, FileSys::OpenMode::Read);
1884 if (!file) { 1884 if (!file) {
1885 return; 1885 return;
1886 } 1886 }
@@ -2274,7 +2274,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
2274 open_target = tr("Save Data"); 2274 open_target = tr("Save Data");
2275 const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); 2275 const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
2276 auto vfs_nand_dir = 2276 auto vfs_nand_dir =
2277 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); 2277 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
2278 2278
2279 if (has_user_save) { 2279 if (has_user_save) {
2280 // User save data 2280 // User save data
@@ -2653,7 +2653,7 @@ void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& g
2653void GMainWindow::RemoveCacheStorage(u64 program_id) { 2653void GMainWindow::RemoveCacheStorage(u64 program_id) {
2654 const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); 2654 const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
2655 auto vfs_nand_dir = 2655 auto vfs_nand_dir =
2656 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); 2656 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
2657 2657
2658 const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( 2658 const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath(
2659 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::CacheStorage, 2659 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::CacheStorage,
@@ -2673,7 +2673,8 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
2673 "cancelled the operation.")); 2673 "cancelled the operation."));
2674 }; 2674 };
2675 2675
2676 const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); 2676 const auto loader =
2677 Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read));
2677 if (loader == nullptr) { 2678 if (loader == nullptr) {
2678 failed(); 2679 failed();
2679 return; 2680 return;
@@ -2717,7 +2718,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
2717 const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed}; 2718 const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed};
2718 auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false); 2719 auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false);
2719 2720
2720 const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::Mode::ReadWrite); 2721 const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::OpenMode::ReadWrite);
2721 2722
2722 if (out == nullptr) { 2723 if (out == nullptr) {
2723 failed(); 2724 failed();
@@ -3015,7 +3016,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
3015 system->GetContentProvider()}; 3016 system->GetContentProvider()};
3016 const auto control = pm.GetControlMetadata(); 3017 const auto control = pm.GetControlMetadata();
3017 const auto loader = 3018 const auto loader =
3018 Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); 3019 Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read));
3019 game_title = fmt::format("{:016X}", program_id); 3020 game_title = fmt::format("{:016X}", program_id);
3020 if (control.first != nullptr) { 3021 if (control.first != nullptr) {
3021 game_title = control.first->GetApplicationName(); 3022 game_title = control.first->GetApplicationName();
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index c3cacf852..c39ace2ec 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -25,7 +25,7 @@
25#include "core/cpu_manager.h" 25#include "core/cpu_manager.h"
26#include "core/crypto/key_manager.h" 26#include "core/crypto/key_manager.h"
27#include "core/file_sys/registered_cache.h" 27#include "core/file_sys/registered_cache.h"
28#include "core/file_sys/vfs_real.h" 28#include "core/file_sys/vfs/vfs_real.h"
29#include "core/hle/service/filesystem/filesystem.h" 29#include "core/hle/service/filesystem/filesystem.h"
30#include "core/loader/loader.h" 30#include "core/loader/loader.h"
31#include "core/telemetry_session.h" 31#include "core/telemetry_session.h"