[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);
|
assert_true(length == 8);
|
||||||
auto eof = xe::load_and_swap<uint64_t>(file_info);
|
auto eof = xe::load_and_swap<uint64_t>(file_info);
|
||||||
result = file->SetLength(eof);
|
result = file->SetLength(eof);
|
||||||
|
|
||||||
|
// Update the files vfs::Entry information
|
||||||
|
file->entry()->update();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case XFileCompletionInformation: {
|
case XFileCompletionInformation: {
|
||||||
|
@ -485,6 +488,11 @@ dword_result_t NtQueryInformationFile(
|
||||||
// };
|
// };
|
||||||
assert_true(length == 56);
|
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*>();
|
auto file_info = file_info_ptr.as<X_FILE_NETWORK_OPEN_INFORMATION*>();
|
||||||
file_info->creation_time = file->entry()->create_timestamp();
|
file_info->creation_time = file->entry()->create_timestamp();
|
||||||
file_info->last_access_time = file->entry()->access_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 vfs
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -38,6 +38,7 @@ class HostPathEntry : public Entry {
|
||||||
std::unique_ptr<MappedMemory> OpenMapped(MappedMemory::Mode mode,
|
std::unique_ptr<MappedMemory> OpenMapped(MappedMemory::Mode mode,
|
||||||
size_t offset,
|
size_t offset,
|
||||||
size_t length) override;
|
size_t length) override;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class HostPathDevice;
|
friend class HostPathDevice;
|
||||||
|
|
|
@ -120,6 +120,7 @@ class Entry {
|
||||||
size_t length = 0) {
|
size_t length = 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
virtual void update() { return; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Entry(Device* device, Entry* parent, const std::string& path);
|
Entry(Device* device, Entry* parent, const std::string& path);
|
||||||
|
|
Loading…
Reference in New Issue