mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 19:23:56 +00:00
Support more mountpoint IOCTLs
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -2,18 +2,119 @@
|
||||
#include "mount_point_manager.hpp"
|
||||
|
||||
#include "../windows_emulator.hpp"
|
||||
#include "mountmgr.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::pair<ULONG, USHORT> write_data(std::vector<uint8_t>& buffer, const std::span<const uint8_t> data)
|
||||
{
|
||||
const auto offset = buffer.size();
|
||||
buffer.insert(buffer.end(), data.begin(), data.end());
|
||||
return std::make_pair(static_cast<ULONG>(offset), static_cast<USHORT>(data.size()));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
std::pair<ULONG, USHORT> write_string(std::vector<uint8_t>& buffer, const std::basic_string_view<Char> str)
|
||||
{
|
||||
std::span data(reinterpret_cast<const uint8_t*>(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<const char*>(&low), sizeof(low));
|
||||
id.append(reinterpret_cast<const char*>(&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<MOUNTMGR_MOUNT_POINT> mount_points{};
|
||||
|
||||
std::vector<uint8_t> buffer{};
|
||||
buffer.resize(struct_size);
|
||||
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
MOUNTMGR_MOUNT_POINT point{};
|
||||
const auto symlink = write_string<char16_t>(buffer, u"\\DosDevices\\");
|
||||
const auto id = write_string<char>(buffer, make_drive_id(0, 1));
|
||||
const auto name = write_string<char16_t>(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<char16_t>(buffer, make_volume(drive, 0));
|
||||
const auto id = write_string<char>(buffer, make_drive_id(drive, 0));
|
||||
const auto name = write_string<char16_t>(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<ULONG>(buffer.size());
|
||||
points.NumberOfMountPoints = static_cast<ULONG>(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<size_t>(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<EmulatorTraits<Emu64>> 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<uint32_t>(c.io_control_code));
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
69
src/windows-emulator/devices/mountmgr.hpp
Normal file
69
src/windows-emulator/devices/mountmgr.hpp
Normal file
@@ -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)
|
||||
@@ -2,8 +2,6 @@
|
||||
#include "std_include.hpp"
|
||||
#include "windows_path.hpp"
|
||||
|
||||
#include <platform/compiler.hpp>
|
||||
|
||||
class file_system
|
||||
{
|
||||
public:
|
||||
@@ -23,6 +21,41 @@ class file_system
|
||||
return !is_escaping_relative_path(relative_path);
|
||||
}
|
||||
|
||||
std::set<char> list_drives() const
|
||||
{
|
||||
std::set<char> 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())
|
||||
|
||||
Reference in New Issue
Block a user