diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index c0ad9655f..012b81797 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -569,7 +569,8 @@ X_STATUS Emulator::LaunchXexFile(const std::filesystem::path& path) { auto file_name = path.filename(); // Launch the game. - auto fs_path = "game:\\" + xe::path_to_utf8(file_name); + auto fs_path = fmt::format("{}\\", kDefaultGameSymbolicLink) + + xe::path_to_utf8(file_name); X_STATUS result = CompleteLaunch(path, fs_path); if (XFAILED(result)) { @@ -585,9 +586,9 @@ X_STATUS Emulator::LaunchXexFile(const std::filesystem::path& path) { const std::string mount_path = utf8::find_base_guest_path(kernel_state_->GetExecutableModule()->path()); - // System related symlinks - file_system_->RegisterSymbolicLink("media:", mount_path); - file_system_->RegisterSymbolicLink("font:", mount_path); + // System related symlinks. This should point to dashboard location in the + // future. + file_system_->RegisterSymbolicLink("\\SystemRoot", mount_path); auto module = kernel_state_->LoadUserModule("xam.xex"); @@ -1378,7 +1379,7 @@ void Emulator::RemoveGameConfigLoadCallback(GameConfigLoadCallback* callback) { } std::string Emulator::FindLaunchModule() { - std::string path("game:\\"); + std::string path(fmt::format("{}\\", kDefaultGameSymbolicLink)); auto xam = kernel_state()->GetKernelModule("xam.xex"); diff --git a/src/xenia/emulator.h b/src/xenia/emulator.h index c98440daf..f6c94536e 100644 --- a/src/xenia/emulator.h +++ b/src/xenia/emulator.h @@ -58,6 +58,7 @@ namespace xe { constexpr fourcc_t kEmulatorSaveSignature = make_fourcc("XSAV"); static constexpr std::string_view kDefaultGameSymbolicLink = "GAME:"; static constexpr std::string_view kDefaultPartitionSymbolicLink = "D:"; +static constexpr std::string_view kDefaultUpdateSymbolicLink = "UPDATE:"; // The main type that runs the whole emulator. // This is responsible for initializing and managing all the various subsystems. diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index e331dfa32..e7a646674 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -621,7 +621,7 @@ const object_ref KernelState::LoadTitleUpdate( "UPDATE", 0, *title_update, content_license, disc_number); std::string mount_path = ""; - if (!file_system()->FindSymbolicLink("game:", mount_path)) { + if (!file_system()->FindSymbolicLink(kDefaultGameSymbolicLink, mount_path)) { return nullptr; } @@ -630,7 +630,8 @@ const object_ref KernelState::LoadTitleUpdate( } std::string resolved_path = ""; - if (!file_system()->FindSymbolicLink("UPDATE:", resolved_path)) { + if (!file_system()->FindSymbolicLink(kDefaultUpdateSymbolicLink, + resolved_path)) { return nullptr; } diff --git a/src/xenia/kernel/xam/content_manager.cc b/src/xenia/kernel/xam/content_manager.cc index f3d49625a..e91608fc0 100644 --- a/src/xenia/kernel/xam/content_manager.cc +++ b/src/xenia/kernel/xam/content_manager.cc @@ -251,8 +251,8 @@ std::vector ContentManager::ListContentODD( fmt::format("{:08X}", static_cast(content_type)); const std::filesystem::path game_content_path = - std::filesystem::path("GAME:") / "content" / xuid_str / title_id_str / - content_type_str; + std::filesystem::path(kDefaultGameSymbolicLink) / "content" / xuid_str / + title_id_str / content_type_str; auto entry = kernel_state_->file_system()->ResolvePath( xe::path_to_utf8(game_content_path)); diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index 76af1ce39..c7e48da4e 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -244,6 +244,16 @@ dword_result_t xeXamContentCreate(dword_t user_index, lpstring_t root_name, return X_ERROR_INVALID_NAME; } + // Check if we have something under provided symlink. + std::string symlink_path = root_name.value(); + if (!symlink_path.ends_with(':')) { + symlink_path += ':'; + } + + if (kernel_state()->file_system()->IsSymbolicLinkRegistered(symlink_path)) { + return X_ERROR_INVALID_PARAMETER; + } + XCONTENT_AGGREGATE_DATA content_data; if (content_data_size == sizeof(XCONTENT_DATA)) { content_data = *content_data_ptr.as(); diff --git a/src/xenia/kernel/xam/xam_content_aggregate.cc b/src/xenia/kernel/xam/xam_content_aggregate.cc index 539b0c431..ad7d5fb45 100644 --- a/src/xenia/kernel/xam/xam_content_aggregate.cc +++ b/src/xenia/kernel/xam/xam_content_aggregate.cc @@ -26,7 +26,7 @@ namespace xam { void AddODDContentTest(object_ref> e, XContentType content_type) { auto root_entry = kernel_state()->file_system()->ResolvePath( - "game:\\Content\\0000000000000000"); + "GAME:\\Content\\0000000000000000"); if (!root_entry) { return; } diff --git a/src/xenia/kernel/xam/xam_module.cc b/src/xenia/kernel/xam/xam_module.cc index 9a85f544c..7d9cca515 100644 --- a/src/xenia/kernel/xam/xam_module.cc +++ b/src/xenia/kernel/xam/xam_module.cc @@ -116,8 +116,8 @@ void XamModule::SaveLoaderData() { } }; - remove_prefix("game:\\"); - remove_prefix("d:\\"); + remove_prefix(fmt::format("{}\\", kDefaultGameSymbolicLink)); + remove_prefix(fmt::format("{}\\", kDefaultPartitionSymbolicLink)); if (host_path.extension() == ".xex") { host_path.remove_filename(); diff --git a/src/xenia/vfs/virtual_file_system.cc b/src/xenia/vfs/virtual_file_system.cc index e0906502c..01ca0dd8c 100644 --- a/src/xenia/vfs/virtual_file_system.cc +++ b/src/xenia/vfs/virtual_file_system.cc @@ -56,6 +56,15 @@ bool VirtualFileSystem::UnregisterDevice(const std::string_view path) { bool VirtualFileSystem::RegisterSymbolicLink(const std::string_view path, const std::string_view target) { auto global_lock = global_critical_region_.Acquire(); + auto it = std::find_if( + symlinks_.cbegin(), symlinks_.cend(), + [&](const auto& s) { return xe::utf8::equal_case(path, s.first); }); + if (it != symlinks_.end()) { + XELOGE("Trying to re-register already registered symbolic link: {} => {}", + path, target); + return false; + } + symlinks_.insert({std::string(path), std::string(target)}); XELOGD("Registered symbolic link: {} => {}", path, target); @@ -76,6 +85,14 @@ bool VirtualFileSystem::UnregisterSymbolicLink(const std::string_view path) { return true; } +bool VirtualFileSystem::IsSymbolicLinkRegistered(const std::string_view path) { + auto it = std::find_if( + symlinks_.cbegin(), symlinks_.cend(), + [&](const auto& s) { return xe::utf8::equal_case(path, s.first); }); + + return it != symlinks_.cend(); +} + bool VirtualFileSystem::FindSymbolicLink(const std::string_view path, std::string& target) { auto it = std::find_if( diff --git a/src/xenia/vfs/virtual_file_system.h b/src/xenia/vfs/virtual_file_system.h index df3271b59..e51b18566 100644 --- a/src/xenia/vfs/virtual_file_system.h +++ b/src/xenia/vfs/virtual_file_system.h @@ -36,6 +36,7 @@ class VirtualFileSystem { bool RegisterSymbolicLink(const std::string_view path, const std::string_view target); bool UnregisterSymbolicLink(const std::string_view path); + bool IsSymbolicLinkRegistered(const std::string_view path); bool FindSymbolicLink(const std::string_view path, std::string& target); Entry* ResolvePath(const std::string_view path);