diff --git a/src/xenia/vfs/devices/null_device.h b/src/xenia/vfs/devices/null_device.h index 0a87e739f..dd5719392 100644 --- a/src/xenia/vfs/devices/null_device.h +++ b/src/xenia/vfs/devices/null_device.h @@ -34,13 +34,23 @@ class NullDevice : public Device { uint32_t total_allocation_units() const override { return 128 * 1024; } uint32_t available_allocation_units() const override { return 128 * 1024; } - // STFC/cache code seems to require the product of these two to equal 0x10000! - uint32_t sectors_per_allocation_unit() const override { return 1; } - uint32_t bytes_per_sector() const override { return 0x10000; } + // STFC/cache code seems to require the product of these two to equal 0x10000 + // or 0x8000! (depending on SectorsPerCluster value written to partition + // header) + uint32_t sectors_per_allocation_unit() const override { + return sectors_per_allocation_unit_; + } + uint32_t bytes_per_sector() const override { return 512; } + + void sectors_per_allocation_unit(uint32_t value) { + sectors_per_allocation_unit_ = value; + } private: std::unique_ptr root_entry_; std::vector null_paths_; + + uint32_t sectors_per_allocation_unit_ = 0x80; }; } // namespace vfs diff --git a/src/xenia/vfs/devices/null_file.cc b/src/xenia/vfs/devices/null_file.cc index b26a4b6cf..85e3b9381 100644 --- a/src/xenia/vfs/devices/null_file.cc +++ b/src/xenia/vfs/devices/null_file.cc @@ -9,6 +9,7 @@ #include "xenia/vfs/devices/null_file.h" +#include "xenia/vfs/devices/null_device.h" #include "xenia/vfs/devices/null_entry.h" namespace xe { @@ -37,6 +38,20 @@ X_STATUS NullFile::WriteSync(const void* buffer, size_t buffer_length, return X_STATUS_ACCESS_DENIED; } + // Check if game is writing a FATX header... + if (byte_offset == 0 && buffer_length >= (4 * 3)) { + auto* header = (uint32_t*)buffer; + if (xe::load_and_swap(header) == 0x58544146) { + // This is a FATX header - read the SectorsPerCluster value from it + // 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); + } + } + return X_STATUS_SUCCESS; }