[VFS] Use SectorsPerCluster provided by game for cache drive.
This fixes some games (eg. Halo: CEA) not mounting cache. It seems some games use different SectorsPerClusters values, which then changes the value it expects from NtQueryVolumeInformationFile. Since we'd always respond with a static value this would make the game think that mounting failed, and it'd bail out of the cache-mounting code. Now we capture the SectorsPerCluster value when the game writes it to the cache-partition header, and update the NullDevice's sectors_per_allocation_unit with it.
This commit is contained in:
parent
7446d74ac4
commit
55ce179ff2
|
@ -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<Entry> root_entry_;
|
||||
std::vector<std::string> null_paths_;
|
||||
|
||||
uint32_t sectors_per_allocation_unit_ = 0x80;
|
||||
};
|
||||
|
||||
} // namespace vfs
|
||||
|
|
|
@ -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<uint32_t>(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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue