From 6fe668724e0b1318d2d083c9fa7bf95fe025f921 Mon Sep 17 00:00:00 2001 From: Gliniak Date: Sun, 2 Aug 2020 17:09:32 +0200 Subject: [PATCH] NtCreateFile - Return error while trying to create directory with non-directory flag --- src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc | 19 +++---------------- src/xenia/kernel/xfile.cc | 7 ++++++- src/xenia/vfs/file.h | 12 ++++++++++++ src/xenia/vfs/virtual_file_system.cc | 12 +++++++++++- src/xenia/vfs/virtual_file_system.h | 4 ++-- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc index 711a90bb8..3b930725f 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc @@ -27,18 +27,6 @@ namespace xe { namespace kernel { namespace xboxkrnl { -struct CreateOptions { - // https://processhacker.sourceforge.io/doc/ntioapi_8h.html - static const uint32_t FILE_DIRECTORY_FILE = 0x00000001; - // Optimization - files access will be sequential, not random. - static const uint32_t FILE_SEQUENTIAL_ONLY = 0x00000004; - static const uint32_t FILE_SYNCHRONOUS_IO_ALERT = 0x00000010; - static const uint32_t FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020; - static const uint32_t FILE_NON_DIRECTORY_FILE = 0x00000040; - // Optimization - file access will be random, not sequential. - static const uint32_t FILE_RANDOM_ACCESS = 0x00000800; -}; - static bool IsValidPath(const std::string_view s, bool is_pattern) { // TODO(gibbed): validate path components individually for (const auto& c : s) { @@ -126,16 +114,15 @@ dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access, X_STATUS result = kernel_state()->file_system()->OpenFile( root_entry, target_path, vfs::FileDisposition((uint32_t)creation_disposition), desired_access, - (create_options & CreateOptions::FILE_DIRECTORY_FILE) != 0, &vfs_file, - &file_action); + create_options, &vfs_file, &file_action); object_ref file = nullptr; X_HANDLE handle = X_INVALID_HANDLE_VALUE; if (XSUCCEEDED(result)) { // If true, desired_access SYNCHRONIZE flag must be set. bool synchronous = - (create_options & CreateOptions::FILE_SYNCHRONOUS_IO_ALERT) || - (create_options & CreateOptions::FILE_SYNCHRONOUS_IO_NONALERT); + (create_options & vfs::CreateOptions::FILE_SYNCHRONOUS_IO_ALERT) || + (create_options & vfs::CreateOptions::FILE_SYNCHRONOUS_IO_NONALERT); file = object_ref(new XFile(kernel_state(), vfs_file, synchronous)); // Handle ref is incremented, so return that. diff --git a/src/xenia/kernel/xfile.cc b/src/xenia/kernel/xfile.cc index 15529fc6d..e54cf1cdd 100644 --- a/src/xenia/kernel/xfile.cc +++ b/src/xenia/kernel/xfile.cc @@ -258,12 +258,17 @@ object_ref XFile::Restore(KernelState* kernel_state, auto is_directory = stream->Read(); auto is_synchronous = stream->Read(); + uint32_t create_options = 0; + if (is_directory) { + create_options |= vfs::CreateOptions::FILE_DIRECTORY_FILE; + } + XELOGD("XFile {:08X} ({})", file->handle(), abs_path); vfs::File* vfs_file = nullptr; vfs::FileAction action; auto res = kernel_state->file_system()->OpenFile( - nullptr, abs_path, vfs::FileDisposition::kOpen, access, is_directory, + nullptr, abs_path, vfs::FileDisposition::kOpen, access, create_options, &vfs_file, &action); if (XFAILED(res)) { XELOGE("Failed to open XFile: error {:08X}", res); diff --git a/src/xenia/vfs/file.h b/src/xenia/vfs/file.h index af06c1b45..7d7e1265e 100644 --- a/src/xenia/vfs/file.h +++ b/src/xenia/vfs/file.h @@ -17,6 +17,18 @@ namespace xe { namespace vfs { +struct CreateOptions { + // https://processhacker.sourceforge.io/doc/ntioapi_8h.html + static const uint32_t FILE_DIRECTORY_FILE = 0x00000001; + // Optimization - files access will be sequential, not random. + static const uint32_t FILE_SEQUENTIAL_ONLY = 0x00000004; + static const uint32_t FILE_SYNCHRONOUS_IO_ALERT = 0x00000010; + static const uint32_t FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020; + static const uint32_t FILE_NON_DIRECTORY_FILE = 0x00000040; + // Optimization - file access will be random, not sequential. + static const uint32_t FILE_RANDOM_ACCESS = 0x00000800; +}; + class Entry; class File { diff --git a/src/xenia/vfs/virtual_file_system.cc b/src/xenia/vfs/virtual_file_system.cc index a60fd1d7f..a2ba41e33 100644 --- a/src/xenia/vfs/virtual_file_system.cc +++ b/src/xenia/vfs/virtual_file_system.cc @@ -173,7 +173,7 @@ bool VirtualFileSystem::DeletePath(const std::string_view path) { X_STATUS VirtualFileSystem::OpenFile(Entry* root_entry, const std::string_view path, FileDisposition creation_disposition, - uint32_t desired_access, bool is_directory, + uint32_t desired_access, uint32_t create_options, File** out_file, FileAction* out_action) { // TODO(gibbed): should 'is_directory' remain as a bool or should it be // flipped to a generic FileAttributeFlags? @@ -189,11 +189,21 @@ X_STATUS VirtualFileSystem::OpenFile(Entry* root_entry, desired_access |= FileAccess::kFileReadData | FileAccess::kFileWriteData; } + bool is_directory = create_options & CreateOptions::FILE_DIRECTORY_FILE; + // Lookup host device/parent path. // If no device or parent, fail. Entry* parent_entry = nullptr; Entry* entry = nullptr; + auto path_entry = ResolvePath(path); + if (path_entry) { + if (path_entry->attributes() & kFileAttributeDirectory && + create_options & CreateOptions::FILE_NON_DIRECTORY_FILE) { + return X_STATUS_FILE_IS_A_DIRECTORY; + } + } + auto base_path = xe::utf8::find_base_guest_path(path); if (!base_path.empty()) { parent_entry = !root_entry ? ResolvePath(base_path) diff --git a/src/xenia/vfs/virtual_file_system.h b/src/xenia/vfs/virtual_file_system.h index fb85630aa..936adb6a2 100644 --- a/src/xenia/vfs/virtual_file_system.h +++ b/src/xenia/vfs/virtual_file_system.h @@ -46,8 +46,8 @@ class VirtualFileSystem { X_STATUS OpenFile(Entry* root_entry, const std::string_view path, FileDisposition creation_disposition, - uint32_t desired_access, bool is_directory, File** out_file, - FileAction* out_action); + uint32_t desired_access, uint32_t create_options, + File** out_file, FileAction* out_action); private: xe::global_critical_region global_critical_region_;