[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
a303eb7866
commit
dc25bf5961
|
@ -34,13 +34,23 @@ class NullDevice : public Device {
|
||||||
uint32_t total_allocation_units() const override { return 128 * 1024; }
|
uint32_t total_allocation_units() const override { return 128 * 1024; }
|
||||||
uint32_t available_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!
|
// STFC/cache code seems to require the product of these two to equal 0x10000
|
||||||
uint32_t sectors_per_allocation_unit() const override { return 1; }
|
// or 0x8000! (depending on SectorsPerCluster value written to partition
|
||||||
uint32_t bytes_per_sector() const override { return 0x10000; }
|
// 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:
|
private:
|
||||||
std::unique_ptr<Entry> root_entry_;
|
std::unique_ptr<Entry> root_entry_;
|
||||||
std::vector<std::string> null_paths_;
|
std::vector<std::string> null_paths_;
|
||||||
|
|
||||||
|
uint32_t sectors_per_allocation_unit_ = 0x80;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace vfs
|
} // namespace vfs
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "xenia/vfs/devices/null_file.h"
|
#include "xenia/vfs/devices/null_file.h"
|
||||||
|
|
||||||
|
#include "xenia/vfs/devices/null_device.h"
|
||||||
#include "xenia/vfs/devices/null_entry.h"
|
#include "xenia/vfs/devices/null_entry.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -37,6 +38,20 @@ X_STATUS NullFile::WriteSync(const void* buffer, size_t buffer_length,
|
||||||
return X_STATUS_ACCESS_DENIED;
|
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;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue