diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc index 367d980e0..b0c5fdb56 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc @@ -90,6 +90,8 @@ dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access, auto object_name = kernel_memory()->TranslateVirtual(object_attrs->name_ptr); + vfs::Entry* root_entry = nullptr; + // Compute path, possibly attrs relative. auto target_path = util::TranslateAnsiString(kernel_memory(), object_name); if (object_attrs->root_directory != 0xFFFFFFFD && // ObDosDevices @@ -99,18 +101,15 @@ dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access, assert_not_null(root_file); assert_true(root_file->type() == XObject::Type::kTypeFile); - // Resolve the file using the device the root directory is part of. - auto device = root_file->device(); - target_path = xe::utf8::join_guest_paths( - {device->mount_path(), root_file->path(), target_path}); + root_entry = root_file->entry(); } // Attempt open (or create). vfs::File* vfs_file; vfs::FileAction file_action; X_STATUS result = kernel_state()->file_system()->OpenFile( - target_path, vfs::FileDisposition((uint32_t)creation_disposition), - desired_access, + root_entry, target_path, + vfs::FileDisposition((uint32_t)creation_disposition), desired_access, (create_options & CreateOptions::FILE_DIRECTORY_FILE) != 0, &vfs_file, &file_action); object_ref file = nullptr; diff --git a/src/xenia/kernel/xfile.cc b/src/xenia/kernel/xfile.cc index 1ab518963..15529fc6d 100644 --- a/src/xenia/kernel/xfile.cc +++ b/src/xenia/kernel/xfile.cc @@ -263,8 +263,8 @@ object_ref XFile::Restore(KernelState* kernel_state, vfs::File* vfs_file = nullptr; vfs::FileAction action; auto res = kernel_state->file_system()->OpenFile( - abs_path, vfs::FileDisposition::kOpen, access, is_directory, &vfs_file, - &action); + nullptr, abs_path, vfs::FileDisposition::kOpen, access, is_directory, + &vfs_file, &action); if (XFAILED(res)) { XELOGE("Failed to open XFile: error {:08X}", res); return object_ref(file); diff --git a/src/xenia/vfs/devices/disc_image_device.cc b/src/xenia/vfs/devices/disc_image_device.cc index 918701f88..0675e5990 100644 --- a/src/xenia/vfs/devices/disc_image_device.cc +++ b/src/xenia/vfs/devices/disc_image_device.cc @@ -58,20 +58,8 @@ Entry* DiscImageDevice::ResolvePath(const std::string_view path) { // The filesystem will have stripped our prefix off already, so the path will // be in the form: // some\PATH.foo - XELOGFS("DiscImageDevice::ResolvePath({})", path); - - // Walk the path, one separator at a time. - auto entry = root_entry_.get(); - for (const auto& part : xe::utf8::split_path(path)) { - entry = entry->GetChild(part); - if (!entry) { - // Not found. - return nullptr; - } - } - - return entry; + return root_entry_->ResolvePath(path); } DiscImageDevice::Error DiscImageDevice::Verify(ParseState* state) { diff --git a/src/xenia/vfs/devices/host_path_device.cc b/src/xenia/vfs/devices/host_path_device.cc index 25cd568bb..5dcf3d21f 100644 --- a/src/xenia/vfs/devices/host_path_device.cc +++ b/src/xenia/vfs/devices/host_path_device.cc @@ -53,21 +53,8 @@ Entry* HostPathDevice::ResolvePath(const std::string_view path) { // The filesystem will have stripped our prefix off already, so the path will // be in the form: // some\PATH.foo - XELOGFS("HostPathDevice::ResolvePath({})", path); - - // Walk the path, one separator at a time. - auto entry = root_entry_.get(); - auto path_parts = xe::utf8::split_path(path); - for (auto& part : path_parts) { - entry = entry->GetChild(part); - if (!entry) { - // Not found. - return nullptr; - } - } - - return entry; + return root_entry_->ResolvePath(path); } void HostPathDevice::PopulateEntry(HostPathEntry* parent_entry) { diff --git a/src/xenia/vfs/devices/stfs_container_device.cc b/src/xenia/vfs/devices/stfs_container_device.cc index d50c5a231..8da4b303f 100644 --- a/src/xenia/vfs/devices/stfs_container_device.cc +++ b/src/xenia/vfs/devices/stfs_container_device.cc @@ -165,21 +165,8 @@ Entry* StfsContainerDevice::ResolvePath(const std::string_view path) { // The filesystem will have stripped our prefix off already, so the path will // be in the form: // some\PATH.foo - XELOGFS("StfsContainerDevice::ResolvePath({})", path); - - // Walk the path, one separator at a time. - auto entry = root_entry_.get(); - auto path_parts = xe::utf8::split_path(path); - for (auto& part : path_parts) { - entry = entry->GetChild(part); - if (!entry) { - // Not found. - return nullptr; - } - } - - return entry; + return root_entry_->ResolvePath(path); } StfsContainerDevice::Error StfsContainerDevice::ReadPackageType( diff --git a/src/xenia/vfs/entry.cc b/src/xenia/vfs/entry.cc index 1ce80b9bf..7f9017608 100644 --- a/src/xenia/vfs/entry.cc +++ b/src/xenia/vfs/entry.cc @@ -58,6 +58,19 @@ Entry* Entry::GetChild(const std::string_view name) { return (*it).get(); } +Entry* Entry::ResolvePath(const std::string_view path) { + // Walk the path, one separator at a time. + Entry* entry = this; + for (auto& part : xe::utf8::split_path(path)) { + entry = entry->GetChild(part); + if (!entry) { + // Not found. + return nullptr; + } + } + return entry; +} + Entry* Entry::IterateChildren(const xe::filesystem::WildcardEngine& engine, size_t* current_index) { auto global_lock = global_critical_region_.Acquire(); diff --git a/src/xenia/vfs/entry.h b/src/xenia/vfs/entry.h index e5325f115..d4dee331d 100644 --- a/src/xenia/vfs/entry.h +++ b/src/xenia/vfs/entry.h @@ -97,6 +97,7 @@ class Entry { bool is_read_only() const; Entry* GetChild(const std::string_view name); + Entry* ResolvePath(const std::string_view path); const std::vector>& children() const { return children_; diff --git a/src/xenia/vfs/virtual_file_system.cc b/src/xenia/vfs/virtual_file_system.cc index 2e712d951..31cb82f66 100644 --- a/src/xenia/vfs/virtual_file_system.cc +++ b/src/xenia/vfs/virtual_file_system.cc @@ -126,11 +126,6 @@ Entry* VirtualFileSystem::ResolvePath(const std::string_view path) { return device->ResolvePath(relative_path); } -Entry* VirtualFileSystem::ResolveBasePath(const std::string_view path) { - auto base_path = xe::utf8::find_base_guest_path(path); - return ResolvePath(base_path); -} - Entry* VirtualFileSystem::CreatePath(const std::string_view path, uint32_t attributes) { // Create all required directories recursively. @@ -173,7 +168,8 @@ bool VirtualFileSystem::DeletePath(const std::string_view path) { return parent->Delete(entry); } -X_STATUS VirtualFileSystem::OpenFile(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, File** out_file, FileAction* out_action) { @@ -195,8 +191,11 @@ X_STATUS VirtualFileSystem::OpenFile(const std::string_view path, // If no device or parent, fail. Entry* parent_entry = nullptr; Entry* entry = nullptr; - if (!xe::utf8::find_base_guest_path(path).empty()) { - parent_entry = ResolveBasePath(path); + + auto base_path = xe::utf8::find_base_guest_path(path); + if (!base_path.empty()) { + parent_entry = !root_entry ? ResolvePath(base_path) + : root_entry->ResolvePath(base_path); if (!parent_entry) { *out_action = FileAction::kDoesNotExist; return X_STATUS_NO_SUCH_FILE; @@ -205,7 +204,7 @@ X_STATUS VirtualFileSystem::OpenFile(const std::string_view path, auto file_name = xe::utf8::find_name_from_guest_path(path); entry = parent_entry->GetChild(file_name); } else { - entry = ResolvePath(path); + entry = !root_entry ? ResolvePath(path) : root_entry->GetChild(path); } // Check if exists (if we need it to), or that it doesn't (if it shouldn't). diff --git a/src/xenia/vfs/virtual_file_system.h b/src/xenia/vfs/virtual_file_system.h index 9f52f9d6f..8d5b84697 100644 --- a/src/xenia/vfs/virtual_file_system.h +++ b/src/xenia/vfs/virtual_file_system.h @@ -37,12 +37,11 @@ class VirtualFileSystem { bool FindSymbolicLink(const std::string_view path, std::string& target); Entry* ResolvePath(const std::string_view path); - Entry* ResolveBasePath(const std::string_view path); Entry* CreatePath(const std::string_view path, uint32_t attributes); bool DeletePath(const std::string_view path); - X_STATUS OpenFile(const std::string_view path, + 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);