From b5a0f731132dc6f3b5916ecd3c07a9b0dbf829ab Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 8 Feb 2025 12:47:20 +0100 Subject: [PATCH] Fix path syscalls --- src/common/platform/unicode.hpp | 5 + .../devices/mount_point_manager.cpp | 69 +++++++++ .../devices/mount_point_manager.hpp | 4 + src/windows-emulator/io_device.cpp | 6 + src/windows-emulator/syscalls.cpp | 137 ++++++++++++------ src/windows-emulator/windows_path.hpp | 29 ++++ 6 files changed, 206 insertions(+), 44 deletions(-) create mode 100644 src/windows-emulator/devices/mount_point_manager.cpp create mode 100644 src/windows-emulator/devices/mount_point_manager.hpp diff --git a/src/common/platform/unicode.hpp b/src/common/platform/unicode.hpp index b5a895e1..e232958a 100644 --- a/src/common/platform/unicode.hpp +++ b/src/common/platform/unicode.hpp @@ -11,6 +11,11 @@ struct UNICODE_STRING EMULATOR_CAST(typename Traits::PVOID, char16_t*) Buffer; }; +inline std::u16string u8_to_u16(const std::string_view view) +{ + return std::u16string(view.begin(), view.end()); +} + inline std::string u16_to_u8(const std::u16string_view u16_view) { std::string utf8_str; diff --git a/src/windows-emulator/devices/mount_point_manager.cpp b/src/windows-emulator/devices/mount_point_manager.cpp new file mode 100644 index 00000000..918ff081 --- /dev/null +++ b/src/windows-emulator/devices/mount_point_manager.cpp @@ -0,0 +1,69 @@ +#include "mount_point_manager.hpp" + +#include "../windows_emulator.hpp" + +namespace +{ + struct mount_point_manager : stateless_device + { + NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& c) override + { + if (c.io_control_code != 0x6D0030) + { + return STATUS_NOT_SUPPORTED; + } + + if (c.input_buffer_length < 2) + { + return STATUS_NOT_SUPPORTED; + } + + const auto data = win_emu.emu().read_memory(c.input_buffer, c.input_buffer_length); + + const std::u16string_view file(reinterpret_cast(data.data()), (data.size() / 2) - 1); + + constexpr std::u16string_view volume_prefix = u".\\Device\\HarddiskVolume"; + if (!file.starts_with(volume_prefix)) + { + return STATUS_NOT_SUPPORTED; + } + + const auto drive_number = file.substr(volume_prefix.size()); + const auto drive_number_u8 = u16_to_u8(drive_number); + const auto drive_letter = static_cast('A' + atoi(drive_number_u8.c_str()) - 1); + + std::string response{}; + response.push_back(drive_letter); + response.push_back(':'); + response.push_back(0); + response.push_back(0); + + const auto u16_response = u8_to_u16(response); + + const auto length = static_cast(u16_response.size() * 2); + const auto total_length = sizeof(length) + length; + + if (c.io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = total_length; + c.io_status_block.write(block); + } + + if (c.output_buffer_length < total_length) + { + return STATUS_BUFFER_OVERFLOW; + } + + win_emu.emu().write_memory(c.output_buffer, length); + win_emu.emu().write_memory(c.output_buffer + sizeof(length), u16_response.data(), length); + + return STATUS_SUCCESS; + } + }; +} + +std::unique_ptr create_mount_point_manager() +{ + return std::make_unique(); +} diff --git a/src/windows-emulator/devices/mount_point_manager.hpp b/src/windows-emulator/devices/mount_point_manager.hpp new file mode 100644 index 00000000..9df80805 --- /dev/null +++ b/src/windows-emulator/devices/mount_point_manager.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "../io_device.hpp" + +std::unique_ptr create_mount_point_manager(); diff --git a/src/windows-emulator/io_device.cpp b/src/windows-emulator/io_device.cpp index 363bfed4..2cc9e87a 100644 --- a/src/windows-emulator/io_device.cpp +++ b/src/windows-emulator/io_device.cpp @@ -1,5 +1,6 @@ #include "io_device.hpp" #include "devices/afd_endpoint.hpp" +#include "devices/mount_point_manager.hpp" namespace { @@ -28,5 +29,10 @@ std::unique_ptr create_device(const std::u16string_view device) return create_afd_endpoint(); } + if (device == u"MountPointManager") + { + return create_mount_point_manager(); + } + throw std::runtime_error("Unsupported device: " + u16_to_u8(device)); } diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 622298fa..c7a93a79 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -1749,51 +1749,58 @@ namespace const emulator_object>> io_status_block, const uint64_t file_information, const uint32_t length, const uint32_t info_class) { + IO_STATUS_BLOCK> block{}; + block.Status = STATUS_SUCCESS; + block.Information = 0; + + const auto _ = utils::finally([&] { + if (io_status_block) + { + io_status_block.write(block); + } + }); + + const auto ret = [&](const NTSTATUS status) { + block.Status = status; + return status; + }; + const auto* f = c.proc.files.get(file_handle); if (!f) { - return STATUS_INVALID_HANDLE; + return ret(STATUS_INVALID_HANDLE); } - if (info_class == FileNameInformation) + if (info_class == FileNameInformation || info_class == FileNormalizedNameInformation) { - const auto required_length = sizeof(FILE_NAME_INFORMATION) + (f->name.size() * 2); + const auto relative_path = u"\\" + windows_path(f->name).without_drive().u16string(); + const auto required_length = sizeof(FILE_NAME_INFORMATION) + (relative_path.size() * 2); - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_NAME_INFORMATION) + required_length; - io_status_block.write(block); - } + block.Information = required_length; - if (length != required_length) + if (length < block.Information) { - return STATUS_BUFFER_OVERFLOW; + return ret(STATUS_BUFFER_OVERFLOW); } c.emu.write_memory(file_information, FILE_NAME_INFORMATION{ - .FileNameLength = static_cast(f->name.size() * 2), + .FileNameLength = static_cast(relative_path.size() * 2), .FileName = {}, }); - c.emu.write_memory(file_information + offsetof(FILE_NAME_INFORMATION, FileName), f->name.c_str(), - (f->name.size() + 1) * 2); + c.emu.write_memory(file_information + offsetof(FILE_NAME_INFORMATION, FileName), relative_path.c_str(), + (relative_path.size() + 1) * 2); - return STATUS_SUCCESS; + return ret(STATUS_SUCCESS); } if (info_class == FileStandardInformation) { - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_STANDARD_INFORMATION); - io_status_block.write(block); - } + block.Information = sizeof(FILE_STANDARD_INFORMATION); - if (length != sizeof(FILE_STANDARD_INFORMATION)) + if (length < block.Information) { - return STATUS_BUFFER_OVERFLOW; + return ret(STATUS_BUFFER_OVERFLOW); } const emulator_object info{c.emu, file_information}; @@ -1807,26 +1814,21 @@ namespace info.write(i); - return STATUS_SUCCESS; + return ret(STATUS_SUCCESS); } if (info_class == FilePositionInformation) { if (!f->handle) { - return STATUS_NOT_SUPPORTED; + return ret(STATUS_NOT_SUPPORTED); } - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_POSITION_INFORMATION); - io_status_block.write(block); - } + block.Information = sizeof(FILE_POSITION_INFORMATION); - if (length != sizeof(FILE_POSITION_INFORMATION)) + if (length < block.Information) { - return STATUS_BUFFER_OVERFLOW; + return ret(STATUS_BUFFER_OVERFLOW); } const emulator_object info{c.emu, file_information}; @@ -1836,13 +1838,13 @@ namespace info.write(i); - return STATUS_SUCCESS; + return ret(STATUS_SUCCESS); } c.win_emu.log.error("Unsupported query file info class: %X\n", info_class); c.emu.stop(); - return STATUS_NOT_SUPPORTED; + return ret(STATUS_NOT_SUPPORTED); } NTSTATUS handle_NtSetInformationProcess(const syscall_context& c, const handle process_handle, @@ -2868,6 +2870,22 @@ namespace return mode; } + std::optional get_io_device_name(const std::u16string_view filename) + { + constexpr std::u16string_view device_prefix = u"\\Device\\"; + if (filename.starts_with(device_prefix)) + { + return filename.substr(device_prefix.size()); + } + + if (filename.starts_with(u"\\??\\MountPointManager")) + { + return u"MountPointManager"; + } + + return std::nullopt; + } + NTSTATUS handle_NtCreateFile(const syscall_context& c, const emulator_object file_handle, ACCESS_MASK desired_access, const emulator_object>> object_attributes, @@ -2883,16 +2901,15 @@ namespace auto printer = utils::finally( [&] { c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(filename).c_str()); }); - constexpr std::u16string_view device_prefix = u"\\Device\\"; - if (filename.starts_with(device_prefix)) + const auto io_device_name = get_io_device_name(filename); + if (io_device_name.has_value()) { const io_device_creation_data data{ .buffer = ea_buffer, .length = ea_length, }; - auto device_name = filename.substr(device_prefix.size()); - io_device_container container{std::move(device_name), c.win_emu, data}; + io_device_container container{std::u16string(*io_device_name), c.win_emu, data}; const auto handle = c.proc.devices.store(std::move(container)); file_handle.write(handle); @@ -3034,12 +3051,44 @@ namespace share_access, FILE_OPEN, open_options, 0, 0); } - NTSTATUS handle_NtQueryObject(const syscall_context&, const handle /*handle*/, - const OBJECT_INFORMATION_CLASS /*object_information_class*/, - const emulator_pointer /*object_information*/, - const ULONG /*object_information_length*/, - const emulator_object /*return_length*/) + NTSTATUS handle_NtQueryObject(const syscall_context& c, const handle handle, + const OBJECT_INFORMATION_CLASS object_information_class, + const emulator_pointer object_information, const ULONG object_information_length, + const emulator_object return_length) { + if (object_information_class == ObjectNameInformation) + { + if (handle.value.type != handle_types::file) + { + c.win_emu.log.error("Unsupported handle type for name information query: %X\n", handle.value.type); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + const auto file = c.proc.files.get(handle); + if (!file) + { + return STATUS_INVALID_HANDLE; + } + + const auto device_path = windows_path(file->name).to_device_path(); + + const auto required_size = sizeof(UNICODE_STRING>) + (device_path.size() + 1) * 2; + return_length.write(static_cast(required_size)); + + if (required_size > object_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_allocator allocator(c.emu, object_information, object_information_length); + allocator.make_unicode_string(device_path); + + return STATUS_SUCCESS; + } + + c.win_emu.log.error("Unsupported object info class: %X\n", object_information_class); + c.emu.stop(); return STATUS_NOT_SUPPORTED; } diff --git a/src/windows-emulator/windows_path.hpp b/src/windows-emulator/windows_path.hpp index 869d5027..d0b8471e 100644 --- a/src/windows-emulator/windows_path.hpp +++ b/src/windows-emulator/windows_path.hpp @@ -155,6 +155,35 @@ class windows_path return path; } + std::u16string to_device_path() const + { + if (is_relative()) + { + throw std::runtime_error("Device path can not be computed for relative paths!"); + } + + const auto drive_index = *this->drive_ - 'a'; + const auto drive_number = std::to_string(drive_index + 1); + const std::u16string number(drive_number.begin(), drive_number.end()); + + std::u16string path = u"\\Device\\HarddiskVolume"; + path.append(number); + path.push_back(u'\\'); + path.append(this->without_drive().u16string()); + + return path; + } + + std::optional get_drive() const + { + return this->drive_; + } + + windows_path without_drive() const + { + return windows_path{std::nullopt, this->folders_}; + } + windows_path operator/(const windows_path& path) const { if (path.is_absolute())