[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:
emoose 2019-08-18 05:18:16 +01:00 committed by Rick Gibbed
parent 06cacbb9af
commit f46e3c7e39
4 changed files with 22 additions and 0 deletions

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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);