mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-05-07 13:37:46 +00:00
Add support to play from a BD Drive (currently only on Windows) (#18648)
Follow up of #18345 to add support (currently only on `Windows`; see notes below) for playing a PS3 disc game directly from a Blu-Ray Disc Drive. ### HOW IT WORKS: - The BD drive can be added as any other game so from `VFS games` or from `Add Games` menu. In case it is selected from `VFS games`, any attempt to write files is discarded, e.g. file `Disc Games Can Be Put Here For Automatic Detection.txt` - It scans the default redump keys folder `<rpcs3>/data/redump` (it currently needs to be manually created due it is not yet provided by rpcs3 installation) to find a matching decryption key ### NOTES: - Support is currently provided on `Windows` where I can fully test it. I cannot test under other OS. However, the additions needed for the other OS are limited only on `fs::file.h/cpp`. In particular inside the following new functions: - `bool is_optical_raw_device(const std::string& path);` - `bool get_optical_raw_device(const std::string& path, std::string* raw_device = nullptr);` - Icons etc. are always refreshed (ISO cache cannot be used due `mtime` on raw device is not available and any cache check would always fail) - Code in `ISO.h/cpp` needed some rework to properly manage a read on a raw device (alignment on offset, size and memory is mandatory). The BD drive needs to be detected as a file, not as a folder ### MINOR FIXES: - Fixed wrong specifier used in logging on `ISO.h/cpp`
This commit is contained in:
parent
e05d359721
commit
b212935c70
12 changed files with 668 additions and 212 deletions
|
|
@ -38,6 +38,17 @@ static std::unique_ptr<wchar_t[]> to_wchar(std::string_view source)
|
|||
// Buffer for max possible output length
|
||||
std::unique_ptr<wchar_t[]> buffer(new wchar_t[buf_size + 8 + 32768]);
|
||||
|
||||
// If path points to an optical raw device, copy it AS IS
|
||||
if (fs::is_optical_raw_device(std::string(source)))
|
||||
{
|
||||
ensure(MultiByteToWideChar(CP_UTF8, 0, source.data(), size, buffer.get() + 32768, size)); // "to_wchar"
|
||||
|
||||
// Canonicalize wide path (replace '/', ".", "..", \\ repetitions, etc)
|
||||
ensure(GetFullPathNameW(buffer.get() + 32768, 32768, buffer.get(), nullptr) - 1 < 32768 - 1); // "to_wchar"
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Prepend wide path prefix (4 characters)
|
||||
std::memcpy(buffer.get() + 32768, L"\\\\\?\\", 4 * sizeof(wchar_t));
|
||||
|
||||
|
|
@ -400,11 +411,12 @@ namespace fs
|
|||
class windows_file final : public file_base
|
||||
{
|
||||
HANDLE m_handle;
|
||||
bool m_raw_device;
|
||||
atomic_t<u64> m_pos {0};
|
||||
|
||||
public:
|
||||
windows_file(HANDLE handle)
|
||||
: m_handle(handle)
|
||||
windows_file(HANDLE handle, bool raw_device = false)
|
||||
: m_handle(handle), m_raw_device(raw_device)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -564,11 +576,20 @@ namespace fs
|
|||
|
||||
u64 size() override
|
||||
{
|
||||
// NOTE: this can fail if we access a mounted empty drive (e.g. after unmounting an iso).
|
||||
LARGE_INTEGER size;
|
||||
ensure(GetFileSizeEx(m_handle, &size)); // "file::size"
|
||||
if (!m_raw_device)
|
||||
{
|
||||
// NOTE: this can fail if we access a mounted empty drive (e.g. after unmounting an iso).
|
||||
LARGE_INTEGER size;
|
||||
|
||||
return size.QuadPart;
|
||||
ensure(GetFileSizeEx(m_handle, &size)); // "file::size"
|
||||
return size.QuadPart;
|
||||
}
|
||||
|
||||
// For a raw device, we need to use DeviceIoControl.
|
||||
DISK_GEOMETRY_EX geometry;
|
||||
|
||||
ensure(DeviceIoControl(m_handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, nullptr, 0, &geometry, sizeof(geometry), nullptr, nullptr));
|
||||
return geometry.DiskSize.QuadPart;
|
||||
}
|
||||
|
||||
native_handle get_handle() override
|
||||
|
|
@ -1091,6 +1112,68 @@ bool fs::is_symlink(const std::string& path)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool fs::is_optical_raw_device(const std::string& path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (path.starts_with("\\\\.\\"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fs::get_optical_raw_device(const std::string& path, std::string* raw_device)
|
||||
{
|
||||
if (fs::is_optical_raw_device(path))
|
||||
{
|
||||
if (raw_device)
|
||||
{
|
||||
*raw_device = path;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
constexpr u32 BUF_SIZE = 1000;
|
||||
WCHAR drive_list[BUF_SIZE] = {0};
|
||||
|
||||
// GetLogicalDriveStrings() returns a double-null terminated list of null-terminated strings.
|
||||
// E.g. A:\<nul>B:\<nul>C:\<nul><nul>
|
||||
const DWORD copied = GetLogicalDriveStrings(BUF_SIZE, drive_list);
|
||||
|
||||
if (copied == 0 || copied > BUF_SIZE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const WCHAR* drive = drive_list; drive && *drive; drive += wcslen(drive) + 1)
|
||||
{
|
||||
if (GetDriveType(drive) == DRIVE_CDROM)
|
||||
{
|
||||
const std::wstring ws(drive);
|
||||
const std::string s = std::string(ws.begin(), ws.end() - 1);
|
||||
|
||||
if (path.starts_with(s))
|
||||
{
|
||||
if (raw_device)
|
||||
{
|
||||
*raw_device = "\\\\.\\" + s;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fs::statfs(const std::string& path, fs::device_stat& info)
|
||||
{
|
||||
if (auto device = get_virtual_device(path))
|
||||
|
|
@ -1658,9 +1741,18 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
|||
return;
|
||||
}
|
||||
|
||||
// If path points to an optical raw device, complete the file opening
|
||||
// (the following GetFileInformationByHandle() would always fail on a raw device).
|
||||
if (is_optical_raw_device(path))
|
||||
{
|
||||
m_file = std::make_unique<windows_file>(handle, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the handle is actually valid.
|
||||
// This can fail on empty mounted drives (e.g. with ERROR_NOT_READY or ERROR_INVALID_FUNCTION).
|
||||
BY_HANDLE_FILE_INFORMATION info{};
|
||||
|
||||
if (!GetFileInformationByHandle(handle, &info))
|
||||
{
|
||||
const DWORD last_error = GetLastError();
|
||||
|
|
@ -1671,7 +1763,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
|||
g_tls_error = fs::error::isdir;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
g_tls_error = to_error(last_error);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue