From 794a9f5c5adef5915fc68cab4f8f306c2671198c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 26 Dec 2024 10:43:17 +0100 Subject: [PATCH] Support more directory enumeration classes --- src/windows-emulator/syscalls.cpp | 167 +++++++++++++++++------------- 1 file changed, 94 insertions(+), 73 deletions(-) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 9fa1a028..0810b65a 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -1435,6 +1435,90 @@ namespace return files; } + template + NTSTATUS handle_file_enumeration(const syscall_context& c, const emulator_object io_status_block, + const uint64_t file_information, const uint32_t length, const ULONG query_flags, + file* f) + { + if (!f->enumeration_state || query_flags & SL_RESTART_SCAN) + { + f->enumeration_state.emplace(file_enumeration_state{}); + f->enumeration_state->files = scan_directory(f->name); + } + + auto& enum_state = *f->enumeration_state; + + size_t current_offset{0}; + emulator_object object{c.emu}; + + size_t current_index = enum_state.current_index; + + do + { + if (current_index >= enum_state.files.size()) + { + break; + } + + const auto new_offset = align_up(current_offset, 8); + const auto& current_file = enum_state.files[current_index]; + const auto file_name = current_file.file_path.u16string(); + const auto required_size = sizeof(T) + (file_name.size() * 2) - 2; + const auto end_offset = new_offset + required_size; + + if (end_offset > length) + { + if (current_offset == 0) + { + IO_STATUS_BLOCK block{}; + block.Information = end_offset; + io_status_block.write(block); + + return STATUS_BUFFER_OVERFLOW; + } + + break; + } + + if (object) + { + const auto object_offset = object.value() - file_information; + + object.access([&](T& dir_info) + { + dir_info.NextEntryOffset = static_cast(new_offset - object_offset); + }); + } + + T info{}; + info.NextEntryOffset = 0; + info.FileIndex = static_cast(current_index); + info.FileAttributes = FILE_ATTRIBUTE_NORMAL; + info.FileNameLength = static_cast(file_name.size() * 2); + + object.set_address(file_information + new_offset); + object.write(info); + + c.emu.write_memory(object.value() + offsetof(T, FileName), file_name.data(), + info.FileNameLength); + + ++current_index; + current_offset = end_offset; + } + while ((query_flags & SL_RETURN_SINGLE_ENTRY) == 0); + + if ((query_flags & SL_NO_CURSOR_UPDATE) == 0) + { + enum_state.current_index = current_index; + } + + IO_STATUS_BLOCK block{}; + block.Information = current_offset; + io_status_block.write(block); + + return current_index < enum_state.files.size() ? STATUS_SUCCESS : STATUS_NO_MORE_FILES; + } + NTSTATUS handle_NtQueryDirectoryFileEx(const syscall_context& c, const handle file_handle, const handle /*event_handle*/, const emulator_pointer /*PIO_APC_ROUTINE*/ /*apc_routine*/, @@ -1450,85 +1534,22 @@ namespace return STATUS_INVALID_HANDLE; } - if (!f->enumeration_state || query_flags & SL_RESTART_SCAN) + if (info_class == FileDirectoryInformation) { - f->enumeration_state.emplace(file_enumeration_state{}); - f->enumeration_state->files = scan_directory(f->name); + return handle_file_enumeration(c, io_status_block, file_information, length, + query_flags, f); } - auto& enum_state = *f->enumeration_state; - if (info_class == FileFullDirectoryInformation) { - size_t current_offset{0}; - emulator_object object{c.emu}; + return handle_file_enumeration(c, io_status_block, file_information, length, + query_flags, f); + } - size_t current_index = enum_state.current_index; - - do - { - if (current_index >= enum_state.files.size()) - { - break; - } - - const auto new_offset = align_up(current_offset, 8); - const auto& current_file = enum_state.files[current_index]; - const auto file_name = current_file.file_path.u16string(); - const auto required_size = sizeof(FILE_FULL_DIR_INFORMATION) + (file_name.size() * 2) - 2; - const auto end_offset = new_offset + required_size; - - if (end_offset > length) - { - if (current_offset == 0) - { - IO_STATUS_BLOCK block{}; - block.Information = end_offset; - io_status_block.write(block); - - return STATUS_BUFFER_OVERFLOW; - } - - break; - } - - if (object) - { - const auto object_offset = object.value() - file_information; - - object.access([&](FILE_FULL_DIR_INFORMATION& dir_info) - { - dir_info.NextEntryOffset = static_cast(new_offset - object_offset); - }); - } - - FILE_FULL_DIR_INFORMATION info{}; - info.NextEntryOffset = 0; - info.FileIndex = static_cast(current_index); - info.FileAttributes = FILE_ATTRIBUTE_NORMAL; - info.FileNameLength = static_cast(file_name.size() * 2); - - object.set_address(file_information + new_offset); - object.write(info); - - c.emu.write_memory(object.value() + offsetof(FILE_FULL_DIR_INFORMATION, FileName), file_name.data(), - info.FileNameLength); - - ++current_index; - current_offset = end_offset; - } - while ((query_flags & SL_RETURN_SINGLE_ENTRY) == 0); - - if ((query_flags & SL_NO_CURSOR_UPDATE) == 0) - { - f->enumeration_state->current_index = current_index; - } - - IO_STATUS_BLOCK block{}; - block.Information = current_offset; - io_status_block.write(block); - - return current_index < enum_state.files.size() ? STATUS_SUCCESS : STATUS_NO_MORE_FILES; + if (info_class == FileBothDirectoryInformation) + { + return handle_file_enumeration(c, io_status_block, file_information, length, + query_flags, f); } printf("Unsupported query directory file info class: %X\n", info_class);