diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index cca28982f41..87b5aab8a93 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -316,6 +316,7 @@ X_STATUS Emulator::LaunchXexFile(const std::filesystem::path& path) { // Create symlinks to the device. file_system_->RegisterSymbolicLink("game:", mount_path); + file_system_->RegisterSymbolicLink("update:", mount_path); file_system_->RegisterSymbolicLink("d:", mount_path); // Get just the filename (foo.xex). @@ -342,6 +343,7 @@ X_STATUS Emulator::LaunchDiscImage(const std::filesystem::path& path) { // Create symlinks to the device. file_system_->RegisterSymbolicLink("game:", mount_path); + file_system_->RegisterSymbolicLink("update:", mount_path); file_system_->RegisterSymbolicLink("d:", mount_path); // Launch the game. @@ -365,6 +367,7 @@ X_STATUS Emulator::LaunchStfsContainer(const std::filesystem::path& path) { } file_system_->RegisterSymbolicLink("game:", mount_path); + file_system_->RegisterSymbolicLink("update:", mount_path); file_system_->RegisterSymbolicLink("d:", mount_path); // Launch the game. diff --git a/src/xenia/kernel/xam/content_manager.cc b/src/xenia/kernel/xam/content_manager.cc index 883020ce949..4bbc3639943 100644 --- a/src/xenia/kernel/xam/content_manager.cc +++ b/src/xenia/kernel/xam/content_manager.cc @@ -18,7 +18,7 @@ #include "xenia/kernel/xfile.h" #include "xenia/kernel/xobject.h" #include "xenia/vfs/devices/host_path_device.h" - +#include "xenia/vfs/devices/stfs_container_device.h" namespace xe { namespace kernel { namespace xam { @@ -32,14 +32,21 @@ static int content_device_id_ = 0; ContentPackage::ContentPackage(KernelState* kernel_state, const std::string_view root_name, const XCONTENT_AGGREGATE_DATA& data, - const std::filesystem::path& package_path) + const std::filesystem::path& package_path, + bool stfs) : kernel_state_(kernel_state), root_name_(root_name) { device_path_ = fmt::format("\\Device\\Content\\{0}\\", ++content_device_id_); content_data_ = data; auto fs = kernel_state_->file_system(); - auto device = - std::make_unique(device_path_, package_path, false); + std::unique_ptr device; + if (stfs) + device = + std::make_unique(device_path_, package_path); + else + device = std::make_unique(device_path_, package_path, + false); + device->Initialize(); fs->RegisterDevice(std::move(device)); fs->RegisterSymbolicLink(root_name_ + ":", device_path_); @@ -153,6 +160,49 @@ X_RESULT ContentManager::CreateContent(const std::string_view root_name, return X_ERROR_SUCCESS; } +// saves content from vfs to host +// if successful, initlisised data thats passed. +X_RESULT ContentManager::MountContentToHost(const std::string_view vpath, + const std::string_view root_name, + XCONTENT_AGGREGATE_DATA& data) { + data.content_type = + XContentType::kAvatarItem; //? this is what velocity says for + // Database,NuiIdentity + data.device_id = 4; // DeviceType::ODD; + data.set_display_name(to_utf16(root_name)); + data.title_id = kernel_state_->title_id(); + data.set_file_name(root_name); + + auto path = ResolvePackagePath(data); + if (!std::filesystem::exists(path)) { + std::filesystem::create_directories(path.parent_path()); + auto fs = kernel_state_->file_system(); + auto hostfile = xe::filesystem::OpenFile(path, "wb"); + xe::vfs::FileAction action; + xe::vfs::File* guestFile; + fs->OpenFile(nullptr, vpath, xe::vfs::FileDisposition::kOpen, + xe::vfs::FileAccess::kGenericRead, false, true, &guestFile, + &action); + + auto size = guestFile->entry()->size(); + std::vector buffer(size); + size_t read; + guestFile->ReadSync(buffer.data(), size, 0, &read); + fwrite(buffer.data(), 1, size, hostfile); + fclose(hostfile); + } + if (open_packages_.count(string_key(root_name))) { + return X_ERROR_ALREADY_EXISTS; + } + auto global_lock = global_critical_region_.Acquire(); + + auto package = std::make_unique(kernel_state_, root_name, + data, path, true); + open_packages_.insert({string_key::create(root_name), package.release()}); + + return X_E_SUCCESS; +} + X_RESULT ContentManager::OpenContent(const std::string_view root_name, const XCONTENT_AGGREGATE_DATA& data) { auto global_lock = global_critical_region_.Acquire(); diff --git a/src/xenia/kernel/xam/content_manager.h b/src/xenia/kernel/xam/content_manager.h index 0db9f0cb5e5..bc81b7d8329 100644 --- a/src/xenia/kernel/xam/content_manager.h +++ b/src/xenia/kernel/xam/content_manager.h @@ -19,6 +19,7 @@ #include "xenia/base/mutex.h" #include "xenia/base/string_key.h" #include "xenia/base/string_util.h" +#include "xenia/vfs/devices/host_path_device.h" #include "xenia/xbox.h" namespace xe { @@ -121,7 +122,7 @@ class ContentPackage { public: ContentPackage(KernelState* kernel_state, const std::string_view root_name, const XCONTENT_AGGREGATE_DATA& data, - const std::filesystem::path& package_path); + const std::filesystem::path& package_path, bool stfs = false); ~ContentPackage(); const XCONTENT_AGGREGATE_DATA& GetPackageContentData() const { @@ -151,6 +152,9 @@ class ContentManager { bool ContentExists(const XCONTENT_AGGREGATE_DATA& data); X_RESULT CreateContent(const std::string_view root_name, const XCONTENT_AGGREGATE_DATA& data); + X_RESULT MountContentToHost(const std::string_view vpath, + const std::string_view root_name, + XCONTENT_AGGREGATE_DATA& data); X_RESULT OpenContent(const std::string_view root_name, const XCONTENT_AGGREGATE_DATA& data); X_RESULT CloseContent(const std::string_view root_name); diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index 0fe3cc5bb32..7a817b91d5f 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -259,8 +259,10 @@ dword_result_t XamContentOpenFile_entry(dword_t user_index, lpdword_t disposition_ptr, lpdword_t license_mask_ptr, lpvoid_t overlapped_ptr) { - // TODO(gibbed): arguments assumed based on XamContentCreate. - return X_ERROR_FILE_NOT_FOUND; + auto content_manager = kernel_state()->content_manager(); + XCONTENT_AGGREGATE_DATA data; + return content_manager->MountContentToHost(path.value(), root_name.value(), + data); } DECLARE_XAM_EXPORT1(XamContentOpenFile, kContent, kStub);