diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index ef960cf52..00a6281f3 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -95,9 +95,6 @@ char szFolder_CxbxReloadedData[MAX_PATH] = { 0 }; char szFilePath_EEPROM_bin[MAX_PATH] = { 0 }; char szFilePath_Xbe[xbox::max_path*2] = { 0 }; // NOTE: LAUNCH_DATA_HEADER's szLaunchPath is xbox::max_path*2 = 520 -std::string CxbxBasePath; -std::string MuBasePath; -HANDLE CxbxBasePathHandle; Xbe* CxbxKrnl_Xbe = NULL; bool g_bIsChihiro = false; bool g_bIsDebug = false; @@ -1431,17 +1428,18 @@ __declspec(noreturn) void CxbxKrnlInit // Initialize devices : { - char szBuffer[sizeof(szFilePath_Xbe)]; - g_EmuShared->GetStorageLocation(szBuffer); + char cxbxr_data_path[sizeof(szFilePath_Xbe)]; + g_EmuShared->GetStorageLocation(cxbxr_data_path); - MuBasePath = std::string(szBuffer) + "\\EmuMu"; - CxbxBasePath = std::string(szBuffer) + "\\EmuDisk"; - CxbxResolveHostToFullPath(CxbxBasePath, "Cxbx-Reloaded's EmuDisk directory"); - CxbxResolveHostToFullPath(MuBasePath, "Cxbx-Reloaded's EmuMu directory"); + g_DiskBasePath = std::string(cxbxr_data_path) + "\\EmuDisk"; + g_MuBasePath = std::string(cxbxr_data_path) + "\\EmuMu"; + CxbxResolveHostToFullPath(g_DiskBasePath, "Cxbx-Reloaded's EmuDisk directory"); + CxbxResolveHostToFullPath(g_MuBasePath, "Cxbx-Reloaded's EmuMu directory"); // Since canonical always remove the extra slash, we need to manually add it back. - // TODO: Once CxbxBasePath is filesystem::path, replace CxbxBasePath's + operators to / for include path separator internally. - CxbxBasePath = std::filesystem::path(CxbxBasePath).append("").string(); - MuBasePath = std::filesystem::path(MuBasePath).append("").string(); + // TODO: Once g_DiskBasePath is filesystem::path, replace g_DiskBasePath's + operators to / for include path separator internally. + g_DiskBasePath = std::filesystem::path(g_DiskBasePath).append("").string(); + g_MuBasePath = std::filesystem::path(g_MuBasePath).append("").string(); + // NOTE: Do NOT modify global variables above after this point! } // Determine xbe path @@ -1471,9 +1469,9 @@ __declspec(noreturn) void CxbxKrnlInit } CxbxResolveHostToFullPath(relative_path, "xbe's directory"); - CxbxBasePathHandle = CreateFile(CxbxBasePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + g_DiskBasePathHandle = CreateFile(g_DiskBasePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); int CxbxCdrom0DeviceIndex = -1; - bool isEmuDisk = _strnicmp(relative_path.c_str(), CxbxBasePath.c_str(), CxbxBasePath.size() - 1) == 0; + bool isEmuDisk = CxbxrIsPathInsideEmuDisk(relative_path); // Check if title mounth path is already set. This may occur from early boot of Chihiro title. char title_mount_path[sizeof(szFilePath_Xbe)]; const char* p_default_mount_path = title_mount_path; @@ -1489,6 +1487,7 @@ __declspec(noreturn) void CxbxKrnlInit // TODO: Find a place to make permanent placement for DeviceCdrom0 that does not have disc loaded. if (p_default_mount_path[0] != '\0') { + // NOTE: Don't need to perform CxbxResolveHostToFullPath again for p_default_mount_path. CxbxCdrom0DeviceIndex = CxbxRegisterDeviceHostPath(DeviceCdrom0, p_default_mount_path); // Since Chihiro also map Mbfs to the same path as Cdrom0, we'll map it the same way. if (g_bIsChihiro) { @@ -1497,31 +1496,31 @@ __declspec(noreturn) void CxbxKrnlInit } // Partition 0 contains configuration data, and is accessed as a native file, instead as a folder : - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition0, CxbxBasePath + "Partition0", /*IsFile=*/true); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition0, g_DiskBasePath + "Partition0", /*IsFile=*/true); // The first two partitions are for Data and Shell files, respectively : - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition1, CxbxBasePath + "Partition1"); - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition2, CxbxBasePath + "Partition2"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition1, g_DiskBasePath + "Partition1"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition2, g_DiskBasePath + "Partition2"); // The following partitions are for caching purposes - for now we allocate up to 7 (as xbmp needs that many) : - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition3, CxbxBasePath + "Partition3"); - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition4, CxbxBasePath + "Partition4"); - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition5, CxbxBasePath + "Partition5"); - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition6, CxbxBasePath + "Partition6"); - CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition7, CxbxBasePath + "Partition7"); - CxbxRegisterDeviceHostPath(DevicePrefix + "\\Chihiro", CxbxBasePath + "Chihiro"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition3, g_DiskBasePath + "Partition3"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition4, g_DiskBasePath + "Partition4"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition5, g_DiskBasePath + "Partition5"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition6, g_DiskBasePath + "Partition6"); + CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition7, g_DiskBasePath + "Partition7"); + CxbxRegisterDeviceHostPath(DevicePrefix + "\\Chihiro", g_DiskBasePath + "Chihiro"); // Create the MU directories and the bin files - CxbxRegisterDeviceHostPath(DeviceMU0, MuBasePath + "F", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU1, MuBasePath + "G", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU2, MuBasePath + "H", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU3, MuBasePath + "I", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU4, MuBasePath + "J", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU5, MuBasePath + "K", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU6, MuBasePath + "L", false, sizeof(FATX_SUPERBLOCK)); - CxbxRegisterDeviceHostPath(DeviceMU7, MuBasePath + "M", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU0, g_MuBasePath + "F", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU1, g_MuBasePath + "G", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU2, g_MuBasePath + "H", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU3, g_MuBasePath + "I", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU4, g_MuBasePath + "J", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU5, g_MuBasePath + "K", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU6, g_MuBasePath + "L", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU7, g_MuBasePath + "M", false, sizeof(FATX_SUPERBLOCK)); std::mbstate_t ps = std::mbstate_t(); - const char *src = MuBasePath.c_str(); - std::wstring wMuBasePath(MuBasePath.size(), L'0'); + const char *src = g_MuBasePath.c_str(); + std::wstring wMuBasePath(g_MuBasePath.size(), L'0'); std::mbsrtowcs(wMuBasePath.data(), &src, wMuBasePath.size(), &ps); g_io_mu_metadata = new io_mu_metadata(wMuBasePath); diff --git a/src/core/kernel/support/EmuFile.cpp b/src/core/kernel/support/EmuFile.cpp index b7afe8429..b7b7a54ec 100644 --- a/src/core/kernel/support/EmuFile.cpp +++ b/src/core/kernel/support/EmuFile.cpp @@ -47,7 +47,11 @@ #include // partition emulation directory handles -HANDLE g_hCurDir_hack = NULL; // HACK: We should not be depending on this variable. Instead, we should fix/implement Ob/Io objects such as IoCreateDevice. +HANDLE g_hCurDir_hack = NULL; // HACK: We should not be depending on this variable. Instead, we should fix/implement Ob/Io objects such as IoCreateDevice. + +HANDLE g_DiskBasePathHandle; +std::string g_DiskBasePath; +std::string g_MuBasePath; // Default Xbox Partition Table #define PE_PARTFLAGS_IN_USE 0x80000000 @@ -157,23 +161,44 @@ void io_mu_metadata::flush(const wchar_t lett) ofs.flush(); } +// NOTE: root_path input must already had called canonical function for optimization purpose. +static bool CxbxrIsPathInsideRootPath(const std::filesystem::path& path, const std::filesystem::path& root_path) +{ + std::error_code rootError, finalError; + const std::filesystem::path rootPath = std::filesystem::canonical(root_path, rootError); // TODO: Replace rootPath to root_path when possible. + const std::filesystem::path finalPath = std::filesystem::canonical(path, finalError); + if (rootError || finalError) { + return false; + } + auto match = std::mismatch(rootPath.begin(), rootPath.end(), finalPath.begin(), finalPath.end()); + return match.first == rootPath.end(); +} + +bool CxbxrIsPathInsideEmuDisk(const std::filesystem::path& path) +{ + return CxbxrIsPathInsideRootPath(path, g_DiskBasePath); +} + +static bool CxbxrIsPathInsideEmuMu(const std::filesystem::path& path) +{ + return CxbxrIsPathInsideRootPath(path, g_MuBasePath); +} + DeviceType CxbxrGetDeviceTypeFromHandle(HANDLE hFile) { - const std::wstring path = CxbxGetFinalPathNameByHandle(hFile); + const std::filesystem::path path = CxbxGetFinalPathNameByHandle(hFile); - size_t pos = path.rfind(L"\\EmuDisk\\Partition"); - if (pos != std::string::npos) { + if (CxbxrIsPathInsideEmuDisk(path)) { return DeviceType::Harddisk0; } - pos = path.rfind(L"\\EmuMu"); - if (pos != std::string::npos) { + if (CxbxrIsPathInsideEmuMu(path)) { return DeviceType::MU; } EmuDirPath hybrid_path; FindEmuDirPathByDevice(DeviceCdrom0, hybrid_path); - if (hybrid_path.HostDirPath != "") { + if (!hybrid_path.HostDirPath.empty() && CxbxrIsPathInsideRootPath(path, hybrid_path.HostDirPath)) { return DeviceType::Cdrom0; } @@ -202,9 +227,9 @@ void CxbxCreatePartitionHeaderFile(std::string filename, bool partition0 = false XboxPartitionTable CxbxGetPartitionTable() { XboxPartitionTable table; - FILE* fp = fopen((CxbxBasePath + "Partition0.bin").c_str(), "rb"); + FILE* fp = fopen((g_DiskBasePath + "Partition0.bin").c_str(), "rb"); if (fp == nullptr) { - CxbxKrnlCleanup("CxbxGetPartitionTable Failed:\nUnable to open file: %s", (CxbxBasePath + "Partition0.bin").c_str()); + CxbxKrnlCleanup("CxbxGetPartitionTable Failed:\nUnable to open file: %s", (g_DiskBasePath + "Partition0.bin").c_str()); } fread(&table, sizeof(XboxPartitionTable), 1, fp); @@ -215,8 +240,8 @@ XboxPartitionTable CxbxGetPartitionTable() // Or invalid partition tables left behind from previous versions // of Cxbx-Reloaded if (memcmp(table.Magic, BackupPartTbl.Magic, 16) != 0) { - DeleteFile((CxbxBasePath + "Partition0.bin").c_str()); - CxbxCreatePartitionHeaderFile(CxbxBasePath + "Partition0.bin", true); + DeleteFile((g_DiskBasePath + "Partition0.bin").c_str()); + CxbxCreatePartitionHeaderFile(g_DiskBasePath + "Partition0.bin", true); memcpy(&table, &BackupPartTbl, sizeof(XboxPartitionTable)); } @@ -228,7 +253,7 @@ FATX_SUPERBLOCK CxbxGetFatXSuperBlock(int partitionNumber) FATX_SUPERBLOCK superblock; std::stringstream ss; - ss << CxbxBasePath << "Partition" << partitionNumber << ".bin"; + ss << g_DiskBasePath << "Partition" << partitionNumber << ".bin"; FILE* fp = fopen(ss.str().c_str(), "rb"); fread(&superblock, sizeof(FATX_SUPERBLOCK), 1, fp); fclose(fp); @@ -256,19 +281,6 @@ std::wstring CxbxGetFinalPathNameByHandle(HANDLE hFile) return path; } -static bool CxbxIsPathInsideEmuDisk(const std::filesystem::path& path) -{ - std::error_code rootError, finalError; - - const std::filesystem::path rootPath = std::filesystem::canonical(CxbxBasePath, rootError); - const std::filesystem::path finalPath = std::filesystem::canonical(path, finalError); - if (rootError || finalError) { - return false; - } - auto match = std::mismatch(rootPath.begin(), rootPath.end(), finalPath.begin(), finalPath.end()); - return match.first == rootPath.end(); -} - static int CxbxGetPartitionNumber(const std::wstring_view path) { const std::wstring_view partitionString = L"\\EmuDisk\\Partition"; @@ -314,7 +326,7 @@ void CxbxFormatPartitionByHandle(HANDLE hFile) const std::filesystem::path partitionPath = CxbxGetPartitionDataPathFromHandle(hFile); // Sanity check, make sure we are actually deleting something within the Cxbx-Reloaded folder - if (!CxbxIsPathInsideEmuDisk(partitionPath)) { + if (!CxbxrIsPathInsideEmuDisk(partitionPath)) { EmuLog(LOG_LEVEL::WARNING, "Attempting to format a path that is not within a Cxbx-Reloaded data folder... Ignoring!\n"); return; } @@ -539,16 +551,16 @@ NTSTATUS CxbxConvertFilePath( if (RelativePath.compare(0, DrivePrefix.length(), DrivePrefix.c_str()) == 0) RelativePath.erase(0, 4); - // Check if we where called from a File-handling API : + // Check if we were called from a File-handling API : if (!aFileAPIName.empty()) { if (RelativePath.compare(DriveMbrom0) == 0) { - *RootDirectory = CxbxBasePathHandle; - HostPath = CxbxBasePath; + *RootDirectory = g_DiskBasePathHandle; + HostPath = g_DiskBasePath; RelativePath = MediaBoardSegaBoot0; } else if (RelativePath.compare(DriveMbrom1) == 0) { - *RootDirectory = CxbxBasePathHandle; - HostPath = CxbxBasePath; + *RootDirectory = g_DiskBasePathHandle; + HostPath = g_DiskBasePath; RelativePath = MediaBoardSegaBoot1; } else if (!partitionHeader) { @@ -607,8 +619,8 @@ NTSTATUS CxbxConvertFilePath( // Remove Harddisk0 prefix, in the hope that the remaining path might work : RelativePath.erase(0, DeviceHarddisk0.length() + 1); // And set Root to the folder containing the partition-folders : - *RootDirectory = CxbxBasePathHandle; - HostPath = CxbxBasePath; + *RootDirectory = g_DiskBasePathHandle; + HostPath = g_DiskBasePath; } // NOTE: RootDirectory cannot be ignored. // Any special handling for it should be done below. @@ -650,8 +662,8 @@ NTSTATUS CxbxConvertFilePath( *RootDirectory = find_path.HostDirHandle; } } else { - *RootDirectory = CxbxBasePathHandle; - HostPath = CxbxBasePath; + *RootDirectory = g_DiskBasePathHandle; + HostPath = g_DiskBasePath; RelativePath = RelativeXboxPath.substr(DeviceHarddisk0.length()) + ".bin"; } @@ -669,8 +681,8 @@ NTSTATUS CxbxConvertFilePath( if (g_bPrintfOn) { EmuLog(LOG_LEVEL::DEBUG, "%s Corrected path...", aFileAPIName.c_str()); EmuLog(LOG_LEVEL::DEBUG, " Org:\"%s\"", OriginalPath.c_str()); - if (_strnicmp(HostPath.c_str(), CxbxBasePath.c_str(), CxbxBasePath.length()) == 0) { - EmuLog(LOG_LEVEL::DEBUG, " New:\"$CxbxPath\\%s%s\"", (HostPath.substr(CxbxBasePath.length(), std::string::npos)).c_str(), RelativePath.c_str()); + if (_strnicmp(HostPath.c_str(), g_DiskBasePath.c_str(), g_DiskBasePath.length()) == 0) { + EmuLog(LOG_LEVEL::DEBUG, " New:\"$CxbxPath\\%s%s\"", (HostPath.substr(g_DiskBasePath.length(), std::string::npos)).c_str(), RelativePath.c_str()); } else EmuLog(LOG_LEVEL::DEBUG, " New:\"$XbePath\\%s\"", RelativePath.c_str()); diff --git a/src/core/kernel/support/EmuFile.h b/src/core/kernel/support/EmuFile.h index eedc2e2b2..c9e4cdce2 100644 --- a/src/core/kernel/support/EmuFile.h +++ b/src/core/kernel/support/EmuFile.h @@ -119,8 +119,9 @@ inline constexpr xbox::ulong_xt fsctl_read_fatx_metadata = 0x0009411C; inline constexpr xbox::ulong_xt fsctl_write_fatx_metadata = 0x00098120; inline constexpr std::size_t mu_max_name_lenght = 32 * sizeof(xbox::wchar_xt); // MU names are in wide chars -extern std::string CxbxBasePath; -extern HANDLE CxbxBasePathHandle; +extern std::string g_DiskBasePath; +extern std::string g_MuBasePath; +extern HANDLE g_DiskBasePathHandle; const size_t XboxFileInfoStructSizes[xbox::FileMaximumInformation] = { 0, // (index 0) @@ -277,6 +278,7 @@ int CxbxDeviceIndexByDevicePath(const char *XboxDevicePath); XboxDevice* CxbxDeviceByDevicePath(const std::string_view XboxDevicePath); XboxDevice* CxbxDeviceByHostPath(const std::string_view HostPath); std::string CxbxConvertXboxToHostPath(const std::string_view XboxDevicePath); +bool CxbxrIsPathInsideEmuDisk(const std::filesystem::path& path); char SymbolicLinkToDriveLetter(std::string aSymbolicLinkName); EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByDriveLetter(const char DriveLetter);