diff options
174 files changed, 3747 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 @@ # # SPDX-License-Identifier: GPL-3.0-or-later -find_path(SimpleIni_INCLUDE_DIR SimpleIni.h) - include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(SimpleIni - REQUIRED_VARS SimpleIni_INCLUDE_DIR -) -if (SimpleIni_FOUND AND NOT TARGET SimpleIni::SimpleIni) - add_library(SimpleIni::SimpleIni INTERFACE IMPORTED) - set_target_properties(SimpleIni::SimpleIni PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${SimpleIni_INCLUDE_DIR}" +find_package(SimpleIni QUIET CONFIG) +if (SimpleIni_CONSIDERED_CONFIGS) + find_package_handle_standard_args(SimpleIni CONFIG_MODE) +else() + find_package(PkgConfig QUIET) + pkg_search_module(SIMPLEINI QUIET IMPORTED_TARGET simpleini) + find_package_handle_standard_args(SimpleIni + REQUIRED_VARS SIMPLEINI_INCLUDEDIR + VERSION_VAR SIMPLEINI_VERSION ) endif() -mark_as_advanced(SimpleIni_INCLUDE_DIR) +if (SimpleIni_FOUND AND NOT TARGET SimpleIni::SimpleIni) + add_library(SimpleIni::SimpleIni ALIAS PkgConfig::SIMPLEINI) +endif() 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 { return super.dispatchKeyEvent(event) } + if (emulationViewModel.drawerOpen.value) { + return super.dispatchKeyEvent(event) + } + return InputHandler.dispatchKeyEvent(event) } @@ -203,6 +207,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { return super.dispatchGenericMotionEvent(event) } + if (emulationViewModel.drawerOpen.value) { + return super.dispatchGenericMotionEvent(event) + } + // Don't attempt to do anything if we are disconnecting a device. if (event.actionMasked == MotionEvent.ACTION_CANCEL) { 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() { } binding.textVersionName.text = BuildConfig.VERSION_NAME - binding.textVersionName.setOnClickListener { + binding.buttonVersionName.setOnClickListener { val clipBoard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager 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 import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.slider.Slider import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import org.yuzu.yuzu_emu.HomeNavigationDirections @@ -184,10 +185,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { override fun onDrawerOpened(drawerView: View) { binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) + binding.inGameMenu.requestFocus() + emulationViewModel.setDrawerOpen(true) } override fun onDrawerClosed(drawerView: View) { binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt()) + emulationViewModel.setDrawerOpen(false) } override fun onDrawerStateChanged(newState: Int) { @@ -239,6 +243,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { requireContext().theme ) } + binding.inGameMenu.requestFocus() true } @@ -247,6 +252,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { null, Settings.MenuTag.SECTION_ROOT ) + binding.inGameMenu.requestFocus() binding.root.findNavController().navigate(action) true } @@ -256,6 +262,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { args.game, Settings.MenuTag.SECTION_ROOT ) + binding.inGameMenu.requestFocus() binding.root.findNavController().navigate(action) true } @@ -287,6 +294,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { ) } } + binding.inGameMenu.requestFocus() NativeConfig.saveGlobalConfig() true } @@ -295,7 +303,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { emulationState.stop() emulationViewModel.setIsEmulationStopping(true) binding.drawerLayout.close() - binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) + binding.inGameMenu.requestFocus() true } @@ -312,12 +320,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { if (!NativeLibrary.isRunning()) { return } - - if (binding.drawerLayout.isOpen) { - binding.drawerLayout.close() - } else { - binding.drawerLayout.open() - } + emulationViewModel.setDrawerOpen(!binding.drawerLayout.isOpen) } } ) @@ -408,6 +411,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } } } + launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + emulationViewModel.drawerOpen.collect { + if (it) { + binding.drawerLayout.open() + binding.inGameMenu.requestFocus() + } else { + binding.drawerLayout.close() + } + } + } + } } } 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 import androidx.lifecycle.ViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow class EmulationViewModel : ViewModel() { val emulationStarted: StateFlow<Boolean> get() = _emulationStarted @@ -23,6 +24,9 @@ class EmulationViewModel : ViewModel() { val shaderMessage: StateFlow<String> get() = _shaderMessage private val _shaderMessage = MutableStateFlow("") + private val _drawerOpen = MutableStateFlow(false) + val drawerOpen = _drawerOpen.asStateFlow() + fun setEmulationStarted(started: Boolean) { _emulationStarted.value = started } @@ -49,6 +53,10 @@ class EmulationViewModel : ViewModel() { setTotalShaders(max) } + fun setDrawerOpen(value: Boolean) { + _drawerOpen.value = value + } + fun clear() { setEmulationStarted(false) 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 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <core/core.h> -#include <core/file_sys/mode.h> -#include <core/file_sys/patch_manager.h> -#include <core/loader/nro.h> -#include <jni.h> +#include "core/core.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/patch_manager.h" #include "core/loader/loader.h" +#include "core/loader/nro.h" +#include "jni.h" #include "jni/android_common/android_common.h" #include "native.h" @@ -79,7 +79,7 @@ extern "C" { jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj, jstring jpath) { const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( - GetJString(env, jpath), FileSys::Mode::Read); + GetJString(env, jpath), FileSys::OpenMode::Read); if (!file) { return false; } 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 @@ #include "core/crypto/key_manager.h" #include "core/file_sys/card_image.h" #include "core/file_sys/content_archive.h" +#include "core/file_sys/fs_filesystem.h" #include "core/file_sys/submission_package.h" -#include "core/file_sys/vfs.h" -#include "core/file_sys/vfs_real.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_real.h" #include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/error.h" @@ -154,7 +155,7 @@ void EmulationSession::SurfaceChanged() { } void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) { - const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read); + const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::OpenMode::Read); if (!file) { return; } @@ -475,8 +476,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en u64 program_id = EmulationSession::GetProgramId(env, jprogramId); std::string updatePath = GetJString(env, jupdatePath); std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>( - EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(updatePath, - FileSys::Mode::Read)); + EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( + updatePath, FileSys::OpenMode::Read)); for (const auto& item : nsp->GetNCAs()) { for (const auto& nca_details : item.second) { if (nca_details.second->GetName().ends_with(".cnmt.nca")) { @@ -719,7 +720,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv* jobject instance) { const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory( - Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); + Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); const auto user_id = EmulationSession::GetInstance().System().GetProfileManager().GetUser( static_cast<std::size_t>(0)); @@ -889,7 +890,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j const auto nandDir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); auto vfsNandDir = system.GetFilesystem()->OpenDirectory(Common::FS::PathToUTF8String(nandDir), - FileSys::Mode::Read); + FileSys::OpenMode::Read); const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( {}, 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 @@ android:id="@+id/appbar_about" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fitsSystemWindows="true"> + android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_about" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:navigationIcon="@drawable/ic_back" app:title="@string/about" /> @@ -28,6 +30,7 @@ android:layout_height="match_parent" android:fadeScrollbars="false" android:scrollbars="vertical" + android:defaultFocusHighlightEnabled="false" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <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 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/coordinator_about" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/colorSurface"> + + <com.google.android.material.appbar.AppBarLayout + android:id="@+id/appbar_info" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false"> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar_info" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" + app:navigationIcon="@drawable/ic_back" /> + + </com.google.android.material.appbar.AppBarLayout> + + <androidx.core.widget.NestedScrollView + android:id="@+id/scroll_info" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:defaultFocusHighlightEnabled="false" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> + + <LinearLayout + android:id="@+id/content_info" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingHorizontal="16dp" + android:baselineAligned="false"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:layout_weight="3" + android:gravity="top|center_horizontal" + android:paddingHorizontal="16dp"> + + <com.google.android.material.button.MaterialButton + android:id="@+id/button_copy" + style="@style/Widget.Material3.Button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:text="@string/copy_details" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/button_verify_integrity" + style="@style/Widget.Material3.Button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="@string/verify_integrity" /> + + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:layout_weight="1"> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/path" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="16dp"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/path_field" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:editable="false" + android:importantForAutofill="no" + android:inputType="none" + android:minHeight="48dp" + android:textAlignment="viewStart" + tools:text="1.0.0" /> + + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/program_id" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="16dp"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/program_id_field" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:editable="false" + android:importantForAutofill="no" + android:inputType="none" + android:minHeight="48dp" + android:textAlignment="viewStart" + tools:text="1.0.0" /> + + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/developer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="16dp"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/developer_field" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:editable="false" + android:importantForAutofill="no" + android:inputType="none" + android:minHeight="48dp" + android:textAlignment="viewStart" + tools:text="1.0.0" /> + + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/version" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="16dp"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/version_field" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:editable="false" + android:importantForAutofill="no" + android:inputType="none" + android:minHeight="48dp" + android:textAlignment="viewStart" + tools:text="1.0.0" /> + + </com.google.android.material.textfield.TextInputLayout> + + </LinearLayout> + + </LinearLayout> + + </androidx.core.widget.NestedScrollView> + +</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 @@ android:clipToPadding="false" android:fadeScrollbars="false" android:scrollbars="vertical" + android:defaultFocusHighlightEnabled="false" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/icon_layout" 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 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" + android:focusable="false" android:clickable="false" android:checked="false" /> 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 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="16dp" - android:layout_marginVertical="12dp" - android:focusable="true"> + android:layout_marginVertical="12dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="16dp" - android:layout_gravity="center_vertical" - android:animateLayoutChanges="true"> + android:layout_gravity="center_vertical"> <com.google.android.material.textview.MaterialTextView 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 @@ android:id="@+id/appbar_about" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fitsSystemWindows="true"> + android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_about" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:title="@string/about" app:navigationIcon="@drawable/ic_back" /> @@ -28,6 +30,7 @@ android:layout_height="match_parent" android:scrollbars="vertical" android:fadeScrollbars="false" + android:defaultFocusHighlightEnabled="false" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <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 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> @@ -19,6 +20,7 @@ android:id="@+id/toolbar_addons" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:navigationIcon="@drawable/ic_back" /> </com.google.android.material.appbar.AppBarLayout> @@ -28,6 +30,8 @@ android:layout_width="match_parent" android:layout_height="0dp" android:clipToPadding="false" + android:defaultFocusHighlightEnabled="false" + android:nextFocusDown="@id/button_install" app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_constraintBottom_toBottomOf="parent" 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 @@ android:id="@+id/appbar_applets" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fitsSystemWindows="true"> + android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_applets" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:navigationIcon="@drawable/ic_back" app:title="@string/applets" /> 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 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false" app:liftOnScrollTargetViewId="@id/list_drivers"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_drivers" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:navigationIcon="@drawable/ic_back" app:title="@string/gpu_driver_manager" /> 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 @@ android:id="@+id/appbar_ea" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fitsSystemWindows="true"> + android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_about" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:navigationIcon="@drawable/ic_back" app:title="@string/early_access" /> @@ -30,6 +32,7 @@ android:paddingBottom="20dp" android:scrollbars="vertical" android:fadeScrollbars="false" + android:defaultFocusHighlightEnabled="false" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <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 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:keepScreenOn="true" + android:defaultFocusHighlightEnabled="false" tools:context="org.yuzu.yuzu_emu.fragments.EmulationFragment" tools:openDrawer="start"> @@ -24,7 +25,8 @@ android:layout_height="match_parent" android:layout_gravity="center" android:focusable="false" - android:focusableInTouchMode="false" /> + android:focusableInTouchMode="false" + android:defaultFocusHighlightEnabled="false" /> <com.google.android.material.card.MaterialCardView android:id="@+id/loading_indicator" @@ -32,7 +34,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:focusable="false" + android:defaultFocusHighlightEnabled="false" android:clickable="false"> <androidx.constraintlayout.widget.ConstraintLayout @@ -118,6 +120,7 @@ android:layout_gravity="center" android:focusable="true" android:focusableInTouchMode="true" + android:defaultFocusHighlightEnabled="false" android:visibility="invisible" /> <Button @@ -160,6 +163,7 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" + android:focusedByDefault="true" app:headerLayout="@layout/header_in_game" app:menu="@menu/menu_in_game" 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 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false" app:liftOnScrollTargetViewId="@id/list_folders"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_folders" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:navigationIcon="@drawable/ic_back" app:title="@string/game_folders" /> @@ -31,6 +33,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:clipToPadding="false" + android:defaultFocusHighlightEnabled="false" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </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 @@ android:id="@+id/appbar_info" android:layout_width="match_parent" android:layout_height="wrap_content" + android:touchscreenBlocksFocus="false" android:fitsSystemWindows="true"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_info" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:navigationIcon="@drawable/ic_back" /> </com.google.android.material.appbar.AppBarLayout> @@ -25,6 +27,7 @@ android:id="@+id/scroll_info" android:layout_width="match_parent" android:layout_height="wrap_content" + android:defaultFocusHighlightEnabled="false" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <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 @@ android:layout_height="match_parent" android:scrollbars="vertical" android:fadeScrollbars="false" - android:clipToPadding="false"> + android:clipToPadding="false" + android:defaultFocusHighlightEnabled="false"> <LinearLayout android:id="@+id/layout_all" @@ -86,7 +87,7 @@ android:id="@+id/list_properties" android:layout_width="match_parent" android:layout_height="match_parent" - tools:listitem="@layout/card_simple_outlined" /> + android:defaultFocusHighlightEnabled="false" /> </LinearLayout> 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 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" + android:defaultFocusHighlightEnabled="false" tools:listitem="@layout/card_game" /> </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 @@ android:background="?attr/colorSurface" android:scrollbars="vertical" android:fadeScrollbars="false" - android:clipToPadding="false"> + android:clipToPadding="false" + android:defaultFocusHighlightEnabled="false"> <androidx.appcompat.widget.LinearLayoutCompat 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 @@ android:id="@+id/appbar_installables" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fitsSystemWindows="true"> + android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_installables" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:title="@string/manage_yuzu_data" app:navigationIcon="@drawable/ic_back" /> 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 @@ android:id="@+id/appbar_licenses" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fitsSystemWindows="true"> + android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_licenses" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:title="@string/licenses" app:navigationIcon="@drawable/ic_back" /> 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 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false" app:elevation="0dp"> <com.google.android.material.appbar.CollapsingToolbarLayout @@ -24,6 +25,7 @@ android:id="@+id/toolbar_settings" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:touchscreenBlocksFocus="false" app:layout_collapseMode="pin" app:navigationIcon="@drawable/ic_back" /> 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 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/selectableItemBackground" - android:focusable="true" + android:focusable="false" android:paddingHorizontal="20dp" android:paddingVertical="16dp"> 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 @@ android:textAlignment="viewStart" android:textColor="?attr/colorPrimary" android:textStyle="bold" + android:focusable="false" 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 @@ #pragma once +#include <algorithm> #include <type_traits> #include "bit_cast.h" @@ -19,4 +20,21 @@ inline T WrappingAdd(T lhs, T rhs) { return BitCast<T>(lhs_u + rhs_u); } +template <typename T> + requires(std::is_integral_v<T> && std::is_signed_v<T>) +inline bool CanAddWithoutOverflow(T lhs, T rhs) { +#ifdef _MSC_VER + if (lhs >= 0 && rhs >= 0) { + return WrappingAdd(lhs, rhs) >= std::max(lhs, rhs); + } else if (lhs < 0 && rhs < 0) { + return WrappingAdd(lhs, rhs) <= std::min(lhs, rhs); + } else { + return true; + } +#else + T res; + return !__builtin_add_overflow(lhs, rhs, &res); +#endif +} + } // 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 cpu_manager.h crypto/aes_util.cpp crypto/aes_util.h + crypto/ctr_encryption_layer.cpp + crypto/ctr_encryption_layer.h crypto/encryption_layer.cpp crypto/encryption_layer.h crypto/key_manager.cpp crypto/key_manager.h crypto/partition_data_manager.cpp crypto/partition_data_manager.h - crypto/ctr_encryption_layer.cpp - crypto/ctr_encryption_layer.h crypto/xts_encryption_layer.cpp crypto/xts_encryption_layer.h - debugger/debugger_interface.h debugger/debugger.cpp debugger/debugger.h - debugger/gdbstub_arch.cpp - debugger/gdbstub_arch.h + debugger/debugger_interface.h debugger/gdbstub.cpp debugger/gdbstub.h + debugger/gdbstub_arch.cpp + debugger/gdbstub_arch.h device_memory_manager.h device_memory_manager.inc device_memory.cpp device_memory.h + file_sys/bis_factory.cpp + file_sys/bis_factory.h + file_sys/card_image.cpp + file_sys/card_image.h + file_sys/common_funcs.h + file_sys/content_archive.cpp + file_sys/content_archive.h + file_sys/control_metadata.cpp + file_sys/control_metadata.h + file_sys/errors.h + file_sys/fs_directory.h + file_sys/fs_file.h + file_sys/fs_filesystem.h + file_sys/fs_memory_management.h + file_sys/fs_operate_range.h + file_sys/fs_path.h + file_sys/fs_path_utility.h + file_sys/fs_string_util.h + file_sys/fsmitm_romfsbuild.cpp + file_sys/fsmitm_romfsbuild.h file_sys/fssystem/fs_i_storage.h + file_sys/fssystem/fs_types.h file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h file_sys/fssystem/fssystem_aes_ctr_storage.cpp @@ -83,25 +104,10 @@ add_library(core STATIC file_sys/fssystem/fssystem_switch_storage.h file_sys/fssystem/fssystem_utility.cpp file_sys/fssystem/fssystem_utility.h - file_sys/fssystem/fs_types.h - file_sys/bis_factory.cpp - file_sys/bis_factory.h - file_sys/card_image.cpp - file_sys/card_image.h - file_sys/common_funcs.h - file_sys/content_archive.cpp - file_sys/content_archive.h - file_sys/control_metadata.cpp - file_sys/control_metadata.h - file_sys/directory.h - file_sys/errors.h - file_sys/fsmitm_romfsbuild.cpp - file_sys/fsmitm_romfsbuild.h file_sys/ips_layer.cpp file_sys/ips_layer.h file_sys/kernel_executable.cpp file_sys/kernel_executable.h - file_sys/mode.h file_sys/nca_metadata.cpp file_sys/nca_metadata.h file_sys/partition_filesystem.cpp @@ -146,22 +152,22 @@ add_library(core STATIC file_sys/system_archive/system_version.h file_sys/system_archive/time_zone_binary.cpp file_sys/system_archive/time_zone_binary.h - file_sys/vfs.cpp - file_sys/vfs.h - file_sys/vfs_cached.cpp - file_sys/vfs_cached.h - file_sys/vfs_concat.cpp - file_sys/vfs_concat.h - file_sys/vfs_layered.cpp - file_sys/vfs_layered.h - file_sys/vfs_offset.cpp - file_sys/vfs_offset.h - file_sys/vfs_real.cpp - file_sys/vfs_real.h - file_sys/vfs_static.h - file_sys/vfs_types.h - file_sys/vfs_vector.cpp - file_sys/vfs_vector.h + file_sys/vfs/vfs.cpp + file_sys/vfs/vfs.h + file_sys/vfs/vfs_cached.cpp + file_sys/vfs/vfs_cached.h + file_sys/vfs/vfs_concat.cpp + file_sys/vfs/vfs_concat.h + file_sys/vfs/vfs_layered.cpp + file_sys/vfs/vfs_layered.h + file_sys/vfs/vfs_offset.cpp + file_sys/vfs/vfs_offset.h + file_sys/vfs/vfs_real.cpp + file_sys/vfs/vfs_real.h + file_sys/vfs/vfs_static.h + file_sys/vfs/vfs_types.h + file_sys/vfs/vfs_vector.cpp + file_sys/vfs/vfs_vector.h file_sys/xts_archive.cpp file_sys/xts_archive.h frontend/applets/cabinet.cpp @@ -194,7 +200,6 @@ add_library(core STATIC hle/kernel/board/nintendo/nx/secure_monitor.h hle/kernel/code_set.cpp hle/kernel/code_set.h - hle/kernel/svc_results.h hle/kernel/global_scheduler_context.cpp hle/kernel/global_scheduler_context.h hle/kernel/init/init_slab_setup.cpp @@ -204,11 +209,11 @@ add_library(core STATIC hle/kernel/k_address_arbiter.h hle/kernel/k_address_space_info.cpp hle/kernel/k_address_space_info.h + hle/kernel/k_affinity_mask.h hle/kernel/k_auto_object.cpp hle/kernel/k_auto_object.h hle/kernel/k_auto_object_container.cpp hle/kernel/k_auto_object_container.h - hle/kernel/k_affinity_mask.h hle/kernel/k_capabilities.cpp hle/kernel/k_capabilities.h hle/kernel/k_class_token.cpp @@ -232,9 +237,9 @@ add_library(core STATIC hle/kernel/k_event_info.h hle/kernel/k_handle_table.cpp hle/kernel/k_handle_table.h - hle/kernel/k_hardware_timer_base.h hle/kernel/k_hardware_timer.cpp hle/kernel/k_hardware_timer.h + hle/kernel/k_hardware_timer_base.h hle/kernel/k_interrupt_manager.cpp hle/kernel/k_interrupt_manager.h hle/kernel/k_light_client_session.cpp @@ -261,10 +266,10 @@ add_library(core STATIC hle/kernel/k_page_bitmap.h hle/kernel/k_page_buffer.cpp hle/kernel/k_page_buffer.h - hle/kernel/k_page_heap.cpp - hle/kernel/k_page_heap.h hle/kernel/k_page_group.cpp hle/kernel/k_page_group.h + hle/kernel/k_page_heap.cpp + hle/kernel/k_page_heap.h hle/kernel/k_page_table.h hle/kernel/k_page_table_base.cpp hle/kernel/k_page_table_base.h @@ -329,8 +334,6 @@ add_library(core STATIC hle/kernel/slab_helpers.h hle/kernel/svc.cpp hle/kernel/svc.h - hle/kernel/svc_common.h - hle/kernel/svc_types.h hle/kernel/svc/svc_activity.cpp hle/kernel/svc/svc_address_arbiter.cpp hle/kernel/svc/svc_address_translation.cpp @@ -368,6 +371,9 @@ add_library(core STATIC hle/kernel/svc/svc_thread_profiler.cpp hle/kernel/svc/svc_tick.cpp hle/kernel/svc/svc_transfer_memory.cpp + hle/kernel/svc_common.h + hle/kernel/svc_results.h + hle/kernel/svc_types.h hle/result.h hle/service/acc/acc.cpp hle/service/acc/acc.h @@ -486,14 +492,25 @@ add_library(core STATIC hle/service/fatal/fatal_p.h hle/service/fatal/fatal_u.cpp hle/service/fatal/fatal_u.h + hle/service/fgm/fgm.cpp + hle/service/fgm/fgm.h hle/service/filesystem/filesystem.cpp hle/service/filesystem/filesystem.h - hle/service/filesystem/fsp_ldr.cpp - hle/service/filesystem/fsp_ldr.h - hle/service/filesystem/fsp_pr.cpp - hle/service/filesystem/fsp_pr.h - hle/service/filesystem/fsp_srv.cpp - hle/service/filesystem/fsp_srv.h + hle/service/filesystem/fsp/fs_i_directory.cpp + hle/service/filesystem/fsp/fs_i_directory.h + hle/service/filesystem/fsp/fs_i_file.cpp + hle/service/filesystem/fsp/fs_i_file.h + hle/service/filesystem/fsp/fs_i_filesystem.cpp + hle/service/filesystem/fsp/fs_i_filesystem.h + hle/service/filesystem/fsp/fs_i_storage.cpp + hle/service/filesystem/fsp/fs_i_storage.h + hle/service/filesystem/fsp/fsp_ldr.cpp + hle/service/filesystem/fsp/fsp_ldr.h + hle/service/filesystem/fsp/fsp_pr.cpp + hle/service/filesystem/fsp/fsp_pr.h + hle/service/filesystem/fsp/fsp_srv.cpp + hle/service/filesystem/fsp/fsp_srv.h + hle/service/filesystem/fsp/fsp_util.h hle/service/filesystem/romfs_controller.cpp hle/service/filesystem/romfs_controller.h hle/service/filesystem/save_data_controller.cpp @@ -551,13 +568,18 @@ add_library(core STATIC hle/service/hid/irs.h hle/service/hid/xcd.cpp hle/service/hid/xcd.h + hle/service/hle_ipc.cpp + hle/service/hle_ipc.h + hle/service/ipc_helpers.h + hle/service/kernel_helpers.cpp + hle/service/kernel_helpers.h hle/service/lbl/lbl.cpp hle/service/lbl/lbl.h hle/service/ldn/lan_discovery.cpp hle/service/ldn/lan_discovery.h - hle/service/ldn/ldn_results.h hle/service/ldn/ldn.cpp hle/service/ldn/ldn.h + hle/service/ldn/ldn_results.h hle/service/ldn/ldn_types.h hle/service/ldr/ldr.cpp hle/service/ldr/ldr.h @@ -565,16 +587,6 @@ add_library(core STATIC hle/service/lm/lm.h hle/service/mig/mig.cpp hle/service/mig/mig.h - hle/service/mii/types/char_info.cpp - hle/service/mii/types/char_info.h - hle/service/mii/types/core_data.cpp - hle/service/mii/types/core_data.h - hle/service/mii/types/raw_data.cpp - hle/service/mii/types/raw_data.h - hle/service/mii/types/store_data.cpp - hle/service/mii/types/store_data.h - hle/service/mii/types/ver3_store_data.cpp - hle/service/mii/types/ver3_store_data.h hle/service/mii/mii.cpp hle/service/mii/mii.h hle/service/mii/mii_database.cpp @@ -586,10 +598,22 @@ add_library(core STATIC hle/service/mii/mii_result.h hle/service/mii/mii_types.h hle/service/mii/mii_util.h + hle/service/mii/types/char_info.cpp + hle/service/mii/types/char_info.h + hle/service/mii/types/core_data.cpp + hle/service/mii/types/core_data.h + hle/service/mii/types/raw_data.cpp + hle/service/mii/types/raw_data.h + hle/service/mii/types/store_data.cpp + hle/service/mii/types/store_data.h + hle/service/mii/types/ver3_store_data.cpp + hle/service/mii/types/ver3_store_data.h hle/service/mm/mm_u.cpp hle/service/mm/mm_u.h hle/service/mnpp/mnpp_app.cpp hle/service/mnpp/mnpp_app.h + hle/service/mutex.cpp + hle/service/mutex.h hle/service/ncm/ncm.cpp hle/service/ncm/ncm.h hle/service/nfc/common/amiibo_crypto.cpp @@ -759,19 +783,12 @@ add_library(core STATIC hle/service/ptm/ptm.h hle/service/ptm/ts.cpp hle/service/ptm/ts.h - hle/service/hle_ipc.cpp - hle/service/hle_ipc.h - hle/service/ipc_helpers.h - hle/service/kernel_helpers.cpp - hle/service/kernel_helpers.h - hle/service/mutex.cpp - hle/service/mutex.h + hle/service/ro/ro.cpp + hle/service/ro/ro.h hle/service/ro/ro_nro_utils.cpp hle/service/ro/ro_nro_utils.h hle/service/ro/ro_results.h hle/service/ro/ro_types.h - hle/service/ro/ro.cpp - hle/service/ro/ro.h hle/service/server_manager.cpp hle/service/server_manager.h hle/service/service.cpp @@ -838,9 +855,9 @@ add_library(core STATIC internal_network/network.h internal_network/network_interface.cpp internal_network/network_interface.h - internal_network/sockets.h internal_network/socket_proxy.cpp internal_network/socket_proxy.h + internal_network/sockets.h loader/deconstructed_rom_directory.cpp loader/deconstructed_rom_directory.h loader/kip.cpp @@ -859,13 +876,13 @@ add_library(core STATIC loader/nsp.h loader/xci.cpp loader/xci.h + memory.cpp + memory.h memory/cheat_engine.cpp memory/cheat_engine.h memory/dmnt_cheat_types.h memory/dmnt_cheat_vm.cpp memory/dmnt_cheat_vm.h - memory.cpp - memory.h perf_stats.cpp perf_stats.h 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 @@ #include "core/debugger/debugger.h" #include "core/device_memory.h" #include "core/file_sys/bis_factory.h" -#include "core/file_sys/mode.h" +#include "core/file_sys/fs_filesystem.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" -#include "core/file_sys/vfs_concat.h" -#include "core/file_sys/vfs_real.h" +#include "core/file_sys/vfs/vfs_concat.h" +#include "core/file_sys/vfs/vfs_real.h" #include "core/gpu_dirty_memory_manager.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_process.h" @@ -102,7 +102,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, Common::SplitPath(path, &dir_name, &filename, nullptr); if (filename == "00") { - const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read); + const auto dir = vfs->OpenDirectory(dir_name, FileSys::OpenMode::Read); std::vector<FileSys::VirtualFile> concat; for (u32 i = 0; i < 0x10; ++i) { @@ -127,10 +127,10 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, } if (Common::FS::IsDir(path)) { - return vfs->OpenFile(path + "/main", FileSys::Mode::Read); + return vfs->OpenFile(path + "/main", FileSys::OpenMode::Read); } - return vfs->OpenFile(path, FileSys::Mode::Read); + return vfs->OpenFile(path, FileSys::OpenMode::Read); } struct 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 @@ #include <vector> #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace Core::Frontend { class 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 @@ #include <span> #include <type_traits> #include "common/common_types.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace Core::Crypto { 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 @@ #pragma once #include "common/common_types.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace Core::Crypto { 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 @@ #include "core/crypto/partition_data_manager.h" #include "core/crypto/xts_encryption_layer.h" #include "core/file_sys/kernel_executable.h" -#include "core/file_sys/vfs.h" -#include "core/file_sys/vfs_offset.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_offset.h" +#include "core/file_sys/vfs/vfs_vector.h" #include "core/loader/loader.h" using 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 @@ #include <vector> #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace Core::Crypto { 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 @@ #include <fmt/format.h> #include "common/fs/path_util.h" #include "core/file_sys/bis_factory.h" -#include "core/file_sys/mode.h" #include "core/file_sys/registered_cache.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { @@ -84,7 +83,7 @@ VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id, VirtualFilesystem file_system) const { auto& keys = Core::Crypto::KeyManager::Instance(); Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory( - Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir), Mode::Read)}; + Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir), OpenMode::Read)}; keys.PopulateFromPartitionData(pdm); 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 @@ #include <memory> #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys { 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 @@ #include "core/file_sys/nca_metadata.h" #include "core/file_sys/partition_filesystem.h" #include "core/file_sys/submission_package.h" -#include "core/file_sys/vfs_offset.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_offset.h" +#include "core/file_sys/vfs/vfs_vector.h" #include "core/loader/loader.h" namespace 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 @@ #include <vector> #include "common/common_types.h" #include "common/swap.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace Core::Crypto { class 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 @@ #include "core/crypto/key_manager.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/partition_filesystem.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs_offset.h" #include "core/loader/loader.h" #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 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/crypto/key_manager.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace Loader { enum 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 @@ #include "common/string_util.h" #include "common/swap.h" #include "core/file_sys/control_metadata.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys { 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 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <cstddef> -#include "common/common_funcs.h" -#include "common/common_types.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -enum class EntryType : u8 { - Directory = 0, - File = 1, -}; - -// Structure of a directory entry, from -// http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry -struct Entry { - Entry(std::string_view view, EntryType entry_type, u64 entry_size) - : type{entry_type}, file_size{entry_size} { - const std::size_t copy_size = view.copy(filename, std::size(filename) - 1); - filename[copy_size] = '\0'; - } - - char filename[0x301]; - INSERT_PADDING_BYTES(3); - EntryType type; - INSERT_PADDING_BYTES(3); - u64 file_size; -}; -static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x310 bytes long!"); -static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry."); -static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry."); - -} // 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 @@ namespace FileSys { -constexpr Result ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1}; -constexpr Result ERROR_PATH_ALREADY_EXISTS{ErrorModule::FS, 2}; -constexpr Result ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002}; -constexpr Result ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001}; -constexpr Result ERROR_OUT_OF_BOUNDS{ErrorModule::FS, 3005}; -constexpr Result ERROR_FAILED_MOUNT_ARCHIVE{ErrorModule::FS, 3223}; -constexpr Result ERROR_INVALID_ARGUMENT{ErrorModule::FS, 6001}; -constexpr Result ERROR_INVALID_OFFSET{ErrorModule::FS, 6061}; -constexpr Result ERROR_INVALID_SIZE{ErrorModule::FS, 6062}; - +constexpr Result ResultPathNotFound{ErrorModule::FS, 1}; +constexpr Result ResultPathAlreadyExists{ErrorModule::FS, 2}; constexpr Result ResultUnsupportedSdkVersion{ErrorModule::FS, 50}; constexpr Result ResultPartitionNotFound{ErrorModule::FS, 1001}; +constexpr Result ResultTargetNotFound{ErrorModule::FS, 1002}; +constexpr Result ResultPortSdCardNoDevice{ErrorModule::FS, 2001}; +constexpr Result ResultNotImplemented{ErrorModule::FS, 3001}; constexpr Result ResultUnsupportedVersion{ErrorModule::FS, 3002}; constexpr Result ResultOutOfRange{ErrorModule::FS, 3005}; constexpr Result ResultAllocationMemoryFailedInFileSystemBuddyHeapA{ErrorModule::FS, 3294}; @@ -78,10 +73,21 @@ constexpr Result ResultUnexpectedInCompressedStorageA{ErrorModule::FS, 5324}; constexpr Result ResultUnexpectedInCompressedStorageB{ErrorModule::FS, 5325}; constexpr Result ResultUnexpectedInCompressedStorageC{ErrorModule::FS, 5326}; constexpr Result ResultUnexpectedInCompressedStorageD{ErrorModule::FS, 5327}; +constexpr Result ResultUnexpectedInPathA{ErrorModule::FS, 5328}; constexpr Result ResultInvalidArgument{ErrorModule::FS, 6001}; +constexpr Result ResultInvalidPath{ErrorModule::FS, 6002}; +constexpr Result ResultTooLongPath{ErrorModule::FS, 6003}; +constexpr Result ResultInvalidCharacter{ErrorModule::FS, 6004}; +constexpr Result ResultInvalidPathFormat{ErrorModule::FS, 6005}; +constexpr Result ResultDirectoryUnobtainable{ErrorModule::FS, 6006}; +constexpr Result ResultNotNormalized{ErrorModule::FS, 6007}; constexpr Result ResultInvalidOffset{ErrorModule::FS, 6061}; constexpr Result ResultInvalidSize{ErrorModule::FS, 6062}; constexpr Result ResultNullptrArgument{ErrorModule::FS, 6063}; +constexpr Result ResultInvalidOpenMode{ErrorModule::FS, 6072}; +constexpr Result ResultFileExtensionWithoutOpenModeAllowAppend{ErrorModule::FS, 6201}; +constexpr Result ResultReadNotPermitted{ErrorModule::FS, 6202}; +constexpr Result ResultWriteNotPermitted{ErrorModule::FS, 6203}; constexpr Result ResultUnsupportedSetSizeForIndirectStorage{ErrorModule::FS, 6325}; constexpr Result ResultUnsupportedWriteForCompressedStorage{ErrorModule::FS, 6387}; constexpr 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace FileSys { + +constexpr inline size_t EntryNameLengthMax = 0x300; + +struct DirectoryEntry { + DirectoryEntry(std::string_view view, s8 entry_type, u64 entry_size) + : type{entry_type}, file_size{static_cast<s64>(entry_size)} { + const std::size_t copy_size = view.copy(name, std::size(name) - 1); + name[copy_size] = '\0'; + } + + char name[EntryNameLengthMax + 1]; + INSERT_PADDING_BYTES(3); + s8 type; + INSERT_PADDING_BYTES(3); + s64 file_size; +}; + +static_assert(sizeof(DirectoryEntry) == 0x310, + "Directory Entry struct isn't exactly 0x310 bytes long!"); +static_assert(offsetof(DirectoryEntry, type) == 0x304, "Wrong offset for type in Entry."); +static_assert(offsetof(DirectoryEntry, file_size) == 0x308, "Wrong offset for file_size in Entry."); + +struct DirectoryHandle { + void* handle; +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" + +namespace FileSys { + +struct ReadOption { + u32 value; + + static const ReadOption None; +}; + +enum ReadOptionFlag : u32 { + ReadOptionFlag_None = (0 << 0), +}; + +inline constexpr const ReadOption ReadOption::None = {ReadOptionFlag_None}; + +inline constexpr bool operator==(const ReadOption& lhs, const ReadOption& rhs) { + return lhs.value == rhs.value; +} + +inline constexpr bool operator!=(const ReadOption& lhs, const ReadOption& rhs) { + return !(lhs == rhs); +} + +static_assert(sizeof(ReadOption) == sizeof(u32)); + +enum WriteOptionFlag : u32 { + WriteOptionFlag_None = (0 << 0), + WriteOptionFlag_Flush = (1 << 0), +}; + +struct WriteOption { + u32 value; + + constexpr inline bool HasFlushFlag() const { + return value & WriteOptionFlag_Flush; + } + + static const WriteOption None; + static const WriteOption Flush; +}; + +inline constexpr const WriteOption WriteOption::None = {WriteOptionFlag_None}; +inline constexpr const WriteOption WriteOption::Flush = {WriteOptionFlag_Flush}; + +inline constexpr bool operator==(const WriteOption& lhs, const WriteOption& rhs) { + return lhs.value == rhs.value; +} + +inline constexpr bool operator!=(const WriteOption& lhs, const WriteOption& rhs) { + return !(lhs == rhs); +} + +static_assert(sizeof(WriteOption) == sizeof(u32)); + +struct FileHandle { + void* handle; +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace FileSys { + +enum class OpenMode : u32 { + Read = (1 << 0), + Write = (1 << 1), + AllowAppend = (1 << 2), + + ReadWrite = (Read | Write), + All = (ReadWrite | AllowAppend), +}; +DECLARE_ENUM_FLAG_OPERATORS(OpenMode) + +enum class OpenDirectoryMode : u64 { + Directory = (1 << 0), + File = (1 << 1), + + All = (Directory | File), +}; +DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode) + +enum class DirectoryEntryType : u8 { + Directory = 0, + File = 1, +}; + +enum class CreateOption : u8 { + None = (0 << 0), + BigFile = (1 << 0), +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <mutex> +#include "common/alignment.h" + +namespace FileSys { + +constexpr size_t RequiredAlignment = alignof(u64); + +void* AllocateUnsafe(size_t size) { + // Allocate + void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment}); + + // Check alignment + ASSERT(Common::IsAligned(reinterpret_cast<uintptr_t>(ptr), RequiredAlignment)); + + // Return allocated pointer + return ptr; +} + +void DeallocateUnsafe(void* ptr, size_t size) { + // Deallocate the pointer + ::operator delete(ptr, std::align_val_t{RequiredAlignment}); +} + +void* Allocate(size_t size) { + return AllocateUnsafe(size); +} + +void Deallocate(void* ptr, size_t size) { + // If the pointer is non-null, deallocate it + if (ptr != nullptr) { + DeallocateUnsafe(ptr, size); + } +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" + +namespace FileSys { + +enum class OperationId : s64 { + FillZero = 0, + DestroySignature = 1, + Invalidate = 2, + QueryRange = 3, + QueryUnpreparedRange = 4, + QueryLazyLoadCompletionRate = 5, + SetLazyLoadPriority = 6, + + ReadLazyLoadFileForciblyForDebug = 10001, +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/alignment.h" +#include "common/common_funcs.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/fs_memory_management.h" +#include "core/file_sys/fs_path_utility.h" +#include "core/file_sys/fs_string_util.h" +#include "core/hle/result.h" + +namespace FileSys { +class DirectoryPathParser; + +class Path { + YUZU_NON_COPYABLE(Path); + YUZU_NON_MOVEABLE(Path); + +private: + static constexpr const char* EmptyPath = ""; + static constexpr size_t WriteBufferAlignmentLength = 8; + +private: + friend class DirectoryPathParser; + +public: + class WriteBuffer { + YUZU_NON_COPYABLE(WriteBuffer); + + private: + char* m_buffer; + size_t m_length_and_is_normalized; + + public: + constexpr WriteBuffer() : m_buffer(nullptr), m_length_and_is_normalized(0) {} + + constexpr ~WriteBuffer() { + if (m_buffer != nullptr) { + Deallocate(m_buffer, this->GetLength()); + this->ResetBuffer(); + } + } + + constexpr WriteBuffer(WriteBuffer&& rhs) + : m_buffer(rhs.m_buffer), m_length_and_is_normalized(rhs.m_length_and_is_normalized) { + rhs.ResetBuffer(); + } + + constexpr WriteBuffer& operator=(WriteBuffer&& rhs) { + if (m_buffer != nullptr) { + Deallocate(m_buffer, this->GetLength()); + } + + m_buffer = rhs.m_buffer; + m_length_and_is_normalized = rhs.m_length_and_is_normalized; + + rhs.ResetBuffer(); + + return *this; + } + + constexpr void ResetBuffer() { + m_buffer = nullptr; + this->SetLength(0); + } + + constexpr char* Get() const { + return m_buffer; + } + + constexpr size_t GetLength() const { + return m_length_and_is_normalized >> 1; + } + + constexpr bool IsNormalized() const { + return static_cast<bool>(m_length_and_is_normalized & 1); + } + + constexpr void SetNormalized() { + m_length_and_is_normalized |= static_cast<size_t>(1); + } + + constexpr void SetNotNormalized() { + m_length_and_is_normalized &= ~static_cast<size_t>(1); + } + + private: + constexpr WriteBuffer(char* buffer, size_t length) + : m_buffer(buffer), m_length_and_is_normalized(0) { + this->SetLength(length); + } + + public: + static WriteBuffer Make(size_t length) { + if (void* alloc = Allocate(length); alloc != nullptr) { + return WriteBuffer(static_cast<char*>(alloc), length); + } else { + return WriteBuffer(); + } + } + + private: + constexpr void SetLength(size_t size) { + m_length_and_is_normalized = (m_length_and_is_normalized & 1) | (size << 1); + } + }; + +private: + const char* m_str; + WriteBuffer m_write_buffer; + +public: + constexpr Path() : m_str(EmptyPath), m_write_buffer() {} + + constexpr Path(const char* s) : m_str(s), m_write_buffer() { + m_write_buffer.SetNormalized(); + } + + constexpr ~Path() = default; + + constexpr Result SetShallowBuffer(const char* buffer) { + // Check pre-conditions + ASSERT(m_write_buffer.GetLength() == 0); + + // Check the buffer is valid + R_UNLESS(buffer != nullptr, ResultNullptrArgument); + + // Set buffer + this->SetReadOnlyBuffer(buffer); + + // Note that we're normalized + this->SetNormalized(); + + R_SUCCEED(); + } + + constexpr const char* GetString() const { + // Check pre-conditions + ASSERT(this->IsNormalized()); + + return m_str; + } + + constexpr size_t GetLength() const { + if (std::is_constant_evaluated()) { + return Strlen(this->GetString()); + } else { + return std::strlen(this->GetString()); + } + } + + constexpr bool IsEmpty() const { + return *m_str == '\x00'; + } + + constexpr bool IsMatchHead(const char* p, size_t len) const { + return Strncmp(this->GetString(), p, len) == 0; + } + + Result Initialize(const Path& rhs) { + // Check the other path is normalized + const bool normalized = rhs.IsNormalized(); + R_UNLESS(normalized, ResultNotNormalized); + + // Allocate buffer for our path + const auto len = rhs.GetLength(); + R_TRY(this->Preallocate(len + 1)); + + // Copy the path + const size_t copied = Strlcpy<char>(m_write_buffer.Get(), rhs.GetString(), len + 1); + R_UNLESS(copied == len, ResultUnexpectedInPathA); + + // Set normalized + this->SetNormalized(); + R_SUCCEED(); + } + + Result Initialize(const char* path, size_t len) { + // Check the path is valid + R_UNLESS(path != nullptr, ResultNullptrArgument); + + // Initialize + R_TRY(this->InitializeImpl(path, len)); + + // Set not normalized + this->SetNotNormalized(); + + R_SUCCEED(); + } + + Result Initialize(const char* path) { + // Check the path is valid + R_UNLESS(path != nullptr, ResultNullptrArgument); + + R_RETURN(this->Initialize(path, std::strlen(path))); + } + + Result InitializeWithReplaceBackslash(const char* path) { + // Check the path is valid + R_UNLESS(path != nullptr, ResultNullptrArgument); + + // Initialize + R_TRY(this->InitializeImpl(path, std::strlen(path))); + + // Replace slashes as desired + if (const auto write_buffer_length = m_write_buffer.GetLength(); write_buffer_length > 1) { + Replace(m_write_buffer.Get(), write_buffer_length - 1, '\\', '/'); + } + + // Set not normalized + this->SetNotNormalized(); + + R_SUCCEED(); + } + + Result InitializeWithReplaceForwardSlashes(const char* path) { + // Check the path is valid + R_UNLESS(path != nullptr, ResultNullptrArgument); + + // Initialize + R_TRY(this->InitializeImpl(path, std::strlen(path))); + + // Replace slashes as desired + if (m_write_buffer.GetLength() > 1) { + if (auto* p = m_write_buffer.Get(); p[0] == '/' && p[1] == '/') { + p[0] = '\\'; + p[1] = '\\'; + } + } + + // Set not normalized + this->SetNotNormalized(); + + R_SUCCEED(); + } + + Result InitializeWithNormalization(const char* path, size_t size) { + // Check the path is valid + R_UNLESS(path != nullptr, ResultNullptrArgument); + + // Initialize + R_TRY(this->InitializeImpl(path, size)); + + // Set not normalized + this->SetNotNormalized(); + + // Perform normalization + PathFlags path_flags; + if (IsPathRelative(m_str)) { + path_flags.AllowRelativePath(); + } else if (IsWindowsPath(m_str, true)) { + path_flags.AllowWindowsPath(); + } else { + /* NOTE: In this case, Nintendo checks is normalized, then sets is normalized, then + * returns success. */ + /* This seems like a bug. */ + size_t dummy; + bool normalized; + R_TRY(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(dummy), + m_str)); + + this->SetNormalized(); + R_SUCCEED(); + } + + // Normalize + R_TRY(this->Normalize(path_flags)); + + this->SetNormalized(); + R_SUCCEED(); + } + + Result InitializeWithNormalization(const char* path) { + // Check the path is valid + R_UNLESS(path != nullptr, ResultNullptrArgument); + + R_RETURN(this->InitializeWithNormalization(path, std::strlen(path))); + } + + Result InitializeAsEmpty() { + // Clear our buffer + this->ClearBuffer(); + + // Set normalized + this->SetNormalized(); + + R_SUCCEED(); + } + + Result AppendChild(const char* child) { + // Check the path is valid + R_UNLESS(child != nullptr, ResultNullptrArgument); + + // Basic checks. If we have a path and the child is empty, we have nothing to do + const char* c = child; + if (m_str[0]) { + // Skip an early separator + if (*c == '/') { + ++c; + } + + R_SUCCEED_IF(*c == '\x00'); + } + + // If we don't have a string, we can just initialize + auto cur_len = std::strlen(m_str); + if (cur_len == 0) { + R_RETURN(this->Initialize(child)); + } + + // Remove a trailing separator + if (m_str[cur_len - 1] == '/' || m_str[cur_len - 1] == '\\') { + --cur_len; + } + + // Get the child path's length + auto child_len = std::strlen(c); + + // Reset our write buffer + WriteBuffer old_write_buffer; + if (m_write_buffer.Get() != nullptr) { + old_write_buffer = std::move(m_write_buffer); + this->ClearBuffer(); + } + + // Pre-allocate the new buffer + R_TRY(this->Preallocate(cur_len + 1 + child_len + 1)); + + // Get our write buffer + auto* dst = m_write_buffer.Get(); + if (old_write_buffer.Get() != nullptr && cur_len > 0) { + Strlcpy<char>(dst, old_write_buffer.Get(), cur_len + 1); + } + + // Add separator + dst[cur_len] = '/'; + + // Copy the child path + const size_t copied = Strlcpy<char>(dst + cur_len + 1, c, child_len + 1); + R_UNLESS(copied == child_len, ResultUnexpectedInPathA); + + R_SUCCEED(); + } + + Result AppendChild(const Path& rhs) { + R_RETURN(this->AppendChild(rhs.GetString())); + } + + Result Combine(const Path& parent, const Path& child) { + // Get the lengths + const auto p_len = parent.GetLength(); + const auto c_len = child.GetLength(); + + // Allocate our buffer + R_TRY(this->Preallocate(p_len + c_len + 1)); + + // Initialize as parent + R_TRY(this->Initialize(parent)); + + // If we're empty, we can just initialize as child + if (this->IsEmpty()) { + R_TRY(this->Initialize(child)); + } else { + // Otherwise, we should append the child + R_TRY(this->AppendChild(child)); + } + + R_SUCCEED(); + } + + Result RemoveChild() { + // If we don't have a write-buffer, ensure that we have one + if (m_write_buffer.Get() == nullptr) { + if (const auto len = std::strlen(m_str); len > 0) { + R_TRY(this->Preallocate(len)); + Strlcpy<char>(m_write_buffer.Get(), m_str, len + 1); + } + } + + // Check that it's possible for us to remove a child + auto* p = m_write_buffer.Get(); + s32 len = std::strlen(p); + R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented); + + // Handle a trailing separator + if (len > 0 && (p[len - 1] == '\\' || p[len - 1] == '/')) { + --len; + } + + // Remove the child path segment + while ((--len) >= 0 && p[len]) { + if (p[len] == '/' || p[len] == '\\') { + if (len > 0) { + p[len] = 0; + } else { + p[1] = 0; + len = 1; + } + break; + } + } + + // Check that length remains > 0 + R_UNLESS(len > 0, ResultNotImplemented); + + R_SUCCEED(); + } + + Result Normalize(const PathFlags& flags) { + // If we're already normalized, nothing to do + R_SUCCEED_IF(this->IsNormalized()); + + // Check if we're normalized + bool normalized; + size_t dummy; + R_TRY(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(dummy), m_str, + flags)); + + // If we're not normalized, normalize + if (!normalized) { + // Determine necessary buffer length + auto len = m_write_buffer.GetLength(); + if (flags.IsRelativePathAllowed() && IsPathRelative(m_str)) { + len += 2; + } + if (flags.IsWindowsPathAllowed() && IsWindowsPath(m_str, true)) { + len += 1; + } + + // Allocate a new buffer + const size_t size = Common::AlignUp(len, WriteBufferAlignmentLength); + auto buf = WriteBuffer::Make(size); + R_UNLESS(buf.Get() != nullptr, ResultAllocationMemoryFailedMakeUnique); + + // Normalize into it + R_TRY(PathFormatter::Normalize(buf.Get(), size, m_write_buffer.Get(), + m_write_buffer.GetLength(), flags)); + + // Set the normalized buffer as our buffer + this->SetModifiableBuffer(std::move(buf)); + } + + // Set normalized + this->SetNormalized(); + R_SUCCEED(); + } + +private: + void ClearBuffer() { + m_write_buffer.ResetBuffer(); + m_str = EmptyPath; + } + + void SetModifiableBuffer(WriteBuffer&& buffer) { + // Check pre-conditions + ASSERT(buffer.Get() != nullptr); + ASSERT(buffer.GetLength() > 0); + ASSERT(Common::IsAligned(buffer.GetLength(), WriteBufferAlignmentLength)); + + // Get whether we're normalized + if (m_write_buffer.IsNormalized()) { + buffer.SetNormalized(); + } else { + buffer.SetNotNormalized(); + } + + // Set write buffer + m_write_buffer = std::move(buffer); + m_str = m_write_buffer.Get(); + } + + constexpr void SetReadOnlyBuffer(const char* buffer) { + m_str = buffer; + m_write_buffer.ResetBuffer(); + } + + Result Preallocate(size_t length) { + // Allocate additional space, if needed + if (length > m_write_buffer.GetLength()) { + // Allocate buffer + const size_t size = Common::AlignUp(length, WriteBufferAlignmentLength); + auto buf = WriteBuffer::Make(size); + R_UNLESS(buf.Get() != nullptr, ResultAllocationMemoryFailedMakeUnique); + + // Set write buffer + this->SetModifiableBuffer(std::move(buf)); + } + + R_SUCCEED(); + } + + Result InitializeImpl(const char* path, size_t size) { + if (size > 0 && path[0]) { + // Pre allocate a buffer for the path + R_TRY(this->Preallocate(size + 1)); + + // Copy the path + const size_t copied = Strlcpy<char>(m_write_buffer.Get(), path, size + 1); + R_UNLESS(copied >= size, ResultUnexpectedInPathA); + } else { + // We can just clear the buffer + this->ClearBuffer(); + } + + R_SUCCEED(); + } + + constexpr char* GetWriteBuffer() { + ASSERT(m_write_buffer.Get() != nullptr); + return m_write_buffer.Get(); + } + + constexpr size_t GetWriteBufferLength() const { + return m_write_buffer.GetLength(); + } + + constexpr bool IsNormalized() const { + return m_write_buffer.IsNormalized(); + } + + constexpr void SetNormalized() { + m_write_buffer.SetNormalized(); + } + + constexpr void SetNotNormalized() { + m_write_buffer.SetNotNormalized(); + } + +public: + bool operator==(const FileSys::Path& rhs) const { + return std::strcmp(this->GetString(), rhs.GetString()) == 0; + } + bool operator!=(const FileSys::Path& rhs) const { + return !(*this == rhs); + } + bool operator==(const char* p) const { + return std::strcmp(this->GetString(), p) == 0; + } + bool operator!=(const char* p) const { + return !(*this == p); + } +}; + +inline Result SetUpFixedPath(FileSys::Path* out, const char* s) { + // Verify the path is normalized + bool normalized; + size_t dummy; + R_TRY(PathNormalizer::IsNormalized(std::addressof(normalized), std::addressof(dummy), s)); + + R_UNLESS(normalized, ResultInvalidPathFormat); + + // Set the fixed path + R_RETURN(out->SetShallowBuffer(s)); +} + +constexpr inline bool IsWindowsDriveRootPath(const FileSys::Path& path) { + const char* const str = path.GetString(); + return IsWindowsDrive(str) && + (str[2] == StringTraits::DirectorySeparator || + str[2] == StringTraits::AlternateDirectorySeparator) && + str[3] == StringTraits::NullTerminator; +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/scope_exit.h" +#include "core/file_sys/fs_directory.h" +#include "core/file_sys/fs_memory_management.h" +#include "core/file_sys/fs_string_util.h" +#include "core/hle/result.h" + +namespace FileSys { + +constexpr inline size_t MountNameLengthMax = 15; + +namespace StringTraits { + +constexpr inline char DirectorySeparator = '/'; +constexpr inline char DriveSeparator = ':'; +constexpr inline char Dot = '.'; +constexpr inline char NullTerminator = '\x00'; + +constexpr inline char AlternateDirectorySeparator = '\\'; + +constexpr inline const char InvalidCharacters[6] = {':', '*', '?', '<', '>', '|'}; +constexpr inline const char InvalidCharactersForHostName[6] = {':', '*', '<', '>', '|', '$'}; +constexpr inline const char InvalidCharactersForMountName[5] = {'*', '?', '<', '>', '|'}; + +namespace impl { + +template <const char* InvalidCharacterSet, size_t NumInvalidCharacters> +consteval u64 MakeInvalidCharacterMask(size_t n) { + u64 mask = 0; + for (size_t i = 0; i < NumInvalidCharacters; ++i) { + if ((static_cast<u64>(InvalidCharacterSet[i]) >> 6) == n) { + mask |= static_cast<u64>(1) << (static_cast<u64>(InvalidCharacterSet[i]) & 0x3F); + } + } + return mask; +} + +template <const char* InvalidCharacterSet, size_t NumInvalidCharacters> +constexpr bool IsInvalidCharacterImpl(char c) { + constexpr u64 Masks[4] = { + MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(0), + MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(1), + MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(2), + MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(3)}; + + return (Masks[static_cast<u64>(c) >> 6] & + (static_cast<u64>(1) << (static_cast<u64>(c) & 0x3F))) != 0; +} + +} // namespace impl + +constexpr bool IsInvalidCharacter(char c) { + return impl::IsInvalidCharacterImpl<InvalidCharacters, Common::Size(InvalidCharacters)>(c); +} +constexpr bool IsInvalidCharacterForHostName(char c) { + return impl::IsInvalidCharacterImpl<InvalidCharactersForHostName, + Common::Size(InvalidCharactersForHostName)>(c); +} +constexpr bool IsInvalidCharacterForMountName(char c) { + return impl::IsInvalidCharacterImpl<InvalidCharactersForMountName, + Common::Size(InvalidCharactersForMountName)>(c); +} + +} // namespace StringTraits + +constexpr inline size_t WindowsDriveLength = 2; +constexpr inline size_t UncPathPrefixLength = 2; +constexpr inline size_t DosDevicePathPrefixLength = 4; + +class PathFlags { +private: + static constexpr u32 WindowsPathFlag = (1 << 0); + static constexpr u32 RelativePathFlag = (1 << 1); + static constexpr u32 EmptyPathFlag = (1 << 2); + static constexpr u32 MountNameFlag = (1 << 3); + static constexpr u32 BackslashFlag = (1 << 4); + static constexpr u32 AllCharactersFlag = (1 << 5); + +private: + u32 m_value; + +public: + constexpr PathFlags() : m_value(0) { /* ... */ + } + +#define DECLARE_PATH_FLAG_HANDLER(__WHICH__) \ + constexpr bool Is##__WHICH__##Allowed() const { return (m_value & __WHICH__##Flag) != 0; } \ + constexpr void Allow##__WHICH__() { m_value |= __WHICH__##Flag; } + + DECLARE_PATH_FLAG_HANDLER(WindowsPath) + DECLARE_PATH_FLAG_HANDLER(RelativePath) + DECLARE_PATH_FLAG_HANDLER(EmptyPath) + DECLARE_PATH_FLAG_HANDLER(MountName) + DECLARE_PATH_FLAG_HANDLER(Backslash) + DECLARE_PATH_FLAG_HANDLER(AllCharacters) + +#undef DECLARE_PATH_FLAG_HANDLER +}; + +template <typename T> + requires(std::same_as<T, char> || std::same_as<T, wchar_t>) +constexpr inline bool IsDosDevicePath(const T* path) { + ASSERT(path != nullptr); + + using namespace StringTraits; + + return path[0] == AlternateDirectorySeparator && path[1] == AlternateDirectorySeparator && + (path[2] == Dot || path[2] == '?') && + (path[3] == DirectorySeparator || path[3] == AlternateDirectorySeparator); +} + +template <typename T> + requires(std::same_as<T, char> || std::same_as<T, wchar_t>) +constexpr inline bool IsUncPath(const T* path, bool allow_forward_slash = true, + bool allow_back_slash = true) { + ASSERT(path != nullptr); + + using namespace StringTraits; + + return (allow_forward_slash && path[0] == DirectorySeparator && + path[1] == DirectorySeparator) || + (allow_back_slash && path[0] == AlternateDirectorySeparator && + path[1] == AlternateDirectorySeparator); +} + +constexpr inline bool IsWindowsDrive(const char* path) { + ASSERT(path != nullptr); + + return (('a' <= path[0] && path[0] <= 'z') || ('A' <= path[0] && path[0] <= 'Z')) && + path[1] == StringTraits::DriveSeparator; +} + +constexpr inline bool IsWindowsPath(const char* path, bool allow_forward_slash_unc) { + return IsWindowsDrive(path) || IsDosDevicePath(path) || + IsUncPath(path, allow_forward_slash_unc, true); +} + +constexpr inline int GetWindowsSkipLength(const char* path) { + if (IsDosDevicePath(path)) { + return DosDevicePathPrefixLength; + } else if (IsWindowsDrive(path)) { + return WindowsDriveLength; + } else if (IsUncPath(path)) { + return UncPathPrefixLength; + } else { + return 0; + } +} + +constexpr inline bool IsPathAbsolute(const char* path) { + return IsWindowsPath(path, false) || path[0] == StringTraits::DirectorySeparator; +} + +constexpr inline bool IsPathRelative(const char* path) { + return path[0] && !IsPathAbsolute(path); +} + +constexpr inline bool IsCurrentDirectory(const char* path) { + return path[0] == StringTraits::Dot && + (path[1] == StringTraits::NullTerminator || path[1] == StringTraits::DirectorySeparator); +} + +constexpr inline bool IsParentDirectory(const char* path) { + return path[0] == StringTraits::Dot && path[1] == StringTraits::Dot && + (path[2] == StringTraits::NullTerminator || path[2] == StringTraits::DirectorySeparator); +} + +constexpr inline bool IsPathStartWithCurrentDirectory(const char* path) { + return IsCurrentDirectory(path) || IsParentDirectory(path); +} + +constexpr inline bool IsSubPath(const char* lhs, const char* rhs) { + // Check pre-conditions + ASSERT(lhs != nullptr); + ASSERT(rhs != nullptr); + + // Import StringTraits names for current scope + using namespace StringTraits; + + // Special case certain paths + if (IsUncPath(lhs) && !IsUncPath(rhs)) { + return false; + } + if (!IsUncPath(lhs) && IsUncPath(rhs)) { + return false; + } + + if (lhs[0] == DirectorySeparator && lhs[1] == NullTerminator && rhs[0] == DirectorySeparator && + rhs[1] != NullTerminator) { + return true; + } + if (rhs[0] == DirectorySeparator && rhs[1] == NullTerminator && lhs[0] == DirectorySeparator && + lhs[1] != NullTerminator) { + return true; + } + + // Check subpath + for (size_t i = 0; /* ... */; ++i) { + if (lhs[i] == NullTerminator) { + return rhs[i] == DirectorySeparator; + } else if (rhs[i] == NullTerminator) { + return lhs[i] == DirectorySeparator; + } else if (lhs[i] != rhs[i]) { + return false; + } + } +} + +// Path utilities +constexpr inline void Replace(char* dst, size_t dst_size, char old_char, char new_char) { + ASSERT(dst != nullptr); + for (char* cur = dst; cur < dst + dst_size && *cur; ++cur) { + if (*cur == old_char) { + *cur = new_char; + } + } +} + +constexpr inline Result CheckUtf8(const char* s) { + // Check pre-conditions + ASSERT(s != nullptr); + + // Iterate, checking for utf8-validity + while (*s) { + char utf8_buf[4] = {}; + + const auto pick_res = PickOutCharacterFromUtf8String(utf8_buf, std::addressof(s)); + R_UNLESS(pick_res == CharacterEncodingResult_Success, ResultInvalidPathFormat); + + u32 dummy; + const auto cvt_res = ConvertCharacterUtf8ToUtf32(std::addressof(dummy), utf8_buf); + R_UNLESS(cvt_res == CharacterEncodingResult_Success, ResultInvalidPathFormat); + } + + R_SUCCEED(); +} + +// Path formatting +class PathNormalizer { +private: + enum class PathState { + Start, + Normal, + FirstSeparator, + Separator, + CurrentDir, + ParentDir, + }; + +private: + static constexpr void ReplaceParentDirectoryPath(char* dst, const char* src) { + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + // Start with a dir-separator + dst[0] = DirectorySeparator; + + auto i = 1; + while (src[i] != NullTerminator) { + if ((src[i - 1] == DirectorySeparator || src[i - 1] == AlternateDirectorySeparator) && + src[i + 0] == Dot && src[i + 1] == Dot && + (src[i + 2] == DirectorySeparator || src[i + 2] == AlternateDirectorySeparator)) { + dst[i - 1] = DirectorySeparator; + dst[i + 0] = Dot; + dst[i + 1] = Dot; + dst[i + 2] = DirectorySeparator; + i += 3; + } else { + if (src[i - 1] == AlternateDirectorySeparator && src[i + 0] == Dot && + src[i + 1] == Dot && src[i + 2] == NullTerminator) { + dst[i - 1] = DirectorySeparator; + dst[i + 0] = Dot; + dst[i + 1] = Dot; + i += 2; + break; + } + + dst[i] = src[i]; + ++i; + } + } + + dst[i] = StringTraits::NullTerminator; + } + +public: + static constexpr bool IsParentDirectoryPathReplacementNeeded(const char* path) { + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + if (path[0] != DirectorySeparator && path[0] != AlternateDirectorySeparator) { + return false; + } + + // Check to find a parent reference using alternate separators + if (path[0] != NullTerminator && path[1] != NullTerminator && path[2] != NullTerminator) { + size_t i; + for (i = 0; path[i + 3] != NullTerminator; ++path) { + if (path[i + 1] != Dot || path[i + 2] != Dot) { + continue; + } + + const char c0 = path[i + 0]; + const char c3 = path[i + 3]; + + if (c0 == AlternateDirectorySeparator && + (c3 == DirectorySeparator || c3 == AlternateDirectorySeparator || + c3 == NullTerminator)) { + return true; + } + + if (c3 == AlternateDirectorySeparator && + (c0 == DirectorySeparator || c0 == AlternateDirectorySeparator)) { + return true; + } + } + + if (path[i + 0] == AlternateDirectorySeparator && path[i + 1] == Dot && + path[i + 2] == Dot /* && path[i + 3] == NullTerminator */) { + return true; + } + } + + return false; + } + + static constexpr Result IsNormalized(bool* out, size_t* out_len, const char* path, + bool allow_all_characters = false) { + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + // Parse the path + auto state = PathState::Start; + size_t len = 0; + while (path[len] != NullTerminator) { + // Get the current character + const char c = path[len++]; + + // Check the current character is valid + if (!allow_all_characters && state != PathState::Start) { + R_UNLESS(!IsInvalidCharacter(c), ResultInvalidCharacter); + } + + // Process depending on current state + switch (state) { + // Import the PathState enums for convenience + using enum PathState; + + case Start: + R_UNLESS(c == DirectorySeparator, ResultInvalidPathFormat); + state = FirstSeparator; + break; + case Normal: + if (c == DirectorySeparator) { + state = Separator; + } + break; + case FirstSeparator: + case Separator: + if (c == DirectorySeparator) { + *out = false; + R_SUCCEED(); + } + + if (c == Dot) { + state = CurrentDir; + } else { + state = Normal; + } + break; + case CurrentDir: + if (c == DirectorySeparator) { + *out = false; + R_SUCCEED(); + } + + if (c == Dot) { + state = ParentDir; + } else { + state = Normal; + } + break; + case ParentDir: + if (c == DirectorySeparator) { + *out = false; + R_SUCCEED(); + } + + state = Normal; + break; + default: + UNREACHABLE(); + break; + } + } + + // Check the final state + switch (state) { + // Import the PathState enums for convenience + using enum PathState; + case Start: + R_THROW(ResultInvalidPathFormat); + case Normal: + case FirstSeparator: + *out = true; + break; + case Separator: + case CurrentDir: + case ParentDir: + *out = false; + break; + default: + UNREACHABLE(); + break; + } + + // Set the output length + *out_len = len; + R_SUCCEED(); + } + + static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size, + bool is_windows_path, bool is_drive_relative_path, + bool allow_all_characters = false) { + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + // Prepare to iterate + const char* cur_path = path; + size_t total_len = 0; + + // If path begins with a separator, check that we're not drive relative + if (cur_path[0] != DirectorySeparator) { + R_UNLESS(is_drive_relative_path, ResultInvalidPathFormat); + + dst[total_len++] = DirectorySeparator; + } + + // We're going to need to do path replacement, potentially + char* replacement_path = nullptr; + size_t replacement_path_size = 0; + + SCOPE_EXIT({ + if (replacement_path != nullptr) { + if (std::is_constant_evaluated()) { + delete[] replacement_path; + } else { + Deallocate(replacement_path, replacement_path_size); + } + } + }); + + // Perform path replacement, if necessary + if (IsParentDirectoryPathReplacementNeeded(cur_path)) { + if (std::is_constant_evaluated()) { + replacement_path_size = EntryNameLengthMax + 1; + replacement_path = new char[replacement_path_size]; + } else { + replacement_path_size = EntryNameLengthMax + 1; + replacement_path = static_cast<char*>(Allocate(replacement_path_size)); + } + + ReplaceParentDirectoryPath(replacement_path, cur_path); + + cur_path = replacement_path; + } + + // Iterate, normalizing path components + bool skip_next_sep = false; + size_t i = 0; + + while (cur_path[i] != NullTerminator) { + // Process a directory separator, if we run into one + if (cur_path[i] == DirectorySeparator) { + // Swallow separators + do { + ++i; + } while (cur_path[i] == DirectorySeparator); + + // Check if we hit end of string + if (cur_path[i] == NullTerminator) { + break; + } + + // If we aren't skipping the separator, write it, checking that we remain in bounds. + if (!skip_next_sep) { + if (total_len + 1 == max_out_size) { + dst[total_len] = NullTerminator; + *out_len = total_len; + R_THROW(ResultTooLongPath); + } + + dst[total_len++] = DirectorySeparator; + } + + // Don't skip the next separator + skip_next_sep = false; + } + + // Get the length of the current directory component + size_t dir_len = 0; + while (cur_path[i + dir_len] != DirectorySeparator && + cur_path[i + dir_len] != NullTerminator) { + // Check for validity + if (!allow_all_characters) { + R_UNLESS(!IsInvalidCharacter(cur_path[i + dir_len]), ResultInvalidCharacter); + } + + ++dir_len; + } + + // Handle the current dir component + if (IsCurrentDirectory(cur_path + i)) { + skip_next_sep = true; + } else if (IsParentDirectory(cur_path + i)) { + // We should have just written a separator + ASSERT(dst[total_len - 1] == DirectorySeparator); + + // We should have started with a separator, for non-windows paths + if (!is_windows_path) { + ASSERT(dst[0] == DirectorySeparator); + } + + // Remove the previous component + if (total_len == 1) { + R_UNLESS(is_windows_path, ResultDirectoryUnobtainable); + + --total_len; + } else { + total_len -= 2; + + do { + if (dst[total_len] == DirectorySeparator) { + break; + } + } while ((--total_len) != 0); + } + + // We should be pointing to a directory separator, for non-windows paths + if (!is_windows_path) { + ASSERT(dst[total_len] == DirectorySeparator); + } + + // We should remain in bounds + ASSERT(total_len < max_out_size); + } else { + // Copy, possibly truncating + if (total_len + dir_len + 1 > max_out_size) { + const size_t copy_len = max_out_size - (total_len + 1); + + for (size_t j = 0; j < copy_len; ++j) { + dst[total_len++] = cur_path[i + j]; + } + + dst[total_len] = NullTerminator; + *out_len = total_len; + R_THROW(ResultTooLongPath); + } + + for (size_t j = 0; j < dir_len; ++j) { + dst[total_len++] = cur_path[i + j]; + } + } + + // Advance past the current directory component + i += dir_len; + } + + if (skip_next_sep) { + --total_len; + } + + if (total_len == 0 && max_out_size != 0) { + total_len = 1; + dst[0] = DirectorySeparator; + } + + // NOTE: Probable nintendo bug, as max_out_size must be at least total_len + 1 for the null + // terminator. + R_UNLESS(max_out_size >= total_len - 1, ResultTooLongPath); + + dst[total_len] = NullTerminator; + + // Check that the result path is normalized + bool is_normalized; + size_t dummy; + R_TRY(IsNormalized(std::addressof(is_normalized), std::addressof(dummy), dst, + allow_all_characters)); + + // Assert that the result path is normalized + ASSERT(is_normalized); + + // Set the output length + *out_len = total_len; + R_SUCCEED(); + } +}; + +class PathFormatter { +private: + static constexpr Result CheckSharedName(const char* name, size_t len) { + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + if (len == 1) { + R_UNLESS(name[0] != Dot, ResultInvalidPathFormat); + } else if (len == 2) { + R_UNLESS(name[0] != Dot || name[1] != Dot, ResultInvalidPathFormat); + } + + for (size_t i = 0; i < len; ++i) { + R_UNLESS(!IsInvalidCharacter(name[i]), ResultInvalidCharacter); + } + + R_SUCCEED(); + } + + static constexpr Result CheckHostName(const char* name, size_t len) { + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + if (len == 2) { + R_UNLESS(name[0] != Dot || name[1] != Dot, ResultInvalidPathFormat); + } + + for (size_t i = 0; i < len; ++i) { + R_UNLESS(!IsInvalidCharacterForHostName(name[i]), ResultInvalidCharacter); + } + + R_SUCCEED(); + } + + static constexpr Result CheckInvalidBackslash(bool* out_contains_backslash, const char* path, + bool allow_backslash) { + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + // Default to no backslashes, so we can just write if we see one + *out_contains_backslash = false; + + while (*path != NullTerminator) { + if (*(path++) == AlternateDirectorySeparator) { + *out_contains_backslash = true; + + R_UNLESS(allow_backslash, ResultInvalidCharacter); + } + } + + R_SUCCEED(); + } + +public: + static constexpr Result CheckPathFormat(const char* path, const PathFlags& flags) { + bool normalized; + size_t len; + R_RETURN(IsNormalized(std::addressof(normalized), std::addressof(len), path, flags)); + } + + static constexpr Result SkipMountName(const char** out, size_t* out_len, const char* path) { + R_RETURN(ParseMountName(out, out_len, nullptr, 0, path)); + } + + static constexpr Result ParseMountName(const char** out, size_t* out_len, char* out_mount_name, + size_t out_mount_name_buffer_size, const char* path) { + // Check pre-conditions + ASSERT(path != nullptr); + ASSERT(out_len != nullptr); + ASSERT(out != nullptr); + ASSERT((out_mount_name == nullptr) == (out_mount_name_buffer_size == 0)); + + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + // Determine max mount length + const auto max_mount_len = + out_mount_name_buffer_size == 0 + ? MountNameLengthMax + 1 + : std::min(MountNameLengthMax + 1, out_mount_name_buffer_size); + + // Parse the path until we see a drive separator + size_t mount_len = 0; + for (/* ... */; mount_len < max_mount_len && path[mount_len]; ++mount_len) { + const char c = path[mount_len]; + + // If we see a drive separator, advance, then we're done with the pre-drive separator + // part of the mount. + if (c == DriveSeparator) { + ++mount_len; + break; + } + + // If we see a directory separator, we're not in a mount name + if (c == DirectorySeparator || c == AlternateDirectorySeparator) { + *out = path; + *out_len = 0; + R_SUCCEED(); + } + } + + // Check to be sure we're actually looking at a mount name + if (mount_len <= 2 || path[mount_len - 1] != DriveSeparator) { + *out = path; + *out_len = 0; + R_SUCCEED(); + } + + // Check that all characters in the mount name are allowable + for (size_t i = 0; i < mount_len; ++i) { + R_UNLESS(!IsInvalidCharacterForMountName(path[i]), ResultInvalidCharacter); + } + + // Copy out the mount name + if (out_mount_name_buffer_size > 0) { + R_UNLESS(mount_len < out_mount_name_buffer_size, ResultTooLongPath); + + for (size_t i = 0; i < mount_len; ++i) { + out_mount_name[i] = path[i]; + } + out_mount_name[mount_len] = NullTerminator; + } + + // Set the output + *out = path + mount_len; + *out_len = mount_len; + R_SUCCEED(); + } + + static constexpr Result SkipRelativeDotPath(const char** out, size_t* out_len, + const char* path) { + R_RETURN(ParseRelativeDotPath(out, out_len, nullptr, 0, path)); + } + + static constexpr Result ParseRelativeDotPath(const char** out, size_t* out_len, + char* out_relative, + size_t out_relative_buffer_size, + const char* path) { + // Check pre-conditions + ASSERT(path != nullptr); + ASSERT(out_len != nullptr); + ASSERT(out != nullptr); + ASSERT((out_relative == nullptr) == (out_relative_buffer_size == 0)); + + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + // Initialize the output buffer, if we have one + if (out_relative_buffer_size > 0) { + out_relative[0] = NullTerminator; + } + + // Check if the path is relative + if (path[0] == Dot && (path[1] == NullTerminator || path[1] == DirectorySeparator || + path[1] == AlternateDirectorySeparator)) { + if (out_relative_buffer_size > 0) { + R_UNLESS(out_relative_buffer_size >= 2, ResultTooLongPath); + + out_relative[0] = Dot; + out_relative[1] = NullTerminator; + } + + *out = path + 1; + *out_len = 1; + R_SUCCEED(); + } + + // Ensure the path isn't a parent directory + R_UNLESS(!(path[0] == Dot && path[1] == Dot), ResultDirectoryUnobtainable); + + // There was no relative dot path + *out = path; + *out_len = 0; + R_SUCCEED(); + } + + static constexpr Result SkipWindowsPath(const char** out, size_t* out_len, bool* out_normalized, + const char* path, bool has_mount_name) { + // We're normalized if and only if the parsing doesn't throw ResultNotNormalized() + *out_normalized = true; + + R_TRY_CATCH(ParseWindowsPath(out, out_len, nullptr, 0, path, has_mount_name)) { + R_CATCH(ResultNotNormalized) { + *out_normalized = false; + } + } + R_END_TRY_CATCH; + ON_RESULT_INCLUDED(ResultNotNormalized) { + *out_normalized = false; + }; + + R_SUCCEED(); + } + + static constexpr Result ParseWindowsPath(const char** out, size_t* out_len, char* out_win, + size_t out_win_buffer_size, const char* path, + bool has_mount_name) { + // Check pre-conditions + ASSERT(path != nullptr); + ASSERT(out_len != nullptr); + ASSERT(out != nullptr); + ASSERT((out_win == nullptr) == (out_win_buffer_size == 0)); + + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + // Initialize the output buffer, if we have one + if (out_win_buffer_size > 0) { + out_win[0] = NullTerminator; + } + + // Handle path start + const char* cur_path = path; + if (has_mount_name && path[0] == DirectorySeparator) { + if (path[1] == AlternateDirectorySeparator && path[2] == AlternateDirectorySeparator) { + R_UNLESS(out_win_buffer_size > 0, ResultNotNormalized); + + ++cur_path; + } else if (IsWindowsDrive(path + 1)) { + R_UNLESS(out_win_buffer_size > 0, ResultNotNormalized); + + ++cur_path; + } + } + + // Handle windows drive + if (IsWindowsDrive(cur_path)) { + // Parse up to separator + size_t win_path_len = WindowsDriveLength; + for (/* ... */; cur_path[win_path_len] != NullTerminator; ++win_path_len) { + R_UNLESS(!IsInvalidCharacter(cur_path[win_path_len]), ResultInvalidCharacter); + + if (cur_path[win_path_len] == DirectorySeparator || + cur_path[win_path_len] == AlternateDirectorySeparator) { + break; + } + } + + // Ensure that we're normalized, if we're required to be + if (out_win_buffer_size == 0) { + for (size_t i = 0; i < win_path_len; ++i) { + R_UNLESS(cur_path[i] != AlternateDirectorySeparator, ResultNotNormalized); + } + } else { + // Ensure we can copy into the normalized buffer + R_UNLESS(win_path_len < out_win_buffer_size, ResultTooLongPath); + + for (size_t i = 0; i < win_path_len; ++i) { + out_win[i] = cur_path[i]; + } + out_win[win_path_len] = NullTerminator; + + Replace(out_win, win_path_len, AlternateDirectorySeparator, DirectorySeparator); + } + + *out = cur_path + win_path_len; + *out_len = win_path_len; + R_SUCCEED(); + } + + // Handle DOS device + if (IsDosDevicePath(cur_path)) { + size_t dos_prefix_len = DosDevicePathPrefixLength; + + if (IsWindowsDrive(cur_path + dos_prefix_len)) { + dos_prefix_len += WindowsDriveLength; + } else { + --dos_prefix_len; + } + + if (out_win_buffer_size > 0) { + // Ensure we can copy into the normalized buffer + R_UNLESS(dos_prefix_len < out_win_buffer_size, ResultTooLongPath); + + for (size_t i = 0; i < dos_prefix_len; ++i) { + out_win[i] = cur_path[i]; + } + out_win[dos_prefix_len] = NullTerminator; + + Replace(out_win, dos_prefix_len, DirectorySeparator, AlternateDirectorySeparator); + } + + *out = cur_path + dos_prefix_len; + *out_len = dos_prefix_len; + R_SUCCEED(); + } + + // Handle UNC path + if (IsUncPath(cur_path, false, true)) { + const char* final_path = cur_path; + + R_UNLESS(cur_path[UncPathPrefixLength] != DirectorySeparator, ResultInvalidPathFormat); + R_UNLESS(cur_path[UncPathPrefixLength] != AlternateDirectorySeparator, + ResultInvalidPathFormat); + + size_t cur_component_offset = 0; + size_t pos = UncPathPrefixLength; + for (/* ... */; cur_path[pos] != NullTerminator; ++pos) { + if (cur_path[pos] == DirectorySeparator || + cur_path[pos] == AlternateDirectorySeparator) { + if (cur_component_offset != 0) { + R_TRY(CheckSharedName(cur_path + cur_component_offset, + pos - cur_component_offset)); + + final_path = cur_path + pos; + break; + } + + R_UNLESS(cur_path[pos + 1] != DirectorySeparator, ResultInvalidPathFormat); + R_UNLESS(cur_path[pos + 1] != AlternateDirectorySeparator, + ResultInvalidPathFormat); + + R_TRY(CheckHostName(cur_path + 2, pos - 2)); + + cur_component_offset = pos + 1; + } + } + + R_UNLESS(cur_component_offset != pos, ResultInvalidPathFormat); + + if (cur_component_offset != 0 && final_path == cur_path) { + R_TRY(CheckSharedName(cur_path + cur_component_offset, pos - cur_component_offset)); + + final_path = cur_path + pos; + } + + size_t unc_prefix_len = final_path - cur_path; + + // Ensure that we're normalized, if we're required to be + if (out_win_buffer_size == 0) { + for (size_t i = 0; i < unc_prefix_len; ++i) { + R_UNLESS(cur_path[i] != DirectorySeparator, ResultNotNormalized); + } + } else { + // Ensure we can copy into the normalized buffer + R_UNLESS(unc_prefix_len < out_win_buffer_size, ResultTooLongPath); + + for (size_t i = 0; i < unc_prefix_len; ++i) { + out_win[i] = cur_path[i]; + } + out_win[unc_prefix_len] = NullTerminator; + + Replace(out_win, unc_prefix_len, DirectorySeparator, AlternateDirectorySeparator); + } + + *out = cur_path + unc_prefix_len; + *out_len = unc_prefix_len; + R_SUCCEED(); + } + + // There's no windows path to parse + *out = path; + *out_len = 0; + R_SUCCEED(); + } + + static constexpr Result IsNormalized(bool* out, size_t* out_len, const char* path, + const PathFlags& flags = {}) { + // Ensure nothing is null + R_UNLESS(out != nullptr, ResultNullptrArgument); + R_UNLESS(out_len != nullptr, ResultNullptrArgument); + R_UNLESS(path != nullptr, ResultNullptrArgument); + + // Verify that the path is valid utf-8 + R_TRY(CheckUtf8(path)); + + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + // Handle the case where the path is empty + if (path[0] == NullTerminator) { + R_UNLESS(flags.IsEmptyPathAllowed(), ResultInvalidPathFormat); + + *out = true; + *out_len = 0; + R_SUCCEED(); + } + + // All normalized paths start with a directory separator...unless they're windows paths, + // relative paths, or have mount names. + if (path[0] != DirectorySeparator) { + R_UNLESS(flags.IsWindowsPathAllowed() || flags.IsRelativePathAllowed() || + flags.IsMountNameAllowed(), + ResultInvalidPathFormat); + } + + // Check that the path is allowed to be a windows path, if it is + if (IsWindowsPath(path, false)) { + R_UNLESS(flags.IsWindowsPathAllowed(), ResultInvalidPathFormat); + } + + // Skip past the mount name, if one is present + size_t total_len = 0; + size_t mount_name_len = 0; + R_TRY(SkipMountName(std::addressof(path), std::addressof(mount_name_len), path)); + + // If we had a mount name, check that that was allowed + if (mount_name_len > 0) { + R_UNLESS(flags.IsMountNameAllowed(), ResultInvalidPathFormat); + + total_len += mount_name_len; + } + + // Check that the path starts as a normalized path should + if (path[0] != DirectorySeparator && !IsPathStartWithCurrentDirectory(path) && + !IsWindowsPath(path, false)) { + R_UNLESS(flags.IsRelativePathAllowed(), ResultInvalidPathFormat); + R_UNLESS(!IsInvalidCharacter(path[0]), ResultInvalidPathFormat); + + *out = false; + R_SUCCEED(); + } + + // Process relative path + size_t relative_len = 0; + R_TRY(SkipRelativeDotPath(std::addressof(path), std::addressof(relative_len), path)); + + // If we have a relative path, check that was allowed + if (relative_len > 0) { + R_UNLESS(flags.IsRelativePathAllowed(), ResultInvalidPathFormat); + + total_len += relative_len; + + if (path[0] == NullTerminator) { + *out = true; + *out_len = total_len; + R_SUCCEED(); + } + } + + // Process windows path + size_t windows_len = 0; + bool normalized_win = false; + R_TRY(SkipWindowsPath(std::addressof(path), std::addressof(windows_len), + std::addressof(normalized_win), path, mount_name_len > 0)); + + // If the windows path wasn't normalized, we're not normalized + if (!normalized_win) { + R_UNLESS(flags.IsWindowsPathAllowed(), ResultInvalidPathFormat); + + *out = false; + R_SUCCEED(); + } + + // If we had a windows path, check that was allowed + if (windows_len > 0) { + R_UNLESS(flags.IsWindowsPathAllowed(), ResultInvalidPathFormat); + + total_len += windows_len; + + // We can't have both a relative path and a windows path + R_UNLESS(relative_len == 0, ResultInvalidPathFormat); + + // A path ending in a windows path isn't normalized + if (path[0] == NullTerminator) { + *out = false; + R_SUCCEED(); + } + + // Check that there are no windows directory separators in the path + for (size_t i = 0; path[i] != NullTerminator; ++i) { + if (path[i] == AlternateDirectorySeparator) { + *out = false; + R_SUCCEED(); + } + } + } + + // Check that parent directory replacement is not needed if backslashes are allowed + if (flags.IsBackslashAllowed() && + PathNormalizer::IsParentDirectoryPathReplacementNeeded(path)) { + *out = false; + R_SUCCEED(); + } + + // Check that the backslash state is valid + bool is_backslash_contained = false; + R_TRY(CheckInvalidBackslash(std::addressof(is_backslash_contained), path, + flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed())); + + // Check that backslashes are contained only if allowed + if (is_backslash_contained && !flags.IsBackslashAllowed()) { + *out = false; + R_SUCCEED(); + } + + // Check that the final result path is normalized + size_t normal_len = 0; + R_TRY(PathNormalizer::IsNormalized(out, std::addressof(normal_len), path, + flags.IsAllCharactersAllowed())); + + // Add the normal length + total_len += normal_len; + + // Set the output length + *out_len = total_len; + R_SUCCEED(); + } + + static Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len, + const PathFlags& flags) { + // Use StringTraits names for remainder of scope + using namespace StringTraits; + + // Prepare to iterate + const char* src = path; + size_t cur_pos = 0; + bool is_windows_path = false; + + // Check if the path is empty + if (src[0] == NullTerminator) { + if (dst_size != 0) { + dst[0] = NullTerminator; + } + + R_UNLESS(flags.IsEmptyPathAllowed(), ResultInvalidPathFormat); + + R_SUCCEED(); + } + + // Handle a mount name + size_t mount_name_len = 0; + if (flags.IsMountNameAllowed()) { + R_TRY(ParseMountName(std::addressof(src), std::addressof(mount_name_len), dst + cur_pos, + dst_size - cur_pos, src)); + + cur_pos += mount_name_len; + } + + // Handle a drive-relative prefix + bool is_drive_relative = false; + if (src[0] != DirectorySeparator && !IsPathStartWithCurrentDirectory(src) && + !IsWindowsPath(src, false)) { + R_UNLESS(flags.IsRelativePathAllowed(), ResultInvalidPathFormat); + R_UNLESS(!IsInvalidCharacter(src[0]), ResultInvalidPathFormat); + + dst[cur_pos++] = Dot; + is_drive_relative = true; + } + + size_t relative_len = 0; + if (flags.IsRelativePathAllowed()) { + R_UNLESS(cur_pos < dst_size, ResultTooLongPath); + + R_TRY(ParseRelativeDotPath(std::addressof(src), std::addressof(relative_len), + dst + cur_pos, dst_size - cur_pos, src)); + + cur_pos += relative_len; + + if (src[0] == NullTerminator) { + R_UNLESS(cur_pos < dst_size, ResultTooLongPath); + + dst[cur_pos] = NullTerminator; + R_SUCCEED(); + } + } + + // Handle a windows path + if (flags.IsWindowsPathAllowed()) { + const char* const orig = src; + + R_UNLESS(cur_pos < dst_size, ResultTooLongPath); + + size_t windows_len = 0; + R_TRY(ParseWindowsPath(std::addressof(src), std::addressof(windows_len), dst + cur_pos, + dst_size - cur_pos, src, mount_name_len != 0)); + + cur_pos += windows_len; + + if (src[0] == NullTerminator) { + /* NOTE: Bug in original code here repeated, should be checking cur_pos + 2. */ + R_UNLESS(cur_pos + 1 < dst_size, ResultTooLongPath); + + dst[cur_pos + 0] = DirectorySeparator; + dst[cur_pos + 1] = NullTerminator; + R_SUCCEED(); + } + + if ((src - orig) > 0) { + is_windows_path = true; + } + } + + // Check for invalid backslash + bool backslash_contained = false; + R_TRY(CheckInvalidBackslash(std::addressof(backslash_contained), src, + flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed())); + + // Handle backslash replacement as necessary + if (backslash_contained && flags.IsWindowsPathAllowed()) { + // Create a temporary buffer holding a slash-replaced version of the path. + // NOTE: Nintendo unnecessarily allocates and replaces here a fully copy of the path, + // despite having skipped some of it already. + const size_t replaced_src_len = path_len - (src - path); + + char* replaced_src = nullptr; + SCOPE_EXIT({ + if (replaced_src != nullptr) { + if (std::is_constant_evaluated()) { + delete[] replaced_src; + } else { + Deallocate(replaced_src, replaced_src_len); + } + } + }); + + if (std::is_constant_evaluated()) { + replaced_src = new char[replaced_src_len]; + } else { + replaced_src = static_cast<char*>(Allocate(replaced_src_len)); + } + + Strlcpy<char>(replaced_src, src, replaced_src_len); + + Replace(replaced_src, replaced_src_len, AlternateDirectorySeparator, + DirectorySeparator); + + size_t dummy; + R_TRY(PathNormalizer::Normalize(dst + cur_pos, std::addressof(dummy), replaced_src, + dst_size - cur_pos, is_windows_path, is_drive_relative, + flags.IsAllCharactersAllowed())); + } else { + // We can just do normalization + size_t dummy; + R_TRY(PathNormalizer::Normalize(dst + cur_pos, std::addressof(dummy), src, + dst_size - cur_pos, is_windows_path, is_drive_relative, + flags.IsAllCharactersAllowed())); + } + + R_SUCCEED(); + } +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/assert.h" + +namespace FileSys { + +template <typename T> +constexpr int Strlen(const T* str) { + ASSERT(str != nullptr); + + int length = 0; + while (*str++) { + ++length; + } + + return length; +} + +template <typename T> +constexpr int Strnlen(const T* str, int count) { + ASSERT(str != nullptr); + ASSERT(count >= 0); + + int length = 0; + while (count-- && *str++) { + ++length; + } + + return length; +} + +template <typename T> +constexpr int Strncmp(const T* lhs, const T* rhs, int count) { + ASSERT(lhs != nullptr); + ASSERT(rhs != nullptr); + ASSERT(count >= 0); + + if (count == 0) { + return 0; + } + + T l, r; + do { + l = *(lhs++); + r = *(rhs++); + } while (l && (l == r) && (--count)); + + return l - r; +} + +template <typename T> +static constexpr int Strlcpy(T* dst, const T* src, int count) { + ASSERT(dst != nullptr); + ASSERT(src != nullptr); + + const T* cur = src; + if (count > 0) { + while ((--count) && *cur) { + *(dst++) = *(cur++); + } + *dst = 0; + } + + while (*cur) { + cur++; + } + + return static_cast<int>(cur - src); +} + +enum CharacterEncodingResult { + CharacterEncodingResult_Success = 0, + CharacterEncodingResult_InsufficientLength = 1, + CharacterEncodingResult_InvalidFormat = 2, +}; + +namespace impl { + +class CharacterEncodingHelper { +public: + static constexpr int8_t Utf8NBytesInnerTable[0x100 + 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, 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, 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, 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, 1, + 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, + 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, + 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, + 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, + 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, + }; + + static constexpr char GetUtf8NBytes(size_t i) { + return static_cast<char>(Utf8NBytesInnerTable[1 + i]); + } +}; + +} // namespace impl + +constexpr inline CharacterEncodingResult ConvertCharacterUtf8ToUtf32(u32* dst, const char* src) { + // Check pre-conditions + ASSERT(dst != nullptr); + ASSERT(src != nullptr); + + // Perform the conversion + const auto* p = src; + switch (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[0]))) { + case 1: + *dst = static_cast<u32>(p[0]); + return CharacterEncodingResult_Success; + case 2: + if ((static_cast<u32>(p[0]) & 0x1E) != 0) { + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == + 0) { + *dst = (static_cast<u32>(p[0] & 0x1F) << 6) | (static_cast<u32>(p[1] & 0x3F) << 0); + return CharacterEncodingResult_Success; + } + } + break; + case 3: + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 && + impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0) { + const u32 c = (static_cast<u32>(p[0] & 0xF) << 12) | + (static_cast<u32>(p[1] & 0x3F) << 6) | + (static_cast<u32>(p[2] & 0x3F) << 0); + if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) { + *dst = c; + return CharacterEncodingResult_Success; + } + } + return CharacterEncodingResult_InvalidFormat; + case 4: + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 && + impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0 && + impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[3])) == 0) { + const u32 c = + (static_cast<u32>(p[0] & 0x7) << 18) | (static_cast<u32>(p[1] & 0x3F) << 12) | + (static_cast<u32>(p[2] & 0x3F) << 6) | (static_cast<u32>(p[3] & 0x3F) << 0); + if (c >= 0x10000 && c < 0x110000) { + *dst = c; + return CharacterEncodingResult_Success; + } + } + return CharacterEncodingResult_InvalidFormat; + default: + break; + } + + // We failed to convert + return CharacterEncodingResult_InvalidFormat; +} + +constexpr inline CharacterEncodingResult PickOutCharacterFromUtf8String(char* dst, + const char** str) { + // Check pre-conditions + ASSERT(dst != nullptr); + ASSERT(str != nullptr); + ASSERT(*str != nullptr); + + // Clear the output + dst[0] = 0; + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; + + // Perform the conversion + const auto* p = *str; + u32 c = static_cast<u32>(*p); + switch (impl::CharacterEncodingHelper::GetUtf8NBytes(c)) { + case 1: + dst[0] = (*str)[0]; + ++(*str); + break; + case 2: + if ((p[0] & 0x1E) != 0) { + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == + 0) { + c = (static_cast<u32>(p[0] & 0x1F) << 6) | (static_cast<u32>(p[1] & 0x3F) << 0); + dst[0] = (*str)[0]; + dst[1] = (*str)[1]; + (*str) += 2; + break; + } + } + return CharacterEncodingResult_InvalidFormat; + case 3: + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 && + impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0) { + c = (static_cast<u32>(p[0] & 0xF) << 12) | (static_cast<u32>(p[1] & 0x3F) << 6) | + (static_cast<u32>(p[2] & 0x3F) << 0); + if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) { + dst[0] = (*str)[0]; + dst[1] = (*str)[1]; + dst[2] = (*str)[2]; + (*str) += 3; + break; + } + } + return CharacterEncodingResult_InvalidFormat; + case 4: + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 && + impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0 && + impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[3])) == 0) { + c = (static_cast<u32>(p[0] & 0x7) << 18) | (static_cast<u32>(p[1] & 0x3F) << 12) | + (static_cast<u32>(p[2] & 0x3F) << 6) | (static_cast<u32>(p[3] & 0x3F) << 0); + if (c >= 0x10000 && c < 0x110000) { + dst[0] = (*str)[0]; + dst[1] = (*str)[1]; + dst[2] = (*str)[2]; + dst[3] = (*str)[3]; + (*str) += 4; + break; + } + } + return CharacterEncodingResult_InvalidFormat; + default: + return CharacterEncodingResult_InvalidFormat; + } + + return CharacterEncodingResult_Success; +} + +} // 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 @@ #include "common/assert.h" #include "core/file_sys/fsmitm_romfsbuild.h" #include "core/file_sys/ips_layer.h" -#include "core/file_sys/vfs.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_vector.h" namespace FileSys { 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 @@ #include <memory> #include <string> #include "common/common_types.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include "common/overflow.h" #include "core/file_sys/errors.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include "core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h" #include "core/file_sys/fssystem/fssystem_aes_ctr_storage.h" #include "core/file_sys/fssystem/fssystem_nca_header.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs_offset.h" namespace FileSys { 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 @@ #include "core/crypto/key_manager.h" #include "core/file_sys/errors.h" #include "core/file_sys/fssystem/fs_i_storage.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include "common/common_types.h" #include "common/literals.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/result.h" namespace 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 @@ #include "core/file_sys/fssystem/fssystem_bucket_tree.h" #include "core/file_sys/fssystem/fssystem_compression_common.h" #include "core/file_sys/fssystem/fssystem_pooled_buffer.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs_offset.h" namespace FileSys { 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 @@ #include "core/file_sys/fssystem/fs_types.h" #include "core/file_sys/fssystem/fssystem_alignment_matching_storage.h" #include "core/file_sys/fssystem/fssystem_integrity_verification_storage.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs_offset.h" namespace FileSys { 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 @@ #include "core/file_sys/errors.h" #include "core/file_sys/fssystem/fs_i_storage.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include "core/file_sys/fssystem/fs_i_storage.h" #include "core/file_sys/fssystem/fssystem_bucket_tree.h" #include "core/file_sys/fssystem/fssystem_bucket_tree_template_impl.h" -#include "core/file_sys/vfs.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_offset.h" namespace FileSys { 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 @@ #include "core/file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h" #include "core/file_sys/fssystem/fssystem_nca_header.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_vector.h" namespace FileSys { 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 @@ #include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h" #include "core/file_sys/fssystem/fssystem_sparse_storage.h" #include "core/file_sys/fssystem/fssystem_switch_storage.h" -#include "core/file_sys/vfs_offset.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_offset.h" +#include "core/file_sys/vfs/vfs_vector.h" namespace FileSys { 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 @@ #include "core/file_sys/fssystem/fssystem_compression_common.h" #include "core/file_sys/fssystem/fssystem_nca_header.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include "core/file_sys/fssystem/fssystem_aes_xts_storage.h" #include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs_offset.h" namespace FileSys { 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 @@ #include "common/logging/log.h" #include "common/swap.h" #include "core/file_sys/ips_layer.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_vector.h" namespace FileSys { 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 @@ #include <vector> #include "common/common_types.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include "common/string_util.h" #include "core/file_sys/kernel_executable.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs_offset.h" #include "core/loader/loader.h" namespace 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 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace Loader { enum 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 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/common_funcs.h" -#include "common/common_types.h" - -namespace FileSys { - -enum class Mode : u32 { - Read = 1 << 0, - Write = 1 << 1, - ReadWrite = Read | Write, - Append = 1 << 2, - ReadAppend = Read | Append, - WriteAppend = Write | Append, - All = ReadWrite | Append, -}; - -DECLARE_ENUM_FLAG_OPERATORS(Mode) - -} // 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 @@ #include "common/logging/log.h" #include "common/swap.h" #include "core/file_sys/nca_metadata.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys { class 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 @@ #include "common/logging/log.h" #include "core/file_sys/partition_filesystem.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs_offset.h" #include "core/loader/loader.h" namespace 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 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace Loader { enum 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 @@ #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" -#include "core/file_sys/vfs_cached.h" -#include "core/file_sys/vfs_layered.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_cached.h" +#include "core/file_sys/vfs/vfs_layered.h" +#include "core/file_sys/vfs/vfs_vector.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/language.h" #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 @@ #include <string> #include "common/common_types.h" #include "core/file_sys/nca_metadata.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" #include "core/memory/dmnt_cheat_types.h" namespace 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 @@ #include "common/logging/log.h" #include "common/scope_exit.h" #include "core/file_sys/program_metadata.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/loader/loader.h" namespace 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 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace Loader { enum 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 @@ #include "core/file_sys/nca_metadata.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/submission_package.h" -#include "core/file_sys/vfs_concat.h" +#include "core/file_sys/vfs/vfs_concat.h" #include "core/loader/loader.h" namespace 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 @@ #include <boost/container/flat_map.hpp> #include "common/common_types.h" #include "core/crypto/key_manager.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { class 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 @@ #include "common/swap.h" #include "core/file_sys/fsmitm_romfsbuild.h" #include "core/file_sys/romfs.h" -#include "core/file_sys/vfs.h" -#include "core/file_sys/vfs_cached.h" -#include "core/file_sys/vfs_concat.h" -#include "core/file_sys/vfs_offset.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_cached.h" +#include "core/file_sys/vfs/vfs_concat.h" +#include "core/file_sys/vfs/vfs_offset.h" +#include "core/file_sys/vfs/vfs_vector.h" namespace FileSys { namespace { 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 @@ #pragma once -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include <memory> #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" #include "core/hle/result.h" namespace 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 @@ #include "common/uuid.h" #include "core/core.h" #include "core/file_sys/savedata_factory.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include <string> #include "common/common_funcs.h" #include "common/common_types.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/result.h" namespace 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 @@ #include <memory> #include "core/file_sys/registered_cache.h" #include "core/file_sys/sdmc_factory.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/file_sys/xts_archive.h" namespace 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 @@ #pragma once #include <memory> -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" #include "core/hle/result.h" namespace 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 @@ #include <vector> #include "common/common_types.h" #include "core/file_sys/nca_metadata.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace Core::Crypto { class 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 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/file_sys/system_archive/mii_model.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_vector.h" namespace FileSys::SystemArchive { 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 @@ #pragma once -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys::SystemArchive { 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 @@ #include <fmt/format.h> #include "common/common_types.h" #include "core/file_sys/system_archive/ng_word.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_vector.h" namespace FileSys::SystemArchive { 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 @@ #pragma once -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys::SystemArchive { 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 @@ #include "core/file_sys/system_archive/data/font_nintendo_extended.h" #include "core/file_sys/system_archive/data/font_standard.h" #include "core/file_sys/system_archive/shared_font.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_vector.h" #include "core/hle/service/ns/iplatform_service_manager.h" namespace 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 @@ #pragma once -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys::SystemArchive { 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 @@ #pragma once #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys::SystemArchive { 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 @@ #include "common/logging/log.h" #include "core/file_sys/system_archive/system_version.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_vector.h" #include "core/hle/api_version.h" namespace 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 @@ #pragma once #include <string> -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys::SystemArchive { 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 @@ #include "common/swap.h" #include "core/file_sys/system_archive/time_zone_binary.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_vector.h" #include "nx_tzdb.h" 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 @@ #pragma once -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys::SystemArchive { 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 @@ #include <numeric> #include <string> #include "common/fs/path_util.h" -#include "core/file_sys/mode.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { @@ -36,12 +35,12 @@ VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const { return VfsEntryType::None; } -VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) { +VirtualFile VfsFilesystem::OpenFile(std::string_view path_, OpenMode perms) { const auto path = Common::FS::SanitizePath(path_); return root->GetFileRelative(path); } -VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) { +VirtualFile VfsFilesystem::CreateFile(std::string_view path_, OpenMode perms) { const auto path = Common::FS::SanitizePath(path_); return root->CreateFileRelative(path); } @@ -54,17 +53,17 @@ VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view if (Common::FS::GetParentPath(old_path) == Common::FS::GetParentPath(new_path)) { if (!root->Copy(Common::FS::GetFilename(old_path), Common::FS::GetFilename(new_path))) return nullptr; - return OpenFile(new_path, Mode::ReadWrite); + return OpenFile(new_path, OpenMode::ReadWrite); } // Do it using RawCopy. Non-default impls are encouraged to optimize this. - const auto old_file = OpenFile(old_path, Mode::Read); + const auto old_file = OpenFile(old_path, OpenMode::Read); if (old_file == nullptr) return nullptr; - auto new_file = OpenFile(new_path, Mode::Read); + auto new_file = OpenFile(new_path, OpenMode::Read); if (new_file != nullptr) return nullptr; - new_file = CreateFile(new_path, Mode::Write); + new_file = CreateFile(new_path, OpenMode::Write); if (new_file == nullptr) return nullptr; if (!VfsRawCopy(old_file, new_file)) @@ -87,18 +86,18 @@ VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view bool VfsFilesystem::DeleteFile(std::string_view path_) { const auto path = Common::FS::SanitizePath(path_); - auto parent = OpenDirectory(Common::FS::GetParentPath(path), Mode::Write); + auto parent = OpenDirectory(Common::FS::GetParentPath(path), OpenMode::Write); if (parent == nullptr) return false; return parent->DeleteFile(Common::FS::GetFilename(path)); } -VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { +VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, OpenMode perms) { const auto path = Common::FS::SanitizePath(path_); return root->GetDirectoryRelative(path); } -VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { +VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, OpenMode perms) { const auto path = Common::FS::SanitizePath(path_); return root->CreateDirectoryRelative(path); } @@ -108,13 +107,13 @@ VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_ const auto new_path = Common::FS::SanitizePath(new_path_); // Non-default impls are highly encouraged to provide a more optimized version of this. - auto old_dir = OpenDirectory(old_path, Mode::Read); + auto old_dir = OpenDirectory(old_path, OpenMode::Read); if (old_dir == nullptr) return nullptr; - auto new_dir = OpenDirectory(new_path, Mode::Read); + auto new_dir = OpenDirectory(new_path, OpenMode::Read); if (new_dir != nullptr) return nullptr; - new_dir = CreateDirectory(new_path, Mode::Write); + new_dir = CreateDirectory(new_path, OpenMode::Write); if (new_dir == nullptr) return nullptr; @@ -149,7 +148,7 @@ VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_v bool VfsFilesystem::DeleteDirectory(std::string_view path_) { const auto path = Common::FS::SanitizePath(path_); - auto parent = OpenDirectory(Common::FS::GetParentPath(path), Mode::Write); + auto parent = OpenDirectory(Common::FS::GetParentPath(path), OpenMode::Write); if (parent == nullptr) return false; 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 @@ #include "common/common_funcs.h" #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys { -enum class Mode : u32; - // An enumeration representing what can be at the end of a path in a VfsFilesystem enum class VfsEntryType { None, @@ -49,9 +48,9 @@ public: virtual VfsEntryType GetEntryType(std::string_view path) const; // Opens the file with path relative to root. If it doesn't exist, returns nullptr. - virtual VirtualFile OpenFile(std::string_view path, Mode perms); + virtual VirtualFile OpenFile(std::string_view path, OpenMode perms); // Creates a new, empty file at path - virtual VirtualFile CreateFile(std::string_view path, Mode perms); + virtual VirtualFile CreateFile(std::string_view path, OpenMode perms); // Copies the file from old_path to new_path, returning the new file on success and nullptr on // failure. virtual VirtualFile CopyFile(std::string_view old_path, std::string_view new_path); @@ -62,9 +61,9 @@ public: virtual bool DeleteFile(std::string_view path); // Opens the directory with path relative to root. If it doesn't exist, returns nullptr. - virtual VirtualDir OpenDirectory(std::string_view path, Mode perms); + virtual VirtualDir OpenDirectory(std::string_view path, OpenMode perms); // Creates a new, empty directory at path - virtual VirtualDir CreateDirectory(std::string_view path, Mode perms); + virtual VirtualDir CreateDirectory(std::string_view path, OpenMode perms); // Copies the directory from old_path to new_path, returning the new directory on success and // nullptr on failure. 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 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/file_sys/vfs_cached.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_cached.h" +#include "core/file_sys/vfs/vfs_types.h" namespace FileSys { 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 @@ #include <string_view> #include <vector> -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include <utility> #include "common/assert.h" -#include "core/file_sys/vfs_concat.h" -#include "core/file_sys/vfs_static.h" +#include "core/file_sys/vfs/vfs_concat.h" +#include "core/file_sys/vfs/vfs_static.h" namespace FileSys { 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 @@ #include <compare> #include <map> #include <memory> -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include <set> #include <unordered_set> #include <utility> -#include "core/file_sys/vfs_layered.h" +#include "core/file_sys/vfs/vfs_layered.h" namespace FileSys { 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 @@ #pragma once #include <memory> -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include <algorithm> #include <utility> -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs_offset.h" namespace FileSys { 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 @@ #include <memory> -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/logging/log.h" -#include "core/file_sys/vfs.h" -#include "core/file_sys/vfs_real.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_real.h" // For FileTimeStampRaw #include <sys/stat.h> @@ -28,16 +28,14 @@ namespace { constexpr size_t MaxOpenFiles = 512; -constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(Mode mode) { +constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(OpenMode mode) { switch (mode) { - case Mode::Read: + case OpenMode::Read: return FS::FileAccessMode::Read; - case Mode::Write: - case Mode::ReadWrite: - case Mode::Append: - case Mode::ReadAppend: - case Mode::WriteAppend: - case Mode::All: + case OpenMode::Write: + case OpenMode::ReadWrite: + case OpenMode::AllowAppend: + case OpenMode::All: return FS::FileAccessMode::ReadWrite; default: return {}; @@ -74,7 +72,7 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { } VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size, - Mode perms) { + OpenMode perms) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); std::scoped_lock lk{list_lock}; @@ -98,11 +96,11 @@ VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::op return file; } -VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { +VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, OpenMode perms) { return OpenFileFromEntry(path_, {}, perms); } -VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { +VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, OpenMode perms) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); { std::scoped_lock lk{list_lock}; @@ -145,7 +143,7 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ if (!FS::RenameFile(old_path, new_path)) { return nullptr; } - return OpenFile(new_path, Mode::ReadWrite); + return OpenFile(new_path, OpenMode::ReadWrite); } bool RealVfsFilesystem::DeleteFile(std::string_view path_) { @@ -157,12 +155,12 @@ bool RealVfsFilesystem::DeleteFile(std::string_view path_) { return FS::RemoveFile(path); } -VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { +VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, OpenMode perms) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); } -VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { +VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, OpenMode perms) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); if (!FS::CreateDirs(path)) { return nullptr; @@ -184,7 +182,7 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, if (!FS::RenameDir(old_path, new_path)) { return nullptr; } - return OpenDirectory(new_path, Mode::ReadWrite); + return OpenDirectory(new_path, OpenMode::ReadWrite); } bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { @@ -193,7 +191,7 @@ bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { } std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::string& path, - Mode perms, + OpenMode perms, FileReference& reference) { std::unique_lock lk{list_lock}; @@ -266,7 +264,7 @@ void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference) } RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_, - const std::string& path_, Mode perms_, std::optional<u64> size_) + const std::string& path_, OpenMode perms_, std::optional<u64> size_) : base(base_), reference(std::move(reference_)), path(path_), parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponentsCopy(path_)), size(size_), perms(perms_) {} @@ -298,11 +296,11 @@ VirtualDir RealVfsFile::GetContainingDirectory() const { } bool RealVfsFile::IsWritable() const { - return True(perms & Mode::Write); + return True(perms & OpenMode::Write); } bool RealVfsFile::IsReadable() const { - return True(perms & Mode::Read); + return True(perms & OpenMode::Read); } std::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) { template <> std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const { - if (perms == Mode::Append) { + if (perms == OpenMode::AllowAppend) { return {}; } @@ -353,7 +351,7 @@ std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>( template <> std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const { - if (perms == Mode::Append) { + if (perms == OpenMode::AllowAppend) { return {}; } @@ -373,10 +371,11 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi return out; } -RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_) +RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, + OpenMode perms_) : base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)), path_components(FS::SplitPathComponentsCopy(path)), perms(perms_) { - if (!FS::Exists(path) && True(perms & Mode::Write)) { + if (!FS::Exists(path) && True(perms & OpenMode::Write)) { void(FS::CreateDirs(path)); } } @@ -456,11 +455,11 @@ std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const { } bool RealVfsDirectory::IsWritable() const { - return True(perms & Mode::Write); + return True(perms & OpenMode::Write); } bool RealVfsDirectory::IsReadable() const { - return True(perms & Mode::Read); + return True(perms & OpenMode::Read); } std::string RealVfsDirectory::GetName() const { @@ -507,7 +506,7 @@ std::string RealVfsDirectory::GetFullPath() const { } std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() const { - if (perms == Mode::Append) { + if (perms == OpenMode::AllowAppend) { return {}; } 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 @@ #include <optional> #include <string_view> #include "common/intrusive_list.h" -#include "core/file_sys/mode.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/vfs/vfs.h" namespace Common::FS { class IOFile; @@ -33,13 +33,14 @@ public: bool IsReadable() const override; bool IsWritable() const override; VfsEntryType GetEntryType(std::string_view path) const override; - VirtualFile OpenFile(std::string_view path, Mode perms = Mode::Read) override; - VirtualFile CreateFile(std::string_view path, Mode perms = Mode::ReadWrite) override; + VirtualFile OpenFile(std::string_view path, OpenMode perms = OpenMode::Read) override; + VirtualFile CreateFile(std::string_view path, OpenMode perms = OpenMode::ReadWrite) override; VirtualFile CopyFile(std::string_view old_path, std::string_view new_path) override; VirtualFile MoveFile(std::string_view old_path, std::string_view new_path) override; bool DeleteFile(std::string_view path) override; - VirtualDir OpenDirectory(std::string_view path, Mode perms = Mode::Read) override; - VirtualDir CreateDirectory(std::string_view path, Mode perms = Mode::ReadWrite) override; + VirtualDir OpenDirectory(std::string_view path, OpenMode perms = OpenMode::Read) override; + VirtualDir CreateDirectory(std::string_view path, + OpenMode perms = OpenMode::ReadWrite) override; VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path) override; VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path) override; bool DeleteDirectory(std::string_view path) override; @@ -54,14 +55,14 @@ private: private: friend class RealVfsFile; - std::unique_lock<std::mutex> RefreshReference(const std::string& path, Mode perms, + std::unique_lock<std::mutex> RefreshReference(const std::string& path, OpenMode perms, FileReference& reference); void DropReference(std::unique_ptr<FileReference>&& reference); private: friend class RealVfsDirectory; VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size, - Mode perms = Mode::Read); + OpenMode perms = OpenMode::Read); private: void EvictSingleReferenceLocked(); @@ -89,7 +90,8 @@ public: private: RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference, - const std::string& path, Mode perms = Mode::Read, std::optional<u64> size = {}); + const std::string& path, OpenMode perms = OpenMode::Read, + std::optional<u64> size = {}); RealVfsFilesystem& base; std::unique_ptr<FileReference> reference; @@ -97,7 +99,7 @@ private: std::string parent_path; std::vector<std::string> path_components; std::optional<u64> size; - Mode perms; + OpenMode perms; }; // An implementation of VfsDirectory that represents a directory on the user's computer. @@ -130,7 +132,8 @@ public: std::map<std::string, VfsEntryType, std::less<>> GetEntries() const override; private: - RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read); + RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, + OpenMode perms = OpenMode::Read); template <typename T, typename R> std::vector<std::shared_ptr<R>> IterateEntries() const; @@ -139,7 +142,7 @@ private: std::string path; std::string parent_path; std::vector<std::string> path_components; - Mode perms; + OpenMode perms; }; } // 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 @@ #include <memory> #include <string_view> -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include <algorithm> #include <utility> -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_vector.h" namespace FileSys { VectorVfsFile::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 @@ #include <memory> #include <string> #include <vector> -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace FileSys { 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 @@ #include "core/crypto/key_manager.h" #include "core/crypto/xts_encryption_layer.h" #include "core/file_sys/content_archive.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs_offset.h" #include "core/file_sys/xts_archive.h" #include "core/loader/loader.h" 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 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/crypto/key_manager.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace Loader { enum 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 {} void DefaultErrorApplet::ShowError(Result error, FinishedCallback finished) const { LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})", - error.module.Value(), error.description.Value(), error.raw); + error.GetModule(), error.GetDescription(), error.raw); } void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::seconds time, @@ -20,7 +20,7 @@ void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::secon LOG_CRITICAL( Service_Fatal, "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}", - error.module.Value(), error.description.Value(), error.raw, time.count()); + error.GetModule(), error.GetDescription(), error.raw, time.count()); } void DefaultErrorApplet::ShowCustomErrorText(Result error, std::string main_text, @@ -28,7 +28,7 @@ void DefaultErrorApplet::ShowCustomErrorText(Result error, std::string main_text FinishedCallback finished) const { LOG_CRITICAL(Service_Fatal, "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})", - error.module.Value(), error.description.Value(), error.raw); + error.GetModule(), error.GetDescription(), error.raw); LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text); LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text); } 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 { union Result { u32 raw; - BitField<0, 9, ErrorModule> module; - BitField<9, 13, u32> description; + using Module = BitField<0, 9, ErrorModule>; + using Description = BitField<9, 13, u32>; Result() = default; constexpr explicit Result(u32 raw_) : raw(raw_) {} constexpr Result(ErrorModule module_, u32 description_) - : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} + : raw(Module::FormatValue(module_) | Description::FormatValue(description_)) {} [[nodiscard]] constexpr bool IsSuccess() const { return raw == 0; @@ -211,7 +211,15 @@ union Result { } [[nodiscard]] constexpr u32 GetInnerValue() const { - return static_cast<u32>(module.Value()) | (description << module.bits); + return raw; + } + + [[nodiscard]] constexpr ErrorModule GetModule() const { + return Module::ExtractValue(raw); + } + + [[nodiscard]] constexpr u32 GetDescription() const { + return Description::ExtractValue(raw); } [[nodiscard]] constexpr bool Includes(Result result) const { @@ -274,8 +282,9 @@ public: } [[nodiscard]] constexpr bool Includes(Result other) const { - return code.module == other.module && code.description <= other.description && - other.description <= description_end; + return code.GetModule() == other.GetModule() && + code.GetDescription() <= other.GetDescription() && + other.GetDescription() <= description_end; } private: @@ -330,6 +339,16 @@ constexpr bool EvaluateResultFailure(const Result& r) { return R_FAILED(r); } +template <auto... R> +constexpr bool EvaluateAnyResultIncludes(const Result& r) { + return ((r == R) || ...); +} + +template <auto... R> +constexpr bool EvaluateResultNotIncluded(const Result& r) { + return !EvaluateAnyResultIncludes<R...>(r); +} + template <typename T> constexpr void UpdateCurrentResultReference(T result_reference, Result result) = delete; // Intentionally not defined @@ -371,6 +390,13 @@ constexpr void UpdateCurrentResultReference<const Result>(Result result_referenc DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \ ON_RESULT_SUCCESS_2 +#define ON_RESULT_INCLUDED_2(...) \ + ON_RESULT_RETURN_IMPL(ResultImpl::EvaluateAnyResultIncludes<__VA_ARGS__>) + +#define ON_RESULT_INCLUDED(...) \ + DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \ + ON_RESULT_INCLUDED_2(__VA_ARGS__) + constexpr inline Result __TmpCurrentResultReference = ResultSuccess; /// 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 { static constexpr ErrorCode FromResult(Result result) { return { - .error_category{2000 + static_cast<u32>(result.module.Value())}, - .error_number{result.description.Value()}, + .error_category{2000 + static_cast<u32>(result.GetModule())}, + .error_number{result.GetDescription()}, }; } 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 @@ #include "common/string_util.h" #include "core/core.h" #include "core/file_sys/content_archive.h" -#include "core/file_sys/mode.h" +#include "core/file_sys/fs_filesystem.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" #include "core/file_sys/system_archive/system_archive.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_vector.h" #include "core/frontend/applets/web_browser.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" @@ -213,7 +213,7 @@ void ExtractSharedFonts(Core::System& system) { std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]); const auto temp_dir = system.GetFilesystem()->CreateDirectory( - Common::FS::PathToUTF8String(fonts_dir), FileSys::Mode::ReadWrite); + Common::FS::PathToUTF8String(fonts_dir), FileSys::OpenMode::ReadWrite); const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]); @@ -333,7 +333,7 @@ void WebBrowser::ExtractOfflineRomFS() { const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs); const auto temp_dir = system.GetFilesystem()->CreateDirectory( - Common::FS::PathToUTF8String(offline_cache_dir), FileSys::Mode::ReadWrite); + Common::FS::PathToUTF8String(offline_cache_dir), FileSys::OpenMode::ReadWrite); FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir); } 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 @@ #include <optional> #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" #include "core/hle/result.h" #include "core/hle/service/am/applets/applet_web_browser_types.h" #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: ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1); } } else { - LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description); + LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", + result.GetDescription()); } 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 @@ #include <string> #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" #include "core/hle/result.h" #include "core/hle/service/kernel_helpers.h" 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 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/bcat/backend/backend.h" #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) { } if ((in_result.raw & 0x3801ff) == ResultUnknown1024.raw) { - if (in_result.description - 0x514 < 100) { + if (in_result.GetDescription() - 0x514 < 100) { return ResultInvalidFileData; } - if (in_result.description - 0x5dc < 100) { + if (in_result.GetDescription() - 0x5dc < 100) { return ResultInvalidFileData; } - if (in_result.description - 0x578 < 100) { + if (in_result.GetDescription() - 0x578 < 100) { if (in_result == ResultFileCountLimit) { return ResultUnknown22; } @@ -244,9 +244,10 @@ Result IAlbumAccessorService::TranslateResult(Result in_result) { return ResultUnknown1024; } - if (in_result.module == ErrorModule::FS) { - if ((in_result.description >> 0xc < 0x7d) || (in_result.description - 1000 < 2000) || - (((in_result.description - 3000) >> 3) < 0x271)) { + if (in_result.GetModule() == ErrorModule::FS) { + if ((in_result.GetDescription() >> 0xc < 0x7d) || + (in_result.GetDescription() - 1000 < 2000) || + (((in_result.GetDescription() - 3000) >> 3) < 0x271)) { // TODO: Translate FS error return in_result; } 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() { }; } -template <bool Domain, typename MethodArguments> -constexpr RequestLayout GetReplyInLayout() { - return Domain ? GetDomainReplyInLayout<MethodArguments>() : GetNonDomainReplyInLayout<MethodArguments>(); +template <typename MethodArguments> +constexpr RequestLayout GetReplyInLayout(bool is_domain) { + return is_domain ? GetDomainReplyInLayout<MethodArguments>() : GetNonDomainReplyInLayout<MethodArguments>(); } -template <bool Domain, typename MethodArguments> -constexpr RequestLayout GetReplyOutLayout() { - return Domain ? GetDomainReplyOutLayout<MethodArguments>() : GetNonDomainReplyOutLayout<MethodArguments>(); +template <typename MethodArguments> +constexpr RequestLayout GetReplyOutLayout(bool is_domain) { + return is_domain ? GetDomainReplyOutLayout<MethodArguments>() : GetNonDomainReplyOutLayout<MethodArguments>(); } using OutTemporaryBuffers = std::array<Common::ScratchBuffer<u8>, 3>; -template <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> -void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { +template <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> +void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { return; } else { @@ -134,25 +134,25 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& std::memcpy(&std::get<ArgIndex>(args), raw_data + ArgOffset, ArgSize); } - return ReadInArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, false, ArgIndex + 1>(args, raw_data, ctx, temp); + return ReadInArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, false, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InInterface) { constexpr size_t ArgAlign = alignof(u32); constexpr size_t ArgSize = sizeof(u32); constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); constexpr size_t ArgEnd = ArgOffset + ArgSize; - static_assert(Domain); + ASSERT(is_domain); ASSERT(ctx.GetDomainMessageHeader().input_object_count > 0); u32 value{}; std::memcpy(&value, raw_data + ArgOffset, ArgSize); std::get<ArgIndex>(args) = ctx.GetDomainHandler<ArgType::Type>(value - 1); - return ReadInArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(args, raw_data, ctx, temp); + return ReadInArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InCopyHandle) { - std::get<ArgIndex>(args) = std::move(ctx.GetObjectFromHandle<typename ArgType::Type>(ctx.GetCopyHandle(HandleIndex))); + std::get<ArgIndex>(args) = ctx.GetObjectFromHandle<typename ArgType::Type>(ctx.GetCopyHandle(HandleIndex)).GetPointerUnsafe(); - return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) { constexpr size_t BufferSize = sizeof(ArgType); @@ -172,7 +172,7 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& std::memcpy(&std::get<ArgIndex>(args), buffer.data(), std::min(BufferSize, buffer.size())); - return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InBuffer) { using ElementType = typename ArgType::Type; @@ -193,14 +193,14 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& std::get<ArgIndex>(args) = std::span(ptr, size); - return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { constexpr size_t BufferSize = sizeof(ArgType); // Clear the existing data. std::memset(&std::get<ArgIndex>(args), 0, BufferSize); - return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { using ElementType = typename ArgType::Type; @@ -217,15 +217,15 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& std::get<ArgIndex>(args) = std::span(ptr, size); - return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else { - return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } } } -template <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> -void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { +template <typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> +void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { return; } else { @@ -243,23 +243,23 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, std::memcpy(raw_data + ArgOffset, &std::get<ArgIndex>(args), ArgSize); - return WriteOutArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(args, raw_data, ctx, temp); + return WriteOutArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutInterface) { - if constexpr (Domain) { + if (is_domain) { ctx.AddDomainObject(std::get<ArgIndex>(args)); } else { ctx.AddMoveInterface(std::get<ArgIndex>(args)); } - return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(args, raw_data, ctx, temp); + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutCopyHandle) { - ctx.AddCopyObject(std::get<ArgIndex>(args).GetPointerUnsafe()); + ctx.AddCopyObject(std::get<ArgIndex>(args)); - return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutMoveHandle) { - ctx.AddMoveObject(std::get<ArgIndex>(args).GetPointerUnsafe()); + ctx.AddMoveObject(std::get<ArgIndex>(args)); - return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { constexpr size_t BufferSize = sizeof(ArgType); @@ -272,7 +272,7 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, ctx.WriteBufferC(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex); } - return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { auto& buffer = temp[OutBufferIndex]; const size_t size = buffer.size(); @@ -287,9 +287,9 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, } } - return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>( args, raw_data, ctx, temp); + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else { - return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } } } @@ -297,11 +297,10 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, template <bool Domain, typename T, typename... A> void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { // Verify domain state. - if constexpr (Domain) { - ASSERT_MSG(ctx.GetManager()->IsDomain(), "Domain reply used on non-domain session"); - } else { + if constexpr (!Domain) { ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Non-domain reply used on domain session"); } + const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false; using MethodArguments = std::tuple<std::remove_reference_t<A>...>; @@ -310,7 +309,7 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { // Read inputs. const size_t offset_plus_command_id = ctx.GetDataPayloadOffset() + 2; - ReadInArgument<Domain, MethodArguments>(call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + offset_plus_command_id), ctx, buffers); + ReadInArgument<MethodArguments>(is_domain, call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + offset_plus_command_id), ctx, buffers); // Call. const auto Callable = [&]<typename... CallArgs>(CallArgs&... args) { @@ -319,12 +318,12 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { const Result res = std::apply(Callable, call_arguments); // Write result. - constexpr RequestLayout layout = GetReplyOutLayout<Domain, MethodArguments>(); + const RequestLayout layout = GetReplyOutLayout<MethodArguments>(is_domain); 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}; rb.Push(res); // Write out arguments. - WriteOutArgument<Domain, MethodArguments>(call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + rb.GetCurrentOffset()), ctx, buffers); + WriteOutArgument<MethodArguments>(is_domain, call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + rb.GetCurrentOffset()), ctx, buffers); } // clang-format on 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 { template <typename T> class Out { public: - /* implicit */ Out(T& t) : raw(&t) {} + using Type = T; + + /* implicit */ Out(Type& t) : raw(&t) {} ~Out() = default; - T* Get() const { + Type* Get() const { return raw; } - T& operator*() { + Type& operator*() { return *raw; } private: - T* raw; + Type* raw; }; template <typename T> @@ -45,51 +47,93 @@ struct ClientProcessId { u64 pid; }; +struct ProcessId { + explicit operator bool() const { + return pid != 0; + } + + const u64& operator*() const { + return pid; + } + + u64 pid; +}; + using ClientAppletResourceUserId = ClientProcessId; +using AppletResourceUserId = ProcessId; template <typename T> -class InCopyHandle : public Kernel::KScopedAutoObject<T> { +class InCopyHandle { public: using Type = T; - template <typename... Args> - /* implicit */ InCopyHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {} + /* implicit */ InCopyHandle(Type* t) : raw(t) {} + /* implicit */ InCopyHandle() : raw() {} ~InCopyHandle() = default; - InCopyHandle& operator=(InCopyHandle&& rhs) { - Kernel::KScopedAutoObject<T>::operator=(std::move(rhs)); + InCopyHandle& operator=(Type* rhs) { + raw = rhs; return *this; } + + Type* Get() const { + return raw; + } + + Type& operator*() const { + return *raw; + } + + Type* operator->() const { + return raw; + } + + explicit operator bool() const { + return raw != nullptr; + } + +private: + Type* raw; }; template <typename T> -class OutCopyHandle : public Kernel::KScopedAutoObject<T> { +class OutCopyHandle { public: - using Type = T; + using Type = T*; - template <typename... Args> - /* implicit */ OutCopyHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {} + /* implicit */ OutCopyHandle(Type& t) : raw(&t) {} ~OutCopyHandle() = default; - OutCopyHandle& operator=(OutCopyHandle&& rhs) { - Kernel::KScopedAutoObject<T>::operator=(std::move(rhs)); - return *this; + Type* Get() const { + return raw; + } + + Type& operator*() { + return *raw; } + +private: + Type* raw; }; template <typename T> -class OutMoveHandle : public Kernel::KScopedAutoObject<T> { +class OutMoveHandle { public: - using Type = T; + using Type = T*; - template <typename... Args> - /* implicit */ OutMoveHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {} + /* implicit */ OutMoveHandle(Type& t) : raw(&t) {} ~OutMoveHandle() = default; - OutMoveHandle& operator=(OutMoveHandle&& rhs) { - Kernel::KScopedAutoObject<T>::operator=(std::move(rhs)); - return *this; + Type* Get() const { + return raw; + } + + Type& operator*() { + return *raw; } + +private: + Type* raw; }; enum BufferAttr : int { @@ -105,12 +149,15 @@ enum BufferAttr : int { template <typename T, int A> struct Buffer : public std::span<T> { - static_assert(std::is_trivial_v<T>, "Buffer type must be trivial"); + static_assert(std::is_trivially_copyable_v<T>, "Buffer type must be trivially copyable"); static_assert((A & BufferAttr_FixedSize) == 0, "Buffer attr must not contain FixedSize"); static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "Buffer attr must be In or Out"); static constexpr BufferAttr Attr = static_cast<BufferAttr>(A); using Type = T; + /* implicit */ Buffer(const std::span<T>& rhs) : std::span<T>(rhs) {} + /* implicit */ Buffer() = default; + Buffer& operator=(const std::span<T>& rhs) { std::span<T>::operator=(rhs); return *this; @@ -139,11 +186,14 @@ using OutArray = Buffer<T, BufferAttr_Out | A>; template <typename T, int A> struct LargeData : public T { - static_assert(std::is_trivial_v<T>, "LargeData type must be trivial"); + static_assert(std::is_trivially_copyable_v<T>, "LargeData type must be trivially copyable"); static_assert((A & BufferAttr_FixedSize) != 0, "LargeData attr must contain FixedSize"); static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "LargeData attr must be In or Out"); static constexpr BufferAttr Attr = static_cast<BufferAttr>(A); using Type = T; + + /* implicit */ LargeData(const T& rhs) : T(rhs) {} + /* implicit */ LargeData() = default; }; template <typename T, BufferAttr A> @@ -159,7 +209,17 @@ struct RemoveOut { template <typename T> struct RemoveOut<Out<T>> { - using Type = T; + using Type = typename Out<T>::Type; +}; + +template <typename T> +struct RemoveOut<OutCopyHandle<T>> { + using Type = typename OutCopyHandle<T>::Type; +}; + +template <typename T> +struct RemoveOut<OutMoveHandle<T>> { + using Type = typename OutMoveHandle<T>::Type; }; enum 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 "Program entry point: 0x{:16X}\n" "\n", Common::g_scm_branch, Common::g_scm_desc, title_id, error_code.raw, - 2000 + static_cast<u32>(error_code.module.Value()), - static_cast<u32>(error_code.description.Value()), info.set_flags, info.program_entry_point); + 2000 + static_cast<u32>(error_code.GetModule()), + static_cast<u32>(error_code.GetDescription()), info.set_flags, info.program_entry_point); if (info.backtrace_size != 0x0) { crash_report += "Registers:\n"; 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 @@ #include "core/file_sys/card_image.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/errors.h" -#include "core/file_sys/mode.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/sdmc_factory.h" -#include "core/file_sys/vfs.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_offset.h" #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/filesystem/fsp_ldr.h" -#include "core/hle/service/filesystem/fsp_pr.h" -#include "core/hle/service/filesystem/fsp_srv.h" +#include "core/hle/service/filesystem/fsp/fsp_ldr.h" +#include "core/hle/service/filesystem/fsp/fsp_pr.h" +#include "core/hle/service/filesystem/fsp/fsp_srv.h" #include "core/hle/service/filesystem/romfs_controller.h" #include "core/hle/service/filesystem/save_data_controller.h" #include "core/hle/service/server_manager.h" @@ -53,12 +52,12 @@ Result VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size std::string path(Common::FS::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } - FileSys::EntryType entry_type{}; + FileSys::DirectoryEntryType entry_type{}; if (GetEntryType(&entry_type, path) == ResultSuccess) { - return FileSys::ERROR_PATH_ALREADY_EXISTS; + return FileSys::ResultPathAlreadyExists; } auto file = dir->CreateFile(Common::FS::GetFilename(path)); @@ -82,7 +81,7 @@ Result VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } if (!dir->DeleteFile(Common::FS::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this @@ -153,12 +152,12 @@ Result VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { // Use more-optimized vfs implementation rename. if (src == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } if (dst && Common::FS::Exists(dst->GetFullPath())) { LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath()); - return FileSys::ERROR_PATH_ALREADY_EXISTS; + return FileSys::ResultPathAlreadyExists; } if (!src->Rename(Common::FS::GetFilename(dest_path))) { @@ -195,7 +194,7 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_, if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { // Use more-optimized vfs implementation rename. if (src == nullptr) - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; if (!src->Rename(Common::FS::GetFilename(dest_path))) { // TODO(DarkLordZach): Find a better error code for this return ResultUnknown; @@ -214,7 +213,8 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_, } Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file, - const std::string& path_, FileSys::Mode mode) const { + const std::string& path_, + FileSys::OpenMode mode) const { const std::string path(Common::FS::SanitizePath(path_)); std::string_view npath = path; while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) { @@ -223,10 +223,10 @@ Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file, auto file = backing->GetFileRelative(npath); if (file == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } - if (mode == FileSys::Mode::Append) { + if (mode == FileSys::OpenMode::AllowAppend) { *out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize()); } else { *out_file = file; @@ -241,50 +241,50 @@ Result VfsDirectoryServiceWrapper::OpenDirectory(FileSys::VirtualDir* out_direct auto dir = GetDirectoryRelativeWrapped(backing, path); if (dir == nullptr) { // TODO(DarkLordZach): Find a better error code for this - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } *out_directory = dir; return ResultSuccess; } -Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::EntryType* out_entry_type, +Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::DirectoryEntryType* out_entry_type, const std::string& path_) const { std::string path(Common::FS::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } auto filename = Common::FS::GetFilename(path); // TODO(Subv): Some games use the '/' path, find out what this means. if (filename.empty()) { - *out_entry_type = FileSys::EntryType::Directory; + *out_entry_type = FileSys::DirectoryEntryType::Directory; return ResultSuccess; } if (dir->GetFile(filename) != nullptr) { - *out_entry_type = FileSys::EntryType::File; + *out_entry_type = FileSys::DirectoryEntryType::File; return ResultSuccess; } if (dir->GetSubdirectory(filename) != nullptr) { - *out_entry_type = FileSys::EntryType::Directory; + *out_entry_type = FileSys::DirectoryEntryType::Directory; return ResultSuccess; } - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw( FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const { auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } - FileSys::EntryType entry_type; + FileSys::DirectoryEntryType entry_type; if (GetEntryType(&entry_type, path) != ResultSuccess) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } *out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path)); @@ -317,7 +317,7 @@ Result FileSystemController::OpenProcess( const auto it = registrations.find(process_id); if (it == registrations.end()) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } *out_program_id = it->second.program_id; @@ -347,7 +347,7 @@ std::shared_ptr<SaveDataController> FileSystemController::OpenSaveDataController std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory( ProgramId program_id) { using YuzuPath = Common::FS::YuzuPath; - const auto rw_mode = FileSys::Mode::ReadWrite; + const auto rw_mode = FileSys::OpenMode::ReadWrite; auto vfs = system.GetFilesystem(); const auto nand_directory = @@ -360,12 +360,12 @@ Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const { LOG_TRACE(Service_FS, "Opening SDMC"); if (sdmc_factory == nullptr) { - return FileSys::ERROR_SD_CARD_NOT_FOUND; + return FileSys::ResultPortSdCardNoDevice; } auto sdmc = sdmc_factory->Open(); if (sdmc == nullptr) { - return FileSys::ERROR_SD_CARD_NOT_FOUND; + return FileSys::ResultPortSdCardNoDevice; } *out_sdmc = sdmc; @@ -377,12 +377,12 @@ Result FileSystemController::OpenBISPartition(FileSys::VirtualDir* out_bis_parti LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id); if (bis_factory == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } auto part = bis_factory->OpenPartition(id); if (part == nullptr) { - return FileSys::ERROR_INVALID_ARGUMENT; + return FileSys::ResultInvalidArgument; } *out_bis_partition = part; @@ -394,12 +394,12 @@ Result FileSystemController::OpenBISPartitionStorage( LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id); if (bis_factory == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } auto part = bis_factory->OpenPartitionStorage(id, system.GetFilesystem()); if (part == nullptr) { - return FileSys::ERROR_INVALID_ARGUMENT; + return FileSys::ResultInvalidArgument; } *out_bis_partition_storage = part; @@ -686,15 +686,15 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove using YuzuPath = Common::FS::YuzuPath; const auto sdmc_dir_path = Common::FS::GetYuzuPath(YuzuPath::SDMCDir); const auto sdmc_load_dir_path = sdmc_dir_path / "atmosphere/contents"; - const auto rw_mode = FileSys::Mode::ReadWrite; + const auto rw_mode = FileSys::OpenMode::ReadWrite; auto nand_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode); auto sd_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_dir_path), rw_mode); - auto load_directory = - vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), FileSys::Mode::Read); - auto sd_load_directory = - vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), FileSys::Mode::Read); + auto load_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), + FileSys::OpenMode::Read); + auto sd_load_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), + FileSys::OpenMode::Read); auto dump_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode); 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 @@ #pragma once #include <memory> +#include <mutex> #include "common/common_types.h" -#include "core/file_sys/directory.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/fs_directory.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/result.h" namespace Core { @@ -26,7 +28,6 @@ class XCI; enum class BisPartitionId : u32; enum class ContentRecordType : u8; -enum class Mode : u32; enum class SaveDataSpaceId : u8; enum class SaveDataType : u8; enum class StorageId : u8; @@ -57,13 +58,6 @@ enum class ImageDirectoryId : u32 { SdCard, }; -enum class OpenDirectoryMode : u64 { - Directory = (1 << 0), - File = (1 << 1), - All = Directory | File -}; -DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode); - using ProcessId = u64; using ProgramId = u64; @@ -237,7 +231,7 @@ public: * @return Opened file, or error code */ Result OpenFile(FileSys::VirtualFile* out_file, const std::string& path, - FileSys::Mode mode) const; + FileSys::OpenMode mode) const; /** * Open a directory specified by its path @@ -250,7 +244,7 @@ public: * Get the type of the specified path * @return The type of the specified path or error code */ - Result GetEntryType(FileSys::EntryType* out_entry_type, const std::string& path) const; + Result GetEntryType(FileSys::DirectoryEntryType* out_entry_type, const std::string& path) const; /** * 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/savedata_factory.h" +#include "core/hle/service/filesystem/fsp/fs_i_directory.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +template <typename T> +static void BuildEntryIndex(std::vector<FileSys::DirectoryEntry>& entries, + const std::vector<T>& new_data, FileSys::DirectoryEntryType type) { + entries.reserve(entries.size() + new_data.size()); + + for (const auto& new_entry : new_data) { + auto name = new_entry->GetName(); + + if (type == FileSys::DirectoryEntryType::File && + name == FileSys::GetSaveDataSizeFileName()) { + continue; + } + + entries.emplace_back(name, static_cast<s8>(type), + type == FileSys::DirectoryEntryType::Directory ? 0 + : new_entry->GetSize()); + } +} + +IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_, + FileSys::OpenDirectoryMode mode) + : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { + static const FunctionInfo functions[] = { + {0, &IDirectory::Read, "Read"}, + {1, &IDirectory::GetEntryCount, "GetEntryCount"}, + }; + RegisterHandlers(functions); + + // TODO(DarkLordZach): Verify that this is the correct behavior. + // Build entry index now to save time later. + if (True(mode & FileSys::OpenDirectoryMode::Directory)) { + BuildEntryIndex(entries, backend->GetSubdirectories(), + FileSys::DirectoryEntryType::Directory); + } + if (True(mode & FileSys::OpenDirectoryMode::File)) { + BuildEntryIndex(entries, backend->GetFiles(), FileSys::DirectoryEntryType::File); + } +} + +void IDirectory::Read(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called."); + + // Calculate how many entries we can fit in the output buffer + const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::DirectoryEntry>(); + + // Cap at total number of entries. + const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index); + + // Determine data start and end + const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index); + const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries); + const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); + + next_entry_index += actual_entries; + + // Write the data to memory + ctx.WriteBuffer(begin, range_size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(actual_entries); +} + +void IDirectory::GetEntryCount(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + u64 count = entries.size() - next_entry_index; + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(count); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/service.h" + +namespace FileSys { +struct DirectoryEntry; +} + +namespace Service::FileSystem { + +class IDirectory final : public ServiceFramework<IDirectory> { +public: + explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, + FileSys::OpenDirectoryMode mode); + +private: + FileSys::VirtualDir backend; + std::vector<FileSys::DirectoryEntry> entries; + u64 next_entry_index = 0; + + void Read(HLERequestContext& ctx); + void GetEntryCount(HLERequestContext& ctx); +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/file_sys/errors.h" +#include "core/hle/service/filesystem/fsp/fs_i_file.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_) + : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { + static const FunctionInfo functions[] = { + {0, &IFile::Read, "Read"}, + {1, &IFile::Write, "Write"}, + {2, &IFile::Flush, "Flush"}, + {3, &IFile::SetSize, "SetSize"}, + {4, &IFile::GetSize, "GetSize"}, + {5, nullptr, "OperateRange"}, + {6, nullptr, "OperateRangeWithBuffer"}, + }; + RegisterHandlers(functions); +} + +void IFile::Read(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 option = rp.Pop<u64>(); + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length); + + // Error checking + if (length < 0) { + LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidSize); + return; + } + if (offset < 0) { + LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidOffset); + return; + } + + // Read the data from the Storage backend + std::vector<u8> output = backend->ReadBytes(length, offset); + + // Write the data to memory + ctx.WriteBuffer(output); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u64>(output.size())); +} + +void IFile::Write(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 option = rp.Pop<u64>(); + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length); + + // Error checking + if (length < 0) { + LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidSize); + return; + } + if (offset < 0) { + LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidOffset); + return; + } + + const auto data = ctx.ReadBuffer(); + + ASSERT_MSG(static_cast<s64>(data.size()) <= length, + "Attempting to write more data than requested (requested={:016X}, actual={:016X}).", + length, data.size()); + + // Write the data to the Storage backend + const auto write_size = + static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length)); + const std::size_t written = backend->Write(data.data(), write_size, offset); + + ASSERT_MSG(static_cast<s64>(written) == length, + "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length, + written); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFile::Flush(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + // Exists for SDK compatibiltity -- No need to flush file. + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFile::SetSize(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 size = rp.Pop<u64>(); + LOG_DEBUG(Service_FS, "called, size={}", size); + + backend->Resize(size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFile::GetSize(HLERequestContext& ctx) { + const u64 size = backend->GetSize(); + LOG_DEBUG(Service_FS, "called, size={}", size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(size); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/service.h" + +namespace Service::FileSystem { + +class IFile final : public ServiceFramework<IFile> { +public: + explicit IFile(Core::System& system_, FileSys::VirtualFile backend_); + +private: + FileSys::VirtualFile backend; + + void Read(HLERequestContext& ctx); + void Write(HLERequestContext& ctx); + void Flush(HLERequestContext& ctx); + void SetSize(HLERequestContext& ctx); + void GetSize(HLERequestContext& ctx); +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/string_util.h" +#include "core/hle/service/filesystem/fsp/fs_i_directory.h" +#include "core/hle/service/filesystem/fsp/fs_i_file.h" +#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) + : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( + size_)} { + static const FunctionInfo functions[] = { + {0, &IFileSystem::CreateFile, "CreateFile"}, + {1, &IFileSystem::DeleteFile, "DeleteFile"}, + {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, + {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, + {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, + {5, &IFileSystem::RenameFile, "RenameFile"}, + {6, nullptr, "RenameDirectory"}, + {7, &IFileSystem::GetEntryType, "GetEntryType"}, + {8, &IFileSystem::OpenFile, "OpenFile"}, + {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, + {10, &IFileSystem::Commit, "Commit"}, + {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"}, + {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"}, + {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, + {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, + {15, nullptr, "QueryEntry"}, + {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, + }; + RegisterHandlers(functions); +} + +void IFileSystem::CreateFile(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + const u64 file_mode = rp.Pop<u64>(); + const u32 file_size = rp.Pop<u32>(); + + LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode, + file_size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.CreateFile(name, file_size)); +} + +void IFileSystem::DeleteFile(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. file={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteFile(name)); +} + +void IFileSystem::CreateDirectory(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. directory={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.CreateDirectory(name)); +} + +void IFileSystem::DeleteDirectory(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. directory={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteDirectory(name)); +} + +void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. directory={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteDirectoryRecursively(name)); +} + +void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. Directory: {}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.CleanDirectoryRecursively(name)); +} + +void IFileSystem::RenameFile(HLERequestContext& ctx) { + const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); + const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); + + LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.RenameFile(src_name, dst_name)); +} + +void IFileSystem::OpenFile(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + const auto mode = static_cast<FileSys::OpenMode>(rp.Pop<u32>()); + + LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode); + + FileSys::VirtualFile vfs_file{}; + auto result = backend.OpenFile(&vfs_file, name, mode); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + auto file = std::make_shared<IFile>(system, vfs_file); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IFile>(std::move(file)); +} + +void IFileSystem::OpenDirectory(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>(); + + LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); + + FileSys::VirtualDir vfs_dir{}; + auto result = backend.OpenDirectory(&vfs_dir, name); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDirectory>(std::move(directory)); +} + +void IFileSystem::GetEntryType(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. file={}", name); + + FileSys::DirectoryEntryType vfs_entry_type{}; + auto result = backend.GetEntryType(&vfs_entry_type, name); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(static_cast<u32>(vfs_entry_type)); +} + +void IFileSystem::Commit(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(size.get_free_size()); +} + +void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(size.get_total_size()); +} + +void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name); + + FileSys::FileTimeStampRaw vfs_timestamp{}; + auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(ResultSuccess); + rb.PushRaw(vfs_timestamp); +} + +void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + struct FileSystemAttribute { + u8 dir_entry_name_length_max_defined; + u8 file_entry_name_length_max_defined; + u8 dir_path_name_length_max_defined; + u8 file_path_name_length_max_defined; + INSERT_PADDING_BYTES_NOINIT(0x5); + u8 utf16_dir_entry_name_length_max_defined; + u8 utf16_file_entry_name_length_max_defined; + u8 utf16_dir_path_name_length_max_defined; + u8 utf16_file_path_name_length_max_defined; + INSERT_PADDING_BYTES_NOINIT(0x18); + s32 dir_entry_name_length_max; + s32 file_entry_name_length_max; + s32 dir_path_name_length_max; + s32 file_path_name_length_max; + INSERT_PADDING_WORDS_NOINIT(0x5); + s32 utf16_dir_entry_name_length_max; + s32 utf16_file_entry_name_length_max; + s32 utf16_dir_path_name_length_max; + s32 utf16_file_path_name_length_max; + INSERT_PADDING_WORDS_NOINIT(0x18); + INSERT_PADDING_WORDS_NOINIT(0x1); + }; + static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size"); + + FileSystemAttribute savedata_attribute{}; + savedata_attribute.dir_entry_name_length_max_defined = true; + savedata_attribute.file_entry_name_length_max_defined = true; + savedata_attribute.dir_entry_name_length_max = 0x40; + savedata_attribute.file_entry_name_length_max = 0x40; + + IPC::ResponseBuilder rb{ctx, 50}; + rb.Push(ResultSuccess); + rb.PushRaw(savedata_attribute); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/fsp/fsp_util.h" +#include "core/hle/service/service.h" + +namespace Service::FileSystem { + +class IFileSystem final : public ServiceFramework<IFileSystem> { +public: + explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_); + + void CreateFile(HLERequestContext& ctx); + void DeleteFile(HLERequestContext& ctx); + void CreateDirectory(HLERequestContext& ctx); + void DeleteDirectory(HLERequestContext& ctx); + void DeleteDirectoryRecursively(HLERequestContext& ctx); + void CleanDirectoryRecursively(HLERequestContext& ctx); + void RenameFile(HLERequestContext& ctx); + void OpenFile(HLERequestContext& ctx); + void OpenDirectory(HLERequestContext& ctx); + void GetEntryType(HLERequestContext& ctx); + void Commit(HLERequestContext& ctx); + void GetFreeSpaceSize(HLERequestContext& ctx); + void GetTotalSpaceSize(HLERequestContext& ctx); + void GetFileTimeStampRaw(HLERequestContext& ctx); + void GetFileSystemAttribute(HLERequestContext& ctx); + +private: + VfsDirectoryServiceWrapper backend; + SizeGetter size; +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/file_sys/errors.h" +#include "core/hle/service/filesystem/fsp/fs_i_storage.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_) + : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { + static const FunctionInfo functions[] = { + {0, &IStorage::Read, "Read"}, + {1, nullptr, "Write"}, + {2, nullptr, "Flush"}, + {3, nullptr, "SetSize"}, + {4, &IStorage::GetSize, "GetSize"}, + {5, nullptr, "OperateRange"}, + }; + RegisterHandlers(functions); +} + +void IStorage::Read(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); + + // Error checking + if (length < 0) { + LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidSize); + return; + } + if (offset < 0) { + LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidOffset); + return; + } + + // Read the data from the Storage backend + std::vector<u8> output = backend->ReadBytes(length, offset); + // Write the data to memory + ctx.WriteBuffer(output); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IStorage::GetSize(HLERequestContext& ctx) { + const u64 size = backend->GetSize(); + LOG_DEBUG(Service_FS, "called, size={}", size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(size); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/service.h" + +namespace Service::FileSystem { + +class IStorage final : public ServiceFramework<IStorage> { +public: + explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_); + +private: + FileSys::VirtualFile backend; + + void Read(HLERequestContext& ctx); + void GetSize(HLERequestContext& ctx); +}; + +} // 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 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/hle/service/filesystem/fsp_ldr.h" +#include "core/hle/service/filesystem/fsp/fsp_ldr.h" namespace Service::FileSystem { 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 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/hle/service/filesystem/fsp_pr.h" +#include "core/hle/service/filesystem/fsp/fsp_pr.h" namespace Service::FileSystem { 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 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" -#include "core/file_sys/directory.h" #include "core/file_sys/errors.h" -#include "core/file_sys/mode.h" +#include "core/file_sys/fs_directory.h" +#include "core/file_sys/fs_filesystem.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/system_archive/system_archive.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/result.h" #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/filesystem/fsp_srv.h" +#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" +#include "core/hle/service/filesystem/fsp/fs_i_storage.h" +#include "core/hle/service/filesystem/fsp/fsp_srv.h" #include "core/hle/service/filesystem/romfs_controller.h" #include "core/hle/service/filesystem/save_data_controller.h" #include "core/hle/service/hle_ipc.h" @@ -34,19 +36,6 @@ #include "core/reporter.h" namespace Service::FileSystem { - -struct SizeGetter { - std::function<u64()> get_free_size; - std::function<u64()> get_total_size; - - static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) { - return { - [&fsc, id] { return fsc.GetFreeSpaceSize(id); }, - [&fsc, id] { return fsc.GetTotalSpaceSize(id); }, - }; - } -}; - enum class FileSystemType : u8 { Invalid0 = 0, Invalid1 = 1, @@ -58,525 +47,6 @@ enum class FileSystemType : u8 { ApplicationPackage = 7, }; -class IStorage final : public ServiceFramework<IStorage> { -public: - explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_) - : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { - static const FunctionInfo functions[] = { - {0, &IStorage::Read, "Read"}, - {1, nullptr, "Write"}, - {2, nullptr, "Flush"}, - {3, nullptr, "SetSize"}, - {4, &IStorage::GetSize, "GetSize"}, - {5, nullptr, "OperateRange"}, - }; - RegisterHandlers(functions); - } - -private: - FileSys::VirtualFile backend; - - void Read(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const s64 offset = rp.Pop<s64>(); - const s64 length = rp.Pop<s64>(); - - LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); - - // Error checking - if (length < 0) { - LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_SIZE); - return; - } - if (offset < 0) { - LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_OFFSET); - return; - } - - // Read the data from the Storage backend - std::vector<u8> output = backend->ReadBytes(length, offset); - // Write the data to memory - ctx.WriteBuffer(output); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetSize(HLERequestContext& ctx) { - const u64 size = backend->GetSize(); - LOG_DEBUG(Service_FS, "called, size={}", size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(size); - } -}; - -class IFile final : public ServiceFramework<IFile> { -public: - explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) - : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { - static const FunctionInfo functions[] = { - {0, &IFile::Read, "Read"}, - {1, &IFile::Write, "Write"}, - {2, &IFile::Flush, "Flush"}, - {3, &IFile::SetSize, "SetSize"}, - {4, &IFile::GetSize, "GetSize"}, - {5, nullptr, "OperateRange"}, - {6, nullptr, "OperateRangeWithBuffer"}, - }; - RegisterHandlers(functions); - } - -private: - FileSys::VirtualFile backend; - - void Read(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 option = rp.Pop<u64>(); - const s64 offset = rp.Pop<s64>(); - const s64 length = rp.Pop<s64>(); - - LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, - length); - - // Error checking - if (length < 0) { - LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_SIZE); - return; - } - if (offset < 0) { - LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_OFFSET); - return; - } - - // Read the data from the Storage backend - std::vector<u8> output = backend->ReadBytes(length, offset); - - // Write the data to memory - ctx.WriteBuffer(output); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(static_cast<u64>(output.size())); - } - - void Write(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 option = rp.Pop<u64>(); - const s64 offset = rp.Pop<s64>(); - const s64 length = rp.Pop<s64>(); - - LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, - length); - - // Error checking - if (length < 0) { - LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_SIZE); - return; - } - if (offset < 0) { - LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_OFFSET); - return; - } - - const auto data = ctx.ReadBuffer(); - - ASSERT_MSG( - static_cast<s64>(data.size()) <= length, - "Attempting to write more data than requested (requested={:016X}, actual={:016X}).", - length, data.size()); - - // Write the data to the Storage backend - const auto write_size = - static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length)); - const std::size_t written = backend->Write(data.data(), write_size, offset); - - ASSERT_MSG(static_cast<s64>(written) == length, - "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length, - written); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void Flush(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - // Exists for SDK compatibiltity -- No need to flush file. - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void SetSize(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 size = rp.Pop<u64>(); - LOG_DEBUG(Service_FS, "called, size={}", size); - - backend->Resize(size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetSize(HLERequestContext& ctx) { - const u64 size = backend->GetSize(); - LOG_DEBUG(Service_FS, "called, size={}", size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(size); - } -}; - -template <typename T> -static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data, - FileSys::EntryType type) { - entries.reserve(entries.size() + new_data.size()); - - for (const auto& new_entry : new_data) { - auto name = new_entry->GetName(); - - if (type == FileSys::EntryType::File && name == FileSys::GetSaveDataSizeFileName()) { - continue; - } - - entries.emplace_back(name, type, - type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize()); - } -} - -class IDirectory final : public ServiceFramework<IDirectory> { -public: - explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, OpenDirectoryMode mode) - : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { - static const FunctionInfo functions[] = { - {0, &IDirectory::Read, "Read"}, - {1, &IDirectory::GetEntryCount, "GetEntryCount"}, - }; - RegisterHandlers(functions); - - // TODO(DarkLordZach): Verify that this is the correct behavior. - // Build entry index now to save time later. - if (True(mode & OpenDirectoryMode::Directory)) { - BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory); - } - if (True(mode & OpenDirectoryMode::File)) { - BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File); - } - } - -private: - FileSys::VirtualDir backend; - std::vector<FileSys::Entry> entries; - u64 next_entry_index = 0; - - void Read(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called."); - - // Calculate how many entries we can fit in the output buffer - const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::Entry>(); - - // Cap at total number of entries. - const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index); - - // Determine data start and end - const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index); - const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries); - const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); - - next_entry_index += actual_entries; - - // Write the data to memory - ctx.WriteBuffer(begin, range_size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(actual_entries); - } - - void GetEntryCount(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - u64 count = entries.size() - next_entry_index; - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(count); - } -}; - -class IFileSystem final : public ServiceFramework<IFileSystem> { -public: - explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) - : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( - size_)} { - static const FunctionInfo functions[] = { - {0, &IFileSystem::CreateFile, "CreateFile"}, - {1, &IFileSystem::DeleteFile, "DeleteFile"}, - {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, - {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, - {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, - {5, &IFileSystem::RenameFile, "RenameFile"}, - {6, nullptr, "RenameDirectory"}, - {7, &IFileSystem::GetEntryType, "GetEntryType"}, - {8, &IFileSystem::OpenFile, "OpenFile"}, - {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, - {10, &IFileSystem::Commit, "Commit"}, - {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"}, - {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"}, - {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, - {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, - {15, nullptr, "QueryEntry"}, - {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, - }; - RegisterHandlers(functions); - } - - void CreateFile(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - const u64 file_mode = rp.Pop<u64>(); - const u32 file_size = rp.Pop<u32>(); - - LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode, - file_size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.CreateFile(name, file_size)); - } - - void DeleteFile(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. file={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.DeleteFile(name)); - } - - void CreateDirectory(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. directory={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.CreateDirectory(name)); - } - - void DeleteDirectory(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. directory={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.DeleteDirectory(name)); - } - - void DeleteDirectoryRecursively(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. directory={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.DeleteDirectoryRecursively(name)); - } - - void CleanDirectoryRecursively(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. Directory: {}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.CleanDirectoryRecursively(name)); - } - - void RenameFile(HLERequestContext& ctx) { - const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); - const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); - - LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.RenameFile(src_name, dst_name)); - } - - void OpenFile(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); - - LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode); - - FileSys::VirtualFile vfs_file{}; - auto result = backend.OpenFile(&vfs_file, name, mode); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - auto file = std::make_shared<IFile>(system, vfs_file); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IFile>(std::move(file)); - } - - void OpenDirectory(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - const auto mode = rp.PopRaw<OpenDirectoryMode>(); - - LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); - - FileSys::VirtualDir vfs_dir{}; - auto result = backend.OpenDirectory(&vfs_dir, name); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDirectory>(std::move(directory)); - } - - void GetEntryType(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. file={}", name); - - FileSys::EntryType vfs_entry_type{}; - auto result = backend.GetEntryType(&vfs_entry_type, name); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(static_cast<u32>(vfs_entry_type)); - } - - void Commit(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetFreeSpaceSize(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(size.get_free_size()); - } - - void GetTotalSpaceSize(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(size.get_total_size()); - } - - void GetFileTimeStampRaw(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name); - - FileSys::FileTimeStampRaw vfs_timestamp{}; - auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(ResultSuccess); - rb.PushRaw(vfs_timestamp); - } - - void GetFileSystemAttribute(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); - - struct FileSystemAttribute { - u8 dir_entry_name_length_max_defined; - u8 file_entry_name_length_max_defined; - u8 dir_path_name_length_max_defined; - u8 file_path_name_length_max_defined; - INSERT_PADDING_BYTES_NOINIT(0x5); - u8 utf16_dir_entry_name_length_max_defined; - u8 utf16_file_entry_name_length_max_defined; - u8 utf16_dir_path_name_length_max_defined; - u8 utf16_file_path_name_length_max_defined; - INSERT_PADDING_BYTES_NOINIT(0x18); - s32 dir_entry_name_length_max; - s32 file_entry_name_length_max; - s32 dir_path_name_length_max; - s32 file_path_name_length_max; - INSERT_PADDING_WORDS_NOINIT(0x5); - s32 utf16_dir_entry_name_length_max; - s32 utf16_file_entry_name_length_max; - s32 utf16_dir_path_name_length_max; - s32 utf16_file_path_name_length_max; - INSERT_PADDING_WORDS_NOINIT(0x18); - INSERT_PADDING_WORDS_NOINIT(0x1); - }; - static_assert(sizeof(FileSystemAttribute) == 0xc0, - "FileSystemAttribute has incorrect size"); - - FileSystemAttribute savedata_attribute{}; - savedata_attribute.dir_entry_name_length_max_defined = true; - savedata_attribute.file_entry_name_length_max_defined = true; - savedata_attribute.dir_entry_name_length_max = 0x40; - savedata_attribute.file_entry_name_length_max = 0x40; - - IPC::ResponseBuilder rb{ctx, 50}; - rb.Push(ResultSuccess); - rb.PushRaw(savedata_attribute); - } - -private: - VfsDirectoryServiceWrapper backend; - SizeGetter size; -}; - class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { public: explicit ISaveDataInfoReader(Core::System& system_, @@ -960,7 +430,7 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) { save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute); if (result != ResultSuccess) { IPC::ResponseBuilder rb{ctx, 2, 0, 0}; - rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); + rb.Push(FileSys::ResultTargetNotFound); return; } @@ -1127,7 +597,7 @@ void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); + rb.Push(FileSys::ResultTargetNotFound); } void 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/filesystem/filesystem.h" + +namespace Service::FileSystem { + +struct SizeGetter { + std::function<u64()> get_free_size; + std::function<u64()> get_total_size; + + static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) { + return { + [&fsc, id] { return fsc.GetFreeSpaceSize(id); }, + [&fsc, id] { return fsc.GetTotalSpaceSize(id); }, + }; + } +}; + +} // 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 @@ #include "core/file_sys/nca_metadata.h" #include "core/file_sys/romfs_factory.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace Service::FileSystem { 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, auto save_data = factory->Create(space, attribute); if (save_data == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } *out_save_data = save_data; @@ -56,7 +56,7 @@ Result SaveDataController::OpenSaveData(FileSys::VirtualDir* out_save_data, const FileSys::SaveDataAttribute& attribute) { auto save_data = factory->Open(space, attribute); if (save_data == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } *out_save_data = save_data; @@ -67,7 +67,7 @@ Result SaveDataController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_ FileSys::SaveDataSpaceId space) { auto save_data_space = factory->GetSaveDataSpaceDirectory(space); if (save_data_space == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } *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 @@ #include "core/file_sys/nca_metadata.h" #include "core/file_sys/savedata_factory.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace Service::FileSystem { 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 @@ #include "common/settings.h" #include "common/time_zone.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/kernel/svc.h" #include "core/hle/service/glue/time/manager.h" #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 @@ #include <string> #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" #include "core/hle/service/glue/time/file_timestamp_worker.h" #include "core/hle/service/glue/time/standard_steady_clock_resource.h" #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 @@ #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" #include "core/file_sys/system_archive/system_archive.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/glue/time/time_zone_binary.h" 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"); class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { public: explicit IJitEnvironment(Core::System& system_, - Kernel::KScopedAutoObject<Kernel::KProcess>&& process_, + Kernel::KScopedAutoObject<Kernel::KProcess> process_, CodeMemory&& user_rx_, CodeMemory&& user_ro_) : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)}, user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)}, @@ -129,7 +129,7 @@ public: Result LoadPlugin(u64 tmem_size, InCopyHandle<Kernel::KTransferMemory>& tmem, InBuffer<BufferAttr_HipcMapAlias> nrr, InBuffer<BufferAttr_HipcMapAlias> nro) { - if (tmem.IsNull()) { + if (!tmem) { LOG_ERROR(Service_JIT, "Invalid transfer memory handle!"); R_THROW(ResultUnknown); } @@ -271,15 +271,15 @@ private: u64 rx_size, u64 ro_size, InCopyHandle<Kernel::KProcess>& process, InCopyHandle<Kernel::KCodeMemory>& rx_mem, InCopyHandle<Kernel::KCodeMemory>& ro_mem) { - if (process.IsNull()) { + if (!process) { LOG_ERROR(Service_JIT, "process is null"); R_THROW(ResultUnknown); } - if (rx_mem.IsNull()) { + if (!rx_mem) { LOG_ERROR(Service_JIT, "rx_mem is null"); R_THROW(ResultUnknown); } - if (rx_mem.IsNull()) { + if (!ro_mem) { LOG_ERROR(Service_JIT, "ro_mem is null"); R_THROW(ResultUnknown); } @@ -291,8 +291,8 @@ private: R_TRY(ro.Initialize(*process, *ro_mem, ro_size, Kernel::Svc::MemoryPermission::Read, generate_random)); - *out_jit_environment = std::make_shared<IJitEnvironment>(system, std::move(process), - std::move(rx), std::move(ro)); + *out_jit_environment = + std::make_shared<IJitEnvironment>(system, process.Get(), std::move(rx), std::move(ro)); R_SUCCEED(); } 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 { return result; } - if (result.module != ErrorModule::NFC) { + if (result.GetModule() != ErrorModule::NFC) { return result; } 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 @@ #include "core/core.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/glue/glue_manager.h" #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: Result RegisterProcessHandle(ClientProcessId client_pid, InCopyHandle<Kernel::KProcess>& process) { // Register the process. - R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process.GetPointerUnsafe(), - *client_pid)); + R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process.Get(), *client_pid)); } 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 345c7ec32..e907b57b6 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& const auto ver_file = romfs->GetFile("file"); if (ver_file == nullptr) { return early_exit_failure("The system version archive didn't contain the file 'file'.", - FileSys::ERROR_INVALID_ARGUMENT); + FileSys::ResultInvalidArgument); } auto data = ver_file->ReadAllBytes(); if (data.size() != sizeof(FirmwareVersionFormat)) { return early_exit_failure("The system version file 'file' was not the correct size.", - FileSys::ERROR_OUT_OF_BOUNDS); + FileSys::ResultOutOfRange); } 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 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "core/file_sys/control_metadata.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" namespace Core { class 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 @@ #include "core/core.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/romfs_factory.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs_offset.h" #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_page_table.h" #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 auto out = json{ {"title_id", fmt::format("{:016X}", title_id)}, {"result_raw", fmt::format("{:08X}", result.raw)}, - {"result_module", fmt::format("{:08X}", static_cast<u32>(result.module.Value()))}, - {"result_description", fmt::format("{:08X}", result.description.Value())}, + {"result_module", fmt::format("{:08X}", static_cast<u32>(result.GetModule()))}, + {"result_description", fmt::format("{:08X}", result.GetDescription())}, {"timestamp", timestamp}, }; 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 @@ #include "core/core.h" #include "core/file_sys/common_funcs.h" #include "core/file_sys/content_archive.h" -#include "core/file_sys/mode.h" +#include "core/file_sys/fs_filesystem.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" @@ -159,7 +159,7 @@ inline InstallResult InstallNSP(Core::System& system, FileSys::VfsFilesystem& vf }; std::shared_ptr<FileSys::NSP> nsp; - FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::Mode::Read); + FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::OpenMode::Read); if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) { nsp = std::make_shared<FileSys::NSP>(file); if (nsp->IsExtractedType()) { @@ -224,7 +224,8 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem& vfs, const std::string& return true; }; - const auto nca = std::make_shared<FileSys::NCA>(vfs.OpenFile(filename, FileSys::Mode::Read)); + const auto nca = + std::make_shared<FileSys::NCA>(vfs.OpenFile(filename, FileSys::OpenMode::Read)); const auto id = nca->GetStatus(); // Game updates necessary are missing base RomFS @@ -345,8 +346,8 @@ inline std::vector<std::string> VerifyInstalledContents( inline GameVerificationResult VerifyGameContents( Core::System& system, const std::string& game_path, const std::function<bool(size_t, size_t)>& callback) { - const auto loader = - Loader::GetLoader(system, system.GetFilesystem()->OpenFile(game_path, FileSys::Mode::Read)); + const auto loader = Loader::GetLoader( + system, system.GetFilesystem()->OpenFile(game_path, FileSys::OpenMode::Read)); if (loader == nullptr) { return GameVerificationResult::NotImplemented; } diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp index 755f82f29..a2295219a 100644 --- a/src/hid_core/resource_manager.cpp +++ b/src/hid_core/resource_manager.cpp @@ -379,6 +379,10 @@ Result ResourceManager::SendVibrationValue(u64 aruid, device = GetNSVibrationDevice(handle); } if (device != nullptr) { + // Prevent sending vibrations to an inactive vibration handle + if (!device->IsActive()) { + return ResultSuccess; + } result = device->SendVibrationValue(value); } return result; diff --git a/src/hid_core/resources/vibration/vibration_base.cpp b/src/hid_core/resources/vibration/vibration_base.cpp index f28d30406..90bff88f4 100644 --- a/src/hid_core/resources/vibration/vibration_base.cpp +++ b/src/hid_core/resources/vibration/vibration_base.cpp @@ -23,6 +23,10 @@ Result NpadVibrationBase::Deactivate() { return ResultSuccess; } +bool NpadVibrationBase::IsActive() const { + return ref_counter > 0; +} + bool NpadVibrationBase::IsVibrationMounted() const { return is_mounted; } diff --git a/src/hid_core/resources/vibration/vibration_base.h b/src/hid_core/resources/vibration/vibration_base.h index 69c26e669..8fe35634d 100644 --- a/src/hid_core/resources/vibration/vibration_base.h +++ b/src/hid_core/resources/vibration/vibration_base.h @@ -21,6 +21,7 @@ public: virtual Result Activate(); virtual Result Deactivate(); + bool IsActive() const; bool IsVibrationMounted() const; protected: 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 { callback = std::move(finished); emit MainWindowDisplayError( tr("Error Code: %1-%2 (0x%3)") - .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) - .arg(error.description, 4, 10, QChar::fromLatin1('0')) + .arg(static_cast<u32>(error.GetModule()) + 2000, 4, 10, QChar::fromLatin1('0')) + .arg(error.GetDescription(), 4, 10, QChar::fromLatin1('0')) .arg(error.raw, 8, 16, QChar::fromLatin1('0')), tr("An error has occurred.\nPlease try again or contact the developer of the software.")); } @@ -38,8 +38,8 @@ void QtErrorDisplay::ShowErrorWithTimestamp(Result error, std::chrono::seconds t const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count()); emit MainWindowDisplayError( tr("Error Code: %1-%2 (0x%3)") - .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) - .arg(error.description, 4, 10, QChar::fromLatin1('0')) + .arg(static_cast<u32>(error.GetModule()) + 2000, 4, 10, QChar::fromLatin1('0')) + .arg(error.GetDescription(), 4, 10, QChar::fromLatin1('0')) .arg(error.raw, 8, 16, QChar::fromLatin1('0')), tr("An error occurred on %1 at %2.\nPlease try again or contact the developer of the " "software.") @@ -53,8 +53,8 @@ void QtErrorDisplay::ShowCustomErrorText(Result error, std::string dialog_text, callback = std::move(finished); emit MainWindowDisplayError( tr("Error Code: %1-%2 (0x%3)") - .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) - .arg(error.description, 4, 10, QChar::fromLatin1('0')) + .arg(static_cast<u32>(error.GetModule()) + 2000, 4, 10, QChar::fromLatin1('0')) + .arg(error.GetDescription(), 4, 10, QChar::fromLatin1('0')) .arg(error.raw, 8, 16, QChar::fromLatin1('0')), tr("An error has occurred.\n\n%1\n\n%2") .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 @@ #include <QList> #include "configuration/shared_widget.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" #include "frontend_common/config.h" #include "vk_device_info.h" #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 @@ #include <QList> -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace Core { class 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 @@ #include "core/file_sys/card_image.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/control_metadata.h" -#include "core/file_sys/mode.h" +#include "core/file_sys/fs_filesystem.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" @@ -347,7 +347,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa if (!is_dir && (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { - const auto file = vfs->OpenFile(physical_name, FileSys::Mode::Read); + const auto file = vfs->OpenFile(physical_name, FileSys::OpenMode::Read); if (!file) { return true; } 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 @@ #include "configuration/configure_per_game.h" #include "configuration/configure_tas.h" #include "core/file_sys/romfs_factory.h" -#include "core/file_sys/vfs.h" -#include "core/file_sys/vfs_real.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_real.h" #include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/general_frontend.h" @@ -56,7 +56,7 @@ // These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows // defines. static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper( - const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::Mode mode) { + const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::OpenMode mode) { return vfs->CreateDirectory(path, mode); } @@ -1880,7 +1880,7 @@ bool GMainWindow::SelectAndSetCurrentUser( void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { // Ensure all NCAs are registered before launching the game - const auto file = vfs->OpenFile(filepath, FileSys::Mode::Read); + const auto file = vfs->OpenFile(filepath, FileSys::OpenMode::Read); if (!file) { return; } @@ -2274,7 +2274,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target open_target = tr("Save Data"); const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); auto vfs_nand_dir = - vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); + vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); if (has_user_save) { // User save data @@ -2653,7 +2653,7 @@ void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& g void GMainWindow::RemoveCacheStorage(u64 program_id) { const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); auto vfs_nand_dir = - vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); + vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::CacheStorage, @@ -2673,7 +2673,8 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa "cancelled the operation.")); }; - const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); + const auto loader = + Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); if (loader == nullptr) { failed(); return; @@ -2717,7 +2718,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed}; auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false); - const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::Mode::ReadWrite); + const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::OpenMode::ReadWrite); if (out == nullptr) { failed(); @@ -3015,7 +3016,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga system->GetContentProvider()}; const auto control = pm.GetControlMetadata(); const auto loader = - Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); + Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); game_title = fmt::format("{:016X}", program_id); if (control.first != nullptr) { 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 @@ #include "core/cpu_manager.h" #include "core/crypto/key_manager.h" #include "core/file_sys/registered_cache.h" -#include "core/file_sys/vfs_real.h" +#include "core/file_sys/vfs/vfs_real.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" #include "core/telemetry_session.h" |