From 8445a029983bebf51bb011009dc71d885682950b Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Sun, 28 Mar 2021 18:17:41 -0500 Subject: [PATCH] kernel: implement title mount path --- src/common/Settings.hpp | 2 +- src/common/win32/EmuShared.h | 22 +++++- src/common/xbox_types.h | 5 ++ src/core/hle/XAPI/Xapi.cpp | 2 +- src/core/kernel/exports/EmuKrnlHal.cpp | 29 +------ src/core/kernel/init/CxbxKrnl.cpp | 70 ++++++++++++----- src/core/kernel/init/CxbxKrnl.h | 2 +- src/core/kernel/support/EmuFile.cpp | 101 ++++++++++++++++++++----- src/core/kernel/support/EmuFile.h | 9 ++- 9 files changed, 166 insertions(+), 76 deletions(-) diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index 013652272..000ff615d 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -100,7 +100,7 @@ public: unsigned int FlagsLLE; DebugMode KrnlDebugMode; char szKrnlDebug[MAX_PATH] = ""; - char szStorageLocation[MAX_PATH] = ""; + char szStorageLocation[xbox::max_path] = ""; unsigned int LoggedModules[NUM_INTEGERS_LOG]; int LogLevel = 1; bool bUseLoaderExec; diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index 1589c2741..923d5f9c7 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -30,6 +30,7 @@ #include "Mutex.h" #include "common\IPCHybrid.hpp" #include "common\input\Button.h" +#include "common/xbox_types.h" #include "CxbxVersion.h" #include "core/common/imgui/settings.h" #include @@ -245,8 +246,8 @@ class EmuShared : public Mutex // ****************************************************************** // * File storage location // ****************************************************************** - void GetStorageLocation(char *path) { Lock(); strncpy(path, m_core.szStorageLocation, MAX_PATH); Unlock(); } - void SetStorageLocation(const char *path) { Lock(); strncpy(m_core.szStorageLocation, path, MAX_PATH); Unlock(); } + void GetStorageLocation(char *path) { Lock(); strncpy(path, m_core.szStorageLocation, xbox::max_path); Unlock(); } + void SetStorageLocation(const char *path) { Lock(); strncpy(m_core.szStorageLocation, path, xbox::max_path); Unlock(); } // ****************************************************************** // * ClipCursor flag Accessors @@ -301,6 +302,22 @@ class EmuShared : public Mutex Unlock(); } + // ****************************************************************** + // * TitleMountPath Accessor + // ****************************************************************** + void GetTitleMountPath(char *value) + { + Lock(); + std::strncpy(value, m_TitleMountPath, sizeof(m_TitleMountPath)); + Unlock(); + } + void SetTitleMountPath(const char* value) + { + Lock(); + std::strncpy(m_TitleMountPath, value, sizeof(m_TitleMountPath) - 1); + Unlock(); + } + // ****************************************************************** // * Reset specific variables to default for kernel mode. // ****************************************************************** @@ -351,6 +368,7 @@ class EmuShared : public Mutex int m_DeviceType[4]; char m_DeviceControlNames[4][HIGHEST_NUM_BUTTONS][HOST_BUTTON_NAME_LENGTH]; char m_DeviceName[4][50]; + char m_TitleMountPath[xbox::max_path]; // Settings class in memory should not be tampered by third-party. // Third-party program should only be allow to edit settings.ini file. diff --git a/src/common/xbox_types.h b/src/common/xbox_types.h index 971fa9a9d..8eac42c5f 100644 --- a/src/common/xbox_types.h +++ b/src/common/xbox_types.h @@ -133,4 +133,9 @@ namespace xbox // ****************************************************************** static_assert(CHAR_BIT == 8); static_assert(sizeof(char16_t) == 2); + + // ****************************************************************** + // Defines + // ****************************************************************** + constexpr uint_xt max_path{ 260 }; // Xbox file path max limitation } diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 13b8af253..ecdd4e56d 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -958,7 +958,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XLaunchNewImageA) if (lpTitlePath == xbox::zeroptr) { // If no path is specified, then the xbe is rebooting to dashboard - char szDashboardPath[MAX_PATH] = { 0 }; + char szDashboardPath[xbox::max_path] = { 0 }; XboxDevice* rootDevice = CxbxDeviceByDevicePath(DeviceHarddisk0Partition2); if (rootDevice != nullptr) sprintf(szDashboardPath, "%s\\xboxdash.xbe", rootDevice->HostDevicePath.c_str()); diff --git a/src/core/kernel/exports/EmuKrnlHal.cpp b/src/core/kernel/exports/EmuKrnlHal.cpp index d719bdfa5..80addb59f 100644 --- a/src/core/kernel/exports/EmuKrnlHal.cpp +++ b/src/core/kernel/exports/EmuKrnlHal.cpp @@ -27,7 +27,7 @@ // ****************************************************************** #define LOG_PREFIX CXBXR_MODULE::HAL - +#pragma optimize("", off) #include // For HalReadSMCTrayState, etc. #include // For PathRemoveFileSpec() @@ -540,7 +540,7 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi std::string TitlePath = xbox::LaunchDataPage->Header.szLaunchPath; - char szWorkingDirectoy[MAX_PATH]; + char szWorkingDirectoy[xbox::max_path]; // If the title path starts with a semicolon, remove it if (TitlePath.length() > 0 && TitlePath[0] == ';') { @@ -552,30 +552,7 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi TitlePath = DeviceHarddisk0Partition2 + "\\xboxdash.xbe"; } - std::string XbePath = TitlePath; - // Convert Xbox XBE Path to Windows Path - { - HANDLE rootDirectoryHandle = nullptr; - std::wstring wXbePath; - // We pretend to come from NtCreateFile to force symbolic link resolution - CxbxConvertFilePath(TitlePath, wXbePath, &rootDirectoryHandle, "NtCreateFile"); - - // Convert Wide String as returned by above to a string, for XbePath - XbePath = utf16_to_ascii(wXbePath.c_str()); - - // If the rootDirectoryHandle is not null, we have a relative path - // We need to prepend the path of the root directory to get a full DOS path - if (rootDirectoryHandle != nullptr) { - char directoryPathBuffer[MAX_PATH]; - GetFinalPathNameByHandle(rootDirectoryHandle, directoryPathBuffer, MAX_PATH, VOLUME_NAME_DOS); - XbePath = directoryPathBuffer + std::string("\\") + XbePath; - - // Trim \\?\ from the output string, as we want the raw DOS path, not NT path - // We can do this always because GetFinalPathNameByHandle ALWAYS returns this format - // Without exception - XbePath.erase(0, 4); - } - } + std::string& XbePath = CxbxConvertXboxToHostPath(TitlePath); // Determine Working Directory { diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 72fcd012e..de823b1ef 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -90,7 +90,7 @@ static std::vector g_hThreads; char szFilePath_CxbxReloaded_Exe[MAX_PATH] = { 0 }; char szFolder_CxbxReloadedData[MAX_PATH] = { 0 }; char szFilePath_EEPROM_bin[MAX_PATH] = { 0 }; -char szFilePath_Xbe[MAX_PATH*2] = { 0 }; // NOTE: LAUNCH_DATA_HEADER's szLaunchPath is MAX_PATH*2 = 520 +char szFilePath_Xbe[xbox::max_path*2] = { 0 }; // NOTE: LAUNCH_DATA_HEADER's szLaunchPath is xbox::max_path*2 = 520 std::string CxbxBasePath; HANDLE CxbxBasePathHandle; @@ -997,7 +997,7 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res // Remove extra slashes. std::string slash_search[] = { "\\\\", "//" }; std::string slash_str = "/"; - for (n = 0, i = 0; i < slash_search->size(); i++, n = 0) { + for (n = 0, i = 1; i < slash_search->size(); i++, n = 0) { while ((n = xbePath.find(slash_search[i], n)) != std::string::npos) { xbePath.replace(n, slash_search[i].size(), slash_str); n += slash_str.size(); @@ -1005,7 +1005,7 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res } // Once clean up process is done, proceed set to global variable string. - strncpy(szFilePath_Xbe, xbePath.c_str(), MAX_PATH - 1); + strncpy(szFilePath_Xbe, xbePath.c_str(), xbox::max_path - 1); std::replace(xbePath.begin(), xbePath.end(), ';', '/'); // Load Xbe (this one will reside above WinMain's virtual_memory_placeholder) CxbxKrnl_Xbe = new Xbe(xbePath.c_str(), false); // TODO : Instead of using the Xbe class, port Dxbx _ReadXbeBlock() @@ -1230,7 +1230,7 @@ void LoadXboxKeys(std::string path) // If we didn't already exit the function, keys.bin could not be loaded EmuLog(LOG_LEVEL::WARNING, "Failed to load Keys.bin. Cxbx-Reloaded will be unable to read Save Data from a real Xbox"); } - +#pragma optimize("", off) __declspec(noreturn) void CxbxKrnlInit ( void *pTLSData, @@ -1344,7 +1344,7 @@ __declspec(noreturn) void CxbxKrnlInit char szBuffer[sizeof(szFilePath_Xbe)]; g_EmuShared->GetStorageLocation(szBuffer); - CxbxBasePath = std::string(szBuffer) + "\\EmuDisk\\"; + CxbxBasePath = std::filesystem::path(std::string(szBuffer) + "\\EmuDisk\\").make_preferred().string(); // Let filesystem library clean it up for us. // Determine XBE Path strncpy(szBuffer, szFilePath_Xbe, sizeof(szBuffer)-1); @@ -1352,23 +1352,45 @@ __declspec(noreturn) void CxbxKrnlInit std::string xbePath(szBuffer); std::replace(xbePath.begin(), xbePath.end(), ';', '/'); - std::string xbeDirectory(szBuffer); - size_t lastFind = xbeDirectory.find(';'); + xbePath = std::filesystem::path(xbePath).make_preferred().string(); // Let filesystem library clean it up for us. + + std::string mount_d_dir(szBuffer); + size_t lastFind = mount_d_dir.find(';'); // First find if there is a semicolon when dashboard or title disc (such as demo disc) has it. // Then we must obey the current directory it asked for. if (lastFind != std::string::npos) { - if (xbeDirectory.find(';', lastFind + 1) != std::string::npos) { + if (mount_d_dir.find(';', lastFind + 1) != std::string::npos) { CxbxKrnlCleanupEx(LOG_PREFIX_INIT, "Cannot contain multiple of ; symbol."); } - xbeDirectory = xbeDirectory.substr(0, lastFind); + mount_d_dir = mount_d_dir.substr(0, lastFind); } else { - xbeDirectory = xbeDirectory.substr(0, xbeDirectory.find_last_of("\\/")); + mount_d_dir = mount_d_dir.substr(0, mount_d_dir.find_last_of("\\/")); } + mount_d_dir = std::filesystem::path(mount_d_dir).make_preferred().string(); // Let filesystem library clean it up for us. + CxbxBasePathHandle = CreateFile(CxbxBasePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + // Titles may assume they are running from CdRom0/Mbfs : + std::string_view titleDevice = g_bIsChihiro ? DriveMbfs : DeviceCdrom0; + int CxbxTitleDeviceDriveIndex = -1; + if (BootFlags == BOOT_NONE) { + // Remember our first initialize mount path. + if (_strnicmp(mount_d_dir.c_str(), CxbxBasePath.c_str(), CxbxBasePath.size()-1) != 0) { + g_EmuShared->SetTitleMountPath(mount_d_dir.c_str()); + CxbxTitleDeviceDriveIndex = CxbxRegisterDeviceHostPath(titleDevice, mount_d_dir); + } + else { + g_EmuShared->SetTitleMountPath(""); + } + } + else { + g_EmuShared->GetTitleMountPath(szBuffer); + if (szBuffer[0] != '\0') { + CxbxTitleDeviceDriveIndex = CxbxRegisterDeviceHostPath(titleDevice, szBuffer); + } + } memset(szBuffer, 0, sizeof(szBuffer)); - // Games may assume they are running from CdRom : - CxbxDefaultXbeDriveIndex = CxbxRegisterDeviceHostPath(DeviceCdrom0, xbeDirectory); + // Partition 0 contains configuration data, and is accessed as a native file, instead as a folder : CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition0, CxbxBasePath + "Partition0", /*IsFile=*/true); // The first two partitions are for Data and Shell files, respectively : @@ -1384,14 +1406,22 @@ __declspec(noreturn) void CxbxKrnlInit // Create default symbolic links : EmuLogInit(LOG_LEVEL::DEBUG, "Creating default symbolic links."); { - // TODO: DriveD should always point to the Xbe Path + // TODO: DriveD should auto mount base on launchdata page's ; delimiter xbe path. // This is the only symbolic link the Xbox Kernel sets, the rest are set by the application, usually via XAPI. // If the Xbe is located outside of the emulated HDD, mounting it as DeviceCdrom0 is correct // If the Xbe is located inside the emulated HDD, the full path should be used, eg: "\\Harddisk0\\partition2\\xboxdash.xbe" - CxbxCreateSymbolicLink(DriveD, DeviceCdrom0); - // Arrange that the Xbe path can reside outside the partitions, and put it to g_hCurDir : - EmuNtSymbolicLinkObject* xbePathSymbolicLinkObject = FindNtSymbolicLinkObjectByDriveLetter(CxbxDefaultXbeDriveLetter); - g_hCurDir = xbePathSymbolicLinkObject->RootDirectoryHandle; +#ifdef CXBX_KERNEL_REWORK_ENABLED + if (lastFind != std::string::npos) { +#else + // HACK: It is a hack to override XDK's default mount to CdRom0 which may not exist when launch to dashboard directly. + // Otherwise, titles may launch to dashboard, more specifically xbox live title, and back. + if (CxbxTitleDeviceDriveIndex == -1 || lastFind != std::string::npos) { +#endif + CxbxCreateSymbolicLink(DriveD, mount_d_dir); + // Arrange that the Xbe path can reside outside the partitions, and put it to g_hCurDir : + EmuNtSymbolicLinkObject* xbePathSymbolicLinkObject = FindNtSymbolicLinkObjectByDriveLetter(CxbxDelimiterAutoMountDriveLetter); + g_hCurDir = xbePathSymbolicLinkObject->RootDirectoryHandle; + } } // Determine Xbox path to XBE and place it in XeImageFileName @@ -1407,9 +1437,9 @@ __declspec(noreturn) void CxbxKrnlInit free(xbox::XeImageFileName.Buffer); // Assign the running Xbe path, so it can be accessed via the kernel thunk 'XeImageFileName' : - xbox::XeImageFileName.MaximumLength = MAX_PATH; - xbox::XeImageFileName.Buffer = (PCHAR)xbox::ExAllocatePool(MAX_PATH); - sprintf(xbox::XeImageFileName.Buffer, "%c:\\%s", CxbxDefaultXbeDriveLetter, fileName.c_str()); + xbox::XeImageFileName.MaximumLength = xbox::max_path; + xbox::XeImageFileName.Buffer = (PCHAR)xbox::ExAllocatePool(xbox::max_path); + sprintf(xbox::XeImageFileName.Buffer, "%c:\\%s", CxbxDelimiterAutoMountDriveLetter, fileName.c_str()); xbox::XeImageFileName.Length = (USHORT)strlen(xbox::XeImageFileName.Buffer); EmuLogInit(LOG_LEVEL::INFO, "XeImageFileName = %s", xbox::XeImageFileName.Buffer); } diff --git a/src/core/kernel/init/CxbxKrnl.h b/src/core/kernel/init/CxbxKrnl.h index f4df488e6..d2f14a74e 100644 --- a/src/core/kernel/init/CxbxKrnl.h +++ b/src/core/kernel/init/CxbxKrnl.h @@ -223,7 +223,7 @@ extern std::string CxbxKrnl_DebugFileName; extern char szFilePath_CxbxReloaded_Exe[MAX_PATH]; extern char szFolder_CxbxReloadedData[MAX_PATH]; extern char szFilePath_EEPROM_bin[MAX_PATH]; -extern char szFilePath_Xbe[MAX_PATH*2]; +extern char szFilePath_Xbe[xbox::max_path*2]; #ifdef __cplusplus } diff --git a/src/core/kernel/support/EmuFile.cpp b/src/core/kernel/support/EmuFile.cpp index 71e501ea3..cc5d26acd 100644 --- a/src/core/kernel/support/EmuFile.cpp +++ b/src/core/kernel/support/EmuFile.cpp @@ -39,9 +39,10 @@ #pragma warning(default:4005) #include "core\kernel\init\CxbxKrnl.h" #include "Logging.h" +#include "common/util/strConverter.hpp" #include - +#pragma optimize("", off) // Default Xbox Partition Table #define PE_PARTFLAGS_IN_USE 0x80000000 #define XBOX_SWAPPART1_LBA_START 0x400 @@ -273,9 +274,7 @@ const std::string DeviceHarddisk0Partition17 = DeviceHarddisk0PartitionPrefix + const std::string DeviceHarddisk0Partition18 = DeviceHarddisk0PartitionPrefix + "18"; const std::string DeviceHarddisk0Partition19 = DeviceHarddisk0PartitionPrefix + "19"; const std::string DeviceHarddisk0Partition20 = DeviceHarddisk0PartitionPrefix + "20"; // 20 = Largest possible partition number -const char CxbxDefaultXbeDriveLetter = 'D'; -int CxbxDefaultXbeDriveIndex = -1; EmuNtSymbolicLinkObject* NtSymbolicLinkObjects['Z' - 'A' + 1]; std::vector Devices; @@ -446,6 +445,12 @@ NTSTATUS CxbxConvertFilePath( if (RelativePath.compare(0, 7, "serial:") == 0) return STATUS_UNRECOGNIZED_VOLUME; + // Raw handle access to the CDROM0: + /*if (RelativePath.compare(0, 7, "CDROM0:") == 0) { + RelativePath = DeviceCdrom0 + "\\CDROM0.bin"; + // we should have a return and likely forward to special handler function, including serial: above. + }*/ + // The path seems to be a device path, look it up : NtSymbolicLinkObject = FindNtSymbolicLinkObjectByDevice(RelativePath); // Fixup RelativePath path here @@ -593,6 +598,15 @@ int CxbxDeviceIndexByDevicePath(const char *XboxDevicePath) return -1; } +int CxbxDeviceIndexByHostPath(const char * HostDevicePath) +{ + for (size_t i = 0; i < Devices.size(); i++) + if (_strnicmp(HostDevicePath, Devices[i].HostDevicePath.c_str(), Devices[i].HostDevicePath.length()) == 0) + return(i); + + return -1; +} + XboxDevice *CxbxDeviceByDevicePath(const std::string XboxDevicePath) { int DeviceIndex = CxbxDeviceIndexByDevicePath(XboxDevicePath.c_str()); @@ -602,7 +616,44 @@ XboxDevice *CxbxDeviceByDevicePath(const std::string XboxDevicePath) return nullptr; } -int CxbxRegisterDeviceHostPath(std::string XboxDevicePath, std::string HostDevicePath, bool IsFile) +XboxDevice *CxbxDeviceByHostPath(const std::string HostDevicePath) +{ + int DeviceIndex = CxbxDeviceIndexByHostPath(HostDevicePath.c_str()); + if (DeviceIndex >= 0) + return &Devices[DeviceIndex]; + + return nullptr; +} + +std::string CxbxConvertXboxToHostPath(const std::string_view XboxDevicePath) { + std::string XbePath; + // Convert Xbox XBE Path to Host Path + { + HANDLE rootDirectoryHandle = nullptr; + std::wstring wXbePath; + // We pretend to come from NtCreateFile to force symbolic link resolution + CxbxConvertFilePath(XboxDevicePath.data(), wXbePath, &rootDirectoryHandle, "NtCreateFile"); + + // Convert Wide String as returned by above to a string, for XbePath + XbePath = utf16_to_ascii(wXbePath.c_str()); + + // If the rootDirectoryHandle is not null, we have a relative path + // We need to prepend the path of the root directory to get a full DOS path + if (rootDirectoryHandle != nullptr) { + char directoryPathBuffer[MAX_PATH]; + GetFinalPathNameByHandle(rootDirectoryHandle, directoryPathBuffer, MAX_PATH, VOLUME_NAME_DOS); + XbePath = directoryPathBuffer + std::string("\\") + XbePath; + + // Trim \\?\ from the output string, as we want the raw DOS path, not NT path + // We can do this always because GetFinalPathNameByHandle ALWAYS returns this format + // Without exception + XbePath.erase(0, 4); + } + } + return XbePath; +} + +int CxbxRegisterDeviceHostPath(const std::string_view XboxDevicePath, std::string HostDevicePath, bool IsFile) { XboxDevice newDevice; newDevice.XboxDevicePath = XboxDevicePath; @@ -611,7 +662,7 @@ int CxbxRegisterDeviceHostPath(std::string XboxDevicePath, std::string HostDevic bool succeeded{ false }; // All HDD partitions have a .bin file to allow direct file io on the partition info - if (_strnicmp(XboxDevicePath.c_str(), DeviceHarddisk0PartitionPrefix.c_str(), DeviceHarddisk0PartitionPrefix.length()) == 0) { + if (_strnicmp(XboxDevicePath.data(), DeviceHarddisk0PartitionPrefix.c_str(), DeviceHarddisk0PartitionPrefix.length()) == 0) { std::string partitionHeaderPath = HostDevicePath + ".bin"; if (!std::filesystem::exists(partitionHeaderPath)) { CxbxCreatePartitionHeaderFile(partitionHeaderPath, XboxDevicePath == DeviceHarddisk0Partition0); @@ -622,7 +673,8 @@ int CxbxRegisterDeviceHostPath(std::string XboxDevicePath, std::string HostDevic // If this path is not a raw file partition, create the directory for it if (!IsFile) { - succeeded = std::filesystem::exists(HostDevicePath) || std::filesystem::create_directory(HostDevicePath); + std::error_code error; + succeeded = std::filesystem::exists(HostDevicePath) || std::filesystem::create_directory(HostDevicePath, error); } if (succeeded) { @@ -636,14 +688,15 @@ int CxbxRegisterDeviceHostPath(std::string XboxDevicePath, std::string HostDevic } -NTSTATUS CxbxCreateSymbolicLink(std::string SymbolicLinkName, std::string FullPath) +xbox::ntstatus_xt CxbxCreateSymbolicLink(std::string SymbolicLinkName, std::string FullPath) { - NTSTATUS result = 0; + xbox::ntstatus_xt result = 0; EmuNtSymbolicLinkObject* SymbolicLinkObject = FindNtSymbolicLinkObjectByName(SymbolicLinkName); - if (SymbolicLinkObject != NULL) - // In that case, close it (will also delete if reference count drops to zero) - SymbolicLinkObject->NtClose(); + // If symbolic link exist, return object name collsion. Do NOT delete existing symlink object! + if (SymbolicLinkObject != NULL) { + return xbox::status_object_name_collision; + } // Now (re)create a symbolic link object, and initialize it with the new definition : SymbolicLinkObject = new EmuNtSymbolicLinkObject(); @@ -660,7 +713,7 @@ NTSTATUS EmuNtSymbolicLinkObject::Init(std::string aSymbolicLinkName, std::strin { NTSTATUS result = STATUS_OBJECT_NAME_INVALID; int i = 0; - int DeviceIndex = 0; + int DeviceIndex = -1; // If aFullPath is an empty string, set it to the CD-ROM drive // This should work for all titles, as CD-ROM is mapped to the current working directory @@ -688,31 +741,37 @@ NTSTATUS EmuNtSymbolicLinkObject::Init(std::string aSymbolicLinkName, std::strin // Make a distinction between Xbox paths (starting with '\Device'...) and host paths : IsHostBasedPath = _strnicmp(aFullPath.c_str(), DevicePrefix.c_str(), DevicePrefix.length()) != 0; - if (IsHostBasedPath) - DeviceIndex = CxbxDefaultXbeDriveIndex; - else + if (IsHostBasedPath) { + DeviceIndex = CxbxDeviceIndexByHostPath(aFullPath.c_str()); + } + else { DeviceIndex = CxbxDeviceIndexByDevicePath(aFullPath.c_str()); + } if (DeviceIndex >= 0) { result = xbox::status_success; SymbolicLinkName = aSymbolicLinkName; - if (IsHostBasedPath) - { - XboxSymbolicLinkPath = ""; + if (IsHostBasedPath) { + // Handle the case where a sub folder of the partition is mounted (instead of it's root) : + std::string ExtraPath = aFullPath.substr(Devices[DeviceIndex].HostDevicePath.length(), std::string::npos); + + XboxSymbolicLinkPath = Devices[DeviceIndex].XboxDevicePath + ExtraPath; HostSymbolicLinkPath = aFullPath; + } - else - { + else { XboxSymbolicLinkPath = aFullPath; HostSymbolicLinkPath = Devices[DeviceIndex].HostDevicePath; // Handle the case where a sub folder of the partition is mounted (instead of it's root) : std::string ExtraPath = aFullPath.substr(Devices[DeviceIndex].XboxDevicePath.length(), std::string::npos); - if (!ExtraPath.empty()) + if (!ExtraPath.empty()) { HostSymbolicLinkPath = HostSymbolicLinkPath + ExtraPath; + } } + RootDirectoryHandle = CreateFile(HostSymbolicLinkPath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (RootDirectoryHandle == INVALID_HANDLE_VALUE) { diff --git a/src/core/kernel/support/EmuFile.h b/src/core/kernel/support/EmuFile.h index c82b0f6b8..bf3ba9d4b 100644 --- a/src/core/kernel/support/EmuFile.h +++ b/src/core/kernel/support/EmuFile.h @@ -91,8 +91,7 @@ extern const std::string DeviceHarddisk0Partition17; extern const std::string DeviceHarddisk0Partition18; extern const std::string DeviceHarddisk0Partition19; extern const std::string DeviceHarddisk0Partition20; -extern const char CxbxDefaultXbeDriveLetter; -extern int CxbxDefaultXbeDriveIndex; +static constexpr char CxbxDelimiterAutoMountDriveLetter = 'D'; extern std::string CxbxBasePath; extern HANDLE CxbxBasePathHandle; @@ -219,9 +218,11 @@ struct XboxDevice { CHAR* NtStatusToString(IN NTSTATUS Status); -int CxbxRegisterDeviceHostPath(std::string XboxFullPath, std::string HostDevicePath, bool IsFile = false); +int CxbxRegisterDeviceHostPath(std::string_view XboxFullPath, std::string HostDevicePath, bool IsFile = false); int CxbxDeviceIndexByDevicePath(const char *XboxDevicePath); XboxDevice *CxbxDeviceByDevicePath(const std::string XboxDevicePath); +XboxDevice* CxbxDeviceByHostPath(const std::string HostPath); +std::string CxbxConvertXboxToHostPath(const std::string_view XboxDevicePath); char SymbolicLinkToDriveLetter(std::string aSymbolicLinkName); EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByDriveLetter(const char DriveLetter); @@ -231,7 +232,7 @@ EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByRootHandle(HANDLE Handle); void CleanupSymbolicLinks(); HANDLE CxbxGetDeviceNativeRootHandle(std::string XboxFullPath); -NTSTATUS CxbxCreateSymbolicLink(std::string SymbolicLinkName, std::string FullPath); +xbox::ntstatus_xt CxbxCreateSymbolicLink(std::string SymbolicLinkName, std::string FullPath); std::wstring string_to_wstring(std::string const & src); std::wstring PUNICODE_STRING_to_wstring(NtDll::PUNICODE_STRING const & src);