mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-28 07:21:02 +00:00
Improvements to NtQueryDirectoryFileEx (#235)
This PR aims to: - [Stub FileBasicInformation in NtSetInformationFile](6d0ad1dd61) - [Make sure a root `windows_path` have slash at the end](02ed4fbb03), this was necessary because `directory_iterator` fails when the path is `C:` (without slash).. - [Improve NtQueryDirectoryFileEx](f6ec1fc9cc) by adding filename filtering support, including more basic file information in the struct, and fixing an issue that prevented the last chunk of files from being enumerated correctly.
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <utils/finally.hpp>
|
||||
#include <utils/wildcard.hpp>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -21,6 +22,11 @@ namespace syscalls
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (info_class == FileBasicInformation)
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (info_class == FilePositionInformation)
|
||||
{
|
||||
if (!f->handle)
|
||||
@@ -99,17 +105,27 @@ namespace syscalls
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<file_entry> scan_directory(const std::filesystem::path& dir)
|
||||
std::vector<file_entry> scan_directory(const std::filesystem::path& dir, const std::u16string_view file_mask)
|
||||
{
|
||||
std::vector<file_entry> files{
|
||||
{"."},
|
||||
{".."},
|
||||
};
|
||||
std::vector<file_entry> files{};
|
||||
|
||||
if (file_mask.empty() || file_mask == u"*")
|
||||
{
|
||||
files.emplace_back(file_entry{.file_path = ".", .is_directory = true});
|
||||
files.emplace_back(file_entry{.file_path = "..", .is_directory = true});
|
||||
}
|
||||
|
||||
for (const auto& file : std::filesystem::directory_iterator(dir))
|
||||
{
|
||||
if (!file_mask.empty() && !utils::wildcard::match_filename(file.path().filename().u16string(), file_mask))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
files.emplace_back(file_entry{
|
||||
.file_path = file.path().filename(),
|
||||
.file_size = file.file_size(),
|
||||
.is_directory = file.is_directory(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -120,12 +136,13 @@ namespace syscalls
|
||||
NTSTATUS handle_file_enumeration(const syscall_context& c,
|
||||
const emulator_object<IO_STATUS_BLOCK<EmulatorTraits<Emu64>>> io_status_block,
|
||||
const uint64_t file_information, const uint32_t length, const ULONG query_flags,
|
||||
file* f)
|
||||
const emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> file_mask, file* f)
|
||||
{
|
||||
if (!f->enumeration_state || query_flags & SL_RESTART_SCAN)
|
||||
{
|
||||
f->enumeration_state.emplace(file_enumeration_state{});
|
||||
f->enumeration_state->files = scan_directory(c.win_emu.file_sys.translate(f->name));
|
||||
f->enumeration_state->files = scan_directory(c.win_emu.file_sys.translate(f->name),
|
||||
file_mask ? read_unicode_string(c.emu, file_mask) : u"");
|
||||
}
|
||||
|
||||
auto& enum_state = *f->enumeration_state;
|
||||
@@ -135,13 +152,13 @@ namespace syscalls
|
||||
|
||||
size_t current_index = enum_state.current_index;
|
||||
|
||||
if (current_index >= enum_state.files.size())
|
||||
{
|
||||
return STATUS_NO_MORE_FILES;
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -175,7 +192,12 @@ namespace syscalls
|
||||
info.NextEntryOffset = 0;
|
||||
info.FileIndex = static_cast<ULONG>(current_index);
|
||||
info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
if (current_file.is_directory)
|
||||
{
|
||||
info.FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
info.FileNameLength = static_cast<ULONG>(file_name.size() * 2);
|
||||
info.EndOfFile.QuadPart = current_file.file_size;
|
||||
|
||||
object.set_address(file_information + new_offset);
|
||||
object.write(info);
|
||||
@@ -184,7 +206,7 @@ namespace syscalls
|
||||
|
||||
++current_index;
|
||||
current_offset = end_offset;
|
||||
} while ((query_flags & SL_RETURN_SINGLE_ENTRY) == 0);
|
||||
} while ((query_flags & SL_RETURN_SINGLE_ENTRY) == 0 && current_index < enum_state.files.size());
|
||||
|
||||
if ((query_flags & SL_NO_CURSOR_UPDATE) == 0)
|
||||
{
|
||||
@@ -195,7 +217,7 @@ namespace syscalls
|
||||
block.Information = current_offset;
|
||||
io_status_block.write(block);
|
||||
|
||||
return current_index < enum_state.files.size() ? STATUS_SUCCESS : STATUS_NO_MORE_FILES;
|
||||
return current_index <= enum_state.files.size() ? STATUS_SUCCESS : STATUS_NO_MORE_FILES;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueryDirectoryFileEx(
|
||||
@@ -203,7 +225,7 @@ namespace syscalls
|
||||
const emulator_pointer /*PIO_APC_ROUTINE*/ /*apc_routine*/, const emulator_pointer /*apc_context*/,
|
||||
const emulator_object<IO_STATUS_BLOCK<EmulatorTraits<Emu64>>> io_status_block, const uint64_t file_information,
|
||||
const uint32_t length, const uint32_t info_class, const ULONG query_flags,
|
||||
const emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> /*file_name*/)
|
||||
const emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> file_name)
|
||||
{
|
||||
auto* f = c.proc.files.get(file_handle);
|
||||
if (!f || !f->is_directory())
|
||||
@@ -214,19 +236,19 @@ namespace syscalls
|
||||
if (info_class == FileDirectoryInformation)
|
||||
{
|
||||
return handle_file_enumeration<FILE_DIRECTORY_INFORMATION>(c, io_status_block, file_information, length,
|
||||
query_flags, f);
|
||||
query_flags, file_name, f);
|
||||
}
|
||||
|
||||
if (info_class == FileFullDirectoryInformation)
|
||||
{
|
||||
return handle_file_enumeration<FILE_FULL_DIR_INFORMATION>(c, io_status_block, file_information, length,
|
||||
query_flags, f);
|
||||
query_flags, file_name, f);
|
||||
}
|
||||
|
||||
if (info_class == FileBothDirectoryInformation)
|
||||
{
|
||||
return handle_file_enumeration<FILE_BOTH_DIR_INFORMATION>(c, io_status_block, file_information, length,
|
||||
query_flags, f);
|
||||
query_flags, file_name, f);
|
||||
}
|
||||
|
||||
c.win_emu.log.error("Unsupported query directory file info class: %X\n", info_class);
|
||||
@@ -235,6 +257,28 @@ namespace syscalls
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueryDirectoryFile(const syscall_context& c, const handle file_handle, const handle event_handle,
|
||||
const emulator_pointer /*PIO_APC_ROUTINE*/ apc_routine,
|
||||
const emulator_pointer apc_context,
|
||||
const emulator_object<IO_STATUS_BLOCK<EmulatorTraits<Emu64>>> io_status_block,
|
||||
const uint64_t file_information, const uint32_t length,
|
||||
const uint32_t info_class, const BOOLEAN return_single_entry,
|
||||
const emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> file_name,
|
||||
const BOOLEAN restart_scan)
|
||||
{
|
||||
ULONG query_flags = 0;
|
||||
if (return_single_entry)
|
||||
{
|
||||
query_flags |= SL_RETURN_SINGLE_ENTRY;
|
||||
}
|
||||
if (restart_scan)
|
||||
{
|
||||
query_flags |= SL_RESTART_SCAN;
|
||||
}
|
||||
return handle_NtQueryDirectoryFileEx(c, file_handle, event_handle, apc_routine, apc_context, io_status_block,
|
||||
file_information, length, info_class, query_flags, file_name);
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtQueryInformationFile(
|
||||
const syscall_context& c, const handle file_handle,
|
||||
const emulator_object<IO_STATUS_BLOCK<EmulatorTraits<Emu64>>> io_status_block, const uint64_t file_information,
|
||||
@@ -599,21 +643,24 @@ namespace syscalls
|
||||
|
||||
printer.cancel();
|
||||
|
||||
if (f.name.ends_with(u"\\") || create_options & FILE_DIRECTORY_FILE)
|
||||
const windows_path path = f.name;
|
||||
const bool is_directory = std::filesystem::is_directory(c.win_emu.file_sys.translate(path));
|
||||
|
||||
if (is_directory || create_options & FILE_DIRECTORY_FILE)
|
||||
{
|
||||
c.win_emu.log.print(color::dark_gray, "--> Opening folder: %s\n", u16_to_u8(f.name).c_str());
|
||||
|
||||
if (create_disposition & FILE_CREATE)
|
||||
{
|
||||
std::error_code ec{};
|
||||
create_directory(c.win_emu.file_sys.translate(f.name), ec);
|
||||
create_directory(c.win_emu.file_sys.translate(path), ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
else if (!is_directory(c.win_emu.file_sys.translate(f.name)))
|
||||
else if (!is_directory)
|
||||
{
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
@@ -626,7 +673,6 @@ namespace syscalls
|
||||
|
||||
c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(f.name).c_str());
|
||||
|
||||
const windows_path path = f.name;
|
||||
std::u16string mode = map_mode(desired_access, create_disposition);
|
||||
|
||||
if (mode.empty() || path.is_relative())
|
||||
|
||||
Reference in New Issue
Block a user