From 8f92c60a0bf01a78c190a4477260ff11defcc3e7 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Thu, 17 Dec 2015 17:14:43 -0600 Subject: [PATCH] ObCreateSymbolicLink/ObDeleteSymbolicLink --- src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc | 31 +++++++++++++++++++ src/xenia/vfs/virtual_file_system.cc | 38 ++++++++++++++++++++---- src/xenia/vfs/virtual_file_system.h | 1 + 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc index 057b27297..15ee29804 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc @@ -169,6 +169,37 @@ SHIM_CALL ObDereferenceObject_shim(PPCContext* ppc_context, SHIM_SET_RETURN_32(0); } +dword_result_t ObCreateSymbolicLink(pointer_t path, + pointer_t target) { + auto path_str = path->to_string(kernel_memory()->virtual_membase()); + auto target_str = target->to_string(kernel_memory()->virtual_membase()); + path_str = filesystem::CanonicalizePath(path_str); + target_str = filesystem::CanonicalizePath(target_str); + + auto pos = path_str.find("\\??\\"); + if (pos != path_str.npos && pos == 0) { + path_str = path_str.substr(4); // Strip the full qualifier + } + + if (!kernel_state()->file_system()->RegisterSymbolicLink(path_str, + target_str)) { + return X_STATUS_UNSUCCESSFUL; + } + + return X_STATUS_SUCCESS; +} +DECLARE_XBOXKRNL_EXPORT(ObCreateSymbolicLink, ExportTag::kImplemented); + +dword_result_t ObDeleteSymbolicLink(pointer_t path) { + auto path_str = path->to_string(kernel_memory()->virtual_membase()); + if (!kernel_state()->file_system()->UnregisterSymbolicLink(path_str)) { + return X_STATUS_UNSUCCESSFUL; + } + + return X_STATUS_SUCCESS; +} +DECLARE_XBOXKRNL_EXPORT(ObDeleteSymbolicLink, ExportTag::kImplemented); + dword_result_t NtDuplicateObject(dword_t handle, lpdword_t new_handle_ptr, dword_t options) { // NOTE: new_handle_ptr can be zero to just close a handle. diff --git a/src/xenia/vfs/virtual_file_system.cc b/src/xenia/vfs/virtual_file_system.cc index 5806c0824..3f3c3d638 100644 --- a/src/xenia/vfs/virtual_file_system.cc +++ b/src/xenia/vfs/virtual_file_system.cc @@ -36,6 +36,8 @@ bool VirtualFileSystem::RegisterSymbolicLink(std::string path, std::string target) { auto global_lock = global_critical_region_.Acquire(); symlinks_.insert({path, target}); + XELOGD("Registered symbolic link: %s => %s", path.c_str(), target.c_str()); + return true; } @@ -45,10 +47,22 @@ bool VirtualFileSystem::UnregisterSymbolicLink(std::string path) { if (it == symlinks_.end()) { return false; } + XELOGD("Unregistered symbolic link: %s => %s", it->first.c_str(), + it->second.c_str()); + symlinks_.erase(it); return true; } +bool VirtualFileSystem::IsSymbolicLink(const std::string& path) { + auto global_lock = global_critical_region_.Acquire(); + auto it = symlinks_.find(path); + if (it == symlinks_.end()) { + return false; + } + return true; +} + Entry* VirtualFileSystem::ResolvePath(std::string path) { auto global_lock = global_critical_region_.Acquire(); @@ -58,17 +72,29 @@ Entry* VirtualFileSystem::ResolvePath(std::string path) { // Resolve symlinks. std::string device_path; std::string relative_path; - for (const auto& it : symlinks_) { - if (xe::find_first_of_case(normalized_path, it.first) == 0) { - // Found symlink! - device_path = it.second; - relative_path = normalized_path.substr(it.first.size()); + for (int i = 0; i < 2; i++) { + for (const auto& it : symlinks_) { + if (xe::find_first_of_case(normalized_path, it.first) == 0) { + // Found symlink! + device_path = it.second; + if (relative_path.empty()) { + relative_path = normalized_path.substr(it.first.size()); + } + + // Bit of a cheaty move here, but allows double symlinks to be resolved. + normalized_path = device_path; + break; + } + } + + // Break as soon as we've completely resolved the symlinks to a device. + if (!IsSymbolicLink(device_path)) { break; } } - // Not to fret, check to see if the path is fully qualified. if (device_path.empty()) { + // Symlink wasn't passed in - Check if we've received a raw device name. for (auto& device : devices_) { if (xe::find_first_of_case(normalized_path, device->mount_path()) == 0) { device_path = device->mount_path(); diff --git a/src/xenia/vfs/virtual_file_system.h b/src/xenia/vfs/virtual_file_system.h index f9f3eff62..f7d23190a 100644 --- a/src/xenia/vfs/virtual_file_system.h +++ b/src/xenia/vfs/virtual_file_system.h @@ -32,6 +32,7 @@ class VirtualFileSystem { bool RegisterSymbolicLink(std::string path, std::string target); bool UnregisterSymbolicLink(std::string path); + bool IsSymbolicLink(const std::string& path); Entry* ResolvePath(std::string path); Entry* ResolveBasePath(std::string path);