[Kernel/VFS] Ensure vfs::Entry is up-to-date before retrieving file information
Games like Forza use NtQueryInformationFile to get the size of the file, to make sure that there's enough room inside it to write data. Previously, updating the file size (via SetInfoFile(EndOfFile) or WriteFile) wouldn't update the vfs::Entry size field, which NtQueryInfo uses to return the size of the file. This resulted in the game thinking that the file was smaller than it actually is, and trying to correct that by using SetInfoFile(EndOfFile), which then truncated the file and deleted important data that was written to it.
This commit is contained in:
parent
06cacbb9af
commit
f46e3c7e39
|
@ -402,6 +402,9 @@ dword_result_t NtSetInformationFile(
|
|||
assert_true(length == 8);
|
||||
auto eof = xe::load_and_swap<uint64_t>(file_info);
|
||||
result = file->SetLength(eof);
|
||||
|
||||
// Update the files vfs::Entry information
|
||||
file->entry()->update();
|
||||
break;
|
||||
}
|
||||
case XFileCompletionInformation: {
|
||||
|
@ -485,6 +488,11 @@ dword_result_t NtQueryInformationFile(
|
|||
// };
|
||||
assert_true(length == 56);
|
||||
|
||||
// Make sure we're working with up-to-date information, just in case the
|
||||
// file size has changed via something other than NtSetInfoFile
|
||||
// (eg. seems NtWriteFile might extend the file in some cases)
|
||||
file->entry()->update();
|
||||
|
||||
auto file_info = file_info_ptr.as<X_FILE_NETWORK_OPEN_INFORMATION*>();
|
||||
file_info->creation_time = file->entry()->create_timestamp();
|
||||
file_info->last_access_time = file->entry()->access_timestamp();
|
||||
|
|
|
@ -104,5 +104,17 @@ bool HostPathEntry::DeleteEntryInternal(Entry* entry) {
|
|||
}
|
||||
}
|
||||
|
||||
void HostPathEntry::update() {
|
||||
xe::filesystem::FileInfo file_info;
|
||||
if (!xe::filesystem::GetInfo(local_path_, &file_info)) {
|
||||
return;
|
||||
}
|
||||
if (file_info.type == xe::filesystem::FileInfo::Type::kFile) {
|
||||
size_ = file_info.total_size;
|
||||
allocation_size_ =
|
||||
xe::round_up(file_info.total_size, device()->bytes_per_sector());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace vfs
|
||||
} // namespace xe
|
||||
|
|
|
@ -38,6 +38,7 @@ class HostPathEntry : public Entry {
|
|||
std::unique_ptr<MappedMemory> OpenMapped(MappedMemory::Mode mode,
|
||||
size_t offset,
|
||||
size_t length) override;
|
||||
void update() override;
|
||||
|
||||
private:
|
||||
friend class HostPathDevice;
|
||||
|
|
|
@ -120,6 +120,7 @@ class Entry {
|
|||
size_t length = 0) {
|
||||
return nullptr;
|
||||
}
|
||||
virtual void update() { return; }
|
||||
|
||||
protected:
|
||||
Entry(Device* device, Entry* parent, const std::string& path);
|
||||
|
|
Loading…
Reference in New Issue