[VFS] Clear out cache partition when game writes FATX header
Writing FATX header likely means the game is trying to format it, so we'll help it along by deleting the contents too. HostPathDevice actually loads in all the file entries when its first inited though, so we also have to re-init the HostPathDevice for the cache partition too :/
This commit is contained in:
parent
e62ac39d4b
commit
ef6e0a32c3
|
@ -20,6 +20,7 @@
|
|||
#include "xenia/emulator.h"
|
||||
#include "xenia/ui/file_picker.h"
|
||||
#include "xenia/vfs/devices/host_path_device.h"
|
||||
#include "xenia/vfs/devices/null_device.h"
|
||||
|
||||
// Available audio systems:
|
||||
#include "xenia/apu/nop/nop_audio_system.h"
|
||||
|
@ -273,6 +274,9 @@ int xenia_main(const std::vector<std::wstring>& args) {
|
|||
}
|
||||
|
||||
if (cvars::mount_cache) {
|
||||
// NOTE: make sure to update null_file.cc if changing the local paths of
|
||||
// cache!
|
||||
|
||||
auto cache0_device =
|
||||
std::make_unique<xe::vfs::HostPathDevice>("\\CACHE0", L"cache0", false);
|
||||
if (!cache0_device->Initialize()) {
|
||||
|
@ -297,6 +301,17 @@ int xenia_main(const std::vector<std::wstring>& args) {
|
|||
emulator->file_system()->RegisterSymbolicLink("cache1:", "\\CACHE1");
|
||||
}
|
||||
}
|
||||
|
||||
// Below are accessed directly by STFC/cache code baked into the game
|
||||
// By using a NullDevice that just returns success to all IO requests, the
|
||||
// cache code should hopefully progress without erroring out
|
||||
auto null_files = {std::string("\\Partition0"), std::string("\\Cache0"),
|
||||
std::string("\\Cache1")};
|
||||
auto null_device = std::make_unique<vfs::NullDevice>(
|
||||
"\\Device\\Harddisk0", null_files, emulator->file_system());
|
||||
if (null_device->Initialize()) {
|
||||
emulator->file_system()->RegisterDevice(std::move(null_device));
|
||||
}
|
||||
}
|
||||
|
||||
// Set a debug handler.
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include "xenia/ui/imgui_dialog.h"
|
||||
#include "xenia/vfs/devices/disc_image_device.h"
|
||||
#include "xenia/vfs/devices/host_path_device.h"
|
||||
#include "xenia/vfs/devices/null_device.h"
|
||||
#include "xenia/vfs/devices/stfs_container_device.h"
|
||||
#include "xenia/vfs/virtual_file_system.h"
|
||||
|
||||
|
@ -658,19 +657,6 @@ std::string Emulator::FindLaunchModule() {
|
|||
|
||||
X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
|
||||
const std::string& module_path) {
|
||||
if (cvars::mount_cache) {
|
||||
// Below are accessed directly by STFC/cache code baked into the game
|
||||
// By using a NullDevice that just returns success to all IO requests, the
|
||||
// cache code should hopefully progress without erroring out
|
||||
auto null_files = {std::string("\\Partition0"), std::string("\\Cache0"),
|
||||
std::string("\\Cache1")};
|
||||
auto null_device =
|
||||
std::make_unique<vfs::NullDevice>("\\Device\\Harddisk0", null_files);
|
||||
if (null_device->Initialize()) {
|
||||
file_system_->RegisterDevice(std::move(null_device));
|
||||
}
|
||||
}
|
||||
|
||||
// Reset state.
|
||||
title_id_ = 0;
|
||||
game_title_ = L"";
|
||||
|
|
|
@ -19,8 +19,9 @@ namespace xe {
|
|||
namespace vfs {
|
||||
|
||||
NullDevice::NullDevice(const std::string& mount_path,
|
||||
const std::initializer_list<std::string>& null_paths)
|
||||
: Device(mount_path), null_paths_(null_paths) {}
|
||||
const std::initializer_list<std::string>& null_paths,
|
||||
VirtualFileSystem* vfs)
|
||||
: Device(mount_path), null_paths_(null_paths), vfs_(vfs) {}
|
||||
|
||||
NullDevice::~NullDevice() = default;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "xenia/vfs/device.h"
|
||||
#include "xenia/vfs/virtual_file_system.h"
|
||||
|
||||
namespace xe {
|
||||
namespace vfs {
|
||||
|
@ -22,7 +23,8 @@ class NullEntry;
|
|||
class NullDevice : public Device {
|
||||
public:
|
||||
NullDevice(const std::string& mount_path,
|
||||
const std::initializer_list<std::string>& null_paths);
|
||||
const std::initializer_list<std::string>& null_paths,
|
||||
VirtualFileSystem* vfs);
|
||||
~NullDevice() override;
|
||||
|
||||
bool Initialize() override;
|
||||
|
@ -46,11 +48,15 @@ class NullDevice : public Device {
|
|||
sectors_per_allocation_unit_ = value;
|
||||
}
|
||||
|
||||
VirtualFileSystem* vfs() { return vfs_; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<Entry> root_entry_;
|
||||
std::vector<std::string> null_paths_;
|
||||
|
||||
uint32_t sectors_per_allocation_unit_ = 0x80;
|
||||
|
||||
VirtualFileSystem* vfs_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace vfs
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
#include "xenia/vfs/devices/null_file.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/vfs/devices/null_device.h"
|
||||
#include "xenia/vfs/devices/null_entry.h"
|
||||
|
||||
|
@ -46,9 +49,37 @@ X_STATUS NullFile::WriteSync(const void* buffer, size_t buffer_length,
|
|||
// Game will try reading this back through NtQueryVolumeInformationFile
|
||||
// later on, if it doesn't match, cache partition mount won't succeed
|
||||
auto sectors_per_cluster = xe::byte_swap(header[2]);
|
||||
|
||||
// Update NullDevice with the SectorsPerCluster value
|
||||
auto* null_device = (NullDevice*)entry_->device();
|
||||
null_device->sectors_per_allocation_unit(sectors_per_cluster);
|
||||
|
||||
// Since the game is trying to remake the FATX header (in other words,
|
||||
// formatting the partition), we'll clear out the folder for this
|
||||
// partition
|
||||
auto folder_name = entry_->name();
|
||||
std::transform(folder_name.begin(), folder_name.end(),
|
||||
folder_name.begin(), tolower);
|
||||
|
||||
// TODO: this works because atm cache0/cache1 folders are in same folder
|
||||
// as xenia.exe, if that changes we should update this code too!
|
||||
auto files = xe::filesystem::ListFiles(xe::to_wstring(folder_name));
|
||||
for (auto file : files) {
|
||||
auto filepath = xe::join_paths(file.path, file.name);
|
||||
if (file.type == xe::filesystem::FileInfo::Type::kDirectory) {
|
||||
xe::filesystem::DeleteFolder(filepath);
|
||||
} else {
|
||||
xe::filesystem::DeleteFile(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
// Now re-init the device for this cache partition
|
||||
// (otherwise device will think it has files that don't actually exist)
|
||||
auto* device_root =
|
||||
null_device->vfs()->ResolveDevice("\\" + folder_name + "\\");
|
||||
if (device_root) {
|
||||
device_root->device()->Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue