From 909b2db20d3457988240937c42e9e3759d080ba6 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 1 Jun 2025 11:31:48 +0200 Subject: [PATCH] Support more mountpoint IOCTLs --- src/common/platform/file_management.hpp | 9 ++ .../devices/mount_point_manager.cpp | 128 +++++++++++++++++- src/windows-emulator/devices/mountmgr.hpp | 69 ++++++++++ src/windows-emulator/file_system.hpp | 37 ++++- 4 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 src/windows-emulator/devices/mountmgr.hpp diff --git a/src/common/platform/file_management.hpp b/src/common/platform/file_management.hpp index d0a98586..aea288cb 100644 --- a/src/common/platform/file_management.hpp +++ b/src/common/platform/file_management.hpp @@ -77,6 +77,15 @@ #define SEC_RESERVE 0x04000000 #endif +#define CTL_CODE(DeviceType, Function, Method, Access) \ + (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) + +#define METHOD_BUFFERED 0 + +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS (0x0001) // file & pipe +#define FILE_WRITE_ACCESS (0x0002) // file & pipe + typedef enum _FSINFOCLASS { FileFsVolumeInformation = 1, // q: FILE_FS_VOLUME_INFORMATION diff --git a/src/windows-emulator/devices/mount_point_manager.cpp b/src/windows-emulator/devices/mount_point_manager.cpp index c0f0f8b9..e61b5923 100644 --- a/src/windows-emulator/devices/mount_point_manager.cpp +++ b/src/windows-emulator/devices/mount_point_manager.cpp @@ -2,18 +2,119 @@ #include "mount_point_manager.hpp" #include "../windows_emulator.hpp" +#include "mountmgr.hpp" namespace { + std::pair write_data(std::vector& buffer, const std::span data) + { + const auto offset = buffer.size(); + buffer.insert(buffer.end(), data.begin(), data.end()); + return std::make_pair(static_cast(offset), static_cast(data.size())); + } + + template + std::pair write_string(std::vector& buffer, const std::basic_string_view str) + { + std::span data(reinterpret_cast(str.data()), str.size() * sizeof(Char)); + return write_data(buffer, data); + } + + std::string make_drive_id(const uint64_t low = 0, const uint64_t high = 0) + { + std::string id = "DMIO:ID:"; + id.append(reinterpret_cast(&low), sizeof(low)); + id.append(reinterpret_cast(&high), sizeof(high)); + + return id; + } + + std::u16string make_volume(const uint64_t low = 0, const uint64_t high = 0) + { + auto str = utils::string::to_hex_string(low) + utils::string::to_hex_string(high); + str.insert(str.begin() + 20, '-'); + str.insert(str.begin() + 16, '-'); + str.insert(str.begin() + 12, '-'); + str.insert(str.begin() + 8, '-'); + + const std::string volume = utils::string::va("\\??\\Volume{%s}", str.c_str()); + return u8_to_u16(volume); + } + struct mount_point_manager : stateless_device { - NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& c) override + static NTSTATUS query_points(windows_emulator& win_emu, const io_device_context& c) { - if (c.io_control_code != 0x6D0030) + const auto drives = win_emu.file_sys.list_drives(); + const auto struct_size = sizeof(MOUNTMGR_MOUNT_POINTS) + sizeof(MOUNTMGR_MOUNT_POINT) * drives.size(); + + std::vector mount_points{}; + + std::vector buffer{}; + buffer.resize(struct_size); + { - return STATUS_NOT_SUPPORTED; + MOUNTMGR_MOUNT_POINT point{}; + const auto symlink = write_string(buffer, u"\\DosDevices\\"); + const auto id = write_string(buffer, make_drive_id(0, 1)); + const auto name = write_string(buffer, u"\\Device\\HarddiskVolume0"); + + point.SymbolicLinkNameOffset = symlink.first; + point.SymbolicLinkNameLength = symlink.second; + + point.UniqueIdOffset = id.first; + point.UniqueIdLength = id.second; + + point.DeviceNameOffset = name.first; + point.DeviceNameLength = name.second; + + mount_points.push_back(point); } + for (const auto drive : drives) + { + MOUNTMGR_MOUNT_POINT point{}; + const auto symlink = write_string(buffer, make_volume(drive, 0)); + const auto id = write_string(buffer, make_drive_id(drive, 0)); + const auto name = write_string(buffer, u"\\Device\\HarddiskVolume" + + u8_to_u16(std::to_string(drive - 'a' + 1))); + + point.SymbolicLinkNameOffset = symlink.first; + point.SymbolicLinkNameLength = symlink.second; + + point.UniqueIdOffset = id.first; + point.UniqueIdLength = id.second; + + point.DeviceNameOffset = name.first; + point.DeviceNameLength = name.second; + + mount_points.push_back(point); + } + + MOUNTMGR_MOUNT_POINTS points{}; + points.Size = static_cast(buffer.size()); + points.NumberOfMountPoints = static_cast(mount_points.size()); + + memcpy(buffer.data(), &points, sizeof(points)); + memcpy(buffer.data() + offsetof(MOUNTMGR_MOUNT_POINTS, MountPoints), mount_points.data(), + mount_points.size() * sizeof(MOUNTMGR_MOUNT_POINT)); + + const auto length = std::min(static_cast(c.output_buffer_length), buffer.size()); + + win_emu.emu().write_memory(c.output_buffer, buffer.data(), length); + + if (c.io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = buffer.size(); + c.io_status_block.write(block); + } + + return length < buffer.size() ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS; + } + + static NTSTATUS get_drive_letter(windows_emulator& win_emu, const io_device_context& c) + { if (c.input_buffer_length < 2) { return STATUS_NOT_SUPPORTED; @@ -61,6 +162,27 @@ namespace return STATUS_SUCCESS; } + + NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& c) override + { + if (c.io_control_code == IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH) + { + return get_drive_letter(win_emu, c); + } + + if (c.io_control_code == IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS) + { + return get_drive_letter(win_emu, c); + } + + if (c.io_control_code == IOCTL_MOUNTMGR_QUERY_POINTS) + { + return query_points(win_emu, c); + } + + win_emu.log.error("Unsupported mount point IOCTL: %X\n", static_cast(c.io_control_code)); + return STATUS_NOT_SUPPORTED; + } }; } diff --git a/src/windows-emulator/devices/mountmgr.hpp b/src/windows-emulator/devices/mountmgr.hpp new file mode 100644 index 00000000..99162a0e --- /dev/null +++ b/src/windows-emulator/devices/mountmgr.hpp @@ -0,0 +1,69 @@ +#pragma once + +// NOLINTBEGIN(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + +#define MOUNTMGRCONTROLTYPE 0x0000006D // 'm' +#define MOUNTDEVCONTROLTYPE 0x0000004D // 'M' + +#define IOCTL_MOUNTMGR_CREATE_POINT \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_DELETE_POINTS \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_QUERY_POINTS CTL_CODE(MOUNTMGRCONTROLTYPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 4, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 5, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 6, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 7, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_CHANGE_NOTIFY CTL_CODE(MOUNTMGRCONTROLTYPE, 8, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 9, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES CTL_CODE(MOUNTMGRCONTROLTYPE, 10, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION CTL_CODE(MOUNTMGRCONTROLTYPE, 11, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH CTL_CODE(MOUNTMGRCONTROLTYPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS CTL_CODE(MOUNTMGRCONTROLTYPE, 13, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_MOUNTMGR_SCRUB_REGISTRY \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 14, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT CTL_CODE(MOUNTMGRCONTROLTYPE, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_MOUNTMGR_SET_AUTO_MOUNT \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_BOOT_DL_ASSIGNMENT \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 17, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) // since WIN7 +#define IOCTL_MOUNTMGR_TRACELOG_CACHE CTL_CODE(MOUNTMGRCONTROLTYPE, 18, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_MOUNTMGR_PREPARE_VOLUME_DELETE \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 19, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_CANCEL_VOLUME_DELETE \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 20, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) // since WIN8 +#define IOCTL_MOUNTMGR_SILO_ARRIVAL \ + CTL_CODE(MOUNTMGRCONTROLTYPE, 21, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) // since RS1 + +#define IOCTL_MOUNTDEV_QUERY_DEVICE_NAME CTL_CODE(MOUNTDEVCONTROLTYPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) + +typedef struct _MOUNTMGR_MOUNT_POINT +{ + ULONG SymbolicLinkNameOffset; + USHORT SymbolicLinkNameLength; + ULONG UniqueIdOffset; + USHORT UniqueIdLength; + ULONG DeviceNameOffset; + USHORT DeviceNameLength; +} MOUNTMGR_MOUNT_POINT, *PMOUNTMGR_MOUNT_POINT; + +// +// Output structure for IOCTL_MOUNTMGR_DELETE_POINTS, +// IOCTL_MOUNTMGR_QUERY_POINTS, and IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY. +// + +typedef struct _MOUNTMGR_MOUNT_POINTS +{ + ULONG Size; + ULONG NumberOfMountPoints; + MOUNTMGR_MOUNT_POINT MountPoints[1]; +} MOUNTMGR_MOUNT_POINTS, *PMOUNTMGR_MOUNT_POINTS; + +// NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) diff --git a/src/windows-emulator/file_system.hpp b/src/windows-emulator/file_system.hpp index ae5a60dc..8de7bc43 100644 --- a/src/windows-emulator/file_system.hpp +++ b/src/windows-emulator/file_system.hpp @@ -2,8 +2,6 @@ #include "std_include.hpp" #include "windows_path.hpp" -#include - class file_system { public: @@ -23,6 +21,41 @@ class file_system return !is_escaping_relative_path(relative_path); } + std::set list_drives() const + { + std::set drives{}; + +#ifdef OS_WINDOWS + if (this->root_.empty()) + { + const auto drive_bits = GetLogicalDrives(); + + for (char drive = 'a'; drive <= 'z'; ++drive) + { + const auto drive_index = drive - 'a'; + if (drive_bits & (1 << drive_index)) + { + drives.insert(drive); + } + } + + return drives; + } +#endif + + std::error_code ec{}; + for (const auto& file : std::filesystem::directory_iterator(this->root_, ec)) + { + const auto filename = file.path().filename().string(); + if (filename.size() == 1) + { + drives.insert(utils::string::char_to_lower(filename.front())); + } + } + + return drives; + } + std::filesystem::path translate(const windows_path& win_path) const { if (!win_path.is_absolute())