Merge pull request #2193 from RadWolfie/title-mount-path

kernel: implement title mount path
This commit is contained in:
PatrickvL 2021-04-23 22:48:59 +02:00 committed by GitHub
commit dd7fbe302f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 239 additions and 93 deletions

View File

@ -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;

View File

@ -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 <memory.h>
@ -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.

View File

@ -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
}

View File

@ -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());

View File

@ -28,7 +28,6 @@
#define LOG_PREFIX CXBXR_MODULE::HAL
#include <core\kernel\exports\xboxkrnl.h> // For HalReadSMCTrayState, etc.
#include <Shlwapi.h> // For PathRemoveFileSpec()
#include "Logging.h" // For LOG_FUNC()
@ -540,7 +539,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 +551,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
{

View File

@ -90,7 +90,7 @@ static std::vector<HANDLE> 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;
@ -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()
@ -1231,6 +1231,24 @@ void LoadXboxKeys(std::string path)
EmuLog(LOG_LEVEL::WARNING, "Failed to load Keys.bin. Cxbx-Reloaded will be unable to read Save Data from a real Xbox");
}
//TODO: Possible move CxbxResolveHostToFullPath inline function someplace else if become useful elsewhere.
// Let filesystem library clean it up for us, including resolve host's symbolic link path.
// Since internal kernel do translate to full path than preserved host symoblic link path.
static inline void CxbxResolveHostToFullPath(std::filesystem::path& file_path, std::string_view finish_error_sentence) {
std::error_code error;
std::filesystem::path sanityPath = std::filesystem::canonical(file_path, error);
if (error.value() != 0) {
CxbxKrnlCleanupEx(LOG_PREFIX_INIT, "Could not resolve to %s: %s", finish_error_sentence.data(), file_path.string().c_str());
}
file_path = sanityPath;
}
// TODO: Eventually, we should remove this function to start using std::filesystem::path method for all host paths.
static inline void CxbxResolveHostToFullPath(std::string& file_path, std::string_view finish_error_sentence) {
std::filesystem::path sanityPath(file_path);
CxbxResolveHostToFullPath(sanityPath, finish_error_sentence);
file_path = sanityPath.string();
}
__declspec(noreturn) void CxbxKrnlInit
(
void *pTLSData,
@ -1341,34 +1359,67 @@ __declspec(noreturn) void CxbxKrnlInit
#endif
// Initialize devices :
char szBuffer[sizeof(szFilePath_Xbe)];
g_EmuShared->GetStorageLocation(szBuffer);
{
char szBuffer[sizeof(szFilePath_Xbe)];
g_EmuShared->GetStorageLocation(szBuffer);
CxbxBasePath = std::string(szBuffer) + "\\EmuDisk\\";
CxbxBasePath = std::string(szBuffer) + "\\EmuDisk";
CxbxResolveHostToFullPath(CxbxBasePath, "Cxbx-Reloaded's EmuDisk 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();
}
// Determine XBE Path
strncpy(szBuffer, szFilePath_Xbe, sizeof(szBuffer)-1);
szBuffer[sizeof(szBuffer) - 1] = '\0'; // Safely null terminate at the end.
// Determine xbe path
std::filesystem::path xbePath;
{
std::string szBuffer(szFilePath_Xbe);
std::replace(szBuffer.begin(), szBuffer.end(), ';', '/');
xbePath = szBuffer;
}
CxbxResolveHostToFullPath(xbePath, "xbe's file");
std::string xbePath(szBuffer);
std::replace(xbePath.begin(), xbePath.end(), ';', '/');
std::string xbeDirectory(szBuffer);
size_t lastFind = xbeDirectory.find(';');
// Determine location for where possible auto mount D letter if ";" delimiter exist.
// Also used to store in EmuShared's title mount path permanent storage on first emulation launch.
// Unless it's launch within Cxbx-Reloaded's EmuDisk directly, then we don't store anything in title mount path storage.
std::string relative_path(szFilePath_Xbe);
size_t lastFind = relative_path.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 (relative_path.find(';', lastFind + 1) != std::string::npos) {
CxbxKrnlCleanupEx(LOG_PREFIX_INIT, "Cannot contain multiple of ; symbol.");
}
xbeDirectory = xbeDirectory.substr(0, lastFind);
relative_path = relative_path.substr(0, lastFind);
}
else {
xbeDirectory = xbeDirectory.substr(0, xbeDirectory.find_last_of("\\/"));
relative_path = relative_path.substr(0, relative_path.find_last_of("\\/"));
}
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);
memset(szBuffer, 0, sizeof(szBuffer));
// Games may assume they are running from CdRom :
CxbxDefaultXbeDriveIndex = CxbxRegisterDeviceHostPath(DeviceCdrom0, xbeDirectory);
// Titles may assume they are running from CdRom0/Mbfs :
std::string_view titleDevice = g_bIsChihiro ? DriveMbfs : DeviceCdrom0;
int CxbxTitleDeviceDriveIndex = -1;
bool isEmuDisk = _strnicmp(relative_path.c_str(), CxbxBasePath.c_str(), CxbxBasePath.size() - 1) == 0;
if (BootFlags == BOOT_NONE) {
// Remember our first initialize mount path for CdRom0/Mbfs.
if (!isEmuDisk) {
g_EmuShared->SetTitleMountPath(relative_path.c_str());
CxbxTitleDeviceDriveIndex = CxbxRegisterDeviceHostPath(titleDevice, relative_path);
}
else {
g_EmuShared->SetTitleMountPath("");
}
}
else {
char szBuffer[sizeof(szFilePath_Xbe)];
g_EmuShared->GetTitleMountPath(szBuffer);
if (szBuffer[0] != '\0') {
CxbxTitleDeviceDriveIndex = CxbxRegisterDeviceHostPath(titleDevice, szBuffer);
}
}
// 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,33 +1435,69 @@ __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 based on the launchdata page's ; delimiter in the 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, relative_path);
// Arrange that the Xbe path can reside outside the partitions, and put it to g_hCurDir :
EmuNtSymbolicLinkObject* xbePathSymbolicLinkObject = FindNtSymbolicLinkObjectByDriveLetter(CxbxAutoMountDriveLetter);
g_hCurDir = xbePathSymbolicLinkObject->RootDirectoryHandle;
}
}
// Determine Xbox path to XBE and place it in XeImageFileName
{
std::string fileName(xbePath);
// Strip out the path, leaving only the XBE file name
// NOTE: we assume that the XBE is always on the root of the D: drive
// This is a safe assumption as the Xbox kernel ALWAYS mounts D: as the Xbe Path
if (fileName.rfind('\\') != std::string::npos)
fileName = fileName.substr(fileName.rfind('\\') + 1);
std::string fileName;
if (xbox::LaunchDataPage == xbox::zeroptr) {
// First launch and possible launch to dashboard
if (isEmuDisk) {
XboxDevice* xbeLoc = CxbxDeviceByHostPath(xbePath.string());
fileName = xbeLoc->XboxDevicePath;
}
// Otherwise it might be from titleDevice source.
else {
fileName = titleDevice;
}
if (xbox::XeImageFileName.Buffer != NULL)
free(xbox::XeImageFileName.Buffer);
// Strip out the path, leaving only the XBE file name to append.
if (xbePath.has_filename()) {
fileName += "\\" + xbePath.filename().string();
}
}
else {
// One way to say launch to dashboard. We already load the xbe and check it's xbe type.
if (xbox::LaunchDataPage->Header.szLaunchPath[0] == '\0') {
fileName = DeviceHarddisk0Partition2;
// Strip out the path, leaving only the XBE file name to append.
if (xbePath.has_filename()) {
fileName += "\\" + xbePath.filename().string();
}
}
// Otherwise, preserve the launch path and replace delimiter.
else {
fileName = xbox::LaunchDataPage->Header.szLaunchPath;
std::replace(fileName.begin(), fileName.end(), ';', '\\');
}
}
if (xbox::XeImageFileName.Buffer != xbox::zeroptr) {
xbox::ExFreePool(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.Length = (USHORT)strlen(xbox::XeImageFileName.Buffer);
xbox::XeImageFileName.Length = static_cast<xbox::ushort_xt>(fileName.size());
xbox::XeImageFileName.MaximumLength = xbox::XeImageFileName.Length + 1;
xbox::XeImageFileName.Buffer = (PCHAR)xbox::ExAllocatePoolWithTag(xbox::XeImageFileName.MaximumLength, 'nFeX');
strncpy_s(xbox::XeImageFileName.Buffer, xbox::XeImageFileName.MaximumLength,fileName.c_str(), fileName.size());
EmuLogInit(LOG_LEVEL::INFO, "XeImageFileName = %s", xbox::XeImageFileName.Buffer);
}

View File

@ -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
}

View File

@ -39,6 +39,7 @@
#pragma warning(default:4005)
#include "core\kernel\init\CxbxKrnl.h"
#include "Logging.h"
#include "common/util/strConverter.hpp" // utf16_to_ascii
#include <filesystem>
@ -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<XboxDevice> Devices;
@ -446,6 +445,14 @@ NTSTATUS CxbxConvertFilePath(
if (RelativePath.compare(0, 7, "serial:") == 0)
return STATUS_UNRECOGNIZED_VOLUME;
// TODO: CDROM0: need access to raw file handle which doesn't exist in file system.
// Similar concept with serial: and perhaps mediaboards.
// Raw handle access to the CDROM0:
/*if (RelativePath.compare(0, 7, "CDROM0:") == 0) {
// we should have a return and likely forward to special handler function, including serial: above.
return ?;
}*/
// The path seems to be a device path, look it up :
NtSymbolicLinkObject = FindNtSymbolicLinkObjectByDevice(RelativePath);
// Fixup RelativePath path here
@ -593,16 +600,61 @@ int CxbxDeviceIndexByDevicePath(const char *XboxDevicePath)
return -1;
}
XboxDevice *CxbxDeviceByDevicePath(const std::string XboxDevicePath)
int CxbxDeviceIndexByHostPath(const char * HostDevicePath)
{
int DeviceIndex = CxbxDeviceIndexByDevicePath(XboxDevicePath.c_str());
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_view XboxDevicePath)
{
int DeviceIndex = CxbxDeviceIndexByDevicePath(XboxDevicePath.data());
if (DeviceIndex >= 0)
return &Devices[DeviceIndex];
return nullptr;
}
int CxbxRegisterDeviceHostPath(std::string XboxDevicePath, std::string HostDevicePath, bool IsFile)
XboxDevice *CxbxDeviceByHostPath(const std::string_view HostDevicePath)
{
int DeviceIndex = CxbxDeviceIndexByHostPath(HostDevicePath.data());
if (DeviceIndex >= 0)
return &Devices[DeviceIndex];
return nullptr;
}
// Convert Xbox XBE Path to Host Path
std::string CxbxConvertXboxToHostPath(const std::string_view XboxDevicePath)
{
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
std::string 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 +663,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 +674,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; // We do not want filesystem to throw an exception on directory creation. Instead, listen for return value to fail.
succeeded = std::filesystem::exists(HostDevicePath) || std::filesystem::create_directory(HostDevicePath, error);
}
if (succeeded) {
@ -636,14 +689,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 +714,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,29 +742,34 @@ 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);

View File

@ -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;
constexpr char CxbxAutoMountDriveLetter = '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 *CxbxDeviceByDevicePath(const std::string_view XboxDevicePath);
XboxDevice* CxbxDeviceByHostPath(const std::string_view 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);